Merge "Fix implicit fallthrough warnings." am: 591171a659 am: 9232ca3782
am: ec4022d410

Change-Id: I9489669f4797b188027ba7e3686d1e2ecfebefc4
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 531e44e..0900eea 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -66,3 +66,6 @@
 $(call add-clean-step, find $(PRODUCT_OUT)/system $(PRODUCT_OUT)/vendor -type f -name "android\.hardware\.configstore\@1\.1*" -print0 | xargs -0 rm -f)
 $(call add-clean-step, find $(PRODUCT_OUT)/system $(PRODUCT_OUT)/vendor -type f -name "android\.hardware\.configstore*" -print0 | xargs -0 rm -f)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/seccomp_policy/configstore@1.0.policy)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/seccomp_policy/configstore@1.1.policy)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/bin/hw/android.hardware.configstore@1.1-service)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/vendor/etc/init/android.hardware.configstore@1.1-service.rc)
diff --git a/audio/4.1/config/audio_policy_configuration.xsd b/audio/4.1/config/audio_policy_configuration.xsd
new file mode 100644
index 0000000..311b9c1
--- /dev/null
+++ b/audio/4.1/config/audio_policy_configuration.xsd
@@ -0,0 +1,595 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+         Licensed under the Apache License, Version 2.0 (the "License");
+         you may not use this file except in compliance with the License.
+         You may obtain a copy of the License at
+
+                    http://www.apache.org/licenses/LICENSE-2.0
+
+         Unless required by applicable law or agreed to in writing, software
+         distributed under the License is distributed on an "AS IS" BASIS,
+         WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+         See the License for the specific language governing permissions and
+         limitations under the License.
+-->
+<!-- TODO: define a targetNamespace. Note that it will break retrocompatibility -->
+<xs:schema version="2.0"
+           elementFormDefault="qualified"
+           attributeFormDefault="unqualified"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+    <!-- List the config versions supported by audio policy. -->
+    <xs:simpleType name="version">
+        <xs:restriction base="xs:decimal">
+            <xs:enumeration value="1.0"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="halVersion">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Version of the interface the hal implements.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:decimal">
+            <!-- List of HAL versions supported by the framework. -->
+            <xs:enumeration value="2.0"/>
+            <xs:enumeration value="3.0"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:element name="audioPolicyConfiguration">
+        <xs:complexType>
+            <xs:sequence>
+                <xs:element name="globalConfiguration" type="globalConfiguration"/>
+                <xs:element name="modules" type="modules" maxOccurs="unbounded"/>
+                <xs:element name="volumes" type="volumes" maxOccurs="unbounded"/>
+                <xs:element name="surroundSound" type="surroundSound" />
+            </xs:sequence>
+            <xs:attribute name="version" type="version"/>
+        </xs:complexType>
+        <xs:key name="moduleNameKey">
+            <xs:selector xpath="modules/module"/>
+            <xs:field xpath="@name"/>
+        </xs:key>
+        <xs:unique name="volumeTargetUniqueness">
+            <xs:selector xpath="volumes/volume"/>
+            <xs:field xpath="@stream"/>
+            <xs:field xpath="@deviceCategory"/>
+        </xs:unique>
+        <xs:key name="volumeCurveNameKey">
+            <xs:selector xpath="volumes/reference"/>
+            <xs:field xpath="@name"/>
+        </xs:key>
+        <xs:keyref name="volumeCurveRef" refer="volumeCurveNameKey">
+            <xs:selector xpath="volumes/volume"/>
+            <xs:field xpath="@ref"/>
+        </xs:keyref>
+    </xs:element>
+    <xs:complexType name="globalConfiguration">
+        <xs:attribute name="speaker_drc_enabled" type="xs:boolean" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="modules">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                There should be one section per audio HW module present on the platform.
+                Each <module/> contains two mandatory tags: “halVersion” and “name”.
+                The module "name" is the same as in previous .conf file.
+                Each module must contain the following sections:
+                 - <devicePorts/>: a list of device descriptors for all
+                   input and output devices accessible via this module.
+                   This contains both permanently attached devices and removable devices.
+                 - <mixPorts/>: listing all output and input streams exposed by the audio HAL
+                 - <routes/>: list of possible connections between input
+                   and output devices or between stream and devices.
+                   A <route/> is defined by a set of 3 attributes:
+                        -"type": mux|mix means all sources are mutual exclusive (mux) or can be mixed (mix)
+                        -"sink": the sink involved in this route
+                        -"sources": all the sources than can be connected to the sink via this route
+                 - <attachedDevices/>: permanently attached devices.
+                   The attachedDevices section is a list of devices names.
+                   Their names correspond to device names defined in "devicePorts" section.
+                 - <defaultOutputDevice/> is the device to be used when no policy rule applies
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="module" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="attachedDevices" type="attachedDevices" minOccurs="0">
+                            <xs:unique name="attachedDevicesUniqueness">
+                                <xs:selector xpath="item"/>
+                                <xs:field xpath="."/>
+                            </xs:unique>
+                        </xs:element>
+                        <xs:element name="defaultOutputDevice" type="xs:token" minOccurs="0"/>
+                        <xs:element name="mixPorts" type="mixPorts" minOccurs="0"/>
+                        <xs:element name="devicePorts" type="devicePorts" minOccurs="0"/>
+                        <xs:element name="routes" type="routes" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="name" type="xs:string" use="required"/>
+                    <xs:attribute name="halVersion" type="halVersion" use="required"/>
+                </xs:complexType>
+                <xs:unique name="mixPortNameUniqueness">
+                    <xs:selector xpath="mixPorts/mixPort"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+                <xs:key name="devicePortNameKey">
+                    <xs:selector xpath="devicePorts/devicePort"/>
+                    <xs:field xpath="@tagName"/>
+                </xs:key>
+                <xs:unique name="devicePortUniqueness">
+                    <xs:selector xpath="devicePorts/devicePort"/>
+                    <xs:field xpath="@type"/>
+                    <xs:field xpath="@address"/>
+                </xs:unique>
+                <xs:keyref name="defaultOutputDeviceRef" refer="devicePortNameKey">
+                    <xs:selector xpath="defaultOutputDevice"/>
+                    <xs:field xpath="."/>
+                </xs:keyref>
+                <xs:keyref name="attachedDeviceRef" refer="devicePortNameKey">
+                    <xs:selector xpath="attachedDevices/item"/>
+                    <xs:field xpath="."/>
+                </xs:keyref>
+                <!-- The following 3 constraints try to make sure each sink port
+                     is reference in one an only one route. -->
+                <xs:key name="routeSinkKey">
+                    <!-- predicate [@type='sink'] does not work in xsd 1.0 -->
+                    <xs:selector xpath="devicePorts/devicePort|mixPorts/mixPort"/>
+                    <xs:field xpath="@tagName|@name"/>
+                </xs:key>
+                <xs:keyref name="routeSinkRef" refer="routeSinkKey">
+                    <xs:selector xpath="routes/route"/>
+                    <xs:field xpath="@sink"/>
+                </xs:keyref>
+                <xs:unique name="routeUniqueness">
+                    <xs:selector xpath="routes/route"/>
+                    <xs:field xpath="@sink"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="attachedDevices">
+        <xs:sequence>
+            <xs:element name="item" type="xs:token" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+    <!-- TODO: separate values by space for better xsd validations. -->
+    <xs:simpleType name="audioInOutFlags">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                "|" separated list of audio_output_flags_t or audio_input_flags_t.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="|[_A-Z]+(\|[_A-Z]+)*"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="role">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="sink"/>
+            <xs:enumeration value="source"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="mixPorts">
+        <xs:sequence>
+            <xs:element name="mixPort" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+                        <xs:element name="gains" type="gains" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="name" type="xs:token" use="required"/>
+                    <xs:attribute name="role" type="role" use="required"/>
+                    <xs:attribute name="flags" type="audioInOutFlags"/>
+                    <xs:attribute name="maxOpenCount" type="xs:unsignedInt"/>
+                    <xs:attribute name="maxActiveCount" type="xs:unsignedInt"/>
+                    <xs:attribute name="preferredUsage" type="audioUsageList">
+                        <xs:annotation>
+                            <xs:documentation xml:lang="en">
+                                When choosing the mixPort of an audio track, the audioPolicy
+                                first considers the mixPorts with a preferredUsage including
+                                the track AudioUsage preferred .
+                                If non support the track format, the other mixPorts are considered.
+                                Eg: a <mixPort preferredUsage="AUDIO_USAGE_MEDIA" /> will receive
+                                    the audio of all apps playing with a MEDIA usage.
+                                    It may receive audio from ALARM if there are no audio compatible
+                                    <mixPort preferredUsage="AUDIO_USAGE_ALARM" />.
+                             </xs:documentation>
+                        </xs:annotation>
+                    </xs:attribute>
+                </xs:complexType>
+                <xs:unique name="mixPortProfileUniqueness">
+                    <xs:selector xpath="profile"/>
+                    <xs:field xpath="format"/>
+                    <xs:field xpath="samplingRate"/>
+                    <xs:field xpath="channelMasks"/>
+                </xs:unique>
+                <xs:unique name="mixPortGainUniqueness">
+                    <xs:selector xpath="gains/gain"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <!-- Enum values of audio_device_t in audio.h
+         TODO: generate from hidl to avoid manual sync.
+         TODO: separate source and sink in the xml for better xsd validations. -->
+    <xs:simpleType name="audioDevice">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_DEVICE_NONE"/>
+
+            <xs:enumeration value="AUDIO_DEVICE_OUT_EARPIECE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_WIRED_HEADPHONE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_DIGITAL"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_ACCESSORY"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_DEVICE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_REMOTE_SUBMIX"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_TELEPHONY_TX"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HDMI_ARC"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPDIF"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_FM"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_AUX_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_SPEAKER_SAFE"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_IP"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_BUS"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_PROXY"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_USB_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_HEARING_AID"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_ECHO_CANCELLER"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_DEFAULT"/>
+            <xs:enumeration value="AUDIO_DEVICE_OUT_STUB"/>
+
+            <!-- Due to the xml format, IN types can not be a separated from OUT types -->
+            <xs:enumeration value="AUDIO_DEVICE_IN_COMMUNICATION"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_AMBIENT"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BUILTIN_MIC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_WIRED_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_AUX_DIGITAL"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_HDMI"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_VOICE_CALL"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_TELEPHONY_RX"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BACK_MIC"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_REMOTE_SUBMIX"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_ACCESSORY"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_DEVICE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_FM_TUNER"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_TV_TUNER"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_LINE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_SPDIF"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_A2DP"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_LOOPBACK"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_IP"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BUS"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_PROXY"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_USB_HEADSET"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_BLUETOOTH_BLE"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_DEFAULT"/>
+            <xs:enumeration value="AUDIO_DEVICE_IN_STUB"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- Enum values of audio_format_t in audio.h
+         TODO: generate from hidl to avoid manual sync. -->
+    <xs:simpleType name="audioFormat">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_FORMAT_PCM_16_BIT" />
+            <xs:enumeration value="AUDIO_FORMAT_PCM_8_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_32_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_8_24_BIT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_FLOAT"/>
+            <xs:enumeration value="AUDIO_FORMAT_PCM_24_BIT_PACKED"/>
+            <xs:enumeration value="AUDIO_FORMAT_MP3"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_NB"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_WB"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_MAIN"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_SSR"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LTP"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_SCALABLE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ERLC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_LD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ELD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_MAIN"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SSR"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LTP"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_SCALABLE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ERLC"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_LD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_HE_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_ELD"/>
+            <xs:enumeration value="AUDIO_FORMAT_VORBIS"/>
+            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V1"/>
+            <xs:enumeration value="AUDIO_FORMAT_HE_AAC_V2"/>
+            <xs:enumeration value="AUDIO_FORMAT_OPUS"/>
+            <xs:enumeration value="AUDIO_FORMAT_AC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_E_AC3"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS"/>
+            <xs:enumeration value="AUDIO_FORMAT_DTS_HD"/>
+            <xs:enumeration value="AUDIO_FORMAT_IEC61937"/>
+            <xs:enumeration value="AUDIO_FORMAT_DOLBY_TRUEHD"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRC"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCB"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCWB"/>
+            <xs:enumeration value="AUDIO_FORMAT_EVRCNW"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADIF"/>
+            <xs:enumeration value="AUDIO_FORMAT_WMA"/>
+            <xs:enumeration value="AUDIO_FORMAT_WMA_PRO"/>
+            <xs:enumeration value="AUDIO_FORMAT_AMR_WB_PLUS"/>
+            <xs:enumeration value="AUDIO_FORMAT_MP2"/>
+            <xs:enumeration value="AUDIO_FORMAT_QCELP"/>
+            <xs:enumeration value="AUDIO_FORMAT_DSD"/>
+            <xs:enumeration value="AUDIO_FORMAT_FLAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_ALAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_APE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS"/>
+            <xs:enumeration value="AUDIO_FORMAT_SBC"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX"/>
+            <xs:enumeration value="AUDIO_FORMAT_APTX_HD"/>
+            <xs:enumeration value="AUDIO_FORMAT_AC4"/>
+            <xs:enumeration value="AUDIO_FORMAT_LDAC"/>
+            <xs:enumeration value="AUDIO_FORMAT_E_AC3_JOC"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_1_0"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_2_0"/>
+            <xs:enumeration value="AUDIO_FORMAT_MAT_2_1"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_XHE"/>
+            <xs:enumeration value="AUDIO_FORMAT_AAC_ADTS_XHE"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- Enum values of audio::common::4_0::AudioUsage
+         TODO: generate from HIDL to avoid manual sync. -->
+    <xs:simpleType name="audioUsage">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_USAGE_UNKNOWN" />
+            <xs:enumeration value="AUDIO_USAGE_MEDIA" />
+            <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION" />
+            <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING" />
+            <xs:enumeration value="AUDIO_USAGE_ALARM" />
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION" />
+            <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION" />
+            <xs:enumeration value="AUDIO_USAGE_GAME" />
+            <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE" />
+            <xs:enumeration value="AUDIO_USAGE_ASSISTANT" />
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:simpleType name="audioUsageList">
+        <xs:list itemType="audioUsage"/>
+    </xs:simpleType>
+    <!-- TODO: Change to a space separated list to xsd enforce correctness. -->
+    <xs:simpleType name="samplingRates">
+        <xs:restriction base="xs:string">
+            <xs:pattern value="[0-9]+(,[0-9]+)*"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- TODO: Change to a space separated list to xsd enforce correctness. -->
+    <xs:simpleType name="channelMask">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Comma (",") separated list of channel flags
+                from audio_channel_mask_t.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="[_A-Z][_A-Z0-9]*(,[_A-Z][_A-Z0-9]*)*"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="profile">
+        <xs:attribute name="name" type="xs:token" use="optional"/>
+        <xs:attribute name="format" type="audioFormat" use="optional"/>
+        <xs:attribute name="samplingRates" type="samplingRates" use="optional"/>
+        <xs:attribute name="channelMasks" type="channelMask" use="optional"/>
+    </xs:complexType>
+    <xs:simpleType name="gainMode">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_GAIN_MODE_JOINT"/>
+            <xs:enumeration value="AUDIO_GAIN_MODE_CHANNELS"/>
+            <xs:enumeration value="AUDIO_GAIN_MODE_RAMP"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="gains">
+        <xs:sequence>
+            <xs:element name="gain" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="name" type="xs:token" use="required"/>
+                    <xs:attribute name="mode" type="gainMode" use="required"/>
+                    <xs:attribute name="channel_mask" type="channelMask" use="optional"/>
+                    <xs:attribute name="minValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="maxValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="defaultValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="stepValueMB" type="xs:int" use="optional"/>
+                    <xs:attribute name="minRampMs" type="xs:int" use="optional"/>
+                    <xs:attribute name="maxRampMs" type="xs:int" use="optional"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="devicePorts">
+        <xs:sequence>
+            <xs:element name="devicePort" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:sequence>
+                        <xs:element name="profile" type="profile" minOccurs="0" maxOccurs="unbounded"/>
+                        <xs:element name="gains" type="gains" minOccurs="0"/>
+                    </xs:sequence>
+                    <xs:attribute name="tagName" type="xs:token" use="required"/>
+                    <xs:attribute name="type" type="audioDevice" use="required"/>
+                    <xs:attribute name="role" type="role" use="required"/>
+                    <xs:attribute name="address" type="xs:string" use="optional" default=""/>
+                    <!-- Note that XSD 1.0 can not check that a type only has one default. -->
+                    <xs:attribute name="default" type="xs:boolean" use="optional">
+                        <xs:annotation>
+                            <xs:documentation xml:lang="en">
+                                The default device will be used if multiple have the same type
+                                and no explicit route request exists for a specific device of
+                                that type.
+                            </xs:documentation>
+                        </xs:annotation>
+                    </xs:attribute>
+                </xs:complexType>
+                <xs:unique name="devicePortProfileUniqueness">
+                    <xs:selector xpath="profile"/>
+                    <xs:field xpath="format"/>
+                    <xs:field xpath="samplingRate"/>
+                    <xs:field xpath="channelMasks"/>
+                </xs:unique>
+                <xs:unique name="devicePortGainUniqueness">
+                    <xs:selector xpath="gains/gain"/>
+                    <xs:field xpath="@name"/>
+                </xs:unique>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:simpleType name="mixType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="mix"/>
+            <xs:enumeration value="mux"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="routes">
+        <xs:sequence>
+            <xs:element name="route" minOccurs="0" maxOccurs="unbounded">
+                <xs:annotation>
+                    <xs:documentation xml:lang="en">
+                        List all available sources for a given sink.
+                    </xs:documentation>
+                </xs:annotation>
+                <xs:complexType>
+                    <xs:attribute name="type" type="mixType" use="required"/>
+                    <xs:attribute name="sink" type="xs:string" use="required"/>
+                    <xs:attribute name="sources" type="xs:string" use="required"/>
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:complexType name="volumes">
+        <xs:sequence>
+            <xs:element name="volume" type="volume" minOccurs="0" maxOccurs="unbounded"/>
+            <xs:element name="reference" type="reference" minOccurs="0" maxOccurs="unbounded">
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+    <!-- TODO: Always require a ref for better xsd validations.
+               Currently a volume could have no points nor ref
+               as it can not be forbidden by xsd 1.0.-->
+    <xs:simpleType name="volumePoint">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Comma separated pair of number.
+                The fist one is the framework level (between 0 and 100).
+                The second one is the volume to send to the HAL.
+                The framework will interpolate volumes not specified.
+                Their MUST be at least 2 points specified.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:pattern value="([0-9]{1,2}|100),-?[0-9]+"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- Enum values of audio_stream_type_t in audio-base.h
+         TODO: generate from hidl to avoid manual sync. -->
+    <xs:simpleType name="stream">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="AUDIO_STREAM_VOICE_CALL"/>
+            <xs:enumeration value="AUDIO_STREAM_SYSTEM"/>
+            <xs:enumeration value="AUDIO_STREAM_RING"/>
+            <xs:enumeration value="AUDIO_STREAM_MUSIC"/>
+            <xs:enumeration value="AUDIO_STREAM_ALARM"/>
+            <xs:enumeration value="AUDIO_STREAM_NOTIFICATION"/>
+            <xs:enumeration value="AUDIO_STREAM_BLUETOOTH_SCO"/>
+            <xs:enumeration value="AUDIO_STREAM_ENFORCED_AUDIBLE"/>
+            <xs:enumeration value="AUDIO_STREAM_DTMF"/>
+            <xs:enumeration value="AUDIO_STREAM_TTS"/>
+            <xs:enumeration value="AUDIO_STREAM_ACCESSIBILITY"/>
+            <xs:enumeration value="AUDIO_STREAM_REROUTING"/>
+            <xs:enumeration value="AUDIO_STREAM_PATCH"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <!-- Enum values of device_category from Volume.h.
+         TODO: generate from hidl to avoid manual sync. -->
+    <xs:simpleType name="deviceCategory">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="DEVICE_CATEGORY_HEADSET"/>
+            <xs:enumeration value="DEVICE_CATEGORY_SPEAKER"/>
+            <xs:enumeration value="DEVICE_CATEGORY_EARPIECE"/>
+            <xs:enumeration value="DEVICE_CATEGORY_EXT_MEDIA"/>
+            <xs:enumeration value="DEVICE_CATEGORY_HEARING_AID"/>
+        </xs:restriction>
+    </xs:simpleType>
+    <xs:complexType name="volume">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Volume section defines a volume curve for a given use case and device category.
+                It contains a list of points of this curve expressing the attenuation in Millibels
+                for a given volume index from 0 to 100.
+                <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER">
+                    <point>0,-9600</point>
+                    <point>100,0</point>
+                </volume>
+
+                It may also reference a reference/@name to avoid duplicating curves.
+                <volume stream="AUDIO_STREAM_MUSIC" deviceCategory="DEVICE_CATEGORY_SPEAKER"
+                        ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+                <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+                    <point>0,-9600</point>
+                    <point>100,0</point>
+                </reference>
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="point" type="volumePoint" minOccurs="0" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="stream" type="stream"/>
+        <xs:attribute name="deviceCategory" type="deviceCategory"/>
+        <xs:attribute name="ref" type="xs:token" use="optional"/>
+    </xs:complexType>
+    <xs:complexType name="reference">
+        <xs:sequence>
+            <xs:element name="point" type="volumePoint" minOccurs="2" maxOccurs="unbounded"/>
+        </xs:sequence>
+        <xs:attribute name="name" type="xs:token" use="required"/>
+    </xs:complexType>
+    <xs:complexType name="surroundSound">
+        <xs:annotation>
+            <xs:documentation xml:lang="en">
+                Surround Sound section provides configuration related to handling of
+                multi-channel formats.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="formats" type="surroundFormats"/>
+        </xs:sequence>
+    </xs:complexType>
+    <xs:simpleType name="surroundFormatsList">
+        <xs:list itemType="audioFormat" />
+    </xs:simpleType>
+    <xs:complexType name="surroundFormats">
+        <xs:sequence>
+            <xs:element name="format" minOccurs="0" maxOccurs="unbounded">
+                <xs:complexType>
+                    <xs:attribute name="name" type="audioFormat" use="required"/>
+                    <xs:attribute name="subformats" type="surroundFormatsList" />
+                </xs:complexType>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+</xs:schema>
diff --git a/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.impl.h b/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.impl.h
index 8ab7350..632e816 100644
--- a/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.impl.h
+++ b/audio/common/all-versions/default/include/common/all-versions/default/HidlUtils.impl.h
@@ -174,9 +174,9 @@
             config->ext.mix.hwModule = halConfig.ext.mix.hw_module;
             config->ext.mix.ioHandle = halConfig.ext.mix.handle;
             if (halConfig.role == AUDIO_PORT_ROLE_SOURCE) {
-                config->ext.mix.useCase.source = AudioSource(halConfig.ext.mix.usecase.source);
-            } else if (halConfig.role == AUDIO_PORT_ROLE_SINK) {
                 config->ext.mix.useCase.stream = AudioStreamType(halConfig.ext.mix.usecase.stream);
+            } else if (halConfig.role == AUDIO_PORT_ROLE_SINK) {
+                config->ext.mix.useCase.source = AudioSource(halConfig.ext.mix.usecase.source);
             }
             break;
         }
@@ -212,11 +212,11 @@
             halConfig->ext.mix.hw_module = config.ext.mix.hwModule;
             halConfig->ext.mix.handle = config.ext.mix.ioHandle;
             if (config.role == AudioPortRole::SOURCE) {
-                halConfig->ext.mix.usecase.source =
-                    static_cast<audio_source_t>(config.ext.mix.useCase.source);
-            } else if (config.role == AudioPortRole::SINK) {
                 halConfig->ext.mix.usecase.stream =
                     static_cast<audio_stream_type_t>(config.ext.mix.useCase.stream);
+            } else if (config.role == AudioPortRole::SINK) {
+                halConfig->ext.mix.usecase.source =
+                    static_cast<audio_source_t>(config.ext.mix.useCase.source);
             }
             break;
         }
diff --git a/audio/common/all-versions/default/service/Android.mk b/audio/common/all-versions/default/service/Android.mk
index e48a2a5..84de75e 100644
--- a/audio/common/all-versions/default/service/Android.mk
+++ b/audio/common/all-versions/default/service/Android.mk
@@ -31,12 +31,14 @@
 LOCAL_CFLAGS := -Wall -Werror
 
 LOCAL_SHARED_LIBRARIES := \
+    libcutils \
     libbinder \
     libhidlbase \
     libhidltransport \
     liblog \
     libutils \
     libhardware \
+    libhwbinder \
     android.hardware.audio@2.0 \
     android.hardware.audio@4.0 \
     android.hardware.audio.common@2.0 \
diff --git a/audio/common/all-versions/default/service/service.cpp b/audio/common/all-versions/default/service/service.cpp
index c7ce638..ff1394e 100644
--- a/audio/common/all-versions/default/service/service.cpp
+++ b/audio/common/all-versions/default/service/service.cpp
@@ -24,16 +24,26 @@
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
 #include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
 #include <binder/ProcessState.h>
+#include <cutils/properties.h>
 #include <hidl/HidlTransportSupport.h>
 #include <hidl/LegacySupport.h>
+#include <hwbinder/ProcessState.h>
 
 using namespace android::hardware;
 using android::OK;
 
 int main(int /* argc */, char* /* argv */ []) {
-    android::ProcessState::initWithDriver("/dev/vndbinder");
+    ::android::ProcessState::initWithDriver("/dev/vndbinder");
     // start a threadpool for vndbinder interactions
-    android::ProcessState::self()->startThreadPool();
+    ::android::ProcessState::self()->startThreadPool();
+
+    const int32_t defaultValue = -1;
+    int32_t value =
+        property_get_int32("persist.vendor.audio.service.hwbinder.size_kbyte", defaultValue);
+    if (value != defaultValue) {
+        ALOGD("Configuring hwbinder with mmap size %d KBytes", value);
+        ProcessState::initWithMmapSize(static_cast<size_t>(value) * 1024);
+    }
     configureRpcThreadpool(16, true /*callerWillJoin*/);
 
     bool fail = registerPassthroughServiceImplementation<audio::V4_0::IDevicesFactory>() != OK &&
diff --git a/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
index 8a8338b..f1e0b21 100644
--- a/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
@@ -65,8 +65,8 @@
 using ::android::hardware::hidl_handle;
 using ::android::hardware::hidl_string;
 using ::android::hardware::hidl_vec;
-using ::android::hardware::kSynchronizedReadWrite;
 using ::android::hardware::IPCThreadState;
+using ::android::hardware::kSynchronizedReadWrite;
 using ::android::hardware::MessageQueue;
 using ::android::hardware::MQDescriptorSync;
 using ::android::hardware::Return;
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Device.h b/audio/core/all-versions/default/include/core/all-versions/default/Device.h
index eb53b48..222d3de 100644
--- a/audio/core/all-versions/default/include/core/all-versions/default/Device.h
+++ b/audio/core/all-versions/default/include/core/all-versions/default/Device.h
@@ -124,7 +124,8 @@
     Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override;
 
     // Utility methods for extending interfaces.
-    Result analyzeStatus(const char* funcName, int status);
+    Result analyzeStatus(const char* funcName, int status,
+                         const std::vector<int>& ignoreErrors = {});
     void closeInputStream(audio_stream_in_t* stream);
     void closeOutputStream(audio_stream_out_t* stream);
     audio_hw_device_t* device() const { return mDevice; }
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/Device.impl.h b/audio/core/all-versions/default/include/core/all-versions/default/Device.impl.h
index 230b8de..52d2186 100644
--- a/audio/core/all-versions/default/include/core/all-versions/default/Device.impl.h
+++ b/audio/core/all-versions/default/include/core/all-versions/default/Device.impl.h
@@ -40,8 +40,9 @@
     mDevice = nullptr;
 }
 
-Result Device::analyzeStatus(const char* funcName, int status) {
-    return util::analyzeStatus("Device", funcName, status);
+Result Device::analyzeStatus(const char* funcName, int status,
+                             const std::vector<int>& ignoreErrors) {
+    return util::analyzeStatus("Device", funcName, status, ignoreErrors);
 }
 
 void Device::closeInputStream(audio_stream_in_t* stream) {
@@ -155,7 +156,8 @@
     }
     AudioConfig suggestedConfig;
     HidlUtils::audioConfigFromHal(halConfig, &suggestedConfig);
-    _hidl_cb(analyzeStatus("open_output_stream", status), streamOut, suggestedConfig);
+    _hidl_cb(analyzeStatus("open_output_stream", status, {EINVAL} /* ignore */), streamOut,
+             suggestedConfig);
     return Void();
 }
 
@@ -183,7 +185,8 @@
     }
     AudioConfig suggestedConfig;
     HidlUtils::audioConfigFromHal(halConfig, &suggestedConfig);
-    _hidl_cb(analyzeStatus("open_input_stream", status), streamIn, suggestedConfig);
+    _hidl_cb(analyzeStatus("open_input_stream", status, {EINVAL} /* ignore */), streamIn,
+             suggestedConfig);
     return Void();
 }
 
diff --git a/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h b/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h
index 43e5d6e..a9f59fb 100644
--- a/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h
+++ b/audio/core/all-versions/default/include/core/all-versions/default/DevicesFactory.impl.h
@@ -106,8 +106,8 @@
     return rc;
 }
 
-IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* /* name */) {
-    return new DevicesFactory();
+IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* name) {
+    return strcmp(name, "default") == 0 ? new DevicesFactory() : nullptr;
 }
 
 }  // namespace implementation
diff --git a/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h b/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h
index b0351c9..f3256f1 100644
--- a/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h
+++ b/audio/effect/all-versions/default/include/effect/all-versions/default/EffectsFactory.impl.h
@@ -184,8 +184,8 @@
     return Void();
 }
 
-IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* /* name */) {
-    return new EffectsFactory();
+IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* name) {
+    return strcmp(name, "default") == 0 ? new EffectsFactory() : nullptr;
 }
 
 }  // namespace implementation
diff --git a/automotive/vehicle/2.0/Android.bp b/automotive/vehicle/2.0/Android.bp
index 6af774e..f64028c 100644
--- a/automotive/vehicle/2.0/Android.bp
+++ b/automotive/vehicle/2.0/Android.bp
@@ -30,7 +30,6 @@
         "StatusCode",
         "SubscribeFlags",
         "SubscribeOptions",
-        "VehicleApPowerBootupReason",
         "VehicleApPowerStateConfigFlag",
         "VehicleApPowerStateReport",
         "VehicleApPowerStateReq",
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 22ab079..7802ef0 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -58,12 +58,14 @@
     vendor: true,
     defaults: ["vhal_v2_0_defaults"],
     srcs: [
+        "impl/vhal_v2_0/CommConn.cpp",
         "impl/vhal_v2_0/EmulatedVehicleHal.cpp",
         "impl/vhal_v2_0/VehicleEmulator.cpp",
         "impl/vhal_v2_0/PipeComm.cpp",
         "impl/vhal_v2_0/SocketComm.cpp",
         "impl/vhal_v2_0/LinearFakeValueGenerator.cpp",
         "impl/vhal_v2_0/JsonFakeValueGenerator.cpp",
+        "impl/vhal_v2_0/GeneratorHub.cpp",
     ],
     local_include_dirs: ["common/include/vhal_v2_0"],
     export_include_dirs: ["impl"],
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommBase.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommBase.h
deleted file mode 100644
index 6832ad3..0000000
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommBase.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_
-#define android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_
-
-#include <string>
-#include <vector>
-
-namespace android {
-namespace hardware {
-namespace automotive {
-namespace vehicle {
-namespace V2_0 {
-
-namespace impl {
-
-/**
- * This is the communications base class.  It defines the interface used in DefaultVehicleHal to
- * send and receive data to and from the emulator.
- */
-class CommBase {
-public:
-    virtual ~CommBase() = default;
-
-    /**
-     * Closes a connection if it is open.
-     */
-    virtual void stop() {}
-
-    /**
-     * Creates a connection to the other side.
-     *
-     * @return int Returns fd or socket number if connection is successful.
-     *              Otherwise, returns -1 if no connection is availble.
-     */
-    virtual int connect() { return 0; }
-
-    /**
-     * Opens the communications channel.
-     *
-     * @return int Returns 0 if channel is opened, else -errno if failed.
-     */
-    virtual int open() = 0;
-
-    /**
-     * Blocking call to read data from the connection.
-     *
-     * @return std::vector<uint8_t> Serialized protobuf data received from emulator.  This will be
-     *              an empty vector if the connection was closed or some other error occurred.
-     */
-    virtual std::vector<uint8_t> read() = 0;
-
-    /**
-     * Transmits a string of data to the emulator.
-     *
-     * @param data Serialized protobuf data to transmit.
-     *
-     * @return int Number of bytes transmitted, or -1 if failed.
-     */
-    virtual int write(const std::vector<uint8_t>& data) = 0;
-};
-
-}  // impl
-
-}  // namespace V2_0
-}  // namespace vehicle
-}  // namespace automotive
-}  // namespace hardware
-}  // namespace android
-
-
-#endif  // android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_
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
new file mode 100644
index 0000000..bf1de81
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CommConn"
+
+#include <thread>
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <log/log.h>
+
+#include "CommConn.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+void CommConn::start() {
+    mReadThread = std::make_unique<std::thread>(std::bind(&CommConn::readThread, this));
+}
+
+void CommConn::stop() {
+    if (mReadThread->joinable()) {
+        mReadThread->join();
+    }
+}
+
+void CommConn::sendMessage(emulator::EmulatorMessage const& msg) {
+    int numBytes = msg.ByteSize();
+    std::vector<uint8_t> buffer(static_cast<size_t>(numBytes));
+    if (!msg.SerializeToArray(buffer.data(), numBytes)) {
+        ALOGE("%s: SerializeToString failed!", __func__);
+        return;
+    }
+
+    write(buffer);
+}
+
+void CommConn::readThread() {
+    std::vector<uint8_t> buffer;
+    while (isOpen()) {
+        buffer = read();
+        if (buffer.size() == 0) {
+            ALOGI("%s: Read returned empty message, exiting read loop.", __func__);
+            break;
+        }
+
+        emulator::EmulatorMessage rxMsg;
+        if (rxMsg.ParseFromArray(buffer.data(), static_cast<int32_t>(buffer.size()))) {
+            emulator::EmulatorMessage respMsg;
+            mMessageProcessor->processMessage(rxMsg, respMsg);
+
+            sendMessage(respMsg);
+        }
+    }
+}
+
+}  // 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/CommConn.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h
new file mode 100644
index 0000000..87b0dfc
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/CommConn.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include "VehicleHalProto.pb.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+/**
+ * MessageProcess is an interface implemented by VehicleEmulator to process messages received
+ * over a CommConn.
+ */
+class MessageProcessor {
+   public:
+    virtual ~MessageProcessor() = default;
+
+    /**
+     * 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;
+};
+
+/**
+ * This is the interface that both PipeComm and SocketComm use to represent a connection. The
+ * connection will listen for commands on a separate 'read' thread.
+ */
+class CommConn {
+   public:
+    CommConn(MessageProcessor* messageProcessor) : mMessageProcessor(messageProcessor) {}
+
+    virtual ~CommConn() {}
+
+    /**
+     * Start the read thread reading messages from this connection.
+     */
+    virtual void start();
+
+    /**
+     * Closes a connection if it is open.
+     */
+    virtual void stop();
+
+    /**
+     * Returns true if the connection is open and available to send/receive.
+     */
+    virtual bool isOpen() = 0;
+
+    /**
+     * Blocking call to read data from the connection.
+     *
+     * @return std::vector<uint8_t> Serialized protobuf data received from emulator.  This will be
+     *              an empty vector if the connection was closed or some other error occurred.
+     */
+    virtual std::vector<uint8_t> read() = 0;
+
+    /**
+     * Transmits a string of data to the emulator.
+     *
+     * @param data Serialized protobuf data to transmit.
+     *
+     * @return int Number of bytes transmitted, or -1 if failed.
+     */
+    virtual int write(const std::vector<uint8_t>& data) = 0;
+
+    /**
+     * Serialized and send the given message to the other side.
+     */
+    void sendMessage(emulator::EmulatorMessage const& msg);
+
+   protected:
+    std::unique_ptr<std::thread> mReadThread;
+    MessageProcessor* mMessageProcessor;
+
+    /**
+     * A thread that reads messages in a loop, and responds. You can stop this thread by calling
+     * stop().
+     */
+    void readThread();
+};
+
+}  // namespace impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_V2_0_impl_CommBase_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index eb9d660..5007a6d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -34,6 +34,13 @@
 constexpr int AP_POWER_STATE_REPORT = (int)VehicleProperty::AP_POWER_STATE_REPORT;
 constexpr int DOOR_1_LEFT = (int)VehicleAreaDoor::ROW_1_LEFT;
 constexpr int DOOR_1_RIGHT = (int)VehicleAreaDoor::ROW_1_RIGHT;
+constexpr int DOOR_2_LEFT = (int)VehicleAreaDoor::ROW_2_LEFT;
+constexpr int DOOR_2_RIGHT = (int)VehicleAreaDoor::ROW_2_RIGHT;
+constexpr int WINDOW_1_LEFT = (int)VehicleAreaWindow::ROW_1_LEFT;
+constexpr int WINDOW_2_LEFT = (int)VehicleAreaWindow::ROW_2_LEFT;
+constexpr int WINDOW_2_RIGHT = (int)VehicleAreaWindow::ROW_2_RIGHT;
+constexpr int FAN_DIRECTION_FACE = (int)VehicleHvacFanDirection::FACE;
+constexpr int FAN_DIRECTION_FLOOR = (int)VehicleHvacFanDirection::FLOOR;
 constexpr int OBD2_LIVE_FRAME = (int)VehicleProperty::OBD2_LIVE_FRAME;
 constexpr int OBD2_FREEZE_FRAME = (int)VehicleProperty::OBD2_FREEZE_FRAME;
 constexpr int OBD2_FREEZE_FRAME_INFO = (int)VehicleProperty::OBD2_FREEZE_FRAME_INFO;
@@ -44,10 +51,28 @@
 constexpr int ALL_WHEELS =
     (int)(VehicleAreaWheel::LEFT_FRONT | VehicleAreaWheel::RIGHT_FRONT |
           VehicleAreaWheel::LEFT_REAR | VehicleAreaWheel::RIGHT_REAR);
+constexpr int SEAT_1_LEFT = (int)(VehicleAreaSeat::ROW_1_LEFT);
+constexpr int SEAT_1_RIGHT = (int)(VehicleAreaSeat::ROW_1_RIGHT);
 constexpr int HVAC_LEFT = (int)(VehicleAreaSeat::ROW_1_LEFT | VehicleAreaSeat::ROW_2_LEFT |
                                 VehicleAreaSeat::ROW_2_CENTER);
 constexpr int HVAC_RIGHT = (int)(VehicleAreaSeat::ROW_1_RIGHT | VehicleAreaSeat::ROW_2_RIGHT);
 constexpr int HVAC_ALL = HVAC_LEFT | HVAC_RIGHT;
+constexpr int VENDOR_EXTENSION_BOOLEAN_PROPERTY =
+    (int)(0x101 | VehiclePropertyGroup::VENDOR | VehiclePropertyType::BOOLEAN | VehicleArea::DOOR);
+constexpr int VENDOR_EXTENSION_FLOAT_PROPERTY =
+    (int)(0x102 | VehiclePropertyGroup::VENDOR | VehiclePropertyType::FLOAT | VehicleArea::SEAT);
+constexpr int VENDOR_EXTENSION_INT_PROPERTY =
+    (int)(0x103 | VehiclePropertyGroup::VENDOR | VehiclePropertyType::INT32 | VehicleArea::WINDOW);
+constexpr int VENDOR_EXTENSION_STRING_PROPERTY =
+    (int)(0x104 | VehiclePropertyGroup::VENDOR | VehiclePropertyType::STRING | VehicleArea::GLOBAL);
+constexpr int FUEL_DOOR_REAR_LEFT = (int)PortLocationType::REAR_LEFT;
+constexpr int CHARGE_PORT_FRONT_LEFT = (int)PortLocationType::FRONT_LEFT;
+constexpr int LIGHT_STATE_ON = (int)VehicleLightState::ON;
+constexpr int LIGHT_SWITCH_AUTO = (int)VehicleLightSwitch::AUTOMATIC;
+constexpr int WHEEL_FRONT_LEFT = (int)VehicleAreaWheel::LEFT_FRONT;
+constexpr int WHEEL_FRONT_RIGHT = (int)VehicleAreaWheel::RIGHT_FRONT;
+constexpr int WHEEL_REAR_LEFT = (int)VehicleAreaWheel::LEFT_REAR;
+constexpr int WHEEL_REAR_RIGHT = (int)VehicleAreaWheel::RIGHT_REAR;
 
 /**
  * This property is used for test purpose to generate fake events. Here is the test package that
@@ -70,33 +95,39 @@
 enum class FakeDataCommand : int32_t {
     /**
      * Starts linear fake data generation. Caller must provide additional data:
-     *     int32Values[1] - VehicleProperty to which command applies
+     *     int32Values[1] - vehicle property to which command applies
      *     int64Values[0] - periodic interval in nanoseconds
      *     floatValues[0] - initial value
      *     floatValues[1] - dispersion defines the min/max value relative to initial value, where
      *                      max = initial_value + dispersion, min = initial_value - dispersion.
      *                      Dispersion should be non-negative, otherwise the behavior is undefined.
      *     floatValues[2] - increment, with every timer tick the value will be incremented by this
-     *                      amount. When reaching to max value, the current value will be set to min.
-     *                      It should be non-negative, otherwise the behavior is undefined.
+     *                      amount. When reaching to max value, the current value will be set to
+     *                      min. It should be non-negative, otherwise the behavior is undefined.
      */
     StartLinear = 0,
 
-    /** Stops generating of fake data that was triggered by Start commands.
-     *     int32Values[1] - VehicleProperty to which command applies. VHAL will stop the
+    /** Stops linear fake data generation that was triggered by StartLinear commands.
+     *     int32Values[1] - vehicle property to which command applies. VHAL will stop the
      *                      corresponding linear generation for that property.
      */
     StopLinear = 1,
 
     /**
-     * Starts JSON-based fake data generation. Caller must provide a string value specifying
-     * the path to fake value JSON file:
+     * Starts JSON-based fake data generation. It iterates through JSON-encoded VHAL events from a
+     * file and inject them to VHAL. The iteration can be repeated multiple times or infinitely.
+     * Caller must provide additional data:
+     *     int32Values[1] - number of iterations. If it is not provided or -1. The iteration will be
+     *                      repeated infinite times.
      *     stringValue    - path to the fake values JSON file
      */
     StartJson = 2,
 
     /**
-     * Stops JSON-based fake data generation. No additional arguments needed.
+     * Stops JSON-based fake data generation. As multiple JSON-based generation can happen at the
+     * same time. Caller must provide the path of fake value JSON file to stop the corresponding
+     * generation:
+     *     stringValue    - path to the fake values JSON file
      */
     StopJson = 3,
 
@@ -133,8 +164,9 @@
              .prop = toInt(VehicleProperty::INFO_FUEL_CAPACITY),
              .access = VehiclePropertyAccess::READ,
              .changeMode = VehiclePropertyChangeMode::STATIC,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
          },
-     .initialValue = {.floatValues = {15000}}},
+     .initialValue = {.floatValues = {15000.0f}}},
 
     {.config =
          {
@@ -149,8 +181,9 @@
              .prop = toInt(VehicleProperty::INFO_EV_BATTERY_CAPACITY),
              .access = VehiclePropertyAccess::READ,
              .changeMode = VehiclePropertyChangeMode::STATIC,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
          },
-     .initialValue = {.floatValues = {150000}}},
+     .initialValue = {.floatValues = {150000.0f}}},
 
     {.config =
          {
@@ -162,6 +195,24 @@
 
     {.config =
          {
+             .prop = toInt(VehicleProperty::INFO_FUEL_DOOR_LOCATION),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::STATIC,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+         },
+     .initialValue = {.int32Values = {FUEL_DOOR_REAR_LEFT}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::INFO_EV_PORT_LOCATION),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::STATIC,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+         },
+     .initialValue = {.int32Values = {CHARGE_PORT_FRONT_LEFT}}},
+
+    {.config =
+         {
              .prop = toInt(VehicleProperty::INFO_MAKE),
              .access = VehiclePropertyAccess::READ,
              .changeMode = VehiclePropertyChangeMode::STATIC,
@@ -179,6 +230,16 @@
 
     {.config =
          {
+             .prop = toInt(VehicleProperty::INFO_DRIVER_SEAT),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::STATIC,
+             // this was a zoned property on an old vhal, but it is meant to be global
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+         },
+     .initialValue = {.int32Values = {SEAT_1_LEFT}}},
+
+    {.config =
+         {
              .prop = toInt(VehicleProperty::PERF_ODOMETER),
              .access = VehiclePropertyAccess::READ,
              .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -202,14 +263,16 @@
              .prop = toInt(VehicleProperty::FUEL_LEVEL),
              .access = VehiclePropertyAccess::READ,
              .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
          },
-     .initialValue = {.floatValues = {15000}}},
+     .initialValue = {.floatValues = {15000.0f}}},
 
     {.config =
          {
              .prop = toInt(VehicleProperty::FUEL_DOOR_OPEN),
-             .access = VehiclePropertyAccess::READ,
+             .access = VehiclePropertyAccess::READ_WRITE,
              .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
          },
      .initialValue = {.int32Values = {0}}},
 
@@ -218,14 +281,16 @@
              .prop = toInt(VehicleProperty::EV_BATTERY_LEVEL),
              .access = VehiclePropertyAccess::READ,
              .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
          },
-     .initialValue = {.floatValues = {150000}}},
+     .initialValue = {.floatValues = {150000.0f}}},
 
     {.config =
          {
              .prop = toInt(VehicleProperty::EV_CHARGE_PORT_OPEN),
-             .access = VehiclePropertyAccess::READ,
+             .access = VehiclePropertyAccess::READ_WRITE,
              .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
          },
      .initialValue = {.int32Values = {0}}},
 
@@ -234,6 +299,7 @@
              .prop = toInt(VehicleProperty::EV_CHARGE_PORT_CONNECTED),
              .access = VehiclePropertyAccess::READ,
              .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
          },
      .initialValue = {.int32Values = {0}}},
 
@@ -242,8 +308,37 @@
              .prop = toInt(VehicleProperty::EV_BATTERY_INSTANTANEOUS_CHARGE_RATE),
              .access = VehiclePropertyAccess::READ,
              .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
          },
-     .initialValue = {.floatValues = {0}}},
+     .initialValue = {.floatValues = {0.0f}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::RANGE_REMAINING),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+         },
+     .initialValue = {.floatValues = {100.0f}}},  // units in meters
+
+    {.config =
+         {.prop = toInt(VehicleProperty::TIRE_PRESSURE),
+          .access = VehiclePropertyAccess::READ,
+          .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+          .areaConfigs =
+              {VehicleAreaConfig{
+                   .areaId = WHEEL_FRONT_LEFT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f,
+               },
+               VehicleAreaConfig{
+                   .areaId = WHEEL_FRONT_RIGHT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f,
+               },
+               VehicleAreaConfig{
+                   .areaId = WHEEL_REAR_LEFT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f,
+               },
+               VehicleAreaConfig{
+                   .areaId = WHEEL_REAR_RIGHT, .minFloatValue = 100.0f, .maxFloatValue = 300.0f,
+               }}},
+     .initialValue = {.floatValues = {200}}},  // units in kPa
 
     {.config =
          {
@@ -266,6 +361,7 @@
              .prop = toInt(VehicleProperty::FUEL_LEVEL_LOW),
              .access = VehiclePropertyAccess::READ,
              .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
          },
      .initialValue = {.int32Values = {0}}},
 
@@ -355,6 +451,24 @@
                 .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
      .initialValue = {.int32Values = {toInt(VehicleHvacFanDirection::FACE)}}},
 
+    {.config = {.prop = toInt(VehicleProperty::HVAC_FAN_DIRECTION_AVAILABLE),
+                .access = VehiclePropertyAccess::READ,
+                .changeMode = VehiclePropertyChangeMode::STATIC,
+                .areaConfigs = {VehicleAreaConfig{.areaId = HVAC_ALL}}},
+     .initialValue = {.int32Values = {FAN_DIRECTION_FACE, FAN_DIRECTION_FLOOR,
+                                      FAN_DIRECTION_FACE | FAN_DIRECTION_FLOOR}}},
+
+    {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_VENTILATION),
+                .access = VehiclePropertyAccess::READ_WRITE,
+                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                .areaConfigs = {VehicleAreaConfig{
+                                    .areaId = SEAT_1_LEFT, .minInt32Value = 0, .maxInt32Value = 3,
+                                },
+                                VehicleAreaConfig{
+                                    .areaId = SEAT_1_RIGHT, .minInt32Value = 0, .maxInt32Value = 3,
+                                }}},
+     .initialValue = {.int32Values = {0}}},  // 0 is off and +ve values indicate ventilation level.
+
     {.config = {.prop = toInt(VehicleProperty::HVAC_STEERING_WHEEL_HEAT),
                 .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -362,14 +476,29 @@
                     .areaId = (0), .minInt32Value = -2, .maxInt32Value = 2}}},
      .initialValue = {.int32Values = {0}}},  // +ve values for heating and -ve for cooling
 
+    {.config = {.prop = toInt(VehicleProperty::HVAC_SEAT_TEMPERATURE),
+                .access = VehiclePropertyAccess::READ_WRITE,
+                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                .areaConfigs = {VehicleAreaConfig{
+                                    .areaId = SEAT_1_LEFT, .minInt32Value = -2, .maxInt32Value = 2,
+                                },
+                                VehicleAreaConfig{
+                                    .areaId = SEAT_1_RIGHT, .minInt32Value = -2, .maxInt32Value = 2,
+                                }}},
+     .initialValue = {.int32Values = {0}}},  // +ve values for heating and -ve for cooling
+
     {.config = {.prop = toInt(VehicleProperty::HVAC_TEMPERATURE_SET),
                 .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
                 .areaConfigs = {VehicleAreaConfig{
-                                    .areaId = HVAC_LEFT, .minFloatValue = 16, .maxFloatValue = 32,
+                                    .areaId = HVAC_LEFT,
+                                    .minFloatValue = 16,
+                                    .maxFloatValue = 32,
                                 },
                                 VehicleAreaConfig{
-                                    .areaId = HVAC_RIGHT, .minFloatValue = 16, .maxFloatValue = 32,
+                                    .areaId = HVAC_RIGHT,
+                                    .minFloatValue = 16,
+                                    .maxFloatValue = 32,
                                 }}},
      .initialAreaValues = {{HVAC_LEFT, {.floatValues = {16}}},
                            {HVAC_RIGHT, {.floatValues = {20}}}}},
@@ -443,13 +572,20 @@
     },
 
     {.config = {.prop = toInt(VehicleProperty::DOOR_LOCK),
-                .access = VehiclePropertyAccess::READ,
+                .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
                 .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT},
                                 VehicleAreaConfig{.areaId = DOOR_1_RIGHT}}},
      .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}},
                            {DOOR_1_RIGHT, {.int32Values = {1}}}}},
 
+    {.config = {.prop = toInt(VehicleProperty::WINDOW_LOCK),
+                .access = VehiclePropertyAccess::READ_WRITE,
+                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                .areaConfigs = {VehicleAreaConfig{.areaId = WINDOW_1_LEFT | WINDOW_2_LEFT |
+                                                            WINDOW_2_RIGHT}}},
+     .initialAreaValues = {{WINDOW_1_LEFT | WINDOW_2_LEFT | WINDOW_2_RIGHT, {.int32Values = {0}}}}},
+
     {.config =
          {
              .prop = WHEEL_TICK,
@@ -475,12 +611,12 @@
                 .access = VehiclePropertyAccess::READ,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
                 .configArray = {3}},
-     .initialValue = {.int32Values = {toInt(VehicleApPowerStateReq::ON_FULL), 0}}},
+     .initialValue = {.int32Values = {toInt(VehicleApPowerStateReq::ON), 0}}},
 
     {.config = {.prop = toInt(VehicleProperty::AP_POWER_STATE_REPORT),
                 .access = VehiclePropertyAccess::WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
-     .initialValue = {.int32Values = {toInt(VehicleApPowerStateReport::BOOT_COMPLETE), 0}}},
+     .initialValue = {.int32Values = {toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL), 0}}},
 
     {.config = {.prop = toInt(VehicleProperty::DISPLAY_BRIGHTNESS),
                 .access = VehiclePropertyAccess::READ_WRITE,
@@ -488,11 +624,6 @@
                 .areaConfigs = {VehicleAreaConfig{.minInt32Value = 0, .maxInt32Value = 100}}},
      .initialValue = {.int32Values = {100}}},
 
-    {.config = {.prop = toInt(VehicleProperty::AP_POWER_BOOTUP_REASON),
-                .access = VehiclePropertyAccess::READ,
-                .changeMode = VehiclePropertyChangeMode::STATIC},
-     .initialValue = {.int32Values = {toInt(VehicleApPowerBootupReason::USER_POWER_ON)}}},
-
     {
         .config = {.prop = OBD2_LIVE_FRAME,
                    .access = VehiclePropertyAccess::READ,
@@ -520,9 +651,126 @@
                    .configArray = {1}},
     },
 
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::HEADLIGHTS_STATE),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+         },
+     .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_STATE),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+         },
+     .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::FOG_LIGHTS_STATE),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+         },
+     .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::HAZARD_LIGHTS_STATE),
+             .access = VehiclePropertyAccess::READ,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+         },
+     .initialValue = {.int32Values = {LIGHT_STATE_ON}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::HEADLIGHTS_SWITCH),
+             .access = VehiclePropertyAccess::READ_WRITE,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+         },
+     .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::HIGH_BEAM_LIGHTS_SWITCH),
+             .access = VehiclePropertyAccess::READ_WRITE,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+         },
+     .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::FOG_LIGHTS_SWITCH),
+             .access = VehiclePropertyAccess::READ_WRITE,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+         },
+     .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
+
+    {.config =
+         {
+             .prop = toInt(VehicleProperty::HAZARD_LIGHTS_SWITCH),
+             .access = VehiclePropertyAccess::READ_WRITE,
+             .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+             .areaConfigs = {VehicleAreaConfig{.areaId = (0)}},
+         },
+     .initialValue = {.int32Values = {LIGHT_SWITCH_AUTO}}},
+
     {.config = {.prop = VEHICLE_MAP_SERVICE,
                 .access = VehiclePropertyAccess::READ_WRITE,
                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE}},
+
+    // Example Vendor Extension properties for testing
+    {.config = {.prop = VENDOR_EXTENSION_BOOLEAN_PROPERTY,
+                .access = VehiclePropertyAccess::READ_WRITE,
+                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                .areaConfigs = {VehicleAreaConfig{.areaId = DOOR_1_LEFT},
+                                VehicleAreaConfig{.areaId = DOOR_1_RIGHT},
+                                VehicleAreaConfig{.areaId = DOOR_2_LEFT},
+                                VehicleAreaConfig{.areaId = DOOR_2_RIGHT}}},
+     .initialAreaValues = {{DOOR_1_LEFT, {.int32Values = {1}}},
+                           {DOOR_1_RIGHT, {.int32Values = {1}}},
+                           {DOOR_2_LEFT, {.int32Values = {0}}},
+                           {DOOR_2_RIGHT, {.int32Values = {0}}}}},
+
+    {.config = {.prop = VENDOR_EXTENSION_FLOAT_PROPERTY,
+                .access = VehiclePropertyAccess::READ_WRITE,
+                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                .areaConfigs = {VehicleAreaConfig{
+                                    .areaId = HVAC_LEFT, .minFloatValue = -10, .maxFloatValue = 10},
+                                VehicleAreaConfig{.areaId = HVAC_RIGHT,
+                                                  .minFloatValue = -10,
+                                                  .maxFloatValue = 10}}},
+     .initialAreaValues = {{HVAC_LEFT, {.floatValues = {1}}}, {HVAC_RIGHT, {.floatValues = {2}}}}},
+
+    {.config = {.prop = VENDOR_EXTENSION_INT_PROPERTY,
+                .access = VehiclePropertyAccess::READ_WRITE,
+                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                .areaConfigs = {VehicleAreaConfig{
+                                    .areaId = (int)VehicleAreaWindow::FRONT_WINDSHIELD,
+                                    .minInt32Value = -100,
+                                    .maxInt32Value = 100},
+                                VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::REAR_WINDSHIELD,
+                                                  .minInt32Value = -100,
+                                                  .maxInt32Value = 100},
+                                VehicleAreaConfig{.areaId = (int)VehicleAreaWindow::ROOF_TOP_1,
+                                                  .minInt32Value = -100,
+                                                  .maxInt32Value = 100}}},
+     .initialAreaValues = {{(int)VehicleAreaWindow::FRONT_WINDSHIELD, {.int32Values = {1}}},
+                           {(int)VehicleAreaWindow::REAR_WINDSHIELD, {.int32Values = {0}}},
+                           {(int)VehicleAreaWindow::ROOF_TOP_1, {.int32Values = {-1}}}}},
+
+    {.config = {.prop = VENDOR_EXTENSION_STRING_PROPERTY,
+                .access = VehiclePropertyAccess::READ_WRITE,
+                .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+     .initialValue = {.stringValue = "Vendor String Property"}},
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 07695bf..4f77348 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -92,10 +92,8 @@
       mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
       mRecurrentTimer(
           std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)),
-      mLinearFakeValueGenerator(std::make_unique<LinearFakeValueGenerator>(
-          std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1))),
-      mJsonFakeValueGenerator(std::make_unique<JsonFakeValueGenerator>(
-          std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1))) {
+      mGeneratorHub(
+          std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1)) {
     initStaticConfig();
     for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
         mPropStore->registerProperty(kVehicleProperties[i].config);
@@ -158,13 +156,6 @@
                 // Placeholder for future implementation of VMS property in the default hal. For
                 // now, just returns OK; otherwise, hal clients crash with property not supported.
                 return StatusCode::OK;
-            case AP_POWER_STATE_REPORT:
-                // This property has different behavior between get/set.  When it is set, the value
-                //  goes to the vehicle but is NOT updated in the property store back to Android.
-                // Commented out for now, because it may mess up automated testing that use the
-                //  emulator interface.
-                // getEmulatorOrDie()->doSetValueFromClient(propValue);
-                return StatusCode::OK;
         }
     }
 
@@ -189,6 +180,7 @@
     }
 
     getEmulatorOrDie()->doSetValueFromClient(propValue);
+    doHalEvent(getValuePool()->obtain(propValue));
 
     return StatusCode::OK;
 }
@@ -343,19 +335,54 @@
     switch (command) {
         case FakeDataCommand::StartLinear: {
             ALOGI("%s, FakeDataCommand::StartLinear", __func__);
-            return mLinearFakeValueGenerator->start(request);
+            if (v.int32Values.size() < 2) {
+                ALOGE("%s: expected property ID in int32Values", __func__);
+                return StatusCode::INVALID_ARG;
+            }
+            if (!v.int64Values.size()) {
+                ALOGE("%s: interval is not provided in int64Values", __func__);
+                return StatusCode::INVALID_ARG;
+            }
+            if (v.floatValues.size() < 3) {
+                ALOGE("%s: expected at least 3 elements in floatValues, got: %zu", __func__,
+                      v.floatValues.size());
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = v.int32Values[1];
+            mGeneratorHub.registerGenerator(cookie,
+                                            std::make_unique<LinearFakeValueGenerator>(request));
+            break;
         }
         case FakeDataCommand::StartJson: {
             ALOGI("%s, FakeDataCommand::StartJson", __func__);
-            return mJsonFakeValueGenerator->start(request);
+            if (v.stringValue.empty()) {
+                ALOGE("%s: path to JSON file is missing", __func__);
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = std::hash<std::string>()(v.stringValue);
+            mGeneratorHub.registerGenerator(cookie,
+                                            std::make_unique<JsonFakeValueGenerator>(request));
+            break;
         }
         case FakeDataCommand::StopLinear: {
             ALOGI("%s, FakeDataCommand::StopLinear", __func__);
-            return mLinearFakeValueGenerator->stop(request);
+            if (v.int32Values.size() < 2) {
+                ALOGE("%s: expected property ID in int32Values", __func__);
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = v.int32Values[1];
+            mGeneratorHub.unregisterGenerator(cookie);
+            break;
         }
         case FakeDataCommand::StopJson: {
             ALOGI("%s, FakeDataCommand::StopJson", __func__);
-            return mJsonFakeValueGenerator->stop(request);
+            if (v.stringValue.empty()) {
+                ALOGE("%s: path to JSON file is missing", __func__);
+                return StatusCode::INVALID_ARG;
+            }
+            int32_t cookie = std::hash<std::string>()(v.stringValue);
+            mGeneratorHub.unregisterGenerator(cookie);
+            break;
         }
         case FakeDataCommand::KeyPress: {
             ALOGI("%s, FakeDataCommand::KeyPress", __func__);
@@ -398,7 +425,7 @@
         mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus);
         auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode;
         if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) {
-            doHalEvent(move(updatedPropValue));
+            doHalEvent(std::move(updatedPropValue));
         }
     }
 }
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index c188aef..ec59690 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -30,8 +30,7 @@
 #include "vhal_v2_0/VehiclePropertyStore.h"
 
 #include "DefaultConfig.h"
-#include "FakeValueGenerator.h"
-
+#include "GeneratorHub.h"
 #include "VehicleEmulator.h"
 
 namespace android {
@@ -85,8 +84,7 @@
     VehiclePropertyStore* mPropStore;
     std::unordered_set<int32_t> mHvacPowerProps;
     RecurrentTimer mRecurrentTimer;
-    std::unique_ptr<FakeValueGenerator> mLinearFakeValueGenerator;
-    std::unique_ptr<FakeValueGenerator> mJsonFakeValueGenerator;
+    GeneratorHub mGeneratorHub;
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
index 1eeb88d..d6ad77d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
@@ -27,28 +27,22 @@
 
 namespace impl {
 
-using OnHalEvent = std::function<void(const VehiclePropValue& event)>;
-using MuxGuard = std::lock_guard<std::mutex>;
-
 class FakeValueGenerator {
 public:
     virtual ~FakeValueGenerator() = default;
-    /**
-     * Starts generating VHAL events
-     *
-     * @param request in VehiclePropValue with required information to start fake data generation
-     * @return StatusCode of the start request
-     */
-    virtual StatusCode start(const VehiclePropValue& request) = 0;
-    /**
-     * Stops generating VHAL events
-     * @param request in VehiclePropValue with required information to stop fake data generation
-     * @return StatusCode of the stop request
-     */
-    virtual StatusCode stop(const VehiclePropValue& request) = 0;
+
+    virtual VehiclePropValue nextEvent() = 0;
+
+    virtual bool hasNext() = 0;
 };
 
-}  // impl
+using Clock = std::chrono::steady_clock;
+using Nanos = std::chrono::nanoseconds;
+using TimePoint = std::chrono::time_point<Clock, Nanos>;
+
+using FakeValueGeneratorPtr = std::unique_ptr<FakeValueGenerator>;
+
+}  // namespace impl
 
 }  // namespace V2_0
 }  // namespace vehicle
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp
new file mode 100644
index 0000000..548285a
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GeneratorHub"
+
+#include <log/log.h>
+
+#include "GeneratorHub.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+GeneratorHub::GeneratorHub(const OnHalEvent& onHalEvent)
+    : mOnHalEvent(onHalEvent), mThread(&GeneratorHub::run, this) {}
+
+void GeneratorHub::registerGenerator(int32_t cookie, FakeValueGeneratorPtr generator) {
+    {
+        std::lock_guard<std::mutex> g(mLock);
+        // Register only if the generator can produce event
+        if (generator->hasNext()) {
+            // Push the next event if it is a new generator
+            if (mGenerators.find(cookie) == mGenerators.end()) {
+                ALOGI("%s: Registering new generator, cookie: %d", __func__, cookie);
+                mEventQueue.push({cookie, generator->nextEvent()});
+            }
+            mGenerators[cookie] = std::move(generator);
+            ALOGI("%s: Registered generator, cookie: %d", __func__, cookie);
+        }
+    }
+    mCond.notify_one();
+}
+
+void GeneratorHub::unregisterGenerator(int32_t cookie) {
+    {
+        std::lock_guard<std::mutex> g(mLock);
+        mGenerators.erase(cookie);
+    }
+    mCond.notify_one();
+    ALOGI("%s: Unregistered generator, cookie: %d", __func__, cookie);
+}
+
+void GeneratorHub::run() {
+    while (true) {
+        std::unique_lock<std::mutex> g(mLock);
+        // Pop events whose generator does not exist (may be already unregistered)
+        while (!mEventQueue.empty()
+               && mGenerators.find(mEventQueue.top().cookie) == mGenerators.end()) {
+             mEventQueue.pop();
+        }
+        // Wait until event queue is not empty
+        mCond.wait(g, [this] { return !mEventQueue.empty(); });
+
+        const VhalEvent& curEvent = mEventQueue.top();
+
+        TimePoint eventTime(Nanos(curEvent.val.timestamp));
+        // Wait until the soonest event happen
+        if (mCond.wait_until(g, eventTime) != std::cv_status::timeout) {
+        // It is possible that a new generator is registered and produced a sooner event, or current
+        // generator is unregistered, in this case the thread will re-evaluate the soonest event
+            ALOGI("Something happened while waiting");
+            continue;
+        }
+        // Now it's time to handle current event.
+        mOnHalEvent(curEvent.val);
+        // Update queue by popping current event and producing next event from the same generator
+        int32_t cookie = curEvent.cookie;
+        mEventQueue.pop();
+        if (hasNext(cookie)) {
+            mEventQueue.push({cookie, mGenerators[cookie]->nextEvent()});
+        } else {
+            ALOGI("%s: Generator ended, unregister it, cookie: %d", __func__, cookie);
+            mGenerators.erase(cookie);
+        }
+    }
+}
+
+bool GeneratorHub::hasNext(int32_t cookie) {
+    return mGenerators.find(cookie) != mGenerators.end() && mGenerators[cookie]->hasNext();
+}
+
+}  // 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/GeneratorHub.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.h
new file mode 100644
index 0000000..dcf6a4f
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/GeneratorHub.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_GeneratorHub_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_GeneratorHub_H_
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <iostream>
+#include <queue>
+#include <thread>
+#include <unordered_map>
+
+#include "FakeValueGenerator.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+/**
+ * This is the scheduler for all VHAL event generators. It manages all generators and uses priority
+ * queue to maintain generated events ordered by timestamp. The scheduler uses a single thread to
+ * keep querying and updating the event queue to make sure events from all generators are produced
+ * in order.
+ */
+class GeneratorHub {
+private:
+    struct VhalEvent {
+        int32_t cookie;  // Cookie is used to find the associated generator.
+        VehiclePropValue val;
+    };
+    // Comparator used by priority queue to keep track of soonest event.
+    struct GreaterByTime {
+        bool operator()(const VhalEvent& lhs, const VhalEvent& rhs) const {
+            return lhs.val.timestamp > rhs.val.timestamp;
+        }
+    };
+
+    using OnHalEvent = std::function<void(const VehiclePropValue& event)>;
+
+public:
+    GeneratorHub(const OnHalEvent& onHalEvent);
+    ~GeneratorHub() = default;
+
+    /**
+     * Register a new generator. The generator will be discarded if it could not produce next event.
+     * The existing generator will be overridden if it has the same cookie.
+     */
+    void registerGenerator(int32_t cookie, FakeValueGeneratorPtr generator);
+
+    void unregisterGenerator(int32_t cookie);
+
+private:
+    /**
+     * Main loop of the single thread to producing event and updating event queue.
+     */
+    void run();
+
+    bool hasNext(int32_t cookie);
+
+private:
+    std::priority_queue<VhalEvent, std::vector<VhalEvent>, GreaterByTime> mEventQueue;
+    std::unordered_map<int32_t, FakeValueGeneratorPtr> mGenerators;
+    OnHalEvent mOnHalEvent;
+
+    mutable std::mutex mLock;
+    std::condition_variable mCond;
+    std::thread mThread;
+};
+
+}  // namespace impl
+
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_V2_0_impl_GeneratorHub_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
index 88b8f86..b8fd2ba 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "JsonFakeValueGenerator"
 
 #include <fstream>
+#include <type_traits>
+#include <typeinfo>
 
 #include <log/log.h>
 #include <vhal_v2_0/VehicleUtils.h>
@@ -31,57 +33,48 @@
 
 namespace impl {
 
-JsonFakeValueGenerator::JsonFakeValueGenerator(const OnHalEvent& onHalEvent)
-    : mOnHalEvent(onHalEvent), mThread(&JsonFakeValueGenerator::loop, this) {}
-
-JsonFakeValueGenerator::~JsonFakeValueGenerator() {
-    mStopRequested = true;
-    {
-        MuxGuard g(mLock);
-        mGenCfg.index = 0;
-        mGenCfg.events.clear();
-    }
-    mCond.notify_one();
-    if (mThread.joinable()) {
-        mThread.join();
-    }
-}
-
-StatusCode JsonFakeValueGenerator::start(const VehiclePropValue& request) {
+JsonFakeValueGenerator::JsonFakeValueGenerator(const VehiclePropValue& request) {
     const auto& v = request.value;
-    if (v.stringValue.empty()) {
-        ALOGE("%s: path to JSON file is missing", __func__);
-        return StatusCode::INVALID_ARG;
-    }
     const char* file = v.stringValue.c_str();
     std::ifstream ifs(file);
     if (!ifs) {
         ALOGE("%s: couldn't open %s for parsing.", __func__, file);
-        return StatusCode::INTERNAL_ERROR;
     }
-    std::vector<VehiclePropValue> fakeVhalEvents = parseFakeValueJson(ifs);
-
-    {
-        MuxGuard g(mLock);
-        mGenCfg = {0, fakeVhalEvents};
-    }
-    mCond.notify_one();
-    return StatusCode::OK;
+    mGenCfg = {
+        .index = 0,
+        .events = parseFakeValueJson(ifs),
+    };
+    // Iterate infinitely if repetition number is not provided
+    mNumOfIterations = v.int32Values.size() < 2 ? -1 : v.int32Values[1];
 }
 
-StatusCode JsonFakeValueGenerator::stop(const VehiclePropValue& request) {
-    const auto& v = request.value;
-    if (!v.stringValue.empty()) {
-        ALOGI("%s: %s", __func__, v.stringValue.c_str());
+VehiclePropValue JsonFakeValueGenerator::nextEvent() {
+    VehiclePropValue generatedValue;
+    if (!hasNext()) {
+        return generatedValue;
     }
+    TimePoint eventTime = Clock::now();
+    if (mGenCfg.index != 0) {
+        // All events (start from 2nd one) are supposed to happen in the future with a delay
+        // equals to the duration between previous and current event.
+        eventTime += Nanos(mGenCfg.events[mGenCfg.index].timestamp -
+                           mGenCfg.events[mGenCfg.index - 1].timestamp);
+    }
+    generatedValue = mGenCfg.events[mGenCfg.index];
+    generatedValue.timestamp = eventTime.time_since_epoch().count();
 
-    {
-        MuxGuard g(mLock);
+    mGenCfg.index++;
+    if (mGenCfg.index == mGenCfg.events.size()) {
         mGenCfg.index = 0;
-        mGenCfg.events.clear();
+        if (mNumOfIterations > 0) {
+            mNumOfIterations--;
+        }
     }
-    mCond.notify_one();
-    return StatusCode::OK;
+    return generatedValue;
+}
+
+bool JsonFakeValueGenerator::hasNext() {
+    return mNumOfIterations != 0 && mGenCfg.events.size() > 0;
 }
 
 std::vector<VehiclePropValue> JsonFakeValueGenerator::parseFakeValueJson(std::istream& is) {
@@ -131,9 +124,14 @@
             case VehiclePropertyType::STRING:
                 value.stringValue = rawEventValue.asString();
                 break;
+            case VehiclePropertyType::MIXED:
+                copyMixedValueJson(value, rawEventValue);
+                if (isDiagnosticProperty(event.prop)) {
+                    value.bytes = generateDiagnosticBytes(value);
+                }
+                break;
             default:
-                ALOGE("%s: unsupported type for property: 0x%x with value: %s", __func__,
-                      event.prop, rawEventValue.asString().c_str());
+                ALOGE("%s: unsupported type for property: 0x%x", __func__, event.prop);
                 continue;
         }
         fakeVhalEvents.push_back(event);
@@ -141,30 +139,60 @@
     return fakeVhalEvents;
 }
 
-void JsonFakeValueGenerator::loop() {
-    static constexpr auto kInvalidTime = TimePoint(Nanos::max());
+void JsonFakeValueGenerator::copyMixedValueJson(VehiclePropValue::RawValue& dest,
+                                                const Json::Value& jsonValue) {
+    copyJsonArray(dest.int32Values, jsonValue["int32Values"]);
+    copyJsonArray(dest.int64Values, jsonValue["int64Values"]);
+    copyJsonArray(dest.floatValues, jsonValue["floatValues"]);
+    dest.stringValue = jsonValue["stringValue"].asString();
+}
 
-    while (!mStopRequested) {
-        auto nextEventTime = kInvalidTime;
-        {
-            MuxGuard g(mLock);
-            if (mGenCfg.index < mGenCfg.events.size()) {
-                mOnHalEvent(mGenCfg.events[mGenCfg.index]);
-            }
-            if (!mGenCfg.events.empty() && mGenCfg.index < mGenCfg.events.size() - 1) {
-                Nanos intervalNano =
-                    static_cast<Nanos>(mGenCfg.events[mGenCfg.index + 1].timestamp -
-                                       mGenCfg.events[mGenCfg.index].timestamp);
-                nextEventTime = Clock::now() + intervalNano;
-            }
-            mGenCfg.index++;
+template <typename T>
+void JsonFakeValueGenerator::copyJsonArray(hidl_vec<T>& dest, const Json::Value& jsonArray) {
+    dest.resize(jsonArray.size());
+    for (Json::Value::ArrayIndex i = 0; i < jsonArray.size(); i++) {
+        if (std::is_same<T, int32_t>::value) {
+            dest[i] = jsonArray[i].asInt();
+        } else if (std::is_same<T, int64_t>::value) {
+            dest[i] = jsonArray[i].asInt64();
+        } else if (std::is_same<T, float>::value) {
+            dest[i] = jsonArray[i].asFloat();
         }
-
-        std::unique_lock<std::mutex> g(mLock);
-        mCond.wait_until(g, nextEventTime);
     }
 }
 
+bool JsonFakeValueGenerator::isDiagnosticProperty(int32_t prop) {
+    return prop == (int32_t)VehicleProperty::OBD2_LIVE_FRAME ||
+           prop == (int32_t)VehicleProperty::OBD2_FREEZE_FRAME;
+}
+
+hidl_vec<uint8_t> JsonFakeValueGenerator::generateDiagnosticBytes(
+    const VehiclePropValue::RawValue& diagnosticValue) {
+    size_t byteSize = ((size_t)DiagnosticIntegerSensorIndex::LAST_SYSTEM_INDEX +
+                       (size_t)DiagnosticFloatSensorIndex::LAST_SYSTEM_INDEX + 2);
+    hidl_vec<uint8_t> bytes(byteSize % 8 == 0 ? byteSize / 8 : byteSize / 8 + 1);
+
+    auto& int32Values = diagnosticValue.int32Values;
+    for (size_t i = 0; i < int32Values.size(); i++) {
+        if (int32Values[i] != 0) {
+            setBit(bytes, i);
+        }
+    }
+
+    auto& floatValues = diagnosticValue.floatValues;
+    for (size_t i = 0; i < floatValues.size(); i++) {
+        if (floatValues[i] != 0.0) {
+            setBit(bytes, i + (size_t)DiagnosticIntegerSensorIndex::LAST_SYSTEM_INDEX + 1);
+        }
+    }
+    return bytes;
+}
+
+void JsonFakeValueGenerator::setBit(hidl_vec<uint8_t>& bytes, size_t idx) {
+    uint8_t mask = 1 << (idx % 8);
+    bytes[idx / 8] |= mask;
+}
+
 }  // namespace impl
 
 }  // namespace V2_0
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
index 51da4c5..70575f7 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
@@ -17,11 +17,8 @@
 #ifndef android_hardware_automotive_vehicle_V2_0_impl_JsonFakeValueGenerator_H_
 #define android_hardware_automotive_vehicle_V2_0_impl_JsonFakeValueGenerator_H_
 
-#include <atomic>
 #include <chrono>
-#include <condition_variable>
 #include <iostream>
-#include <thread>
 
 #include <json/json.h>
 
@@ -37,32 +34,33 @@
 
 class JsonFakeValueGenerator : public FakeValueGenerator {
 private:
-    using Nanos = std::chrono::nanoseconds;
-    using Clock = std::chrono::steady_clock;
-    using TimePoint = std::chrono::time_point<Clock, Nanos>;
-
     struct GeneratorCfg {
         size_t index;
         std::vector<VehiclePropValue> events;
     };
 
 public:
-    JsonFakeValueGenerator(const OnHalEvent& onHalEvent);
-    ~JsonFakeValueGenerator();
-    StatusCode start(const VehiclePropValue& request) override;
-    StatusCode stop(const VehiclePropValue& request) override;
+    JsonFakeValueGenerator(const VehiclePropValue& request);
+    ~JsonFakeValueGenerator() = default;
+
+    VehiclePropValue nextEvent();
+
+    bool hasNext();
 
 private:
     std::vector<VehiclePropValue> parseFakeValueJson(std::istream& is);
-    void loop();
+    void copyMixedValueJson(VehiclePropValue::RawValue& dest, const Json::Value& jsonValue);
+
+    template <typename T>
+    void copyJsonArray(hidl_vec<T>& dest, const Json::Value& jsonArray);
+
+    bool isDiagnosticProperty(int32_t prop);
+    hidl_vec<uint8_t> generateDiagnosticBytes(const VehiclePropValue::RawValue& diagnosticValue);
+    void setBit(hidl_vec<uint8_t>& bytes, size_t idx);
 
 private:
-    OnHalEvent mOnHalEvent;
-    std::thread mThread;
-    mutable std::mutex mLock;
-    std::condition_variable mCond;
     GeneratorCfg mGenCfg;
-    std::atomic_bool mStopRequested{false};
+    int32_t mNumOfIterations;
 };
 
 }  // namespace impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
index 8cb9322..7bdc97c 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
@@ -29,101 +29,48 @@
 
 namespace impl {
 
-LinearFakeValueGenerator::LinearFakeValueGenerator(const OnHalEvent& onHalEvent)
-    : mOnHalEvent(onHalEvent),
-      mRecurrentTimer(std::bind(&LinearFakeValueGenerator::onTimer, this, std::placeholders::_1)) {}
-
-StatusCode LinearFakeValueGenerator::start(const VehiclePropValue& request) {
+LinearFakeValueGenerator::LinearFakeValueGenerator(const VehiclePropValue& request) {
     const auto& v = request.value;
-    if (v.int32Values.size() < 2) {
-        ALOGE("%s: expected property ID in int32Values", __func__);
-        return StatusCode::INVALID_ARG;
-    }
-    int32_t propId = v.int32Values[1];
-
-    if (!v.int64Values.size()) {
-        ALOGE("%s: interval is not provided in int64Values", __func__);
-        return StatusCode::INVALID_ARG;
-    }
-    auto interval = std::chrono::nanoseconds(v.int64Values[0]);
-
-    if (v.floatValues.size() < 3) {
-        ALOGE("%s: expected at least 3 elements in floatValues, got: %zu", __func__,
-              v.floatValues.size());
-        return StatusCode::INVALID_ARG;
-    }
-    float initialValue = v.floatValues[0];
-    float dispersion = v.floatValues[1];
-    float increment = v.floatValues[2];
-
-    MuxGuard g(mLock);
-    removeLocked(propId);
-    mGenCfg.insert({propId, GeneratorCfg{
-                                .initialValue = initialValue,
-                                .currentValue = initialValue,
-                                .dispersion = dispersion,
-                                .increment = increment,}});
-
-    mRecurrentTimer.registerRecurrentEvent(interval, propId);
-    return StatusCode::OK;
+    mGenCfg = GeneratorCfg{
+        .propId = v.int32Values[1],
+        .initialValue = v.floatValues[0],
+        .currentValue = v.floatValues[0],
+        .dispersion = v.floatValues[1],
+        .increment = v.floatValues[2],
+        .interval = Nanos(v.int64Values[0]),
+    };
 }
 
-StatusCode LinearFakeValueGenerator::stop(const VehiclePropValue& request) {
-    const auto& v = request.value;
-    if (v.int32Values.size() < 2) {
-        ALOGE("%s: expected property ID in int32Values", __func__);
-        return StatusCode::INVALID_ARG;
+VehiclePropValue LinearFakeValueGenerator::nextEvent() {
+    mGenCfg.currentValue += mGenCfg.increment;
+    if (mGenCfg.currentValue > mGenCfg.initialValue + mGenCfg.dispersion) {
+        mGenCfg.currentValue = mGenCfg.initialValue - mGenCfg.dispersion;
     }
-    int32_t propId = v.int32Values[1];
-
-    MuxGuard g(mLock);
-    if (propId == 0) {
-        // Remove all.
-        for (auto&& it : mGenCfg) {
-            removeLocked(it.first);
-        }
-    } else {
-        removeLocked(propId);
+    VehiclePropValue event = {.prop = mGenCfg.propId};
+    auto& value = event.value;
+    switch (getPropType(event.prop)) {
+        case VehiclePropertyType::INT32:
+            value.int32Values.resize(1);
+            value.int32Values[0] = static_cast<int32_t>(mGenCfg.currentValue);
+            break;
+        case VehiclePropertyType::INT64:
+            value.int64Values.resize(1);
+            value.int64Values[0] = static_cast<int64_t>(mGenCfg.currentValue);
+            break;
+        case VehiclePropertyType::FLOAT:
+            value.floatValues.resize(1);
+            value.floatValues[0] = mGenCfg.currentValue;
+            break;
+        default:
+            ALOGE("%s: unsupported property type for 0x%x", __func__, event.prop);
     }
-    return StatusCode::OK;
+    TimePoint eventTime = Clock::now() + mGenCfg.interval;
+    event.timestamp = eventTime.time_since_epoch().count();
+    return event;
 }
 
-void LinearFakeValueGenerator::removeLocked(int propId) {
-    if (mGenCfg.erase(propId)) {
-        mRecurrentTimer.unregisterRecurrentEvent(propId);
-    }
-}
-
-void LinearFakeValueGenerator::onTimer(const std::vector<int32_t>& properties) {
-    MuxGuard g(mLock);
-
-    for (int32_t propId : properties) {
-        auto& cfg = mGenCfg[propId];
-        cfg.currentValue += cfg.increment;
-        if (cfg.currentValue > cfg.initialValue + cfg.dispersion) {
-            cfg.currentValue = cfg.initialValue - cfg.dispersion;
-        }
-        VehiclePropValue event = {.prop = propId};
-        auto& value = event.value;
-        switch (getPropType(event.prop)) {
-            case VehiclePropertyType::INT32:
-                value.int32Values.resize(1);
-                value.int32Values[0] = static_cast<int32_t>(cfg.currentValue);
-                break;
-            case VehiclePropertyType::INT64:
-                value.int64Values.resize(1);
-                value.int64Values[0] = static_cast<int64_t>(cfg.currentValue);
-                break;
-            case VehiclePropertyType::FLOAT:
-                value.floatValues.resize(1);
-                value.floatValues[0] = cfg.currentValue;
-                break;
-            default:
-                ALOGE("%s: unsupported property type for 0x%x", __func__, event.prop);
-                continue;
-        }
-        mOnHalEvent(event);
-    }
+bool LinearFakeValueGenerator::hasNext() {
+    return true;
 }
 
 }  // namespace impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h
index fe6d097..d3b666d 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h
@@ -17,8 +17,6 @@
 #ifndef android_hardware_automotive_vehicle_V2_0_impl_LinearFakeValueGenerator_H_
 #define android_hardware_automotive_vehicle_V2_0_impl_LinearFakeValueGenerator_H_
 
-#include <vhal_v2_0/RecurrentTimer.h>
-
 #include "FakeValueGenerator.h"
 
 namespace android {
@@ -36,27 +34,24 @@
     // to the client.
 
     struct GeneratorCfg {
-        float initialValue;  //
+        int32_t propId;
+        float initialValue;
         float currentValue;  //  Should be in range (initialValue +/- dispersion).
         float dispersion;    //  Defines minimum and maximum value based on initial value.
         float increment;     //  Value that we will be added to currentValue with each timer tick.
+        Nanos interval;
     };
 
 public:
-    LinearFakeValueGenerator(const OnHalEvent& onHalEvent);
+    LinearFakeValueGenerator(const VehiclePropValue& request);
     ~LinearFakeValueGenerator() = default;
-    StatusCode start(const VehiclePropValue& request) override;
-    StatusCode stop(const VehiclePropValue& request) override;
+
+    VehiclePropValue nextEvent();
+
+    bool hasNext();
 
 private:
-    void removeLocked(int propId);
-    void onTimer(const std::vector<int32_t>& properties);
-
-private:
-    mutable std::mutex mLock;
-    OnHalEvent mOnHalEvent;
-    RecurrentTimer mRecurrentTimer;
-    std::unordered_map<int32_t, GeneratorCfg> mGenCfg;
+    GeneratorCfg mGenCfg;
 };
 
 }  // namespace impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp
index 5a9b254..f024287 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.cpp
@@ -33,23 +33,28 @@
 
 namespace impl {
 
-PipeComm::PipeComm() {
-    // Initialize member vars
-    mPipeFd = -1;
-}
+PipeComm::PipeComm(MessageProcessor* messageProcessor) : CommConn(messageProcessor), mPipeFd(-1) {}
 
-
-int PipeComm::open() {
+void PipeComm::start() {
     int fd = qemu_pipe_open(CAR_SERVICE_NAME);
 
     if (fd < 0) {
         ALOGE("%s: Could not open connection to service: %s %d", __FUNCTION__, strerror(errno), fd);
-        return -errno;
+        return;
     }
 
-    ALOGI("%s: OPENED PIPE, fd=%d", __FUNCTION__, fd);
+    ALOGI("%s: Starting pipe connection, fd=%d", __FUNCTION__, fd);
     mPipeFd = fd;
-    return 0;
+
+    CommConn::start();
+}
+
+void PipeComm::stop() {
+    if (mPipeFd > 0) {
+        ::close(mPipeFd);
+        mPipeFd = -1;
+    }
+    CommConn::stop();
 }
 
 std::vector<uint8_t> PipeComm::read() {
@@ -60,16 +65,13 @@
     numBytes = qemu_pipe_frame_recv(mPipeFd, msg.data(), msg.size());
 
     if (numBytes == MAX_RX_MSG_SZ) {
-        ALOGE("%s:  Received max size = %d", __FUNCTION__, MAX_RX_MSG_SZ);
+        ALOGE("%s: Received max size = %d", __FUNCTION__, MAX_RX_MSG_SZ);
     } else if (numBytes > 0) {
         msg.resize(numBytes);
         return msg;
     } else {
         ALOGD("%s: Connection terminated on pipe %d, numBytes=%d", __FUNCTION__, mPipeFd, numBytes);
-        {
-            std::lock_guard<std::mutex> lock(mMutex);
-            mPipeFd = -1;
-        }
+        mPipeFd = -1;
     }
 
     return std::vector<uint8_t>();
@@ -78,11 +80,8 @@
 int PipeComm::write(const std::vector<uint8_t>& data) {
     int retVal = 0;
 
-    {
-        std::lock_guard<std::mutex> lock(mMutex);
-        if (mPipeFd != -1) {
-            retVal = qemu_pipe_frame_send(mPipeFd, data.data(), data.size());
-        }
+    if (mPipeFd != -1) {
+        retVal = qemu_pipe_frame_send(mPipeFd, data.data(), data.size());
     }
 
     if (retVal < 0) {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h
index bcd32d0..c8eabb8 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PipeComm.h
@@ -19,7 +19,7 @@
 
 #include <mutex>
 #include <vector>
-#include "CommBase.h"
+#include "CommConn.h"
 
 namespace android {
 namespace hardware {
@@ -30,38 +30,25 @@
 namespace impl {
 
 /**
- * PipeComm uses a qemu pipe interface to connect to the Goldfish Emulator.
+ * PipeComm opens a qemu pipe to connect to the emulator, allowing the emulator UI to access the
+ * Vehicle HAL and simulate changing properties.
+ *
+ * Since the pipe is a client, it directly implements CommConn, and only one PipeComm can be open
+ * at a time.
  */
-class PipeComm : public CommBase {
-public:
-    PipeComm();
+class PipeComm : public CommConn {
+   public:
+    PipeComm(MessageProcessor* messageProcessor);
 
-    /**
-     * Opens a pipe and begins listening.
-     *
-     * @return int Returns 0 on success.
-     */
-    int open() override;
+    void start() override;
+    void stop() override;
 
-    /**
-     * Blocking call to read data from the connection.
-     *
-     * @return std::vector<uint8_t> Serialized protobuf data received from emulator.  This will be
-     *              an empty vector if the connection was closed or some other error occurred.
-     */
     std::vector<uint8_t> read() override;
-
-    /**
-     * Transmits a string of data to the emulator.
-     *
-     * @param data Serialized protobuf data to transmit.
-     *
-     * @return int Number of bytes transmitted, or -1 if failed.
-     */
     int write(const std::vector<uint8_t>& data) override;
 
-private:
-    std::mutex mMutex;
+    inline bool isOpen() override { return mPipeFd > 0; }
+
+   private:
     int mPipeFd;
 };
 
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 42c1c78..9eb8894 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
@@ -18,6 +18,7 @@
 
 #include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
 #include <android/log.h>
+#include <arpa/inet.h>
 #include <log/log.h>
 #include <netinet/in.h>
 #include <sys/socket.h>
@@ -35,45 +36,46 @@
 
 namespace impl {
 
-SocketComm::SocketComm() {
-    // Initialize member vars
-    mCurSockFd = -1;
-    mExit      =  0;
-    mSockFd    = -1;
-}
-
+SocketComm::SocketComm(MessageProcessor* messageProcessor)
+    : mListenFd(-1), mMessageProcessor(messageProcessor) {}
 
 SocketComm::~SocketComm() {
-    stop();
 }
 
-int SocketComm::connect() {
-    sockaddr_in cliAddr;
-    socklen_t cliLen = sizeof(cliAddr);
-    int cSockFd = accept(mSockFd, reinterpret_cast<struct sockaddr*>(&cliAddr), &cliLen);
-
-    if (cSockFd >= 0) {
-        {
-            std::lock_guard<std::mutex> lock(mMutex);
-            mCurSockFd = cSockFd;
-        }
-        ALOGD("%s: Incoming connection received on socket %d", __FUNCTION__, cSockFd);
-    } else {
-        cSockFd = -1;
+void SocketComm::start() {
+    if (!listen()) {
+        return;
     }
 
-    return cSockFd;
+    mListenThread = std::make_unique<std::thread>(std::bind(&SocketComm::listenThread, this));
 }
 
-int SocketComm::open() {
+void SocketComm::stop() {
+    if (mListenFd > 0) {
+        ::close(mListenFd);
+        if (mListenThread->joinable()) {
+            mListenThread->join();
+        }
+        mListenFd = -1;
+    }
+}
+
+void SocketComm::sendMessage(emulator::EmulatorMessage const& msg) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    for (std::unique_ptr<SocketConn> const& conn : mOpenConnections) {
+        conn->sendMessage(msg);
+    }
+}
+
+bool SocketComm::listen() {
     int retVal;
     struct sockaddr_in servAddr;
 
-    mSockFd = socket(AF_INET, SOCK_STREAM, 0);
-    if (mSockFd < 0) {
-        ALOGE("%s: socket() failed, mSockFd=%d, errno=%d", __FUNCTION__, mSockFd, errno);
-        mSockFd = -1;
-        return -errno;
+    mListenFd = socket(AF_INET, SOCK_STREAM, 0);
+    if (mListenFd < 0) {
+        ALOGE("%s: socket() failed, mSockFd=%d, errno=%d", __FUNCTION__, mListenFd, errno);
+        mListenFd = -1;
+        return false;
     }
 
     memset(&servAddr, 0, sizeof(servAddr));
@@ -81,82 +83,114 @@
     servAddr.sin_addr.s_addr = INADDR_ANY;
     servAddr.sin_port = htons(DEBUG_SOCKET);
 
-    retVal = bind(mSockFd, reinterpret_cast<struct sockaddr*>(&servAddr), sizeof(servAddr));
+    retVal = bind(mListenFd, reinterpret_cast<struct sockaddr*>(&servAddr), sizeof(servAddr));
     if(retVal < 0) {
         ALOGE("%s: Error on binding: retVal=%d, errno=%d", __FUNCTION__, retVal, errno);
+        close(mListenFd);
+        mListenFd = -1;
+        return false;
+    }
+
+    ALOGI("%s: Listening for connections on port %d", __FUNCTION__, DEBUG_SOCKET);
+    ::listen(mListenFd, 1);
+    return true;
+}
+
+SocketConn* SocketComm::accept() {
+    sockaddr_in cliAddr;
+    socklen_t cliLen = sizeof(cliAddr);
+    int sfd = ::accept(mListenFd, reinterpret_cast<struct sockaddr*>(&cliAddr), &cliLen);
+
+    if (sfd > 0) {
+        char addr[INET_ADDRSTRLEN];
+        inet_ntop(AF_INET, &cliAddr.sin_addr, addr, INET_ADDRSTRLEN);
+
+        ALOGD("%s: Incoming connection received from %s:%d", __FUNCTION__, addr, cliAddr.sin_port);
+        return new SocketConn(mMessageProcessor, sfd);
+    }
+
+    return nullptr;
+}
+
+void SocketComm::listenThread() {
+    while (true) {
+        SocketConn* conn = accept();
+        if (conn == nullptr) {
+            return;
+        }
+
+        conn->start();
+        {
+            std::lock_guard<std::mutex> lock(mMutex);
+            mOpenConnections.push_back(std::unique_ptr<SocketConn>(conn));
+        }
+    }
+}
+
+/**
+ * Called occasionally to clean up connections that have been closed.
+ */
+void SocketComm::removeClosedConnections() {
+    std::lock_guard<std::mutex> lock(mMutex);
+    std::remove_if(mOpenConnections.begin(), mOpenConnections.end(),
+                   [](std::unique_ptr<SocketConn> const& c) { return !c->isOpen(); });
+}
+
+SocketConn::SocketConn(MessageProcessor* messageProcessor, int sfd)
+    : CommConn(messageProcessor), mSockFd(sfd) {}
+
+/**
+ * Reads, in a loop, exactly numBytes from the given fd. If the connection is closed, returns
+ * an empty buffer, otherwise will return exactly the given number of bytes.
+ */
+std::vector<uint8_t> readExactly(int fd, int numBytes) {
+    std::vector<uint8_t> buffer(numBytes);
+    int totalRead = 0;
+    int offset = 0;
+    while (totalRead < numBytes) {
+        int numRead = ::read(fd, &buffer.data()[offset], numBytes - offset);
+        if (numRead == 0) {
+            buffer.resize(0);
+            return buffer;
+        }
+
+        totalRead += numRead;
+    }
+    return buffer;
+}
+
+/**
+ * Reads an int, guaranteed to be non-zero, from the given fd. If the connection is closed, returns
+ * -1.
+ */
+int32_t readInt(int fd) {
+    std::vector<uint8_t> buffer = readExactly(fd, sizeof(int32_t));
+    if (buffer.size() == 0) {
+        return -1;
+    }
+
+    int32_t value = *reinterpret_cast<int32_t*>(buffer.data());
+    return ntohl(value);
+}
+
+std::vector<uint8_t> SocketConn::read() {
+    int32_t msgSize = readInt(mSockFd);
+    if (msgSize <= 0) {
+        ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, mSockFd);
+        return std::vector<uint8_t>();
+    }
+
+    return readExactly(mSockFd, msgSize);
+}
+
+void SocketConn::stop() {
+    if (mSockFd > 0) {
         close(mSockFd);
         mSockFd = -1;
-        return -errno;
-    }
-
-    listen(mSockFd, 1);
-
-    // Set the socket to be non-blocking so we can poll it continouously
-    fcntl(mSockFd, F_SETFL, O_NONBLOCK);
-
-    return 0;
-}
-
-std::vector<uint8_t> SocketComm::read() {
-    int32_t msgSize;
-    int numBytes = 0;
-
-    // This is a variable length message.
-    // Read the number of bytes to rx over the socket
-    numBytes = ::read(mCurSockFd, &msgSize, sizeof(msgSize));
-    msgSize = ntohl(msgSize);
-
-    if (numBytes != sizeof(msgSize)) {
-        // This happens when connection is closed
-        ALOGD("%s: numBytes=%d, expected=4", __FUNCTION__, numBytes);
-        ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, mCurSockFd);
-        {
-            std::lock_guard<std::mutex> lock(mMutex);
-            mCurSockFd = -1;
-        }
-
-        return std::vector<uint8_t>();
-    }
-
-    std::vector<uint8_t> msg = std::vector<uint8_t>(msgSize);
-
-    numBytes = ::read(mCurSockFd, msg.data(), msgSize);
-
-    if ((numBytes == msgSize) && (msgSize > 0)) {
-        // Received a message.
-        return msg;
-    } else {
-        // This happens when connection is closed
-        ALOGD("%s: numBytes=%d, msgSize=%d", __FUNCTION__, numBytes, msgSize);
-        ALOGD("%s: Connection terminated on socket %d", __FUNCTION__, mCurSockFd);
-        {
-            std::lock_guard<std::mutex> lock(mMutex);
-            mCurSockFd = -1;
-        }
-
-        return std::vector<uint8_t>();
     }
 }
 
-void SocketComm::stop() {
-    if (mExit == 0) {
-        std::lock_guard<std::mutex> lock(mMutex);
-        mExit = 1;
-
-        // Close emulator socket if it is open
-        if (mCurSockFd != -1) {
-            close(mCurSockFd);
-            mCurSockFd = -1;
-        }
-
-        if (mSockFd != -1) {
-            close(mSockFd);
-            mSockFd = -1;
-        }
-    }
-}
-
-int SocketComm::write(const std::vector<uint8_t>& data) {
+int SocketConn::write(const std::vector<uint8_t>& data) {
     static constexpr int MSG_HEADER_LEN = 4;
     int retVal = 0;
     union {
@@ -168,19 +202,17 @@
     msgLen = static_cast<uint32_t>(data.size());
     msgLen = htonl(msgLen);
 
-    std::lock_guard<std::mutex> lock(mMutex);
-    if (mCurSockFd != -1) {
-        retVal = ::write(mCurSockFd, msgLenBytes, MSG_HEADER_LEN);
+    if (mSockFd > 0) {
+        retVal = ::write(mSockFd, msgLenBytes, MSG_HEADER_LEN);
 
         if (retVal == MSG_HEADER_LEN) {
-            retVal = ::write(mCurSockFd, data.data(), data.size());
+            retVal = ::write(mSockFd, data.data(), data.size());
         }
     }
 
     return retVal;
 }
 
-
 }  // impl
 
 }  // namespace V2_0
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 12cfb29..88b852b 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
@@ -18,8 +18,9 @@
 #define android_hardware_automotive_vehicle_V2_0_impl_SocketComm_H_
 
 #include <mutex>
+#include <thread>
 #include <vector>
-#include "CommBase.h"
+#include "CommConn.h"
 
 namespace android {
 namespace hardware {
@@ -29,29 +30,60 @@
 
 namespace impl {
 
+class SocketConn;
+
 /**
- * SocketComm opens a socket via adb's TCP port forwarding to enable a Host PC to connect to
- * the VehicleHAL.
+ * SocketComm opens a socket, and listens for connections from clients. Typically the client will be
+ * adb's TCP port-forwarding to enable a host PC to connect to the VehicleHAL.
  */
-class SocketComm : public CommBase {
-public:
-    SocketComm();
+class SocketComm {
+   public:
+    SocketComm(MessageProcessor* messageProcessor);
     virtual ~SocketComm();
 
+    void start();
+    void stop();
+
     /**
-     * Creates a connection to the other side.
+     * Serialized and send the given message to all connected clients.
+     */
+    void sendMessage(emulator::EmulatorMessage const& msg);
+
+   private:
+    int mListenFd;
+    std::unique_ptr<std::thread> mListenThread;
+    std::vector<std::unique_ptr<SocketConn>> mOpenConnections;
+    MessageProcessor* mMessageProcessor;
+    std::mutex mMutex;
+
+    /**
+     * Opens the socket and begins listening.
+     *
+     * @return bool Returns true on success.
+     */
+    bool listen();
+
+    /**
+     * Blocks and waits for a connection from a client, returns a new SocketConn with the connection
+     * or null, if the connection has been closed.
      *
      * @return int Returns fd or socket number if connection is successful.
      *              Otherwise, returns -1 if no connection is availble.
      */
-    int connect() override;
+    SocketConn* accept();
 
-    /**
-     * Opens a socket and begins listening.
-     *
-     * @return int Returns 0 on success.
-     */
-    int open() override;
+    void listenThread();
+
+    void removeClosedConnections();
+};
+
+/**
+ * SocketConn represents a single connection to a client.
+ */
+class SocketConn : public CommConn {
+   public:
+    SocketConn(MessageProcessor* messageProcessor, int sfd);
+    virtual ~SocketConn() = default;
 
     /**
      * Blocking call to read data from the connection.
@@ -75,10 +107,9 @@
      */
     int write(const std::vector<uint8_t>& data) override;
 
-private:
-    int mCurSockFd;
-    std::atomic<int> mExit;
-    std::mutex mMutex;
+    inline bool isOpen() override { return mSockFd > 0; }
+
+   private:
     int mSockFd;
 };
 
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 bf7be09..356a6b9 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
@@ -16,9 +16,10 @@
 #define LOG_TAG "VehicleEmulator_v2_0"
 #include <android/log.h>
 
-#include <algorithm>
 #include <android-base/properties.h>
+#include <log/log.h>
 #include <utils/SystemClock.h>
+#include <algorithm>
 
 #include <vhal_v2_0/VehicleUtils.h>
 
@@ -35,32 +36,45 @@
 
 namespace impl {
 
-std::unique_ptr<CommBase> CommFactory::create() {
-    bool isEmulator = android::base::GetBoolProperty("ro.kernel.qemu", false);
+VehicleEmulator::VehicleEmulator(EmulatedVehicleHalIface* hal) : mHal{hal} {
+    mHal->registerEmulator(this);
 
-    if (isEmulator) {
-        return std::make_unique<PipeComm>();
-    } else {
-        return std::make_unique<SocketComm>();
+    ALOGI("Starting SocketComm");
+    mSocketComm = std::make_unique<SocketComm>(this);
+    mSocketComm->start();
+
+    if (android::base::GetBoolProperty("ro.kernel.qemu", false)) {
+        ALOGI("Starting PipeComm");
+        mPipeComm = std::make_unique<PipeComm>(this);
+        mPipeComm->start();
     }
 }
 
 VehicleEmulator::~VehicleEmulator() {
-    mExit = true;   // Notify thread to finish and wait for it to terminate.
-    mComm->stop();  // Close emulator socket if it is open.
-    if (mThread.joinable()) mThread.join();
+    mSocketComm->stop();
+    if (mPipeComm) {
+        mPipeComm->stop();
+    }
 }
 
+/**
+ * This is called by the HAL when a property changes. We need to notify our clients that it has
+ * changed.
+ */
 void VehicleEmulator::doSetValueFromClient(const VehiclePropValue& propValue) {
     emulator::EmulatorMessage msg;
     emulator::VehiclePropValue *val = msg.add_value();
     populateProtoVehiclePropValue(val, &propValue);
     msg.set_status(emulator::RESULT_OK);
     msg.set_msg_type(emulator::SET_PROPERTY_ASYNC);
-    txMsg(msg);
+
+    mSocketComm->sendMessage(msg);
+    if (mPipeComm) {
+        mPipeComm->sendMessage(msg);
+    }
 }
 
-void VehicleEmulator::doGetConfig(VehicleEmulator::EmulatorMessage& rxMsg,
+void VehicleEmulator::doGetConfig(VehicleEmulator::EmulatorMessage const& rxMsg,
                                   VehicleEmulator::EmulatorMessage& respMsg) {
     std::vector<VehiclePropConfig> configs = mHal->listProperties();
     emulator::VehiclePropGet getProp = rxMsg.prop(0);
@@ -79,7 +93,7 @@
     }
 }
 
-void VehicleEmulator::doGetConfigAll(VehicleEmulator::EmulatorMessage& /* rxMsg */,
+void VehicleEmulator::doGetConfigAll(VehicleEmulator::EmulatorMessage const& /* rxMsg */,
                                      VehicleEmulator::EmulatorMessage& respMsg) {
     std::vector<VehiclePropConfig> configs = mHal->listProperties();
 
@@ -92,8 +106,8 @@
     }
 }
 
-void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage& rxMsg,
-                                    VehicleEmulator::EmulatorMessage& respMsg)  {
+void VehicleEmulator::doGetProperty(VehicleEmulator::EmulatorMessage const& rxMsg,
+                                    VehicleEmulator::EmulatorMessage& respMsg) {
     int32_t areaId = 0;
     emulator::VehiclePropGet getProp = rxMsg.prop(0);
     int32_t propId = getProp.prop();
@@ -119,8 +133,8 @@
     respMsg.set_status(status);
 }
 
-void VehicleEmulator::doGetPropertyAll(VehicleEmulator::EmulatorMessage& /* rxMsg */,
-                                       VehicleEmulator::EmulatorMessage& respMsg)  {
+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);
 
@@ -132,7 +146,7 @@
     }
 }
 
-void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage& rxMsg,
+void VehicleEmulator::doSetProperty(VehicleEmulator::EmulatorMessage const& rxMsg,
                                     VehicleEmulator::EmulatorMessage& respMsg) {
     emulator::VehiclePropValue protoVal = rxMsg.value(0);
     VehiclePropValue val = {
@@ -173,58 +187,28 @@
     respMsg.set_status(halRes ? emulator::RESULT_OK : emulator::ERROR_INVALID_PROPERTY);
 }
 
-void VehicleEmulator::txMsg(emulator::EmulatorMessage& txMsg) {
-    int numBytes = txMsg.ByteSize();
-    std::vector<uint8_t> msg(static_cast<size_t>(numBytes));
-
-    if (!txMsg.SerializeToArray(msg.data(), static_cast<int32_t>(msg.size()))) {
-        ALOGE("%s: SerializeToString failed!", __func__);
-        return;
-    }
-
-    if (mExit) {
-        ALOGW("%s: unable to transmit a message, connection closed", __func__);
-        return;
-    }
-
-    // Send the message
-    int retVal = mComm->write(msg);
-    if (retVal < 0) {
-        ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __func__, retVal, errno);
-    }
-}
-
-void VehicleEmulator::parseRxProtoBuf(std::vector<uint8_t>& msg) {
-    emulator::EmulatorMessage rxMsg;
-    emulator::EmulatorMessage respMsg;
-
-    if (rxMsg.ParseFromArray(msg.data(), static_cast<int32_t>(msg.size()))) {
-        switch (rxMsg.msg_type()) {
-            case emulator::GET_CONFIG_CMD:
-                doGetConfig(rxMsg, respMsg);
-                break;
-            case emulator::GET_CONFIG_ALL_CMD:
-                doGetConfigAll(rxMsg, respMsg);
-                break;
-            case emulator::GET_PROPERTY_CMD:
-                doGetProperty(rxMsg, respMsg);
-                break;
-            case emulator::GET_PROPERTY_ALL_CMD:
-                doGetPropertyAll(rxMsg, respMsg);
-                break;
-            case emulator::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);
-                break;
-        }
-
-        // Send the reply
-        txMsg(respMsg);
-    } else {
-        ALOGE("%s: ParseFromString() failed. msgSize=%d", __func__, static_cast<int>(msg.size()));
+void VehicleEmulator::processMessage(emulator::EmulatorMessage const& rxMsg,
+                                     emulator::EmulatorMessage& respMsg) {
+    switch (rxMsg.msg_type()) {
+        case emulator::GET_CONFIG_CMD:
+            doGetConfig(rxMsg, respMsg);
+            break;
+        case emulator::GET_CONFIG_ALL_CMD:
+            doGetConfigAll(rxMsg, respMsg);
+            break;
+        case emulator::GET_PROPERTY_CMD:
+            doGetProperty(rxMsg, respMsg);
+            break;
+        case emulator::GET_PROPERTY_ALL_CMD:
+            doGetPropertyAll(rxMsg, respMsg);
+            break;
+        case emulator::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);
+            break;
     }
 }
 
@@ -316,40 +300,6 @@
     }
 }
 
-void VehicleEmulator::rxMsg() {
-    while (!mExit) {
-        std::vector<uint8_t> msg = mComm->read();
-
-        if (msg.size() > 0) {
-            // Received a message.
-            parseRxProtoBuf(msg);
-        } else {
-            // This happens when connection is closed
-            ALOGD("%s: msgSize=%zu", __func__, msg.size());
-            break;
-        }
-    }
-}
-
-void VehicleEmulator::rxThread() {
-    if (mExit) return;
-
-    int retVal = mComm->open();
-    if (retVal != 0) mExit = true;
-
-    // Comms are properly opened
-    while (!mExit) {
-        retVal = mComm->connect();
-
-        if (retVal >= 0) {
-            rxMsg();
-        }
-
-        // Check every 100ms for a new connection
-        std::this_thread::sleep_for(std::chrono::milliseconds(100));
-    }
-}
-
 }  // impl
 
 }  // namespace V2_0
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 1a8cfe2..58e387a 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
@@ -24,7 +24,9 @@
 
 #include "vhal_v2_0/VehicleHal.h"
 
-#include "CommBase.h"
+#include "CommConn.h"
+#include "PipeComm.h"
+#include "SocketComm.h"
 #include "VehicleHalProto.pb.h"
 
 namespace android {
@@ -61,48 +63,36 @@
     VehicleEmulator* mEmulator;
 };
 
-struct CommFactory {
-    static std::unique_ptr<CommBase> create();
-};
-
 /**
  * Emulates vehicle by providing controlling interface from host side either through ADB or Pipe.
  */
-class VehicleEmulator {
-public:
-    VehicleEmulator(EmulatedVehicleHalIface* hal,
-                    std::unique_ptr<CommBase> comm = CommFactory::create())
-            : mHal { hal },
-              mComm(comm.release()),
-              mThread { &VehicleEmulator::rxThread, this} {
-        mHal->registerEmulator(this);
-    }
+class VehicleEmulator : public MessageProcessor {
+   public:
+    VehicleEmulator(EmulatedVehicleHalIface* hal);
     virtual ~VehicleEmulator();
 
     void doSetValueFromClient(const VehiclePropValue& propValue);
+    void processMessage(emulator::EmulatorMessage const& rxMsg,
+                        emulator::EmulatorMessage& respMsg) override;
 
-private:
+   private:
+    friend class ConnectionThread;
     using EmulatorMessage = emulator::EmulatorMessage;
 
-    void doGetConfig(EmulatorMessage& rxMsg, EmulatorMessage& respMsg);
-    void doGetConfigAll(EmulatorMessage& rxMsg, EmulatorMessage& respMsg);
-    void doGetProperty(EmulatorMessage& rxMsg, EmulatorMessage& respMsg);
-    void doGetPropertyAll(EmulatorMessage& rxMsg, EmulatorMessage& respMsg);
-    void doSetProperty(EmulatorMessage& rxMsg, EmulatorMessage& respMsg);
-    void txMsg(emulator::EmulatorMessage& txMsg);
-    void parseRxProtoBuf(std::vector<uint8_t>& msg);
+    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,
                                     const VehiclePropConfig& cfg);
     void populateProtoVehiclePropValue(emulator::VehiclePropValue* protoVal,
                                        const VehiclePropValue* val);
-    void rxMsg();
-    void rxThread();
 
 private:
-    std::atomic<bool> mExit { false };
     EmulatedVehicleHalIface* mHal;
-    std::unique_ptr<CommBase> mComm;
-    std::thread mThread;
+    std::unique_ptr<SocketComm> mSocketComm;
+    std::unique_ptr<PipeComm> mPipeComm;
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 57179df..4751a76 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -306,6 +306,37 @@
         | VehicleArea:GLOBAL),
 
     /**
+     * Speed of the vehicle for displays
+     *
+     * Some cars display a slightly slower speed than the actual speed.  This is
+     * usually displayed on the speedometer.
+     *
+     * @change_mode VehiclePropertyChangeMode:CONTINUOUS
+     * @access VehiclePropertyAccess:READ
+     * @unit VehicleUnit:METER_PER_SEC
+     */
+    PERF_VEHICLE_SPEED_DISPLAY = (
+        0x0208
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:FLOAT
+        | VehicleArea:GLOBAL),
+
+    /**
+     * Steering angle of the vehicle
+     *
+     * Angle is in degrees.  Left is negative.
+     *
+     * @change_mode VehiclePropertyChangeMode:CONTINUOUS
+     * @access VehiclePropertyAccess:READ
+     * @unit VehicleUnit:DEGREES
+     */
+    PERF_STEERING_ANGLE = (
+        0x0209
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:FLOAT
+        | VehicleArea:GLOBAL),
+
+    /**
      * Temperature of engine coolant
      *
      * @change_mode VehiclePropertyChangeMode:CONTINUOUS
@@ -587,7 +618,13 @@
      *
      * This property corresponds to the low fuel warning on the dashboard.
      * Once FUEL_LEVEL_LOW is set, it should not be cleared until more fuel is
-     * added to the vehicle.
+     * added to the vehicle.  This property may take into account all fuel
+     * sources for a vehicle - for example:
+     *
+     *   For a gas powered vehicle, this property is based soley on gas level.
+     *   For a battery powered vehicle, this property is based solely on battery level.
+     *   For a hybrid vehicle, this property may be based on the combination of gas and battery
+     *      levels, at the OEM's discretion.
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:READ
@@ -1088,7 +1125,7 @@
     /**
      * Property to control power state of application processor
      *
-     * It is assumed that AP's power state is controller by separate power
+     * It is assumed that AP's power state is controlled by a separate power
      * controller.
      *
      * For configuration information, VehiclePropConfig.configArray can have bit flag combining
@@ -1099,7 +1136,7 @@
      *                    0 if not used.
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VEHICLE_PROP_ACCESS_READ
+     * @access VehiclePropertyAccess:READ
      */
     AP_POWER_STATE_REQ = (
         0x0A00
@@ -1118,7 +1155,7 @@
 
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VEHICLE_PROP_ACCESS_WRITE
+     * @access VehiclePropertyAccess:WRITE
      */
     AP_POWER_STATE_REPORT = (
         0x0A01
@@ -2230,17 +2267,8 @@
 };
 
 enum VehicleApPowerStateReq : int32_t {
-    /** vehicle HAL will never publish this state to AP */
-    OFF = 0,
-
-    /** vehicle HAL will never publish this state to AP */
-    DEEP_SLEEP = 1,
-
-    /** AP is on but display must be off. */
-    ON_DISP_OFF = 2,
-
-    /** AP is on with display on. This state allows full user interaction. */
-    ON_FULL = 3,
+    /** Transition Android from WAIT_FOR_VHAL to ON state */
+    ON = 0,
 
     /**
      * The power controller has requested AP to shutdown. AP can either enter
@@ -2250,8 +2278,16 @@
      * system.
      *
      * int32Values[1] : one of enum_vehicle_ap_power_state_shutdown_param_type
+     *
+     * SHUTDOWN_PRPARE may be requested from either WAIT_FOR_VHAL or ON states.
      */
-    SHUTDOWN_PREPARE = 4,
+    SHUTDOWN_PREPARE = 1,
+
+    /** Cancel the shutdown and transition from SHUTDOWN_PREPARE to WAIT_FOR_VHAL state */
+    CANCEL_SHUTDOWN = 2,
+
+    /** VHAL is finished with shutdown procedures and ready for Android to suspend/shutdown */
+    FINISHED = 3,
 };
 
 /**
@@ -2277,26 +2313,30 @@
 
 enum VehicleApPowerStateReport : int32_t {
     /**
-     * AP has finished boot up, and can start shutdown if requested by power
-     * controller.
+     * Device has booted, CarService has initialized and is ready to accept commands from VHAL.
+     * Device starts in WAIT_FOR_VHAL state.  The user is not logged in, and vendor apps/services
+     * are expected to control the display and audio.
      */
-    BOOT_COMPLETE = 0x1,
+    WAIT_FOR_VHAL = 0x1,
 
     /**
-     * AP is entering deep sleep state. How this state is implemented may vary
-     * depending on each H/W, but AP's power must be kept in this state.
+     * AP is ready to suspend and has entered WAIT_FOR_FINISHED state.
+     *
+     * int32Values[1]: Time to turn on AP in secs. Power controller may turn on
+     *                 AP after specified time so that AP can run tasks like
+     *                 update. If it is set to 0, there is no wake up, and power
+     *                 controller may not necessarily support wake-up.
      */
     DEEP_SLEEP_ENTRY = 0x2,
 
     /**
-     * AP is exiting from deep sleep state, and is in
-     * VehicleApPowerState#SHUTDOWN_PREPARE state.
-     * The power controller may change state to other ON states based on the
-     * current state.
+     * AP is exiting from deep sleep state, and is in WAIT_FOR_VHAL state.
      */
     DEEP_SLEEP_EXIT = 0x3,
 
     /**
+     * AP remains in SHUTDOWN_PREPARE state as idle and cleanup tasks execute.
+     *
      * int32Values[1]: Time to postpone shutdown in ms. Maximum value can be
      *                 5000 ms.
      *                 If AP needs more time, it will send another POSTPONE
@@ -2305,63 +2345,31 @@
     SHUTDOWN_POSTPONE = 0x4,
 
     /**
-     * AP is starting shutting down. When system completes shutdown, everything
-     * will stop in AP as kernel will stop all other contexts. It is
-     * responsibility of vehicle HAL or lower level to synchronize that state
-     * with external power controller. As an example, some kind of ping
-     * with timeout in power controller can be a solution.
+     * AP is ready to shutdown and has entered WAIT_FOR_FINISHED state.
      *
      * int32Values[1]: Time to turn on AP in secs. Power controller may turn on
      *                 AP after specified time so that AP can run tasks like
      *                 update. If it is set to 0, there is no wake up, and power
-     *                 controller may not necessarily support wake-up. If power
-     *                 controller turns on AP due to timer, it must start with
-     *                 VehicleApPowerState#ON_DISP_OFF state, and after
-     *                 receiving VehicleApPowerSetState#BOOT_COMPLETE, it shall
-     *                 do state transition to
-     *                 VehicleApPowerState#SHUTDOWN_PREPARE.
+     *                 controller may not necessarily support wake-up.
      */
     SHUTDOWN_START = 0x5,
 
     /**
-     * User has requested to turn off headunit's display, which is detected in
-     * android side.
-     * The power controller may change the power state to
-     * VehicleApPowerState#ON_DISP_OFF.
+     * AP has transitioned from WAIT_FOR_VHAL state to ON.
      */
-    DISPLAY_OFF = 0x6,
+    ON = 0x6,
 
     /**
-     * User has requested to turn on headunit's display, most probably from power
-     * key input which is attached to headunit. The power controller may change
-     * the power state to VehicleApPowerState#ON_FULL.
+     * AP has transitions to SHUTDOWN_PREPARE state.  In this state, Garage Mode will execute idle
+     * tasks, and other services that have registered for this state transition may execute
+     * cleanup activities.
      */
-    DISPLAY_ON = 0x7,
-};
-
-/**
- * Enum to represent bootup reason.
- */
-enum VehicleApPowerBootupReason : int32_t {
-    /**
-     * Power on due to user's pressing of power key or rotating of ignition
-     * switch.
-     */
-    USER_POWER_ON = 0,
+    SHUTDOWN_PREPARE = 0x7,
 
     /**
-     * Automatic power on triggered by door unlock or any other kind of automatic
-     * user detection.
+     * AP has transitioned from SHUTDOWN_PREPARE state to WAIT_FOR_VHAL.
      */
-    USER_UNLOCK = 1,
-
-    /**
-     * Automatic power on triggered by timer. This only happens when AP has asked
-     * wake-up after
-     * certain time through time specified in
-     * VehicleApPowerSetState#SHUTDOWN_START.
-     */
-    TIMER = 2,
+    SHUTDOWN_CANCELLED = 0x8,
 };
 
 enum VehicleHwKeyInputAction : int32_t {
@@ -2399,13 +2407,15 @@
     NANO_SECS      = 0x50,
     SECS           = 0x53,
     YEAR           = 0x59,
-    KILOPASCAL     = 0x70,
 
     // Electrical Units
     WATT_HOUR      = 0x60,
     MILLIAMPERE    = 0x61,
     MILLIVOLT      = 0x62,
     MILLIWATTS     = 0x63,
+
+    KILOPASCAL     = 0x70,
+    DEGREES        = 0x80,
 };
 
 /**
diff --git a/biometrics/face/1.0/Android.bp b/biometrics/face/1.0/Android.bp
new file mode 100644
index 0000000..45dbad9
--- /dev/null
+++ b/biometrics/face/1.0/Android.bp
@@ -0,0 +1,27 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.biometrics.face@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IBiometricsFace.hal",
+        "IBiometricsFaceClientCallback.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "FaceAcquiredInfo",
+        "FaceError",
+        "OptionalBool",
+        "OptionalUint64",
+        "Status",
+        "UserHandle",
+    ],
+    gen_java: true,
+}
+
diff --git a/biometrics/face/1.0/IBiometricsFace.hal b/biometrics/face/1.0/IBiometricsFace.hal
new file mode 100644
index 0000000..0ac788e
--- /dev/null
+++ b/biometrics/face/1.0/IBiometricsFace.hal
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.face@1.0;
+
+import IBiometricsFaceClientCallback;
+
+// TODO(b/78538290): Update comments with state machine transitions when ready.
+// TODO(b/78537981): Update comments with callback interaction contract.
+// TODO(b/79496983): Update comments with status returns fully enumerated.
+/**
+ * The HAL interface for biometric face authentication.
+ */
+interface IBiometricsFace {
+
+    /**
+     * Sets the current client callback.
+     *
+     * Registers a user function that must receive notifications from the HAL.
+     * There is usually only one client (FaceService). This call must block
+     * if the HAL state machine is in busy state until the HAL leaves the
+     * busy state.
+     *
+     * All callback methods pass a deviceId to differentiate callback
+     * invocations in the case where multiple sensors exist.
+     *
+     * @param clientCallback The client defined callback to register.
+     * @return result, with its "value" parameter representing a "deviceId",
+     *     which must be unique for a given sensor.
+     */
+    @callflow(next={"setActiveUser"})
+    @entry
+    setCallback(IBiometricsFaceClientCallback clientCallback)
+        generates (OptionalUint64 result);
+
+    /**
+     * Sets the active user, which all subsequent HAL operations are applied to.
+     *
+     * HAL service implementors must ensure that operations are restricted to
+     * the given user. Clients must not call any part of this interface, except
+     * for setCallback(), without first having set an active user. The
+     * implementation is responsible for cancelling the current operation and
+     * returning to the idle state. Calling this method with the same userId
+     * should have no effect on the state machine.
+     *
+     * @param userId A non-negative user identifier that must be unique and
+     *     persistent for a given user.
+     * @param storePath filesystem path to the template storage directory.
+     */
+    @callflow(next={"authenticate", "generateChallenge", "enumerate", "remove"})
+    setActiveUser(int32_t userId, string storePath) generates (Status status);
+
+    /**
+     * Begins a secure transaction request, e.g. enrollment.
+     *
+     * Generates a unique and cryptographically secure random token used to
+     * indicate the start of a secure transaction. generateChallenge() and
+     * revokeChallenge() specify a pin/pattern/password cleared time window where
+     * the secure transaction is allowed.
+     *
+     * generateChallenge() generates a challenge which must then be wrapped by the
+     * gatekeeper after verifying a successful strong authentication attempt,
+     * which generates a Hardware Authentication Token. The challenge prevents
+     * spoofing and replay attacks and ensures that we only update a user’s face
+     * template if the operation was preceded by some kind of strong credential
+     * confirmation (e.g. device password).
+     *
+     * @param challengeTimeoutSec A timeout in seconds, after which the driver
+     *     must invalidate the challenge. This is to prevent bugs or crashes in
+     *     the system from leaving a challenge enabled indefinitely.
+     * @return result, with its "value" parameter representing a "challenge": a
+     *     unique and cryptographically secure random token.
+     */
+    @callflow(next={"enroll", "revokeChallenge", "setRequireAttention"})
+    generateChallenge(uint32_t challengeTimeoutSec)
+        generates (OptionalUint64 result);
+
+    /**
+     * Enrolls a user's face.
+     *
+     * Note that this interface permits implementations where multiple faces can
+     * be enrolled for a single user. However, allowing multiple faces to be
+     * enrolled can be a severe security vulnerability and hence, most
+     * implementations must ensure that only a single face be enrolled at a
+     * given time. Multi-enrollment must only be used where there is a clear
+     * necessity for a shared use case, e.g. TVs or cars.
+     *
+     * Note that the Hardware Authentication Token must still be valid after
+     * this call, and must be explicitly invalidated by a call to
+     * revokeChallenge(). This allows clients to immediately reattempt
+     * enrollment (for example, if a user wasn’t satisfied with their enrollment)
+     * without having to go through another strong authentication flow.
+     *
+     * This method triggers the IBiometricsFaceClientCallback#onEnrollResult()
+     * method.
+     *
+     * @param hat A valid Hardware Authentication Token, generated as a result
+     *     of a generateChallenge() challenge being wrapped by the gatekeeper
+     *     after a sucessful strong authentication request.
+     * @param timeoutSec A timeout in seconds, after which this enrollment
+     *     attempt is cancelled. Note that the client still needs to
+     *     call revokeChallenge() to terminate the enrollment session.
+     * @param requireAttention When set to true, requires user attention (e.g.
+     *     eyes open and looking at the device) for enrollment to complete, as
+     *     well as subsequent authentication. This is expected to be enabled by
+     *     default to improve security and decrease falsing (unintentional face
+     *     detection). This feature can be disabled at the user's request
+     *     during enrollment, e.g. for accessibility reasons. When enabled,
+     *     the FaceAcquiredInfo#POOR_GAZE message must be sent when the user's
+     *     attention has not been established. The UI should inform the user
+     *     to look at the device.
+     * @return status The status of this method call.
+     */
+    @callflow(next={"cancel", "enroll", "revokeChallenge", "remove"})
+    enroll(vec<uint8_t> hat, uint32_t timeoutSec, bool requireAttention)
+        generates (Status status);
+
+    /**
+     * Finishes the secure transaction by invalidating the challenge generated
+     * by generateChallenge().
+     *
+     * Clients must call this method once enrollment is complete, and the user's
+     * face template no longer needs to be updated.
+     *
+     * @return status The status of this method call.
+     */
+    @callflow(next={"authenticate", "setActiveUser", "enumerate", "remove"})
+    revokeChallenge() generates (Status status);
+
+    /**
+     * Requires that all subsequent authenticate calls to first have the
+     * user's attention. This method does not affect enroll, which has its
+     * own requireAttention parameter.
+     *
+     * Changes the state of previous enrollment setting. Because this may
+     * decrease security, the user must enter their password before this method
+     * is invoked (see @param HAT). The driver must verify the HAT before
+     * changing the requireAttention state.
+     * Note: In some cases it may not be possible to change the state of this
+     * flag without re-enrolling. For example, if the user didn't provide
+     * attention during the original enrollment. This flag reflects the same
+     * persistent state as the one passed to enroll().
+     *
+     * @param requireAttention When set to true, requires user attention for
+     *     authentication to succeed.
+     * @param hat A valid Hardware Authentication Token, generated as a result
+     *     of getChallenge().
+     * @return status The status of this method call.
+     */
+    setRequireAttention(bool requireAttention, vec<uint8_t> hat)
+        generates(Status status);
+
+    /**
+     * Retrieves the current requireAttention state.
+     *
+     * @return result, with its value parameter representing the current
+     *     requireAttention state.
+     */
+    getRequireAttention(vec<uint8_t> hat) generates (OptionalBool result);
+
+    /**
+     * Returns an identifier associated with the current face set.
+     *
+     * The authenticator ID must change whenever a new face is enrolled. The
+     * authenticator ID must not be changed when a face is deleted. The
+     * authenticator ID must be an entropy-encoded random number which all
+     * current templates are tied to. The authenticator ID must be immutable
+     * outside of an active enrollment window to prevent replay attacks.
+     *
+     * @return result, with its value parameter representing an
+     *     "authenticatorId": an identifier associated to the user's current
+     *     face enrollment.
+     */
+    @callflow(next={"authenticate"})
+    getAuthenticatorId() generates (OptionalUint64 result);
+
+    /**
+     * Cancels a pending enrollment or authentication request.
+     *
+     * @return status The status of this method call.
+     */
+    @callflow(next={"authenticate", "enroll", "enumerate", "remove",
+        "setActiveUser"})
+    cancel() generates (Status status);
+
+    /**
+     * Enumerates all face templates associated with the active user.
+     *
+     * The onEnumerate() callback method is invoked once for each face template
+     * found.
+     *
+     * @return status The status of this method call.
+     */
+    @callflow(next={"remove", "enroll", "authenticate", "setActiveUser"})
+    enumerate() generates (Status status);
+
+    /**
+     * Removes a face template or all face templates associated with the active
+     * user.
+     *
+     * This method triggers the IBiometricsFaceClientCallback#onRemoved() method.
+     *
+     * @param faceId The id correpsonding to the face to be removed; or 0 if all
+     *    faces are to be removed.
+     * @return status The status of this method call.
+     */
+    @callflow(next={"enumerate", "authenticate", "cancel", "getAuthenticatorId",
+        "setActiveUser"})
+    remove(uint32_t faceId) generates (Status status);
+
+    /**
+     * Authenticates the active user.
+     *
+     * An optional operationId can be specified as a token from the transaction
+     * being authorized. The hardware may enter a standby state during
+     * authentication, where the device is idle to conserve power while
+     * authenticating, e.g. after 3 seconds without finding a face. See
+     * IBiometricsFace#userActivity() for more info.
+     *
+     * @param operationId A non-zero operation id associated with a crypto
+     * object instance; or 0 if not being used.
+     * @return status The status of this method call.
+     */
+    @callflow(next={"cancel", "generateChallenge", "remove"})
+    authenticate(uint64_t operationId) generates (Status status);
+
+    /**
+     * A hint to the HAL to continue looking for faces.
+     *
+     * This method should only be used when the HAL is in the authenticating
+     * or standby state. Using this method when the HAL is not in one of the
+     * mentioned states must return OPERATION_NOT_SUPPORTED. Calling this
+     * method while the HAL is already authenticating may extend the duration
+     * where it's looking for a face.
+     *
+     * @return status The status of this method call.
+     */
+    userActivity() generates (Status status);
+};
diff --git a/biometrics/face/1.0/IBiometricsFaceClientCallback.hal b/biometrics/face/1.0/IBiometricsFaceClientCallback.hal
new file mode 100644
index 0000000..93848c5
--- /dev/null
+++ b/biometrics/face/1.0/IBiometricsFaceClientCallback.hal
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.face@1.0;
+
+/**
+ * This callback interface is used by clients to recieve updates from the face
+ * HAL.
+ */
+interface IBiometricsFaceClientCallback {
+
+    /**
+     * A callback invoked when one enrollment step has been completed.
+     *
+     * @param deviceId A unique id associated with the HAL implementation
+     *     service that processed this enrollment step.
+     * @param faceId The id of the face template being enrolled.
+     * @param userId The active user id for the template being enrolled.
+     * @param remaining The number of remaining steps before enrolllment is
+     *     complete or 0 if enrollment has completed successfully.
+     */
+    oneway onEnrollResult(uint64_t deviceId, uint32_t faceId, int32_t userId,
+        uint32_t remaining);
+
+    /**
+     * A callback invoked when a face has been successfully authenticated.
+     *
+     * @param deviceId A unique id associated with the HAL implementation
+     *     service that processed this autentication attempt.
+     * @param faceId The id of the face template that passed the authentication
+     *     challenge.
+     * @param userId The active user id for the authenticated face.
+     * @param token The hardware authentication token associated with this
+     *     authenticate operation.
+     */
+    oneway onAuthenticated(uint64_t deviceId, uint32_t faceId, int32_t userId,
+        vec<uint8_t> token);
+
+    /**
+     * A callback invoked when a face is acquired.
+     *
+     * If a non-critical, recoverable error occurs during an enrollment or
+     * authentication attempt, the HAL implementation must invoke this callback
+     * to allow clients to inform the user that some actionable change must be
+     * made.
+     *
+     * @param deviceId A unique id associated with the HAL implementation
+     *     service that acquired a face.
+     * @param userId The id of the active user associated with the attempted
+     *     face acquisition.
+     * @param acquiredInfo A message about the quality of the acquired image.
+     * @param vendorCode An optional vendor-specific message. This is only valid
+     *     when acquiredInfo == FaceAcquiredInfo.VENDOR. This message is opaque
+     *     to the framework, and vendors must provide code to handle it. For
+     *     example this can be used to guide enrollment in Settings or provide
+     *     a message during authentication that is vendor-specific. The vendor
+     *     is expected to provide help strings to cover all known values.
+     */
+     oneway onAcquired(uint64_t deviceId, int32_t userId,
+         FaceAcquiredInfo acquiredInfo, int32_t vendorCode);
+
+    /**
+     * A callback invoked when an error has occured.
+     *
+     * @param deviceId A unique id associated with the HAL implementation
+     *     service where this error occured.
+     * @param userId The id of the active user when the error occured, or
+     *     UserHandle::NONE if an active user had not been set yet.
+     * @param error A message about the error that occurred.
+     * @param vendorCode An optional, vendor-speicifc error message. Only valid
+     *     when error == FaceError.VENDOR. This message is opaque to the
+     *     framework, and vendors must provide code to handle it. For example,
+     *     this scan be used to show the user an error message specific to the
+     *     device. The vendor is expected to provide error strings to cover
+     *     all known values.
+     */
+    oneway onError(uint64_t deviceId, int32_t userId, FaceError error,
+        int32_t vendorCode);
+
+    /**
+     * A callback invoked when a face template has been removed.
+     *
+     * @param deviceId A unique id associated with the HAL implementation
+     *     service that processed this removal.
+     * @param faceId The id of the face template that was removed.
+     * @param userId The active user id for the removed face template.
+     * @param remaining The number of face templates remaining after this
+     *     removal, or 0 if there are no more.
+     */
+    oneway onRemoved(uint64_t deviceId, uint32_t faceId, int32_t userId,
+        uint32_t remaining);
+
+    /**
+     * A callback invoked to enumerate all current face templates.
+     *
+     * @param deviceId A unique id associated with the HAL implementation
+     *     service that processed this enumeration.
+     * @param faceIds A list of ids of all currently enrolled face templates.
+     * @param userId The active user id for the enumerated face template.
+     */
+    oneway onEnumerate(uint64_t deviceId, vec<uint32_t> faceIds,
+        int32_t userId);
+};
diff --git a/biometrics/face/1.0/types.hal b/biometrics/face/1.0/types.hal
new file mode 100644
index 0000000..2628af9
--- /dev/null
+++ b/biometrics/face/1.0/types.hal
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.biometrics.face@1.0;
+
+/*
+ * In the event setActiveUser is not called, all error messages will return
+ * this userId.
+ */
+enum UserHandle : int32_t {
+    NONE = -1
+};
+
+/**
+ * Status codes returned directly by the HIDL method calls upon critical errors
+ * where the callback cannot be invoked. Most errors should sent through the
+ * onError callback using one of the FaceErrors below.
+ */
+enum Status : uint32_t {
+    /**
+     * The method was invoked successfully.
+     */
+    OK = 0,
+
+    /**
+     * One of the arguments to the method call is invalid.
+     */
+    ILLEGAL_ARGUMENT = 1,
+
+    /**
+     * This face HAL does not support this operation.
+     */
+    OPERATION_NOT_SUPPORTED = 2,
+
+    /**
+     * The HAL has encountered an internal error and cannot complete the request.
+     */
+    INTERNAL_ERROR = 3,
+
+    /**
+     * The operation could not be completed because there are no enrolled
+     * templates.
+     */
+    NOT_ENROLLED = 4
+};
+
+/**
+ * Face errors represent events that can't be immediately recovered by user
+ * intervention. These are returned in the onError callback.
+ *
+ * Upon receiving a face error, clients must terminate the current operation and
+ * notify the user where possible.
+ */
+enum FaceError : int32_t {
+
+    /**
+     * A hardware error has occured that cannot be resolved. Try again later.
+     */
+    HW_UNAVAILABLE = 1,
+
+    /**
+     * The current enroll or authenticate operation could not be completed;
+     * the sensor was unable to process the current image.
+     */
+    UNABLE_TO_PROCESS = 2,
+
+    /**
+     * The current operation took too long to complete. This is intended to
+     * prevent programs from blocking the face HAL indefinitely. The timeout is
+     * framework and sensor-specific, but is generally on the order of 30
+     * seconds.
+     */
+    TIMEOUT = 3,
+
+    /**
+     * The current operation could not be completed because there is not enough
+     * storage space remaining to do so.
+     */
+    NO_SPACE = 4,
+
+    /**
+     * The current operation has been cancelled. This may happen if a new
+     * request (authenticate, remove) is initiated while an on-going operation
+     * is in progress, or if cancel() was called.
+     */
+    CANCELED = 5,
+
+    /**
+     * The current remove operation could not be completed; the face template
+     * provided could not be removed.
+     */
+    UNABLE_TO_REMOVE = 6,
+
+    /**
+     * Face authentication is locked out due to too many unsuccessful attempts.
+     */
+    LOCKOUT = 7,
+
+    /**
+     * Used to enable a vendor-specific error message.
+     */
+    VENDOR = 8,
+};
+
+/**
+ * Face acquisition information provides feedback for the current enrollment
+ * or authentication operation.
+ *
+ * This information indicates that the user can take immediate action to resolve
+ * an issue, and clients must ensure that this information is surfaced to the
+ * user.
+ */
+enum FaceAcquiredInfo : int32_t {
+
+    /**
+     * The face acquired was good; no further user interaction is necessary.
+     */
+    GOOD = 0,
+
+    /**
+     * The face data acquired was too noisy or did not have sufficient detail.
+     * This is a catch-all for all acquisition errors not captured by the other
+     * constants.
+     */
+    INSUFFICIENT = 1,
+
+    /**
+     * Because there was too much ambient light, the captured face data was too
+     * bright. It's reasonable to return this after multiple
+     * FaceAcquiredInfo.INSUFFICIENT.
+     *
+     * The user is expected to take action to retry the operation in better
+     * lighting conditions when this is returned.
+     */
+    TOO_BRIGHT = 2,
+
+    /**
+     * Because there was not enough illumination, the captured face data was too
+     * dark. It's reasonable to return this after multiple
+     * FaceAcquiredInfo.INSUFFICIENT.
+     *
+     * The user is expected to take action to retry the operation in better
+     * lighting conditions when this is returned.
+     */
+    TOO_DARK = 3,
+
+    /**
+     * The detected face is too close to the sensor, and the image cannot be
+     * processed.
+     *
+     * The user is expected to be informed to move further from the sensor when
+     * this is returned.
+     */
+    TOO_CLOSE = 4,
+
+    /**
+     * The detected face is too small, as the user might be too far away from
+     * the sensor.
+     *
+     * The user is expected to be informed to move closer to the sensor when
+     * this is returned.
+     */
+    TOO_FAR = 5,
+
+    /**
+     * Only the upper part of the face was detected. The sensor's field of view
+     * is too high.
+     *
+     * The user should be informed to move up with respect to the sensor when
+     * this is returned.
+     */
+    FACE_TOO_HIGH = 6,
+
+    /**
+     * Only the lower part of the face was detected. The sensor's field of view
+     * is too low.
+     *
+     * The user should be informed to move down with respect to the sensor when
+     * this is returned.
+     */
+    FACE_TOO_LOW = 7,
+
+    /**
+     * Only the right part of the face was detected. The sensor's field of view
+     * is too far right.
+     *
+     * The user should be informed to move to the right with respect to the
+     * sensor when this is returned.
+     */
+    FACE_TOO_RIGHT = 8,
+
+    /**
+     * Only the left part of the face was detected. The sensor's field of view
+     * is too far left.
+     *
+     * The user should be informed to move to the left with respect to the
+     * sensor when this is returned.
+     */
+    FACE_TOO_LEFT = 9,
+
+    /**
+     * The user's eyes have strayed away from the sensor. If this message is
+     * sent, the user should be informed to look at the device. If the user
+     * can't be found in the frame, one of the other acquisition messages
+     * must be sent, e.g. NOT_DETECTED.
+     */
+    POOR_GAZE = 10,
+
+    /**
+     * No face was detected within the sensor's field of view.
+     *
+     * The user should be informed to point the sensor to a face when this is
+     * returned.
+     */
+    NOT_DETECTED = 11,
+
+    /**
+     * Too much motion was detected.
+     *
+     * The user should be informed to keep their face steady relative to the
+     * sensor.
+     */
+    TOO_MUCH_MOTION = 12,
+
+    /**
+     * The sensor needs to be re-calibrated. This is an unexpected condition,
+     * and must only be sent if a serious, uncorrectable, and unrecoverable
+     * calibration issue is detected which requires user intervention, e.g.
+     * re-enrolling. The expected response to this message is to direct the
+     * user to re-enroll.
+     */
+    RECALIBRATE = 13,
+
+    /**
+     * Used to enable a vendor-specific acquisition message.
+     */
+    VENDOR = 14
+};
+
+/**
+ * Result structure with an additional uint64_t field. See documentation in
+ * setCallback(), preEnroll(), and getAuthenticatorId() for usage of the value.
+ */
+struct OptionalUint64 {
+    /**
+     * The return status.
+     */
+    Status status;
+
+    /**
+     * This value is only meaningful if status is OK.
+     */
+    uint64_t value;
+};
+
+/**
+ * Result structure with an addition bool field. See documentation in
+ * getRequireAttention() for usage of the value.
+ */
+struct OptionalBool {
+    /**
+     * The return status.
+     */
+    Status status;
+
+    /**
+     * This value is only meaningful if status is OK.
+     */
+    bool value;
+};
\ No newline at end of file
diff --git a/camera/common/1.0/default/CameraModule.cpp b/camera/common/1.0/default/CameraModule.cpp
index dc4e0f0..392ebbc 100644
--- a/camera/common/1.0/default/CameraModule.cpp
+++ b/camera/common/1.0/default/CameraModule.cpp
@@ -235,7 +235,7 @@
     chars.update(keyTag, availableKeys);
 }
 
-CameraModule::CameraModule(camera_module_t *module) {
+CameraModule::CameraModule(camera_module_t *module) : mNumberOfCameras(0) {
     if (module == NULL) {
         ALOGE("%s: camera hardware module must not be null", __FUNCTION__);
         assert(0);
@@ -264,7 +264,8 @@
         res = mModule->init();
         ATRACE_END();
     }
-    mCameraInfoMap.setCapacity(getNumberOfCameras());
+    mNumberOfCameras = getNumberOfCameras();
+    mCameraInfoMap.setCapacity(mNumberOfCameras);
     return res;
 }
 
@@ -319,6 +320,45 @@
     return OK;
 }
 
+int CameraModule::getPhysicalCameraInfo(int physicalCameraId, camera_metadata_t **physicalInfo) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mCameraInfoLock);
+    if (physicalCameraId < mNumberOfCameras) {
+        ALOGE("%s: Invalid physical camera ID %d", __FUNCTION__, physicalCameraId);
+        return -EINVAL;
+    }
+
+    // Only query physical camera info for 2.5 version for newer
+    int apiVersion = mModule->common.module_api_version;
+    if (apiVersion < CAMERA_MODULE_API_VERSION_2_5) {
+        ALOGE("%s: Module version must be at least 2.5 to handle getPhysicalCameraInfo",
+                __FUNCTION__);
+        return -ENODEV;
+    }
+    if (mModule->get_physical_camera_info == nullptr) {
+        ALOGE("%s: get_physical_camera is NULL for module version 2.5", __FUNCTION__);
+        return -EINVAL;
+    }
+
+    ssize_t index = mPhysicalCameraInfoMap.indexOfKey(physicalCameraId);
+    if (index == NAME_NOT_FOUND) {
+        // Get physical camera characteristics, and cache it
+        camera_metadata_t *info = nullptr;
+        ATRACE_BEGIN("camera_module->get_physical_camera_info");
+        int ret = mModule->get_physical_camera_info(physicalCameraId, &info);
+        ATRACE_END();
+        if (ret != 0) {
+            return ret;
+        }
+
+        index = mPhysicalCameraInfoMap.add(physicalCameraId, info);
+    }
+
+    assert(index != NAME_NOT_FOUND);
+    *physicalInfo = mPhysicalCameraInfoMap[index];
+    return OK;
+}
+
 int CameraModule::getDeviceVersion(int cameraId) {
     ssize_t index = mDeviceVersionMap.indexOfKey(cameraId);
     if (index == NAME_NOT_FOUND) {
diff --git a/camera/common/1.0/default/OWNERS b/camera/common/1.0/default/OWNERS
index 18acfee..369b204 100644
--- a/camera/common/1.0/default/OWNERS
+++ b/camera/common/1.0/default/OWNERS
@@ -1,6 +1,7 @@
 cychen@google.com
 epeev@google.com
 etalvala@google.com
+jchowdhary@google.com
 shuzhenwang@google.com
 yinchiayeh@google.com
 zhijunhe@google.com
diff --git a/camera/common/1.0/default/include/CameraModule.h b/camera/common/1.0/default/include/CameraModule.h
index deebd09..aee9654 100644
--- a/camera/common/1.0/default/include/CameraModule.h
+++ b/camera/common/1.0/default/include/CameraModule.h
@@ -65,6 +65,7 @@
     void *getDso();
     // Only used by CameraProvider
     void removeCamera(int cameraId);
+    int getPhysicalCameraInfo(int physicalCameraId, camera_metadata_t **physicalInfo);
 
 private:
     // Derive camera characteristics keys defined after HAL device version
@@ -74,8 +75,10 @@
             int32_t keyTag, const Vector<int32_t>& appendKeys);
     status_t filterOpenErrorCode(status_t err);
     camera_module_t *mModule;
+    int mNumberOfCameras;
     KeyedVector<int, camera_info> mCameraInfoMap;
     KeyedVector<int, int> mDeviceVersionMap;
+    KeyedVector<int, camera_metadata_t*> mPhysicalCameraInfoMap;
     Mutex mCameraInfoLock;
 };
 
diff --git a/camera/device/1.0/default/OWNERS b/camera/device/1.0/default/OWNERS
index 18acfee..369b204 100644
--- a/camera/device/1.0/default/OWNERS
+++ b/camera/device/1.0/default/OWNERS
@@ -1,6 +1,7 @@
 cychen@google.com
 epeev@google.com
 etalvala@google.com
+jchowdhary@google.com
 shuzhenwang@google.com
 yinchiayeh@google.com
 zhijunhe@google.com
diff --git a/camera/device/3.2/ICameraDevice.hal b/camera/device/3.2/ICameraDevice.hal
index 1f523e4..5236bb1 100644
--- a/camera/device/3.2/ICameraDevice.hal
+++ b/camera/device/3.2/ICameraDevice.hal
@@ -148,7 +148,9 @@
      * session handle for active operations.
      *
      * @param callback Interface to invoke by the HAL for device asynchronous
-     *     events.
+     *     events. For HALs newer than version 3.2, HAL must use castFrom
+     *     method to check the exact version of callback sent by camera service.
+     *
      * @return status Status code for the operation, one of:
      *     OK:
      *         On a successful open of the camera device.
diff --git a/camera/device/3.2/ICameraDeviceSession.hal b/camera/device/3.2/ICameraDeviceSession.hal
index 477a3cc..225e52b 100644
--- a/camera/device/3.2/ICameraDeviceSession.hal
+++ b/camera/device/3.2/ICameraDeviceSession.hal
@@ -149,9 +149,8 @@
      *           - Including too many output streams of a certain format.
      *           - Unsupported rotation configuration
      *           - Stream sizes/formats don't satisfy the
-     *             camera3_stream_configuration_t->operation_mode requirements
-     *             for non-NORMAL mode, or the requested operation_mode is not
-     *             supported by the HAL.
+     *             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
diff --git a/camera/device/3.2/default/CameraDevice.cpp b/camera/device/3.2/default/CameraDevice.cpp
index dfbb976..2e80ce8 100644
--- a/camera/device/3.2/default/CameraDevice.cpp
+++ b/camera/device/3.2/default/CameraDevice.cpp
@@ -101,7 +101,7 @@
 }
 
 // Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow.
-Return<void> CameraDevice::getResourceCost(getResourceCost_cb _hidl_cb)  {
+Return<void> CameraDevice::getResourceCost(ICameraDevice::getResourceCost_cb _hidl_cb)  {
     Status status = initStatus();
     CameraResourceCost resCost;
     if (status == Status::OK) {
@@ -141,7 +141,8 @@
     return Void();
 }
 
-Return<void> CameraDevice::getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb)  {
+Return<void> CameraDevice::getCameraCharacteristics(
+        ICameraDevice::getCameraCharacteristics_cb _hidl_cb)  {
     Status status = initStatus();
     CameraMetadata cameraCharacteristics;
     if (status == Status::OK) {
@@ -172,7 +173,8 @@
     return status;
 }
 
-Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb)  {
+Return<void> CameraDevice::open(const sp<ICameraDeviceCallback>& callback,
+        ICameraDevice::open_cb _hidl_cb)  {
     Status status = initStatus();
     sp<CameraDeviceSession> session = nullptr;
 
diff --git a/camera/device/3.2/default/CameraDevice_3_2.h b/camera/device/3.2/default/CameraDevice_3_2.h
index 9534707..f474533 100644
--- a/camera/device/3.2/default/CameraDevice_3_2.h
+++ b/camera/device/3.2/default/CameraDevice_3_2.h
@@ -51,7 +51,7 @@
 /*
  * The camera device HAL implementation is opened lazily (via the open call)
  */
-struct CameraDevice : public ICameraDevice {
+struct CameraDevice : public virtual RefBase {
     // Called by provider HAL. Provider HAL must ensure the uniqueness of
     // CameraDevice object per cameraId, or there could be multiple CameraDevice
     // trying to access the same physical camera.
@@ -60,7 +60,14 @@
     CameraDevice(sp<CameraModule> module,
                  const std::string& cameraId,
                  const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames);
-    ~CameraDevice();
+    virtual ~CameraDevice();
+
+    // Retrieve the HIDL interface, split into its own class to avoid inheritance issues when
+    // dealing with minor version revs and simultaneous implementation and interface inheritance
+    virtual sp<ICameraDevice> getInterface() {
+        return new TrampolineDeviceInterface_3_2(this);
+    }
+
     // Caller must use this method to check if CameraDevice ctor failed
     bool isInitFailed() { return mInitFail; }
     // Used by provider HAL to signal external camera disconnected
@@ -68,16 +75,16 @@
 
     /* Methods from ::android::hardware::camera::device::V3_2::ICameraDevice follow. */
     // The following method can be called without opening the actual camera device
-    Return<void> getResourceCost(getResourceCost_cb _hidl_cb) override;
-    Return<void> getCameraCharacteristics(getCameraCharacteristics_cb _hidl_cb) override;
-    Return<Status> setTorchMode(TorchMode mode) override;
+    Return<void> getResourceCost(ICameraDevice::getResourceCost_cb _hidl_cb);
+    Return<void> getCameraCharacteristics(ICameraDevice::getCameraCharacteristics_cb _hidl_cb);
+    Return<Status> setTorchMode(TorchMode mode);
 
     // Open the device HAL and also return a default capture session
-    Return<void> open(const sp<ICameraDeviceCallback>& callback, open_cb _hidl_cb) override;
+    Return<void> open(const sp<ICameraDeviceCallback>& callback, ICameraDevice::open_cb _hidl_cb);
 
 
     // Forward the dump call to the opened session, or do nothing
-    Return<void> dumpState(const ::android::hardware::hidl_handle& fd) override;
+    Return<void> dumpState(const ::android::hardware::hidl_handle& fd);
     /* End of Methods from ::android::hardware::camera::device::V3_2::ICameraDevice */
 
 protected:
@@ -106,6 +113,39 @@
     static Status getHidlStatus(int);
 
     Status initStatus() const;
+
+private:
+    struct TrampolineDeviceInterface_3_2 : public ICameraDevice {
+        TrampolineDeviceInterface_3_2(sp<CameraDevice> parent) :
+            mParent(parent) {}
+
+        virtual Return<void> getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb)
+                override {
+            return mParent->getResourceCost(_hidl_cb);
+        }
+
+        virtual Return<void> getCameraCharacteristics(
+                V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override {
+            return mParent->getCameraCharacteristics(_hidl_cb);
+        }
+
+        virtual Return<Status> setTorchMode(TorchMode mode) override {
+            return mParent->setTorchMode(mode);
+        }
+
+        virtual Return<void> open(const sp<V3_2::ICameraDeviceCallback>& callback,
+                V3_2::ICameraDevice::open_cb _hidl_cb) override {
+            return mParent->open(callback, _hidl_cb);
+        }
+
+        virtual Return<void> dumpState(const hidl_handle& fd) override {
+            return mParent->dumpState(fd);
+        }
+
+    private:
+        sp<CameraDevice> mParent;
+    };
+
 };
 
 }  // namespace implementation
diff --git a/camera/device/3.2/default/OWNERS b/camera/device/3.2/default/OWNERS
index 18acfee..369b204 100644
--- a/camera/device/3.2/default/OWNERS
+++ b/camera/device/3.2/default/OWNERS
@@ -1,6 +1,7 @@
 cychen@google.com
 epeev@google.com
 etalvala@google.com
+jchowdhary@google.com
 shuzhenwang@google.com
 yinchiayeh@google.com
 zhijunhe@google.com
diff --git a/camera/device/3.3/default/OWNERS b/camera/device/3.3/default/OWNERS
index 18acfee..369b204 100644
--- a/camera/device/3.3/default/OWNERS
+++ b/camera/device/3.3/default/OWNERS
@@ -1,6 +1,7 @@
 cychen@google.com
 epeev@google.com
 etalvala@google.com
+jchowdhary@google.com
 shuzhenwang@google.com
 yinchiayeh@google.com
 zhijunhe@google.com
diff --git a/camera/device/3.4/ICameraDeviceSession.hal b/camera/device/3.4/ICameraDeviceSession.hal
index c41d90e..e1663e6 100644
--- a/camera/device/3.4/ICameraDeviceSession.hal
+++ b/camera/device/3.4/ICameraDeviceSession.hal
@@ -54,7 +54,7 @@
      *           - Including too many output streams of a certain format.
      *           - Unsupported rotation configuration
      *           - Stream sizes/formats don't satisfy the
-     *             camera3_stream_configuration_t->operation_mode requirements
+     *             StreamConfigurationMode requirements
      *             for non-NORMAL mode, or the requested operation_mode is not
      *             supported by the HAL.
      *           - Unsupported usage flag
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index dce40ff..653ad59 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -344,17 +344,31 @@
         ICameraDeviceSession::configureStreams_3_4_cb _hidl_cb)  {
     V3_2::StreamConfiguration config_v32;
     V3_3::HalStreamConfiguration outStreams_v33;
+    V3_4::HalStreamConfiguration outStreams;
     Mutex::Autolock _il(mInterfaceLock);
 
     config_v32.operationMode = requestedConfiguration.operationMode;
     config_v32.streams.resize(requestedConfiguration.streams.size());
+    uint32_t blobBufferSize = 0;
+    int numStallStream = 0;
     for (size_t i = 0; i < config_v32.streams.size(); i++) {
         config_v32.streams[i] = requestedConfiguration.streams[i].v3_2;
+        if (config_v32.streams[i].format == PixelFormat::BLOB) {
+            blobBufferSize = requestedConfiguration.streams[i].bufferSize;
+            numStallStream++;
+        }
     }
 
-    Status status = configureStreams(config_v32, &outStreams_v33);
+    // Fail early if there are multiple BLOB streams
+    if (numStallStream > kMaxStallStream) {
+        ALOGE("%s: too many stall streams (expect <= %d, got %d)", __FUNCTION__,
+                kMaxStallStream, numStallStream);
+        _hidl_cb(Status::ILLEGAL_ARGUMENT, outStreams);
+        return Void();
+    }
 
-    V3_4::HalStreamConfiguration outStreams;
+    Status status = configureStreams(config_v32, &outStreams_v33, blobBufferSize);
+
     outStreams.streams.resize(outStreams_v33.streams.size());
     for (size_t i = 0; i < outStreams.streams.size(); i++) {
         outStreams.streams[i].v3_3 = outStreams_v33.streams[i];
@@ -1592,8 +1606,9 @@
      * main image needs to hold APP1, headers, and at most a poorly
      * compressed image */
     const ssize_t maxThumbCodeSize = 64 * 1024;
-    const ssize_t maxJpegCodeSize = parent->getJpegBufferSize(jpegSize.width,
-                                                             jpegSize.height);
+    const ssize_t maxJpegCodeSize = mBlobBufferSize == 0 ?
+            parent->getJpegBufferSize(jpegSize.width, jpegSize.height) :
+            mBlobBufferSize;
 
     /* Check that getJpegBufferSize did not return an error */
     if (maxJpegCodeSize < 0) {
@@ -1859,7 +1874,8 @@
 
 Status ExternalCameraDeviceSession::OutputThread::allocateIntermediateBuffers(
         const Size& v4lSize, const Size& thumbSize,
-        const hidl_vec<Stream>& streams) {
+        const hidl_vec<Stream>& streams,
+        uint32_t blobBufferSize) {
     std::lock_guard<std::mutex> lk(mBufferLock);
     if (mScaledYu12Frames.size() != 0) {
         ALOGE("%s: intermediate buffer pool has %zu inflight buffers! (expect 0)",
@@ -1928,6 +1944,8 @@
             it = mIntermediateBuffers.erase(it);
         }
     }
+
+    mBlobBufferSize = blobBufferSize;
     return Status::OK;
 }
 
@@ -2425,7 +2443,9 @@
 }
 
 Status ExternalCameraDeviceSession::configureStreams(
-        const V3_2::StreamConfiguration& config, V3_3::HalStreamConfiguration* out) {
+        const V3_2::StreamConfiguration& config,
+        V3_3::HalStreamConfiguration* out,
+        uint32_t blobBufferSize) {
     ATRACE_CALL();
     if (config.operationMode != StreamConfigurationMode::NORMAL_MODE) {
         ALOGE("%s: unsupported operation mode: %d", __FUNCTION__, config.operationMode);
@@ -2587,7 +2607,7 @@
     }
 
     status = mOutputThread->allocateIntermediateBuffers(v4lSize,
-                mMaxThumbResolution, config.streams);
+                mMaxThumbResolution, config.streams, blobBufferSize);
     if (status != Status::OK) {
         ALOGE("%s: allocating intermediate buffers failed!", __FUNCTION__);
         return status;
diff --git a/camera/device/3.4/default/OWNERS b/camera/device/3.4/default/OWNERS
index 18acfee..369b204 100644
--- a/camera/device/3.4/default/OWNERS
+++ b/camera/device/3.4/default/OWNERS
@@ -1,6 +1,7 @@
 cychen@google.com
 epeev@google.com
 etalvala@google.com
+jchowdhary@google.com
 shuzhenwang@google.com
 yinchiayeh@google.com
 zhijunhe@google.com
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
index 0b94c11..6e56596 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -177,7 +177,10 @@
     Status initStatus() const;
     status_t initDefaultRequests();
     status_t fillCaptureResult(common::V1_0::helper::CameraMetadata& md, nsecs_t timestamp);
-    Status configureStreams(const V3_2::StreamConfiguration&, V3_3::HalStreamConfiguration* out);
+    Status configureStreams(const V3_2::StreamConfiguration&,
+            V3_3::HalStreamConfiguration* out,
+            // Only filled by configureStreams_3_4, and only one blob stream supported
+            uint32_t blobBufferSize = 0);
     // fps = 0.0 means default, which is
     // slowest fps that is at least 30, or fastest fps if 30 is not supported
     int configureV4l2StreamLocked(const SupportedV4L2Format& fmt, double fps = 0.0);
@@ -225,7 +228,8 @@
 
         Status allocateIntermediateBuffers(
                 const Size& v4lSize, const Size& thumbSize,
-                const hidl_vec<Stream>& streams);
+                const hidl_vec<Stream>& streams,
+                uint32_t blobBufferSize);
         Status submitRequest(const std::shared_ptr<HalRequest>&);
         void flush();
         void dump(int fd);
@@ -289,6 +293,7 @@
         std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
         YCbCrLayout mYu12FrameLayout;
         YCbCrLayout mYu12ThumbFrameLayout;
+        uint32_t mBlobBufferSize = 0; // 0 -> HAL derive buffer size, else: use given size
 
         std::string mExifMake;
         std::string mExifModel;
diff --git a/camera/device/3.5/Android.bp b/camera/device/3.5/Android.bp
new file mode 100644
index 0000000..2a9ba05
--- /dev/null
+++ b/camera/device/3.5/Android.bp
@@ -0,0 +1,33 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.camera.device@3.5",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "ICameraDevice.hal",
+        "ICameraDeviceCallback.hal",
+        "ICameraDeviceSession.hal",
+    ],
+    interfaces: [
+        "android.hardware.camera.common@1.0",
+        "android.hardware.camera.device@3.2",
+        "android.hardware.camera.device@3.3",
+        "android.hardware.camera.device@3.4",
+        "android.hardware.graphics.common@1.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "BufferRequest",
+        "BufferRequestStatus",
+        "StreamBufferRequestError",
+        "StreamBufferRet",
+        "StreamBuffersVal",
+        "StreamConfiguration",
+    ],
+    gen_java: false,
+}
+
diff --git a/camera/device/3.5/ICameraDevice.hal b/camera/device/3.5/ICameraDevice.hal
new file mode 100644
index 0000000..a77380f
--- /dev/null
+++ b/camera/device/3.5/ICameraDevice.hal
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.5;
+
+import android.hardware.camera.common@1.0::Status;
+import @3.2::CameraMetadata;
+import @3.2::ICameraDevice;
+
+/**
+ * Camera device interface
+ *
+ * Supports the android.hardware.Camera API, and the android.hardware.camera2
+ * API at LIMITED or better hardware level.
+ *
+ */
+interface ICameraDevice extends @3.2::ICameraDevice {
+
+    /**
+     * getPhysicalCameraCharacteristics:
+     *
+     * Return the static camera information for a physical camera ID backing
+     * this logical camera device. This information may not change between consecutive calls.
+     *
+     * Note that HAL must support this function for physical camera IDs that are
+     * not exposed via ICameraProvider::getCameraIdList(). Calling
+     * getCameraDeviceInterface_V3_x() on these camera IDs must return ILLEGAL_ARGUMENT.
+     *
+     * The characteristics of all cameras returned by
+     * ICameraProvider::getCameraIdList() must be queried via
+     * getCameraCharacteristics(). Calling getPhysicalCameraCharacteristics() on
+     * those cameras must return ILLEGAL_ARGUMENT.
+     *
+     * @param physicalCameraId The physical camera id parsed from the logical
+     *     camera's ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS static metadata
+     *     key. The framework assumes that this ID is just the <id> part of fully
+     *     qualified camera device name "device@<major>.<minor>/<type>/<id>". And
+     *     the physical camera must be of the same version and type as the parent
+     *     logical camera device.
+     *
+     * @return status Status code for the operation, one of:
+     *     OK:
+     *         On a successful query of the physical camera device characteristics
+     *     INTERNAL_ERROR:
+     *         The camera device cannot be opened due to an internal
+     *         error.
+     *     CAMERA_DISCONNECTED:
+     *         An external camera device has been disconnected, and is no longer
+     *         available. This camera device interface is now stale, and a new
+     *         instance must be acquired if the device is reconnected. All
+     *         subsequent calls on this interface must return
+     *         CAMERA_DISCONNECTED.
+     *     ILLEGAL_ARGUMENT:
+     *         If the physicalCameraId is not a valid physical camera Id outside
+     *         of ICameraProvider::getCameraIdList().
+     *
+     * @return cameraCharacteristics
+     *     The static metadata for this logical camera device's physical device, or an empty
+     *     metadata structure if status is not OK.
+     *
+     */
+    getPhysicalCameraCharacteristics(string physicalCameraId)
+            generates (Status status, CameraMetadata cameraCharacteristics);
+
+};
diff --git a/camera/device/3.5/ICameraDeviceCallback.hal b/camera/device/3.5/ICameraDeviceCallback.hal
new file mode 100644
index 0000000..aa4ad22
--- /dev/null
+++ b/camera/device/3.5/ICameraDeviceCallback.hal
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.5;
+
+import @3.2::StreamBuffer;
+import @3.4::ICameraDeviceCallback;
+
+/**
+ * Callback methods for the HAL to call into the framework.
+ */
+interface ICameraDeviceCallback extends @3.4::ICameraDeviceCallback {
+
+    /**
+     * requestStreamBuffers:
+     *
+     * Synchronous callback for HAL to ask for output buffers from camera service.
+     *
+     * This call may be serialized in camera service so it is strongly
+     * recommended to only call this method from one thread.
+     *
+     * When camera device advertises
+     * (CameraMetadataEnumAndroidInfoSupportedBufferManagementVersion ==
+     * ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5), HAL
+     * can use this method to request buffers from camera service.
+     *
+     * @return status Status code for the operation, one of:
+     *     OK: all requested buffers are returned
+     *     FAILED_PARTIAL: some streams failed while some succeeds. Check
+     *             individual StreamBufferRet for details.
+     *     FAILED_CONFIGURING: the request failed because camera servicve is
+     *             performing configureStreams and no buffers are returned.
+     *     FAILED_UNKNOWN: the request failed for unknown reason and no buffers
+     *             are returned.
+     *
+     * Performance requirements:
+     * This is a blocking call that takes more time with more buffers requested.
+     * HAL must not request large amount of buffers on a latency critical code
+     * path. It is highly recommended to use a dedicated thread to perform
+     * all requestStreamBuffers calls, and adjust the thread priority and/or
+     * timing of making the call in order for buffers to arrive before HAL is
+     * ready to fill the buffer.
+     */
+    requestStreamBuffers(vec<BufferRequest> bufReqs)
+            generates (BufferRequestStatus st, vec<StreamBufferRet> buffers);
+
+    /**
+     * returnStreamBuffers:
+     *
+     * Synchronous callback for HAL to return output buffers to camera service.
+     *
+     * If this method is called during a configureStreams call, it must be blocked
+     * until camera service finishes the ongoing configureStreams call.
+     */
+    returnStreamBuffers(vec<StreamBuffer> buffers);
+
+};
diff --git a/camera/device/3.5/ICameraDeviceSession.hal b/camera/device/3.5/ICameraDeviceSession.hal
new file mode 100644
index 0000000..b2b71cd
--- /dev/null
+++ b/camera/device/3.5/ICameraDeviceSession.hal
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.5;
+
+import android.hardware.camera.common@1.0::Status;
+import @3.4::ICameraDeviceSession;
+import @3.4::HalStreamConfiguration;
+
+/**
+ * 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.4::ICameraDeviceSession {
+
+    /**
+     * configureStreams_3_5:
+     *
+     * Identical to @3.4::ICameraDeviceSession.configureStreams, except that:
+     *
+     * - a streamConfigCounter counter is provided to check for race condition
+     *   between configureStreams_3_5 and signalStreamFlush call.
+     *
+     * @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_5(@3.5::StreamConfiguration requestedConfiguration)
+            generates (Status status,
+                       @3.4::HalStreamConfiguration halConfiguration);
+
+
+    /**
+     * signalStreamFlush:
+     *
+     * Signaling HAL camera service is about to perform configureStreams_3_5 and
+     * HAL must return all buffers of designated streams. HAL must finish
+     * inflight requests normally and return all buffers that belongs to the
+     * designated streams through processCaptureResult or returnStreamBuffer
+     * API in a timely manner, or camera service will run into a fatal error.
+     *
+     * Note that this call serves as an optional hint and camera service may
+     * skip sending this call if all buffers are already returned.
+     *
+     * @param streamIds The ID of streams camera service need all of its
+     *     buffers returned.
+     *
+     * @param streamConfigCounter Note that due to concurrency nature, it is
+     *     possible the signalStreamFlush call arrives later than the
+     *     corresponding configureStreams_3_5 call, HAL must check
+     *     streamConfigCounter for such race condition. If the counter is less
+     *     than the counter in the last configureStreams_3_5 call HAL last
+     *     received, the call is stale and HAL should just return this call.
+     */
+    oneway signalStreamFlush(
+        vec<int32_t> streamIds,
+        uint32_t streamConfigCounter
+    );
+};
diff --git a/camera/device/3.5/default/Android.bp b/camera/device/3.5/default/Android.bp
new file mode 100644
index 0000000..09cf3a4
--- /dev/null
+++ b/camera/device/3.5/default/Android.bp
@@ -0,0 +1,54 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_headers {
+    name: "camera.device@3.5-impl_headers",
+    vendor: true,
+    export_include_dirs: ["include/device_v3_5_impl"]
+}
+
+cc_library_shared {
+    name: "camera.device@3.5-impl",
+    defaults: ["hidl_defaults"],
+    proprietary: true,
+    vendor: true,
+    srcs: [
+        "CameraDevice.cpp",
+        "CameraDeviceSession.cpp",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "libutils",
+        "libcutils",
+        "camera.device@3.2-impl",
+        "camera.device@3.3-impl",
+        "camera.device@3.4-impl",
+        "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.camera.provider@2.4",
+        "android.hardware.graphics.mapper@2.0",
+        "liblog",
+        "libhardware",
+        "libcamera_metadata",
+    ],
+    static_libs: [
+        "android.hardware.camera.common@1.0-helper",
+    ],
+    local_include_dirs: ["include/device_v3_5_impl"],
+}
diff --git a/camera/device/3.5/default/CameraDevice.cpp b/camera/device/3.5/default/CameraDevice.cpp
new file mode 100644
index 0000000..a6969af
--- /dev/null
+++ b/camera/device/3.5/default/CameraDevice.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamDev@3.5-impl"
+#include <log/log.h>
+
+#include "CameraModule.h"
+#include "CameraDevice_3_5.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_5 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::device::V3_2::CameraMetadata;
+
+CameraDevice::CameraDevice(sp<CameraModule> module, const std::string& cameraId,
+        const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames) :
+        V3_4::implementation::CameraDevice(module, cameraId, cameraDeviceNames) {
+}
+
+CameraDevice::~CameraDevice() {
+}
+
+sp<V3_2::implementation::CameraDeviceSession> CameraDevice::createSession(camera3_device_t* device,
+        const camera_metadata_t* deviceInfo,
+        const sp<V3_2::ICameraDeviceCallback>& callback) {
+    sp<CameraDeviceSession> session = new CameraDeviceSession(device, deviceInfo, callback);
+    IF_ALOGV() {
+        session->getInterface()->interfaceChain([](
+            ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
+                ALOGV("Session interface chain:");
+                for (auto iface : interfaceChain) {
+                    ALOGV("  %s", iface.c_str());
+                }
+            });
+    }
+    return session;
+}
+
+Return<void> CameraDevice::getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId,
+        V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) {
+    Status status = initStatus();
+    CameraMetadata cameraCharacteristics;
+    if (status == Status::OK) {
+        // Require module 2.5+ version.
+        if (mModule->getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_5) {
+            ALOGE("%s: get_physical_camera_info must be called on camera module 2.5 or newer",
+                    __FUNCTION__);
+            status = Status::INTERNAL_ERROR;
+        } else {
+            char *end;
+            errno = 0;
+            long id = strtol(physicalCameraId.c_str(), &end, 0);
+            if (id > INT_MAX || (errno == ERANGE && id == LONG_MAX) ||
+                    id < INT_MIN || (errno == ERANGE && id == LONG_MIN) ||
+                    *end != '\0') {
+                ALOGE("%s: Invalid physicalCameraId %s", __FUNCTION__, physicalCameraId.c_str());
+                status = Status::ILLEGAL_ARGUMENT;
+            } else {
+                camera_metadata_t *physicalInfo = nullptr;
+                int ret = mModule->getPhysicalCameraInfo((int)id, &physicalInfo);
+                if (ret == OK) {
+                    V3_2::implementation::convertToHidl(physicalInfo, &cameraCharacteristics);
+                } else if (ret == -EINVAL) {
+                    ALOGE("%s: %s is not a valid physical camera Id outside of getCameraIdList()",
+                            __FUNCTION__, physicalCameraId.c_str());
+                    status = Status::ILLEGAL_ARGUMENT;
+                } else {
+                    ALOGE("%s: Failed to get physical camera %s info: %s (%d)!", __FUNCTION__,
+                            physicalCameraId.c_str(), strerror(-ret), ret);
+                    status = Status::INTERNAL_ERROR;
+                }
+            }
+        }
+    }
+    _hidl_cb(status, cameraCharacteristics);
+    return Void();
+}
+
+// End of methods from ::android::hardware::camera::device::V3_2::ICameraDevice.
+
+} // namespace implementation
+}  // namespace V3_5
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
diff --git a/camera/device/3.5/default/CameraDeviceSession.cpp b/camera/device/3.5/default/CameraDeviceSession.cpp
new file mode 100644
index 0000000..963893a
--- /dev/null
+++ b/camera/device/3.5/default/CameraDeviceSession.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "CamDevSession@3.5-impl"
+#include <android/log.h>
+
+#include <utils/Trace.h>
+#include "CameraDeviceSession.h"
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_5 {
+namespace implementation {
+
+CameraDeviceSession::CameraDeviceSession(
+    camera3_device_t* device,
+    const camera_metadata_t* deviceInfo,
+    const sp<V3_2::ICameraDeviceCallback>& callback) :
+        V3_4::implementation::CameraDeviceSession(device, deviceInfo, callback) {
+
+    mHasCallback_3_5 = false;
+
+    auto castResult = ICameraDeviceCallback::castFrom(callback);
+    if (castResult.isOk()) {
+        sp<ICameraDeviceCallback> callback3_5 = castResult;
+        if (callback3_5 != nullptr) {
+            mHasCallback_3_5 = true;
+        }
+    }
+}
+
+CameraDeviceSession::~CameraDeviceSession() {
+}
+
+Return<void> CameraDeviceSession::configureStreams_3_5(
+        const StreamConfiguration& requestedConfiguration,
+        ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb)  {
+    return configureStreams_3_4(requestedConfiguration.v3_4, _hidl_cb);
+}
+
+Return<void> CameraDeviceSession::signalStreamFlush(
+        const hidl_vec<int32_t>& /*requests*/, uint32_t /*streamConfigCounter*/) {
+    return Void();
+}
+
+} // namespace implementation
+}  // namespace V3_5
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
diff --git a/camera/device/3.5/default/OWNERS b/camera/device/3.5/default/OWNERS
new file mode 100644
index 0000000..369b204
--- /dev/null
+++ b/camera/device/3.5/default/OWNERS
@@ -0,0 +1,7 @@
+cychen@google.com
+epeev@google.com
+etalvala@google.com
+jchowdhary@google.com
+shuzhenwang@google.com
+yinchiayeh@google.com
+zhijunhe@google.com
diff --git a/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h b/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h
new file mode 100644
index 0000000..ec34769
--- /dev/null
+++ b/camera/device/3.5/default/include/device_v3_5_impl/CameraDeviceSession.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE3SESSION_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE3SESSION_H
+
+#include <android/hardware/camera/device/3.5/ICameraDevice.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.5/ICameraDeviceCallback.h>
+#include <../../3.4/default/include/device_v3_4_impl/CameraDeviceSession.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_5 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+using ::android::hardware::camera::device::V3_2::CaptureRequest;
+using ::android::hardware::camera::device::V3_5::StreamConfiguration;
+using ::android::hardware::camera::device::V3_4::HalStreamConfiguration;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceSession;
+using ::android::hardware::camera::device::V3_5::ICameraDeviceCallback;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::hardware::camera::common::V1_0::helper::HandleImporter;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+using ::android::Mutex;
+
+struct CameraDeviceSession : public V3_4::implementation::CameraDeviceSession {
+
+    CameraDeviceSession(camera3_device_t*,
+            const camera_metadata_t* deviceInfo,
+            const sp<V3_2::ICameraDeviceCallback>&);
+    virtual ~CameraDeviceSession();
+
+    virtual sp<V3_2::ICameraDeviceSession> getInterface() override {
+        return new TrampolineSessionInterface_3_5(this);
+    }
+
+protected:
+    // Methods from v3.4 and earlier will trampoline to inherited implementation
+    Return<void> configureStreams_3_5(
+            const StreamConfiguration& requestedConfiguration,
+            ICameraDeviceSession::configureStreams_3_5_cb _hidl_cb);
+
+    Return<void> signalStreamFlush(
+            const hidl_vec<int32_t>& requests,
+            uint32_t streamConfigCounter);
+
+
+    // Whether this camera device session is created with version 3.5 callback.
+    bool mHasCallback_3_5;
+
+private:
+
+    struct TrampolineSessionInterface_3_5 : public ICameraDeviceSession {
+        TrampolineSessionInterface_3_5(sp<CameraDeviceSession> parent) :
+                mParent(parent) {}
+
+        virtual Return<void> constructDefaultRequestSettings(
+                V3_2::RequestTemplate type,
+                V3_3::ICameraDeviceSession::constructDefaultRequestSettings_cb _hidl_cb) override {
+            return mParent->constructDefaultRequestSettings(type, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams(
+                const V3_2::StreamConfiguration& requestedConfiguration,
+                V3_3::ICameraDeviceSession::configureStreams_cb _hidl_cb) override {
+            return mParent->configureStreams(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> processCaptureRequest_3_4(
+                const hidl_vec<V3_4::CaptureRequest>& requests,
+                const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+                ICameraDeviceSession::processCaptureRequest_3_4_cb _hidl_cb) override {
+            return mParent->processCaptureRequest_3_4(requests, cachesToRemove, _hidl_cb);
+        }
+
+        virtual Return<void> processCaptureRequest(const hidl_vec<V3_2::CaptureRequest>& requests,
+                const hidl_vec<V3_2::BufferCache>& cachesToRemove,
+                V3_3::ICameraDeviceSession::processCaptureRequest_cb _hidl_cb) override {
+            return mParent->processCaptureRequest(requests, cachesToRemove, _hidl_cb);
+        }
+
+        virtual Return<void> getCaptureRequestMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureRequestMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureRequestMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<void> getCaptureResultMetadataQueue(
+                V3_3::ICameraDeviceSession::getCaptureResultMetadataQueue_cb _hidl_cb) override  {
+            return mParent->getCaptureResultMetadataQueue(_hidl_cb);
+        }
+
+        virtual Return<Status> flush() override {
+            return mParent->flush();
+        }
+
+        virtual Return<void> close() override {
+            return mParent->close();
+        }
+
+        virtual Return<void> configureStreams_3_3(
+                const V3_2::StreamConfiguration& requestedConfiguration,
+                configureStreams_3_3_cb _hidl_cb) override {
+            return mParent->configureStreams_3_3(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_4(
+                const V3_4::StreamConfiguration& requestedConfiguration,
+                configureStreams_3_4_cb _hidl_cb) override {
+            return mParent->configureStreams_3_4(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> configureStreams_3_5(
+                const StreamConfiguration& requestedConfiguration,
+                configureStreams_3_5_cb _hidl_cb) override {
+            return mParent->configureStreams_3_5(requestedConfiguration, _hidl_cb);
+        }
+
+        virtual Return<void> signalStreamFlush(
+                const hidl_vec<int32_t>& requests,
+                uint32_t streamConfigCounter) override {
+            return mParent->signalStreamFlush(requests, streamConfigCounter);
+        }
+
+    private:
+        sp<CameraDeviceSession> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_5
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE3SESSION_H
diff --git a/camera/device/3.5/default/include/device_v3_5_impl/CameraDevice_3_5.h b/camera/device/3.5/default/include/device_v3_5_impl/CameraDevice_3_5.h
new file mode 100644
index 0000000..6bdc60f
--- /dev/null
+++ b/camera/device/3.5/default/include/device_v3_5_impl/CameraDevice_3_5.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE_H
+#define ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE_H
+
+#include "CameraDeviceSession.h"
+#include <../../../../3.4/default/include/device_v3_4_impl/CameraDevice_3_4.h>
+
+#include <android/hardware/camera/device/3.5/ICameraDevice.h>
+
+namespace android {
+namespace hardware {
+namespace camera {
+namespace device {
+namespace V3_5 {
+namespace implementation {
+
+using namespace ::android::hardware::camera::device;
+
+using ::android::hardware::camera::common::V1_0::helper::CameraModule;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_string;
+using ::android::hardware::camera::common::V1_0::TorchMode;
+using ::android::hardware::camera::common::V1_0::helper::CameraModule;
+using ::android::hardware::camera::common::V1_0::Status;
+using ::android::sp;
+
+struct CameraDevice : public V3_4::implementation::CameraDevice {
+    // Called by provider HAL.
+    // Provider HAL must ensure the uniqueness of CameraDevice object per cameraId, or there could
+    // be multiple CameraDevice trying to access the same physical camera.  Also, provider will have
+    // to keep track of all CameraDevice objects in order to notify CameraDevice when the underlying
+    // camera is detached.
+    // Delegates nearly all work to CameraDevice_3_4
+    CameraDevice(sp<CameraModule> module,
+                 const std::string& cameraId,
+                 const SortedVector<std::pair<std::string, std::string>>& cameraDeviceNames);
+    virtual ~CameraDevice();
+
+    virtual sp<V3_2::ICameraDevice> getInterface() override {
+        return new TrampolineDeviceInterface_3_5(this);
+    }
+
+protected:
+    virtual sp<V3_2::implementation::CameraDeviceSession> createSession(camera3_device_t*,
+            const camera_metadata_t* deviceInfo,
+            const sp<V3_2::ICameraDeviceCallback>&) override;
+
+    Return<void> getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId,
+            V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb);
+
+private:
+    struct TrampolineDeviceInterface_3_5 : public ICameraDevice {
+        TrampolineDeviceInterface_3_5(sp<CameraDevice> parent) :
+            mParent(parent) {}
+
+        virtual Return<void> getResourceCost(V3_2::ICameraDevice::getResourceCost_cb _hidl_cb)
+                override {
+            return mParent->getResourceCost(_hidl_cb);
+        }
+
+        virtual Return<void> getCameraCharacteristics(
+                V3_2::ICameraDevice::getCameraCharacteristics_cb _hidl_cb) override {
+            return mParent->getCameraCharacteristics(_hidl_cb);
+        }
+
+        virtual Return<Status> setTorchMode(TorchMode mode) override {
+            return mParent->setTorchMode(mode);
+        }
+
+        virtual Return<void> open(const sp<V3_2::ICameraDeviceCallback>& callback,
+                V3_2::ICameraDevice::open_cb _hidl_cb) override {
+            return mParent->open(callback, _hidl_cb);
+        }
+
+        virtual Return<void> dumpState(const hidl_handle& fd) override {
+            return mParent->dumpState(fd);
+        }
+
+        virtual Return<void> getPhysicalCameraCharacteristics(const hidl_string& physicalCameraId,
+                V3_5::ICameraDevice::getPhysicalCameraCharacteristics_cb _hidl_cb) override {
+            return mParent->getPhysicalCameraCharacteristics(physicalCameraId, _hidl_cb);
+        }
+    private:
+        sp<CameraDevice> mParent;
+    };
+};
+
+}  // namespace implementation
+}  // namespace V3_5
+}  // namespace device
+}  // namespace camera
+}  // namespace hardware
+}  // namespace android
+
+#endif // ANDROID_HARDWARE_CAMERA_DEVICE_V3_5_CAMERADEVICE_H
diff --git a/camera/device/3.5/types.hal b/camera/device/3.5/types.hal
new file mode 100644
index 0000000..613187d
--- /dev/null
+++ b/camera/device/3.5/types.hal
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera.device@3.5;
+
+import @3.2::StreamBuffer;
+import @3.4::StreamConfiguration;
+
+/**
+ * StreamConfiguration:
+ *
+ * Identical to @3.4::StreamConfiguration, except that it contains streamConfigCounter
+ */
+struct StreamConfiguration {
+    @3.4::StreamConfiguration v3_4;
+
+    /**
+     * An incrementing counter used for HAL to keep track of the stream
+     * configuration and the paired oneway signalStreamFlush call. When the
+     * counter in signalStreamFlush call is less than the counter here, that
+     * signalStreamFlush call is stale.
+     */
+    uint32_t streamConfigCounter;
+};
+
+enum StreamBufferRequestError : uint32_t {
+    /**
+     * Get buffer failed due to timeout waiting for an available buffer. This is
+     * likely due to the client application holding too many buffers, or the
+     * system is under memory pressure.
+     * This is not a fatal error. HAL may try to request buffer for this stream
+     * later. If HAL cannot get a buffer for certain capture request in time
+     * due to this error, HAL can send an ERROR_REQUEST to camera service and
+     * drop processing that request.
+     */
+    NO_BUFFER_AVAILABLE = 1,
+
+    /**
+     * Get buffer failed due to HAL has reached its maxBuffer count. This is not
+     * a fatal error. HAL may try to request buffer for this stream again after
+     * it returns at least one buffer of that stream to camera service.
+     */
+    MAX_BUFFER_EXCEEDED = 2,
+
+    /**
+     * Get buffer failed due to the stream is disconnected by client
+     * application, has been removed, or not recognized by camera service.
+     * This means application is no longer interested in this stream.
+     * Requesting buffer for this stream must never succeed after this error is
+     * returned. HAL must safely return all buffers of this stream after
+     * getting this error. If HAL gets another capture request later targeting
+     * a disconnected stream, HAL must send an ERROR_REQUEST to camera service
+     * and drop processing that request.
+     */
+    STREAM_DISCONNECTED = 3,
+
+    /**
+     * Get buffer failed for unknown reasons. This is a fatal error and HAL must
+     * send ERROR_DEVICE to camera service and be ready to be closed.
+     */
+    UNKNOWN_ERROR = 4
+};
+
+/**
+ * Per-stream return value for requestStreamBuffers.
+ * For each stream, either an StreamBufferRequestError error code, or all
+ * requested buffers for this stream is returned, so buffers.size() must be
+ * equal to BufferRequest::numBuffersRequested of corresponding stream.
+ */
+safe_union StreamBuffersVal {
+    StreamBufferRequestError error;
+    vec<@3.2::StreamBuffer> buffers;
+};
+
+struct StreamBufferRet {
+    int32_t streamId;
+    StreamBuffersVal val;
+};
+
+enum BufferRequestStatus : uint32_t {
+    /**
+     * Method call succeeded and all requested buffers are returned.
+     */
+    OK = 0,
+
+    /**
+     * Method call failed for some streams. Check per stream status for each
+     * returned StreamBufferRet.
+     */
+    FAILED_PARTIAL = 1,
+
+    /**
+     * Method call failed for all streams and no buffers are returned at all.
+     * Camera service is about to or is performing configureStreams. HAL must
+     * wait until next configureStreams call is finished before requesting
+     * buffers again.
+     */
+    FAILED_CONFIGURING = 2,
+
+    /**
+     * Method call failed for all streams and no buffers are returned at all.
+     * Failure due to bad BufferRequest input, eg: unknown streamId or repeated
+     * streamId.
+     */
+    FAILED_ILLEGAL_ARGUMENTS = 3,
+
+    /**
+     * Method call failed for all streams and no buffers are returned at all.
+     * Failure due to unknown reason.
+     */
+    FAILED_UNKNOWN = 4,
+};
+
+struct BufferRequest {
+    int32_t streamId;
+    uint32_t numBuffersRequested;
+};
+
diff --git a/camera/metadata/3.3/types.hal b/camera/metadata/3.3/types.hal
index 04edfe9..d21bb7c 100644
--- a/camera/metadata/3.3/types.hal
+++ b/camera/metadata/3.3/types.hal
@@ -100,7 +100,7 @@
 
     /** android.request.availablePhysicalCameraRequestKeys [static, int32[], hidden]
      *
-     * <p>A subset of the available request keys that can be overriden for
+     * <p>A subset of the available request keys that can be overridden for
      * physical devices backing a logical multi-camera.</p>
      */
     ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS,
@@ -109,8 +109,8 @@
 
     /** android.statistics.oisDataMode [dynamic, enum, public]
      *
-     * <p>A control for selecting whether OIS position information is included in output
-     * result metadata.</p>
+     * <p>A control for selecting whether optical stabilization (OIS) position
+     * information is included in output result metadata.</p>
      */
     ANDROID_STATISTICS_OIS_DATA_MODE = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_STATISTICS_END,
 
diff --git a/camera/metadata/3.4/Android.bp b/camera/metadata/3.4/Android.bp
new file mode 100644
index 0000000..388df68
--- /dev/null
+++ b/camera/metadata/3.4/Android.bp
@@ -0,0 +1,22 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.camera.metadata@3.4",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+    ],
+    interfaces: [
+        "android.hardware.camera.metadata@3.2",
+        "android.hardware.camera.metadata@3.3",
+    ],
+    types: [
+        "CameraMetadataEnumAndroidInfoSupportedBufferManagementVersion",
+        "CameraMetadataTag",
+    ],
+    gen_java: true,
+}
+
diff --git a/camera/metadata/3.4/types.hal b/camera/metadata/3.4/types.hal
new file mode 100644
index 0000000..b228de8
--- /dev/null
+++ b/camera/metadata/3.4/types.hal
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata@3.4;
+
+/* Include definitions from all prior minor HAL metadata revisions */
+import android.hardware.camera.metadata@3.2;
+import android.hardware.camera.metadata@3.3;
+
+// No new metadata sections added in this revision
+
+/**
+ * Main enumeration for defining camera metadata tags added in this revision
+ *
+ * <p>Partial documentation is included for each tag; for complete documentation, reference
+ * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
+ */
+enum CameraMetadataTag : @3.3::CameraMetadataTag {
+    /** android.request.characteristicKeysNeedingPermission [static, int32[], hidden]
+     *
+     * <p>A list of camera characteristics keys that are only available
+     * in case the camera client has camera permission.</p>
+     */
+    ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_REQUEST_END_3_3,
+
+    ANDROID_REQUEST_END_3_4,
+
+    /** android.info.supportedBufferManagementVersion [static, enum, system]
+     *
+     * <p>The version of buffer management API this camera device supports and opts into.</p>
+     */
+    ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION = android.hardware.camera.metadata@3.3::CameraMetadataTag:ANDROID_INFO_END_3_3,
+
+    ANDROID_INFO_END_3_4,
+
+};
+
+/*
+ * Enumeration definitions for the various entries that need them
+ */
+
+/** android.info.supportedBufferManagementVersion enumeration values
+ * @see ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION
+ */
+enum CameraMetadataEnumAndroidInfoSupportedBufferManagementVersion : uint32_t {
+    ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION_HIDL_DEVICE_3_5,
+};
diff --git a/camera/provider/2.4/default/Android.bp b/camera/provider/2.4/default/Android.bp
index ae24d78..de02d78 100644
--- a/camera/provider/2.4/default/Android.bp
+++ b/camera/provider/2.4/default/Android.bp
@@ -14,10 +14,12 @@
         "android.hardware.camera.device@3.2",
         "android.hardware.camera.device@3.3",
         "android.hardware.camera.device@3.4",
+        "android.hardware.camera.device@3.5",
         "camera.device@1.0-impl",
         "camera.device@3.2-impl",
         "camera.device@3.3-impl",
         "camera.device@3.4-impl",
+        "camera.device@3.5-impl",
         "camera.device@3.4-external-impl",
         "android.hardware.camera.provider@2.4",
         "android.hardware.camera.common@1.0",
@@ -31,6 +33,7 @@
     ],
     header_libs: [
         "camera.device@3.4-impl_headers",
+        "camera.device@3.5-impl_headers",
         "camera.device@3.4-external-impl_headers"
     ],
     static_libs: [
@@ -56,6 +59,7 @@
         "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.camera.provider@2.4",
         "android.hardware.camera.common@1.0",
     ],
@@ -80,6 +84,7 @@
         "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.camera.provider@2.4",
         "android.hardware.camera.common@1.0",
     ],
diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp
index 6313939..488b9af 100644
--- a/camera/provider/2.4/default/CameraProvider.cpp
+++ b/camera/provider/2.4/default/CameraProvider.cpp
@@ -23,6 +23,7 @@
 #include "CameraDevice_1_0.h"
 #include "CameraDevice_3_3.h"
 #include "CameraDevice_3_4.h"
+#include "CameraDevice_3_5.h"
 #include <cutils/properties.h>
 #include <string.h>
 #include <utils/Trace.h>
@@ -43,6 +44,7 @@
 const char *kHAL3_2 = "3.2";
 const char *kHAL3_3 = "3.3";
 const char *kHAL3_4 = "3.4";
+const char *kHAL3_5 = "3.5";
 const char *kHAL1_0 = "1.0";
 const int kMaxCameraDeviceNameLen = 128;
 const int kMaxCameraIdLen = 16;
@@ -250,7 +252,11 @@
     int versionMajor = isV1 ? 1 : 3;
     int versionMinor = isV1 ? 0 : mPreferredHal3MinorVersion;
     if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) {
-        versionMinor = 4;
+        if (mModule->getModuleApiVersion() == CAMERA_MODULE_API_VERSION_2_5) {
+            versionMinor = 5;
+        } else {
+            versionMinor = 4;
+        }
     }
     char deviceName[kMaxCameraDeviceNameLen];
     snprintf(deviceName, sizeof(deviceName), "device@%d.%d/legacy/%s",
@@ -546,63 +552,69 @@
         return Void();
     }
 
-    sp<android::hardware::camera::device::V3_2::ICameraDevice> device;
-    if (deviceVersion == kHAL3_4) {
+    // ICameraDevice 3.4 or upper
+    sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl;
+    if (deviceVersion >= kHAL3_4) {
         ALOGV("Constructing v3.4 camera device");
-        sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl =
-            new android::hardware::camera::device::V3_4::implementation::CameraDevice(
+        if (deviceVersion == kHAL3_4) {
+            deviceImpl = new android::hardware::camera::device::V3_4::implementation::CameraDevice(
                     mModule, cameraId, mCameraDeviceNames);
+        } else if (deviceVersion == kHAL3_5) {
+            deviceImpl = new android::hardware::camera::device::V3_5::implementation::CameraDevice(
+                    mModule, cameraId, mCameraDeviceNames);
+        }
         if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
             ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
-            device = nullptr;
             _hidl_cb(Status::INTERNAL_ERROR, nullptr);
             return Void();
         }
-
-        device = deviceImpl;
-        _hidl_cb (Status::OK, device);
+        IF_ALOGV() {
+            deviceImpl->getInterface()->interfaceChain([](
+                ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
+                    ALOGV("Device interface chain:");
+                    for (auto iface : interfaceChain) {
+                        ALOGV("  %s", iface.c_str());
+                    }
+                });
+        }
+        _hidl_cb (Status::OK, deviceImpl->getInterface());
         return Void();
     }
 
+    // ICameraDevice 3.2 and 3.3
     // Since some Treble HAL revisions can map to the same legacy HAL version(s), we default
     // to the newest possible Treble HAL revision, but allow for override if needed via
     // system property.
     switch (mPreferredHal3MinorVersion) {
         case 2: { // Map legacy camera device v3 HAL to Treble camera device HAL v3.2
             ALOGV("Constructing v3.2 camera device");
-            sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl =
-                    new android::hardware::camera::device::V3_2::implementation::CameraDevice(
+            deviceImpl = new android::hardware::camera::device::V3_2::implementation::CameraDevice(
                     mModule, cameraId, mCameraDeviceNames);
             if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
                 ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
-                device = nullptr;
                 _hidl_cb(Status::INTERNAL_ERROR, nullptr);
                 return Void();
             }
-            device = deviceImpl;
             break;
         }
         case 3: { // Map legacy camera device v3 HAL to Treble camera device HAL v3.3
             ALOGV("Constructing v3.3 camera device");
-            sp<android::hardware::camera::device::V3_2::implementation::CameraDevice> deviceImpl =
-                    new android::hardware::camera::device::V3_3::implementation::CameraDevice(
+            deviceImpl = new android::hardware::camera::device::V3_3::implementation::CameraDevice(
                     mModule, cameraId, mCameraDeviceNames);
             if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
                 ALOGE("%s: camera device %s init failed!", __FUNCTION__, cameraId.c_str());
-                device = nullptr;
                 _hidl_cb(Status::INTERNAL_ERROR, nullptr);
                 return Void();
             }
-            device = deviceImpl;
             break;
         }
         default:
             ALOGE("%s: Unknown HAL minor version %d!", __FUNCTION__, mPreferredHal3MinorVersion);
-            device = nullptr;
             _hidl_cb(Status::INTERNAL_ERROR, nullptr);
             return Void();
     }
-    _hidl_cb (Status::OK, device);
+
+    _hidl_cb (Status::OK, deviceImpl->getInterface());
     return Void();
 }
 
diff --git a/camera/provider/2.4/default/OWNERS b/camera/provider/2.4/default/OWNERS
index 18acfee..369b204 100644
--- a/camera/provider/2.4/default/OWNERS
+++ b/camera/provider/2.4/default/OWNERS
@@ -1,6 +1,7 @@
 cychen@google.com
 epeev@google.com
 etalvala@google.com
+jchowdhary@google.com
 shuzhenwang@google.com
 yinchiayeh@google.com
 zhijunhe@google.com
diff --git a/camera/provider/2.4/vts/functional/Android.bp b/camera/provider/2.4/vts/functional/Android.bp
index ead4083..eb8d43e 100644
--- a/camera/provider/2.4/vts/functional/Android.bp
+++ b/camera/provider/2.4/vts/functional/Android.bp
@@ -37,6 +37,7 @@
         "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.camera.provider@2.4",
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.common@1.0",
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 71b78f4..94d06e8 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -28,6 +28,7 @@
 
 #include <android/hardware/camera/device/1.0/ICameraDevice.h>
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
+#include <android/hardware/camera/device/3.5/ICameraDevice.h>
 #include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.4/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.4/ICameraDeviceCallback.h>
@@ -144,10 +145,12 @@
 namespace {
     // "device@<version>/legacy/<id>"
     const char *kDeviceNameRE = "device@([0-9]+\\.[0-9]+)/%s/(.+)";
+    const int CAMERA_DEVICE_API_VERSION_3_5 = 0x305;
     const int CAMERA_DEVICE_API_VERSION_3_4 = 0x304;
     const int CAMERA_DEVICE_API_VERSION_3_3 = 0x303;
     const int CAMERA_DEVICE_API_VERSION_3_2 = 0x302;
     const int CAMERA_DEVICE_API_VERSION_1_0 = 0x100;
+    const char *kHAL3_5 = "3.5";
     const char *kHAL3_4 = "3.4";
     const char *kHAL3_3 = "3.3";
     const char *kHAL3_2 = "3.2";
@@ -182,7 +185,9 @@
             return -1;
         }
 
-        if (version.compare(kHAL3_4) == 0) {
+        if (version.compare(kHAL3_5) == 0) {
+            return CAMERA_DEVICE_API_VERSION_3_5;
+        } else if (version.compare(kHAL3_4) == 0) {
             return CAMERA_DEVICE_API_VERSION_3_4;
         } else if (version.compare(kHAL3_3) == 0) {
             return CAMERA_DEVICE_API_VERSION_3_3;
@@ -670,12 +675,19 @@
             HalStreamConfiguration *halStreamConfig /*out*/,
             bool *supportsPartialResults /*out*/,
             uint32_t *partialResultCount /*out*/);
+
+    void verifyLogicalCameraMetadata(const std::string& cameraName,
+            const ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice>& device,
+            const CameraMetadata& chars, int deviceVersion,
+            const hidl_vec<hidl_string>& deviceNames);
+    void verifyCameraCharacteristics(Status status, const CameraMetadata& chars);
+
     static Status getAvailableOutputStreams(camera_metadata_t *staticMeta,
             std::vector<AvailableStream> &outputStreams,
             const AvailableStream *threshold = nullptr);
     static Status isConstrainedModeAvailable(camera_metadata_t *staticMeta);
-    static Status isLogicalMultiCamera(camera_metadata_t *staticMeta);
-    static Status getPhysicalCameraIds(camera_metadata_t *staticMeta,
+    static Status isLogicalMultiCamera(const camera_metadata_t *staticMeta);
+    static Status getPhysicalCameraIds(const camera_metadata_t *staticMeta,
             std::unordered_set<std::string> *physicalIds/*out*/);
     static Status getSupportedKeys(camera_metadata_t *staticMeta,
             uint32_t tagId, std::unordered_set<int32_t> *requestIDs/*out*/);
@@ -1266,6 +1278,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
@@ -1307,6 +1320,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
@@ -2047,6 +2061,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
@@ -2063,33 +2078,31 @@
                 ASSERT_TRUE(ret.isOk());
 
                 ret = device3_x->getCameraCharacteristics([&](auto status, const auto& chars) {
-                    ALOGI("getCameraCharacteristics returns status:%d", (int)status);
-                    ASSERT_EQ(Status::OK, status);
-                    const camera_metadata_t* metadata = (camera_metadata_t*)chars.data();
-                    size_t expectedSize = chars.size();
-                    int result = validate_camera_metadata_structure(metadata, &expectedSize);
-                    ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
-                    size_t entryCount = get_camera_metadata_entry_count(metadata);
-                    // TODO: we can do better than 0 here. Need to check how many required
-                    // characteristics keys we've defined.
-                    ASSERT_GT(entryCount, 0u);
-                    ALOGI("getCameraCharacteristics metadata entry count is %zu", entryCount);
+                    verifyCameraCharacteristics(status, chars);
 
-                    camera_metadata_ro_entry entry;
-                    int retcode = find_camera_metadata_ro_entry(metadata,
-                            ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &entry);
-                    if ((0 == retcode) && (entry.count > 0)) {
-                        uint8_t hardwareLevel = entry.data.u8[0];
-                        ASSERT_TRUE(
-                                hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED ||
-                                hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL ||
-                                hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_3 ||
-                                hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL);
-                    } else {
-                        ADD_FAILURE() << "Get camera hardware level failed!";
-                    }
+                    verifyLogicalCameraMetadata(name, device3_x, chars, deviceVersion,
+                            cameraDeviceNames);
                 });
                 ASSERT_TRUE(ret.isOk());
+
+                //getPhysicalCameraCharacteristics will fail for publicly
+                //advertised camera IDs.
+                if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5) {
+                    auto castResult = device::V3_5::ICameraDevice::castFrom(device3_x);
+                    ASSERT_TRUE(castResult.isOk());
+                    ::android::sp<::android::hardware::camera::device::V3_5::ICameraDevice>
+                            device3_5 = castResult;
+                    ASSERT_NE(device3_5, nullptr);
+
+                    std::string version, cameraId;
+                    ASSERT_TRUE(::matchDeviceName(name, mProviderType, &version, &cameraId));
+                    Return<void> ret = device3_5->getPhysicalCameraCharacteristics(cameraId,
+                            [&](auto status, const auto& chars) {
+                        ASSERT_TRUE(Status::ILLEGAL_ARGUMENT == status);
+                        ASSERT_EQ(0, chars.size());
+                    });
+                    ASSERT_TRUE(ret.isOk());
+                }
             }
             break;
             case CAMERA_DEVICE_API_VERSION_1_0: {
@@ -2126,6 +2139,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
@@ -2251,6 +2265,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
@@ -2315,6 +2330,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
@@ -2343,7 +2359,8 @@
                 sp<device::V3_3::ICameraDeviceSession> sessionV3_3;
                 sp<device::V3_4::ICameraDeviceSession> sessionV3_4;
                 castSession(session, deviceVersion, &sessionV3_3, &sessionV3_4);
-                if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4) {
+                if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_4 ||
+                        deviceVersion == CAMERA_DEVICE_API_VERSION_3_5) {
                     ASSERT_TRUE(sessionV3_4.get() != nullptr);
                 } else if (deviceVersion == CAMERA_DEVICE_API_VERSION_3_3) {
                     ASSERT_TRUE(sessionV3_3.get() != nullptr);
@@ -2401,6 +2418,7 @@
     for (const auto& name : cameraDeviceNames) {
         int deviceVersion = getCameraDeviceVersion(name, mProviderType);
         switch (deviceVersion) {
+            case CAMERA_DEVICE_API_VERSION_3_5:
             case CAMERA_DEVICE_API_VERSION_3_4:
             case CAMERA_DEVICE_API_VERSION_3_3:
             case CAMERA_DEVICE_API_VERSION_3_2: {
@@ -4144,7 +4162,7 @@
 }
 
 // Check if the camera device has logical multi-camera capability.
-Status CameraHidlTest::isLogicalMultiCamera(camera_metadata_t *staticMeta) {
+Status CameraHidlTest::isLogicalMultiCamera(const camera_metadata_t *staticMeta) {
     Status ret = Status::METHOD_NOT_SUPPORTED;
     if (nullptr == staticMeta) {
         return Status::ILLEGAL_ARGUMENT;
@@ -4168,7 +4186,7 @@
 }
 
 // Generate a list of physical camera ids backing a logical multi-camera.
-Status CameraHidlTest::getPhysicalCameraIds(camera_metadata_t *staticMeta,
+Status CameraHidlTest::getPhysicalCameraIds(const camera_metadata_t *staticMeta,
         std::unordered_set<std::string> *physicalIds) {
     if ((nullptr == staticMeta) || (nullptr == physicalIds)) {
         return Status::ILLEGAL_ARGUMENT;
@@ -4641,6 +4659,7 @@
     ASSERT_NE(nullptr, session3_4);
 
     switch (deviceVersion) {
+        case CAMERA_DEVICE_API_VERSION_3_5:
         case CAMERA_DEVICE_API_VERSION_3_4: {
             auto castResult = device::V3_4::ICameraDeviceSession::castFrom(session);
             ASSERT_TRUE(castResult.isOk());
@@ -4659,6 +4678,101 @@
     }
 }
 
+// Verify logical camera static metadata
+void CameraHidlTest::verifyLogicalCameraMetadata(const std::string& cameraName,
+        const ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice>& device,
+        const CameraMetadata &chars, int deviceVersion,
+        const hidl_vec<hidl_string>& deviceNames) {
+    const camera_metadata_t* metadata = (camera_metadata_t*)chars.data();
+    ASSERT_NE(nullptr, metadata);
+
+    Status rc = isLogicalMultiCamera(metadata);
+    ASSERT_TRUE(Status::OK == rc || Status::METHOD_NOT_SUPPORTED == rc);
+    if (Status::METHOD_NOT_SUPPORTED == rc) {
+        return;
+    }
+
+    std::string version, cameraId;
+    ASSERT_TRUE(::matchDeviceName(cameraName, mProviderType, &version, &cameraId));
+    std::unordered_set<std::string> physicalIds;
+    ASSERT_TRUE(Status::OK == getPhysicalCameraIds(metadata, &physicalIds));
+    for (auto physicalId : physicalIds) {
+        ASSERT_NE(physicalId, cameraId);
+        bool isPublicId = false;
+        for (auto& deviceName : deviceNames) {
+            std::string publicVersion, publicId;
+            ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, &publicVersion, &publicId));
+            if (physicalId == publicId) {
+                isPublicId = true;
+                break;
+            }
+        }
+        if (isPublicId) {
+            continue;
+        }
+
+        ASSERT_TRUE(deviceVersion >= CAMERA_DEVICE_API_VERSION_3_5);
+        auto castResult = device::V3_5::ICameraDevice::castFrom(device);
+        ASSERT_TRUE(castResult.isOk());
+        ::android::sp<::android::hardware::camera::device::V3_5::ICameraDevice> device3_5 =
+                castResult;
+        ASSERT_NE(device3_5, nullptr);
+
+        // Check camera characteristics for hidden camera id
+        Return<void> ret = device3_5->getPhysicalCameraCharacteristics(physicalId,
+                [&](auto status, const auto& chars) {
+            verifyCameraCharacteristics(status, chars);
+        });
+        ASSERT_TRUE(ret.isOk());
+
+        // Check calling getCameraDeviceInterface_V3_x() on hidden camera id returns
+        // ILLEGAL_ARGUMENT.
+        std::stringstream s;
+        s << "device@" << version << "/" << mProviderType << "/" << physicalId;
+        hidl_string fullPhysicalId(s.str());
+        ret = mProvider->getCameraDeviceInterface_V3_x(fullPhysicalId,
+                [&](auto status, const auto& device3_x) {
+            ASSERT_EQ(Status::ILLEGAL_ARGUMENT, status);
+            ASSERT_EQ(device3_x, nullptr);
+        });
+        ASSERT_TRUE(ret.isOk());
+    }
+}
+
+void CameraHidlTest::verifyCameraCharacteristics(Status status, const CameraMetadata& chars) {
+    ASSERT_EQ(Status::OK, status);
+    const camera_metadata_t* metadata = (camera_metadata_t*)chars.data();
+    size_t expectedSize = chars.size();
+    int result = validate_camera_metadata_structure(metadata, &expectedSize);
+    ASSERT_TRUE((result == 0) || (result == CAMERA_METADATA_VALIDATION_SHIFTED));
+    size_t entryCount = get_camera_metadata_entry_count(metadata);
+    // TODO: we can do better than 0 here. Need to check how many required
+    // characteristics keys we've defined.
+    ASSERT_GT(entryCount, 0u);
+
+    camera_metadata_ro_entry entry;
+    int retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL, &entry);
+    if ((0 == retcode) && (entry.count > 0)) {
+        uint8_t hardwareLevel = entry.data.u8[0];
+        ASSERT_TRUE(
+                hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED ||
+                hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_FULL ||
+                hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_3 ||
+                hardwareLevel == ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL);
+    } else {
+        ADD_FAILURE() << "Get camera hardware level failed!";
+    }
+
+    entry.count = 0;
+    retcode = find_camera_metadata_ro_entry(metadata,
+            ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION, &entry);
+    if ((0 == retcode) || (entry.count > 0)) {
+        ADD_FAILURE() << "ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION "
+            << " per API contract should never be set by Hal!";
+    }
+}
+
 // Open a device session with empty callbacks and return static metadata.
 void CameraHidlTest::openEmptyDeviceSession(const std::string &name,
         sp<ICameraProvider> provider,
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 0d60be6..b64ff86 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -56,6 +56,14 @@
         </interface>
     </hal>
     <hal format="hidl" optional="true">
+        <name>android.hardware.biometrics.face</name>
+        <version>1.0</version>
+        <interface>
+            <name>IBiometricsFace</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
         <name>android.hardware.biometrics.fingerprint</name>
         <version>2.1</version>
         <interface>
@@ -113,7 +121,7 @@
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.configstore</name>
-        <version>1.1</version>
+        <version>1.2</version>
         <interface>
             <name>ISurfaceFlingerConfigs</name>
             <instance>default</instance>
@@ -216,16 +224,20 @@
         </interface>
     </hal>
     <hal format="hidl" optional="true">
-        <name>android.hardware.health.filesystem</name>
+        <name>android.hardware.health.storage</name>
         <version>1.0</version>
         <interface>
-            <name>IFileSystem</name>
+            <name>IStorage</name>
             <instance>default</instance>
         </interface>
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.ir</name>
         <version>1.0</version>
+        <interface>
+            <name>IConsumerIr</name>
+            <instance>default</instance>
+        </interface>
     </hal>
     <hal format="hidl" optional="false">
         <name>android.hardware.keymaster</name>
@@ -305,6 +317,14 @@
         </interface>
     </hal>
     <hal format="hidl" optional="true">
+        <name>android.hardware.power.stats</name>
+        <version>1.0</version>
+        <interface>
+            <name>IPowerStats</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
         <name>android.hardware.radio</name>
         <version>1.0-2</version>
         <interface>
@@ -441,7 +461,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.wifi</name>
-        <version>1.0-2</version>
+        <version>1.0-3</version>
         <interface>
             <name>IWifi</name>
             <instance>default</instance>
@@ -449,7 +469,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.wifi.hostapd</name>
-        <version>1.0</version>
+        <version>1.0-1</version>
         <interface>
             <name>IHostapd</name>
             <instance>default</instance>
diff --git a/configstore/1.1/default/SurfaceFlingerConfigs.h b/configstore/1.1/default/SurfaceFlingerConfigs.h
deleted file mode 100644
index 3714e81..0000000
--- a/configstore/1.1/default/SurfaceFlingerConfigs.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef ANDROID_HARDWARE_CONFIGSTORE_V1_1_SURFACEFLINGERCONFIGS_H
-#define ANDROID_HARDWARE_CONFIGSTORE_V1_1_SURFACEFLINGERCONFIGS_H
-
-#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
-#include <hidl/MQDescriptor.h>
-#include <hidl/Status.h>
-
-namespace android {
-namespace hardware {
-namespace configstore {
-namespace V1_1 {
-namespace implementation {
-
-using ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::sp;
-
-struct SurfaceFlingerConfigs : public ISurfaceFlingerConfigs {
-    // Methods from
-    // ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs follow.
-    Return<void> vsyncEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) override;
-    Return<void> vsyncSfEventPhaseOffsetNs(vsyncSfEventPhaseOffsetNs_cb _hidl_cb) override;
-    Return<void> useContextPriority(useContextPriority_cb _hidl_cb) override;
-    Return<void> hasWideColorDisplay(hasWideColorDisplay_cb _hidl_cb) override;
-    Return<void> hasHDRDisplay(hasHDRDisplay_cb _hidl_cb) override;
-    Return<void> presentTimeOffsetFromVSyncNs(presentTimeOffsetFromVSyncNs_cb _hidl_cb) override;
-    Return<void> useHwcForRGBtoYUV(useHwcForRGBtoYUV_cb _hidl_cb) override;
-    Return<void> maxVirtualDisplaySize(maxVirtualDisplaySize_cb _hidl_cb) override;
-    Return<void> hasSyncFramework(hasSyncFramework_cb _hidl_cb) override;
-    Return<void> useVrFlinger(useVrFlinger_cb _hidl_cb) override;
-    Return<void> maxFrameBufferAcquiredBuffers(maxFrameBufferAcquiredBuffers_cb _hidl_cb) override;
-    Return<void> startGraphicsAllocatorService(startGraphicsAllocatorService_cb _hidl_cb) override;
-
-    // Methods from
-    // ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs follow.
-    Return<void> primaryDisplayOrientation(primaryDisplayOrientation_cb _hidl_cb) override;
-
-    // Methods from ::android::hidl::base::V1_0::IBase follow.
-};
-
-}  // namespace implementation
-}  // namespace V1_1
-}  // namespace configstore
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_CONFIGSTORE_V1_1_SURFACEFLINGERCONFIGS_H
diff --git a/configstore/1.2/Android.bp b/configstore/1.2/Android.bp
new file mode 100644
index 0000000..cc5644c
--- /dev/null
+++ b/configstore/1.2/Android.bp
@@ -0,0 +1,19 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.configstore@1.2",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "ISurfaceFlingerConfigs.hal",
+    ],
+    interfaces: [
+        "android.hardware.configstore@1.1",
+        "android.hardware.configstore@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
\ No newline at end of file
diff --git a/configstore/1.2/ISurfaceFlingerConfigs.hal b/configstore/1.2/ISurfaceFlingerConfigs.hal
new file mode 100644
index 0000000..c879155
--- /dev/null
+++ b/configstore/1.2/ISurfaceFlingerConfigs.hal
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.configstore@1.2;
+
+import android.hardware.graphics.common@1.1::Dataspace;
+import android.hardware.graphics.common@1.1::PixelFormat;
+import @1.1::ISurfaceFlingerConfigs;
+import @1.0::OptionalBool;
+
+/**
+ * New revision of ISurfaceFlingerConfigs
+ */
+interface ISurfaceFlingerConfigs extends @1.1::ISurfaceFlingerConfigs {
+    /**
+     * useColorManagement indicates whether SurfaceFlinger should manage color
+     * by switching to appropriate color mode automatically depending on the
+     * Dataspace of the surfaces on screen.
+     * This function must return true when hasWideColorDisplay or hasHDRDisplay
+     * return true.
+     */
+    useColorManagement() generates (OptionalBool value);
+
+    /**
+     * Returns the default data space and default pixel format that
+     * SurfaceFlinger expects to receive and output.
+     * To determine the default data space and default pixel format,
+     * there are a few things we recommend to consider:
+     *
+     *   1. Hardware composer's capability to composite contents with the
+     *      data space and pixel format efficiently;
+     *   2. Hardware composer's ability to composite contents when sRGB contents
+     *      and the chosen data space contents coexist;
+     *   3. For better blending, consider using pixel format where the alpha
+     *      channel has as many bits as the RGB color channel.
+     *
+     * @return dataSpace is the default data space that SurfaceFlinger expects.
+     *         The data space must not be Dataspace::UNKNOWN, if unspecified,
+     *         the default data space is Dataspace::V0_SRGB;
+     * @return pixelFormat is the default pixel format that SurfaceFlinger
+     *         expects. If unspecified, the default pixel format is
+     *         PixelFormat::RGBA_8888.
+     */
+    getCompositionPreference()
+        generates (Dataspace dataSpace, PixelFormat pixelFormat);
+};
diff --git a/configstore/1.1/default/Android.mk b/configstore/1.2/default/Android.mk
similarity index 67%
rename from configstore/1.1/default/Android.mk
rename to configstore/1.2/default/Android.mk
index 40f621b..b807357 100644
--- a/configstore/1.1/default/Android.mk
+++ b/configstore/1.2/default/Android.mk
@@ -2,15 +2,15 @@
 
 ################################################################################
 include $(CLEAR_VARS)
-LOCAL_MODULE := android.hardware.configstore@1.1-service
+LOCAL_MODULE := android.hardware.configstore@1.2-service
 # seccomp is not required for coverage build.
 ifneq ($(NATIVE_COVERAGE),true)
-LOCAL_REQUIRED_MODULES_arm64 := configstore@1.1.policy
+LOCAL_REQUIRED_MODULES_arm64 := configstore.policy
 endif
-LOCAL_PROPRIETARY_MODULE := true
+LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_CLASS := EXECUTABLES
 LOCAL_MODULE_RELATIVE_PATH := hw
-LOCAL_INIT_RC := android.hardware.configstore@1.1-service.rc
+LOCAL_INIT_RC := android.hardware.configstore@1.2-service.rc
 LOCAL_SRC_FILES:= service.cpp
 
 include $(LOCAL_PATH)/surfaceflinger.mk
@@ -23,16 +23,17 @@
     liblog \
     libutils \
     android.hardware.configstore@1.0 \
-    android.hardware.configstore@1.1
+    android.hardware.configstore@1.1 \
+    android.hardware.configstore@1.2
 
 include $(BUILD_EXECUTABLE)
 
 # seccomp filter for configstore
 ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm64))
 include $(CLEAR_VARS)
-LOCAL_MODULE := configstore@1.1.policy
+LOCAL_MODULE := configstore.policy
 LOCAL_MODULE_CLASS := ETC
 LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/etc/seccomp_policy
-LOCAL_SRC_FILES := seccomp_policy/configstore@1.1-$(TARGET_ARCH).policy
+LOCAL_SRC_FILES := seccomp_policy/configstore-$(TARGET_ARCH).policy
 include $(BUILD_PREBUILT)
 endif
diff --git a/configstore/1.1/default/SurfaceFlingerConfigs.cpp b/configstore/1.2/default/SurfaceFlingerConfigs.cpp
similarity index 79%
rename from configstore/1.1/default/SurfaceFlingerConfigs.cpp
rename to configstore/1.2/default/SurfaceFlingerConfigs.cpp
index da3081c..ae19dc0 100644
--- a/configstore/1.1/default/SurfaceFlingerConfigs.cpp
+++ b/configstore/1.2/default/SurfaceFlingerConfigs.cpp
@@ -17,16 +17,19 @@
 #include "SurfaceFlingerConfigs.h"
 
 #include <android/hardware/configstore/1.1/types.h>
+#include <android/hardware/graphics/common/1.1/types.h>
 #include <log/log.h>
 
 namespace android {
 namespace hardware {
 namespace configstore {
-namespace V1_1 {
+namespace V1_2 {
 namespace implementation {
 
-// Methods from ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs
-// follow.
+using ::android::hardware::graphics::common::V1_1::Dataspace;
+using ::android::hardware::graphics::common::V1_1::PixelFormat;
+
+// ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs implementation.
 Return<void> SurfaceFlingerConfigs::vsyncEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) {
 #ifdef VSYNC_EVENT_PHASE_OFFSET_NS
     _hidl_cb({true, VSYNC_EVENT_PHASE_OFFSET_NS});
@@ -142,8 +145,7 @@
     return Void();
 }
 
-// Methods from ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs
-// follow.
+// ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs implementation.
 
 #ifdef PRIMARY_DISPLAY_ORIENTATION
 static_assert(PRIMARY_DISPLAY_ORIENTATION == 0 || PRIMARY_DISPLAY_ORIENTATION == 90 ||
@@ -191,10 +193,37 @@
     return Void();
 }
 
-// Methods from ::android::hidl::base::V1_0::IBase follow.
+// ::android::hardware::configstore::V1_2::ISurfaceFlingerConfigs implementation.
+Return<void> SurfaceFlingerConfigs::useColorManagement(useColorManagement_cb _hidl_cb) {
+#if defined(USE_COLOR_MANAGEMENT) || defined(HAS_WIDE_COLOR_DISPLAY) || defined(HAS_HDR_DISPLAY)
+    _hidl_cb({true, true});
+#else
+    _hidl_cb({true, false});
+#endif
+    return Void();
+}
+
+#ifdef COMPOSITION_DATA_SPACE
+static_assert(COMPOSITION_DATA_SPACE != 0, "Expected composition data space must not be UNKNOWN");
+#endif
+
+Return<void> SurfaceFlingerConfigs::getCompositionPreference(getCompositionPreference_cb _hidl_cb) {
+    Dataspace dataSpace = Dataspace::V0_SRGB;
+    PixelFormat pixelFormat = PixelFormat::RGBA_8888;
+
+#ifdef COMPOSITION_DATA_SPACE
+    dataSpace = static_cast<Dataspace>(COMPOSITION_DATA_SPACE);
+#endif
+
+#ifdef COMPOSITION_PIXEL_FORMAT
+    pixelFormat = static_cast<PixelFormat>(COMPOSITION_PIXEL_FORMAT);
+#endif
+    _hidl_cb(dataSpace, pixelFormat);
+    return Void();
+}
 
 }  // namespace implementation
-}  // namespace V1_1
+}  // namespace V1_2
 }  // namespace configstore
 }  // namespace hardware
 }  // namespace android
diff --git a/configstore/1.2/default/SurfaceFlingerConfigs.h b/configstore/1.2/default/SurfaceFlingerConfigs.h
new file mode 100644
index 0000000..7dd8f6d
--- /dev/null
+++ b/configstore/1.2/default/SurfaceFlingerConfigs.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_CONFIGSTORE_V1_2_SURFACEFLINGERCONFIGS_H
+#define ANDROID_HARDWARE_CONFIGSTORE_V1_2_SURFACEFLINGERCONFIGS_H
+
+#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace configstore {
+namespace V1_2 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::configstore::V1_2::ISurfaceFlingerConfigs;
+
+struct SurfaceFlingerConfigs : public ISurfaceFlingerConfigs {
+    // ::android::hardware::configstore::V1_0::ISurfaceFlingerConfigs implementation.
+    Return<void> vsyncEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) override;
+    Return<void> vsyncSfEventPhaseOffsetNs(vsyncSfEventPhaseOffsetNs_cb _hidl_cb) override;
+    Return<void> useContextPriority(useContextPriority_cb _hidl_cb) override;
+    Return<void> hasWideColorDisplay(hasWideColorDisplay_cb _hidl_cb) override;
+    Return<void> hasHDRDisplay(hasHDRDisplay_cb _hidl_cb) override;
+    Return<void> presentTimeOffsetFromVSyncNs(presentTimeOffsetFromVSyncNs_cb _hidl_cb) override;
+    Return<void> useHwcForRGBtoYUV(useHwcForRGBtoYUV_cb _hidl_cb) override;
+    Return<void> maxVirtualDisplaySize(maxVirtualDisplaySize_cb _hidl_cb) override;
+    Return<void> hasSyncFramework(hasSyncFramework_cb _hidl_cb) override;
+    Return<void> useVrFlinger(useVrFlinger_cb _hidl_cb) override;
+    Return<void> maxFrameBufferAcquiredBuffers(maxFrameBufferAcquiredBuffers_cb _hidl_cb) override;
+    Return<void> startGraphicsAllocatorService(startGraphicsAllocatorService_cb _hidl_cb) override;
+
+    // ::android::hardware::configstore::V1_1::ISurfaceFlingerConfigs follow implementation.
+    Return<void> primaryDisplayOrientation(primaryDisplayOrientation_cb _hidl_cb) override;
+
+    // ::android::hardware::configstore::V1_2::ISurfaceFlingerConfigs follow implementation.
+    Return<void> useColorManagement(useColorManagement_cb _hidl_cb) override;
+    Return<void> getCompositionPreference(getCompositionPreference_cb _hidl_cb) override;
+};
+
+}  // namespace implementation
+}  // namespace V1_2
+}  // namespace configstore
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_CONFIGSTORE_V1_2_SURFACEFLINGERCONFIGS_H
diff --git a/configstore/1.1/default/android.hardware.configstore@1.1-service.rc b/configstore/1.2/default/android.hardware.configstore@1.2-service.rc
similarity index 83%
rename from configstore/1.1/default/android.hardware.configstore@1.1-service.rc
rename to configstore/1.2/default/android.hardware.configstore@1.2-service.rc
index 105678a..d6c5d10 100644
--- a/configstore/1.1/default/android.hardware.configstore@1.1-service.rc
+++ b/configstore/1.2/default/android.hardware.configstore@1.2-service.rc
@@ -1,4 +1,4 @@
-service vendor.configstore-hal /vendor/bin/hw/android.hardware.configstore@1.1-service
+service vendor.configstore-hal /vendor/bin/hw/android.hardware.configstore@1.2-service
     class hal animation
     user system
     group system
diff --git a/configstore/1.1/default/seccomp_policy/configstore@1.1-arm64.policy b/configstore/1.2/default/seccomp_policy/configstore-arm64.policy
similarity index 100%
rename from configstore/1.1/default/seccomp_policy/configstore@1.1-arm64.policy
rename to configstore/1.2/default/seccomp_policy/configstore-arm64.policy
diff --git a/configstore/1.1/default/service.cpp b/configstore/1.2/default/service.cpp
similarity index 80%
rename from configstore/1.1/default/service.cpp
rename to configstore/1.2/default/service.cpp
index 3b4e774..65a42f5 100644
--- a/configstore/1.1/default/service.cpp
+++ b/configstore/1.2/default/service.cpp
@@ -14,27 +14,27 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "android.hardware.configstore@1.1-service"
+#define LOG_TAG "android.hardware.configstore@1.2-service"
 
-#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
+#include <android/hardware/configstore/1.2/ISurfaceFlingerConfigs.h>
 #include <hidl/HidlTransportSupport.h>
 #include <hwminijail/HardwareMinijail.h>
 
 #include "SurfaceFlingerConfigs.h"
 
-using android::hardware::configureRpcThreadpool;
-using android::hardware::joinRpcThreadpool;
-using android::hardware::configstore::V1_1::ISurfaceFlingerConfigs;
-using android::hardware::configstore::V1_1::implementation::SurfaceFlingerConfigs;
-using android::hardware::SetupMinijail;
+using android::OK;
 using android::sp;
 using android::status_t;
-using android::OK;
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::SetupMinijail;
+using android::hardware::configstore::V1_2::ISurfaceFlingerConfigs;
+using android::hardware::configstore::V1_2::implementation::SurfaceFlingerConfigs;
 
 int main() {
     configureRpcThreadpool(10, true);
 
-    SetupMinijail("/vendor/etc/seccomp_policy/configstore@1.1.policy");
+    SetupMinijail("/vendor/etc/seccomp_policy/configstore.policy");
 
     sp<ISurfaceFlingerConfigs> surfaceFlingerConfigs = new SurfaceFlingerConfigs;
     status_t status = surfaceFlingerConfigs->registerAsService();
diff --git a/configstore/1.1/default/surfaceflinger.mk b/configstore/1.2/default/surfaceflinger.mk
similarity index 82%
rename from configstore/1.1/default/surfaceflinger.mk
rename to configstore/1.2/default/surfaceflinger.mk
index 35922eb..f323999 100644
--- a/configstore/1.1/default/surfaceflinger.mk
+++ b/configstore/1.2/default/surfaceflinger.mk
@@ -54,3 +54,15 @@
 ifneq ($(SF_PRIMARY_DISPLAY_ORIENTATION),)
     LOCAL_CFLAGS += -DPRIMARY_DISPLAY_ORIENTATION=$(SF_PRIMARY_DISPLAY_ORIENTATION)
 endif
+
+ifeq ($(TARGET_USE_COLOR_MANAGEMENT),true)
+    LOCAL_CFLAGS += -DUSE_COLOR_MANAGEMENT
+endif
+
+ifneq ($(SF_COMPOSITION_DATA_SPACE),)
+    LOCAL_CFLAGS += -DCOMPOSITION_DATA_SPACE=$(SF_COMPOSITION_DATA_SPACE)
+endif
+
+ifneq ($(SF_COMPOSITION_PIXEL_FORMAT),)
+    LOCAL_CFLAGS += -DCOMPOSITION_PIXEL_FORMAT=$(SF_COMPOSITION_PIXEL_FORMAT)
+endif
diff --git a/configstore/utils/Android.bp b/configstore/utils/Android.bp
index 178f245..e0d4aa8 100644
--- a/configstore/utils/Android.bp
+++ b/configstore/utils/Android.bp
@@ -30,12 +30,14 @@
     shared_libs: [
         "android.hardware.configstore@1.0",
         "android.hardware.configstore@1.1",
+        "android.hardware.configstore@1.2",
         "libbase",
         "libhidlbase"
     ],
     export_shared_lib_headers: [
         "android.hardware.configstore@1.0",
         "android.hardware.configstore@1.1",
+        "android.hardware.configstore@1.2",
         "libbase",
         "libhidlbase"
     ],
diff --git a/contexthub/1.0/default/OWNERS b/contexthub/1.0/default/OWNERS
index 49a3204..5373073 100644
--- a/contexthub/1.0/default/OWNERS
+++ b/contexthub/1.0/default/OWNERS
@@ -1,2 +1,4 @@
-ashutoshj@google.com
+aarossig@google.com
+arthuri@google.com
 bduddie@google.com
+bstack@google.com
diff --git a/contexthub/1.0/vts/functional/OWNERS b/contexthub/1.0/vts/functional/OWNERS
index ad036b4..ee01441 100644
--- a/contexthub/1.0/vts/functional/OWNERS
+++ b/contexthub/1.0/vts/functional/OWNERS
@@ -1,6 +1,8 @@
 #Context Hub team
-ashutoshj@google.com
+aarossig@google.com
+arthuri@google.com
 bduddie@google.com
+bstack@google.com
 
 #VTS team
 yim@google.com
diff --git a/current.txt b/current.txt
index b1a651f..a7989d4 100644
--- a/current.txt
+++ b/current.txt
@@ -385,6 +385,10 @@
 10ff2fae516346b86121368ce5790d5accdfcb73983246b813f3d488b66db45a android.hardware.wifi.supplicant@1.1::ISupplicantStaNetwork
 
 # ABI preserving changes to HALs during Android Q
+2a55e224aa9bc62c0387cd85ad3c97e33f0c33a4e1489cbae86b2523e6f9df35 android.hardware.camera.device@3.2::ICameraDevice
+f61b616732d8f374e030f90575d7eba3ecc99d209a05b945949ba892bcb81e1d android.hardware.camera.device@3.2::ICameraDeviceSession
+684702a60deef03a1e8093961dc0a18c555c857ad5a77ba7340b0635ae01eb70 android.hardware.camera.device@3.4::ICameraDeviceSession
+dd2436f251a90f3e5e7ed773b1aeae21e381b00ae26b10ebe3a1001c894e5980 android.hardware.camera.metadata@3.3::types
 da33234403ff5d60f3473711917b9948e6484a4260b5247acdafb111193a9de2 android.hardware.configstore@1.0::ISurfaceFlingerConfigs
 78886339f2c848cf13c1edd3ebba63f89796b2620d3bf3b5c21d038a53519ba0 android.hardware.gnss@1.0::IGnssMeasurementCallback
 b7ecf29927055ec422ec44bf776223f07d79ad9f92ccf9becf167e62c2607e7a android.hardware.keymaster@4.0::IKeymasterDevice
diff --git a/drm/1.0/default/CryptoPlugin.cpp b/drm/1.0/default/CryptoPlugin.cpp
index f9c868d..666653b 100644
--- a/drm/1.0/default/CryptoPlugin.cpp
+++ b/drm/1.0/default/CryptoPlugin.cpp
@@ -52,7 +52,6 @@
     Return<void> CryptoPlugin::setSharedBufferBase(const hidl_memory& base,
             uint32_t bufferId) {
         sp<IMemory> hidlMemory = mapMemory(base);
-        ALOGE_IF(hidlMemory == nullptr, "mapMemory returns nullptr");
 
         // allow mapMemory to return nullptr
         mSharedBufferMap[bufferId] = hidlMemory;
diff --git a/graphics/composer/2.1/utils/vts/ComposerVts.cpp b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
index 2f531b4..250c392 100644
--- a/graphics/composer/2.1/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.1/utils/vts/ComposerVts.cpp
@@ -25,21 +25,19 @@
 namespace V2_1 {
 namespace vts {
 
-Composer::Composer() {
-    mComposer = ::testing::VtsHalHidlTargetTestBase::getService<IComposer>();
-    init();
-}
+Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
 
-Composer::Composer(const std::string& name) {
-    mComposer = ::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name);
-    init();
-}
+Composer::Composer(const std::string& name)
+    : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
 
-void Composer::init() {
-    ASSERT_NE(nullptr, mComposer.get()) << "failed to get composer service";
+Composer::Composer(const sp<IComposer>& composer) : mComposer(composer) {
+    // ASSERT_* can only be used in functions returning void.
+    [this] {
+        ASSERT_NE(nullptr, mComposer.get()) << "failed to get composer service";
 
-    std::vector<IComposer::Capability> capabilities = getCapabilities();
-    mCapabilities.insert(capabilities.begin(), capabilities.end());
+        std::vector<IComposer::Capability> capabilities = getCapabilities();
+        mCapabilities.insert(capabilities.begin(), capabilities.end());
+    }();
 }
 
 sp<IComposer> Composer::getRaw() const {
@@ -295,7 +293,6 @@
     if (queueChanged) {
         auto ret = mClient->setInputCommandQueue(*writer->getMQDescriptor());
         ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
-        return;
     }
 
     mClient->executeCommands(commandLength, commandHandles,
@@ -314,6 +311,8 @@
                                  ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles));
                                  reader->parse();
                              });
+    reader->reset();
+    writer->reset();
 }
 
 }  // namespace vts
diff --git a/graphics/composer/2.1/utils/vts/TestCommandReader.cpp b/graphics/composer/2.1/utils/vts/TestCommandReader.cpp
index 6f8f1ad..454a89c 100644
--- a/graphics/composer/2.1/utils/vts/TestCommandReader.cpp
+++ b/graphics/composer/2.1/utils/vts/TestCommandReader.cpp
@@ -26,23 +26,55 @@
 namespace vts {
 
 void TestCommandReader::parse() {
+    mErrors.clear();
+    mCompositionChanges.clear();
     while (!isEmpty()) {
         IComposerClient::Command command;
         uint16_t length;
         ASSERT_TRUE(beginCommand(&command, &length));
 
         switch (command) {
+            case IComposerClient::Command::SELECT_DISPLAY:
+                ASSERT_EQ(2, length);
+                read64();  // display
+                break;
             case IComposerClient::Command::SET_ERROR: {
                 ASSERT_EQ(2, length);
                 auto loc = read();
                 auto err = readSigned();
-                GTEST_FAIL() << "unexpected error " << err << " at location " << loc;
+                std::pair<uint32_t, uint32_t> error(loc, err);
+                mErrors.push_back(error);
             } break;
-            case IComposerClient::Command::SELECT_DISPLAY:
             case IComposerClient::Command::SET_CHANGED_COMPOSITION_TYPES:
+                ASSERT_EQ(0, length % 3);
+                for (uint16_t count = 0; count < length / 3; ++count) {
+                    uint64_t layerId = read64();
+                    uint32_t composition = read();
+
+                    std::pair<uint64_t, uint32_t> compositionChange(layerId, composition);
+                    mCompositionChanges.push_back(compositionChange);
+                }
+                break;
             case IComposerClient::Command::SET_DISPLAY_REQUESTS:
+                ASSERT_EQ(1, length % 3);
+                read();  // displayRequests, ignored for now
+                for (uint16_t count = 0; count < (length - 1) / 3; ++count) {
+                    read64();  // layer
+                    // silently eat requests to clear the client target, since we won't be testing
+                    // client composition anyway
+                    ASSERT_EQ(1u, read());
+                }
+                break;
             case IComposerClient::Command::SET_PRESENT_FENCE:
+                ASSERT_EQ(1, length);
+                close(readFence());
+                break;
             case IComposerClient::Command::SET_RELEASE_FENCES:
+                ASSERT_EQ(0, length % 3);
+                for (uint16_t count = 0; count < length / 3; ++count) {
+                    read64();
+                    close(readFence());
+                }
                 break;
             default:
                 GTEST_FAIL() << "unexpected return command " << std::hex
diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
index 8d5493e..c97be76 100644
--- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/ComposerVts.h
@@ -57,10 +57,10 @@
     std::unique_ptr<ComposerClient> createClient();
 
    protected:
-    sp<IComposer> mComposer;
+    explicit Composer(const sp<IComposer>& composer);
 
    private:
-    void init();
+    const sp<IComposer> mComposer;
 
     std::unordered_set<IComposer::Capability> mCapabilities;
 };
@@ -68,7 +68,7 @@
 // A wrapper to IComposerClient.
 class ComposerClient {
    public:
-    ComposerClient(const sp<IComposerClient>& client);
+    explicit ComposerClient(const sp<IComposerClient>& client);
     ~ComposerClient();
 
     sp<IComposerClient> getRaw() const;
@@ -116,7 +116,7 @@
     std::unordered_map<Display, DisplayResource> mDisplayResources;
 
    private:
-    sp<IComposerClient> mClient;
+    const sp<IComposerClient> mClient;
 };
 
 }  // namespace vts
diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h
index 3888eeb..c12debe 100644
--- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h
+++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/TestCommandReader.h
@@ -32,6 +32,9 @@
     // Parse all commands in the return command queue.  Call GTEST_FAIL() for
     // unexpected errors or commands.
     void parse();
+
+    std::vector<std::pair<uint32_t, uint32_t>> mErrors;
+    std::vector<std::pair<uint64_t, uint32_t>> mCompositionChanges;
 };
 
 }  // namespace vts
diff --git a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
index 72f3f1b..0a3e88b 100644
--- a/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
+++ b/graphics/composer/2.1/vts/functional/VtsHalGraphicsComposerV2_1TargetTest.cpp
@@ -71,6 +71,7 @@
 class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
    protected:
     void SetUp() override {
+        VtsHalHidlTargetTestBase::SetUp();
         ASSERT_NO_FATAL_FAILURE(
             mComposer = std::make_unique<Composer>(
                 GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
@@ -85,6 +86,13 @@
         // explicitly disable vsync
         mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
         mComposerCallback->setVsyncAllowed(false);
+
+        mInvalidDisplayId = GetInvalidDisplayId();
+
+        // Although 0 could be an invalid display, a return value of 0
+        // from GetInvalidDisplayId means all other ids are in use, a condition which
+        // we are assuming a device will never have
+        ASSERT_NE(0, mInvalidDisplayId);
     }
 
     void TearDown() override {
@@ -93,6 +101,24 @@
             EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
             EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
         }
+        VtsHalHidlTargetTestBase::TearDown();
+    }
+
+    // returns an invalid display id (one that has not been registered to a
+    // display.  Currently assuming that a device will never have close to
+    // std::numeric_limit<uint64_t>::max() displays registered while running tests
+    Display GetInvalidDisplayId() {
+        std::vector<Display> validDisplays = mComposerCallback->getDisplays();
+
+        uint64_t id = std::numeric_limits<uint64_t>::max();
+        while (id > 0) {
+            if (std::find(validDisplays.begin(), validDisplays.end(), id) == validDisplays.end()) {
+                return id;
+            }
+            id--;
+        }
+
+        return 0;
     }
 
     // use the slot count usually set by SF
@@ -103,6 +129,7 @@
     sp<GraphicsComposerCallback> mComposerCallback;
     // the first display and is assumed never to be removed
     Display mPrimaryDisplay;
+    Display mInvalidDisplayId;
 
    private:
     Display waitForFirstDisplay() {
@@ -172,6 +199,22 @@
 }
 
 /**
+ * Test IComposerClient::destroyVirtualDisplay
+ *
+ * Test that passing a bad display handle to destroyVirtualDisplay
+ * returns a BAD_DISPLAY error
+ */
+TEST_F(GraphicsComposerHidlTest, DestroyVirtualDisplayBadDisplay) {
+    if (mComposerClient->getMaxVirtualDisplayCount() == 0) {
+        GTEST_SUCCEED() << "no virtual display support";
+        return;
+    }
+
+    Error error = mComposerClient->getRaw()->destroyVirtualDisplay(mInvalidDisplayId);
+    ASSERT_EQ(Error::BAD_DISPLAY, error);
+}
+
+/**
  * Test IComposerClient::createLayer and IComposerClient::destroyLayer.
  *
  * Test that layers can be created and destroyed.
@@ -185,6 +228,89 @@
 }
 
 /**
+ * Test IComposerClient::createLayer
+ *
+ * Test that passing in an invalid display handle to createLayer returns
+ * BAD_DISPLAY.
+ */
+TEST_F(GraphicsComposerHidlTest, CreateLayerBadDisplay) {
+    Error error;
+    mComposerClient->getRaw()->createLayer(
+        mInvalidDisplayId, kBufferSlotCount,
+        [&](const auto& tmpOutError, const auto&) { error = tmpOutError; });
+    ASSERT_EQ(Error::BAD_DISPLAY, error);
+}
+
+/**
+ * Test IComposerClient::destroyLayer
+ *
+ * Test that passing in an invalid display handle to destroyLayer returns
+ * BAD_DISPLAY
+ */
+TEST_F(GraphicsComposerHidlTest, DestroyLayerBadDisplay) {
+    Error error;
+    Layer layer;
+    ASSERT_NO_FATAL_FAILURE(layer =
+                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+
+    error = mComposerClient->getRaw()->destroyLayer(mInvalidDisplayId, layer);
+
+    EXPECT_EQ(Error::BAD_DISPLAY, error);
+
+    ASSERT_NO_FATAL_FAILURE(mComposerClient->destroyLayer(mPrimaryDisplay, layer));
+}
+
+/**
+ * Test IComposerClient::destroyLayer
+ *
+ * Test that passing in an invalid layer handle to destroyLayer returns
+ * BAD_LAYER
+ */
+TEST_F(GraphicsComposerHidlTest, DestroyLayerBadLayerError) {
+    // We haven't created any layers yet, so any id should be invalid
+    Error error = mComposerClient->getRaw()->destroyLayer(mPrimaryDisplay, 1);
+
+    EXPECT_EQ(Error::BAD_LAYER, error);
+}
+
+/**
+ * Test IComposerClient::getActiveConfig
+ *
+ * Test that passing in a bad display handle to getActiveConfig generates a
+ * BAD_DISPLAY error
+ */
+TEST_F(GraphicsComposerHidlTest, GetActiveConfigBadDisplay) {
+    Error error;
+    mComposerClient->getRaw()->getActiveConfig(
+        mInvalidDisplayId, [&](const auto& tmpOutError, const auto&) { error = tmpOutError; });
+    ASSERT_EQ(Error::BAD_DISPLAY, error);
+}
+
+/**
+ * Test IComposerClient::getDisplayConfigs
+ *
+ * Test IComposerClient::getDisplayConfigs returns no error
+ * when passed in a valid display
+ */
+TEST_F(GraphicsComposerHidlTest, GetDisplayConfig) {
+    std::vector<Config> configs;
+    ASSERT_NO_FATAL_FAILURE(configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay));
+}
+
+/**
+ * Test IComposerClient::getDisplayConfigs
+ *
+ * Test IComposerClient::getDisplayConfigs returns BAD_DISPLAY
+ * when passed in an invalid display handle
+ */
+TEST_F(GraphicsComposerHidlTest, GetDisplayConfigBadDisplay) {
+    Error error;
+    mComposerClient->getRaw()->getDisplayConfigs(
+        mInvalidDisplayId, [&](const auto& tmpOutError, const auto&) { error = tmpOutError; });
+    ASSERT_EQ(Error::BAD_DISPLAY, error);
+}
+
+/**
  * Test IComposerClient::getDisplayName.
  */
 TEST_F(GraphicsComposerHidlTest, GetDisplayName) {
@@ -226,6 +352,30 @@
 }
 
 /**
+ * Test IComposerClient::getClientTargetSupport
+ *
+ * Test that IComposerClient::getClientTargetSupport returns BAD_DISPLAY when
+ * passed an invalid display handle
+ */
+TEST_F(GraphicsComposerHidlTest, GetClientTargetSupportBadDisplay) {
+    std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
+    for (auto config : configs) {
+        int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
+                                                             IComposerClient::Attribute::WIDTH);
+        int32_t height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
+                                                              IComposerClient::Attribute::HEIGHT);
+        ASSERT_LT(0, width);
+        ASSERT_LT(0, height);
+
+        mComposerClient->setActiveConfig(mPrimaryDisplay, config);
+
+        Error error = mComposerClient->getRaw()->getClientTargetSupport(
+            mInvalidDisplayId, width, height, PixelFormat::RGBA_8888, Dataspace::UNKNOWN);
+        EXPECT_EQ(Error::BAD_DISPLAY, error);
+    }
+}
+
+/**
  * Test IComposerClient::getDisplayAttribute.
  *
  * Test that IComposerClient::getDisplayAttribute succeeds for the required
@@ -287,6 +437,43 @@
 }
 
 /**
+ * Test IComposerClient::setActiveConfig
+ *
+ * Test that config set during IComposerClient::setActiveConfig is maintained
+ * during a display on/off power cycle
+ */
+TEST_F(GraphicsComposerHidlTest, SetActiveConfigPowerCycle) {
+    ASSERT_NO_FATAL_FAILURE(
+        mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::OFF));
+    ASSERT_NO_FATAL_FAILURE(
+        mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::ON));
+
+    std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
+    for (auto config : configs) {
+        mComposerClient->setActiveConfig(mPrimaryDisplay, config);
+        ASSERT_EQ(config, mComposerClient->getActiveConfig(mPrimaryDisplay));
+
+        ASSERT_NO_FATAL_FAILURE(
+            mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::OFF));
+        ASSERT_NO_FATAL_FAILURE(
+            mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::ON));
+        ASSERT_EQ(config, mComposerClient->getActiveConfig(mPrimaryDisplay));
+    }
+}
+
+/**
+ * Test IComposerClient::getColorMode
+ *
+ * Test that IComposerClient::getColorMode always returns ColorMode::NATIVE
+ */
+TEST_F(GraphicsComposerHidlTest, GetColorModes) {
+    std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
+    auto nativeModeLocation = std::find(modes.begin(), modes.end(), ColorMode::NATIVE);
+
+    ASSERT_NE(modes.end(), nativeModeLocation);
+}
+
+/**
  * Test IComposerClient::setColorMode.
  *
  * Test that IComposerClient::setColorMode succeeds for all color modes.
@@ -306,6 +493,45 @@
 }
 
 /**
+ * Test IComposerClient::setColorMode
+ *
+ * Test that IComposerClient::setColorMode returns BAD_DISPLAY for
+ * an invalid display handle
+ */
+TEST_F(GraphicsComposerHidlTest, SetColorModeBadDisplay) {
+    std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
+    for (auto mode : modes) {
+        Error error = mComposerClient->getRaw()->setColorMode(mInvalidDisplayId, mode);
+        EXPECT_EQ(Error::BAD_DISPLAY, error);
+    }
+}
+
+/**
+ * Test IComposerClient::setColorMode
+ *
+ * Test that IComposerClient::setColorMode returns BAD_PARAMETER when passed in
+ * an invalid color mode
+ */
+TEST_F(GraphicsComposerHidlTest, SetColorModeBadParameter) {
+    Error error =
+        mComposerClient->getRaw()->setColorMode(mPrimaryDisplay, static_cast<ColorMode>(-1));
+    ASSERT_EQ(Error::BAD_PARAMETER, error);
+}
+
+/**
+ * Test IComposerClient::getDozeSupport
+ *
+ * Test that IComposerClient::getDozeSupport returns
+ * BAD_DISPLAY when passed an invalid display handle
+ */
+TEST_F(GraphicsComposerHidlTest, GetDozeSupportBadDisplay) {
+    Error error;
+    mComposerClient->getRaw()->getDozeSupport(
+        mInvalidDisplayId, [&](const auto& tmpOutError, const auto&) { error = tmpOutError; });
+    ASSERT_EQ(Error::BAD_DISPLAY, error);
+}
+
+/**
  * Test IComposerClient::setPowerMode.
  *
  * Test that IComposerClient::setPowerMode succeeds for all power modes.
@@ -328,6 +554,99 @@
 }
 
 /**
+ * Test IComposerClient::setPowerMode
+ *
+ * Test IComposerClient::setPowerMode succeeds with different
+ * orderings of power modes
+ */
+TEST_F(GraphicsComposerHidlTest, SetPowerModeVariations) {
+    std::vector<IComposerClient::PowerMode> modes;
+    modes.push_back(IComposerClient::PowerMode::OFF);
+    modes.push_back(IComposerClient::PowerMode::ON);
+    modes.push_back(IComposerClient::PowerMode::OFF);
+    for (auto mode : modes) {
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, mode));
+    }
+
+    modes.clear();
+
+    modes.push_back(IComposerClient::PowerMode::OFF);
+    modes.push_back(IComposerClient::PowerMode::OFF);
+    for (auto mode : modes) {
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, mode));
+    }
+
+    modes.clear();
+
+    modes.push_back(IComposerClient::PowerMode::ON);
+    modes.push_back(IComposerClient::PowerMode::ON);
+    for (auto mode : modes) {
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, mode));
+    }
+
+    modes.clear();
+    if (mComposerClient->getDozeSupport(mPrimaryDisplay)) {
+        modes.push_back(IComposerClient::PowerMode::DOZE);
+        modes.push_back(IComposerClient::PowerMode::DOZE);
+
+        for (auto mode : modes) {
+            ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, mode));
+        }
+
+        modes.clear();
+
+        modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND);
+        modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND);
+
+        for (auto mode : modes) {
+            ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, mode));
+        }
+    }
+}
+
+/**
+ * Test IComposerClient::setPowerMode
+ *
+ * Test IComposerClient::setPowerMode returns BAD_DISPLAY when passed an invalid
+ * display handle
+ */
+TEST_F(GraphicsComposerHidlTest, SetPowerModeBadDisplay) {
+    Error error =
+        mComposerClient->getRaw()->setPowerMode(mInvalidDisplayId, IComposerClient::PowerMode::ON);
+    ASSERT_EQ(Error::BAD_DISPLAY, error);
+}
+
+/**
+ * Test IComposerClient::setPowerMode
+ *
+ * Test that IComposerClient::setPowerMode returns UNSUPPORTED when passed DOZE
+ * or DOZE_SUSPEND on devices that do not support DOZE/DOZE_SUSPEND
+ */
+TEST_F(GraphicsComposerHidlTest, SetPowerModeUnsupported) {
+    if (!mComposerClient->getDozeSupport(mPrimaryDisplay)) {
+        Error error = mComposerClient->getRaw()->setPowerMode(mPrimaryDisplay,
+                                                              IComposerClient::PowerMode::DOZE);
+        EXPECT_EQ(Error::UNSUPPORTED, error);
+
+        error = mComposerClient->getRaw()->setPowerMode(mPrimaryDisplay,
+                                                        IComposerClient::PowerMode::DOZE_SUSPEND);
+        EXPECT_EQ(Error::UNSUPPORTED, error);
+    }
+}
+
+/**
+ * Test IComposerClient::setPowerMode
+ *
+ * Tests that IComposerClient::setPowerMode returns BAD_PARAMETER when passed an invalid
+ * PowerMode
+ */
+TEST_F(GraphicsComposerHidlTest, SetPowerModeBadParameter) {
+    Error error = mComposerClient->getRaw()->setPowerMode(
+        mPrimaryDisplay, static_cast<IComposerClient::PowerMode>(-1));
+    ASSERT_EQ(Error::BAD_PARAMETER, error);
+}
+
+/**
  * Test IComposerClient::setVsyncEnabled.
  *
  * Test that IComposerClient::setVsyncEnabled succeeds and there is no
@@ -351,20 +670,29 @@
 
         ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
 
+        Config activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay);
+        mDisplayWidth = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig,
+                                                             IComposerClient::Attribute::WIDTH);
+        mDisplayHeight = mComposerClient->getDisplayAttribute(mPrimaryDisplay, activeConfig,
+                                                              IComposerClient::Attribute::HEIGHT);
         mWriter = std::make_unique<CommandWriterBase>(1024);
         mReader = std::make_unique<TestCommandReader>();
     }
 
-    void TearDown() override { ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown()); }
+    void TearDown() override {
+        ASSERT_EQ(0, mReader->mErrors.size());
+        ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
+    }
 
     const native_handle_t* allocate() {
         IMapper::BufferDescriptorInfo info{};
-        info.width = 64;
-        info.height = 64;
+        info.width = mDisplayWidth;
+        info.height = mDisplayHeight;
         info.layerCount = 1;
         info.format = PixelFormat::RGBA_8888;
         info.usage =
-            static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
+            static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN |
+                                  BufferUsage::COMPOSER_OVERLAY);
 
         return mGralloc->allocate(info);
     }
@@ -373,6 +701,8 @@
 
     std::unique_ptr<CommandWriterBase> mWriter;
     std::unique_ptr<TestCommandReader> mReader;
+    int32_t mDisplayWidth;
+    int32_t mDisplayHeight;
 
    private:
     std::unique_ptr<Gralloc> mGralloc;
@@ -459,6 +789,60 @@
 }
 
 /**
+ * Test IComposerClient::Command::PRESENT_DISPLAY
+ *
+ * Test that IComposerClient::Command::PRESENT_DISPLAY works without
+ * additional call to validateDisplay when only the layer buffer handle and
+ * surface damage have been set
+ */
+TEST_F(GraphicsComposerHidlCommandTest, PRESENT_DISPLAY_NO_LAYER_STATE_CHANGES) {
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mComposerClient->setPowerMode(mPrimaryDisplay, IComposerClient::PowerMode::ON);
+    mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB);
+
+    auto handle = allocate();
+    ASSERT_NE(nullptr, handle);
+
+    IComposerClient::Rect displayFrame{0, 0, mDisplayWidth, mDisplayHeight};
+
+    Layer layer;
+    ASSERT_NO_FATAL_FAILURE(layer =
+                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+    mWriter->selectLayer(layer);
+    mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
+    mWriter->setLayerDisplayFrame(displayFrame);
+    mWriter->setLayerPlaneAlpha(1);
+    mWriter->setLayerSourceCrop({0, 0, (float)mDisplayWidth, (float)mDisplayHeight});
+    mWriter->setLayerTransform(static_cast<Transform>(0));
+    mWriter->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, displayFrame));
+    mWriter->setLayerZOrder(10);
+    mWriter->setLayerBlendMode(IComposerClient::BlendMode::NONE);
+    mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, displayFrame));
+    mWriter->setLayerBuffer(0, handle, -1);
+    mWriter->setLayerDataspace(Dataspace::UNKNOWN);
+
+    mWriter->validateDisplay();
+    execute();
+    if (mReader->mCompositionChanges.size() != 0) {
+        GTEST_SUCCEED() << "Composition change requested, skipping test";
+        return;
+    }
+
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    mWriter->selectLayer(layer);
+    auto handle2 = allocate();
+    ASSERT_NE(nullptr, handle2);
+    mWriter->setLayerBuffer(0, handle2, -1);
+    mWriter->setLayerSurfaceDamage(std::vector<IComposerClient::Rect>(1, {0, 0, 10, 10}));
+    mWriter->presentDisplay();
+    execute();
+}
+
+/**
  * Test IComposerClient::Command::SET_LAYER_CURSOR_POSITION.
  */
 TEST_F(GraphicsComposerHidlCommandTest, SET_LAYER_CURSOR_POSITION) {
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index 6a32071..da99460 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -27,32 +27,31 @@
 namespace V2_2 {
 namespace vts {
 
-using android::hardware::details::canCastInterface;
-using android::hardware::details::getDescriptor;
-using android::hardware::graphics::composer::V2_2::IComposerClient;
+using details::canCastInterface;
+using details::getDescriptor;
 
-std::unique_ptr<ComposerClient_v2_2> Composer_v2_2::createClient_v2_2() {
-    std::unique_ptr<ComposerClient_v2_2> client;
-    mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) {
+std::unique_ptr<ComposerClient> Composer::createClient() {
+    std::unique_ptr<ComposerClient> client;
+    getRaw()->createClient([&](const auto& tmpError, const auto& tmpClient) {
         ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
         ALOGV("tmpClient is a %s", getDescriptor(&(*tmpClient)).c_str());
         ASSERT_TRUE(canCastInterface(
             &(*tmpClient), "android.hardware.graphics.composer@2.2::IComposerClient", false))
             << "Cannot create 2.2 IComposerClient";
-        client = std::make_unique<ComposerClient_v2_2>(IComposerClient::castFrom(tmpClient, true));
+        client = std::make_unique<ComposerClient>(IComposerClient::castFrom(tmpClient, true));
     });
 
     return client;
 }
 
-sp<V2_2::IComposerClient> ComposerClient_v2_2::getRaw() const {
-    return mClient_v2_2;
+sp<IComposerClient> ComposerClient::getRaw() const {
+    return mClient;
 }
 
-std::vector<IComposerClient::PerFrameMetadataKey> ComposerClient_v2_2::getPerFrameMetadataKeys(
+std::vector<IComposerClient::PerFrameMetadataKey> ComposerClient::getPerFrameMetadataKeys(
     Display display) {
     std::vector<IComposerClient::PerFrameMetadataKey> keys;
-    mClient_v2_2->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) {
+    mClient->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) {
         ASSERT_EQ(Error::NONE, tmpError) << "failed to get HDR metadata keys";
         keys = tmpKeys;
     });
@@ -60,43 +59,43 @@
     return keys;
 }
 
-void ComposerClient_v2_2::execute_v2_2(V2_1::vts::TestCommandReader* reader,
-                                       V2_2::CommandWriterBase* writer) {
+void ComposerClient::execute(V2_1::vts::TestCommandReader* reader, CommandWriterBase* writer) {
     bool queueChanged = false;
     uint32_t commandLength = 0;
     hidl_vec<hidl_handle> commandHandles;
     ASSERT_TRUE(writer->writeQueue(&queueChanged, &commandLength, &commandHandles));
 
     if (queueChanged) {
-        auto ret = mClient_v2_2->setInputCommandQueue(*writer->getMQDescriptor());
+        auto ret = mClient->setInputCommandQueue(*writer->getMQDescriptor());
         ASSERT_EQ(Error::NONE, static_cast<Error>(ret));
-        return;
     }
 
-    mClient_v2_2->executeCommands(commandLength, commandHandles,
-                                  [&](const auto& tmpError, const auto& tmpOutQueueChanged,
-                                      const auto& tmpOutLength, const auto& tmpOutHandles) {
-                                      ASSERT_EQ(Error::NONE, tmpError);
+    mClient->executeCommands(commandLength, commandHandles,
+                             [&](const auto& tmpError, const auto& tmpOutQueueChanged,
+                                 const auto& tmpOutLength, const auto& tmpOutHandles) {
+                                 ASSERT_EQ(Error::NONE, tmpError);
 
-                                      if (tmpOutQueueChanged) {
-                                          mClient_v2_2->getOutputCommandQueue(
-                                              [&](const auto& tmpError, const auto& tmpDescriptor) {
-                                                  ASSERT_EQ(Error::NONE, tmpError);
-                                                  reader->setMQDescriptor(tmpDescriptor);
-                                              });
-                                      }
+                                 if (tmpOutQueueChanged) {
+                                     mClient->getOutputCommandQueue(
+                                         [&](const auto& tmpError, const auto& tmpDescriptor) {
+                                             ASSERT_EQ(Error::NONE, tmpError);
+                                             reader->setMQDescriptor(tmpDescriptor);
+                                         });
+                                 }
 
-                                      ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles));
-                                      reader->parse();
-                                  });
+                                 ASSERT_TRUE(reader->readQueue(tmpOutLength, tmpOutHandles));
+                                 reader->parse();
+                             });
+    reader->reset();
+    writer->reset();
 }
 
-Display ComposerClient_v2_2::createVirtualDisplay_2_2(uint32_t width, uint32_t height,
-                                                      PixelFormat formatHint,
-                                                      uint32_t outputBufferSlotCount,
-                                                      PixelFormat* outFormat) {
+Display ComposerClient::createVirtualDisplay_2_2(uint32_t width, uint32_t height,
+                                                 PixelFormat formatHint,
+                                                 uint32_t outputBufferSlotCount,
+                                                 PixelFormat* outFormat) {
     Display display = 0;
-    mClient_v2_2->createVirtualDisplay_2_2(
+    mClient->createVirtualDisplay_2_2(
         width, height, formatHint, outputBufferSlotCount,
         [&](const auto& tmpError, const auto& tmpDisplay, const auto& tmpFormat) {
             ASSERT_EQ(Error::NONE, tmpError) << "failed to create virtual display";
@@ -110,29 +109,27 @@
     return display;
 }
 
-bool ComposerClient_v2_2::getClientTargetSupport_2_2(Display display, uint32_t width,
-                                                     uint32_t height, PixelFormat format,
-                                                     Dataspace dataspace) {
-    Error error =
-        mClient_v2_2->getClientTargetSupport_2_2(display, width, height, format, dataspace);
+bool ComposerClient::getClientTargetSupport_2_2(Display display, uint32_t width, uint32_t height,
+                                                PixelFormat format, Dataspace dataspace) {
+    Error error = mClient->getClientTargetSupport_2_2(display, width, height, format, dataspace);
     return error == Error::NONE;
 }
 
-void ComposerClient_v2_2::setPowerMode_2_2(Display display, V2_2::IComposerClient::PowerMode mode) {
-    Error error = mClient_v2_2->setPowerMode_2_2(display, mode);
+void ComposerClient::setPowerMode_2_2(Display display, IComposerClient::PowerMode mode) {
+    Error error = mClient->setPowerMode_2_2(display, mode);
     ASSERT_TRUE(error == Error::NONE || error == Error::UNSUPPORTED) << "failed to set power mode";
 }
 
-void ComposerClient_v2_2::setReadbackBuffer(Display display, const native_handle_t* buffer,
-                                            int32_t /* releaseFence */) {
+void ComposerClient::setReadbackBuffer(Display display, const native_handle_t* buffer,
+                                       int32_t /* releaseFence */) {
     // Ignoring fence, HIDL doesn't care
-    Error error = mClient_v2_2->setReadbackBuffer(display, buffer, nullptr);
+    Error error = mClient->setReadbackBuffer(display, buffer, nullptr);
     ASSERT_EQ(Error::NONE, error) << "failed to setReadbackBuffer";
 }
 
-void ComposerClient_v2_2::getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
-                                                      Dataspace* outDataspace) {
-    mClient_v2_2->getReadbackBufferAttributes(
+void ComposerClient::getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+                                                 Dataspace* outDataspace) {
+    mClient->getReadbackBufferAttributes(
         display,
         [&](const auto& tmpError, const auto& tmpOutPixelFormat, const auto& tmpOutDataspace) {
             ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback buffer attributes";
@@ -141,42 +138,40 @@
         });
 }
 
-void ComposerClient_v2_2::getReadbackBufferFence(Display display, int32_t* outFence) {
-    hidl_handle handle;
-    mClient_v2_2->getReadbackBufferFence(display, [&](const auto& tmpError, const auto& tmpHandle) {
+void ComposerClient::getReadbackBufferFence(Display display, int32_t* outFence) {
+    mClient->getReadbackBufferFence(display, [&](const auto& tmpError, const auto& tmpHandle) {
         ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback fence";
-        handle = tmpHandle;
+        const native_handle_t* nativeFenceHandle = tmpHandle.getNativeHandle();
+        *outFence = dup(nativeFenceHandle->data[0]);
     });
-    *outFence = 0;
 }
 
-std::vector<ColorMode> ComposerClient_v2_2::getColorModes(Display display) {
+std::vector<ColorMode> ComposerClient::getColorModes(Display display) {
     std::vector<ColorMode> modes;
-    mClient_v2_2->getColorModes_2_2(display, [&](const auto& tmpError, const auto& tmpModes) {
+    mClient->getColorModes_2_2(display, [&](const auto& tmpError, const auto& tmpModes) {
         ASSERT_EQ(Error::NONE, tmpError) << "failed to get color modes";
         modes = tmpModes;
     });
     return modes;
 }
 
-std::vector<RenderIntent> ComposerClient_v2_2::getRenderIntents(Display display, ColorMode mode) {
+std::vector<RenderIntent> ComposerClient::getRenderIntents(Display display, ColorMode mode) {
     std::vector<RenderIntent> intents;
-    mClient_v2_2->getRenderIntents(
-        display, mode, [&](const auto& tmpError, const auto& tmpIntents) {
-            ASSERT_EQ(Error::NONE, tmpError) << "failed to get render intents";
-            intents = tmpIntents;
-        });
+    mClient->getRenderIntents(display, mode, [&](const auto& tmpError, const auto& tmpIntents) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to get render intents";
+        intents = tmpIntents;
+    });
     return intents;
 }
 
-void ComposerClient_v2_2::setColorMode(Display display, ColorMode mode, RenderIntent intent) {
-    Error error = mClient_v2_2->setColorMode_2_2(display, mode, intent);
+void ComposerClient::setColorMode(Display display, ColorMode mode, RenderIntent intent) {
+    Error error = mClient->setColorMode_2_2(display, mode, intent);
     ASSERT_TRUE(error == Error::NONE || error == Error::UNSUPPORTED) << "failed to set color mode";
 }
 
-std::array<float, 16> ComposerClient_v2_2::getDataspaceSaturationMatrix(Dataspace dataspace) {
+std::array<float, 16> ComposerClient::getDataspaceSaturationMatrix(Dataspace dataspace) {
     std::array<float, 16> matrix;
-    mClient_v2_2->getDataspaceSaturationMatrix(
+    mClient->getDataspaceSaturationMatrix(
         dataspace, [&](const auto& tmpError, const auto& tmpMatrix) {
             ASSERT_EQ(Error::NONE, tmpError) << "failed to get datasapce saturation matrix";
             std::copy_n(tmpMatrix.data(), matrix.size(), matrix.begin());
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index 1c6d7ae..2633021 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -36,36 +36,31 @@
 namespace V2_2 {
 namespace vts {
 
-using android::hardware::graphics::common::V1_0::Hdr;
-using android::hardware::graphics::common::V1_1::ColorMode;
-using android::hardware::graphics::common::V1_1::Dataspace;
-using android::hardware::graphics::common::V1_1::PixelFormat;
-using android::hardware::graphics::common::V1_1::RenderIntent;
-using android::hardware::graphics::composer::V2_2::IComposer;
-using android::hardware::graphics::composer::V2_2::IComposerClient;
+using common::V1_0::Hdr;
+using common::V1_1::ColorMode;
+using common::V1_1::Dataspace;
+using common::V1_1::PixelFormat;
+using common::V1_1::RenderIntent;
 
-class ComposerClient_v2_2;
+class ComposerClient;
 
-// Only thing I need for Composer_v2_2 is to create a v2_2 ComposerClient
-// Everything else is the same
-class Composer_v2_2 : public V2_1::vts::Composer {
+// A wrapper to IComposer.
+class Composer : public V2_1::vts::Composer {
    public:
-    Composer_v2_2() : V2_1::vts::Composer(){};
-    explicit Composer_v2_2(const std::string& name) : V2_1::vts::Composer(name){};
+    using V2_1::vts::Composer::Composer;
 
-    std::unique_ptr<ComposerClient_v2_2> createClient_v2_2();
+    std::unique_ptr<ComposerClient> createClient();
 };
 
 // A wrapper to IComposerClient.
-class ComposerClient_v2_2
-    : public android::hardware::graphics::composer::V2_1::vts::ComposerClient {
+class ComposerClient : public V2_1::vts::ComposerClient {
    public:
-    ComposerClient_v2_2(const sp<IComposerClient>& client)
-        : V2_1::vts::ComposerClient(client), mClient_v2_2(client){};
+    explicit ComposerClient(const sp<IComposerClient>& client)
+        : V2_1::vts::ComposerClient(client), mClient(client) {}
 
-    sp<V2_2::IComposerClient> getRaw() const;
+    sp<IComposerClient> getRaw() const;
 
-    void execute_v2_2(V2_1::vts::TestCommandReader* reader, V2_2::CommandWriterBase* writer);
+    void execute(V2_1::vts::TestCommandReader* reader, CommandWriterBase* writer);
 
     std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys(Display display);
 
@@ -73,7 +68,7 @@
                                      uint32_t outputBufferSlotCount, PixelFormat* outFormat);
     bool getClientTargetSupport_2_2(Display display, uint32_t width, uint32_t height,
                                     PixelFormat format, Dataspace dataspace);
-    void setPowerMode_2_2(Display display, V2_2::IComposerClient::PowerMode mode);
+    void setPowerMode_2_2(Display display, IComposerClient::PowerMode mode);
     void setReadbackBuffer(Display display, const native_handle_t* buffer, int32_t releaseFence);
     void getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
                                      Dataspace* outDataspace);
@@ -86,7 +81,7 @@
     std::array<float, 16> getDataspaceSaturationMatrix(Dataspace dataspace);
 
    private:
-    sp<V2_2::IComposerClient> mClient_v2_2;
+    const sp<IComposerClient> mClient;
 };
 
 }  // namespace vts
diff --git a/graphics/composer/2.2/vts/functional/Android.bp b/graphics/composer/2.2/vts/functional/Android.bp
index 669fbae..acc9245 100644
--- a/graphics/composer/2.2/vts/functional/Android.bp
+++ b/graphics/composer/2.2/vts/functional/Android.bp
@@ -17,12 +17,15 @@
 cc_test {
     name: "VtsHalGraphicsComposerV2_2TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
-    srcs: ["VtsHalGraphicsComposerV2_2TargetTest.cpp"],
+    srcs: [
+        "VtsHalGraphicsComposerV2_2ReadbackTest.cpp",
+        "VtsHalGraphicsComposerV2_2TargetTest.cpp",
+    ],
 
     // TODO(b/64437680): Assume these libs are always available on the device.
     shared_libs: [
         "libfmq",
-	"libhidltransport",
+        "libhidltransport",
         "libsync",
     ],
     static_libs: [
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
new file mode 100644
index 0000000..da8858e
--- /dev/null
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -0,0 +1,1336 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "graphics_composer_hidl_hal_readback_tests@2.2"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <android-base/unique_fd.h>
+#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+#include <composer-vts/2.1/GraphicsComposerCallback.h>
+#include <composer-vts/2.1/TestCommandReader.h>
+#include <composer-vts/2.2/ComposerVts.h>
+#include <mapper-vts/2.1/MapperVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_2 {
+namespace vts {
+namespace {
+
+using android::hardware::hidl_handle;
+using common::V1_1::BufferUsage;
+using common::V1_1::Dataspace;
+using common::V1_1::PixelFormat;
+using mapper::V2_1::IMapper;
+using mapper::V2_1::vts::Gralloc;
+using V2_1::Display;
+using V2_1::Layer;
+using V2_1::vts::TestCommandReader;
+
+static const IComposerClient::Color BLACK = {0, 0, 0, 0xff};
+static const IComposerClient::Color RED = {0xff, 0, 0, 0xff};
+static const IComposerClient::Color TRANSLUCENT_RED = {0xff, 0, 0, 0x33};
+static const IComposerClient::Color GREEN = {0, 0xff, 0, 0xff};
+static const IComposerClient::Color BLUE = {0, 0, 0xff, 0xff};
+
+// Test environment for graphics.composer
+class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static GraphicsComposerHidlEnvironment* Instance() {
+        static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment;
+        return instance;
+    }
+    virtual void registerTestServices() override { registerTestService<IComposer>(); }
+
+   private:
+    GraphicsComposerHidlEnvironment() {}
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment);
+};
+
+class TestLayer {
+   public:
+    TestLayer(const std::shared_ptr<ComposerClient>& client, Display display)
+        : mLayer(client->createLayer(display, kBufferSlotCount)), mComposerClient(client) {}
+
+    // ComposerClient will take care of destroying layers, no need to explicitly
+    // call destroyLayers here
+    virtual ~TestLayer(){};
+
+    virtual void write(const std::shared_ptr<CommandWriterBase>& writer) {
+        writer->selectLayer(mLayer);
+        writer->setLayerDisplayFrame(mDisplayFrame);
+        writer->setLayerSourceCrop(mSourceCrop);
+        writer->setLayerZOrder(mZOrder);
+        writer->setLayerSurfaceDamage(mSurfaceDamage);
+        writer->setLayerTransform(mTransform);
+        writer->setLayerPlaneAlpha(mAlpha);
+        writer->setLayerBlendMode(mBlendMode);
+    }
+
+    void setDisplayFrame(IComposerClient::Rect frame) { mDisplayFrame = frame; }
+    void setSourceCrop(IComposerClient::FRect crop) { mSourceCrop = crop; }
+    void setZOrder(uint32_t z) { mZOrder = z; }
+
+    void setSurfaceDamage(std::vector<IComposerClient::Rect> surfaceDamage) {
+        mSurfaceDamage = surfaceDamage;
+    }
+
+    void setTransform(Transform transform) { mTransform = transform; }
+    void setAlpha(float alpha) { mAlpha = alpha; }
+    void setBlendMode(IComposerClient::BlendMode blendMode) { mBlendMode = blendMode; }
+
+    static constexpr uint32_t kBufferSlotCount = 64;
+
+    IComposerClient::Rect mDisplayFrame = {0, 0, 0, 0};
+    uint32_t mZOrder = 0;
+    std::vector<IComposerClient::Rect> mSurfaceDamage;
+    Transform mTransform = static_cast<Transform>(0);
+    IComposerClient::FRect mSourceCrop = {0, 0, 0, 0};
+    float mAlpha = 1.0;
+    IComposerClient::BlendMode mBlendMode = IComposerClient::BlendMode::NONE;
+
+   protected:
+    Layer mLayer;
+
+   private:
+    std::shared_ptr<ComposerClient> const mComposerClient;
+};
+
+class GraphicsComposerReadbackTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    static int32_t GetBytesPerPixel(PixelFormat pixelFormat) {
+        switch (pixelFormat) {
+            case PixelFormat::RGBA_8888:
+                return 4;
+            case PixelFormat::RGB_888:
+                return 3;
+            default:
+                return -1;
+        }
+    }
+
+    static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
+                           PixelFormat pixelFormat,
+                           std::vector<IComposerClient::Color> desiredPixelColors) {
+        ASSERT_TRUE(pixelFormat == PixelFormat::RGB_888 || pixelFormat == PixelFormat::RGBA_8888);
+        int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat);
+        ASSERT_NE(-1, bytesPerPixel);
+        for (int row = 0; row < height; row++) {
+            for (int col = 0; col < width; col++) {
+                int pixel = row * width + col;
+                IComposerClient::Color srcColor = desiredPixelColors[pixel];
+
+                int offset = (row * stride + col) * bytesPerPixel;
+                uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+                pixelColor[0] = srcColor.r;
+                pixelColor[1] = srcColor.g;
+                pixelColor[2] = srcColor.b;
+
+                if (bytesPerPixel == 4) {
+                    pixelColor[3] = srcColor.a;
+                }
+            }
+        }
+    }
+
+   protected:
+    using PowerMode = V2_1::IComposerClient::PowerMode;
+    void SetUp() override {
+        VtsHalHidlTargetTestBase::SetUp();
+        ASSERT_NO_FATAL_FAILURE(
+            mComposer = std::make_unique<Composer>(
+                GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+        ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
+        mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
+        mComposerClient->registerCallback(mComposerCallback);
+
+        // assume the first display is primary and is never removed
+        mPrimaryDisplay = waitForFirstDisplay();
+        Config activeConfig;
+        ASSERT_NO_FATAL_FAILURE(activeConfig = mComposerClient->getActiveConfig(mPrimaryDisplay));
+        ASSERT_NO_FATAL_FAILURE(
+            mDisplayWidth = mComposerClient->getDisplayAttribute(
+                mPrimaryDisplay, activeConfig, IComposerClient::Attribute::WIDTH));
+        ASSERT_NO_FATAL_FAILURE(
+            mDisplayHeight = mComposerClient->getDisplayAttribute(
+                mPrimaryDisplay, activeConfig, IComposerClient::Attribute::HEIGHT));
+
+        // explicitly disable vsync
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setVsyncEnabled(mPrimaryDisplay, false));
+        mComposerCallback->setVsyncAllowed(false);
+
+        // set up command writer/reader and gralloc
+        mWriter = std::make_shared<CommandWriterBase>(1024);
+        mReader = std::make_unique<TestCommandReader>();
+        mGralloc = std::make_shared<Gralloc>();
+
+        mComposerClient->getRaw()->getReadbackBufferAttributes(
+            mPrimaryDisplay,
+            [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
+                mHasReadbackBuffer = readbackSupported(tmpPixelFormat, tmpDataspace, tmpError);
+                mPixelFormat = tmpPixelFormat;
+                mDataspace = tmpDataspace;
+            });
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::ON));
+    }
+
+    void TearDown() override {
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode(mPrimaryDisplay, PowerMode::OFF));
+        EXPECT_EQ(0, mReader->mErrors.size());
+        EXPECT_EQ(0, mReader->mCompositionChanges.size());
+        if (mComposerCallback != nullptr) {
+            EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+        }
+        VtsHalHidlTargetTestBase::TearDown();
+    }
+
+    void clearCommandReaderState() {
+        mReader->mCompositionChanges.clear();
+        mReader->mErrors.clear();
+    }
+
+    void execute() {
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->execute(mReader.get(), mWriter.get()));
+    }
+
+    void writeLayers(const std::vector<std::shared_ptr<TestLayer>>& layers) {
+        for (auto layer : layers) {
+            layer->write(mWriter);
+        }
+        execute();
+    }
+
+    void clearColors(std::vector<IComposerClient::Color>& expectedColors, int32_t width,
+                     int32_t height) {
+        for (int row = 0; row < height; row++) {
+            for (int col = 0; col < width; col++) {
+                int pixel = row * mDisplayWidth + col;
+                expectedColors[pixel] = BLACK;
+            }
+        }
+    }
+
+    void fillColorsArea(std::vector<IComposerClient::Color>& expectedColors, int32_t stride,
+                        IComposerClient::Rect area, IComposerClient::Color color) {
+        for (int row = area.top; row < area.bottom; row++) {
+            for (int col = area.left; col < area.right; col++) {
+                int pixel = row * stride + col;
+                expectedColors[pixel] = color;
+            }
+        }
+    }
+
+    bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
+                           const Error error) {
+        if (error != Error::NONE) {
+            return false;
+        }
+        // TODO: add support for RGBA_1010102
+        if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) {
+            return false;
+        }
+        if (dataspace != Dataspace::V0_SRGB) {
+            return false;
+        }
+        return true;
+    }
+
+
+    std::unique_ptr<Composer> mComposer;
+    std::shared_ptr<ComposerClient> mComposerClient;
+
+    sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
+    // the first display and is assumed never to be removed
+    Display mPrimaryDisplay;
+    int32_t mDisplayWidth;
+    int32_t mDisplayHeight;
+    std::shared_ptr<CommandWriterBase> mWriter;
+    std::unique_ptr<TestCommandReader> mReader;
+    std::shared_ptr<Gralloc> mGralloc;
+
+    bool mHasReadbackBuffer;
+    PixelFormat mPixelFormat;
+    Dataspace mDataspace;
+
+    static constexpr uint32_t kClientTargetSlotCount = 64;
+
+   private:
+    Display waitForFirstDisplay() {
+        while (true) {
+            std::vector<Display> displays = mComposerCallback->getDisplays();
+            if (displays.empty()) {
+                usleep(5 * 1000);
+                continue;
+            }
+            return displays[0];
+        }
+    }
+};
+class ReadbackBuffer {
+   public:
+    ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
+                   const std::shared_ptr<Gralloc>& gralloc, uint32_t width, uint32_t height,
+                   PixelFormat pixelFormat, Dataspace dataspace) {
+        mDisplay = display;
+
+        mComposerClient = client;
+        mGralloc = gralloc;
+
+        mPixelFormat = pixelFormat;
+        mDataspace = dataspace;
+
+        mInfo.width = width;
+        mInfo.height = height;
+        mInfo.layerCount = 1;
+        mInfo.format = mPixelFormat;
+        mInfo.usage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE);
+
+        mAccessRegion.top = 0;
+        mAccessRegion.left = 0;
+        mAccessRegion.width = width;
+        mAccessRegion.height = height;
+    };
+
+    ~ReadbackBuffer() {
+        if (mBufferHandle != nullptr) {
+            mGralloc->freeBuffer(mBufferHandle);
+        }
+    }
+
+    void setReadbackBuffer() {
+        if (mBufferHandle != nullptr) {
+            mGralloc->freeBuffer(mBufferHandle);
+            mBufferHandle = nullptr;
+        }
+        mBufferHandle = mGralloc->allocate(mInfo, /*import*/ true, &mStride);
+        ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mInfo, mStride));
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle, -1));
+    }
+
+    void checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors) {
+        // lock buffer for reading
+        int32_t fenceHandle;
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle));
+
+        void* bufData = mGralloc->lock(mBufferHandle, mInfo.usage, mAccessRegion, fenceHandle);
+        ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
+        int32_t bytesPerPixel = GraphicsComposerReadbackTest::GetBytesPerPixel(mPixelFormat);
+        ASSERT_NE(-1, bytesPerPixel);
+        for (int row = 0; row < mInfo.height; row++) {
+            for (int col = 0; col < mInfo.width; col++) {
+                int pixel = row * mInfo.width + col;
+                int offset = (row * mStride + col) * bytesPerPixel;
+                uint8_t* pixelColor = (uint8_t*)bufData + offset;
+
+                ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]);
+                ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]);
+                ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]);
+            }
+        }
+        int32_t unlockFence = mGralloc->unlock(mBufferHandle);
+        if (unlockFence != -1) {
+            sync_wait(unlockFence, -1);
+            close(unlockFence);
+        }
+    }
+
+   protected:
+    IMapper::BufferDescriptorInfo mInfo;
+    IMapper::Rect mAccessRegion;
+    uint32_t mStride;
+    const native_handle_t* mBufferHandle = nullptr;
+    PixelFormat mPixelFormat;
+    Dataspace mDataspace;
+    Display mDisplay;
+    std::shared_ptr<Gralloc> mGralloc;
+    std::shared_ptr<ComposerClient> mComposerClient;
+};
+
+class TestColorLayer : public TestLayer {
+   public:
+    TestColorLayer(const std::shared_ptr<ComposerClient>& client, Display display)
+        : TestLayer{client, display} {}
+
+    void write(const std::shared_ptr<CommandWriterBase>& writer) override {
+        TestLayer::write(writer);
+        writer->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR);
+        writer->setLayerColor(mColor);
+    }
+
+    void setColor(IComposerClient::Color color) { mColor = color; }
+
+   private:
+    IComposerClient::Color mColor = {0xff, 0xff, 0xff, 0xff};
+};
+
+class TestBufferLayer : public TestLayer {
+   public:
+    TestBufferLayer(const std::shared_ptr<ComposerClient>& client,
+                    const std::shared_ptr<Gralloc>& gralloc, Display display, int32_t width,
+                    int32_t height, PixelFormat format,
+                    IComposerClient::Composition composition = IComposerClient::Composition::DEVICE)
+        : TestLayer{client, display} {
+        mGralloc = gralloc;
+        mComposition = composition;
+        mInfo.width = width;
+        mInfo.height = height;
+        mInfo.layerCount = 1;
+        mInfo.format = format;
+        mInfo.usage =
+            static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                  BufferUsage::COMPOSER_OVERLAY);
+
+        mAccessRegion.top = 0;
+        mAccessRegion.left = 0;
+        mAccessRegion.width = width;
+        mAccessRegion.height = height;
+
+        setSourceCrop({0, 0, (float)width, (float)height});
+    }
+
+    ~TestBufferLayer() {
+        if (mBufferHandle != nullptr) {
+            mGralloc->freeBuffer(mBufferHandle);
+        }
+    }
+
+    void write(const std::shared_ptr<CommandWriterBase>& writer) override {
+        TestLayer::write(writer);
+        writer->setLayerCompositionType(mComposition);
+        writer->setLayerDataspace(Dataspace::UNKNOWN);
+        writer->setLayerVisibleRegion(std::vector<IComposerClient::Rect>(1, mDisplayFrame));
+        if (mBufferHandle != nullptr) writer->setLayerBuffer(0, mBufferHandle, mFillFence);
+    }
+
+    void fillBuffer(std::vector<IComposerClient::Color> expectedColors) {
+        void* bufData = mGralloc->lock(mBufferHandle, mInfo.usage, mAccessRegion, -1);
+        ASSERT_NO_FATAL_FAILURE(GraphicsComposerReadbackTest::fillBuffer(
+            mInfo.width, mInfo.height, mStride, bufData, mInfo.format, expectedColors));
+        mFillFence = mGralloc->unlock(mBufferHandle);
+        if (mFillFence != -1) {
+            sync_wait(mFillFence, -1);
+            close(mFillFence);
+        }
+    }
+    void setBuffer(std::vector<IComposerClient::Color> colors) {
+        if (mBufferHandle != nullptr) {
+            mGralloc->freeBuffer(mBufferHandle);
+            mBufferHandle = nullptr;
+        }
+        mBufferHandle = mGralloc->allocate(mInfo, /*import*/ true, &mStride);
+        ASSERT_NE(nullptr, mBufferHandle);
+        ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
+        ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle, mInfo, mStride));
+    }
+
+    void setToClientComposition(const std::shared_ptr<CommandWriterBase>& writer) {
+        writer->selectLayer(mLayer);
+        writer->setLayerCompositionType(IComposerClient::Composition::CLIENT);
+    }
+
+    IMapper::BufferDescriptorInfo mInfo;
+    IMapper::Rect mAccessRegion;
+    uint32_t mStride;
+
+   protected:
+    IComposerClient::Composition mComposition;
+    std::shared_ptr<Gralloc> mGralloc;
+    int32_t mFillFence;
+    const native_handle_t* mBufferHandle = nullptr;
+};
+
+TEST_F(GraphicsComposerReadbackTest, SingleSolidColorLayer) {
+    if (!mHasReadbackBuffer) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+    mWriter->selectDisplay(mPrimaryDisplay);
+    ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB,
+                                                          RenderIntent::COLORIMETRIC));
+
+    auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+    IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
+    layer->setColor(BLUE);
+    layer->setDisplayFrame(coloredSquare);
+    layer->setZOrder(10);
+
+    std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+    // expected color for each pixel
+    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+    fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
+
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                  mDisplayHeight, mPixelFormat, mDataspace);
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+    writeLayers(layers);
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+    // if hwc cannot handle and asks for composition change,
+    // just succeed the test
+    if (mReader->mCompositionChanges.size() != 0) {
+        clearCommandReaderState();
+        GTEST_SUCCEED();
+        return;
+    }
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+}
+
+TEST_F(GraphicsComposerReadbackTest, SetLayerBuffer) {
+    if (!mHasReadbackBuffer) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                  mDisplayHeight, mPixelFormat, mDataspace);
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+    fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+    fillColorsArea(expectedColors, mDisplayWidth,
+                   {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, GREEN);
+    fillColorsArea(expectedColors, mDisplayWidth,
+                   {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
+
+    auto layer =
+        std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
+                                          mDisplayHeight, PixelFormat::RGBA_8888);
+    layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+    layer->setZOrder(10);
+    ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+    std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+    writeLayers(layers);
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+
+    if (mReader->mCompositionChanges.size() != 0) {
+        clearCommandReaderState();
+        GTEST_SUCCEED();
+        return;
+    }
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    mWriter->presentDisplay();
+    execute();
+
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+}
+
+TEST_F(GraphicsComposerReadbackTest, SetLayerBufferNoEffect) {
+    if (!mHasReadbackBuffer) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+    ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB,
+                                                          RenderIntent::COLORIMETRIC));
+
+    auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+    IComposerClient::Rect coloredSquare({0, 0, mDisplayWidth, mDisplayHeight});
+    layer->setColor(BLUE);
+    layer->setDisplayFrame(coloredSquare);
+    layer->setZOrder(10);
+    layer->write(mWriter);
+
+    // This following buffer call should have no effect
+    IMapper::BufferDescriptorInfo bufferInfo{};
+    bufferInfo.width = mDisplayWidth;
+    bufferInfo.height = mDisplayHeight;
+    bufferInfo.layerCount = 1;
+    bufferInfo.format = PixelFormat::RGBA_8888;
+    bufferInfo.usage =
+        static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN);
+    const native_handle_t* bufferHandle = mGralloc->allocate(bufferInfo);
+    mWriter->setLayerBuffer(0, bufferHandle, -1);
+
+    // expected color for each pixel
+    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+    fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
+
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                  mDisplayHeight, mPixelFormat, mDataspace);
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+    mWriter->validateDisplay();
+    execute();
+
+    if (mReader->mCompositionChanges.size() != 0) {
+        clearCommandReaderState();
+        GTEST_SUCCEED();
+        return;
+    }
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+}
+
+TEST_F(GraphicsComposerReadbackTest, ClientComposition) {
+    if (!mHasReadbackBuffer) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+
+    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+    fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+    fillColorsArea(expectedColors, mDisplayWidth,
+                   {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight / 2}, GREEN);
+    fillColorsArea(expectedColors, mDisplayWidth,
+                   {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
+
+    auto layer =
+        std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
+                                          mDisplayHeight, PixelFormat::RGBA_FP16);
+    layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+    layer->setZOrder(10);
+
+    std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                  mDisplayHeight, mPixelFormat, mDataspace);
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+    writeLayers(layers);
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+
+    if (mReader->mCompositionChanges.size() != 0) {
+        ASSERT_EQ(1, mReader->mCompositionChanges.size());
+        ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
+
+        ASSERT_NO_FATAL_FAILURE(
+            mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount));
+
+        // create client target buffer
+        uint32_t clientStride;
+        IMapper::BufferDescriptorInfo clientInfo;
+        clientInfo.width = layer->mInfo.width;
+        clientInfo.height = layer->mInfo.height;
+        clientInfo.layerCount = layer->mInfo.layerCount;
+        clientInfo.format = PixelFormat::RGBA_8888;
+        clientInfo.usage =
+            static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                  BufferUsage::COMPOSER_CLIENT_TARGET);
+        const native_handle_t* clientBufferHandle =
+            mGralloc->allocate(clientInfo, /*import*/ true, &clientStride);
+        ASSERT_NE(nullptr, clientBufferHandle);
+
+        void* clientBufData =
+            mGralloc->lock(clientBufferHandle, clientInfo.usage, layer->mAccessRegion, -1);
+
+        ASSERT_NO_FATAL_FAILURE(fillBuffer(clientInfo.width, clientInfo.height, clientStride,
+                                           clientBufData, clientInfo.format, expectedColors));
+        int clientFence = mGralloc->unlock(clientBufferHandle);
+        if (clientFence != -1) {
+            sync_wait(clientFence, -1);
+            close(clientFence);
+        }
+
+        IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight};
+        mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN,
+                                 std::vector<IComposerClient::Rect>(1, damage));
+
+        layer->setToClientComposition(mWriter);
+        mWriter->validateDisplay();
+        execute();
+        ASSERT_EQ(0, mReader->mCompositionChanges.size());
+    }
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    mWriter->presentDisplay();
+    execute();
+
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+}
+
+TEST_F(GraphicsComposerReadbackTest, DeviceAndClientComposition) {
+    if (!mHasReadbackBuffer) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+    ASSERT_NO_FATAL_FAILURE(
+        mComposerClient->setClientTargetSlotCount(mPrimaryDisplay, kClientTargetSlotCount));
+
+    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+    fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 2}, GREEN);
+    fillColorsArea(expectedColors, mDisplayWidth,
+                   {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED);
+
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                  mDisplayHeight, mPixelFormat, mDataspace);
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+    auto deviceLayer =
+        std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
+                                          mDisplayHeight / 2, PixelFormat::RGBA_8888);
+    std::vector<IComposerClient::Color> deviceColors(deviceLayer->mInfo.width *
+                                                     deviceLayer->mInfo.height);
+    fillColorsArea(deviceColors, deviceLayer->mInfo.width,
+                   {0, 0, static_cast<int32_t>(deviceLayer->mInfo.width),
+                    static_cast<int32_t>(deviceLayer->mInfo.height)},
+                   GREEN);
+    deviceLayer->setDisplayFrame({0, 0, static_cast<int32_t>(deviceLayer->mInfo.width),
+                                  static_cast<int32_t>(deviceLayer->mInfo.height)});
+    deviceLayer->setZOrder(10);
+    ASSERT_NO_FATAL_FAILURE(deviceLayer->setBuffer(deviceColors));
+    deviceLayer->write(mWriter);
+
+    auto clientLayer = std::make_shared<TestBufferLayer>(
+        mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth, mDisplayHeight / 2,
+        PixelFormat::RGBA_8888, IComposerClient::Composition::CLIENT);
+    IComposerClient::Rect clientFrame = {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight};
+    clientLayer->setDisplayFrame(clientFrame);
+    clientLayer->setZOrder(0);
+    clientLayer->write(mWriter);
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    IMapper::BufferDescriptorInfo clientInfo;
+    clientInfo.width = mDisplayWidth;
+    clientInfo.height = mDisplayHeight;
+    clientInfo.layerCount = 1;
+    clientInfo.format = PixelFormat::RGBA_8888;
+    clientInfo.usage =
+        static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                              BufferUsage::COMPOSER_CLIENT_TARGET);
+
+    uint32_t clientStride;
+    const native_handle_t* clientBufferHandle =
+        mGralloc->allocate(clientInfo, /*import*/ true, &clientStride);
+    ASSERT_NE(nullptr, clientBufferHandle);
+
+    IMapper::Rect clientAccessRegion;
+    clientAccessRegion.left = 0;
+    clientAccessRegion.top = 0;
+    clientAccessRegion.width = mDisplayWidth;
+    clientAccessRegion.height = mDisplayHeight;
+    void* clientData = mGralloc->lock(clientBufferHandle, clientInfo.usage, clientAccessRegion, -1);
+    std::vector<IComposerClient::Color> clientColors(clientInfo.width * clientInfo.height);
+    fillColorsArea(clientColors, clientInfo.width, clientFrame, RED);
+    ASSERT_NO_FATAL_FAILURE(fillBuffer(clientInfo.width, clientInfo.height, clientStride,
+                                       clientData, clientInfo.format, clientColors));
+    int clientFence = mGralloc->unlock(clientBufferHandle);
+    if (clientFence != -1) {
+        sync_wait(clientFence, -1);
+        close(clientFence);
+    }
+
+    mWriter->setClientTarget(0, clientBufferHandle, clientFence, Dataspace::UNKNOWN,
+                             std::vector<IComposerClient::Rect>(1, clientFrame));
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+    if (mReader->mCompositionChanges.size() != 0) {
+        clearCommandReaderState();
+        GTEST_SUCCEED();
+        return;
+    }
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+}
+
+TEST_F(GraphicsComposerReadbackTest, SetLayerDamage) {
+    if (!mHasReadbackBuffer) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelformat/dataspace";
+        return;
+    }
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+
+    IComposerClient::Rect redRect = {0, 0, mDisplayWidth / 4, mDisplayHeight / 4};
+
+    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+    fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+
+    auto layer =
+        std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
+                                          mDisplayHeight, PixelFormat::RGBA_8888);
+    layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+    layer->setZOrder(10);
+    ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+    std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                  mDisplayHeight, mPixelFormat, mDataspace);
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+    writeLayers(layers);
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+    if (mReader->mCompositionChanges.size() != 0) {
+        clearCommandReaderState();
+        GTEST_SUCCEED();
+        return;
+    }
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+
+    // update surface damage and recheck
+    redRect = {mDisplayWidth / 4, mDisplayHeight / 4, mDisplayWidth / 2, mDisplayHeight / 2};
+    clearColors(expectedColors, mDisplayWidth, mDisplayHeight);
+    fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+
+    ASSERT_NO_FATAL_FAILURE(layer->fillBuffer(expectedColors));
+    layer->setSurfaceDamage(
+        std::vector<IComposerClient::Rect>(1, {0, 0, mDisplayWidth / 2, mDisplayWidth / 2}));
+
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+    writeLayers(layers);
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+    ASSERT_EQ(0, mReader->mCompositionChanges.size());
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+}
+
+TEST_F(GraphicsComposerReadbackTest, SetLayerPlaneAlpha) {
+    if (!mHasReadbackBuffer) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+    ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB,
+                                                          RenderIntent::COLORIMETRIC));
+
+    auto layer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+    layer->setColor(RED);
+    layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+    layer->setZOrder(10);
+    layer->setAlpha(0);
+    layer->setBlendMode(IComposerClient::BlendMode::PREMULTIPLIED);
+
+    std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                  mDisplayHeight, mPixelFormat, mDataspace);
+
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+    writeLayers(layers);
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+    if (mReader->mCompositionChanges.size() != 0) {
+        clearCommandReaderState();
+        GTEST_SUCCEED();
+        return;
+    }
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+}
+
+TEST_F(GraphicsComposerReadbackTest, SetLayerSourceCrop) {
+    if (!mHasReadbackBuffer) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+
+    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+    fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight / 4}, RED);
+    fillColorsArea(expectedColors, mDisplayWidth,
+                   {0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, BLUE);
+
+    auto layer =
+        std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay, mDisplayWidth,
+                                          mDisplayHeight, PixelFormat::RGBA_8888);
+    layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+    layer->setZOrder(10);
+    layer->setSourceCrop({0, static_cast<float>(mDisplayHeight / 2),
+                          static_cast<float>(mDisplayWidth), static_cast<float>(mDisplayHeight)});
+    ASSERT_NO_FATAL_FAILURE(layer->setBuffer(expectedColors));
+
+    std::vector<std::shared_ptr<TestLayer>> layers = {layer};
+
+    // update expected colors to match crop
+    fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight}, BLUE);
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                  mDisplayHeight, mPixelFormat, mDataspace);
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+    writeLayers(layers);
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+    if (mReader->mCompositionChanges.size() != 0) {
+        clearCommandReaderState();
+        GTEST_SUCCEED();
+        return;
+    }
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+}
+
+TEST_F(GraphicsComposerReadbackTest, SetLayerZOrder) {
+    if (!mHasReadbackBuffer) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+    ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB,
+                                                          RenderIntent::COLORIMETRIC));
+
+    IComposerClient::Rect redRect = {0, 0, mDisplayWidth, mDisplayHeight / 2};
+    IComposerClient::Rect blueRect = {0, mDisplayHeight / 4, mDisplayWidth, mDisplayHeight};
+    auto redLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+    redLayer->setColor(RED);
+    redLayer->setDisplayFrame(redRect);
+
+    auto blueLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+    blueLayer->setColor(BLUE);
+    blueLayer->setDisplayFrame(blueRect);
+    blueLayer->setZOrder(5);
+
+    std::vector<std::shared_ptr<TestLayer>> layers = {redLayer, blueLayer};
+    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+    // red in front of blue
+    redLayer->setZOrder(10);
+
+    // fill blue first so that red will overwrite on overlap
+    fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
+    fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                  mDisplayHeight, mPixelFormat, mDataspace);
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+    writeLayers(layers);
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+    if (mReader->mCompositionChanges.size() != 0) {
+        clearCommandReaderState();
+        GTEST_SUCCEED();
+        return;
+    }
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+
+    redLayer->setZOrder(1);
+    clearColors(expectedColors, mDisplayWidth, mDisplayHeight);
+    fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
+    fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
+
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+    writeLayers(layers);
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mCompositionChanges.size());
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+}
+
+class GraphicsComposerBlendModeReadbackTest : public GraphicsComposerReadbackTest,
+                                              public ::testing::WithParamInterface<float> {
+   public:
+    void SetUp() override {
+        GraphicsComposerReadbackTest::SetUp();
+        mBackgroundColor = BLACK;
+        mTopLayerColor = RED;
+    }
+
+    void TearDown() override { GraphicsComposerReadbackTest::TearDown(); }
+
+    void setBackgroundColor(IComposerClient::Color color) { mBackgroundColor = color; }
+
+    void setTopLayerColor(IComposerClient::Color color) { mTopLayerColor = color; }
+
+    void setUpLayers(IComposerClient::BlendMode blendMode) {
+        mLayers.clear();
+        std::vector<IComposerClient::Color> topLayerPixelColors(mDisplayWidth * mDisplayHeight);
+        fillColorsArea(topLayerPixelColors, mDisplayWidth, {0, 0, mDisplayWidth, mDisplayHeight},
+                       mTopLayerColor);
+
+        auto backgroundLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        backgroundLayer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        backgroundLayer->setZOrder(0);
+        backgroundLayer->setColor(mBackgroundColor);
+
+        auto layer = std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
+                                                       mDisplayWidth, mDisplayHeight,
+                                                       PixelFormat::RGBA_8888);
+        layer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        layer->setZOrder(10);
+        ASSERT_NO_FATAL_FAILURE(layer->setBuffer(topLayerPixelColors));
+
+        layer->setBlendMode(blendMode);
+        layer->setAlpha(GetParam());
+
+        mLayers.push_back(backgroundLayer);
+        mLayers.push_back(layer);
+    }
+
+    void setExpectedColors(std::vector<IComposerClient::Color>& expectedColors) {
+        ASSERT_EQ(2, mLayers.size());
+        clearColors(expectedColors, mDisplayWidth, mDisplayHeight);
+
+        auto layer = mLayers[1];
+        IComposerClient::BlendMode blendMode = layer->mBlendMode;
+        float alpha = mTopLayerColor.a / 255.0 * layer->mAlpha;
+        if (blendMode == IComposerClient::BlendMode::NONE) {
+            for (int i = 0; i < expectedColors.size(); i++) {
+                expectedColors[i].r = mTopLayerColor.r * layer->mAlpha;
+                expectedColors[i].g = mTopLayerColor.g * layer->mAlpha;
+                expectedColors[i].b = mTopLayerColor.b * layer->mAlpha;
+                expectedColors[i].a = alpha * 255.0;
+            }
+        } else if (blendMode == IComposerClient::BlendMode::PREMULTIPLIED) {
+            for (int i = 0; i < expectedColors.size(); i++) {
+                expectedColors[i].r =
+                    mTopLayerColor.r * layer->mAlpha + mBackgroundColor.r * (1.0 - alpha);
+                expectedColors[i].g =
+                    mTopLayerColor.g * layer->mAlpha + mBackgroundColor.g * (1.0 - alpha);
+                expectedColors[i].b =
+                    mTopLayerColor.b * layer->mAlpha + mBackgroundColor.b * (1.0 - alpha);
+                expectedColors[i].a = alpha + mBackgroundColor.a * (1.0 - alpha);
+            }
+        } else if (blendMode == IComposerClient::BlendMode::COVERAGE) {
+            for (int i = 0; i < expectedColors.size(); i++) {
+                expectedColors[i].r = mTopLayerColor.r * alpha + mBackgroundColor.r * (1.0 - alpha);
+                expectedColors[i].g = mTopLayerColor.g * alpha + mBackgroundColor.g * (1.0 - alpha);
+                expectedColors[i].b = mTopLayerColor.b * alpha + mBackgroundColor.b * (1.0 - alpha);
+                expectedColors[i].a = mTopLayerColor.a * alpha + mBackgroundColor.a * (1.0 - alpha);
+            }
+        }
+    }
+
+   protected:
+    std::vector<std::shared_ptr<TestLayer>> mLayers;
+    IComposerClient::Color mBackgroundColor;
+    IComposerClient::Color mTopLayerColor;
+};
+
+TEST_P(GraphicsComposerBlendModeReadbackTest, None) {
+    if (!mHasReadbackBuffer) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+
+    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+    setBackgroundColor(BLACK);
+    setTopLayerColor(TRANSLUCENT_RED);
+    setUpLayers(IComposerClient::BlendMode::NONE);
+    setExpectedColors(expectedColors);
+
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                  mDisplayHeight, mPixelFormat, mDataspace);
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+    writeLayers(mLayers);
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+    if (mReader->mCompositionChanges.size() != 0) {
+        clearCommandReaderState();
+        GTEST_SUCCEED();
+        return;
+    }
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+}
+
+// TODO: bug 116865056: Readback returns (245, 0, 0) for layer plane
+// alpha of .2, expected 10.2
+TEST_P(GraphicsComposerBlendModeReadbackTest, DISABLED_Coverage) {
+    if (!mHasReadbackBuffer) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+
+    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+    setBackgroundColor(BLACK);
+    setTopLayerColor(TRANSLUCENT_RED);
+
+    setUpLayers(IComposerClient::BlendMode::COVERAGE);
+    setExpectedColors(expectedColors);
+
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                  mDisplayHeight, mPixelFormat, mDataspace);
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+    writeLayers(mLayers);
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+    if (mReader->mCompositionChanges.size() != 0) {
+        clearCommandReaderState();
+        GTEST_SUCCEED();
+        return;
+    }
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+}
+
+TEST_P(GraphicsComposerBlendModeReadbackTest, Premultiplied) {
+    if (!mHasReadbackBuffer) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+
+    mWriter->selectDisplay(mPrimaryDisplay);
+
+    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+
+    setBackgroundColor(BLACK);
+    setTopLayerColor(TRANSLUCENT_RED);
+    setUpLayers(IComposerClient::BlendMode::PREMULTIPLIED);
+    setExpectedColors(expectedColors);
+
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                  mDisplayHeight, mPixelFormat, mDataspace);
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+    writeLayers(mLayers);
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+    if (mReader->mCompositionChanges.size() != 0) {
+        clearCommandReaderState();
+        GTEST_SUCCEED();
+        return;
+    }
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+}
+
+INSTANTIATE_TEST_CASE_P(BlendModeTest, GraphicsComposerBlendModeReadbackTest,
+                        ::testing::Values(.2, 1.0));
+
+class GraphicsComposerTransformReadbackTest : public GraphicsComposerReadbackTest {
+   protected:
+    void SetUp() override {
+        GraphicsComposerReadbackTest::SetUp();
+
+        mWriter->selectDisplay(mPrimaryDisplay);
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::SRGB,
+                                                              RenderIntent::COLORIMETRIC));
+
+        auto backgroundLayer = std::make_shared<TestColorLayer>(mComposerClient, mPrimaryDisplay);
+        backgroundLayer->setColor({0, 0, 0, 0});
+        backgroundLayer->setDisplayFrame({0, 0, mDisplayWidth, mDisplayHeight});
+        backgroundLayer->setZOrder(0);
+
+        mSideLength = mDisplayWidth < mDisplayHeight ? mDisplayWidth : mDisplayHeight;
+        IComposerClient::Rect redRect = {0, 0, mSideLength / 2, mSideLength / 2};
+        IComposerClient::Rect blueRect = {mSideLength / 2, mSideLength / 2, mSideLength,
+                                          mSideLength};
+
+        mLayer =
+            std::make_shared<TestBufferLayer>(mComposerClient, mGralloc, mPrimaryDisplay,
+                                              mSideLength, mSideLength, PixelFormat::RGBA_8888);
+        mLayer->setDisplayFrame({0, 0, mSideLength, mSideLength});
+        mLayer->setZOrder(10);
+
+        std::vector<IComposerClient::Color> baseColors(mSideLength * mSideLength);
+        fillColorsArea(baseColors, mSideLength, redRect, RED);
+        fillColorsArea(baseColors, mSideLength, blueRect, BLUE);
+        ASSERT_NO_FATAL_FAILURE(mLayer->setBuffer(baseColors));
+
+        mLayers = {backgroundLayer, mLayer};
+    }
+
+   protected:
+    std::shared_ptr<TestBufferLayer> mLayer;
+    std::vector<IComposerClient::Color> baseColors;
+    std::vector<std::shared_ptr<TestLayer>> mLayers;
+    int mSideLength;
+};
+
+TEST_F(GraphicsComposerTransformReadbackTest, FLIP_H) {
+    if (!mHasReadbackBuffer) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                  mDisplayHeight, mPixelFormat, mDataspace);
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+    mLayer->setTransform(Transform::FLIP_H);
+    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+    fillColorsArea(expectedColors, mDisplayWidth,
+                   {mSideLength / 2, 0, mSideLength, mSideLength / 2}, RED);
+    fillColorsArea(expectedColors, mDisplayWidth,
+                   {0, mSideLength / 2, mSideLength / 2, mSideLength}, BLUE);
+
+    writeLayers(mLayers);
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+    if (mReader->mCompositionChanges.size() != 0) {
+        clearCommandReaderState();
+        GTEST_SUCCEED();
+        return;
+    }
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+}
+
+TEST_F(GraphicsComposerTransformReadbackTest, FLIP_V) {
+    if (!mHasReadbackBuffer) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                  mDisplayHeight, mPixelFormat, mDataspace);
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+    mLayer->setTransform(Transform::FLIP_V);
+
+    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+    fillColorsArea(expectedColors, mDisplayWidth,
+                   {0, mSideLength / 2, mSideLength / 2, mSideLength}, RED);
+    fillColorsArea(expectedColors, mDisplayWidth,
+                   {mSideLength / 2, 0, mSideLength, mSideLength / 2}, BLUE);
+
+    writeLayers(mLayers);
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+    if (mReader->mCompositionChanges.size() != 0) {
+        clearCommandReaderState();
+        GTEST_SUCCEED();
+        return;
+    }
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+}
+
+TEST_F(GraphicsComposerTransformReadbackTest, ROT_180) {
+    if (!mHasReadbackBuffer) {
+        GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
+        return;
+    }
+    ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
+                                  mDisplayHeight, mPixelFormat, mDataspace);
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
+
+    mLayer->setTransform(Transform::ROT_180);
+
+    std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
+    fillColorsArea(expectedColors, mDisplayWidth,
+                   {mSideLength / 2, mSideLength / 2, mSideLength, mSideLength}, RED);
+    fillColorsArea(expectedColors, mDisplayWidth, {0, 0, mSideLength / 2, mSideLength / 2}, BLUE);
+
+    writeLayers(mLayers);
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->validateDisplay();
+    execute();
+    if (mReader->mCompositionChanges.size() != 0) {
+        clearCommandReaderState();
+        GTEST_SUCCEED();
+        return;
+    }
+    ASSERT_EQ(0, mReader->mErrors.size());
+    mWriter->presentDisplay();
+    execute();
+    ASSERT_EQ(0, mReader->mErrors.size());
+    ASSERT_NO_FATAL_FAILURE(readbackBuffer.checkReadbackBuffer(expectedColors));
+}
+
+}  // anonymous namespace
+}  // namespace vts
+}  // namespace V2_2
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
index 23bf558..7834b94 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -18,11 +18,11 @@
 
 #include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
-#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
 #include <composer-vts/2.1/GraphicsComposerCallback.h>
 #include <composer-vts/2.1/TestCommandReader.h>
 #include <composer-vts/2.2/ComposerVts.h>
-#include <mapper-vts/2.1/MapperVts.h>
+#include <mapper-vts/2.0/MapperVts.h>
 
 namespace android {
 namespace hardware {
@@ -32,17 +32,15 @@
 namespace vts {
 namespace {
 
-using android::hardware::graphics::common::V1_0::BufferUsage;
-using android::hardware::graphics::common::V1_0::ColorTransform;
-using android::hardware::graphics::common::V1_0::Transform;
-using android::hardware::graphics::common::V1_1::ColorMode;
-using android::hardware::graphics::common::V1_1::Dataspace;
-using android::hardware::graphics::common::V1_1::PixelFormat;
-using android::hardware::graphics::common::V1_1::RenderIntent;
-using android::hardware::graphics::composer::V2_2::IComposerClient;
-using android::hardware::graphics::mapper::V2_1::IMapper;
-using android::hardware::graphics::mapper::V2_1::vts::Gralloc;
-using GrallocError = android::hardware::graphics::mapper::V2_0::Error;
+using common::V1_0::BufferUsage;
+using common::V1_0::ColorTransform;
+using common::V1_0::Transform;
+using common::V1_1::ColorMode;
+using common::V1_1::Dataspace;
+using common::V1_1::PixelFormat;
+using common::V1_1::RenderIntent;
+using mapper::V2_0::IMapper;
+using mapper::V2_0::vts::Gralloc;
 
 // Test environment for graphics.composer
 class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
@@ -65,9 +63,9 @@
    protected:
     void SetUp() override {
         ASSERT_NO_FATAL_FAILURE(
-            mComposer = std::make_unique<Composer_v2_2>(
+            mComposer = std::make_unique<Composer>(
                 GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
-        ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient_v2_2());
+        ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
 
         mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
         mComposerClient->registerCallback(mComposerCallback);
@@ -75,14 +73,29 @@
         // assume the first display is primary and is never removed
         mPrimaryDisplay = waitForFirstDisplay();
 
+        Config config = mComposerClient->getActiveConfig(mPrimaryDisplay);
+        mDisplayWidth = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
+                                                             IComposerClient::Attribute::WIDTH);
+        mDisplayHeight = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
+                                                              IComposerClient::Attribute::HEIGHT);
+
         // explicitly disable vsync
         mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
         mComposerCallback->setVsyncAllowed(false);
 
         mComposerClient->getRaw()->getReadbackBufferAttributes(
-            mPrimaryDisplay, [&](const auto& tmpError, const auto&, const auto&) {
+            mPrimaryDisplay,
+            [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
                 mHasReadbackBuffer = tmpError == Error::NONE;
+                if (mHasReadbackBuffer) {
+                    mReadbackPixelFormat = tmpPixelFormat;
+                    mReadbackDataspace = tmpDataspace;
+                    ASSERT_LT(static_cast<PixelFormat>(0), mReadbackPixelFormat);
+                    ASSERT_NE(Dataspace::UNKNOWN, mReadbackDataspace);
+                }
             });
+
+        mInvalidDisplayId = GetInvalidDisplayId();
     }
 
     void TearDown() override {
@@ -93,16 +106,39 @@
         }
     }
 
+    // returns an invalid display id (one that has not been registered to a
+    // display.  Currently assuming that a device will never have close to
+    // std::numeric_limit<uint64_t>::max() displays registered while running tests
+    Display GetInvalidDisplayId() {
+        std::vector<Display> validDisplays = mComposerCallback->getDisplays();
+        uint64_t id = std::numeric_limits<uint64_t>::max();
+        while (id > 0) {
+            if (std::find(validDisplays.begin(), validDisplays.end(), id) == validDisplays.end()) {
+                return id;
+            }
+            id--;
+        }
+
+        return 0;
+    }
+
     // use the slot count usually set by SF
     static constexpr uint32_t kBufferSlotCount = 64;
 
-    std::unique_ptr<Composer_v2_2> mComposer;
-    std::unique_ptr<ComposerClient_v2_2> mComposerClient;
+    std::unique_ptr<Composer> mComposer;
+    std::unique_ptr<ComposerClient> mComposerClient;
     sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
     // the first display and is assumed never to be removed
     Display mPrimaryDisplay;
+    int32_t mDisplayWidth;
+    int32_t mDisplayHeight;
+
     bool mHasReadbackBuffer;
 
+    uint64_t mInvalidDisplayId;
+    PixelFormat mReadbackPixelFormat;
+    Dataspace mReadbackDataspace;
+
    private:
     Display waitForFirstDisplay() {
         while (true) {
@@ -125,27 +161,30 @@
 
         ASSERT_NO_FATAL_FAILURE(mGralloc = std::make_unique<Gralloc>());
 
-        mWriter = std::make_unique<V2_2::CommandWriterBase>(1024);
+        mWriter = std::make_unique<CommandWriterBase>(1024);
         mReader = std::make_unique<V2_1::vts::TestCommandReader>();
     }
 
-    void TearDown() override { ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown()); }
+    void TearDown() override {
+        ASSERT_EQ(0, mReader->mErrors.size());
+        ASSERT_NO_FATAL_FAILURE(GraphicsComposerHidlTest::TearDown());
+    }
 
     const native_handle_t* allocate() {
         IMapper::BufferDescriptorInfo info{};
         info.width = 64;
         info.height = 64;
         info.layerCount = 1;
-        info.format = PixelFormat::RGBA_8888;
+        info.format = static_cast<common::V1_0::PixelFormat>(PixelFormat::RGBA_8888);
         info.usage =
             static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
 
         return mGralloc->allocate(info);
     }
 
-    void execute() { mComposerClient->execute_v2_2(mReader.get(), mWriter.get()); }
+    void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
 
-    std::unique_ptr<V2_2::CommandWriterBase> mWriter;
+    std::unique_ptr<CommandWriterBase> mWriter;
     std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
 
    private:
@@ -191,6 +230,16 @@
         {IComposerClient::PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL, 62.0});
     mWriter->setLayerPerFrameMetadata(hidlMetadata);
     execute();
+
+    if (mReader->mErrors.size() == 1 &&
+        static_cast<Error>(mReader->mErrors[0].second) == Error::UNSUPPORTED) {
+        mReader->mErrors.clear();
+        GTEST_SUCCEED() << "SetLayerPerFrameMetadata is not supported";
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->destroyLayer(mPrimaryDisplay, layer));
+        return;
+    }
+
+    ASSERT_NO_FATAL_FAILURE(mComposerClient->destroyLayer(mPrimaryDisplay, layer));
 }
 
 /**
@@ -249,9 +298,35 @@
 }
 
 /**
+ * Test IComposerClient::getClientTargetSupport_2_2
+ *
+ * Test that IComposerClient::getClientTargetSupport_2_2 returns
+ * Error::BAD_DISPLAY when passed in an invalid display handle
+ */
+
+TEST_F(GraphicsComposerHidlTest, GetClientTargetSupport_2_2BadDisplay) {
+    std::vector<Config> configs = mComposerClient->getDisplayConfigs(mPrimaryDisplay);
+    for (auto config : configs) {
+        int32_t width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
+                                                             IComposerClient::Attribute::WIDTH);
+        int32_t height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
+                                                              IComposerClient::Attribute::HEIGHT);
+        ASSERT_LT(0, width);
+        ASSERT_LT(0, height);
+
+        mComposerClient->setActiveConfig(mPrimaryDisplay, config);
+
+        Error error = mComposerClient->getRaw()->getClientTargetSupport_2_2(
+            mInvalidDisplayId, width, height, PixelFormat::RGBA_8888, Dataspace::UNKNOWN);
+
+        EXPECT_EQ(Error::BAD_DISPLAY, error);
+    }
+}
+
+/**
  * Test IComposerClient::setPowerMode_2_2.
  */
-TEST_F(GraphicsComposerHidlTest, setPowerMode_2_2) {
+TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2) {
     std::vector<IComposerClient::PowerMode> modes;
     modes.push_back(IComposerClient::PowerMode::OFF);
     modes.push_back(IComposerClient::PowerMode::ON_SUSPEND);
@@ -262,25 +337,118 @@
     }
 }
 
-TEST_F(GraphicsComposerHidlTest, setReadbackBuffer) {
+/**
+ * Test IComposerClient::setPowerMode_2_2
+ *
+ * Test that IComposerClient::setPowerMode_2_2 succeeds for different varations
+ * of PowerMode
+ */
+TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2Variations) {
+    std::vector<IComposerClient::PowerMode> modes;
+
+    modes.push_back(IComposerClient::PowerMode::OFF);
+    modes.push_back(IComposerClient::PowerMode::OFF);
+
+    for (auto mode : modes) {
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode));
+    }
+
+    modes.clear();
+
+    modes.push_back(IComposerClient::PowerMode::ON);
+    modes.push_back(IComposerClient::PowerMode::ON);
+
+    for (auto mode : modes) {
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode));
+    }
+
+    modes.clear();
+
+    modes.push_back(IComposerClient::PowerMode::ON_SUSPEND);
+    modes.push_back(IComposerClient::PowerMode::ON_SUSPEND);
+
+    for (auto mode : modes) {
+        ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode));
+    }
+
+    if (mComposerClient->getDozeSupport(mPrimaryDisplay)) {
+        modes.clear();
+
+        modes.push_back(IComposerClient::PowerMode::DOZE);
+        modes.push_back(IComposerClient::PowerMode::DOZE);
+
+        for (auto mode : modes) {
+            ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode));
+        }
+
+        modes.clear();
+
+        modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND);
+        modes.push_back(IComposerClient::PowerMode::DOZE_SUSPEND);
+
+        for (auto mode : modes) {
+            ASSERT_NO_FATAL_FAILURE(mComposerClient->setPowerMode_2_2(mPrimaryDisplay, mode));
+        }
+    }
+}
+
+/**
+ * Test IComposerClient::setPowerMode_2_2
+ *
+ * Tests that IComposerClient::setPowerMode_2_2 returns BAD_DISPLAY when passed an
+ * invalid display handle
+ */
+TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2BadDisplay) {
+    Error error = mComposerClient->getRaw()->setPowerMode_2_2(mInvalidDisplayId,
+                                                              IComposerClient::PowerMode::ON);
+    ASSERT_EQ(Error::BAD_DISPLAY, error);
+}
+
+/**
+ * Test IComposerClient::setPowerMode_2_2
+ *
+ * Test that IComposerClient::setPowerMode_2_2 returns BAD_PARAMETER when passed
+ * an invalid PowerMode
+ */
+TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2BadParameter) {
+    Error error = mComposerClient->getRaw()->setPowerMode_2_2(
+        mPrimaryDisplay, static_cast<IComposerClient::PowerMode>(-1));
+    ASSERT_EQ(Error::BAD_PARAMETER, error);
+}
+
+/**
+ * Test IComposerClient::setPowerMode_2_2
+ *
+ * Test that IComposerClient::setPowerMode_2_2 returns UNSUPPORTED when passed
+ * DOZE or DOZE_SUPPORT on a device that does not support these modes
+ */
+TEST_F(GraphicsComposerHidlTest, SetPowerMode_2_2Unsupported) {
+    if (!mComposerClient->getDozeSupport(mPrimaryDisplay)) {
+        Error error = mComposerClient->getRaw()->setPowerMode_2_2(mPrimaryDisplay,
+                                                                  IComposerClient::PowerMode::DOZE);
+        EXPECT_EQ(Error::UNSUPPORTED, error);
+
+        error = mComposerClient->getRaw()->setPowerMode_2_2(
+            mPrimaryDisplay, IComposerClient::PowerMode::DOZE_SUSPEND);
+        EXPECT_EQ(Error::UNSUPPORTED, error);
+    }
+}
+
+/**
+ * Test IComposerClient::setReadbackBuffer
+ *
+ * Test IComposerClient::setReadbackBuffer
+ */
+TEST_F(GraphicsComposerHidlTest, SetReadbackBuffer) {
     if (!mHasReadbackBuffer) {
         return;
     }
 
-    PixelFormat pixelFormat;
-    Dataspace dataspace;
-    mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &pixelFormat, &dataspace);
-    ASSERT_LT(static_cast<PixelFormat>(0), pixelFormat);
-    ASSERT_NE(Dataspace::UNKNOWN, dataspace);
-
     IMapper::BufferDescriptorInfo info{};
-    Config config = mComposerClient->getActiveConfig(mPrimaryDisplay);
-    info.width = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
-                                                      IComposerClient::Attribute::WIDTH);
-    info.height = mComposerClient->getDisplayAttribute(mPrimaryDisplay, config,
-                                                       IComposerClient::Attribute::HEIGHT);
+    info.width = mDisplayWidth;
+    info.height = mDisplayHeight;
     info.layerCount = 1;
-    info.format = pixelFormat;
+    info.format = static_cast<common::V1_0::PixelFormat>(mReadbackPixelFormat);
     // BufferUsage::COMPOSER_OUTPUT is missing
     info.usage = static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);
 
@@ -292,7 +460,49 @@
     mComposerClient->setReadbackBuffer(mPrimaryDisplay, buffer, -1);
 }
 
-TEST_F(GraphicsComposerHidlTest, getReadbackBufferFenceInactive) {
+/**
+ * Test IComposerClient::setReadbackBuffer
+ *
+ * Test that IComposerClient::setReadbackBuffer returns an Error::BAD_DISPLAY
+ * when passed an invalid display handle
+ */
+TEST_F(GraphicsComposerHidlTest, SetReadbackBufferBadDisplay) {
+    if (!mHasReadbackBuffer) {
+        return;
+    }
+
+    IMapper::BufferDescriptorInfo info{};
+    info.width = mDisplayWidth;
+    info.height = mDisplayHeight;
+    info.layerCount = 1;
+    info.format = static_cast<common::V1_0::PixelFormat>(mReadbackPixelFormat);
+    info.usage = static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);
+
+    std::unique_ptr<Gralloc> gralloc;
+    const native_handle_t* buffer;
+    ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique<Gralloc>());
+    ASSERT_NO_FATAL_FAILURE(buffer = gralloc->allocate(info));
+
+    Error error = mComposerClient->getRaw()->setReadbackBuffer(mInvalidDisplayId, buffer, nullptr);
+    ASSERT_EQ(Error::BAD_DISPLAY, error);
+}
+
+/**
+ * Test IComposerClient::setReadbackBuffer
+ *
+ * Test that IComposerClient::setReadbackBuffer returns Error::BAD_PARAMETER
+ * when passed an invalid buffer handle
+ */
+TEST_F(GraphicsComposerHidlTest, SetReadbackBufferBadParameter) {
+    if (!mHasReadbackBuffer) {
+        return;
+    }
+
+    Error error = mComposerClient->getRaw()->setReadbackBuffer(mPrimaryDisplay, nullptr, nullptr);
+    ASSERT_EQ(Error::BAD_PARAMETER, error);
+}
+
+TEST_F(GraphicsComposerHidlTest, GetReadbackBufferFenceInactive) {
     if (!mHasReadbackBuffer) {
         return;
     }
@@ -313,14 +523,38 @@
 
     mWriter->selectDisplay(mPrimaryDisplay);
     mWriter->selectLayer(layer);
+    mWriter->setLayerCompositionType(IComposerClient::Composition::SOLID_COLOR);
     mWriter->setLayerFloatColor(IComposerClient::FloatColor{1.0, 1.0, 1.0, 1.0});
     mWriter->setLayerFloatColor(IComposerClient::FloatColor{0.0, 0.0, 0.0, 0.0});
+    execute();
+
+    if (mReader->mErrors.size() == 2 &&
+        static_cast<Error>(mReader->mErrors[0].second) == Error::UNSUPPORTED &&
+        static_cast<Error>(mReader->mErrors[1].second) == Error::UNSUPPORTED) {
+        mReader->mErrors.clear();
+        GTEST_SUCCEED() << "SetLayerFloatColor is not supported";
+        return;
+    }
+
+    // ensure setting float color on layer with composition type that is not
+    // SOLID_COLOR does not fail
+    V2_1::Layer clientLayer;
+    ASSERT_NO_FATAL_FAILURE(clientLayer =
+                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->selectLayer(clientLayer);
+    mWriter->setLayerCompositionType(IComposerClient::Composition::CLIENT);
+    mWriter->setLayerFloatColor(IComposerClient::FloatColor{1.0, 1.0, 1.0, 1.0});
+    execute();
+
+    // At this point we know that this function is supported so there should be
+    // no errors (checked upon TearDown)
 }
 
 /**
  * Test IComposerClient::getDataspaceSaturationMatrix.
  */
-TEST_F(GraphicsComposerHidlTest, getDataspaceSaturationMatrix) {
+TEST_F(GraphicsComposerHidlTest, GetDataspaceSaturationMatrix) {
     auto matrix = mComposerClient->getDataspaceSaturationMatrix(Dataspace::SRGB_LINEAR);
     // the last row is known
     ASSERT_EQ(0.0f, matrix[12]);
@@ -329,6 +563,19 @@
     ASSERT_EQ(1.0f, matrix[15]);
 }
 
+/*
+ * Test IComposerClient::getDataspaceSaturationMatrix
+ *
+ * Test that IComposerClient::getDataspaceSaturationMatrix returns
+ * Error::BAD_PARAMETER when passed a dataspace other than
+ * Dataspace::SRGB_LINEAR
+ */
+TEST_F(GraphicsComposerHidlTest, GetDataspaceSaturationMatrixBadParameter) {
+    mComposerClient->getRaw()->getDataspaceSaturationMatrix(
+        Dataspace::UNKNOWN,
+        [&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_PARAMETER, tmpError); });
+}
+
 /**
  * Test IComposerClient::getColorMode_2_2.
  */
@@ -339,10 +586,22 @@
     EXPECT_NE(modes.cend(), nativeMode);
 }
 
-/**
- * Test IComposerClient::getRenderIntent.
+/*
+ * Test IComposerClient::getColorMode_2_2
+ *
+ * Test that IComposerClient::getColorMode returns Error::BAD_DISPLAY when
+ * passed an invalid display handle
  */
-TEST_F(GraphicsComposerHidlTest, GetRenderIntent) {
+TEST_F(GraphicsComposerHidlTest, GetColorMode_2_2BadDisplay) {
+    mComposerClient->getRaw()->getColorModes_2_2(
+        mInvalidDisplayId,
+        [&](const auto& tmpError, const auto&) { ASSERT_EQ(Error::BAD_DISPLAY, tmpError); });
+}
+
+/**
+ * Test IComposerClient::getRenderIntents.
+ */
+TEST_F(GraphicsComposerHidlTest, GetRenderIntents) {
     std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
     for (auto mode : modes) {
         std::vector<RenderIntent> intents =
@@ -366,6 +625,33 @@
     }
 }
 
+/*
+ * Test IComposerClient::getRenderIntents
+ *
+ * Test that IComposerClient::getRenderIntent returns Error::BAD_DISPLAY when
+ * passed an invalid display handle
+ */
+TEST_F(GraphicsComposerHidlTest, GetRenderIntentsBadDisplay) {
+    std::vector<ColorMode> modes = mComposerClient->getColorModes(mPrimaryDisplay);
+    for (auto mode : modes) {
+        mComposerClient->getRaw()->getRenderIntents(
+            mInvalidDisplayId, mode,
+            [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_DISPLAY, tmpError); });
+    }
+}
+
+/*
+ * Test IComposerClient::getRenderIntents
+ *
+ * Test that IComposerClient::getRenderIntents returns Error::BAD_PARAMETER when
+ * pased either an invalid Color mode or an invalid Render Intent
+ */
+TEST_F(GraphicsComposerHidlTest, GetRenderIntentsBadParameter) {
+    mComposerClient->getRaw()->getRenderIntents(
+        mPrimaryDisplay, static_cast<ColorMode>(-1),
+        [&](const auto& tmpError, const auto&) { EXPECT_EQ(Error::BAD_PARAMETER, tmpError); });
+}
+
 /**
  * Test IComposerClient::setColorMode_2_2.
  */
@@ -378,6 +664,37 @@
             mComposerClient->setColorMode(mPrimaryDisplay, mode, intent);
         }
     }
+
+    mComposerClient->setColorMode(mPrimaryDisplay, ColorMode::NATIVE, RenderIntent::COLORIMETRIC);
+}
+
+/*
+ * Test IComposerClient::setColorMode_2_2
+ *
+ * Test that IComposerClient::setColorMode_2_2 returns an Error::BAD_DISPLAY
+ * when passed an invalid display handle
+ */
+TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2BadDisplay) {
+    Error error = mComposerClient->getRaw()->setColorMode_2_2(mInvalidDisplayId, ColorMode::NATIVE,
+                                                              RenderIntent::COLORIMETRIC);
+
+    ASSERT_EQ(Error::BAD_DISPLAY, error);
+}
+
+/*
+ * Test IComposerClient::setColorMode_2_2
+ *
+ * Test that IComposerClient::setColorMode_2_2 returns Error::BAD_PARAMETER when
+ * passed an invalid Color mode or an invalid render intent
+ */
+TEST_F(GraphicsComposerHidlTest, SetColorMode_2_2BadParameter) {
+    Error colorModeError = mComposerClient->getRaw()->setColorMode_2_2(
+        mPrimaryDisplay, static_cast<ColorMode>(-1), RenderIntent::COLORIMETRIC);
+    EXPECT_EQ(Error::BAD_PARAMETER, colorModeError);
+
+    Error renderIntentError = mComposerClient->getRaw()->setColorMode_2_2(
+        mPrimaryDisplay, ColorMode::NATIVE, static_cast<RenderIntent>(-1));
+    EXPECT_EQ(Error::BAD_PARAMETER, renderIntentError);
 }
 
 }  // namespace
diff --git a/graphics/composer/2.3/Android.bp b/graphics/composer/2.3/Android.bp
new file mode 100644
index 0000000..78da099
--- /dev/null
+++ b/graphics/composer/2.3/Android.bp
@@ -0,0 +1,22 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.graphics.composer@2.3",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IComposer.hal",
+        "IComposerClient.hal",
+    ],
+    interfaces: [
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
+
diff --git a/graphics/composer/2.3/IComposer.hal b/graphics/composer/2.3/IComposer.hal
new file mode 100644
index 0000000..90b2427
--- /dev/null
+++ b/graphics/composer/2.3/IComposer.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer@2.3;
+
+import IComposerClient;
+
+import @2.1::Error;
+import @2.2::IComposer;
+
+interface IComposer extends @2.2::IComposer {
+
+    /**
+     * Creates a v2.3 client of the composer. Supersedes @2.1::createClient.
+     *
+     * @return error is NONE upon success. Otherwise,
+     *         NO_RESOURCES when the client could not be created.
+     * @return client is the newly created client.
+     */
+    @entry
+    @callflow(next="*")
+    createClient_2_3() generates (Error error, IComposerClient client);
+
+};
diff --git a/graphics/composer/2.3/IComposerClient.hal b/graphics/composer/2.3/IComposerClient.hal
new file mode 100644
index 0000000..089438e
--- /dev/null
+++ b/graphics/composer/2.3/IComposerClient.hal
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer@2.3;
+
+import android.hardware.graphics.composer@2.1::IComposerClient.Command;
+import @2.2::IComposerClient;
+import @2.1::Display;
+import @2.1::Error;
+
+interface IComposerClient extends @2.2::IComposerClient {
+
+    enum Command : @2.2::IComposerClient.Command {
+        /**
+         * SET_LAYER_COLOR_TRANSFORM has this pseudo prototype
+         *
+         *   setLayerColorTransform(float[16] matrix);
+         *
+         * This command has the following binary layout in bytes:
+         *
+         *     0 - 16 * 4: matrix
+         *
+         * Sets a matrix for color transform which will be applied on this layer
+         * before composition.
+         *
+         * If the device is not capable of apply the matrix on this layer, it must force
+         * this layer to client composition during VALIDATE_DISPLAY.
+         *
+         * The matrix provided is an affine color transformation of the following
+         * form:
+         *
+         * |r.r r.g r.b 0|
+         * |g.r g.g g.b 0|
+         * |b.r b.g b.b 0|
+         * |Tr  Tg  Tb  1|
+         *
+         * This matrix must be provided in row-major form:
+         *
+         * {r.r, r.g, r.b, 0, g.r, ...}.
+         *
+         * Given a matrix of this form and an input color [R_in, G_in, B_in],
+         * the input color must first be converted to linear space
+         * [R_linear, G_linear, B_linear], then the output linear color
+         * [R_out_linear, G_out_linear, B_out_linear] will be:
+         *
+         * R_out_linear = R_linear * r.r + G_linear * g.r + B_linear * b.r + Tr
+         * G_out_linear = R_linear * r.g + G_linear * g.g + B_linear * b.g + Tg
+         * B_out_linear = R_linear * r.b + G_linear * g.b + B_linear * b.b + Tb
+         *
+         * [R_out_linear, G_out_linear, B_out_linear] must then be converted to
+         * gamma space: [R_out, G_out, B_out] before blending.
+         *
+         * @param matrix is a 4x4 transform matrix (16 floats) as described above.
+         */
+        SET_LAYER_COLOR_TRANSFORM = 0x40d << @2.1::IComposerClient.Command:OPCODE_SHIFT,
+    };
+
+    /**
+     * Returns the port and data that describe a physical display. The port is
+     * a unique number that identifies a physical connector (e.g. eDP, HDMI)
+     * for display output. The data blob is parsed to determine its format,
+     * typically EDID 1.3 as specified in VESA E-EDID Standard Release A
+     * Revision 1.
+     *
+     * @param display is the display to query.
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_DISPLAY when an invalid display handle was passed in.
+     *         UNSUPPORTED when identification data is unavailable.
+     * @return port is the connector to which the display is connected.
+     * @return data is the EDID 1.3 blob identifying the display.
+     */
+    @callflow(next="*")
+    getDisplayIdentificationData(Display display)
+               generates (Error error,
+                          uint8_t port,
+                          vec<uint8_t> data);
+
+    /**
+     * Executes commands from the input command message queue. Return values
+     * generated by the input commands are written to the output command
+     * message queue in the form of value commands.
+     *
+     * @param inLength is the length of input commands.
+     * @param inHandles is an array of handles referenced by the input
+     *        commands.
+     * @return error is NONE upon success. Otherwise,
+     *         BAD_PARAMETER when inLength is not equal to the length of
+     *                       commands in the input command message queue.
+     *         NO_RESOURCES when the output command message queue was not
+     *                      properly drained.
+     * @param outQueueChanged indicates whether the output command message
+     *        queue has changed.
+     * @param outLength is the length of output commands.
+     * @param outHandles is an array of handles referenced by the output
+     *        commands.
+     */
+    executeCommands_2_3(uint32_t inLength,
+                        vec<handle> inHandles)
+             generates (Error error,
+                        bool outQueueChanged,
+                        uint32_t outLength,
+                        vec<handle> outHandles);
+};
diff --git a/graphics/composer/2.3/default/Android.bp b/graphics/composer/2.3/default/Android.bp
new file mode 100644
index 0000000..ad49ec3
--- /dev/null
+++ b/graphics/composer/2.3/default/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_binary {
+    name: "android.hardware.graphics.composer@2.3-service",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: ["service.cpp"],
+    init_rc: ["android.hardware.graphics.composer@2.3-service.rc"],
+    header_libs: [
+        "android.hardware.graphics.composer@2.3-passthrough",
+    ],
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.3",
+        "android.hardware.graphics.mapper@2.0",
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libfmq",
+        "libhardware",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwc2on1adapter",
+        "libhwc2onfbadapter",
+        "liblog",
+        "libsync",
+        "libutils",
+    ],
+}
diff --git a/graphics/composer/2.3/default/OWNERS b/graphics/composer/2.3/default/OWNERS
new file mode 100644
index 0000000..3aa5fa1
--- /dev/null
+++ b/graphics/composer/2.3/default/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+jessehall@google.com
+olv@google.com
+stoza@google.com
diff --git a/graphics/composer/2.3/default/android.hardware.graphics.composer@2.3-service.rc b/graphics/composer/2.3/default/android.hardware.graphics.composer@2.3-service.rc
new file mode 100644
index 0000000..08e32d8
--- /dev/null
+++ b/graphics/composer/2.3/default/android.hardware.graphics.composer@2.3-service.rc
@@ -0,0 +1,6 @@
+service vendor.hwcomposer-2-3 /vendor/bin/hw/android.hardware.graphics.composer@2.3-service
+    class hal animation
+    user system
+    group graphics drmrpc
+    capabilities SYS_NICE
+    onrestart restart surfaceflinger
diff --git a/graphics/composer/2.3/default/service.cpp b/graphics/composer/2.3/default/service.cpp
new file mode 100644
index 0000000..347d8be
--- /dev/null
+++ b/graphics/composer/2.3/default/service.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sched.h>
+
+#include <android/hardware/graphics/composer/2.3/IComposer.h>
+#include <binder/ProcessState.h>
+#include <composer-passthrough/2.3/HwcLoader.h>
+#include <hidl/HidlTransportSupport.h>
+
+using android::hardware::graphics::composer::V2_3::IComposer;
+using android::hardware::graphics::composer::V2_3::passthrough::HwcLoader;
+
+int main() {
+    // the conventional HAL might start binder services
+    android::ProcessState::initWithDriver("/dev/vndbinder");
+    android::ProcessState::self()->setThreadPoolMaxThreadCount(4);
+    android::ProcessState::self()->startThreadPool();
+
+    // same as SF main thread
+    struct sched_param param = {0};
+    param.sched_priority = 2;
+    if (sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK, &param) != 0) {
+        ALOGE("Couldn't set SCHED_FIFO: %d", errno);
+    }
+
+    android::hardware::configureRpcThreadpool(4, true /* will join */);
+
+    android::sp<IComposer> composer = HwcLoader::load();
+    if (composer == nullptr) {
+        return 1;
+    }
+    if (composer->registerAsService() != android::NO_ERROR) {
+        ALOGE("failed to register service");
+        return 1;
+    }
+
+    android::hardware::joinRpcThreadpool();
+
+    ALOGE("service is terminating");
+    return 1;
+}
diff --git a/graphics/composer/2.3/utils/OWNERS b/graphics/composer/2.3/utils/OWNERS
new file mode 100644
index 0000000..234bc75
--- /dev/null
+++ b/graphics/composer/2.3/utils/OWNERS
@@ -0,0 +1,7 @@
+# Graphics team
+olv@google.com
+stoza@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/graphics/composer/2.3/utils/command-buffer/Android.bp b/graphics/composer/2.3/utils/command-buffer/Android.bp
new file mode 100644
index 0000000..c48fe7a
--- /dev/null
+++ b/graphics/composer/2.3/utils/command-buffer/Android.bp
@@ -0,0 +1,15 @@
+cc_library_headers {
+    name: "android.hardware.graphics.composer@2.3-command-buffer",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.3",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
new file mode 100644
index 0000000..3f7b2c9
--- /dev/null
+++ b/graphics/composer/2.3/utils/command-buffer/include/composer-command-buffer/2.3/ComposerCommandBuffer.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warn "ComposerCommandBuffer.h included without LOG_TAG"
+#endif
+
+#undef LOG_NDEBUG
+#define LOG_NDEBUG 0
+
+#include <android/hardware/graphics/composer/2.3/IComposer.h>
+#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
+#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+
+using android::hardware::MessageQueue;
+using android::hardware::graphics::composer::V2_1::Error;
+using android::hardware::graphics::composer::V2_1::IComposerCallback;
+using android::hardware::graphics::composer::V2_1::Layer;
+using android::hardware::graphics::composer::V2_3::IComposerClient;
+
+// This class helps build a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandWriterBase : public V2_2::CommandWriterBase {
+   public:
+    CommandWriterBase(uint32_t initialMaxSize) : V2_2::CommandWriterBase(initialMaxSize) {}
+
+    static constexpr uint16_t kSetLayerColorTransformLength = 16;
+    void setLayerColorTransform(const float* matrix) {
+        beginCommand_2_3(IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM,
+                         kSetLayerColorTransformLength);
+        for (int i = 0; i < 16; i++) {
+            writeFloat(matrix[i]);
+        }
+        endCommand();
+    }
+
+   protected:
+    void beginCommand_2_3(IComposerClient::Command command, uint16_t length) {
+        V2_2::CommandWriterBase::beginCommand_2_2(
+            static_cast<V2_2::IComposerClient::Command>(static_cast<int32_t>(command)), length);
+    }
+};
+
+// This class helps parse a command queue.  Note that all sizes/lengths are in
+// units of uint32_t's.
+class CommandReaderBase : public V2_2::CommandReaderBase {
+   public:
+    CommandReaderBase() : V2_2::CommandReaderBase(){};
+};
+
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/utils/hal/Android.bp b/graphics/composer/2.3/utils/hal/Android.bp
new file mode 100644
index 0000000..3ee9300
--- /dev/null
+++ b/graphics/composer/2.3/utils/hal/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_headers {
+    name: "android.hardware.graphics.composer@2.3-hal",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    shared_libs: [
+        "android.hardware.graphics.composer@2.3",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.composer@2.3",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.2-hal",
+        "android.hardware.graphics.composer@2.3-command-buffer",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.composer@2.2-hal",
+        "android.hardware.graphics.composer@2.3-command-buffer",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/Composer.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/Composer.h
new file mode 100644
index 0000000..8e11a5a
--- /dev/null
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/Composer.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "Composer.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.3/IComposer.h>
+#include <composer-hal/2.2/Composer.h>
+#include <composer-hal/2.3/ComposerClient.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace hal {
+
+namespace detail {
+
+// ComposerImpl implements V2_*::IComposer on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerImpl : public V2_2::hal::detail::ComposerImpl<Interface, Hal> {
+   public:
+    static std::unique_ptr<ComposerImpl> create(std::unique_ptr<Hal> hal) {
+        return std::make_unique<ComposerImpl>(std::move(hal));
+    }
+
+    explicit ComposerImpl(std::unique_ptr<Hal> hal) : BaseType2_2(std::move(hal)) {}
+
+    // IComposer 2.3 interface
+
+    Return<void> createClient_2_3(IComposer::createClient_2_3_cb hidl_cb) override {
+        std::unique_lock<std::mutex> lock(mClientMutex);
+        if (!waitForClientDestroyedLocked(lock)) {
+            hidl_cb(Error::NO_RESOURCES, nullptr);
+            return Void();
+        }
+
+        sp<ComposerClient> client = ComposerClient::create(mHal.get()).release();
+        if (!client) {
+            hidl_cb(Error::NO_RESOURCES, nullptr);
+            return Void();
+        }
+
+        auto clientDestroyed = [this]() { onClientDestroyed(); };
+        client->setOnClientDestroyed(clientDestroyed);
+
+        mClient = client;
+        hidl_cb(Error::NONE, client);
+        return Void();
+    }
+
+   private:
+    using BaseType2_2 = V2_2::hal::detail::ComposerImpl<Interface, Hal>;
+    using BaseType2_1 = V2_1::hal::detail::ComposerImpl<Interface, Hal>;
+
+    using BaseType2_1::mClient;
+    using BaseType2_1::mClientMutex;
+    using BaseType2_1::mHal;
+    using BaseType2_1::onClientDestroyed;
+    using BaseType2_1::waitForClientDestroyedLocked;
+};
+
+}  // namespace detail
+
+using Composer = detail::ComposerImpl<IComposer, ComposerHal>;
+
+}  // namespace hal
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
new file mode 100644
index 0000000..c805472
--- /dev/null
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerClient.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerClient.h included without LOG_TAG"
+#endif
+
+#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
+#include <composer-hal/2.3/ComposerClient.h>
+#include <composer-hal/2.3/ComposerCommandEngine.h>
+#include <composer-hal/2.3/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace hal {
+
+namespace detail {
+
+// ComposerClientImpl implements V2_*::IComposerClient on top of V2_*::ComposerHal
+template <typename Interface, typename Hal>
+class ComposerClientImpl : public V2_2::hal::detail::ComposerClientImpl<Interface, Hal> {
+   public:
+    static std::unique_ptr<ComposerClientImpl> create(Hal* hal) {
+        auto client = std::make_unique<ComposerClientImpl>(hal);
+        return client->init() ? std::move(client) : nullptr;
+    }
+
+    ComposerClientImpl(Hal* hal) : BaseType2_2(hal) {}
+
+    // IComposerClient 2.3 interface
+
+    Return<void> getDisplayIdentificationData(
+        Display display, IComposerClient::getDisplayIdentificationData_cb hidl_cb) override {
+        uint8_t port = 0;
+        std::vector<uint8_t> data;
+        Error error = mHal->getDisplayIdentificationData(display, &port, &data);
+        hidl_cb(error, port, data);
+        return Void();
+    }
+
+    Return<void> executeCommands_2_3(uint32_t inLength, const hidl_vec<hidl_handle>& inHandles,
+                                     IComposerClient::executeCommands_2_2_cb hidl_cb) override {
+        std::lock_guard<std::mutex> lock(mCommandEngineMutex);
+        bool outChanged = false;
+        uint32_t outLength = 0;
+        hidl_vec<hidl_handle> outHandles;
+        Error error =
+            mCommandEngine->execute(inLength, inHandles, &outChanged, &outLength, &outHandles);
+
+        hidl_cb(error, outChanged, outLength, outHandles);
+
+        mCommandEngine->reset();
+
+        return Void();
+    }
+
+   private:
+    using BaseType2_2 = V2_2::hal::detail::ComposerClientImpl<Interface, Hal>;
+    using BaseType2_1 = V2_1::hal::detail::ComposerClientImpl<Interface, Hal>;
+    using BaseType2_1::mCommandEngine;
+    using BaseType2_1::mCommandEngineMutex;
+    using BaseType2_1::mHal;
+};
+
+}  // namespace detail
+
+using ComposerClient = detail::ComposerClientImpl<IComposerClient, ComposerHal>;
+
+}  // namespace hal
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
new file mode 100644
index 0000000..c3dcbcd
--- /dev/null
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerCommandEngine.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "ComposerCommandEngine.h included without LOG_TAG"
+#endif
+
+#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
+#include <composer-hal/2.1/ComposerCommandEngine.h>
+#include <composer-hal/2.2/ComposerCommandEngine.h>
+#include <composer-hal/2.2/ComposerResources.h>
+#include <composer-hal/2.3/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace hal {
+
+class ComposerCommandEngine : public V2_2::hal::ComposerCommandEngine {
+   public:
+    ComposerCommandEngine(ComposerHal* hal, V2_2::hal::ComposerResources* resources)
+        : BaseType2_2(hal, resources), mHal(hal) {}
+
+   protected:
+    bool executeCommand(V2_1::IComposerClient::Command command, uint16_t length) override {
+        switch (static_cast<IComposerClient::Command>(command)) {
+            case IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM:
+                return executeSetLayerColorTransform(length);
+            default:
+                return BaseType2_2::executeCommand(command, length);
+        }
+    }
+
+    bool executeSetLayerColorTransform(uint16_t length) {
+        if (length != CommandWriterBase::kSetLayerColorTransformLength) {
+            return false;
+        }
+
+        float matrix[16];
+        for (int i = 0; i < 16; i++) {
+            matrix[i] = readFloat();
+        }
+        auto err = mHal->setLayerColorTransform(mCurrentDisplay, mCurrentLayer, matrix);
+        if (err != Error::NONE) {
+            mWriter.setError(getCommandLoc(), err);
+        }
+
+        return true;
+    }
+
+   private:
+    using BaseType2_1 = V2_1::hal::ComposerCommandEngine;
+    using BaseType2_1::mWriter;
+    using BaseType2_2 = V2_2::hal::ComposerCommandEngine;
+
+    ComposerHal* mHal;
+};
+
+}  // namespace hal
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
new file mode 100644
index 0000000..0f6205a
--- /dev/null
+++ b/graphics/composer/2.3/utils/hal/include/composer-hal/2.3/ComposerHal.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <composer-hal/2.2/ComposerHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace hal {
+
+using V2_1::Display;
+using V2_1::Error;
+using V2_1::Layer;
+
+class ComposerHal : public V2_2::hal::ComposerHal {
+   public:
+    virtual Error getDisplayIdentificationData(Display display, uint8_t* outPort,
+                                               std::vector<uint8_t>* outData) = 0;
+    virtual Error setLayerColorTransform(Display display, Layer layer, const float* matrix) = 0;
+};
+
+}  // namespace hal
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/utils/passthrough/Android.bp b/graphics/composer/2.3/utils/passthrough/Android.bp
new file mode 100644
index 0000000..3ae6b16
--- /dev/null
+++ b/graphics/composer/2.3/utils/passthrough/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_headers {
+    name: "android.hardware.graphics.composer@2.3-passthrough",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    header_libs: [
+        "android.hardware.graphics.composer@2.2-passthrough",
+        "android.hardware.graphics.composer@2.3-hal",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.composer@2.2-passthrough",
+        "android.hardware.graphics.composer@2.3-hal",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
new file mode 100644
index 0000000..ed1878b
--- /dev/null
+++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcHal.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcHal.h included without LOG_TAG"
+#endif
+
+#include <type_traits>
+
+#include <composer-hal/2.3/ComposerHal.h>
+#include <composer-passthrough/2.2/HwcHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace passthrough {
+
+namespace detail {
+
+using V2_1::Display;
+using V2_1::Error;
+
+// HwcHalImpl implements V2_*::hal::ComposerHal on top of hwcomposer2
+template <typename Hal>
+class HwcHalImpl : public V2_2::passthrough::detail::HwcHalImpl<Hal> {
+   public:
+    Error getDisplayIdentificationData(Display display, uint8_t* outPort,
+                                       std::vector<uint8_t>* outData) override {
+        if (!mDispatch.getDisplayIdentificationData) {
+            return Error::UNSUPPORTED;
+        }
+
+        uint32_t size = 0;
+        int32_t error =
+            mDispatch.getDisplayIdentificationData(mDevice, display, outPort, &size, nullptr);
+        if (error != HWC2_ERROR_NONE) {
+            return static_cast<Error>(error);
+        }
+
+        std::vector<uint8_t> data(size);
+        error =
+            mDispatch.getDisplayIdentificationData(mDevice, display, outPort, &size, data.data());
+        if (error != HWC2_ERROR_NONE) {
+            return static_cast<Error>(error);
+        }
+
+        data.resize(size);
+        *outData = std::move(data);
+        return Error::NONE;
+    }
+
+    Error setLayerColorTransform(Display display, Layer layer, const float* matrix) override {
+        if (!mDispatch.setLayerColorTransform) {
+            return Error::UNSUPPORTED;
+        }
+        int32_t err = mDispatch.setLayerColorTransform(mDevice, display, layer, matrix);
+        return static_cast<Error>(err);
+    }
+
+   protected:
+    bool initDispatch() override {
+        if (!BaseType2_2::initDispatch()) {
+            return false;
+        }
+
+        this->initOptionalDispatch(HWC2_FUNCTION_GET_DISPLAY_IDENTIFICATION_DATA,
+                                   &mDispatch.getDisplayIdentificationData);
+        this->initOptionalDispatch(HWC2_FUNCTION_SET_LAYER_COLOR_TRANSFORM,
+                                   &mDispatch.setLayerColorTransform);
+        return true;
+    }
+
+   private:
+    struct {
+        HWC2_PFN_GET_DISPLAY_IDENTIFICATION_DATA getDisplayIdentificationData;
+        HWC2_PFN_SET_LAYER_COLOR_TRANSFORM setLayerColorTransform;
+    } mDispatch = {};
+
+    using BaseType2_2 = V2_2::passthrough::detail::HwcHalImpl<Hal>;
+    using BaseType2_1 = V2_1::passthrough::detail::HwcHalImpl<Hal>;
+    using BaseType2_1::mDevice;
+};
+
+}  // namespace detail
+
+using HwcHal = detail::HwcHalImpl<hal::ComposerHal>;
+
+}  // namespace passthrough
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcLoader.h b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcLoader.h
new file mode 100644
index 0000000..afef475
--- /dev/null
+++ b/graphics/composer/2.3/utils/passthrough/include/composer-passthrough/2.3/HwcLoader.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#ifndef LOG_TAG
+#warning "HwcLoader.h included without LOG_TAG"
+#endif
+
+#include <composer-hal/2.3/Composer.h>
+#include <composer-hal/2.3/ComposerHal.h>
+#include <composer-passthrough/2.2/HwcLoader.h>
+#include <composer-passthrough/2.3/HwcHal.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace passthrough {
+
+class HwcLoader : public V2_2::passthrough::HwcLoader {
+   public:
+    static IComposer* load() {
+        const hw_module_t* module = loadModule();
+        if (!module) {
+            return nullptr;
+        }
+
+        auto hal = createHalWithAdapter(module);
+        if (!hal) {
+            return nullptr;
+        }
+
+        return createComposer(std::move(hal)).release();
+    }
+
+    // create a ComposerHal instance
+    static std::unique_ptr<hal::ComposerHal> createHal(const hw_module_t* module) {
+        auto hal = std::make_unique<HwcHal>();
+        return hal->initWithModule(module) ? std::move(hal) : nullptr;
+    }
+
+    // create a ComposerHal instance, insert an adapter if necessary
+    static std::unique_ptr<hal::ComposerHal> createHalWithAdapter(const hw_module_t* module) {
+        bool adapted;
+        hwc2_device_t* device = openDeviceWithAdapter(module, &adapted);
+        if (!device) {
+            return nullptr;
+        }
+        auto hal = std::make_unique<HwcHal>();
+        return hal->initWithDevice(std::move(device), !adapted) ? std::move(hal) : nullptr;
+    }
+
+    // create an IComposer instance
+    static std::unique_ptr<IComposer> createComposer(std::unique_ptr<hal::ComposerHal> hal) {
+        return hal::Composer::create(std::move(hal));
+    }
+};
+
+}  // namespace passthrough
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/utils/vts/Android.bp b/graphics/composer/2.3/utils/vts/Android.bp
new file mode 100644
index 0000000..19438cb
--- /dev/null
+++ b/graphics/composer/2.3/utils/vts/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "android.hardware.graphics.composer@2.3-vts",
+    defaults: ["hidl_defaults"],
+    srcs: [
+        "ComposerVts.cpp",
+    ],
+    static_libs: [
+        "VtsHalHidlTargetTestBase",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.1-vts",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.2-vts",
+        "android.hardware.graphics.composer@2.3",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+        "android.hardware.graphics.composer@2.3-command-buffer",
+    ],
+    cflags: [
+        "-O0",
+        "-g",
+        "-DLOG_TAG=\"ComposerVts\"",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/composer/2.3/utils/vts/ComposerVts.cpp b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
new file mode 100644
index 0000000..f1d3a50
--- /dev/null
+++ b/graphics/composer/2.3/utils/vts/ComposerVts.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <composer-vts/2.3/ComposerVts.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace vts {
+
+using V2_1::Error;
+
+Composer::Composer() : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>()) {}
+
+Composer::Composer(const std::string& name)
+    : Composer(::testing::VtsHalHidlTargetTestBase::getService<IComposer>(name)) {}
+
+Composer::Composer(const sp<IComposer>& composer)
+    : V2_2::vts::Composer(composer), mComposer(composer) {}
+
+std::unique_ptr<ComposerClient> Composer::createClient() {
+    std::unique_ptr<ComposerClient> client;
+    mComposer->createClient_2_3([&client](const auto& tmpError, const auto& tmpClient) {
+        ASSERT_EQ(Error::NONE, tmpError) << "failed to create client";
+        client = std::make_unique<ComposerClient>(tmpClient);
+    });
+
+    return client;
+}
+
+bool ComposerClient::getDisplayIdentificationData(Display display, uint8_t* outPort,
+                                                  std::vector<uint8_t>* outData) {
+    bool supported = true;
+    mClient->getDisplayIdentificationData(
+        display, [&](const auto& tmpError, const auto& tmpPort, const auto& tmpData) {
+            if (tmpError == Error::UNSUPPORTED) {
+                supported = false;
+                return;
+            }
+            ASSERT_EQ(Error::NONE, tmpError) << "failed to get display identification data";
+
+            *outPort = tmpPort;
+            *outData = tmpData;
+            ASSERT_FALSE(outData->empty()) << "data is empty";
+        });
+
+    return supported;
+}
+
+}  // namespace vts
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
new file mode 100644
index 0000000..103b85a
--- /dev/null
+++ b/graphics/composer/2.3/utils/vts/include/composer-vts/2.3/ComposerVts.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/graphics/composer/2.3/IComposer.h>
+#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
+#include <composer-vts/2.2/ComposerVts.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace vts {
+
+using V2_1::Display;
+using V2_3::IComposer;
+using V2_3::IComposerClient;
+
+class ComposerClient;
+
+// A wrapper to IComposer.
+class Composer : public V2_2::vts::Composer {
+   public:
+    Composer();
+    explicit Composer(const std::string& name);
+
+    std::unique_ptr<ComposerClient> createClient();
+
+   protected:
+    explicit Composer(const sp<IComposer>& composer);
+
+   private:
+    const sp<IComposer> mComposer;
+};
+
+// A wrapper to IComposerClient.
+class ComposerClient : public V2_2::vts::ComposerClient {
+   public:
+    explicit ComposerClient(const sp<IComposerClient>& client)
+        : V2_2::vts::ComposerClient(client), mClient(client) {}
+
+    bool getDisplayIdentificationData(Display display, uint8_t* outPort,
+                                      std::vector<uint8_t>* outData);
+
+   private:
+    const sp<IComposerClient> mClient;
+};
+
+}  // namespace vts
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.3/vts/functional/Android.bp b/graphics/composer/2.3/vts/functional/Android.bp
new file mode 100644
index 0000000..7548cb5
--- /dev/null
+++ b/graphics/composer/2.3/vts/functional/Android.bp
@@ -0,0 +1,45 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalGraphicsComposerV2_3TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalGraphicsComposerV2_3TargetTest.cpp"],
+
+    // TODO(b/64437680): Assume these libs are always available on the device.
+    shared_libs: [
+        "libfmq",
+        "libhidltransport",
+        "libsync",
+    ],
+    static_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.1-vts",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.2-vts",
+        "android.hardware.graphics.composer@2.3",
+        "android.hardware.graphics.composer@2.3-vts",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.0-vts",
+        "android.hardware.graphics.mapper@2.1",
+    ],
+    header_libs: [
+        "android.hardware.graphics.composer@2.1-command-buffer",
+        "android.hardware.graphics.composer@2.2-command-buffer",
+        "android.hardware.graphics.composer@2.3-command-buffer",
+    ],
+}
diff --git a/graphics/composer/2.3/vts/functional/OWNERS b/graphics/composer/2.3/vts/functional/OWNERS
new file mode 100644
index 0000000..234bc75
--- /dev/null
+++ b/graphics/composer/2.3/vts/functional/OWNERS
@@ -0,0 +1,7 @@
+# Graphics team
+olv@google.com
+stoza@google.com
+
+# VTS team
+yim@google.com
+zhuoyao@google.com
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
new file mode 100644
index 0000000..1030ddc
--- /dev/null
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "graphics_composer_hidl_hal_test@2.3"
+
+#include <algorithm>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android-base/logging.h>
+#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
+#include <composer-vts/2.1/GraphicsComposerCallback.h>
+#include <composer-vts/2.1/TestCommandReader.h>
+#include <composer-vts/2.3/ComposerVts.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace composer {
+namespace V2_3 {
+namespace vts {
+namespace {
+
+// Test environment for graphics.composer
+class GraphicsComposerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    // get the test environment singleton
+    static GraphicsComposerHidlEnvironment* Instance() {
+        static GraphicsComposerHidlEnvironment* instance = new GraphicsComposerHidlEnvironment;
+        return instance;
+    }
+
+    virtual void registerTestServices() override { registerTestService<IComposer>(); }
+
+   private:
+    GraphicsComposerHidlEnvironment() {}
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(GraphicsComposerHidlEnvironment);
+};
+
+class GraphicsComposerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   protected:
+    void SetUp() override {
+        ASSERT_NO_FATAL_FAILURE(
+            mComposer = std::make_unique<Composer>(
+                GraphicsComposerHidlEnvironment::Instance()->getServiceName<IComposer>()));
+        ASSERT_NO_FATAL_FAILURE(mComposerClient = mComposer->createClient());
+
+        mComposerCallback = new V2_1::vts::GraphicsComposerCallback;
+        mComposerClient->registerCallback(mComposerCallback);
+
+        // assume the first display is primary and is never removed
+        mPrimaryDisplay = waitForFirstDisplay();
+
+        // explicitly disable vsync
+        mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
+        mComposerCallback->setVsyncAllowed(false);
+
+        mWriter = std::make_unique<CommandWriterBase>(1024);
+        mReader = std::make_unique<V2_1::vts::TestCommandReader>();
+    }
+
+    void TearDown() override {
+        if (mComposerCallback != nullptr) {
+            EXPECT_EQ(0, mComposerCallback->getInvalidHotplugCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidRefreshCount());
+            EXPECT_EQ(0, mComposerCallback->getInvalidVsyncCount());
+        }
+    }
+
+    void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
+
+    // use the slot count usually set by SF
+    static constexpr uint32_t kBufferSlotCount = 64;
+
+    std::unique_ptr<Composer> mComposer;
+    std::unique_ptr<ComposerClient> mComposerClient;
+    sp<V2_1::vts::GraphicsComposerCallback> mComposerCallback;
+    // the first display and is assumed never to be removed
+    Display mPrimaryDisplay;
+    std::unique_ptr<CommandWriterBase> mWriter;
+    std::unique_ptr<V2_1::vts::TestCommandReader> mReader;
+
+   private:
+    Display waitForFirstDisplay() {
+        while (true) {
+            std::vector<Display> displays = mComposerCallback->getDisplays();
+            if (displays.empty()) {
+                usleep(5 * 1000);
+                continue;
+            }
+
+            return displays[0];
+        }
+    }
+};
+
+/**
+ * Test IComposerClient::getDisplayIdentificationData.
+ *
+ * TODO: Check that ports are unique for multiple displays.
+ */
+TEST_F(GraphicsComposerHidlTest, GetDisplayIdentificationData) {
+    uint8_t port0;
+    std::vector<uint8_t> data0;
+    if (mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port0, &data0)) {
+        uint8_t port1;
+        std::vector<uint8_t> data1;
+        ASSERT_TRUE(mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port1, &data1));
+
+        ASSERT_EQ(port0, port1) << "ports are not stable";
+        ASSERT_TRUE(data0.size() == data1.size() &&
+                    std::equal(data0.begin(), data0.end(), data1.begin()))
+            << "data is not stable";
+    }
+}
+
+/**
+ * Test IComposerClient::Command::SET_LAYER_COLOR_TRANSFORM.
+ * TODO Add color to the layer, use matrix to keep only red component,
+ * and check.
+ */
+TEST_F(GraphicsComposerHidlTest, SetLayerColorTransform) {
+    Layer layer;
+    ASSERT_NO_FATAL_FAILURE(layer =
+                                mComposerClient->createLayer(mPrimaryDisplay, kBufferSlotCount));
+    mWriter->selectDisplay(mPrimaryDisplay);
+    mWriter->selectLayer(layer);
+
+    // clang-format off
+    const std::array<float, 16> matrix = {{
+        1.0f, 0.0f, 0.0f, 0.0f,
+        0.0f, 1.0f, 0.0f, 0.0f,
+        0.0f, 0.0f, 1.0f, 0.0f,
+        0.0f, 0.0f, 0.0f, 1.0f,
+    }};
+    // clang-format on
+
+    mWriter->setLayerColorTransform(matrix.data());
+    execute();
+}
+
+}  // namespace
+}  // namespace vts
+}  // namespace V2_3
+}  // namespace composer
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
+
+int main(int argc, char** argv) {
+    using android::hardware::graphics::composer::V2_3::vts::GraphicsComposerHidlEnvironment;
+    ::testing::AddGlobalTestEnvironment(GraphicsComposerHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    GraphicsComposerHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    return status;
+}
diff --git a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
index aa9beff..5ec0af2 100644
--- a/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
+++ b/graphics/mapper/2.0/vts/functional/VtsHalGraphicsMapperV2_0TargetTest.cpp
@@ -16,6 +16,10 @@
 
 #define LOG_TAG "VtsHalGraphicsMapperV2_0TargetTest"
 
+#include <chrono>
+#include <thread>
+#include <vector>
+
 #include <VtsHalHidlTargetTestBase.h>
 #include <android-base/logging.h>
 #include <mapper-vts/2.0/MapperVts.h>
@@ -125,6 +129,36 @@
 }
 
 /**
+ * Test that IAllocator::allocate is thread-safe.
+ */
+TEST_F(GraphicsMapperHidlTest, AllocatorAllocateThreaded) {
+    BufferDescriptor descriptor;
+    ASSERT_NO_FATAL_FAILURE(descriptor = mGralloc->createDescriptor(mDummyDescriptorInfo));
+
+    std::atomic<bool> timeUp(false);
+    std::atomic<uint64_t> allocationCount(0);
+    auto threadLoop = [&]() {
+        while (!timeUp) {
+            mGralloc->getAllocator()->allocate(
+                descriptor, 1, [&](const auto&, const auto&, const auto&) { allocationCount++; });
+        }
+    };
+
+    std::vector<std::thread> threads;
+    for (int i = 0; i < 8; i++) {
+        threads.push_back(std::thread(threadLoop));
+    }
+
+    std::this_thread::sleep_for(std::chrono::seconds(3));
+    timeUp = true;
+    LOG(VERBOSE) << "Made " << allocationCount << " threaded allocations";
+
+    for (auto& thread : threads) {
+        thread.join();
+    }
+}
+
+/**
  * Test IMapper::createDescriptor with valid descriptor info.
  */
 TEST_F(GraphicsMapperHidlTest, CreateDescriptorBasic) {
diff --git a/media/bufferpool/2.0/Android.bp b/media/bufferpool/2.0/Android.bp
new file mode 100644
index 0000000..1f8bbdb
--- /dev/null
+++ b/media/bufferpool/2.0/Android.bp
@@ -0,0 +1,28 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.media.bufferpool@2.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IAccessor.hal",
+        "IClientManager.hal",
+        "IConnection.hal",
+        "IObserver.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "Buffer",
+        "BufferInvalidationMessage",
+        "BufferStatus",
+        "BufferStatusMessage",
+        "ResultStatus",
+    ],
+    gen_java: false,
+}
+
diff --git a/media/bufferpool/2.0/IAccessor.hal b/media/bufferpool/2.0/IAccessor.hal
new file mode 100644
index 0000000..66707fe
--- /dev/null
+++ b/media/bufferpool/2.0/IAccessor.hal
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.bufferpool@2.0;
+
+import IConnection;
+import IObserver;
+/**
+ * IAccessor creates IConnection which is used from IClientManager in order to
+ * use functionality of the specified buffer pool.
+ */
+interface IAccessor {
+
+    /**
+     * Registers a new client and creates IConnection to the buffer pool for
+     * the client. IConnection and FMQ are used by IClientManager in order to
+     * communicate with the buffer pool. Via FMQ IClientManager sends
+     * BufferStatusMesage(s) to the buffer pool.
+     *
+     * FMQ is used to send buffer ownership status changes to a buffer pool
+     * from a buffer pool client. A buffer pool synchronizes FMQ messages when
+     * there is a hidl request from the clients. Every client has its own
+     * connection and FMQ to communicate with the buffer pool. So sending an
+     * FMQ message on behalf of other clients is not possible.
+     *
+     * FMQ messages are sent when a buffer is acquired or released. Also, FMQ
+     * messages are sent when a buffer is transferred from a client to another
+     * client. FMQ has its own ID from a buffer pool. A client is specified
+     * with the ID.
+     *
+     * To transfer a buffer, a sender must send an FMQ message. The message
+     * must include a receiver's ID and a transaction ID. A receiver must send
+     * the transaction ID to fetch a buffer from a buffer pool. Since the
+     * sender already registered the receiver via an FMQ message, The buffer
+     * pool must verify the receiver with the transaction ID. In order to
+     * prevent faking a receiver, a connection to a buffer pool from client is
+     * made and kept private. Also part of transaction ID is a sender ID in
+     * order to prevent fake transactions from other clients. This must be
+     * verified with an FMQ message from a buffer pool.
+
+     * @param observer The buffer pool event observer from the client.
+     *     Observer is provided to ensure FMQ messages are processed even when
+     *     client processes are idle. Buffer invalidation caused by
+     *     reconfiguration does not call observer. Buffer invalidation caused
+     *     by termination of pipeline call observer in order to ensure
+     *     invalidation is done after pipeline completion.
+     *
+     * @return status The status of the call.
+     *     OK               - A connection is made successfully.
+     *     NO_MEMORY        - Memory allocation failure occurred.
+     *     ALREADY_EXISTS   - A connection was already made.
+     *     CRITICAL_ERROR   - Other errors.
+     * @return connection The IConnection have interfaces
+     *     to get shared buffers from the buffer pool.
+     * @return connectionId Id of IConnection. The Id identifies
+     *     sender and receiver in FMQ messages during buffer transfer.
+     * @return toFmqDesc FMQ descriptor. The descriptor is used to
+     *     post buffer status messages.
+     * @return fromFmqDesc FMQ descriptor. The descriptor is used to
+     *     receive buffer invalidation messages from the buffer pool.
+     */
+    connect(IObserver observer)
+        generates (ResultStatus status, IConnection connection,
+                   int64_t connectionId,
+                   fmq_sync<BufferStatusMessage> toFmqDesc,
+                   fmq_unsync<BufferInvalidationMessage> fromFmqDesc);
+};
diff --git a/media/bufferpool/2.0/IClientManager.hal b/media/bufferpool/2.0/IClientManager.hal
new file mode 100644
index 0000000..9253bda
--- /dev/null
+++ b/media/bufferpool/2.0/IClientManager.hal
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.bufferpool@2.0;
+
+import IAccessor;
+
+/**
+ * IClientManager manages IConnection(s) inside a process. A locally
+ * created IConnection represents a communication node(receiver) with the
+ * specified buffer pool(IAccessor).
+ * IConnection(s) are not exposed to other processes(IClientManager).
+ * IClientManager instance must be unique within a process.
+ */
+interface IClientManager {
+
+    /**
+     * Sets up a buffer receiving communication node for the specified
+     * buffer pool. A manager must create a IConnection to the buffer
+     * pool if it does not already have a connection.
+     *
+     * @param bufferPool a buffer pool which is specified with the IAccessor.
+     *     The specified buffer pool is the owner of received buffers.
+     * @return status The status of the call.
+     *     OK               - A sender was set successfully.
+     *     NO_MEMORY        - Memory allocation failure occurred.
+     *     ALREADY_EXISTS   - A sender was registered already.
+     *     CRITICAL_ERROR   - Other errors.
+     * @return connectionId the Id of the communication node to the buffer pool.
+     *     This id is used in FMQ to notify IAccessor that a buffer has been
+     *     sent to that connection during transfers.
+     */
+    registerSender(IAccessor bufferPool) generates
+        (ResultStatus status, int64_t connectionId);
+};
diff --git a/media/bufferpool/2.0/IConnection.hal b/media/bufferpool/2.0/IConnection.hal
new file mode 100644
index 0000000..629f83c
--- /dev/null
+++ b/media/bufferpool/2.0/IConnection.hal
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.bufferpool@2.0;
+
+/**
+ * A connection to a buffer pool which handles requests from a buffer pool
+ * client. The connection must be made in order to receive buffers from
+ * other buffer pool clients.
+ */
+interface IConnection {
+
+    /**
+     * Retrieves a buffer using bufferId. The method must be called from
+     * receiving side of buffer during transferring only when the specified
+     * buffer is neither cached nor used. This fails if the specified
+     * transaction is not valid.
+     *
+     * @param transactionId Unique transaction id for buffer transferring.
+     * @param bufferId Id of the buffer to be fetched.
+     * @return status The status of the call.
+     *     OK               - A buffer was fetched successfully.
+     *     NO_MEMORY        - Memory allocation failure occurred.
+     *     NOT_FOUND        - A buffer was not found due to invalidation.
+     *     CRITICAL_ERROR   - Other errors.
+     * @return buffer The actual buffer which is specified with bufferId.
+     */
+    fetch(uint64_t transactionId, uint32_t bufferId) generates
+        (ResultStatus status, Buffer buffer);
+};
diff --git a/media/bufferpool/2.0/IObserver.hal b/media/bufferpool/2.0/IObserver.hal
new file mode 100644
index 0000000..a998836
--- /dev/null
+++ b/media/bufferpool/2.0/IObserver.hal
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.bufferpool@2.0;
+
+/**
+ * IObserver listens on notifications from the buffer pool. On receiving
+ * notifications, FMQ messages from the specific buffer pool which are already
+ * in the FMQ are processed.
+ */
+interface IObserver {
+
+    /**
+     * The specific buffer pool sent a message to the client. Calling this
+     * method from the buffer pool enforces a buffer pool client process the
+     * message.
+     *
+     * @param connectionId the connection Id of the specific buffer pool client
+     */
+    oneway onMessage(int64_t connectionId);
+};
diff --git a/media/bufferpool/2.0/README.md b/media/bufferpool/2.0/README.md
new file mode 100644
index 0000000..ed985d8
--- /dev/null
+++ b/media/bufferpool/2.0/README.md
@@ -0,0 +1,54 @@
+1. Overview
+
+A buffer pool enables processes to transfer buffers asynchronously.
+Without a buffer pool, a process calls a synchronous method of the other
+process and waits until the call finishes transferring a buffer. This adds
+unwanted latency due to context switching. With help from a buffer pool, a
+process can pass buffers asynchronously and reduce context switching latency.
+
+Passing an interface and a handle adds extra latency also. To mitigate the
+latency, passing IDs with local cache is used. For security concerns about
+rogue clients, FMQ is used to communicate between a buffer pool and a client
+process. FMQ is used to send buffer ownership change status from a client
+process to a buffer pool. Except FMQ, a buffer pool does not use any shared
+memory.
+
+2. FMQ
+
+FMQ is used to send buffer ownership status changes to a buffer pool from a
+buffer pool client. A buffer pool synchronizes FMQ messages when there is a
+hidl request from the clients. Every client has its own connection and FMQ
+to communicate with the buffer pool. So sending an FMQ message on behalf of
+other clients is not possible.
+
+FMQ messages are sent when a buffer is acquired or released. Also, FMQ messages
+are sent when a buffer is transferred from a client to another client. FMQ has
+its own ID from a buffer pool. A client is specified with the ID.
+
+To transfer a buffer, a sender must send an FMQ message. The message must
+include a receiver's ID and a transaction ID. A receiver must send the
+transaction ID to fetch a buffer from a buffer pool. Since the sender already
+registered the receiver via an FMQ message, The buffer pool must verify the
+receiver with the transaction ID. In order to prevent faking a receiver, a
+connection to a buffer pool from client is made and kept privately. Also part of
+transaction ID is a sender ID in order to prevent fake transactions from other
+clients. This must be verified with an FMQ message from a buffer pool.
+
+FMQ messages are defined in BufferStatus and BufferStatusMessage of 'types.hal'.
+
+3. Interfaces
+
+IConnection
+A connection to a buffer pool from a buffer pool client. The connection
+provides the functionalities to share buffers between buffer pool clients.
+The connection must be unique for each client.
+
+IAccessor
+An accessor to a buffer pool which makes a connection to the buffer pool.
+IAccesssor#connect creates an IConnection.
+
+IClientManager
+A manager of buffer pool clients and clients' connections to buffer pools. It
+sets up a process to be a receiver of buffers from a buffer pool. The manager
+is unique in a process.
+
diff --git a/media/bufferpool/2.0/types.hal b/media/bufferpool/2.0/types.hal
new file mode 100644
index 0000000..597e7b3
--- /dev/null
+++ b/media/bufferpool/2.0/types.hal
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.bufferpool@2.0;
+
+enum ResultStatus : int32_t {
+    OK                  = 0,
+
+    NO_MEMORY           = 1,
+    ALREADY_EXISTS      = 2,
+    NOT_FOUND           = 3,
+    CRITICAL_ERROR      = 4,
+};
+
+/**
+ * Generic buffer for fast recycling for media/stagefright.
+ *
+ * During media pipeline buffer references are created, shared and
+ * destroyed frequently. The underlying buffers are allocated on demand
+ * by a buffer pool, and are recycled to the buffer pool when they are
+ * no longer referenced by the clients.
+ *
+ * E.g. ion or gralloc buffer
+ */
+struct Buffer {
+    uint32_t id;
+    handle buffer;
+};
+
+/**
+ * Buffer ownership status for the specified client.
+ * Buffer transfer status for the specified buffer transafer transaction.
+ * BufferStatus is posted along with BufferStatusMessage from a client to
+ * the buffer pool for synchronization after status change.
+ */
+enum BufferStatus : int32_t {
+    /** No longer used by the specified client. */
+    NOT_USED            = 0,
+    /** Buffer is acquired by the specified client. */
+    USED                = 1,
+    /** Buffer is sent by the specified client. */
+    TRANSFER_TO         = 2,
+    /** Buffer transfer is acked by the receiver client. */
+    TRANSFER_FROM       = 3,
+    /** Buffer transfer is timed out by receiver client. */
+    TRANSFER_TIMEOUT    = 4,
+    /** Buffer transfer is not acked by the receiver. */
+    TRANSFER_LOST       = 5,
+    /** Buffer fetch request from the client. */
+    TRANSFER_FETCH      = 6,
+    /** Buffer transaction succeeded. */
+    TRANSFER_OK         = 7,
+    /** Buffer transaction failure. */
+    TRANSFER_ERROR      = 8,
+    /** Buffer invalidation ack. */
+    INVALIDATION_ACK    = 9,
+};
+
+/**
+ * Buffer ownership status change message. This message is
+ * sent via fmq to the buffer pool from client processes.
+ */
+struct BufferStatusMessage {
+    /**
+     * Transaction Id = (SenderId : sender local transaction Id)
+     * Transaction Id is created from sender and posted via fmq within
+     * TRANSFER_TO message.
+     */
+    uint64_t transactionId;
+    uint32_t bufferId;
+    BufferStatus newStatus;
+    /** Used by the buffer pool. not by client. */
+    int64_t connectionId;
+    /** Valid only when TRANSFER_TO is posted. */
+    int64_t targetConnectionId;
+    /**
+     * Used by the buffer pool, not by client.
+     * Monotonic timestamp in Us since fixed point in time as decided
+     * by the sender of the message
+     */
+    int64_t timestampUs;
+};
+
+/*
+ * Buffer pool sends a buffer invalidation message to clients in order to
+ * ensure fast reclamation of the buffers. Clients must free the invalidated
+ * buffers as soon as possible upon receiving the message.
+ */
+struct BufferInvalidationMessage {
+    uint32_t messageId;
+    /**
+     * Buffers from fromBufferId to toBufferId must be invalidated.
+     * fromBufferId is inclusive, but toBufferId is not inclusive.
+     * If fromBufferId > toBufferID, wrap happens. In that case
+     * the wrap is based on UINT32_MAX.
+     */
+    uint32_t fromBufferId;
+    uint32_t toBufferId;
+};
diff --git a/media/c2/1.0/Android.bp b/media/c2/1.0/Android.bp
new file mode 100644
index 0000000..c37c22b
--- /dev/null
+++ b/media/c2/1.0/Android.bp
@@ -0,0 +1,51 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.media.c2@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IComponent.hal",
+        "IComponentInterface.hal",
+        "IComponentListener.hal",
+        "IComponentStore.hal",
+        "IConfigurable.hal",
+        "IInputSurface.hal",
+        "IInputSurfaceConnection.hal",
+    ],
+    interfaces: [
+        "android.hardware.graphics.bufferqueue@1.0",
+        "android.hardware.graphics.common@1.0",
+        "android.hardware.media.bufferpool@2.0",
+        "android.hardware.media.omx@1.0",
+        "android.hardware.media@1.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "BaseBlock",
+        "Block",
+        "Buffer",
+        "FieldDescriptor",
+        "FieldId",
+        "FieldSupportedValues",
+        "FieldSupportedValuesQuery",
+        "FieldSupportedValuesQueryResult",
+        "FrameData",
+        "InfoBuffer",
+        "ParamDescriptor",
+        "ParamField",
+        "ParamFieldValues",
+        "SettingResult",
+        "Status",
+        "StructDescriptor",
+        "Work",
+        "WorkBundle",
+        "WorkOrdinal",
+        "Worklet",
+    ],
+    gen_java: false,
+}
+
diff --git a/media/c2/1.0/IComponent.hal b/media/c2/1.0/IComponent.hal
new file mode 100644
index 0000000..7fd551f
--- /dev/null
+++ b/media/c2/1.0/IComponent.hal
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2@1.0;
+
+import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer;
+import android.hardware.media.omx@1.0::IGraphicBufferSource;
+
+import IConfigurable;
+import IComponentInterface;
+import IComponentListener;
+import IInputSurface;
+import IInputSurfaceConnection;
+
+/**
+ * Interface for a Codec2 component corresponding to API level 1.0 or below.
+ * Components have two states: stopped and running. The running state has three
+ * sub-states: executing, tripped and error.
+ *
+ * All methods in `IComponent` must not block. If a method call cannot be
+ * completed in a timely manner, it must return `TIMED_OUT` in the return
+ * status.
+ */
+interface IComponent {
+
+    // METHODS AVAILABLE WHEN RUNNING
+    // =========================================================================
+
+    /**
+     * Queues up work for the component.
+     *
+     * This method must be supported in running (including tripped) states.
+     *
+     * It is acceptable for this method to return `OK` and return an error value
+     * using the IComponentListener::onWorkDone() callback.
+     *
+     * @param workBundle `WorkBundle` object containing a list of `Work` objects
+     *     to queue to the component.
+     * @return status Status of the call, which may be
+     *   - `OK`        - Works in @p workBundle were successfully queued.
+     *   - `BAD_INDEX` - Some component id in some `Worklet` is not valid.
+     *   - `CANNOT_DO` - The components are not tunneled but some `Work` object
+     *                   contains tunneling information.
+     *   - `NO_MEMORY` - Not enough memory to queue @p workBundle.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     */
+    queue(WorkBundle workBundle) generates (Status status);
+
+    /**
+     * Discards and abandons any pending `Work` items for the component.
+     *
+     * This method must be supported in running (including tripped) states.
+     *
+     * `Work` that could be immediately abandoned/discarded must be returned in
+     * @p flushedWorkBundle. The order in which queued `Work` items are
+     * discarded can be arbitrary.
+     *
+     * `Work` that could not be abandoned or discarded immediately must be
+     * marked to be discarded at the earliest opportunity, and must be returned
+     * via IComponentListener::onWorkDone(). This must be completed within
+     * 500ms.
+     *
+     * @return status Status of the call, which may be
+     *   - `OK`        - The component has been successfully flushed.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return flushedWorkBundle `WorkBundle` object containing flushed `Work`
+     *     items.
+     */
+    flush(
+        ) generates (
+            Status status,
+            WorkBundle flushedWorkBundle
+        );
+
+    /**
+     * Drains the component, and optionally downstream components. This is a
+     * signalling method; as such it does not wait for any work completion.
+     *
+     * The last `Work` item is marked as "drain-till-here", so the component is
+     * notified not to wait for further `Work` before it processes what is
+     * already queued. This method can also be used to set the end-of-stream
+     * flag after `Work` has been queued. Client can continue to queue further
+     * `Work` immediately after this method returns.
+     *
+     * This method must be supported in running (including tripped) states.
+     *
+     * `Work` that is completed must be returned via
+     * IComponentListener::onWorkDone().
+     *
+     * @param withEos Whether to drain the component with marking end-of-stream.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The drain request has been successfully recorded.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     */
+    drain(bool withEos) generates (Status status);
+
+    /**
+     * Starts using a surface for output.
+     *
+     * This method must not block.
+     *
+     * @param blockPoolId Id of the `C2BlockPool` to be associated with the
+     *     output surface.
+     * @param surface Output surface.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The operation completed successfully.
+     *   - `CANNOT_DO` - The component does not support an output surface.
+     *   - `REFUSED`   - The output surface cannot be accessed.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     */
+    setOutputSurface(
+            uint64_t blockPoolId,
+            IGraphicBufferProducer surface
+        ) generates (
+            Status status
+        );
+
+    /**
+     * Starts using an input surface.
+     *
+     * The component must be in running state.
+     *
+     * @param inputSurface Input surface to connect to.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The operation completed successfully.
+     *   - `CANNOT_DO` - The component does not support an input surface.
+     *   - `BAD_STATE` - The component is not in running state.
+     *   - `DUPLICATE` - The component is already connected to an input surface.
+     *   - `REFUSED`   - The input surface is already in use.
+     *   - `NO_MEMORY` - Not enough memory to start the component.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return connection `IInputSurfaceConnection` object, which can be used to
+     *     query and configure properties of the connection. This cannot be
+     *     null.
+     */
+    connectToInputSurface(
+            IInputSurface inputSurface
+        ) generates (
+            Status status,
+            IInputSurfaceConnection connection
+        );
+
+    /**
+     * Starts using an OMX input surface.
+     *
+     * The component must be in running state.
+     *
+     * This method is similar to connectToInputSurface(), but it takes an OMX
+     * input surface (as a pair of `IGraphicBufferProducer` and
+     * `IGraphicBufferSource`) instead of Codec2's own `IInputSurface`.
+     *
+     * @param producer Producer component of an OMX input surface.
+     * @param source Source component of an OMX input surface.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The operation completed successfully.
+     *   - `CANNOT_DO` - The component does not support an OMX input surface.
+     *   - `BAD_STATE` - The component is not in running state.
+     *   - `DUPLICATE` - The component is already connected to an input surface.
+     *   - `REFUSED`   - The input surface is already in use.
+     *   - `NO_MEMORY` - Not enough memory to start the component.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return connection `IInputSurfaceConnection` object, which can be used to
+     *     query and configure properties of the connection. This cannot be
+     *     null.
+     */
+    connectToOmxInputSurface(
+            IGraphicBufferProducer producer,
+            IGraphicBufferSource source
+        ) generates (
+            Status status,
+            IInputSurfaceConnection connection
+        );
+
+    /**
+     * Stops using an input surface.
+     *
+     * The component must be in running state.
+     *
+     * @return status Status of the call, which may be
+     *   - `OK`        - The operation completed successfully.
+     *   - `CANNOT_DO` - The component does not support an input surface.
+     *   - `BAD_STATE` - The component is not in running state.
+     *   - `NOT_FOUND` - The component is not connected to an input surface.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     */
+    disconnectFromInputSurface() generates (Status Status);
+
+    /**
+     * Creates a local `C2BlockPool` backed by the given allocator and returns
+     * its id.
+     *
+     * The returned @p blockPoolId is the only way the client can refer to a
+     * `C2BlockPool` object in the component. The id can be passed to
+     * setOutputSurface() or used in some C2Param objects later.
+     *
+     * The created `C2BlockPool` object can be destroyed by calling
+     * destroyBlockPool(), reset() or release(). reset() and release() must
+     * destroy all `C2BlockPool` objects that have been created.
+     *
+     * @param allocatorId Id of a `C2Allocator`.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The operation completed successfully.
+     *   - `NO_MEMORY` - Not enough memory to create the pool.
+     *   - `BAD_VALUE` - @p allocatorId is not recognized.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return blockPoolId Id of the created C2BlockPool object. This may be
+     *     used in setOutputSurface() if the allocator
+     * @return configurable Configuration interface for the created pool. This
+     *     must not be null.
+     */
+    createBlockPool(uint32_t allocatorId) generates (
+        Status status,
+        uint64_t blockPoolId,
+        IConfigurable configurable
+    );
+
+    /**
+     * Destroys a local block pool previously created by createBlockPool().
+     *
+     * @param blockPoolId Id of a `C2BlockPool` that was previously returned by
+     *      createBlockPool().
+     * @return status Status of the call, which may be
+     *   - `OK`        - The operation completed successfully.
+     *   - `NOT_FOUND` - The supplied blockPoolId is not valid.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     */
+    destroyBlockPool(uint64_t blockPoolId) generates (Status status);
+
+    // STATE CHANGE METHODS
+    // =========================================================================
+
+    /**
+     * Starts the component.
+     *
+     * This method must be supported in stopped state as well as tripped state.
+     *
+     * If the return value is `OK`, the component must be in the running state.
+     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
+     * expected as a response to this call. Otherwise, the component must be in
+     * the stopped state.
+     *
+     * If a component is in the tripped state and start() is called while the
+     * component configuration still results in a trip, start() must succeed and
+     * a new onTripped() callback must be used to communicate the configuration
+     * conflict that results in the new trip.
+     *
+     * @return status Status of the call, which may be
+     *   - `OK`        - The component has started successfully.
+     *   - `BAD_STATE` - Component is not in stopped or tripped state.
+     *   - `DUPLICATE` - When called during another start call from another
+     *                   thread.
+     *   - `NO_MEMORY` - Not enough memory to start the component.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     */
+    start() generates (Status status);
+
+    /**
+     * Stops the component.
+     *
+     * This method must be supported in running (including tripped) state.
+     *
+     * This method must return withing 500ms.
+     *
+     * Upon this call, all pending `Work` must be abandoned.
+     *
+     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
+     * expected as a response to this call. For all other return values, the
+     * component must be in the stopped state.
+     *
+     * This does not alter any settings and tunings that may have resulted in a
+     * tripped state.
+     *
+     * @return status Status of the call, which may be
+     *   - `OK`        - The component has stopped successfully.
+     *   - `BAD_STATE` - Component is not in running state.
+     *   - `DUPLICATE` - When called during another stop call from another
+     *                   thread.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     */
+    stop() generates (Status status);
+
+    /**
+     * Resets the component.
+     *
+     * This method must be supported in all (including tripped) states other
+     * than released.
+     *
+     * This method must be supported during any other blocking call.
+     *
+     * This method must return withing 500ms.
+     *
+     * When this call returns, if @p status is `OK`, all `Work` items must
+     * have been abandoned, and all resources (including `C2BlockPool` objects
+     * previously created by createBlockPool()) must have been released.
+     *
+     * If the return value is `BAD_STATE` or `DUPLICATE`, no state change is
+     * expected as a response to this call. For all other return values, the
+     * component must be in the stopped state.
+     *
+     * This brings settings back to their default, "guaranteeing" no tripped
+     * state.
+     *
+     * @return status Status of the call, which may be
+     *   - `OK`        - The component has been reset.
+     *   - `BAD_STATE` - Component is in released state.
+     *   - `DUPLICATE` - When called during another reset call from another
+     *                   thread.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     */
+    reset() generates (Status status);
+
+    /**
+     * Releases the component.
+     *
+     * This method must be supported in stopped state.
+     *
+     * This method destroys the component. Upon return, if @p status is `OK` or
+     * `DUPLICATE`, all resources must have been released.
+     *
+     * @return status Status of the call, which may be
+     *   - `OK`        - The component has been released.
+     *   - `BAD_STATE` - The component is running.
+     *   - `DUPLICATE` - The component is already released.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     */
+    release() generates (Status status);
+
+    /**
+     * Returns the @ref IComponentInterface instance associated to this
+     * component.
+     *
+     * An @p IConfigurable instance for the component can be obtained by calling
+     * IComponentInterface::getConfigurable() on the returned @p intf.
+     *
+     * @return intf `IComponentInterface` instance. This must not be null.
+     */
+    getInterface() generates (IComponentInterface intf);
+};
+
diff --git a/media/c2/1.0/IComponentInterface.hal b/media/c2/1.0/IComponentInterface.hal
new file mode 100644
index 0000000..a007d02
--- /dev/null
+++ b/media/c2/1.0/IComponentInterface.hal
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2@1.0;
+
+import IConfigurable;
+
+/**
+ * Component interface object. This object contains all of the configurations of
+ * a potential or actual component. It can be created and used independently of
+ * an actual Codec2 component to query supported parameters for various
+ * component settings, and configurations for a potential component.
+ *
+ * An actual component exposes this interface via IComponent::getInterface().
+ */
+interface IComponentInterface {
+    /**
+     * Returns the @ref IConfigurable instance associated to this component
+     * interface.
+     *
+     * @return configurable `IConfigurable` instance. This must not be null.
+     */
+    getConfigurable() generates (IConfigurable configurable);
+};
+
diff --git a/media/c2/1.0/IComponentListener.hal b/media/c2/1.0/IComponentListener.hal
new file mode 100644
index 0000000..70d5fb2
--- /dev/null
+++ b/media/c2/1.0/IComponentListener.hal
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2@1.0;
+
+/**
+ * Callback interface for handling notifications from @ref IComponent.
+ */
+interface IComponentListener {
+
+    /**
+     * Notify the listener that some `Work` items have been completed.
+     *
+     * All the input buffers in the returned `Work` objects must not be used by
+     * the component after onWorkDone() is called.
+     *
+     * @param workBundle List of completed `Work` objects.
+     */
+    oneway onWorkDone(WorkBundle workBundle);
+
+    /**
+     * Notify the listener that the component is tripped.
+     *
+     * @param settingResults List of failures.
+     */
+    oneway onTripped(vec<SettingResult> settingResults);
+
+    /**
+     * Notify the listener of an error.
+     *
+     * @param status Error type. @p status may be `OK`, which means that an
+     *     error has occurred, but the error type does not fit into the type
+     *     `Status`. In this case, additional information is provided by
+     *     @p errorCode.
+     * @param errorCode Additional error information. The framework may not
+     *     recognize the meaning of this value.
+     */
+    oneway onError(Status status, uint32_t errorCode);
+
+    /**
+     * Information about rendering of a frame to a `Surface`.
+     */
+    struct RenderedFrame {
+        /**
+         * Id of the `BufferQueue` containing the rendered buffer.
+         *
+         * This value must have been obtained by an earlier call to
+         * IGraphicBufferProducer::getUniqueId().
+         */
+        uint64_t bufferQueueId;
+        /**
+         * Id of the slot of the rendered buffer.
+         *
+         * This value must have been obtained by an earlier call to
+         * IGraphicBufferProducer::dequeueBuffer() or
+         * IGraphicBufferProducer::attachBuffer().
+         */
+        int32_t slotId;
+        /**
+         * Timestamp the rendering happened.
+         *
+         * The reference point for the timestamp is determined by the
+         * `BufferQueue` that performed the rendering.
+         */
+        int64_t timestampNs;
+    };
+
+    /**
+     * Notify the listener that frames have been rendered.
+     *
+     * @param renderedFrames List of @ref RenderedFrame objects.
+     */
+    oneway onFramesRendered(vec<RenderedFrame> renderedFrames);
+
+    /**
+     * Identifying information for an input buffer previously queued to the
+     * component via IComponent::queue().
+     */
+    struct InputBuffer {
+        /**
+         * This value comes from `Work::input.ordinal.frameIndex` in a `Work`
+         * object that was previously queued.
+         */
+        uint64_t frameIndex;
+        /**
+         * This value is an index into `Work::input.buffers` (which is an array)
+         * in a `Work` object that was previously queued.
+         */
+        uint32_t arrayIndex;
+    };
+
+    /**
+     * Notify the listener that some input buffers are no longer needed by the
+     * component, and hence can be released or reused by the client.
+     *
+     * Input buffers that are contained in a `Work` object returned by an
+     * earlier onWorkDone() call are assumed released, so they must not appear
+     * in any onInputBuffersReleased() calls. That means
+     * onInputBuffersReleased() must only report input buffers that are released
+     * before the output in the same `Work` item is produced. However, it is
+     * possible for an input buffer to be returned by onWorkDone() after it has
+     * been reported by onInputBuffersReleased().
+     *
+     * @note onWorkDone() and onInputBuffersReleased() both notify the client
+     * that input buffers are no longer needed. However, in order to minimize
+     * IPC calls, onInputBuffersReleased() should be called only when
+     * onWorkDone() cannot be called, e.g., the component needs more input
+     * before an output can be produced.
+     *
+     * @param inputBuffers List of `InputBuffer` objects, identifying input
+     * buffers that are no longer needed by the component.
+     */
+    oneway onInputBuffersReleased(vec<InputBuffer> inputBuffers);
+};
+
diff --git a/media/c2/1.0/IComponentStore.hal b/media/c2/1.0/IComponentStore.hal
new file mode 100644
index 0000000..6a57c38
--- /dev/null
+++ b/media/c2/1.0/IComponentStore.hal
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2@1.0;
+
+import android.hardware.media.bufferpool@2.0::IClientManager;
+import IComponentInterface;
+import IComponentListener;
+import IComponent;
+import IConfigurable;
+import IInputSurface;
+
+/**
+ * Entry point for Codec2 HAL.
+ *
+ * All methods in `IComponentStore` must not block. If a method call cannot be
+ * completed in a timely manner, it must return `TIMED_OUT` in the return
+ * status. The only exceptions are getPoolClientManager() and getConfigurable(),
+ * which must always return immediately.
+ */
+interface IComponentStore {
+
+    /**
+     * Creates a component by name.
+     *
+     * @param name Name of the component to create. This must match one of the
+     *     names returned by listComponents().
+     * @param listener Callback receiver.
+     * @param pool `IClientManager` object of the BufferPool in the client
+     *     process. This may be null if the client does not own a BufferPool.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The component was created successfully.
+     *   - `NOT_FOUND` - There is no component with the given name.
+     *   - `NO_MEMORY` - Not enough memory to create the component.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return comp The created component if @p status is `OK`.
+     *
+     * @sa IComponentListener.
+     */
+    createComponent(
+            string name,
+            IComponentListener listener,
+            IClientManager pool
+        ) generates (
+            Status status,
+            IComponent comp
+        );
+
+    /**
+     * Creates a component interface by name.
+     *
+     * @param name Name of the component interface to create. This should match
+     *     one of the names returned by listComponents().
+     * @return status Status of the call, which may be
+     *   - `OK         - The component interface was created successfully.
+     *   - `NOT_FOUND` - There is no component interface with the given name.
+     *   - `NO_MEMORY` - Not enough memory to create the component interface.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return compIntf The created component interface if @p status is `OK`.
+     */
+    createInterface(
+            string name
+        ) generates (
+            Status status,
+            IComponentInterface compIntf
+        );
+
+    /**
+     * Component traits.
+     */
+    struct ComponentTraits {
+        /**
+         * Name of the component. This must be unique for each component.
+         *
+         * This name is use to identify the component to create in
+         * createComponent() and createComponentInterface().
+         */
+        string name;
+
+        enum Domain : uint32_t {
+            OTHER = 0,
+            VIDEO,
+            AUDIO,
+            IMAGE,
+        };
+        /**
+         * Component domain.
+         */
+        Domain domain;
+
+        enum Kind : uint32_t {
+            OTHER = 0,
+            DECODER,
+            ENCODER,
+        };
+        /**
+         * Component kind.
+         */
+        Kind kind;
+
+        /**
+         * Rank used by `MediaCodecList` to determine component ordering. Lower
+         * value means higher priority.
+         */
+        uint32_t rank;
+
+        /**
+         * MIME type.
+         */
+        string mediaType;
+
+        /**
+         * Aliases for component name for backward compatibility.
+         *
+         * Multiple components can have the same alias (but not the same
+         * component name) as long as their media types differ.
+         */
+        vec<string> aliases;
+    };
+
+    /**
+     * Returns the list of components supported by this component store.
+     *
+     * @return status Status of the call, which may be
+     *   - `OK         - The operation was successful.
+     *   - `NO_MEMORY` - Not enough memory to complete this method.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return traits List of component traits for all components supported by
+     *     this store (in no particular order).
+     */
+    listComponents() generates (
+            Status status,
+            vec<ComponentTraits> traits
+        );
+
+    /**
+     * Creates a persistent input surface that can be used as an input surface
+     * for any IComponent instance
+     *
+     * @return status Status of the call, which may be
+     *   - `OK         - The operation was successful.
+     *   - `NO_MEMORY` - Not enough memory to complete this method.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return surface A persistent input surface. This may be null to indicate
+     *     an error.
+     */
+    createInputSurface() generates (
+            Status status,
+            IInputSurface surface
+        );
+
+    /**
+     * Returns a list of `StructDescriptor` objects for a set of requested
+     * C2Param structure indices that this store is aware of.
+     *
+     * This operation must be performed at best effort, e.g. the component
+     * store must simply ignore all struct indices that it is not aware of.
+     *
+     * @param indices Indices of C2Param structures to describe.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The operation completed successfully.
+     *   - `NOT_FOUND` - Some indices were not known.
+     *   - `NO_MEMORY` - Not enough memory to complete this method.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return structs List of `StructDescriptor` objects.
+     */
+    getStructDescriptors(
+            vec<ParamIndex> indices
+        ) generates (
+            Status status,
+            vec<StructDescriptor> structs
+        );
+
+    /**
+     * Copies the contents of @p src into @p dst without changing the format of
+     * @p dst.
+     *
+     * @param src Source buffer.
+     * @param dst Destination buffer.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The copy is successful.
+     *   - `CANNOT_DO` - @p src and @p dst are not compatible.
+     *   - `REFUSED`   - No permission to copy.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     */
+    copyBuffer(Buffer src, Buffer dst) generates (Status status);
+
+    /**
+     * Returns the `IClientManager` object for the component's BufferPool.
+     *
+     * @return pool If the component store supports receiving buffers via
+     *     BufferPool API, @p pool must be a valid `IClientManager` instance.
+     *     Otherwise, @p pool must be null.
+     */
+    getPoolClientManager() generates (IClientManager pool);
+
+    /**
+     * Returns the @ref IConfigurable instance associated to this component
+     * store.
+     *
+     * @return configurable `IConfigurable` instance. This must not be null.
+     */
+    getConfigurable() generates (IConfigurable configurable);
+};
+
diff --git a/media/c2/1.0/IConfigurable.hal b/media/c2/1.0/IConfigurable.hal
new file mode 100644
index 0000000..31dc4d3
--- /dev/null
+++ b/media/c2/1.0/IConfigurable.hal
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2@1.0;
+
+/**
+ * Generic configuration interface presented by all configurable Codec2 objects.
+ *
+ * This interface must be supported in all states of the owning object, and must
+ * not change the state of the owning object.
+ */
+interface IConfigurable {
+    /**
+     * Returns the id of the object. This must be unique among all objects of
+     * the same type hosted by the same store.
+     *
+     * @return id Id of the object.
+     */
+    getId() generates (uint32_t id);
+
+    /**
+     * Returns the name of the object.
+     *
+     * This must match the name that was supplied during the creation of the
+     * object.
+     *
+     * @return name Name of the object.
+     */
+    getName() generates (string name);
+
+    /**
+     * Queries a set of parameters from the object.
+     *
+     * Querying is performed at best effort: the object must query all supported
+     * parameters and skip unsupported ones (which may include parameters that
+     * could not be allocated). Any errors are communicated in the return value.
+     *
+     * If @p mayBlock is false, this method must not block. All parameter
+     * queries that require blocking must be skipped.
+     *
+     * If @p mayBlock is true, a query may block, but the whole method call
+     * has to complete in a timely manner, or `status = TIMED_OUT` is returned.
+     *
+     * If @p mayBlock is false, this method must not block. Otherwise, this
+     * method is allowed to block for a certain period of time before completing
+     * the operation. If the operation is not completed in a timely manner,
+     * `status = TIMED_OUT` is returned.
+     *
+     * @note The order of C2Param objects in @p param does not depend on the
+     *     order of C2Param structure indices in @p indices.
+     *
+     * \par For IComponent
+     *
+     * When the object type is @ref IComponent, this method must be supported in
+     * any state except released. This call must not change the state nor the
+     * internal configuration of the component.
+     *
+     * The blocking behavior of this method differs among states:
+     *   - In the stopped state, this must be non-blocking. @p mayBlock is
+     *     ignored. (The method operates as if @p mayBlock was false.)
+     *   - In any of the running states, this method may block momentarily if
+     *     @p mayBlock is true. However, if the call cannot be completed in a
+     *     timely manner, `status = TIMED_OUT` is returned.
+     *
+     * @param indices List of C2Param structure indices to query.
+     * @param mayBlock Whether this call may block or not.
+     * @return status Status of the call, which may be
+     *   - `OK`        - All parameters could be queried.
+     *   - `BAD_INDEX` - All supported parameters could be queried, but some
+     *                   parameters were not supported.
+     *   - `NO_MEMORY` - Could not allocate memory for a supported parameter.
+     *   - `BLOCKING`  - Querying some parameters requires blocking, but
+     *                   @p mayBlock is false.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return params Flattened representation of C2Param objects.
+     *
+     * @sa Params.
+     */
+    query(
+            vec<ParamIndex> indices,
+            bool mayBlock
+        ) generates (
+            Status status,
+            Params params
+        );
+
+    /**
+     * Sets a set of parameters for the object.
+     *
+     * Tuning is performed at best effort: the object must update all supported
+     * configurations at best effort and skip unsupported parameters. Any errors
+     * are communicated in the return value and in @p failures.
+     *
+     * A non-strict parameter update with an unsupported value shall cause an
+     * update to the closest supported value. A strict parameter update with an
+     * unsupported value shall be skipped and a failure shall be returned.
+     *
+     * If @p mayBlock is false, this method must not block. An update that
+     * requires blocking shall be skipped and a failure shall be returned.
+     *
+     * If @p mayBlock is true, an update may block, but the whole method call
+     * has to complete in a timely manner, or `status = TIMED_OUT` is returned.
+     *
+     * The final values for all parameters set are propagated back to the caller
+     * in @p params.
+     *
+     * \par For IComponent
+     *
+     * When the object type is @ref IComponent, this method must be supported in
+     * any state except released.
+     *
+     * The blocking behavior of this method differs among states:
+     *   - In the stopped state, this must be non-blocking. @p mayBlock is
+     *     ignored. (The method operates as if @p mayBlock was false.)
+     *   - In any of the running states, this method may block momentarily if
+     *     @p mayBlock is true. However, if the call cannot be completed in a
+     *     timely manner, `status = TIMED_OUT` is returned.
+     *
+     * @note Parameter tuning @e does depend on the order of the tuning
+     * parameters, e.g., some parameter update may enable some subsequent
+     * parameter update.
+     *
+     * @param inParams Requested parameter updates.
+     * @param mayBlock Whether this call may block or not.
+     * @return status Status of the call, which may be
+     *   - `OK`        - All parameters could be updated successfully.
+     *   - `BAD_INDEX` - All supported parameters could be updated successfully,
+     *                   but some parameters were not supported.
+     *   - `NO_MEMORY` - Some supported parameters could not be updated
+     *                   successfully because they contained unsupported values.
+     *                   These are returned in @p failures.
+     *   - `BLOCKING`  - Setting some parameters requires blocking, but
+     *                   @p mayBlock is false.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return failures List of update failures.
+     * @return outParams Flattened representation of configured parameters. The
+     *     order of parameters in @p outParams is based on the order of
+     *     requested updates in @p inParams.
+     *
+     * @sa SettingResult.
+     */
+    config(
+            Params inParams,
+            bool mayBlock
+        ) generates (
+            Status status,
+            vec<SettingResult> failures,
+            Params outParams
+        );
+
+    // REFLECTION MECHANISM
+    // =========================================================================
+
+    /**
+     * Returns a list of supported parameters within a selected range of C2Param
+     * structure indices.
+     *
+     * @param start The first index of the selected range.
+     * @param count The length of the selected range.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The operation completed successfully.
+     *   - `NO_MEMORY` - Not enough memory to complete this method.
+     * @return params List of supported parameters in the selected range. This
+     *     list may have fewer than @p count elements if some indices in the
+     *     range are not supported.
+     *
+     * @sa ParamDescriptor.
+     */
+    querySupportedParams(
+            uint32_t start,
+            uint32_t count
+        ) generates (
+            Status status,
+            vec<ParamDescriptor> params
+        );
+
+    /**
+     * Retrieves the supported values for the queried fields.
+     *
+     * The object must process all fields queried even if some queries fail.
+     *
+     * If @p mayBlock is false, this method must not block. Otherwise, this
+     * method is allowed to block for a certain period of time before completing
+     * the operation. If the operation cannot be completed in a timely manner,
+     * `status = TIMED_OUT` is returned.
+     *
+     * \par For IComponent
+     *
+     * When the object type is @ref IComponent, this method must be supported in
+     * any state except released.
+     *
+     * The blocking behavior of this method differs among states:
+     *   - In the stopped state, this must be non-blocking. @p mayBlock is
+     *     ignored. (The method operates as if @p mayBlock was false.)
+     *   - In any of the running states, this method may block momentarily if
+     *     @p mayBlock is true. However, if the call cannot be completed in a
+     *     timely manner, `status = TIMED_OUT` is returned.
+     *
+     * @param inFields List of field queries.
+     * @param mayBlock Whether this call may block or not.
+     * @return status Status of the call, which may be
+     *   - `OK`        - The operation completed successfully.
+     *   - `BLOCKING`  - Querying some parameters requires blocking, but
+     *                   @p mayBlock is false.
+     *   - `NO_MEMORY` - Not enough memory to complete this method.
+     *   - `BAD_INDEX` - At least one field was not recognized as a component
+     *                   field.
+     *   - `BLOCKING`  - Querying some fields requires blocking, but @p mayblock
+     *                   is false.
+     *   - `TIMED_OUT` - The operation cannot be finished in a timely manner.
+     *   - `CORRUPTED` - Some unknown error occurred.
+     * @return outFields List of supported values and results for the
+     *     supplied queries.
+     *
+     * @sa FieldSupportedValuesQuery, FieldSupportedValuesQueryResult.
+     */
+    querySupportedValues(
+            vec<FieldSupportedValuesQuery> inFields,
+            bool mayBlock
+        ) generates (
+            Status status,
+            vec<FieldSupportedValuesQueryResult> outFields
+        );
+
+};
+
diff --git a/media/c2/1.0/IInputSurface.hal b/media/c2/1.0/IInputSurface.hal
new file mode 100644
index 0000000..25c6c8e
--- /dev/null
+++ b/media/c2/1.0/IInputSurface.hal
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2@1.0;
+
+import android.hardware.graphics.bufferqueue@1.0::IGraphicBufferProducer;
+
+import IConfigurable;
+
+/**
+ * Input surface for a Codec2 component.
+ *
+ * An <em>input surface</em> is an instance of `IInputSurface`, which may be
+ * created by calling IComponentStore::createInputSurface(). Once created, the
+ * client may
+ *   1. write data to it via the `IGraphicBufferProducer` interface; and
+ *   2. use it as input to a Codec2 encoder.
+ *
+ * @sa IInputSurfaceConnection, IComponentStore::createInputSurface(),
+ *     IComponent::connectToInputSurface().
+ */
+interface IInputSurface {
+    /**
+     * Returns the producer interface into the internal buffer queue.
+     *
+     * @return producer `IGraphicBufferProducer` instance. This must not be
+     * null.
+     */
+    getGraphicBufferProducer() generates (IGraphicBufferProducer producer);
+
+    /**
+     * Returns the @ref IConfigurable instance associated to this input surface.
+     *
+     * @return configurable `IConfigurable` instance. This must not be null.
+     */
+    getConfigurable() generates (IConfigurable configurable);
+};
+
diff --git a/media/c2/1.0/IInputSurfaceConnection.hal b/media/c2/1.0/IInputSurfaceConnection.hal
new file mode 100644
index 0000000..efd9c6e
--- /dev/null
+++ b/media/c2/1.0/IInputSurfaceConnection.hal
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2@1.0;
+
+import IConfigurable;
+
+/**
+ * Connection between a component and an input surface.
+ *
+ * An instance of `IInputSurfaceConnection` contains an `IConfigurable`
+ * interface for querying and configuring properties of the connection.
+ */
+interface IInputSurfaceConnection {
+    /**
+     * Returns the @ref IConfigurable instance associated to this connection.
+     *
+     * This can be used to customize the connection.
+     *
+     * @return configurable `IConfigurable` instance. This must not be null.
+     */
+    getConfigurable() generates (IConfigurable configurable);
+};
+
diff --git a/media/c2/1.0/types.hal b/media/c2/1.0/types.hal
new file mode 100644
index 0000000..7b75041
--- /dev/null
+++ b/media/c2/1.0/types.hal
@@ -0,0 +1,832 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.media.c2@1.0;
+
+import android.hardware.media.bufferpool@2.0::BufferStatusMessage;
+
+/**
+ * Common return values for Codec2 operations.
+ */
+enum Status : int32_t {
+    /** Operation completed successfully. */
+    OK        = 0,
+
+    // bad input
+
+    /** Argument has invalid value (user error). */
+    BAD_VALUE = -22,
+    /** Argument uses invalid index (user error). */
+    BAD_INDEX = -75,
+    /** Argument/Index is valid but not possible. */
+    CANNOT_DO = -2147483646,
+
+    // bad sequencing of events
+
+    /** Object already exists. */
+    DUPLICATE = -17,
+    /** Object not found. */
+    NOT_FOUND = -2,
+    /** Operation is not permitted in the current state. */
+    BAD_STATE = -38,
+    /** Operation would block but blocking is not permitted. */
+    BLOCKING  = -9930,
+
+    // bad environment
+
+    /** Not enough memory to complete operation. */
+    NO_MEMORY = -12,
+    /** Missing permission to complete operation. */
+    REFUSED   = -1,
+
+    /** Operation did not complete within timeout. */
+    TIMED_OUT = -110,
+
+    // missing functionality
+
+    /** Operation is not implemented/supported (optional only). */
+    OMITTED   = -74,
+
+    // unknown fatal
+
+    /** Some unexpected error prevented the operation. */
+    CORRUPTED = -2147483648,
+
+    // uninitialized
+
+    /** Status has not been initialized. */
+    NO_INIT   = -19,
+};
+
+/**
+ * C2Param structure index.
+ *
+ * This is a number that is unique for each C2Param structure type.
+ *
+ * @sa Codec 2.0 standard.
+ */
+typedef uint32_t ParamIndex;
+
+/**
+ * Flattened representation of C2Param objects.
+ *
+ * The `Params` type is an array of bytes made up by concatenating a list of
+ * C2Param objects. The start index (offset into @ref Params) of each C2Param
+ * object in the list is divisible by 8. Up to 7 padding bytes may be added
+ * after each C2Param object to achieve this 64-bit alignment.
+ *
+ * Each C2Param object has the following layout:
+ * - 4 bytes: C2Param structure index (of type @ref ParamIndex) identifying the
+ *   type of the C2Param object.
+ * - 4 bytes: size of the C2Param object (unsigned 4-byte integer).
+ * - (size - 8) bytes: data of the C2Param object.
+ *
+ * In order to interpret each C2Param object correctly, its structure must be
+ * described by IComponentStore::getStructDescriptors().
+ *
+ * @note Please refer to the Codec 2.0 standard for the list of standard
+ * parameter structures.
+ *
+ * @sa Codec 2.0 standard.
+ */
+typedef vec<uint8_t> Params;
+
+/**
+ * Identifying information of a field relative to a known C2Param structure.
+ *
+ * Within a given C2Param structure, each field is uniquely identified by @ref
+ * FieldId.
+ */
+struct FieldId {
+    /** Offset of the field in bytes. */
+    uint32_t offset;
+    /** Size of the field in bytes. */
+    uint32_t size;
+};
+
+/**
+ * Reference to a field in a C2Param structure.
+ */
+struct ParamField {
+    /** Index of the C2Param structure. */
+    ParamIndex index;
+    /** Identifier of the field inside the C2Param structure. */
+    FieldId fieldId;
+};
+
+/**
+ * Usage description of a C2Param structure.
+ *
+ * @ref ParamDescriptor is returned by IConfigurable::querySupportedParams().
+ */
+struct ParamDescriptor {
+    /**
+     * Index of the C2Param structure being described.
+     */
+    ParamIndex index;
+
+    enum Attrib : uint32_t {
+        /**
+         * The parameter is required to be specified.
+         */
+        REQUIRED   = 1u << 0,
+        /**
+         * The parameter retains its value.
+         */
+        PERSISTENT = 1u << 1,
+        /**
+         * The parameter is strict.
+         */
+        STRICT     = 1u << 2,
+        /**
+         * The parameter is publicly read-only.
+         */
+        READ_ONLY  = 1u << 3,
+        /**
+         * The parameter must not be visible to clients.
+         */
+        HIDDEN     = 1u << 4,
+        /**
+         * The parameter must not be used by framework (other than testing).
+         */
+        INTERNAL   = 1u << 5,
+        /**
+         * The parameter is publicly constant (hence read-only).
+         */
+        CONST      = 1u << 6,
+    };
+    bitfield<Attrib> attrib;
+
+    /**
+     * Name of the structure. This must be unique for each structure.
+     */
+    string name;
+
+    /**
+     * Indices of other C2Param structures that this C2Param structure depends
+     * on.
+     */
+    vec<ParamIndex> dependencies;
+};
+
+// Generic way to describe supported numeric values for Codec2 interfaces.
+
+/**
+ * An untyped value that can fit in 64 bits, the type of which is communicated
+ * via a separate channel (@ref FieldSupportedValues.type).
+ */
+typedef uint64_t PrimitiveValue;
+
+/*
+ * Description of supported values for a field.
+ *
+ * This can be a continuous range or a discrete set of values.
+ */
+struct FieldSupportedValues {
+    /**
+     * Used if #type is `RANGE`.
+     *
+     * If the `step` member is 0, and `num` and `denom` are both 1, the `Range`
+     * structure represents a closed interval bounded by `min` and `max`.
+     *
+     * Otherwise, the #Range structure represents a finite sequence of numbers
+     * produced from the following recurrence relation:
+     *
+     * @code
+     * v[0] = min
+     * v[i] = v[i - 1] * num / denom + step ; i >= 1
+     * @endcode
+     *
+     * Both the ratio `num / denom` and the value `step` must be positive. The
+     * last number in the sequence described by this #Range structure is the
+     * largest number in the sequence that is smaller than or equal to `max`.
+     *
+     * @note
+     * The division in the formula may truncate the result if the data type of
+     * these values is an integral type.
+     */
+    struct Range {
+        /**
+         * Lower end of the range (inclusive).
+         */
+        PrimitiveValue min;
+        /**
+         * Upper end of the range (inclusive).
+         */
+        PrimitiveValue max;
+        /**
+         * The non-homogeneous term in the recurrence relation.
+         */
+        PrimitiveValue step;
+        /**
+         * The numerator of the scale coefficient in the recurrence relation.
+         */
+        PrimitiveValue num;
+        /**
+         * The denominator of the scale coefficient in the recurrence relation.
+         */
+        PrimitiveValue denom;
+    };
+
+    enum Type : int32_t {
+        /** No supported values */
+        EMPTY = 0,
+        /** Numeric range, described in a #Range structure */
+        RANGE,
+        /** List of values */
+        VALUES,
+        /** List of flags that can be OR-ed */
+        FLAGS,
+    };
+    /**
+     * Type of the supported values.
+     */
+    Type type;
+
+    /**
+     * When #type is #Type.RANGE, #range shall specify the range of possible
+     * values.
+     *
+     * The intended type of members of #range shall be clear in the context
+     * where `FieldSupportedValues` is used.
+     */
+    Range range;
+
+    /**
+     * When #type is #Type.VALUES or #Type.FLAGS, #value shall list supported
+     * values/flags.
+     *
+     * The intended type of components of #value shall be clear in the context
+     * where `FieldSupportedValues` is used.
+     */
+    vec<PrimitiveValue> values;
+};
+
+/**
+ * Supported values for a field.
+ *
+ * This is a pair of the field specifier together with an optional supported
+ * values object. This structure is used when reporting parameter configuration
+ * failures and conflicts.
+ */
+struct ParamFieldValues {
+    /**
+     * Reference to a field or a C2Param structure.
+     */
+    ParamField paramOrField;
+
+    /**
+     * Optional supported values for the field if #paramOrField specifies an
+     * actual field that is numeric (non struct, blob or string). Supported
+     * values for arrays (including string and blobs) describe the supported
+     * values for each element (character for string, and bytes for blobs). It
+     * is optional for read-only strings and blobs.
+     */
+    vec<FieldSupportedValues> values;
+};
+
+/**
+ * Description of a field inside a C2Param structure.
+ */
+struct FieldDescriptor {
+
+    /** Location of the field in the C2Param structure */
+    FieldId fieldId;
+
+    /**
+     * Possible types of the field.
+     */
+    enum Type : uint32_t {
+        NO_INIT = 0,
+        INT32,
+        UINT32,
+        CNTR32,
+        INT64,
+        UINT64,
+        CNTR64,
+        FLOAT,
+        /**
+         * Fixed-size string (POD).
+         */
+        STRING = 0x100,
+        /**
+         * A blob has no sub-elements and can be thought of as an array of
+         * bytes. However, bytes cannot be individually addressed by clients.
+         */
+        BLOB,
+        /**
+         * The field is a structure that may contain other fields.
+         */
+        STRUCT = 0x20000,
+    };
+    /**
+     * Type of the field.
+     */
+    bitfield<Type> type;
+
+    /**
+     * If #type is #Type.STRUCT, #structIndex is the C2Param structure index;
+     * otherwise, #structIndex is not used.
+     */
+    ParamIndex structIndex;
+
+    /**
+     * Extent of the field.
+     * - For a non-array field, #extent is 1.
+     * - For a fixed-length array field, #extent is the length. An array field
+     *   of length 1 is indistinguishable from a non-array field.
+     * - For a variable-length array field, #extent is 0. This can only occur as
+     *   the last member of a C2Param structure.
+     */
+    uint32_t extent;
+
+    /**
+     * Name of the field. This must be unique for each field in the same
+     * structure.
+     */
+    string name;
+
+    /**
+     * Named value type. This is used for defining an enum value for a numeric
+     * type.
+     */
+    struct NamedValue {
+        /**
+         * Name of the enum value. This must be unique for each enum value in
+         * the same field.
+         */
+        string name;
+        /**
+         * Underlying value of the enum value. Multiple enum names may have the
+         * same underlying value.
+         */
+        PrimitiveValue value;
+    };
+    /**
+     * List of enum values. This is not used when #type is not one of the
+     * numeric types.
+     */
+    vec<NamedValue> namedValues;
+};
+
+/**
+ * Description of a C2Param structure. It consists of an index and a list of
+ * `FieldDescriptor`s.
+ */
+struct StructDescriptor {
+    /**
+     * Index of the structure.
+     */
+    ParamIndex type;
+    /**
+     * List of fields in the structure.
+     *
+     * Fields are ordered by their offsets. A field that is a structure is
+     * ordered before its members.
+     */
+    vec<FieldDescriptor> fields;
+};
+
+/**
+ * Information describing the reason the parameter settings may fail, or may be
+ * overridden.
+ */
+struct SettingResult {
+    /** Failure code */
+    enum Failure : uint32_t {
+        /** Parameter is not supported. */
+        BAD_TYPE,
+        /** Parameter is not supported on the specific port. */
+        BAD_PORT,
+        /** Parameter is not supported on the specific stream. */
+        BAD_INDEX,
+        /** Parameter is read-only and cannot be set. */
+        READ_ONLY,
+        /** Parameter mismatches input data. */
+        MISMATCH,
+        /** Strict parameter does not accept value for the field at all. */
+        BAD_VALUE,
+        /**
+         * Strict parameter field value is in conflict with an/other
+         * setting(s).
+         */
+        CONFLICT,
+        /**
+         * Parameter field is out of range due to other settings. (This failure
+         * mode can only be used for strict calculated parameters.)
+         */
+        UNSUPPORTED,
+        /**
+         * Field does not access the requested parameter value at all. It has
+         * been corrected to the closest supported value. This failure mode is
+         * provided to give guidance as to what are the currently supported
+         * values for this field (which may be a subset of the at-all-potential
+         * values).
+         */
+        INFO_BAD_VALUE,
+        /**
+         * Requested parameter value is in conflict with an/other setting(s)
+         * and has been corrected to the closest supported value. This failure
+         * mode is given to provide guidance as to what are the currently
+         * supported values as well as to optionally provide suggestion to the
+         * client as to how to enable the requested parameter value.
+         */
+        INFO_CONFLICT,
+    };
+    Failure failure;
+
+    /**
+     * Failing (or corrected) field or parameter and optionally, currently
+     * supported values for the field. Values must only be set for field
+     * failures other than `BAD_VALUE`, and only if they are different from the
+     * globally supported values (e.g. due to restrictions by another parameter
+     * or input data).
+     */
+    ParamFieldValues field;
+
+    /**
+     * Conflicting parameters or fields with (optional) suggested values for any
+     * conflicting fields to avoid the conflict. Values must only be set for
+     * `CONFLICT`, `UNSUPPORTED` or `INFO_CONFLICT` failure code.
+     */
+    vec<ParamFieldValues> conflicts;
+};
+
+/**
+ * Ordering information of @ref FrameData objects. Each member is used for
+ * comparing urgency: a smaller difference from a reference value indicates that
+ * the associated Work object is more urgent. The reference value for each
+ * member is initialized the first time it is communicated between the client
+ * and the codec, and it may be updated to later values that are communicated.
+ *
+ * Each member of `WorkOrdinal` is stored as an unsigned integer, but the actual
+ * order it represents is derived by subtracting the reference value, then
+ * interpreting the result as a signed number with the same storage size (using
+ * two's complement).
+ *
+ * @note `WorkOrdinal` is the HIDL counterpart of `C2WorkOrdinalStruct` in the
+ * Codec 2.0 standard.
+ */
+struct WorkOrdinal {
+    /**
+     * Timestamp in microseconds.
+     */
+    uint64_t timestampUs;
+    /**
+     * Frame index.
+     */
+    uint64_t frameIndex;
+    /**
+     * Component specific frame ordinal.
+     */
+    uint64_t customOrdinal;
+};
+
+/**
+ * Storage type for `BaseBlock`.
+ *
+ * A `BaseBlock` is a representation of a codec memory block. Coded data,
+ * decoded data, codec-specific data, and other codec-related data are all sent
+ * in the form of BaseBlocks.
+ */
+safe_union BaseBlock {
+    /**
+     * #nativeBlock is the opaque representation of a buffer.
+     */
+    handle nativeBlock;
+    /**
+     * #pooledBlock is a reference to a buffer handled by a BufferPool.
+     */
+    BufferStatusMessage pooledBlock;
+};
+
+/**
+ * Reference to a @ref BaseBlock within a @ref WorkBundle.
+ *
+ * `Block` contains additional attributes that `BaseBlock` does not. These
+ * attributes may differ among `Block` objects that refer to the same
+ * `BaseBlock` in the same `WorkBundle`.
+ */
+struct Block {
+    /**
+     * Identity of a `BaseBlock` within a `WorkBundle`. This is an index into
+     * #WorkBundle.baseBlocks.
+     */
+    uint32_t index;
+    /**
+     * Metadata associated with this `Block`.
+     */
+    Params meta;
+    /**
+     * Fence for synchronizing `Block` access.
+     */
+    handle fence;
+};
+
+/**
+ * A codec buffer, which is a collection of @ref Block objects and metadata.
+ *
+ * This is a part of @ref FrameData.
+ */
+struct Buffer {
+    /**
+     * Metadata associated with the buffer.
+     */
+    Params info;
+    /**
+     * Blocks contained in the buffer.
+     */
+    vec<Block> blocks;
+};
+
+/**
+ * An extension of @ref Buffer that also contains a C2Param structure index.
+ *
+ * This is a part of @ref FrameData.
+ */
+struct InfoBuffer {
+    /**
+     * A C2Param structure index.
+     */
+    ParamIndex index;
+    /**
+     * Associated @ref Buffer object.
+     */
+    Buffer buffer;
+};
+
+/**
+ * Data for an input frame or an output frame.
+ *
+ * This structure represents a @e frame with its metadata. A @e frame consists
+ * of an ordered set of buffers, configuration changes, and info buffers along
+ * with some non-configuration metadata.
+ *
+ * @note `FrameData` is the HIDL counterpart of `C2FrameData` in the Codec 2.0
+ * standard.
+ */
+struct FrameData {
+    enum Flags : uint32_t {
+        /**
+         * For input frames: no output frame shall be generated when processing
+         * this frame, but metadata must still be processed.
+         *
+         * For output frames: this frame must be discarded but metadata is still
+         * valid.
+         */
+        DROP_FRAME    = (1 << 0),
+        /**
+         * This frame is the last frame of the current stream. Further frames
+         * are part of a new stream.
+         */
+        END_OF_STREAM = (1 << 1),
+        /**
+         * This frame must be discarded with its metadata.
+         *
+         * This flag is only set by components, e.g. as a response to the flush
+         * command.
+         */
+        DISCARD_FRAME = (1 << 2),
+        /**
+         * This frame is not the last frame produced for the input.
+         *
+         * This flag is normally set by the component - e.g. when an input frame
+         * results in multiple output frames, this flag is set on all but the
+         * last output frame.
+         *
+         * Also, when components are chained, this flag should be propagated
+         * down the work chain. That is, if set on an earlier frame of a
+         * work-chain, it should be propagated to all later frames in that
+         * chain. Additionally, components down the chain could set this flag
+         * even if not set earlier, e.g. if multiple output frames are generated
+         * at that component for the input frame.
+         */
+        FLAG_INCOMPLETE = (1 << 3),
+        /**
+         * This frame contains only codec-specific configuration data, and no
+         * actual access unit.
+         *
+         * @deprecated Pass codec configuration with the codec-specific
+         * configuration info together with the access unit.
+         */
+        CODEC_CONFIG  = (1u << 31),
+    };
+
+    /**
+     * Frame flags, as described in #Flags.
+     */
+    bitfield<Flags> flags;
+
+    /**
+     * @ref WorkOrdinal of the frame.
+     */
+    WorkOrdinal ordinal;
+
+    /**
+     * List of frame buffers.
+     */
+    vec<Buffer> buffers;
+
+    /**
+     * List of configuration updates.
+     */
+    Params configUpdate;
+
+    /**
+     * List of info buffers.
+     */
+    vec<InfoBuffer> infoBuffers;
+};
+
+/**
+ * In/out structure containing some instructions for and results from output
+ * processing.
+ *
+ * This is a part of @ref Work. One `Worklet` corresponds to one output
+ * @ref FrameData. The client must construct an original `Worklet` object inside
+ * a @ref Work object for each expected output before calling
+ * IComponent::queue().
+ */
+struct Worklet {
+    /**
+     * Component id. (Input)
+     *
+     * This is used only when tunneling is enabled.
+     *
+     * When used, this must match the return value from IConfigurable::getId().
+     */
+    uint32_t componentId;
+
+    /**
+     * List of C2Param objects describing tunings to be applied before
+     * processing this `Worklet`. (Input)
+     */
+    Params tunings;
+
+    /**
+     * Flag determining whether this `Worklet` has output or not.
+     */
+    bool hasOutput;
+
+    /**
+     * List of failures. (Output)
+     */
+    vec<SettingResult> failures;
+
+    /**
+     * Output frame data. (Output)
+     */
+    FrameData output;
+};
+
+/**
+ * A collection of input data to and output data from the component.
+ *
+ * A `Work` object holds information about a single work item. It is created by
+ * the client and passed to the component via IComponent::queue(). The component
+ * has two ways of returning a `Work` object to the client:
+ *   1. If the queued `Work` object has been successfully processed,
+ *      IComponentListener::onWorkDone() shall be called to notify the listener,
+ *      and the output shall be included in the returned `Work` object.
+ *   2. If the client calls IComponent::flush(), a `Work` object that has not
+ *      been processed shall be returned.
+ *
+ * `Work` is a part of @ref WorkBundle.
+ */
+struct Work {
+    /**
+     * Additional work chain info not part of this work.
+     */
+    Params chainInfo;
+
+    /**
+     * @ref FrameData for the input.
+     */
+    FrameData input;
+
+    /**
+     * The chain of `Worklet`s.
+     *
+     * The length of #worklets is 1 when tunneling is not enabled.
+     *
+     * If #worklets has more than a single element, the tunnels between
+     * successive components of the work chain must have been successfully
+     * pre-registered at the time that the `Work` is submitted. Allocating the
+     * output buffers in the `Worklet`s is the responsibility of each component
+     * in the chain.
+     *
+     * Upon `Work` submission, #worklets must be an appropriately sized vector
+     * containing `Worklet`s with @ref Worklet.hasOutput set to `false`. After a
+     * successful processing, all but the final `Worklet` in the returned
+     * #worklets must have @ref Worklet.hasOutput set to `false`.
+     */
+    vec<Worklet> worklets;
+
+    /**
+     * The number of `Worklet`s successfully processed in this chain.
+     *
+     * This must be initialized to 0 by the client when the `Work` is submitted,
+     * and it must contain the number of `Worklet`s that were successfully
+     * processed when the `Work` is returned to the client.
+     *
+     * #workletsProcessed cannot exceed the length of #worklets. If
+     * #workletsProcessed is smaller than the length of #worklets, #result
+     * cannot be `OK`.
+     */
+    uint32_t workletsProcessed;
+
+    /**
+     * The final outcome of the `Work` (corresponding to #workletsProcessed).
+     *
+     * The value of @ref Status.OK implies that all `Worklet`s have been
+     * successfully processed.
+     */
+    Status result;
+};
+
+/**
+ * List of `Work` objects.
+ *
+ * `WorkBundle` is used in IComponent::queue(), IComponent::flush() and
+ * IComponentListener::onWorkDone(). A `WorkBundle` object consists of a list of
+ * `Work` objects and a list of `BaseBlock` objects. Bundling multiple `Work`
+ * objects together provides two benefits:
+ *   1. Batching of `Work` objects can reduce the number of IPC calls.
+ *   2. If multiple `Work` objects contain `Block`s that refer to the same
+ *      `BaseBlock`, the number of `BaseBlock`s that is sent between processes
+ *      is also reduced.
+ *
+ * @note `WorkBundle` is the HIDL counterpart of the vector of `C2Work` in the
+ * Codec 2.0 standard. The presence of #baseBlocks helps with minimizing the
+ * data transferred over an IPC.
+ */
+struct WorkBundle {
+    /**
+     * A list of Work items.
+     */
+    vec<Work> works;
+    /**
+     * A list of blocks indexed by elements of #works.
+     */
+    vec<BaseBlock> baseBlocks;
+};
+
+/**
+ * Query information for supported values of a field. This is used as input to
+ * IConfigurable::querySupportedValues().
+ */
+struct FieldSupportedValuesQuery {
+    /**
+     * Identity of the field to query.
+     */
+    ParamField field;
+
+    enum Type : uint32_t {
+        /** Query all possible values regardless of other settings. */
+        POSSIBLE,
+        /** Query currently possible values given dependent settings. */
+        CURRENT,
+    };
+    /**
+     * Type of the query. See #Type for more information.
+     */
+    Type type;
+};
+
+/**
+ * This structure is used to hold the result from
+ * IConfigurable::querySupportedValues().
+ */
+struct FieldSupportedValuesQueryResult {
+    /**
+     * Result of the query. Possible values are
+     * - `OK`: The query was successful.
+     * - `BAD_STATE`: The query was requested when the `IConfigurable` instance
+     *   was in a bad state.
+     * - `BAD_INDEX`: The requested field was not recognized.
+     * - `TIMED_OUT`: The query could not be completed in a timely manner.
+     * - `BLOCKING`: The query must block, but the parameter `mayBlock` in the
+     *   call to `querySupportedValues()` was `false`.
+     * - `CORRUPTED`: Some unknown error occurred.
+     */
+    Status status;
+
+    /**
+     * Supported values. This is meaningful only when #status is `OK`.
+     */
+    FieldSupportedValues values;
+};
+
diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
index 34a96a0..88a9e26 100644
--- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
+++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.cpp
@@ -470,7 +470,7 @@
     status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
                                   OMX_StateExecuting);
     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
-    status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT);
+    status = observer->dequeueMessage(&msg, RELAXED_TIMEOUT);
     ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
     ASSERT_EQ(msg.type, Message::Type::EVENT);
     ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
diff --git a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
index c1863d5..1575ba2 100644
--- a/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
+++ b/media/omx/1.0/vts/functional/common/media_hidl_test_common.h
@@ -41,6 +41,8 @@
 /* As component is switching states (loaded<->idle<->execute), dequeueMessage()
  * expects the events to be received within this duration */
 #define DEFAULT_TIMEOUT 100000
+// b/70933963
+#define RELAXED_TIMEOUT 400000
 /* Time interval between successive Input/Output enqueues */
 #define DEFAULT_TIMEOUT_Q 2000
 /* While the component is amidst a process call, asynchronous commands like
diff --git a/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp
index 7750a12..4ddc833 100644
--- a/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp
+++ b/media/omx/1.0/vts/functional/component/VtsHalMediaOmxV1_0TargetComponentTest.cpp
@@ -1149,15 +1149,13 @@
             ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
 
             // do not enable the port until all the buffers are supplied
-            status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
-                                              &pBuffer[0], &pBuffer[1]);
+            status = observer->dequeueMessage(&msg, RELAXED_TIMEOUT, &pBuffer[0], &pBuffer[1]);
             ASSERT_EQ(status,
                       android::hardware::media::omx::V1_0::Status::TIMED_OUT);
 
             ASSERT_NO_FATAL_FAILURE(allocatePortBuffers(
                 omxNode, &pBuffer[i - portBase], i, portMode[i - portBase]));
-            status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
-                                              &pBuffer[0], &pBuffer[1]);
+            status = observer->dequeueMessage(&msg, RELAXED_TIMEOUT, &pBuffer[0], &pBuffer[1]);
             ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
             ASSERT_EQ(msg.type, Message::Type::EVENT);
             ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortEnable);
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
index 0050e52..a64268f 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
@@ -34,9 +34,11 @@
 namespace neuralnetworks {
 namespace V1_1 {
 
-using V1_0::Request;
 using V1_0::DeviceStatus;
 using V1_0::ErrorStatus;
+using V1_0::Operand;
+using V1_0::OperandType;
+using V1_0::Request;
 
 namespace vts {
 namespace functional {
diff --git a/neuralnetworks/1.2/Android.bp b/neuralnetworks/1.2/Android.bp
index d5ef49d..5a661e0 100644
--- a/neuralnetworks/1.2/Android.bp
+++ b/neuralnetworks/1.2/Android.bp
@@ -17,6 +17,8 @@
     ],
     types: [
         "Model",
+        "Operand",
+        "OperandType",
         "Operation",
         "OperationType",
     ],
diff --git a/neuralnetworks/1.2/IDevice.hal b/neuralnetworks/1.2/IDevice.hal
index 9cc23a2..aff4cf3 100644
--- a/neuralnetworks/1.2/IDevice.hal
+++ b/neuralnetworks/1.2/IDevice.hal
@@ -26,6 +26,36 @@
  */
 interface IDevice extends @1.1::IDevice {
     /**
+     * Get the version string of the driver implementation.
+     *
+     * The version string must be a unique token among the set of version strings of
+     * drivers of a specific device. The token identifies the device driver's
+     * implementation. The token must not be confused with the feature level which is solely
+     * defined by the interface version. This API is opaque to the Android framework, but the
+     * Android framework may use the information for debugging or to pass on to NNAPI applications.
+     *
+     * Application developers sometimes have specific requirements to ensure good user experiences,
+     * and they need more information to make intelligent decisions when the Android framework cannot.
+     * For example, combined with the device name and other information, the token can help
+     * NNAPI applications filter devices based on their needs:
+     *     - An application demands a certain level of performance, but a specific version of
+     *       the driver cannot meet that requirement because of a performance regression.
+     *       The application can blacklist the driver based on the version provided.
+     *     - An application has a minimum precision requirement, but certain versions of
+     *       the driver cannot meet that requirement because of bugs or certain optimizations.
+     *       The application can filter out versions of these drivers.
+     *
+     * @return status Error status returned from querying the version string. Must be:
+     *     - NONE if the query was successful
+     *     - DEVICE_UNAVAILABLE if driver is offline or busy
+     *     - GENERAL_FAILURE if the query resulted in an
+     *       unspecified error
+     * @return version The version string of the device implementation.
+     *     Must have nonzero length
+     */
+    getVersionString() generates (ErrorStatus status, string version);
+
+    /**
      * Gets the supported operations in a model.
      *
      * getSupportedOperations indicates which operations of a model are fully
diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal
index bed1d5c..4a1e7a8 100644
--- a/neuralnetworks/1.2/types.hal
+++ b/neuralnetworks/1.2/types.hal
@@ -16,10 +16,36 @@
 
 package android.hardware.neuralnetworks@1.2;
 
-import @1.0::Operand;
+import @1.0::DataLocation;
+import @1.0::OperandLifeTime;
+import @1.0::OperandType;
 import @1.0::PerformanceInfo;
 import @1.1::OperationType;
 
+enum OperandType : @1.0::OperandType {
+    /**
+     * An 8 bit boolean scalar value.
+     *
+     * Values of this operand type are either true or false. A zero value
+     * represents false; any other value represents true.
+     */
+    BOOL = 6,
+    /**
+     * A tensor of 16 bit signed integers that represent real numbers.
+     *
+     * Attached to this tensor are two numbers that are used to convert the 16
+     * bit integer to the real value and vice versa. These two numbers are:
+     * - scale: a 32 bit floating point value greater than zero.
+     * - zeroPoint: a 32 bit integer, in range [-32768, 32767].
+     *
+     * The formula is:
+     * realValue = (integerValue - zeroPoint) * scale.
+     */
+    TENSOR_QUANT16_ASYMM = 7,
+    /** A tensor of 16 bit floating point values. */
+    TENSOR_FLOAT16 = 8,
+};
+
 /**
  * Operation types.
  *
@@ -102,6 +128,101 @@
 };
 
 /**
+ * Describes one operand of the model's graph.
+ */
+struct Operand {
+    /**
+     * Data type of the operand.
+     */
+    OperandType type;
+
+    /**
+     * Dimensions of the operand.
+     *
+     * For a scalar operand, dimensions.size() must be 0.
+     *
+     * For a tensor operand, dimensions.size() must be at least 1;
+     * however, any of the dimensions may be unspecified.
+     *
+     * A tensor operand with all dimensions specified has "fully
+     * specified" dimensions. Whenever possible (i.e., whenever the
+     * dimensions are known at model construction time), a tensor
+     * operand should have (but is not required to have) fully
+     * specified dimensions, in order to enable the best possible
+     * performance.
+     *
+     * If a tensor operand's dimensions are not fully specified, the
+     * dimensions of the operand are deduced from the operand
+     * dimensions and values of the operation for which that operand
+     * is an output.
+     *
+     * In the following situations, a tensor operand's dimensions must
+     * be fully specified:
+     *
+     *     . The operand has lifetime CONSTANT_COPY or
+     *       CONSTANT_REFERENCE.
+     *
+     *     . The operand has lifetime MODEL_INPUT or MODEL_OUTPUT. Fully
+     *       specified dimensions must either be present in the
+     *       Operand or they must be provided in the corresponding
+     *       RequestArgument.
+     *       EXCEPTION: If the input or output is optional and omitted
+     *       (by setting the hasNoValue field of the corresponding
+     *       RequestArgument to true) then it need not have fully
+     *       specified dimensions.
+     *
+     * A tensor operand with some number of unspecified dimensions is
+     * represented by setting each unspecified dimension to 0.
+     */
+    vec<uint32_t> dimensions;
+
+    /**
+     * The number of times this operand appears as an operation input.
+     *
+     * (For example, if this operand appears once in one operation's
+     * input list, and three times in another operation's input list,
+     * then numberOfConsumers = 4.)
+     */
+    uint32_t numberOfConsumers;
+
+    /**
+     * Quantized scale of the operand.
+     *
+     * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM or
+     * TENSOR_INT32.
+     */
+    float scale;
+
+    /**
+     * Quantized zero-point offset of the operand.
+     *
+     * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM.
+     */
+    int32_t zeroPoint;
+
+    /**
+     * How the operand is used.
+     */
+    OperandLifeTime lifetime;
+
+    /**
+     * Where to find the data for this operand.
+     * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
+     * NO_VALUE:
+     * - All the fields must be 0.
+     * If the lifetime is CONSTANT_COPY:
+     * - location.poolIndex is 0.
+     * - location.offset is the offset in bytes into Model.operandValues.
+     * - location.length is set.
+     * If the lifetime is CONSTANT_REFERENCE:
+     * - location.poolIndex is set.
+     * - location.offset is the offset in bytes into the specified pool.
+     * - location.length is set.
+     */
+    DataLocation location;
+};
+
+/**
  * A Neural Network Model.
  *
  * This includes not only the execution graph, but also constant data such as
diff --git a/neuralnetworks/1.2/vts/functional/BasicTests.cpp b/neuralnetworks/1.2/vts/functional/BasicTests.cpp
index d2dea1d..eb3ebd3 100644
--- a/neuralnetworks/1.2/vts/functional/BasicTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/BasicTests.cpp
@@ -37,6 +37,14 @@
     EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
 }
 
+// device version test
+TEST_F(NeuralnetworksHidlTest, GetDeviceVersionStringTest) {
+    Return<void> ret = device->getVersionString([](ErrorStatus status, const hidl_string& version) {
+        EXPECT_EQ(ErrorStatus::NONE, status);
+        EXPECT_LT(0, version.size());
+    });
+    EXPECT_TRUE(ret.isOk());
+}
 }  // namespace functional
 }  // namespace vts
 }  // namespace V1_2
diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
index 7ec6ff1..b840199 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp
@@ -26,9 +26,7 @@
 namespace V1_2 {
 
 using V1_0::IPreparedModel;
-using V1_0::Operand;
 using V1_0::OperandLifeTime;
-using V1_0::OperandType;
 using V1_1::ExecutionPreference;
 
 namespace vts {
@@ -131,10 +129,10 @@
 ///////////////////////// VALIDATE MODEL OPERAND TYPE /////////////////////////
 
 static const int32_t invalidOperandTypes[] = {
-    static_cast<int32_t>(OperandType::FLOAT32) - 1,              // lower bound fundamental
-    static_cast<int32_t>(OperandType::TENSOR_QUANT8_ASYMM) + 1,  // upper bound fundamental
-    static_cast<int32_t>(OperandType::OEM) - 1,                  // lower bound OEM
-    static_cast<int32_t>(OperandType::TENSOR_OEM_BYTE) + 1,      // upper bound OEM
+    static_cast<int32_t>(OperandType::FLOAT32) - 1,               // lower bound fundamental
+    static_cast<int32_t>(OperandType::TENSOR_QUANT16_ASYMM) + 1,  // upper bound fundamental
+    static_cast<int32_t>(OperandType::OEM) - 1,                   // lower bound OEM
+    static_cast<int32_t>(OperandType::TENSOR_OEM_BYTE) + 1,       // upper bound OEM
 };
 
 static void mutateOperandTypeTest(const sp<IDevice>& device, const Model& model) {
@@ -157,10 +155,13 @@
         case OperandType::FLOAT32:
         case OperandType::INT32:
         case OperandType::UINT32:
+        case OperandType::BOOL:
             return 1;
+        case OperandType::TENSOR_FLOAT16:
         case OperandType::TENSOR_FLOAT32:
         case OperandType::TENSOR_INT32:
         case OperandType::TENSOR_QUANT8_ASYMM:
+        case OperandType::TENSOR_QUANT16_ASYMM:
             return 0;
         default:
             return 0;
@@ -185,11 +186,14 @@
         case OperandType::FLOAT32:
         case OperandType::INT32:
         case OperandType::UINT32:
+        case OperandType::BOOL:
+        case OperandType::TENSOR_FLOAT16:
         case OperandType::TENSOR_FLOAT32:
             return 1.0f;
         case OperandType::TENSOR_INT32:
             return -1.0f;
         case OperandType::TENSOR_QUANT8_ASYMM:
+        case OperandType::TENSOR_QUANT16_ASYMM:
             return 0.0f;
         default:
             return 0.0f;
@@ -214,10 +218,13 @@
         case OperandType::FLOAT32:
         case OperandType::INT32:
         case OperandType::UINT32:
+        case OperandType::BOOL:
+        case OperandType::TENSOR_FLOAT16:
         case OperandType::TENSOR_FLOAT32:
         case OperandType::TENSOR_INT32:
             return {1};
         case OperandType::TENSOR_QUANT8_ASYMM:
+        case OperandType::TENSOR_QUANT16_ASYMM:
             return {-1, 256};
         default:
             return {};
@@ -253,10 +260,12 @@
         case OperandType::FLOAT32:
         case OperandType::INT32:
         case OperandType::UINT32:
+        case OperandType::BOOL:
             newOperand.dimensions = hidl_vec<uint32_t>();
             newOperand.scale = 0.0f;
             newOperand.zeroPoint = 0;
             break;
+        case OperandType::TENSOR_FLOAT16:
         case OperandType::TENSOR_FLOAT32:
             newOperand.dimensions =
                 operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
@@ -269,6 +278,7 @@
             newOperand.zeroPoint = 0;
             break;
         case OperandType::TENSOR_QUANT8_ASYMM:
+        case OperandType::TENSOR_QUANT16_ASYMM:
             newOperand.dimensions =
                 operand->dimensions.size() > 0 ? operand->dimensions : hidl_vec<uint32_t>({1});
             newOperand.scale = operand->scale != 0.0f ? operand->scale : 1.0f;
diff --git a/power/stats/1.0/Android.bp b/power/stats/1.0/Android.bp
new file mode 100644
index 0000000..2f16a21
--- /dev/null
+++ b/power/stats/1.0/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.power.stats@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IPowerStats.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "Status",
+        "RailInfo",
+        "EnergyData",
+    ],
+    gen_java: false,
+}
+
diff --git a/power/stats/1.0/IPowerStats.hal b/power/stats/1.0/IPowerStats.hal
new file mode 100644
index 0000000..d75e170
--- /dev/null
+++ b/power/stats/1.0/IPowerStats.hal
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.power.stats@1.0;
+
+interface IPowerStats {
+
+    /**
+     * Rail information:
+     * Reports information related to the rails being monitored.
+     *
+     * @return rails Information about monitored rails.
+     * @return status SUCCESS on success or NOT_SUPPORTED if
+     *     feature is not enabled or FILESYSTEM_ERROR on filesystem nodes
+     *     access error.
+     */
+    getRailInfo()
+        generates(vec<RailInfo> rails, Status status);
+
+    /**
+     * Rail level energy measurements for low frequency clients:
+     * Reports accumulated energy since boot on each rail.
+     *
+     * @param railIndices Indices of rails for which data is required.
+     *     To get data for all rails pass an empty vector. Rail name to
+     *     index mapping can be queried from getRailInfo() API.
+     * @return data Energy values since boot for all requested rails.
+     * @return status SUCCESS on success or NOT_SUPPORTED if
+     *     feature is not enabled or FILESYSTEM_ERROR on filesystem nodes
+     *     access error.
+     */
+    getEnergyData(vec<uint32_t> railIndices)
+        generates(vec<EnergyData> data, Status status);
+
+    /**
+     * Stream rail level power measurements for high frequency clients:
+     * Streams accumulated energy since boot on each rail. This API is
+     * asynchronous.
+     *
+     * @param timeMs Time(in ms) for which energyData should be streamed
+     * @return mqDesc Unsynchronous Fast Message Queue descriptor - One
+     *     writer(power.stats HAL) multiple readers are supported. Reader
+     *     should read faster than writer otherwise data might be
+     *     overwritten. Data is present in following format in the queue:
+     *     +-----------------------+       <--
+     *     | EnergyData for rail 1 |         |
+     *     +-----------------------+         |
+     *     | EnergyData for rail 2 |         |
+     *     +-----------------------+         |
+     *     |          .            |         |-- 1st Sample
+     *     |          .            |         |
+     *     |          .            |         |
+     *     +-----------------------+         |
+     *     | EnergyData for rail n |         |
+     *     +-----------------------+       <--
+     *     |          .            |
+     *     |          .            |
+     *     |          .            |
+     *     +-----------------------+       <--
+     *     | EnergyData for rail 1 |         |
+     *     +-----------------------+         |
+     *     | EnergyData for rail 2 |         |
+     *     +-----------------------+         |
+     *     |          .            |         |-- kth Sample
+     *     |          .            |         |
+     *     |          .            |         |
+     *     +-----------------------+         |
+     *     | EnergyData for rail n |         |
+     *     +-----------------------+       <--
+     *
+     *     where,
+     *     n = railsPerSample
+     *     k = numSamples
+     *
+     * @return numSamples Number of samples which will be generated in timeMs.
+     * @return railsPerSample Number of rails measured per sample.
+     * @return status SUCCESS on success or FILESYSTEM_ERROR on filesystem
+     *     nodes access or NOT_SUPPORTED if feature is not enabled.
+     */
+    streamEnergyData(uint32_t timeMs)
+        generates(fmq_unsync<EnergyData> mqDesc, uint32_t numSamples,
+                uint32_t railsPerSample, Status status);
+};
diff --git a/power/stats/1.0/types.hal b/power/stats/1.0/types.hal
new file mode 100644
index 0000000..826c29b
--- /dev/null
+++ b/power/stats/1.0/types.hal
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.power.stats@1.0;
+
+enum Status : uint32_t {
+    SUCCESS = 0,
+    NOT_SUPPORTED = 1,
+    INVALID_INPUT = 2,
+    FILESYSTEM_ERROR = 3,
+};
+
+struct RailInfo {
+    /** Index corresponding to the rail */
+    uint32_t index;
+    /** Name of the rail */
+    string railName;
+    /** Name of the subsystem to which this rail belongs */
+    string subsysName;
+    /** Hardware sampling rate */
+    uint32_t samplingRate;
+};
+
+struct EnergyData {
+    /**
+     * Index corrensponding to the rail. This index matches
+     * the index returned in RailInfo
+     */
+    uint32_t index;
+    /** Time since device boot(CLOCK_BOOTTIME) in milli-seconds */
+    uint64_t timestamp;
+    /** Accumulated energy since device boot in microwatt-seconds (uWs) */
+    uint64_t energy;
+};
diff --git a/sensors/1.0/default/OWNERS b/sensors/1.0/default/OWNERS
index 6a38a1f..2031d84 100644
--- a/sensors/1.0/default/OWNERS
+++ b/sensors/1.0/default/OWNERS
@@ -1,2 +1,2 @@
-ashutoshj@google.com
-pengxu@google.com
+bduddie@google.com
+bstack@google.com
diff --git a/sensors/1.0/default/convert.cpp b/sensors/1.0/default/convert.cpp
index a5747d4..52f5e4f 100644
--- a/sensors/1.0/default/convert.cpp
+++ b/sensors/1.0/default/convert.cpp
@@ -74,8 +74,7 @@
     };
 
     switch (dst->sensorType) {
-        case SensorType::META_DATA:
-        {
+        case SensorType::META_DATA: {
             dst->u.meta.what = (MetaDataEventType)src.meta_data.what;
             // Legacy HALs contain the handle reference in the meta data field.
             // Copy that over to the handle of the event. In legacy HALs this
@@ -89,8 +88,7 @@
         case SensorType::ORIENTATION:
         case SensorType::GYROSCOPE:
         case SensorType::GRAVITY:
-        case SensorType::LINEAR_ACCELERATION:
-        {
+        case SensorType::LINEAR_ACCELERATION: {
             dst->u.vec3.x = src.acceleration.x;
             dst->u.vec3.y = src.acceleration.y;
             dst->u.vec3.z = src.acceleration.z;
@@ -98,10 +96,7 @@
             break;
         }
 
-        case SensorType::ROTATION_VECTOR:
-        case SensorType::GAME_ROTATION_VECTOR:
-        case SensorType::GEOMAGNETIC_ROTATION_VECTOR:
-        {
+        case SensorType::GAME_ROTATION_VECTOR: {
             dst->u.vec4.x = src.data[0];
             dst->u.vec4.y = src.data[1];
             dst->u.vec4.z = src.data[2];
@@ -109,151 +104,150 @@
             break;
         }
 
-      case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
-      case SensorType::GYROSCOPE_UNCALIBRATED:
-      case SensorType::ACCELEROMETER_UNCALIBRATED:
-      {
-          dst->u.uncal.x = src.uncalibrated_gyro.x_uncalib;
-          dst->u.uncal.y = src.uncalibrated_gyro.y_uncalib;
-          dst->u.uncal.z = src.uncalibrated_gyro.z_uncalib;
-          dst->u.uncal.x_bias = src.uncalibrated_gyro.x_bias;
-          dst->u.uncal.y_bias = src.uncalibrated_gyro.y_bias;
-          dst->u.uncal.z_bias = src.uncalibrated_gyro.z_bias;
-          break;
-      }
+        case SensorType::ROTATION_VECTOR:
+        case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
+            dst->u.data[0] = src.data[0];
+            dst->u.data[1] = src.data[1];
+            dst->u.data[2] = src.data[2];
+            dst->u.data[3] = src.data[3];
+            dst->u.data[4] = src.data[4];
+            break;
+        }
 
-      case SensorType::DEVICE_ORIENTATION:
-      case SensorType::LIGHT:
-      case SensorType::PRESSURE:
-      case SensorType::TEMPERATURE:
-      case SensorType::PROXIMITY:
-      case SensorType::RELATIVE_HUMIDITY:
-      case SensorType::AMBIENT_TEMPERATURE:
-      case SensorType::SIGNIFICANT_MOTION:
-      case SensorType::STEP_DETECTOR:
-      case SensorType::TILT_DETECTOR:
-      case SensorType::WAKE_GESTURE:
-      case SensorType::GLANCE_GESTURE:
-      case SensorType::PICK_UP_GESTURE:
-      case SensorType::WRIST_TILT_GESTURE:
-      case SensorType::STATIONARY_DETECT:
-      case SensorType::MOTION_DETECT:
-      case SensorType::HEART_BEAT:
-      case SensorType::LOW_LATENCY_OFFBODY_DETECT:
-      {
-          dst->u.scalar = src.data[0];
-          break;
-      }
+        case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+        case SensorType::GYROSCOPE_UNCALIBRATED:
+        case SensorType::ACCELEROMETER_UNCALIBRATED: {
+            dst->u.uncal.x = src.uncalibrated_gyro.x_uncalib;
+            dst->u.uncal.y = src.uncalibrated_gyro.y_uncalib;
+            dst->u.uncal.z = src.uncalibrated_gyro.z_uncalib;
+            dst->u.uncal.x_bias = src.uncalibrated_gyro.x_bias;
+            dst->u.uncal.y_bias = src.uncalibrated_gyro.y_bias;
+            dst->u.uncal.z_bias = src.uncalibrated_gyro.z_bias;
+            break;
+        }
 
-      case SensorType::STEP_COUNTER:
-      {
-          dst->u.stepCount = src.u64.step_counter;
-          break;
-      }
+        case SensorType::DEVICE_ORIENTATION:
+        case SensorType::LIGHT:
+        case SensorType::PRESSURE:
+        case SensorType::TEMPERATURE:
+        case SensorType::PROXIMITY:
+        case SensorType::RELATIVE_HUMIDITY:
+        case SensorType::AMBIENT_TEMPERATURE:
+        case SensorType::SIGNIFICANT_MOTION:
+        case SensorType::STEP_DETECTOR:
+        case SensorType::TILT_DETECTOR:
+        case SensorType::WAKE_GESTURE:
+        case SensorType::GLANCE_GESTURE:
+        case SensorType::PICK_UP_GESTURE:
+        case SensorType::WRIST_TILT_GESTURE:
+        case SensorType::STATIONARY_DETECT:
+        case SensorType::MOTION_DETECT:
+        case SensorType::HEART_BEAT:
+        case SensorType::LOW_LATENCY_OFFBODY_DETECT: {
+            dst->u.scalar = src.data[0];
+            break;
+        }
 
-      case SensorType::HEART_RATE:
-      {
-          dst->u.heartRate.bpm = src.heart_rate.bpm;
-          dst->u.heartRate.status = (SensorStatus)src.heart_rate.status;
-          break;
-      }
+        case SensorType::STEP_COUNTER: {
+            dst->u.stepCount = src.u64.step_counter;
+            break;
+        }
 
-      case SensorType::POSE_6DOF:  // 15 floats
-      {
-          for (size_t i = 0; i < 15; ++i) {
-              dst->u.pose6DOF[i] = src.data[i];
-          }
-          break;
-      }
+        case SensorType::HEART_RATE: {
+            dst->u.heartRate.bpm = src.heart_rate.bpm;
+            dst->u.heartRate.status = (SensorStatus)src.heart_rate.status;
+            break;
+        }
 
-      case SensorType::DYNAMIC_SENSOR_META:
-      {
-          dst->u.dynamic.connected = src.dynamic_sensor_meta.connected;
-          dst->u.dynamic.sensorHandle = src.dynamic_sensor_meta.handle;
+        case SensorType::POSE_6DOF: {  // 15 floats
+            for (size_t i = 0; i < 15; ++i) {
+                dst->u.pose6DOF[i] = src.data[i];
+            }
+            break;
+        }
 
-          memcpy(dst->u.dynamic.uuid.data(),
-                 src.dynamic_sensor_meta.uuid,
-                 16);
+        case SensorType::DYNAMIC_SENSOR_META: {
+            dst->u.dynamic.connected = src.dynamic_sensor_meta.connected;
+            dst->u.dynamic.sensorHandle = src.dynamic_sensor_meta.handle;
 
-          break;
-      }
+            memcpy(dst->u.dynamic.uuid.data(), src.dynamic_sensor_meta.uuid, 16);
 
-      case SensorType::ADDITIONAL_INFO:
-      {
-          ::android::hardware::sensors::V1_0::AdditionalInfo *dstInfo =
-              &dst->u.additional;
+            break;
+        }
 
-          const additional_info_event_t &srcInfo = src.additional_info;
+        case SensorType::ADDITIONAL_INFO: {
+            ::android::hardware::sensors::V1_0::AdditionalInfo* dstInfo = &dst->u.additional;
 
-          dstInfo->type =
-              (::android::hardware::sensors::V1_0::AdditionalInfoType)
-                  srcInfo.type;
+            const additional_info_event_t& srcInfo = src.additional_info;
 
-          dstInfo->serial = srcInfo.serial;
+            dstInfo->type = (::android::hardware::sensors::V1_0::AdditionalInfoType)srcInfo.type;
 
-          CHECK_EQ(sizeof(dstInfo->u), sizeof(srcInfo.data_int32));
-          memcpy(&dstInfo->u, srcInfo.data_int32, sizeof(srcInfo.data_int32));
-          break;
-      }
+            dstInfo->serial = srcInfo.serial;
 
-      default:
-      {
-          CHECK_GE((int32_t)dst->sensorType,
-                   (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+            CHECK_EQ(sizeof(dstInfo->u), sizeof(srcInfo.data_int32));
+            memcpy(&dstInfo->u, srcInfo.data_int32, sizeof(srcInfo.data_int32));
+            break;
+        }
 
-          memcpy(dst->u.data.data(), src.data, 16 * sizeof(float));
-          break;
-      }
-  }
+        default: {
+            CHECK_GE((int32_t)dst->sensorType, (int32_t)SensorType::DEVICE_PRIVATE_BASE);
+
+            memcpy(dst->u.data.data(), src.data, 16 * sizeof(float));
+            break;
+        }
+    }
 }
 
 void convertToSensorEvent(const Event &src, sensors_event_t *dst) {
-  *dst = {
-      .version = sizeof(sensors_event_t),
-      .sensor = src.sensorHandle,
-      .type = (int32_t)src.sensorType,
-      .reserved0 = 0,
-      .timestamp = src.timestamp
-  };
+    *dst = {.version = sizeof(sensors_event_t),
+            .sensor = src.sensorHandle,
+            .type = (int32_t)src.sensorType,
+            .reserved0 = 0,
+            .timestamp = src.timestamp};
 
-  switch (src.sensorType) {
-      case SensorType::META_DATA:
-      {
-          // Legacy HALs expect the handle reference in the meta data field.
-          // Copy it over from the handle of the event.
-          dst->meta_data.what = (int32_t)src.u.meta.what;
-          dst->meta_data.sensor = src.sensorHandle;
-          // Set the sensor handle to 0 to maintain compatibility.
-          dst->sensor = 0;
-          break;
-      }
+    switch (src.sensorType) {
+        case SensorType::META_DATA: {
+            // Legacy HALs expect the handle reference in the meta data field.
+            // Copy it over from the handle of the event.
+            dst->meta_data.what = (int32_t)src.u.meta.what;
+            dst->meta_data.sensor = src.sensorHandle;
+            // Set the sensor handle to 0 to maintain compatibility.
+            dst->sensor = 0;
+            break;
+        }
 
-      case SensorType::ACCELEROMETER:
-      case SensorType::MAGNETIC_FIELD:
-      case SensorType::ORIENTATION:
-      case SensorType::GYROSCOPE:
-      case SensorType::GRAVITY:
-      case SensorType::LINEAR_ACCELERATION:
-      {
-          dst->acceleration.x = src.u.vec3.x;
-          dst->acceleration.y = src.u.vec3.y;
-          dst->acceleration.z = src.u.vec3.z;
-          dst->acceleration.status = (int8_t)src.u.vec3.status;
-          break;
-      }
+        case SensorType::ACCELEROMETER:
+        case SensorType::MAGNETIC_FIELD:
+        case SensorType::ORIENTATION:
+        case SensorType::GYROSCOPE:
+        case SensorType::GRAVITY:
+        case SensorType::LINEAR_ACCELERATION: {
+            dst->acceleration.x = src.u.vec3.x;
+            dst->acceleration.y = src.u.vec3.y;
+            dst->acceleration.z = src.u.vec3.z;
+            dst->acceleration.status = (int8_t)src.u.vec3.status;
+            break;
+        }
 
-      case SensorType::ROTATION_VECTOR:
-      case SensorType::GAME_ROTATION_VECTOR:
-      case SensorType::GEOMAGNETIC_ROTATION_VECTOR:
-      {
-          dst->data[0] = src.u.vec4.x;
-          dst->data[1] = src.u.vec4.y;
-          dst->data[2] = src.u.vec4.z;
-          dst->data[3] = src.u.vec4.w;
-          break;
-      }
+        case SensorType::GAME_ROTATION_VECTOR: {
+            dst->data[0] = src.u.vec4.x;
+            dst->data[1] = src.u.vec4.y;
+            dst->data[2] = src.u.vec4.z;
+            dst->data[3] = src.u.vec4.w;
+            break;
+        }
 
-      case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+        case SensorType::ROTATION_VECTOR:
+        case SensorType::GEOMAGNETIC_ROTATION_VECTOR: {
+            dst->data[0] = src.u.data[0];
+            dst->data[1] = src.u.data[1];
+            dst->data[2] = src.u.data[2];
+            dst->data[3] = src.u.data[3];
+            dst->data[4] = src.u.data[4];
+            break;
+        }
+
+        case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
         case SensorType::GYROSCOPE_UNCALIBRATED:
         case SensorType::ACCELEROMETER_UNCALIBRATED:
         {
@@ -283,35 +277,30 @@
         case SensorType::STATIONARY_DETECT:
         case SensorType::MOTION_DETECT:
         case SensorType::HEART_BEAT:
-        case SensorType::LOW_LATENCY_OFFBODY_DETECT:
-        {
+        case SensorType::LOW_LATENCY_OFFBODY_DETECT: {
             dst->data[0] = src.u.scalar;
             break;
         }
 
-        case SensorType::STEP_COUNTER:
-        {
+        case SensorType::STEP_COUNTER: {
             dst->u64.step_counter = src.u.stepCount;
             break;
         }
 
-        case SensorType::HEART_RATE:
-        {
+        case SensorType::HEART_RATE: {
             dst->heart_rate.bpm = src.u.heartRate.bpm;
             dst->heart_rate.status = (int8_t)src.u.heartRate.status;
             break;
         }
 
-        case SensorType::POSE_6DOF:  // 15 floats
-        {
+        case SensorType::POSE_6DOF: {  // 15 floats
             for (size_t i = 0; i < 15; ++i) {
                 dst->data[i] = src.u.pose6DOF[i];
             }
             break;
         }
 
-        case SensorType::DYNAMIC_SENSOR_META:
-        {
+        case SensorType::DYNAMIC_SENSOR_META: {
             dst->dynamic_sensor_meta.connected = src.u.dynamic.connected;
             dst->dynamic_sensor_meta.handle = src.u.dynamic.sensorHandle;
             dst->dynamic_sensor_meta.sensor = NULL;  // to be filled in later
@@ -323,8 +312,7 @@
             break;
         }
 
-        case SensorType::ADDITIONAL_INFO:
-        {
+        case SensorType::ADDITIONAL_INFO: {
             const ::android::hardware::sensors::V1_0::AdditionalInfo &srcInfo =
                 src.u.additional;
 
@@ -341,8 +329,7 @@
             break;
         }
 
-        default:
-        {
+        default: {
             CHECK_GE((int32_t)src.sensorType,
                      (int32_t)SensorType::DEVICE_PRIVATE_BASE);
 
diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp
index 0ea400e..6563e3c 100644
--- a/sensors/1.0/vts/functional/Android.bp
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -18,13 +18,14 @@
     name: "VtsHalSensorsV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
-        "GrallocWrapper.cpp",
+        "SensorsHidlEnvironmentV1_0.cpp",
         "VtsHalSensorsV1_0TargetTest.cpp"
     ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.sensors@1.0",
+        "VtsHalSensorsTargetTestUtils",
     ],
 }
 
diff --git a/sensors/1.0/vts/functional/GrallocWrapper.cpp b/sensors/1.0/vts/functional/GrallocWrapper.cpp
deleted file mode 100644
index e422d62..0000000
--- a/sensors/1.0/vts/functional/GrallocWrapper.cpp
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "GrallocWrapper"
-
-#include "GrallocWrapper.h"
-
-#include <utils/Log.h>
-
-namespace android {
-
-GrallocWrapper::GrallocWrapper() { init(); }
-
-void GrallocWrapper::init() {
-  mAllocator = allocator2::IAllocator::getService();
-  if (mAllocator == nullptr) {
-    ALOGE("Failed to get allocator service");
-  }
-
-  mMapper = mapper2::IMapper::getService();
-  if (mMapper == nullptr) {
-    ALOGE("Failed to get mapper service");
-  }
-  if (mMapper->isRemote()) {
-    ALOGE("Mapper is not in passthrough mode");
-  }
-}
-
-GrallocWrapper::~GrallocWrapper() {
-  for (auto bufferHandle : mClonedBuffers) {
-    auto buffer = const_cast<native_handle_t*>(bufferHandle);
-    native_handle_close(buffer);
-    native_handle_delete(buffer);
-  }
-  mClonedBuffers.clear();
-
-  for (auto bufferHandle : mImportedBuffers) {
-    auto buffer = const_cast<native_handle_t*>(bufferHandle);
-    if (mMapper->freeBuffer(buffer) != mapper2::Error::NONE) {
-      ALOGE("Failed to free buffer %p", buffer);
-    }
-  }
-  mImportedBuffers.clear();
-}
-
-sp<allocator2::IAllocator> GrallocWrapper::getAllocator() const {
-  return mAllocator;
-}
-
-std::string GrallocWrapper::dumpDebugInfo() {
-  std::string debugInfo;
-  mAllocator->dumpDebugInfo(
-      [&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
-
-  return debugInfo;
-}
-
-const native_handle_t* GrallocWrapper::cloneBuffer(
-    const hardware::hidl_handle& rawHandle) {
-  const native_handle_t* bufferHandle =
-      native_handle_clone(rawHandle.getNativeHandle());
-
-  if (bufferHandle) {
-    mClonedBuffers.insert(bufferHandle);
-  }
-  return bufferHandle;
-}
-
-std::vector<const native_handle_t*> GrallocWrapper::allocate(
-    const mapper2::BufferDescriptor& descriptor, uint32_t count, bool import,
-    uint32_t* outStride) {
-  std::vector<const native_handle_t*> bufferHandles;
-  bufferHandles.reserve(count);
-  mAllocator->allocate(
-      descriptor, count,
-      [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
-        if (mapper2::Error::NONE != tmpError) {
-          ALOGE("Failed to allocate buffers");
-        }
-        if (count != tmpBuffers.size()) {
-          ALOGE("Invalid buffer array");
-        }
-
-        for (uint32_t i = 0; i < count; i++) {
-          if (import) {
-            bufferHandles.push_back(importBuffer(tmpBuffers[i]));
-          } else {
-            bufferHandles.push_back(cloneBuffer(tmpBuffers[i]));
-          }
-        }
-
-        if (outStride) {
-          *outStride = tmpStride;
-        }
-      });
-
-  return bufferHandles;
-}
-
-const native_handle_t* GrallocWrapper::allocate(
-    const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo, bool import,
-    uint32_t* outStride) {
-  mapper2::BufferDescriptor descriptor = createDescriptor(descriptorInfo);
-  ALOGE("QQ");
-  auto buffers = allocate(descriptor, 1, import, outStride);
-  return buffers[0];
-}
-
-sp<mapper2::IMapper> GrallocWrapper::getMapper() const { return mMapper; }
-
-mapper2::BufferDescriptor GrallocWrapper::createDescriptor(
-    const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo) {
-  mapper2::BufferDescriptor descriptor;
-  mMapper->createDescriptor(
-      descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
-        if (tmpError != mapper2::Error::NONE) {
-          ALOGE("Failed to create descriptor");
-        }
-        descriptor = tmpDescriptor;
-      });
-
-  return descriptor;
-}
-
-const native_handle_t* GrallocWrapper::importBuffer(
-    const hardware::hidl_handle& rawHandle) {
-  const native_handle_t* bufferHandle = nullptr;
-  mMapper->importBuffer(
-      rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
-        if (tmpError != mapper2::Error::NONE) {
-          ALOGE("Failed to import buffer %p", rawHandle.getNativeHandle());
-        }
-        bufferHandle = static_cast<const native_handle_t*>(tmpBuffer);
-      });
-
-  if (bufferHandle) {
-    mImportedBuffers.insert(bufferHandle);
-  }
-
-  return bufferHandle;
-}
-
-void GrallocWrapper::freeBuffer(const native_handle_t* bufferHandle) {
-  auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
-  if (mImportedBuffers.erase(bufferHandle)) {
-    mapper2::Error error = mMapper->freeBuffer(buffer);
-    if (error != mapper2::Error::NONE) {
-      ALOGE("Failed to free %p", buffer);
-    }
-  } else {
-    mClonedBuffers.erase(bufferHandle);
-    native_handle_close(buffer);
-    native_handle_delete(buffer);
-  }
-}
-
-void* GrallocWrapper::lock(const native_handle_t* bufferHandle,
-                           uint64_t cpuUsage,
-                           const mapper2::IMapper::Rect& accessRegion,
-                           int acquireFence) {
-  auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
-  NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
-  hardware::hidl_handle acquireFenceHandle;
-  if (acquireFence >= 0) {
-    auto h = native_handle_init(acquireFenceStorage, 1, 0);
-    h->data[0] = acquireFence;
-    acquireFenceHandle = h;
-  }
-
-  void* data = nullptr;
-  mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
-                [&](const auto& tmpError, const auto& tmpData) {
-                  if (tmpError != mapper2::Error::NONE) {
-                    ALOGE("Failed to lock buffer %p", buffer);
-                  }
-                  data = tmpData;
-                });
-
-  if (acquireFence >= 0) {
-    close(acquireFence);
-  }
-
-  return data;
-}
-
-int GrallocWrapper::unlock(const native_handle_t* bufferHandle) {
-  auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
-  int releaseFence = -1;
-  mMapper->unlock(buffer, [&](const auto& tmpError,
-                              const auto& tmpReleaseFence) {
-    if (tmpError != mapper2::Error::NONE) {
-      ALOGE("Failed to unlock buffer %p", buffer);
-    }
-
-    auto fenceHandle = tmpReleaseFence.getNativeHandle();
-    if (fenceHandle) {
-      if (fenceHandle->numInts != 0) {
-        ALOGE("Invalid fence handle %p", fenceHandle);
-      }
-      if (fenceHandle->numFds == 1) {
-        releaseFence = dup(fenceHandle->data[0]);
-        if (releaseFence < 0){
-          ALOGE("Failed to dup fence fd");
-        }
-      } else {
-        if (fenceHandle->numFds != 0) {
-          ALOGE("Invalid fence handle %p", fenceHandle);
-        }
-      }
-    }
-  });
-
-  return releaseFence;
-}
-
-}  // namespace android
diff --git a/sensors/1.0/vts/functional/GrallocWrapper.h b/sensors/1.0/vts/functional/GrallocWrapper.h
deleted file mode 100644
index e506fe1..0000000
--- a/sensors/1.0/vts/functional/GrallocWrapper.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef GRALLO_WRAPPER_H_
-#define GRALLO_WRAPPER_H_
-
-#include <unordered_set>
-
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-
-namespace allocator2 = ::android::hardware::graphics::allocator::V2_0;
-namespace mapper2 = ::android::hardware::graphics::mapper::V2_0;
-
-namespace android {
-
-// Modified from hardware/interfaces/graphics/mapper/2.0/vts/functional/
-class GrallocWrapper {
- public:
-  GrallocWrapper();
-  ~GrallocWrapper();
-
-  sp<allocator2::IAllocator> getAllocator() const;
-  sp<mapper2::IMapper> getMapper() const;
-
-  std::string dumpDebugInfo();
-
-  // When import is false, this simply calls IAllocator::allocate. When import
-  // is true, the returned buffers are also imported into the mapper.
-  //
-  // Either case, the returned buffers must be freed with freeBuffer.
-  std::vector<const native_handle_t*> allocate(
-      const mapper2::BufferDescriptor& descriptor, uint32_t count, bool import = true,
-      uint32_t* outStride = nullptr);
-  const native_handle_t* allocate(
-      const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo, bool import = true,
-      uint32_t* outStride = nullptr);
-
-  mapper2::BufferDescriptor createDescriptor(
-      const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo);
-
-  const native_handle_t* importBuffer(const hardware::hidl_handle& rawHandle);
-  void freeBuffer(const native_handle_t* bufferHandle);
-
-  // We use fd instead of hardware::hidl_handle in these functions to pass fences
-  // in and out of the mapper.  The ownership of the fd is always transferred
-  // with each of these functions.
-  void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
-             const mapper2::IMapper::Rect& accessRegion, int acquireFence);
-
-  int unlock(const native_handle_t* bufferHandle);
-
- private:
-  void init();
-  const native_handle_t* cloneBuffer(const hardware::hidl_handle& rawHandle);
-
-  sp<allocator2::IAllocator> mAllocator;
-  sp<mapper2::IMapper> mMapper;
-
-  // Keep track of all cloned and imported handles.  When a test fails with
-  // ASSERT_*, the destructor will free the handles for the test.
-  std::unordered_set<const native_handle_t*> mClonedBuffers;
-  std::unordered_set<const native_handle_t*> mImportedBuffers;
-};
-
-}  // namespace android
-#endif  // GRALLO_WRAPPER_H_
diff --git a/sensors/1.0/vts/functional/OWNERS b/sensors/1.0/vts/functional/OWNERS
index 8715e5d..759d87b 100644
--- a/sensors/1.0/vts/functional/OWNERS
+++ b/sensors/1.0/vts/functional/OWNERS
@@ -1,6 +1,6 @@
 # Sensors team
-ashutoshj@google.com
-pengxu@google.com
+bduddie@google.com
+bstack@google.com
 
 # VTS team
 trong@google.com
diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
new file mode 100644
index 0000000..f8b021e
--- /dev/null
+++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SensorsHidlEnvironmentV1_0.h"
+
+#include <log/log.h>
+
+#include <vector>
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::sensors::V1_0::ISensors;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+
+bool SensorsHidlEnvironmentV1_0::resetHal() {
+    // wait upto 100ms * 10 = 1s for hidl service.
+    constexpr auto RETRY_DELAY = std::chrono::milliseconds(100);
+
+    std::string step;
+    bool succeed = false;
+    for (size_t retry = 10; retry > 0; --retry) {
+        // this do ... while is for easy error handling
+        do {
+            step = "getService()";
+            sensors = ISensors::getService(
+                SensorsHidlEnvironmentV1_0::Instance()->getServiceName<ISensors>());
+            if (sensors == nullptr) {
+                break;
+            }
+
+            step = "poll() check";
+            // Poke ISensor service. If it has lingering connection from previous generation of
+            // system server, it will kill itself. There is no intention to handle the poll result,
+            // which will be done since the size is 0.
+            if (!sensors->poll(0, [](auto, const auto&, const auto&) {}).isOk()) {
+                break;
+            }
+
+            step = "getSensorList";
+            std::vector<SensorInfo> sensorList;
+            if (!sensors
+                     ->getSensorsList([&](const hidl_vec<SensorInfo>& list) {
+                         sensorList.reserve(list.size());
+                         for (size_t i = 0; i < list.size(); ++i) {
+                             sensorList.push_back(list[i]);
+                         }
+                     })
+                     .isOk()) {
+                break;
+            }
+
+            // stop each sensor individually
+            step = "stop each sensor";
+            bool ok = true;
+            for (const auto& i : sensorList) {
+                if (!sensors->activate(i.sensorHandle, false).isOk()) {
+                    ok = false;
+                    break;
+                }
+            }
+            if (!ok) {
+                break;
+            }
+
+            // mark it done
+            step = "done";
+            succeed = true;
+        } while (0);
+
+        if (succeed) {
+            return true;
+        }
+
+        // Delay 100ms before retry, hidl service is expected to come up in short time after crash.
+        ALOGI("%s unsuccessful, try again soon (remaining retry %zu).", step.c_str(), retry - 1);
+        std::this_thread::sleep_for(RETRY_DELAY);
+    }
+
+    sensors = nullptr;
+    return false;
+}
+
+void SensorsHidlEnvironmentV1_0::startPollingThread() {
+    stopThread = false;
+    pollThread = std::thread(pollingThread, this, std::ref(stopThread));
+    events.reserve(128);
+}
+
+void SensorsHidlEnvironmentV1_0::pollingThread(SensorsHidlEnvironmentV1_0* env,
+                                               std::atomic_bool& stop) {
+    ALOGD("polling thread start");
+
+    while (!stop) {
+        env->sensors->poll(
+            64, [&](auto result, const auto& events, const auto& dynamicSensorsAdded) {
+                if (result != Result::OK ||
+                    (events.size() == 0 && dynamicSensorsAdded.size() == 0) || stop) {
+                    stop = true;
+                    return;
+                }
+
+                for (const auto& e : events) {
+                    env->addEvent(e);
+                }
+            });
+    }
+    ALOGD("polling thread end");
+}
\ No newline at end of file
diff --git a/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h
new file mode 100644
index 0000000..0a9e59f
--- /dev/null
+++ b/sensors/1.0/vts/functional/SensorsHidlEnvironmentV1_0.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SENSORS_HIDL_ENVIRONMENT_V1_0_H
+#define ANDROID_SENSORS_HIDL_ENVIRONMENT_V1_0_H
+
+#include "sensors-vts-utils/SensorsHidlEnvironmentBase.h"
+
+#include <android/hardware/sensors/1.0/ISensors.h>
+#include <android/hardware/sensors/1.0/types.h>
+#include <utils/StrongPointer.h>
+
+#include <atomic>
+#include <memory>
+
+using ::android::sp;
+
+class SensorsHidlTest;
+class SensorsHidlEnvironmentV1_0 : public SensorsHidlEnvironmentBase {
+   public:
+    using Event = ::android::hardware::sensors::V1_0::Event;
+    // get the test environment singleton
+    static SensorsHidlEnvironmentV1_0* Instance() {
+        static SensorsHidlEnvironmentV1_0* instance = new SensorsHidlEnvironmentV1_0();
+        return instance;
+    }
+
+    virtual void registerTestServices() override {
+        registerTestService<android::hardware::sensors::V1_0::ISensors>();
+    }
+
+   private:
+    friend SensorsHidlTest;
+    // sensors hidl service
+    sp<android::hardware::sensors::V1_0::ISensors> sensors;
+
+    SensorsHidlEnvironmentV1_0() {}
+
+    bool resetHal() override;
+    void startPollingThread() override;
+    static void pollingThread(SensorsHidlEnvironmentV1_0* env, std::atomic_bool& stop);
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentV1_0);
+};
+
+#endif  // ANDROID_SENSORS_HIDL_ENVIRONMENT_V1_0_H
\ No newline at end of file
diff --git a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
index c18eedd..47308e1 100644
--- a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
+++ b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
@@ -15,583 +15,66 @@
  */
 
 #define LOG_TAG "sensors_hidl_hal_test"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-#include <android-base/logging.h>
+
+#include "SensorsHidlEnvironmentV1_0.h"
+#include "sensors-vts-utils/SensorsHidlTestBase.h"
+
 #include <android/hardware/sensors/1.0/ISensors.h>
 #include <android/hardware/sensors/1.0/types.h>
-#include <cutils/ashmem.h>
-#include <hardware/sensors.h>  // for sensor type strings
 #include <log/log.h>
 #include <utils/SystemClock.h>
-#include "GrallocWrapper.h"
 
-#include <algorithm>
 #include <cinttypes>
-#include <cmath>
-#include <memory>
-#include <mutex>
-#include <thread>
-#include <unordered_set>
 #include <vector>
 
-#include <sys/mman.h>
-#include <unistd.h>
-
-using ::android::GrallocWrapper;
 using ::android::hardware::Return;
 using ::android::hardware::Void;
-using ::android::hardware::hidl_string;
 using ::android::sp;
 using namespace ::android::hardware::sensors::V1_0;
 
-// Test environment for sensors
-class SensorsHidlTest;
-class SensorsHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static SensorsHidlEnvironment* Instance() {
-        static SensorsHidlEnvironment* instance = new SensorsHidlEnvironment;
-        return instance;
-    }
-
-    virtual void HidlSetUp() override;
-    virtual void HidlTearDown() override;
-
-    virtual void registerTestServices() override { registerTestService<ISensors>(); }
-
-    // Get and clear all events collected so far (like "cat" shell command).
-    // If output is nullptr, it clears all collected events.
-    void catEvents(std::vector<Event>* output);
-
-    // set sensor event collection status
-    void setCollection(bool enable);
-
-   private:
-    friend SensorsHidlTest;
-    // sensors hidl service
-    sp<ISensors> sensors;
-
-    SensorsHidlEnvironment() {}
-
-    void addEvent(const Event& ev);
-    void startPollingThread();
-    void resetHal();
-    static void pollingThread(SensorsHidlEnvironment* env, std::shared_ptr<bool> stop);
-
-    bool collectionEnabled;
-    std::shared_ptr<bool> stopThread;
-    std::thread pollThread;
-    std::vector<Event> events;
-    std::mutex events_mutex;
-
-    GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironment);
-};
-
-void SensorsHidlEnvironment::HidlSetUp() {
-    resetHal();
-
-    ASSERT_NE(sensors, nullptr) << "sensors is nullptr, cannot get hidl service";
-
-    collectionEnabled = false;
-    startPollingThread();
-
-    // In case framework just stopped for test and there is sensor events in the pipe,
-    // wait some time for those events to be cleared to avoid them messing up the test.
-    std::this_thread::sleep_for(std::chrono::seconds(3));
-}
-
-void SensorsHidlEnvironment::HidlTearDown() {
-    if (stopThread) {
-        *stopThread = true;
-    }
-    pollThread.detach();
-}
-
-void SensorsHidlEnvironment::resetHal() {
-  // wait upto 100ms * 10 = 1s for hidl service.
-  constexpr auto RETRY_DELAY = std::chrono::milliseconds(100);
-
-  std::string step;
-  bool succeed = false;
-  for (size_t retry = 10; retry > 0; --retry) {
-    // this do ... while is for easy error handling
-    do {
-      step = "getService()";
-      sensors = ISensors::getService(
-          SensorsHidlEnvironment::Instance()->getServiceName<ISensors>());
-      if (sensors == nullptr) {
-        break;
-      }
-
-      step = "poll() check";
-      // Poke ISensor service. If it has lingering connection from previous generation of
-      // system server, it will kill itself. There is no intention to handle the poll result,
-      // which will be done since the size is 0.
-      if(!sensors->poll(0, [](auto, const auto &, const auto &) {}).isOk()) {
-        break;
-      }
-
-      step = "getSensorList";
-      std::vector<SensorInfo> sensorList;
-      if (!sensors->getSensorsList(
-          [&] (const ::android::hardware::hidl_vec<SensorInfo> &list) {
-            sensorList.reserve(list.size());
-            for (size_t i = 0; i < list.size(); ++i) {
-              sensorList.push_back(list[i]);
-            }
-          }).isOk()) {
-        break;
-      }
-
-      // stop each sensor individually
-      step = "stop each sensor";
-      bool ok = true;
-      for (const auto &i : sensorList) {
-        if (!sensors->activate(i.sensorHandle, false).isOk()) {
-          ok = false;
-          break;
-        }
-      }
-      if (!ok) {
-        break;
-      }
-
-      // mark it done
-      step = "done";
-      succeed = true;
-    } while(0);
-
-    if (succeed) {
-      return;
-    }
-
-    // Delay 100ms before retry, hidl service is expected to come up in short time after crash.
-    ALOGI("%s unsuccessful, try again soon (remaining retry %zu).", step.c_str(), retry - 1);
-    std::this_thread::sleep_for(RETRY_DELAY);
-  }
-
-  sensors = nullptr;
-}
-
-void SensorsHidlEnvironment::catEvents(std::vector<Event>* output) {
-  std::lock_guard<std::mutex> lock(events_mutex);
-  if (output) {
-    output->insert(output->end(), events.begin(), events.end());
-  }
-  events.clear();
-}
-
-void SensorsHidlEnvironment::setCollection(bool enable) {
-  std::lock_guard<std::mutex> lock(events_mutex);
-  collectionEnabled = enable;
-}
-
-void SensorsHidlEnvironment::addEvent(const Event& ev) {
-  std::lock_guard<std::mutex> lock(events_mutex);
-  if (collectionEnabled) {
-    events.push_back(ev);
-  }
-}
-
-void SensorsHidlEnvironment::startPollingThread() {
-  stopThread = std::shared_ptr<bool>(new bool(false));
-  pollThread = std::thread(pollingThread, this, stopThread);
-  events.reserve(128);
-}
-
-void SensorsHidlEnvironment::pollingThread(
-    SensorsHidlEnvironment* env, std::shared_ptr<bool> stop) {
-  ALOGD("polling thread start");
-  bool needExit = *stop;
-
-  while(!needExit) {
-      env->sensors->poll(64, [&](auto result, const auto& events, const auto& dynamicSensorsAdded) {
-          if (result != Result::OK
-              || (events.size() == 0 && dynamicSensorsAdded.size() == 0)
-              || *stop) {
-              needExit = true;
-              return;
-          }
-
-          for (const auto& e : events) {
-              env->addEvent(e);
-          }
-      });
-  }
-  ALOGD("polling thread end");
-}
-
-class SensorsTestSharedMemory {
- public:
-  static SensorsTestSharedMemory* create(SharedMemType type, size_t size);
-  SharedMemInfo getSharedMemInfo() const;
-  char * getBuffer() const;
-  std::vector<Event> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const;
-  virtual ~SensorsTestSharedMemory();
- private:
-  SensorsTestSharedMemory(SharedMemType type, size_t size);
-
-  SharedMemType mType;
-  native_handle_t* mNativeHandle;
-  size_t mSize;
-  char* mBuffer;
-  std::unique_ptr<GrallocWrapper> mGrallocWrapper;
-
-  DISALLOW_COPY_AND_ASSIGN(SensorsTestSharedMemory);
-};
-
-SharedMemInfo SensorsTestSharedMemory::getSharedMemInfo() const {
-  SharedMemInfo mem = {
-    .type = mType,
-    .format = SharedMemFormat::SENSORS_EVENT,
-    .size = static_cast<uint32_t>(mSize),
-    .memoryHandle = mNativeHandle
-  };
-  return mem;
-}
-
-char * SensorsTestSharedMemory::getBuffer() const {
-  return mBuffer;
-}
-
-std::vector<Event> SensorsTestSharedMemory::parseEvents(int64_t lastCounter, size_t offset) const {
-
-  constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
-  constexpr size_t kOffsetSize = static_cast<size_t>(SensorsEventFormatOffset::SIZE_FIELD);
-  constexpr size_t kOffsetToken = static_cast<size_t>(SensorsEventFormatOffset::REPORT_TOKEN);
-  constexpr size_t kOffsetType = static_cast<size_t>(SensorsEventFormatOffset::SENSOR_TYPE);
-  constexpr size_t kOffsetAtomicCounter =
-      static_cast<size_t>(SensorsEventFormatOffset::ATOMIC_COUNTER);
-  constexpr size_t kOffsetTimestamp = static_cast<size_t>(SensorsEventFormatOffset::TIMESTAMP);
-  constexpr size_t kOffsetData = static_cast<size_t>(SensorsEventFormatOffset::DATA);
-
-  std::vector<Event> events;
-  std::vector<float> data(16);
-
-  while (offset + kEventSize <= mSize) {
-    int64_t atomicCounter = *reinterpret_cast<uint32_t *>(mBuffer + offset + kOffsetAtomicCounter);
-    if (atomicCounter <= lastCounter) {
-      ALOGV("atomicCounter = %" PRId64 ", lastCounter = %" PRId64, atomicCounter, lastCounter);
-      break;
-    }
-
-    int32_t size = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetSize);
-    if (size != kEventSize) {
-      // unknown error, events parsed may be wrong, remove all
-      events.clear();
-      break;
-    }
-
-    int32_t token = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetToken);
-    int32_t type = *reinterpret_cast<int32_t *>(mBuffer + offset + kOffsetType);
-    int64_t timestamp = *reinterpret_cast<int64_t *>(mBuffer + offset + kOffsetTimestamp);
-
-    ALOGV("offset = %zu, cnt %" PRId64 ", token %" PRId32 ", type %" PRId32 ", timestamp %" PRId64,
-        offset, atomicCounter, token, type, timestamp);
-
-    Event event = {
-      .timestamp = timestamp,
-      .sensorHandle = token,
-      .sensorType = static_cast<SensorType>(type),
-    };
-    event.u.data = android::hardware::hidl_array<float, 16>
-        (reinterpret_cast<float*>(mBuffer + offset + kOffsetData));
-
-    events.push_back(event);
-
-    lastCounter = atomicCounter;
-    offset += kEventSize;
-  }
-
-  return events;
-}
-
-SensorsTestSharedMemory::SensorsTestSharedMemory(SharedMemType type, size_t size)
-    : mType(type), mSize(0), mBuffer(nullptr) {
-  native_handle_t *handle = nullptr;
-  char *buffer = nullptr;
-  switch(type) {
-    case SharedMemType::ASHMEM: {
-      int fd;
-      handle = ::native_handle_create(1 /*nFds*/, 0/*nInts*/);
-      if (handle != nullptr) {
-        handle->data[0] = fd = ::ashmem_create_region("SensorsTestSharedMemory", size);
-        if (handle->data[0] > 0) {
-          // memory is pinned by default
-          buffer = static_cast<char *>
-              (::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
-          if (buffer != reinterpret_cast<char*>(MAP_FAILED)) {
-            break;
-          }
-          ::native_handle_close(handle);
-        }
-        ::native_handle_delete(handle);
-        handle = nullptr;
-      }
-      break;
-    }
-    case SharedMemType::GRALLOC: {
-      mGrallocWrapper = std::make_unique<GrallocWrapper>();
-      if (mGrallocWrapper->getAllocator() == nullptr || mGrallocWrapper->getMapper() == nullptr) {
-        break;
-      }
-      using android::hardware::graphics::common::V1_0::BufferUsage;
-      using android::hardware::graphics::common::V1_0::PixelFormat;
-      mapper2::IMapper::BufferDescriptorInfo buf_desc_info = {
-        .width = static_cast<uint32_t>(size),
-        .height = 1,
-        .layerCount = 1,
-        .usage = static_cast<uint64_t> (BufferUsage::SENSOR_DIRECT_DATA |
-            BufferUsage::CPU_READ_OFTEN),
-        .format = PixelFormat::BLOB
-      };
-
-      handle = const_cast<native_handle_t *>(mGrallocWrapper->allocate(buf_desc_info));
-      if (handle != nullptr) {
-        mapper2::IMapper::Rect region{0, 0,
-            static_cast<int32_t>(buf_desc_info.width),
-            static_cast<int32_t>(buf_desc_info.height)};
-        buffer = static_cast<char *>
-                (mGrallocWrapper->lock(handle, buf_desc_info.usage, region, /*fence=*/-1));
-        if (buffer != nullptr) {
-          break;
-        }
-        mGrallocWrapper->freeBuffer(handle);
-        handle = nullptr;
-      }
-      break;
-    }
-    default:
-      break;
-  }
-
-  if (buffer != nullptr) {
-    mNativeHandle = handle;
-    mSize = size;
-    mBuffer = buffer;
-  }
-}
-
-SensorsTestSharedMemory::~SensorsTestSharedMemory() {
-  switch(mType) {
-    case SharedMemType::ASHMEM: {
-      if (mSize != 0) {
-        ::munmap(mBuffer, mSize);
-        mBuffer = nullptr;
-
-        ::native_handle_close(mNativeHandle);
-        ::native_handle_delete(mNativeHandle);
-
-        mNativeHandle = nullptr;
-        mSize = 0;
-      }
-      break;
-    }
-    case SharedMemType::GRALLOC: {
-      if (mSize != 0) {
-        mGrallocWrapper->unlock(mNativeHandle);
-        mGrallocWrapper->freeBuffer(mNativeHandle);
-
-        mNativeHandle = nullptr;
-        mSize = 0;
-      }
-      break;
-    }
-    default: {
-      if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) {
-        ALOGE("SensorsTestSharedMemory %p not properly destructed: "
-            "type %d, native handle %p, size %zu, buffer %p",
-            this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer);
-      }
-      break;
-    }
-  }
-}
-
-SensorsTestSharedMemory* SensorsTestSharedMemory::create(SharedMemType type, size_t size) {
-  constexpr size_t kMaxSize = 128*1024*1024; // sensor test should not need more than 128M
-  if (size == 0 || size >= kMaxSize) {
-    return nullptr;
-  }
-
-  auto m = new SensorsTestSharedMemory(type, size);
-  if (m->mSize != size || m->mBuffer == nullptr) {
-    delete m;
-    m = nullptr;
-  }
-  return m;
-}
-
-class SensorEventsChecker {
- public:
-  virtual bool check(const std::vector<Event> &events, std::string *out) const = 0;
-  virtual ~SensorEventsChecker() {}
-};
-
-class NullChecker : public SensorEventsChecker {
- public:
-  virtual bool check(const std::vector<Event> &, std::string *) const {
-    return true;
-  }
-};
-
-class SensorEventPerEventChecker : public SensorEventsChecker {
- public:
-  virtual bool checkEvent(const Event &event, std::string *out) const = 0;
-  virtual bool check(const std::vector<Event> &events, std::string *out) const {
-    for (const auto &e : events) {
-      if (!checkEvent(e, out)) {
-        return false;
-      }
-    }
-    return true;
-  }
-};
-
-class Vec3NormChecker : public SensorEventPerEventChecker {
- public:
-  Vec3NormChecker(float min, float max) : mRange(min, max) {}
-  static Vec3NormChecker byNominal(float nominal, float allowedError) {
-    return Vec3NormChecker(nominal - allowedError, nominal + allowedError);
-  }
-
-  virtual bool checkEvent(const Event &event, std::string *out) const {
-    Vec3 v = event.u.vec3;
-    float norm = std::sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
-    if (norm < mRange.first || norm > mRange.second) {
-      if (out != nullptr) {
-        std::ostringstream ss;
-        ss << "Event @ " << event.timestamp << " (" << v.x << ", " << v.y << ", " << v.z << ")"
-           << " has norm " << norm << ", which is beyond range"
-           << " [" << mRange.first << ", " << mRange.second << "]";
-        *out = ss.str();
-      }
-      return false;
-    }
-    return true;
-  }
- protected:
-  std::pair<float, float> mRange;
-};
-
 // The main test class for SENSORS HIDL HAL.
-class SensorsHidlTest : public ::testing::VtsHalHidlTargetTestBase {
- public:
-  virtual void SetUp() override {
-  }
 
-  virtual void TearDown() override {
-    // stop all sensors
-    for (auto s : mSensorHandles) {
-      S()->activate(s, false);
+class SensorsHidlTest : public SensorsHidlTestBase {
+   protected:
+    SensorInfo defaultSensorByType(SensorType type) override;
+    std::vector<SensorInfo> getSensorsList();
+    // implementation wrapper
+    Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) override {
+        return S()->getSensorsList(_hidl_cb);
     }
-    mSensorHandles.clear();
 
-    // stop all direct report and channels
-    for (auto c : mDirectChannelHandles) {
-      // disable all reports
-      S()->configDirectReport(-1, c, RateLevel::STOP, [] (auto, auto){});
-      S()->unregisterDirectChannel(c);
+    Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t maxReportLatencyNs) override {
+        return S()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
     }
-    mDirectChannelHandles.clear();
-  }
 
- protected:
-  SensorInfo defaultSensorByType(SensorType type);
-  std::vector<SensorInfo> getSensorsList();
-  std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
-        bool clearBeforeStart = true, bool changeCollection = true);
+    Return<Result> flush(int32_t sensorHandle) override { return S()->flush(sensorHandle); }
 
-  // implementation wrapper
-  Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) {
-    return S()->getSensorsList(_hidl_cb);
-  }
+    Return<Result> injectSensorData(const Event& event) override {
+        return S()->injectSensorData(event);
+    }
 
-  Return<Result> activate(
-          int32_t sensorHandle, bool enabled);
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       ISensors::registerDirectChannel_cb _hidl_cb) override;
 
-  Return<Result> batch(
-          int32_t sensorHandle,
-          int64_t samplingPeriodNs,
-          int64_t maxReportLatencyNs) {
-    return S()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
-  }
+    Return<Result> unregisterDirectChannel(int32_t channelHandle) override {
+        return S()->unregisterDirectChannel(channelHandle);
+    }
 
-  Return<Result> flush(int32_t sensorHandle) {
-    return S()->flush(sensorHandle);
-  }
+    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+                                    ISensors::configDirectReport_cb _hidl_cb) override {
+        return S()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
+    }
 
-  Return<Result> injectSensorData(const Event& event) {
-    return S()->injectSensorData(event);
-  }
+    inline sp<ISensors>& S() { return SensorsHidlEnvironmentV1_0::Instance()->sensors; }
 
-  Return<void> registerDirectChannel(
-          const SharedMemInfo& mem, ISensors::registerDirectChannel_cb _hidl_cb);
-
-  Return<Result> unregisterDirectChannel(int32_t channelHandle) {
-    return S()->unregisterDirectChannel(channelHandle);
-  }
-
-  Return<void> configDirectReport(
-          int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
-          ISensors::configDirectReport_cb _hidl_cb) {
-    return S()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
-  }
-
-  inline sp<ISensors>& S() {
-    return SensorsHidlEnvironment::Instance()->sensors;
-  }
-
-  inline static SensorFlagBits extractReportMode(uint64_t flag) {
-    return (SensorFlagBits) (flag
-        & ((uint64_t) SensorFlagBits::CONTINUOUS_MODE
-          | (uint64_t) SensorFlagBits::ON_CHANGE_MODE
-          | (uint64_t) SensorFlagBits::ONE_SHOT_MODE
-          | (uint64_t) SensorFlagBits::SPECIAL_REPORTING_MODE));
-  }
-
-  inline static bool isMetaSensorType(SensorType type) {
-    return (type == SensorType::META_DATA
-            || type == SensorType::DYNAMIC_SENSOR_META
-            || type == SensorType::ADDITIONAL_INFO);
-  }
-
-  inline static bool isValidType(SensorType type) {
-    return (int32_t) type > 0;
-  }
-
-  void testStreamingOperation(SensorType type,
-                              std::chrono::nanoseconds samplingPeriod,
-                              std::chrono::seconds duration,
-                              const SensorEventsChecker &checker);
-  void testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow = true);
-  void testBatchingOperation(SensorType type);
-  void testDirectReportOperation(
-      SensorType type, SharedMemType memType, RateLevel rate, const SensorEventsChecker &checker);
-
-  static void assertTypeMatchStringType(SensorType type, const hidl_string& stringType);
-  static void assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode);
-  static void assertDelayMatchReportMode(
-          int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode);
-  static SensorFlagBits expectedReportModeForType(SensorType type);
-  static bool isDirectReportRateSupported(SensorInfo sensor, RateLevel rate);
-  static bool isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type);
-
-  // checkers
-  static const Vec3NormChecker sAccelNormChecker;
-  static const Vec3NormChecker sGyroNormChecker;
-
-  // all sensors and direct channnels used
-  std::unordered_set<int32_t> mSensorHandles;
-  std::unordered_set<int32_t> mDirectChannelHandles;
+    SensorsHidlEnvironmentBase* getEnvironment() override {
+        return SensorsHidlEnvironmentV1_0::Instance();
+    }
 };
 
-const Vec3NormChecker SensorsHidlTest::sAccelNormChecker(
-        Vec3NormChecker::byNominal(GRAVITY_EARTH, 1.0f/*m/s^2*/));
-const Vec3NormChecker SensorsHidlTest::sGyroNormChecker(
-        Vec3NormChecker::byNominal(0.f, 0.1f/*rad/s*/));
-
 Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
   // If activating a sensor, add the handle in a set so that when test fails it can be turned off.
   // The handle is not removed when it is deactivating on purpose so that it is not necessary to
@@ -618,195 +101,6 @@
   return Void();
 }
 
-std::vector<Event> SensorsHidlTest::collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
-      bool clearBeforeStart, bool changeCollection) {
-  std::vector<Event> events;
-  constexpr useconds_t SLEEP_GRANULARITY = 100*1000; //granularity 100 ms
-
-  ALOGI("collect max of %zu events for %d us, clearBeforeStart %d",
-        nEventLimit, timeLimitUs, clearBeforeStart);
-
-  if (changeCollection) {
-    SensorsHidlEnvironment::Instance()->setCollection(true);
-  }
-  if (clearBeforeStart) {
-    SensorsHidlEnvironment::Instance()->catEvents(nullptr);
-  }
-
-  while (timeLimitUs > 0) {
-    useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs);
-    usleep(duration);
-    timeLimitUs -= duration;
-
-    SensorsHidlEnvironment::Instance()->catEvents(&events);
-    if (events.size() >= nEventLimit) {
-      break;
-    }
-    ALOGV("time to go = %d, events to go = %d",
-          (int)timeLimitUs, (int)(nEventLimit - events.size()));
-  }
-
-  if (changeCollection) {
-    SensorsHidlEnvironment::Instance()->setCollection(false);
-  }
-  return events;
-}
-
-void SensorsHidlTest::assertTypeMatchStringType(SensorType type, const hidl_string& stringType) {
-
-  if (type >= SensorType::DEVICE_PRIVATE_BASE) {
-    return;
-  }
-
-  switch (type) {
-#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type) \
-    case SensorType::type: ASSERT_STREQ(SENSOR_STRING_TYPE_ ## type, stringType.c_str()); break;
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE);
-    CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE);
-    default:
-      FAIL() << "Type " << static_cast<int>(type) << " in android defined range is not checked, "
-             << "stringType = " << stringType;
-#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE
-  }
-}
-
-void SensorsHidlTest::assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode) {
-  if (type >= SensorType::DEVICE_PRIVATE_BASE) {
-    return;
-  }
-
-  SensorFlagBits expected = expectedReportModeForType(type);
-
-  ASSERT_TRUE(expected == (SensorFlagBits) -1 || expected == reportMode)
-      << "reportMode=" << static_cast<int>(reportMode)
-      << "expected=" << static_cast<int>(expected);
-}
-
-void SensorsHidlTest::assertDelayMatchReportMode(
-    int32_t minDelay, int32_t maxDelay, SensorFlagBits reportMode) {
-  switch(reportMode) {
-    case SensorFlagBits::CONTINUOUS_MODE:
-      ASSERT_LT(0, minDelay);
-      ASSERT_LE(0, maxDelay);
-      break;
-    case SensorFlagBits::ON_CHANGE_MODE:
-      ASSERT_LE(0, minDelay);
-      ASSERT_LE(0, maxDelay);
-      break;
-    case SensorFlagBits::ONE_SHOT_MODE:
-      ASSERT_EQ(-1, minDelay);
-      ASSERT_EQ(0, maxDelay);
-      break;
-    case SensorFlagBits::SPECIAL_REPORTING_MODE:
-      // do not enforce anything for special reporting mode
-      break;
-    default:
-      FAIL() << "Report mode " << static_cast<int>(reportMode) << " not checked";
-  }
-}
-
-// return -1 means no expectation for this type
-SensorFlagBits SensorsHidlTest::expectedReportModeForType(SensorType type) {
-  switch (type) {
-    case SensorType::ACCELEROMETER:
-    case SensorType::ACCELEROMETER_UNCALIBRATED:
-    case SensorType::GYROSCOPE:
-    case SensorType::MAGNETIC_FIELD:
-    case SensorType::ORIENTATION:
-    case SensorType::PRESSURE:
-    case SensorType::TEMPERATURE:
-    case SensorType::GRAVITY:
-    case SensorType::LINEAR_ACCELERATION:
-    case SensorType::ROTATION_VECTOR:
-    case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
-    case SensorType::GAME_ROTATION_VECTOR:
-    case SensorType::GYROSCOPE_UNCALIBRATED:
-    case SensorType::GEOMAGNETIC_ROTATION_VECTOR:
-    case SensorType::POSE_6DOF:
-    case SensorType::HEART_BEAT:
-      return SensorFlagBits::CONTINUOUS_MODE;
-
-    case SensorType::LIGHT:
-    case SensorType::PROXIMITY:
-    case SensorType::RELATIVE_HUMIDITY:
-    case SensorType::AMBIENT_TEMPERATURE:
-    case SensorType::HEART_RATE:
-    case SensorType::DEVICE_ORIENTATION:
-    case SensorType::STEP_COUNTER:
-    case SensorType::LOW_LATENCY_OFFBODY_DETECT:
-      return SensorFlagBits::ON_CHANGE_MODE;
-
-    case SensorType::SIGNIFICANT_MOTION:
-    case SensorType::WAKE_GESTURE:
-    case SensorType::GLANCE_GESTURE:
-    case SensorType::PICK_UP_GESTURE:
-    case SensorType::MOTION_DETECT:
-    case SensorType::STATIONARY_DETECT:
-      return SensorFlagBits::ONE_SHOT_MODE;
-
-    case SensorType::STEP_DETECTOR:
-    case SensorType::TILT_DETECTOR:
-    case SensorType::WRIST_TILT_GESTURE:
-    case SensorType::DYNAMIC_SENSOR_META:
-      return SensorFlagBits::SPECIAL_REPORTING_MODE;
-
-    default:
-      ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type);
-      return (SensorFlagBits)-1;
-  }
-}
-
-bool SensorsHidlTest::isDirectReportRateSupported(SensorInfo sensor, RateLevel rate) {
-  unsigned int r =
-      static_cast<unsigned int>(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT)
-        >> static_cast<unsigned int>(SensorFlagShift::DIRECT_REPORT);
-  return r >= static_cast<unsigned int>(rate);
-}
-
-bool SensorsHidlTest::isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type) {
-  switch (type) {
-    case SharedMemType::ASHMEM:
-      return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_ASHMEM) != 0;
-    case SharedMemType::GRALLOC:
-      return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_GRALLOC) != 0;
-    default:
-      return false;
-  }
-}
-
 SensorInfo SensorsHidlTest::defaultSensorByType(SensorType type) {
   SensorInfo ret;
 
@@ -951,69 +245,6 @@
     ASSERT_EQ(Result::OK, S()->setOperationMode(OperationMode::NORMAL));
 }
 
-void SensorsHidlTest::testStreamingOperation(SensorType type,
-                                             std::chrono::nanoseconds samplingPeriod,
-                                             std::chrono::seconds duration,
-                                             const SensorEventsChecker &checker) {
-  std::vector<Event> events;
-  std::vector<Event> sensorEvents;
-
-  const int64_t samplingPeriodInNs = samplingPeriod.count();
-  const int64_t batchingPeriodInNs = 0; // no batching
-  const useconds_t minTimeUs = std::chrono::microseconds(duration).count();
-  const size_t minNEvent = duration / samplingPeriod;
-
-  SensorInfo sensor = defaultSensorByType(type);
-
-  if (!isValidType(sensor.type)) {
-    // no default sensor of this type
-    return;
-  }
-
-  if (std::chrono::microseconds(sensor.minDelay) > samplingPeriod) {
-    // rate not supported
-    return;
-  }
-
-  int32_t handle = sensor.sensorHandle;
-
-  ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK);
-  ASSERT_EQ(activate(handle, 1), Result::OK);
-  events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/);
-  ASSERT_EQ(activate(handle, 0), Result::OK);
-
-  ALOGI("Collected %zu samples", events.size());
-
-  ASSERT_GT(events.size(), 0u);
-
-  bool handleMismatchReported = false;
-  bool metaSensorTypeErrorReported = false;
-  for (auto & e : events) {
-    if (e.sensorType == type) {
-      // avoid generating hundreds of error
-      if (!handleMismatchReported) {
-        EXPECT_EQ(e.sensorHandle, handle)
-            << (handleMismatchReported = true,
-                "Event of the same type must come from the sensor registered");
-      }
-      sensorEvents.push_back(e);
-    } else {
-      // avoid generating hundreds of error
-      if (!metaSensorTypeErrorReported) {
-        EXPECT_TRUE(isMetaSensorType(e.sensorType))
-            << (metaSensorTypeErrorReported = true,
-                "Only meta types are allowed besides the type registered");
-      }
-    }
-  }
-
-  std::string s;
-  EXPECT_TRUE(checker.check(sensorEvents, &s)) << s;
-
-  EXPECT_GE(sensorEvents.size(),
-            minNEvent / 2);  // make sure returned events are not all meta
-}
-
 // Test if sensor hal can do UI speed accelerometer streaming properly
 TEST_F(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
   testStreamingOperation(SensorType::ACCELEROMETER,
@@ -1086,103 +317,6 @@
                          NullChecker());
 }
 
-void SensorsHidlTest::testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow) {
-  std::vector<Event> events1, events2;
-
-  constexpr int64_t batchingPeriodInNs = 0; // no batching
-  constexpr int64_t collectionTimeoutUs = 60000000; // 60s
-  constexpr size_t minNEvent = 50;
-
-  SensorInfo sensor = defaultSensorByType(type);
-
-  if (!isValidType(sensor.type)) {
-    // no default sensor of this type
-    return;
-  }
-
-  int32_t handle = sensor.sensorHandle;
-  int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll;
-  int64_t maxSamplingPeriodInNs = sensor.maxDelay * 1000ll;
-
-  if (minSamplingPeriodInNs == maxSamplingPeriodInNs) {
-    // only support single rate
-    return;
-  }
-
-  int64_t firstCollectionPeriod = fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs;
-  int64_t secondCollectionPeriod = !fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs;
-
-  // first collection
-  ASSERT_EQ(batch(handle, firstCollectionPeriod, batchingPeriodInNs), Result::OK);
-  ASSERT_EQ(activate(handle, 1), Result::OK);
-
-  usleep(500000); // sleep 0.5 sec to wait for change rate to happen
-  events1 = collectEvents(collectionTimeoutUs, minNEvent);
-
-  // second collection, without stop sensor
-  ASSERT_EQ(batch(handle, secondCollectionPeriod, batchingPeriodInNs), Result::OK);
-
-  usleep(500000); // sleep 0.5 sec to wait for change rate to happen
-  events2 = collectEvents(collectionTimeoutUs, minNEvent);
-
-  // end of collection, stop sensor
-  ASSERT_EQ(activate(handle, 0), Result::OK);
-
-  ALOGI("Collected %zu fast samples and %zu slow samples", events1.size(), events2.size());
-
-  ASSERT_GT(events1.size(), 0u);
-  ASSERT_GT(events2.size(), 0u);
-
-  int64_t minDelayAverageInterval, maxDelayAverageInterval;
-  std::vector<Event> &minDelayEvents(fastToSlow ? events1 : events2);
-  std::vector<Event> &maxDelayEvents(fastToSlow ? events2 : events1);
-
-  size_t nEvent = 0;
-  int64_t prevTimestamp = -1;
-  int64_t timestampInterval = 0;
-  for (auto & e : minDelayEvents) {
-    if (e.sensorType == type) {
-      ASSERT_EQ(e.sensorHandle, handle);
-      if (prevTimestamp > 0) {
-        timestampInterval += e.timestamp - prevTimestamp;
-      }
-      prevTimestamp = e.timestamp;
-      ++ nEvent;
-    }
-  }
-  ASSERT_GT(nEvent, 2u);
-  minDelayAverageInterval = timestampInterval / (nEvent - 1);
-
-  nEvent = 0;
-  prevTimestamp = -1;
-  timestampInterval = 0;
-  for (auto & e : maxDelayEvents) {
-    if (e.sensorType == type) {
-      ASSERT_EQ(e.sensorHandle, handle);
-      if (prevTimestamp > 0) {
-        timestampInterval += e.timestamp - prevTimestamp;
-      }
-      prevTimestamp = e.timestamp;
-      ++ nEvent;
-    }
-  }
-  ASSERT_GT(nEvent, 2u);
-  maxDelayAverageInterval = timestampInterval / (nEvent - 1);
-
-  // change of rate is significant.
-  ALOGI("min/maxDelayAverageInterval = %" PRId64 " %" PRId64,
-      minDelayAverageInterval, maxDelayAverageInterval);
-  EXPECT_GT((maxDelayAverageInterval - minDelayAverageInterval), minDelayAverageInterval / 10);
-
-  // fastest rate sampling time is close to spec
-  EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
-      minSamplingPeriodInNs / 10);
-
-  // slowest rate sampling time is close to spec
-  EXPECT_LT(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs),
-      maxSamplingPeriodInNs / 10);
-}
-
 // Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
 TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
   testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER);
@@ -1201,74 +335,6 @@
   testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD, false /*fastToSlow*/);
 }
 
-void SensorsHidlTest::testBatchingOperation(SensorType type) {
-  std::vector<Event> events;
-
-  constexpr int64_t maxBatchingTestTimeNs = 30ull * 1000 * 1000 * 1000;
-  constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000;
-
-  SensorInfo sensor = defaultSensorByType(type);
-
-  if (!isValidType(sensor.type)) {
-    // no default sensor of this type
-    return;
-  }
-
-  int32_t handle = sensor.sensorHandle;
-  int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll;
-  uint32_t minFifoCount = sensor.fifoReservedEventCount;
-  int64_t batchingPeriodInNs = minFifoCount * minSamplingPeriodInNs;
-
-  if (batchingPeriodInNs < oneSecondInNs) {
-    // batching size too small to test reliably
-    return;
-  }
-
-  batchingPeriodInNs = std::min(batchingPeriodInNs, maxBatchingTestTimeNs);
-
-  ALOGI("Test batching for %d ms", (int)(batchingPeriodInNs / 1000 / 1000));
-
-  int64_t allowedBatchDeliverTimeNs =
-      std::max(oneSecondInNs, batchingPeriodInNs / 10);
-
-  ASSERT_EQ(batch(handle, minSamplingPeriodInNs, INT64_MAX), Result::OK);
-  ASSERT_EQ(activate(handle, 1), Result::OK);
-
-  usleep(500000); // sleep 0.5 sec to wait for initialization
-  ASSERT_EQ(flush(handle), Result::OK);
-
-  // wait for 80% of the reserved batching period
-  // there should not be any significant amount of events
-  // since collection is not enabled all events will go down the drain
-  usleep(batchingPeriodInNs / 1000 * 8 / 10);
-
-  SensorsHidlEnvironment::Instance()->setCollection(true);
-  // clean existing collections
-  collectEvents(0 /*timeLimitUs*/, 0/*nEventLimit*/,
-        true /*clearBeforeStart*/, false /*change collection*/);
-
-  // 0.8 + 0.2 times the batching period
-  usleep(batchingPeriodInNs / 1000 * 8 / 10);
-  ASSERT_EQ(flush(handle), Result::OK);
-
-  // plus some time for the event to deliver
-  events = collectEvents(allowedBatchDeliverTimeNs / 1000,
-        minFifoCount, false /*clearBeforeStart*/, false /*change collection*/);
-
-  SensorsHidlEnvironment::Instance()->setCollection(false);
-  ASSERT_EQ(activate(handle, 0), Result::OK);
-
-  size_t nEvent = 0;
-  for (auto & e : events) {
-    if (e.sensorType == type && e.sensorHandle == handle) {
-      ++ nEvent;
-    }
-  }
-
-  // at least reach 90% of advertised capacity
-  ASSERT_GT(nEvent, (size_t)(minFifoCount * 9 / 10));
-}
-
 // Test if sensor hal can do accelerometer batching properly
 TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
   testBatchingOperation(SensorType::ACCELEROMETER);
@@ -1284,124 +350,6 @@
   testBatchingOperation(SensorType::MAGNETIC_FIELD);
 }
 
-void SensorsHidlTest::testDirectReportOperation(
-    SensorType type, SharedMemType memType, RateLevel rate, const SensorEventsChecker &checker) {
-  constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
-  constexpr size_t kNEvent = 4096;
-  constexpr size_t kMemSize = kEventSize * kNEvent;
-
-  constexpr float kNormalNominal = 50;
-  constexpr float kFastNominal = 200;
-  constexpr float kVeryFastNominal = 800;
-
-  constexpr float kNominalTestTimeSec = 1.f;
-  constexpr float kMaxTestTimeSec = kNominalTestTimeSec + 0.5f; // 0.5 second for initialization
-
-  SensorInfo sensor = defaultSensorByType(type);
-
-  if (!isValidType(sensor.type)) {
-    // no default sensor of this type
-    return;
-  }
-
-  if (!isDirectReportRateSupported(sensor, rate)) {
-    return;
-  }
-
-  if (!isDirectChannelTypeSupported(sensor, memType)) {
-    return;
-  }
-
-  std::unique_ptr<SensorsTestSharedMemory>
-      mem(SensorsTestSharedMemory::create(memType, kMemSize));
-  ASSERT_NE(mem, nullptr);
-
-  char* buffer = mem->getBuffer();
-  // fill memory with data
-  for (size_t i = 0; i < kMemSize; ++i) {
-    buffer[i] = '\xcc';
-  }
-
-  int32_t channelHandle;
-  registerDirectChannel(mem->getSharedMemInfo(),
-      [&channelHandle] (auto result, auto channelHandle_) {
-          ASSERT_EQ(result, Result::OK);
-          channelHandle = channelHandle_;
-      });
-
-  // check memory is zeroed
-  for (size_t i = 0; i < kMemSize; ++i) {
-    ASSERT_EQ(buffer[i], '\0');
-  }
-
-  int32_t eventToken;
-  configDirectReport(sensor.sensorHandle, channelHandle, rate,
-      [&eventToken] (auto result, auto token) {
-          ASSERT_EQ(result, Result::OK);
-          eventToken = token;
-      });
-
-  usleep(static_cast<useconds_t>(kMaxTestTimeSec * 1e6f));
-  auto events = mem->parseEvents();
-
-  // find norminal rate
-  float nominalFreq = 0.f;
-  switch (rate) {
-      case RateLevel::NORMAL:
-          nominalFreq = kNormalNominal;
-          break;
-      case RateLevel::FAST:
-          nominalFreq = kFastNominal;
-          break;
-      case RateLevel::VERY_FAST:
-          nominalFreq = kVeryFastNominal;
-          break;
-      case RateLevel::STOP:
-          FAIL();
-  }
-
-  // allowed to be between 55% and 220% of nominal freq
-  ASSERT_GT(events.size(), static_cast<size_t>(nominalFreq * 0.55f * kNominalTestTimeSec));
-  ASSERT_LT(events.size(), static_cast<size_t>(nominalFreq * 2.2f * kMaxTestTimeSec));
-
-  int64_t lastTimestamp = 0;
-  bool typeErrorReported = false;
-  bool tokenErrorReported = false;
-  bool timestampErrorReported = false;
-  std::vector<Event> sensorEvents;
-  for (auto &e : events) {
-    if (!tokenErrorReported) {
-      EXPECT_EQ(eventToken, e.sensorHandle)
-          << (tokenErrorReported = true,
-            "Event token does not match that retured from configDirectReport");
-    }
-
-    if (isMetaSensorType(e.sensorType)) {
-        continue;
-    }
-    sensorEvents.push_back(e);
-
-    if (!typeErrorReported) {
-      EXPECT_EQ(type, e.sensorType)
-          << (typeErrorReported = true,
-              "Type in event does not match type of sensor registered.");
-    }
-    if (!timestampErrorReported) {
-      EXPECT_GT(e.timestamp, lastTimestamp)
-          << (timestampErrorReported = true, "Timestamp not monotonically increasing");
-    }
-    lastTimestamp = e.timestamp;
-  }
-
-  std::string s;
-  EXPECT_TRUE(checker.check(sensorEvents, &s)) << s;
-
-  // stop sensor and unregister channel
-  configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP,
-                     [](auto result, auto) { EXPECT_EQ(result, Result::OK); });
-  EXPECT_EQ(unregisterDirectChannel(channelHandle), Result::OK);
-}
-
 // Test sensor event direct report with ashmem for accel sensor at normal rate
 TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
   testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
@@ -1511,11 +459,11 @@
 }
 
 int main(int argc, char **argv) {
-  ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  SensorsHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  ALOGI("Test result = %d", status);
-  return status;
+    ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironmentV1_0::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    SensorsHidlEnvironmentV1_0::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
 }
 // vim: set ts=2 sw=2
diff --git a/sensors/2.0/Android.bp b/sensors/2.0/Android.bp
new file mode 100644
index 0000000..3b948a9
--- /dev/null
+++ b/sensors/2.0/Android.bp
@@ -0,0 +1,24 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.sensors@2.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "ISensors.hal",
+        "ISensorsCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.sensors@1.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "EventQueueFlagBits",
+        "SensorTimeout",
+    ],
+    gen_java: false,
+}
+
diff --git a/sensors/2.0/ISensors.hal b/sensors/2.0/ISensors.hal
new file mode 100644
index 0000000..939bf73
--- /dev/null
+++ b/sensors/2.0/ISensors.hal
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.sensors@2.0;
+
+import @1.0::Event;
+import @1.0::OperationMode;
+import @1.0::RateLevel;
+import @1.0::Result;
+import @1.0::SensorInfo;
+import @1.0::SharedMemInfo;
+import @2.0::ISensorsCallback;
+
+interface ISensors {
+    /**
+     * Enumerate all available (static) sensors.
+     *
+     * The SensorInfo for each sensor returned by getSensorsList must be stable
+     * from the initial call to getSensorsList after a device boot until the
+     * entire system restarts. The SensorInfo for each sensor must not change
+     * between subsequent calls to getSensorsList, even across restarts of the
+     * HAL and its dependencies (for example, the sensor handle for a given
+     * sensor must not change across HAL restarts).
+     */
+    getSensorsList() generates (vec<SensorInfo> list);
+
+    /**
+     * Place the module in a specific mode. The following modes are defined
+     *
+     *  SENSOR_HAL_NORMAL_MODE - Normal operation. Default state of the module.
+     *
+     *  SENSOR_HAL_DATA_INJECTION_MODE - Loopback mode.
+     *    Data is injected for the supported sensors by the sensor service in
+     *    this mode.
+     *
+     * @return OK on success
+     *     BAD_VALUE if requested mode is not supported
+     *     PERMISSION_DENIED if operation is not allowed
+     */
+    setOperationMode(OperationMode mode) generates (Result result);
+
+    /**
+     * Activate/de-activate one sensor.
+     *
+     * After sensor de-activation, existing sensor events that have not
+     * been written to the event queue must be abandoned immediately so that
+     * subsequent activations do not get stale sensor events (events
+     * that are generated prior to the latter activation).
+     *
+     * @param sensorHandle is the handle of the sensor to change.
+     * @param enabled set to true to enable, or false to disable the sensor.
+     * @return result OK on success, BAD_VALUE if sensorHandle is invalid.
+     */
+    activate(int32_t sensorHandle, bool enabled) generates (Result result);
+
+    /**
+     * Initialize the Sensors HAL's Fast Message Queues (FMQ) and callback.
+     *
+     * The Fast Message Queues (FMQ) that are used to send data between the
+     * framework and the HAL. The callback is used by the HAL to notify the
+     * framework of asynchronous events, such as a dynamic sensor connection.
+     *
+     * The Event FMQ is used to transport sensor events from the HAL to the
+     * framework. The Event FMQ is created using the eventQueueDescriptor.
+     * Data may only be written to the Event FMQ. Data must not be read from
+     * the Event FMQ since the framework is the only reader. Upon receiving
+     * sensor events, the HAL should write the sensor events to the Event FMQ.
+     * Once the HAL is finished writing sensor events to the Event FMQ, the HAL
+     * must call the Event FMQ's EventFlag wake() function with the
+     * EventQueueFlagBits::READ_AND_PROCESS mask which notifies the framework
+     * that sensor events are available to be read and processed.
+     *
+     * The Wake Lock FMQ is used by the framework to notify the HAL when it is
+     * safe to release its wake_lock. When the framework receives WAKE_UP events
+     * from the Event FMQ and the framework has acquired a wake_lock, the
+     * framework must write a WakeLockEvent to the Wake Lock FMQ with the number
+     * of WAKE_UP events processed. When the HAL reads the WakeLockEvent from
+     * the Wake Lock FMQ, the HAL should decrement its current count of
+     * unprocessed WAKE_UP events and release its wake_lock if the current
+     * count of unprocessed WAKE_UP events is zero.
+     *
+     * The ISensorsCallback is used by the HAL to notify the framework of
+     * asynchronous events, such as a dynamic sensor connection.
+     *
+     * The name of any wake_lock acquired by the Sensors HAL for WAKE_UP events
+     * must begin with "SensorsHAL_WAKEUP".
+     *
+     * If WAKE_LOCK_TIMEOUT_SECONDS has elapsed since the most recent WAKE_UP
+     * event was written to the Event FMQ without receiving a message on the
+     * Wake Lock FMQ, then any held wake_lock for WAKE_UP events must be
+     * released.
+     *
+     * If either the Event FMQ or the Wake Lock FMQ is already initialized when
+     * initialize is invoked, then both existing FMQs must be discarded and the
+     * new descriptors must be used to create new FMQs within the HAL. The
+     * number of outstanding WAKE_UP events should also be reset to zero, and
+     * any outstanding wake_locks held as a result of WAKE_UP events should be
+     * released.
+     *
+     * initialize must be thread safe and prevent concurrent calls
+     * to initialize from simultaneously modifying state.
+     *
+     * @param eventQueueDescriptor Fast Message Queue descriptor that is used to
+     *     create the Event FMQ which is where sensor events are written. The
+     *     descriptor is obtained from the framework's FMQ that is used to read
+     *     sensor events.
+     * @param wakeLockDescriptor Fast Message Queue descriptor that is used to
+     *     create the Wake Lock FMQ which is where wake_lock events are read
+     *     from. The descriptor is obtained from the framework's FMQ that is
+     *     used to write wake_lock events.
+     * @param sensorsCallback sensors callback that receives asynchronous data
+     *     from the Sensors HAL.
+     * @return result OK on success; BAD_VALUE if descriptor is invalid (such
+     *     as null)
+     */
+    @entry
+    @callflow(next = {"getSensorsList"})
+    initialize(fmq_sync<Event> eventQueueDescriptor,
+               fmq_sync<uint32_t> wakeLockDescriptor,
+               ISensorsCallback sensorsCallback)
+        generates
+              (Result result);
+
+    /**
+     * Sets a sensor’s parameters, including sampling frequency and maximum
+     * report latency. This function can be called while the sensor is
+     * activated, in which case it must not cause any sensor measurements to
+     * be lost: transitioning from one sampling rate to the other cannot cause
+     * lost events, nor can transitioning from a high maximum report latency to
+     * a low maximum report latency.
+     *
+     * @param sensorHandle handle of sensor to be changed.
+     * @param samplingPeriodNs specifies sensor sample period in nanoseconds.
+     * @param maxReportLatencyNs allowed delay time before an event is sampled
+     *     to time of report.
+     * @return result OK on success, BAD_VALUE if any parameters are invalid.
+     */
+    batch(int32_t sensorHandle,
+          int64_t samplingPeriodNs,
+          int64_t maxReportLatencyNs)
+        generates (
+          Result result);
+
+    /**
+     * Trigger a flush of internal FIFO.
+     *
+     * Flush adds a FLUSH_COMPLETE metadata event to the end of the "batch mode"
+     * FIFO for the specified sensor and flushes the FIFO.  If the FIFO is empty
+     * or if the sensor doesn't support batching (FIFO size zero), return
+     * SUCCESS and add a trivial FLUSH_COMPLETE event added to the event stream.
+     * This applies to all sensors other than one-shot sensors. If the sensor
+     * is a one-shot sensor, flush must return BAD_VALUE and not generate any
+     * flush complete metadata.  If the sensor is not active at the time flush()
+     * is called, flush() return BAD_VALUE.
+     *
+     * @param sensorHandle handle of sensor to be flushed.
+     * @return result OK on success and BAD_VALUE if sensorHandle is invalid.
+     */
+    flush(int32_t sensorHandle) generates (Result result);
+
+    /**
+     * Inject a single sensor event or push operation environment parameters to
+     * device.
+     *
+     * When device is in NORMAL mode, this function is called to push operation
+     * environment data to device. In this operation, Event is always of
+     * SensorType::AdditionalInfo type. See operation evironment parameters
+     * section in AdditionalInfoType.
+     *
+     * When device is in DATA_INJECTION mode, this function is also used for
+     * injecting sensor events.
+     *
+     * Regardless of OperationMode, injected SensorType::ADDITIONAL_INFO
+     * type events should not be routed back to the sensor event queue.
+     *
+     * @see AdditionalInfoType
+     * @see OperationMode
+     * @param event sensor event to be injected
+     * @return result OK on success; PERMISSION_DENIED if operation is not
+     *     allowed; INVALID_OPERATION, if this functionality is unsupported;
+     *     BAD_VALUE if sensor event cannot be injected.
+     */
+    injectSensorData(Event event) generates (Result result);
+
+    /**
+     * Register direct report channel.
+     *
+     * Register a direct channel with supplied shared memory information. Upon
+     * return, the sensor hardware is responsible for resetting the memory
+     * content to initial value (depending on memory format settings).
+     *
+     * @param mem shared memory info data structure.
+     * @return result OK on success; BAD_VALUE if shared memory information is
+     *     not consistent; NO_MEMORY if shared memory cannot be used by sensor
+     *     system; INVALID_OPERATION if functionality is not supported.
+     * @return channelHandle a positive integer used for referencing registered
+     *     direct channel (>0) in configureDirectReport and
+     *     unregisterDirectChannel if result is OK, -1 otherwise.
+     */
+    registerDirectChannel(SharedMemInfo mem)
+               generates (Result result,
+                          int32_t channelHandle);
+
+    /**
+     * Unregister direct report channel.
+     *
+     * Unregister a direct channel previously registered using
+     * registerDirectChannel, and remove all active sensor report configured in
+     * still active sensor report configured in the direct channel.
+     *
+     * @param channelHandle handle of direct channel to be unregistered.
+     * @return result OK if direct report is supported; INVALID_OPERATION
+     *     otherwise.
+     */
+    unregisterDirectChannel(int32_t channelHandle) generates (Result result);
+
+    /**
+     * Configure direct sensor event report in direct channel.
+     *
+     * This function start, modify rate or stop direct report of a sensor in a
+     * certain direct channel.
+     *
+     * @param sensorHandle handle of sensor to be configured. When combined
+     *     with STOP rate, sensorHandle can be -1 to denote all active sensors
+     *     in the direct channel specified by channel Handle.
+     * @param channelHandle handle of direct channel to be configured.
+     * @param rate rate level, see RateLevel enum.
+     * @return result OK on success; BAD_VALUE if parameter is invalid (such as
+     *     rate level is not supported by sensor, channelHandle does not exist,
+     *     etc); INVALID_OPERATION if functionality is not supported.
+     * @return reportToken positive integer to identify multiple sensors of
+     *     the same type in a single direct channel. Ignored if rate is STOP.
+     *     See SharedMemFormat.
+     */
+    configDirectReport(
+            int32_t sensorHandle,
+            int32_t channelHandle,
+            RateLevel rate
+        ) generates (
+            Result result,
+            int32_t reportToken);
+};
diff --git a/sensors/2.0/ISensorsCallback.hal b/sensors/2.0/ISensorsCallback.hal
new file mode 100644
index 0000000..e0bd98f
--- /dev/null
+++ b/sensors/2.0/ISensorsCallback.hal
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.sensors@2.0;
+
+import @1.0::SensorInfo;
+
+interface ISensorsCallback {
+    /**
+     * Notify the framework that new dynamic sensors have been connected.
+     *
+     * If a dynamic sensor was previously connected and has not been
+     * disconnected, then that sensor must not be included in sensorInfos.
+     *
+     * @param sensorInfos vector of SensorInfo for each dynamic sensor that
+     *     was connected.
+     */
+    oneway onDynamicSensorsConnected(vec<SensorInfo> sensorInfos);
+
+    /**
+     * Notify the framework that previously connected dynamic sensors have been
+     * disconnected.
+     *
+     * If a dynamic sensor was previously disconnected and has not been
+     * reconnected, then that sensor must not be included in sensorHandles.
+     *
+     * The HAL must ensure that all sensor events from departing dynamic
+     * sensors have been written to the Event FMQ before calling
+     * onDynamicSensorsDisconnected.
+     *
+     * @param sensorHandles vector of sensor handles for each dynamic sensors
+     *     that was disconnected.
+     */
+    oneway onDynamicSensorsDisconnected(vec<int32_t> sensorHandles);
+};
diff --git a/sensors/2.0/types.hal b/sensors/2.0/types.hal
new file mode 100644
index 0000000..e1a029a
--- /dev/null
+++ b/sensors/2.0/types.hal
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.sensors@2.0;
+
+enum SensorTimeout : int32_t {
+    /**
+     * The maximum number of seconds to wait for a message on the Wake Lock FMQ
+     * before automatically releasing any wake_lock held for a WAKE_UP event.
+     */
+    WAKE_LOCK_SECONDS = 1,
+};
+
+enum EventQueueFlagBits : uint32_t {
+    /**
+     * Used to notify the Event FMQ that events should be read and processed.
+     */
+    READ_AND_PROCESS = 1 << 0,
+};
diff --git a/sensors/2.0/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp
new file mode 100644
index 0000000..8e8413c
--- /dev/null
+++ b/sensors/2.0/vts/functional/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalSensorsV2_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "SensorsHidlEnvironmentV2_0.cpp",
+        "VtsHalSensorsV2_0TargetTest.cpp"
+    ],
+    static_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "libfmq",
+        "VtsHalSensorsTargetTestUtils",
+    ],
+}
+
diff --git a/sensors/2.0/vts/functional/OWNERS b/sensors/2.0/vts/functional/OWNERS
new file mode 100644
index 0000000..759d87b
--- /dev/null
+++ b/sensors/2.0/vts/functional/OWNERS
@@ -0,0 +1,7 @@
+# Sensors team
+bduddie@google.com
+bstack@google.com
+
+# VTS team
+trong@google.com
+yim@google.com
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
new file mode 100644
index 0000000..5444287
--- /dev/null
+++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SensorsHidlEnvironmentV2_0.h"
+
+#include <android/hardware/sensors/2.0/types.h>
+#include <log/log.h>
+
+#include <algorithm>
+#include <vector>
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
+using ::android::hardware::sensors::V2_0::ISensors;
+
+template <typename EnumType>
+constexpr typename std::underlying_type<EnumType>::type asBaseType(EnumType value) {
+    return static_cast<typename std::underlying_type<EnumType>::type>(value);
+}
+
+constexpr size_t SensorsHidlEnvironmentV2_0::MAX_RECEIVE_BUFFER_EVENT_COUNT;
+
+bool SensorsHidlEnvironmentV2_0::resetHal() {
+    bool succeed = false;
+    do {
+        mSensors = ISensors::getService(
+            SensorsHidlEnvironmentV2_0::Instance()->getServiceName<ISensors>());
+        if (mSensors == nullptr) {
+            break;
+        }
+
+        // Initialize FMQs
+        mEventQueue = std::make_unique<EventMessageQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
+                                                          true /* configureEventFlagWord */);
+
+        mWakeLockQueue = std::make_unique<WakeLockQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
+                                                         true /* configureEventFlagWord */);
+
+        if (mEventQueue == nullptr || mWakeLockQueue == nullptr) {
+            break;
+        }
+
+        EventFlag::deleteEventFlag(&mEventQueueFlag);
+        EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag);
+        if (mEventQueueFlag == nullptr) {
+            break;
+        }
+
+        mSensors->initialize(*mEventQueue->getDesc(), *mWakeLockQueue->getDesc(),
+                             nullptr /* TODO: callback */);
+
+        std::vector<SensorInfo> sensorList;
+        if (!mSensors->getSensorsList([&](const hidl_vec<SensorInfo>& list) { sensorList = list; })
+                 .isOk()) {
+            break;
+        }
+
+        // stop each sensor individually
+        bool ok = true;
+        for (const auto& i : sensorList) {
+            if (!mSensors->activate(i.sensorHandle, false).isOk()) {
+                ok = false;
+                break;
+            }
+        }
+        if (!ok) {
+            break;
+        }
+
+        // mark it done
+        succeed = true;
+    } while (0);
+
+    if (!succeed) {
+        mSensors = nullptr;
+    }
+
+    return succeed;
+}
+
+void SensorsHidlEnvironmentV2_0::HidlTearDown() {
+    stopThread = true;
+
+    // Wake up the event queue so the poll thread can exit
+    mEventQueueFlag->wake(asBaseType(EventQueueFlagBits::READ_AND_PROCESS));
+    pollThread.join();
+
+    EventFlag::deleteEventFlag(&mEventQueueFlag);
+}
+
+void SensorsHidlEnvironmentV2_0::startPollingThread() {
+    stopThread = false;
+    pollThread = std::thread(pollingThread, this);
+    events.reserve(MAX_RECEIVE_BUFFER_EVENT_COUNT);
+}
+
+void SensorsHidlEnvironmentV2_0::readEvents() {
+    size_t availableEvents = mEventQueue->availableToRead();
+
+    if (availableEvents == 0) {
+        uint32_t eventFlagState = 0;
+
+        mEventQueueFlag->wait(asBaseType(EventQueueFlagBits::READ_AND_PROCESS), &eventFlagState);
+        availableEvents = mEventQueue->availableToRead();
+    }
+
+    size_t eventsToRead = std::min(availableEvents, mEventBuffer.size());
+    if (eventsToRead > 0) {
+        if (mEventQueue->read(mEventBuffer.data(), eventsToRead)) {
+            for (const auto& e : mEventBuffer) {
+                addEvent(e);
+            }
+        }
+    }
+}
+
+void SensorsHidlEnvironmentV2_0::pollingThread(SensorsHidlEnvironmentV2_0* env) {
+    ALOGD("polling thread start");
+
+    while (!env->stopThread.load()) {
+        env->readEvents();
+    }
+
+    ALOGD("polling thread end");
+}
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
new file mode 100644
index 0000000..7241923
--- /dev/null
+++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H
+#define ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H
+
+#include "sensors-vts-utils/SensorsHidlEnvironmentBase.h"
+
+#include <android/hardware/sensors/1.0/types.h>
+#include <android/hardware/sensors/2.0/ISensors.h>
+#include <fmq/MessageQueue.h>
+#include <utils/StrongPointer.h>
+
+#include <array>
+#include <atomic>
+#include <memory>
+
+using ::android::sp;
+using ::android::hardware::MessageQueue;
+
+class SensorsHidlTest;
+class SensorsHidlEnvironmentV2_0 : public SensorsHidlEnvironmentBase {
+   public:
+    using Event = ::android::hardware::sensors::V1_0::Event;
+    // get the test environment singleton
+    static SensorsHidlEnvironmentV2_0* Instance() {
+        static SensorsHidlEnvironmentV2_0* instance = new SensorsHidlEnvironmentV2_0();
+        return instance;
+    }
+
+    virtual void registerTestServices() override {
+        registerTestService<android::hardware::sensors::V2_0::ISensors>();
+    }
+
+    virtual void HidlTearDown() override;
+
+   private:
+    friend SensorsHidlTest;
+
+    SensorsHidlEnvironmentV2_0() : mEventQueueFlag(nullptr) {}
+
+    /**
+     * Resets the HAL with new FMQs and a new Event Flag
+     *
+     * @return bool true if successful, false otherwise
+     */
+    bool resetHal() override;
+
+    /**
+     * Starts the polling thread that reads sensor events from the Event FMQ
+     */
+    void startPollingThread() override;
+
+    /**
+     * Thread responsible for calling functions to read Event FMQ
+     *
+     * @param env SensorEnvironment to being polling for events on
+     */
+    static void pollingThread(SensorsHidlEnvironmentV2_0* env);
+
+    /**
+     * Reads and saves sensor events from the Event FMQ
+     */
+    void readEvents();
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentV2_0);
+
+    /**
+     * Pointer to the Sensors HAL Interface that allows the test to call HAL functions.
+     */
+    sp<android::hardware::sensors::V2_0::ISensors> mSensors;
+
+    /**
+     * Type used to simplify the creation of the Event FMQ
+     */
+    typedef MessageQueue<Event, ::android::hardware::kSynchronizedReadWrite> EventMessageQueue;
+
+    /**
+     * Type used to simplify the creation of the Wake Lock FMQ
+     */
+    typedef MessageQueue<uint32_t, ::android::hardware::kSynchronizedReadWrite> WakeLockQueue;
+
+    /**
+     * The Event FMQ where the test framework is able to read sensor events that the Sensors HAL
+     * has written.
+     */
+    std::unique_ptr<EventMessageQueue> mEventQueue;
+
+    /**
+     * The Wake Lock FMQ is used by the test to notify the Sensors HAL whenever it has processed
+     * WAKE_UP sensor events.
+     */
+    std::unique_ptr<WakeLockQueue> mWakeLockQueue;
+
+    /**
+     * The Event Queue Flag notifies the test framework when sensor events have been written to the
+     * Event FMQ by the Sensors HAL.
+     */
+    ::android::hardware::EventFlag* mEventQueueFlag;
+
+    /**
+     * The maximum number of sensor events that can be read from the Event FMQ at one time.
+     */
+    static constexpr size_t MAX_RECEIVE_BUFFER_EVENT_COUNT = 128;
+
+    /**
+     * An array that is used to store sensor events read from the Event FMQ
+     */
+    std::array<Event, MAX_RECEIVE_BUFFER_EVENT_COUNT> mEventBuffer;
+};
+
+#endif  // ANDROID_SENSORS_HIDL_ENVIRONMENT_V2_0_H
diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
new file mode 100644
index 0000000..7c6f010
--- /dev/null
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "sensors_hidl_hal_test"
+
+#include "SensorsHidlEnvironmentV2_0.h"
+#include "sensors-vts-utils/SensorsHidlTestBase.h"
+
+#include <android/hardware/sensors/2.0/ISensors.h>
+#include <android/hardware/sensors/2.0/types.h>
+#include <log/log.h>
+#include <utils/SystemClock.h>
+
+#include <cinttypes>
+#include <vector>
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::SensorStatus;
+using ::android::hardware::sensors::V1_0::Vec3;
+
+// The main test class for SENSORS HIDL HAL.
+
+class SensorsHidlTest : public SensorsHidlTestBase {
+   protected:
+    SensorInfo defaultSensorByType(SensorType type) override;
+    std::vector<SensorInfo> getSensorsList();
+    // implementation wrapper
+    Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) override {
+        return getSensors()->getSensorsList(_hidl_cb);
+    }
+
+    Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t maxReportLatencyNs) override {
+        return getSensors()->batch(sensorHandle, samplingPeriodNs, maxReportLatencyNs);
+    }
+
+    Return<Result> flush(int32_t sensorHandle) override {
+        return getSensors()->flush(sensorHandle);
+    }
+
+    Return<Result> injectSensorData(const Event& event) override {
+        return getSensors()->injectSensorData(event);
+    }
+
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       ISensors::registerDirectChannel_cb _hidl_cb) override;
+
+    Return<Result> unregisterDirectChannel(int32_t channelHandle) override {
+        return getSensors()->unregisterDirectChannel(channelHandle);
+    }
+
+    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+                                    ISensors::configDirectReport_cb _hidl_cb) override {
+        return getSensors()->configDirectReport(sensorHandle, channelHandle, rate, _hidl_cb);
+    }
+
+    inline sp<::android::hardware::sensors::V2_0::ISensors>& getSensors() {
+        return SensorsHidlEnvironmentV2_0::Instance()->mSensors;
+    }
+
+    SensorsHidlEnvironmentBase* getEnvironment() override {
+        return SensorsHidlEnvironmentV2_0::Instance();
+    }
+};
+
+Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
+    // If activating a sensor, add the handle in a set so that when test fails it can be turned off.
+    // The handle is not removed when it is deactivating on purpose so that it is not necessary to
+    // check the return value of deactivation. Deactivating a sensor more than once does not have
+    // negative effect.
+    if (enabled) {
+        mSensorHandles.insert(sensorHandle);
+    }
+    return getSensors()->activate(sensorHandle, enabled);
+}
+
+Return<void> SensorsHidlTest::registerDirectChannel(const SharedMemInfo& mem,
+                                                    ISensors::registerDirectChannel_cb cb) {
+    // If registeration of a channel succeeds, add the handle of channel to a set so that it can be
+    // unregistered when test fails. Unregister a channel does not remove the handle on purpose.
+    // Unregistering a channel more than once should not have negative effect.
+    getSensors()->registerDirectChannel(mem, [&](auto result, auto channelHandle) {
+        if (result == Result::OK) {
+            mDirectChannelHandles.insert(channelHandle);
+        }
+        cb(result, channelHandle);
+    });
+    return Void();
+}
+
+SensorInfo SensorsHidlTest::defaultSensorByType(SensorType type) {
+    SensorInfo ret;
+
+    ret.type = (SensorType)-1;
+    getSensors()->getSensorsList([&](const auto& list) {
+        const size_t count = list.size();
+        for (size_t i = 0; i < count; ++i) {
+            if (list[i].type == type) {
+                ret = list[i];
+                return;
+            }
+        }
+    });
+
+    return ret;
+}
+
+std::vector<SensorInfo> SensorsHidlTest::getSensorsList() {
+    std::vector<SensorInfo> ret;
+
+    getSensors()->getSensorsList([&](const auto& list) {
+        const size_t count = list.size();
+        ret.reserve(list.size());
+        for (size_t i = 0; i < count; ++i) {
+            ret.push_back(list[i]);
+        }
+    });
+
+    return ret;
+}
+
+// Test if sensor list returned is valid
+TEST_F(SensorsHidlTest, SensorListValid) {
+    getSensors()->getSensorsList([&](const auto& list) {
+        const size_t count = list.size();
+        for (size_t i = 0; i < count; ++i) {
+            const auto& s = list[i];
+            SCOPED_TRACE(::testing::Message()
+                         << i << "/" << count << ": "
+                         << " handle=0x" << std::hex << std::setw(8) << std::setfill('0')
+                         << s.sensorHandle << std::dec << " type=" << static_cast<int>(s.type)
+                         << " name=" << s.name);
+
+            // Test non-empty type string
+            EXPECT_FALSE(s.typeAsString.empty());
+
+            // Test defined type matches defined string type
+            EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(s.type, s.typeAsString));
+
+            // Test if all sensor has name and vendor
+            EXPECT_FALSE(s.name.empty());
+            EXPECT_FALSE(s.vendor.empty());
+
+            // Test power > 0, maxRange > 0
+            EXPECT_LE(0, s.power);
+            EXPECT_LT(0, s.maxRange);
+
+            // Info type, should have no sensor
+            EXPECT_FALSE(s.type == SensorType::ADDITIONAL_INFO || s.type == SensorType::META_DATA);
+
+            // Test fifoMax >= fifoReserved
+            EXPECT_GE(s.fifoMaxEventCount, s.fifoReservedEventCount)
+                << "max=" << s.fifoMaxEventCount << " reserved=" << s.fifoReservedEventCount;
+
+            // Test Reporting mode valid
+            EXPECT_NO_FATAL_FAILURE(assertTypeMatchReportMode(s.type, extractReportMode(s.flags)));
+
+            // Test min max are in the right order
+            EXPECT_LE(s.minDelay, s.maxDelay);
+            // Test min/max delay matches reporting mode
+            EXPECT_NO_FATAL_FAILURE(
+                assertDelayMatchReportMode(s.minDelay, s.maxDelay, extractReportMode(s.flags)));
+        }
+    });
+}
+
+// Test if sensor list returned is valid
+TEST_F(SensorsHidlTest, SetOperationMode) {
+    std::vector<SensorInfo> sensorList = getSensorsList();
+
+    bool needOperationModeSupport =
+        std::any_of(sensorList.begin(), sensorList.end(),
+                    [](const auto& s) { return (s.flags & SensorFlagBits::DATA_INJECTION) != 0; });
+    if (!needOperationModeSupport) {
+        return;
+    }
+
+    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
+    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
+    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
+}
+
+// Test if sensor list returned is valid
+TEST_F(SensorsHidlTest, InjectSensorEventData) {
+    std::vector<SensorInfo> sensorList = getSensorsList();
+    std::vector<SensorInfo> sensorSupportInjection;
+
+    bool needOperationModeSupport =
+        std::any_of(sensorList.begin(), sensorList.end(), [&sensorSupportInjection](const auto& s) {
+            bool ret = (s.flags & SensorFlagBits::DATA_INJECTION) != 0;
+            if (ret) {
+                sensorSupportInjection.push_back(s);
+            }
+            return ret;
+        });
+    if (!needOperationModeSupport) {
+        return;
+    }
+
+    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
+    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::DATA_INJECTION));
+
+    for (const auto& s : sensorSupportInjection) {
+        switch (s.type) {
+            case SensorType::ACCELEROMETER:
+            case SensorType::GYROSCOPE:
+            case SensorType::MAGNETIC_FIELD: {
+                usleep(100000);  // sleep 100ms
+
+                Event dummy;
+                dummy.timestamp = android::elapsedRealtimeNano();
+                dummy.sensorType = s.type;
+                dummy.sensorHandle = s.sensorHandle;
+                Vec3 v = {1, 2, 3, SensorStatus::ACCURACY_HIGH};
+                dummy.u.vec3 = v;
+
+                EXPECT_EQ(Result::OK, getSensors()->injectSensorData(dummy));
+                break;
+            }
+            default:
+                break;
+        }
+    }
+    ASSERT_EQ(Result::OK, getSensors()->setOperationMode(OperationMode::NORMAL));
+}
+
+// Test if sensor hal can do UI speed accelerometer streaming properly
+TEST_F(SensorsHidlTest, AccelerometerStreamingOperationSlow) {
+    testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(200),
+                           std::chrono::seconds(5), sAccelNormChecker);
+}
+
+// Test if sensor hal can do normal speed accelerometer streaming properly
+TEST_F(SensorsHidlTest, AccelerometerStreamingOperationNormal) {
+    testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(20),
+                           std::chrono::seconds(5), sAccelNormChecker);
+}
+
+// Test if sensor hal can do game speed accelerometer streaming properly
+TEST_F(SensorsHidlTest, AccelerometerStreamingOperationFast) {
+    testStreamingOperation(SensorType::ACCELEROMETER, std::chrono::milliseconds(5),
+                           std::chrono::seconds(5), sAccelNormChecker);
+}
+
+// Test if sensor hal can do UI speed gyroscope streaming properly
+TEST_F(SensorsHidlTest, GyroscopeStreamingOperationSlow) {
+    testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(200),
+                           std::chrono::seconds(5), sGyroNormChecker);
+}
+
+// Test if sensor hal can do normal speed gyroscope streaming properly
+TEST_F(SensorsHidlTest, GyroscopeStreamingOperationNormal) {
+    testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(20),
+                           std::chrono::seconds(5), sGyroNormChecker);
+}
+
+// Test if sensor hal can do game speed gyroscope streaming properly
+TEST_F(SensorsHidlTest, GyroscopeStreamingOperationFast) {
+    testStreamingOperation(SensorType::GYROSCOPE, std::chrono::milliseconds(5),
+                           std::chrono::seconds(5), sGyroNormChecker);
+}
+
+// Test if sensor hal can do UI speed magnetometer streaming properly
+TEST_F(SensorsHidlTest, MagnetometerStreamingOperationSlow) {
+    testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(200),
+                           std::chrono::seconds(5), NullChecker());
+}
+
+// Test if sensor hal can do normal speed magnetometer streaming properly
+TEST_F(SensorsHidlTest, MagnetometerStreamingOperationNormal) {
+    testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(20),
+                           std::chrono::seconds(5), NullChecker());
+}
+
+// Test if sensor hal can do game speed magnetometer streaming properly
+TEST_F(SensorsHidlTest, MagnetometerStreamingOperationFast) {
+    testStreamingOperation(SensorType::MAGNETIC_FIELD, std::chrono::milliseconds(5),
+                           std::chrono::seconds(5), NullChecker());
+}
+
+// Test if sensor hal can do accelerometer sampling rate switch properly when sensor is active
+TEST_F(SensorsHidlTest, AccelerometerSamplingPeriodHotSwitchOperation) {
+    testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER);
+    testSamplingRateHotSwitchOperation(SensorType::ACCELEROMETER, false /*fastToSlow*/);
+}
+
+// Test if sensor hal can do gyroscope sampling rate switch properly when sensor is active
+TEST_F(SensorsHidlTest, GyroscopeSamplingPeriodHotSwitchOperation) {
+    testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE);
+    testSamplingRateHotSwitchOperation(SensorType::GYROSCOPE, false /*fastToSlow*/);
+}
+
+// Test if sensor hal can do magnetometer sampling rate switch properly when sensor is active
+TEST_F(SensorsHidlTest, MagnetometerSamplingPeriodHotSwitchOperation) {
+    testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD);
+    testSamplingRateHotSwitchOperation(SensorType::MAGNETIC_FIELD, false /*fastToSlow*/);
+}
+
+// Test if sensor hal can do accelerometer batching properly
+TEST_F(SensorsHidlTest, AccelerometerBatchingOperation) {
+    testBatchingOperation(SensorType::ACCELEROMETER);
+}
+
+// Test if sensor hal can do gyroscope batching properly
+TEST_F(SensorsHidlTest, GyroscopeBatchingOperation) {
+    testBatchingOperation(SensorType::GYROSCOPE);
+}
+
+// Test if sensor hal can do magnetometer batching properly
+TEST_F(SensorsHidlTest, MagnetometerBatchingOperation) {
+    testBatchingOperation(SensorType::MAGNETIC_FIELD);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at normal rate
+TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationNormal) {
+    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::NORMAL,
+                              sAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at fast rate
+TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationFast) {
+    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM, RateLevel::FAST,
+                              sAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for accel sensor at very fast rate
+TEST_F(SensorsHidlTest, AccelerometerAshmemDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::ASHMEM,
+                              RateLevel::VERY_FAST, sAccelNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at normal rate
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationNormal) {
+    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::NORMAL,
+                              sGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at fast rate
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationFast) {
+    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::FAST,
+                              sGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for gyro sensor at very fast rate
+TEST_F(SensorsHidlTest, GyroscopeAshmemDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::ASHMEM, RateLevel::VERY_FAST,
+                              sGyroNormChecker);
+}
+
+// Test sensor event direct report with ashmem for mag sensor at normal rate
+TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationNormal) {
+    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::NORMAL,
+                              NullChecker());
+}
+
+// Test sensor event direct report with ashmem for mag sensor at fast rate
+TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationFast) {
+    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM, RateLevel::FAST,
+                              NullChecker());
+}
+
+// Test sensor event direct report with ashmem for mag sensor at very fast rate
+TEST_F(SensorsHidlTest, MagnetometerAshmemDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::ASHMEM,
+                              RateLevel::VERY_FAST, NullChecker());
+}
+
+// Test sensor event direct report with gralloc for accel sensor at normal rate
+TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationNormal) {
+    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::NORMAL,
+                              sAccelNormChecker);
+}
+
+// Test sensor event direct report with gralloc for accel sensor at fast rate
+TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationFast) {
+    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC, RateLevel::FAST,
+                              sAccelNormChecker);
+}
+
+// Test sensor event direct report with gralloc for accel sensor at very fast rate
+TEST_F(SensorsHidlTest, AccelerometerGrallocDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorType::ACCELEROMETER, SharedMemType::GRALLOC,
+                              RateLevel::VERY_FAST, sAccelNormChecker);
+}
+
+// Test sensor event direct report with gralloc for gyro sensor at normal rate
+TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationNormal) {
+    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::NORMAL,
+                              sGyroNormChecker);
+}
+
+// Test sensor event direct report with gralloc for gyro sensor at fast rate
+TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationFast) {
+    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::FAST,
+                              sGyroNormChecker);
+}
+
+// Test sensor event direct report with gralloc for gyro sensor at very fast rate
+TEST_F(SensorsHidlTest, GyroscopeGrallocDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorType::GYROSCOPE, SharedMemType::GRALLOC, RateLevel::VERY_FAST,
+                              sGyroNormChecker);
+}
+
+// Test sensor event direct report with gralloc for mag sensor at normal rate
+TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationNormal) {
+    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::NORMAL,
+                              NullChecker());
+}
+
+// Test sensor event direct report with gralloc for mag sensor at fast rate
+TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationFast) {
+    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC, RateLevel::FAST,
+                              NullChecker());
+}
+
+// Test sensor event direct report with gralloc for mag sensor at very fast rate
+TEST_F(SensorsHidlTest, MagnetometerGrallocDirectReportOperationVeryFast) {
+    testDirectReportOperation(SensorType::MAGNETIC_FIELD, SharedMemType::GRALLOC,
+                              RateLevel::VERY_FAST, NullChecker());
+}
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(SensorsHidlEnvironmentV2_0::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    SensorsHidlEnvironmentV2_0::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    ALOGI("Test result = %d", status);
+    return status;
+}
+// vim: set ts=2 sw=2
diff --git a/sensors/common/vts/OWNERS b/sensors/common/vts/OWNERS
new file mode 100644
index 0000000..759d87b
--- /dev/null
+++ b/sensors/common/vts/OWNERS
@@ -0,0 +1,7 @@
+# Sensors team
+bduddie@google.com
+bstack@google.com
+
+# VTS team
+trong@google.com
+yim@google.com
diff --git a/sensors/common/vts/utils/Android.bp b/sensors/common/vts/utils/Android.bp
new file mode 100644
index 0000000..95df425
--- /dev/null
+++ b/sensors/common/vts/utils/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_library_static {
+    name: "VtsHalSensorsTargetTestUtils",
+    srcs: [
+        "GrallocWrapper.cpp",
+        "SensorsHidlEnvironmentBase.cpp",
+        "SensorsHidlTestBase.cpp",
+        "SensorsTestSharedMemory.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+    local_include_dirs: [
+        "include/sensors-vts-utils",
+    ],
+    static_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+        "android.hardware.sensors@1.0",
+        "VtsHalHidlTargetTestBase",
+    ],
+}
diff --git a/sensors/common/vts/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp
new file mode 100644
index 0000000..7bed16d
--- /dev/null
+++ b/sensors/common/vts/utils/GrallocWrapper.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GrallocWrapper"
+
+#include "GrallocWrapper.h"
+
+#include <utils/Log.h>
+
+namespace android {
+
+GrallocWrapper::GrallocWrapper() {
+    init();
+}
+
+void GrallocWrapper::init() {
+    mAllocator = allocator2::IAllocator::getService();
+    if (mAllocator == nullptr) {
+        ALOGE("Failed to get allocator service");
+    }
+
+    mMapper = mapper2::IMapper::getService();
+    if (mMapper == nullptr) {
+        ALOGE("Failed to get mapper service");
+    }
+    if (mMapper->isRemote()) {
+        ALOGE("Mapper is not in passthrough mode");
+    }
+}
+
+GrallocWrapper::~GrallocWrapper() {
+    for (auto bufferHandle : mClonedBuffers) {
+        auto buffer = const_cast<native_handle_t*>(bufferHandle);
+        native_handle_close(buffer);
+        native_handle_delete(buffer);
+    }
+    mClonedBuffers.clear();
+
+    for (auto bufferHandle : mImportedBuffers) {
+        auto buffer = const_cast<native_handle_t*>(bufferHandle);
+        if (mMapper->freeBuffer(buffer) != mapper2::Error::NONE) {
+            ALOGE("Failed to free buffer %p", buffer);
+        }
+    }
+    mImportedBuffers.clear();
+}
+
+sp<allocator2::IAllocator> GrallocWrapper::getAllocator() const {
+    return mAllocator;
+}
+
+std::string GrallocWrapper::dumpDebugInfo() {
+    std::string debugInfo;
+    mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+
+    return debugInfo;
+}
+
+const native_handle_t* GrallocWrapper::cloneBuffer(const hardware::hidl_handle& rawHandle) {
+    const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
+
+    if (bufferHandle) {
+        mClonedBuffers.insert(bufferHandle);
+    }
+    return bufferHandle;
+}
+
+std::vector<const native_handle_t*> GrallocWrapper::allocate(
+    const mapper2::BufferDescriptor& descriptor, uint32_t count, bool import, uint32_t* outStride) {
+    std::vector<const native_handle_t*> bufferHandles;
+    bufferHandles.reserve(count);
+    mAllocator->allocate(descriptor, count,
+                         [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
+                             if (mapper2::Error::NONE != tmpError) {
+                                 ALOGE("Failed to allocate buffers");
+                             }
+                             if (count != tmpBuffers.size()) {
+                                 ALOGE("Invalid buffer array");
+                             }
+
+                             for (uint32_t i = 0; i < count; i++) {
+                                 if (import) {
+                                     bufferHandles.push_back(importBuffer(tmpBuffers[i]));
+                                 } else {
+                                     bufferHandles.push_back(cloneBuffer(tmpBuffers[i]));
+                                 }
+                             }
+
+                             if (outStride) {
+                                 *outStride = tmpStride;
+                             }
+                         });
+
+    return bufferHandles;
+}
+
+const native_handle_t* GrallocWrapper::allocate(
+    const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo, bool import,
+    uint32_t* outStride) {
+    mapper2::BufferDescriptor descriptor = createDescriptor(descriptorInfo);
+    auto buffers = allocate(descriptor, 1, import, outStride);
+    return buffers[0];
+}
+
+sp<mapper2::IMapper> GrallocWrapper::getMapper() const {
+    return mMapper;
+}
+
+mapper2::BufferDescriptor GrallocWrapper::createDescriptor(
+    const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo) {
+    mapper2::BufferDescriptor descriptor;
+    mMapper->createDescriptor(descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
+        if (tmpError != mapper2::Error::NONE) {
+            ALOGE("Failed to create descriptor");
+        }
+        descriptor = tmpDescriptor;
+    });
+
+    return descriptor;
+}
+
+const native_handle_t* GrallocWrapper::importBuffer(const hardware::hidl_handle& rawHandle) {
+    const native_handle_t* bufferHandle = nullptr;
+    mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
+        if (tmpError != mapper2::Error::NONE) {
+            ALOGE("Failed to import buffer %p", rawHandle.getNativeHandle());
+        }
+        bufferHandle = static_cast<const native_handle_t*>(tmpBuffer);
+    });
+
+    if (bufferHandle) {
+        mImportedBuffers.insert(bufferHandle);
+    }
+
+    return bufferHandle;
+}
+
+void GrallocWrapper::freeBuffer(const native_handle_t* bufferHandle) {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    if (mImportedBuffers.erase(bufferHandle)) {
+        mapper2::Error error = mMapper->freeBuffer(buffer);
+        if (error != mapper2::Error::NONE) {
+            ALOGE("Failed to free %p", buffer);
+        }
+    } else {
+        mClonedBuffers.erase(bufferHandle);
+        native_handle_close(buffer);
+        native_handle_delete(buffer);
+    }
+}
+
+void* GrallocWrapper::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+                           const mapper2::IMapper::Rect& accessRegion, int acquireFence) {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+    hardware::hidl_handle acquireFenceHandle;
+    if (acquireFence >= 0) {
+        auto h = native_handle_init(acquireFenceStorage, 1, 0);
+        h->data[0] = acquireFence;
+        acquireFenceHandle = h;
+    }
+
+    void* data = nullptr;
+    mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
+                  [&](const auto& tmpError, const auto& tmpData) {
+                      if (tmpError != mapper2::Error::NONE) {
+                          ALOGE("Failed to lock buffer %p", buffer);
+                      }
+                      data = tmpData;
+                  });
+
+    if (acquireFence >= 0) {
+        close(acquireFence);
+    }
+
+    return data;
+}
+
+int GrallocWrapper::unlock(const native_handle_t* bufferHandle) {
+    auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+    int releaseFence = -1;
+    mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+        if (tmpError != mapper2::Error::NONE) {
+            ALOGE("Failed to unlock buffer %p", buffer);
+        }
+
+        auto fenceHandle = tmpReleaseFence.getNativeHandle();
+        if (fenceHandle) {
+            if (fenceHandle->numInts != 0) {
+                ALOGE("Invalid fence handle %p", fenceHandle);
+            }
+            if (fenceHandle->numFds == 1) {
+                releaseFence = dup(fenceHandle->data[0]);
+                if (releaseFence < 0) {
+                    ALOGE("Failed to dup fence fd");
+                }
+            } else {
+                if (fenceHandle->numFds != 0) {
+                    ALOGE("Invalid fence handle %p", fenceHandle);
+                }
+            }
+        }
+    });
+
+    return releaseFence;
+}
+
+}  // namespace android
diff --git a/sensors/common/vts/utils/OWNERS b/sensors/common/vts/utils/OWNERS
new file mode 100644
index 0000000..759d87b
--- /dev/null
+++ b/sensors/common/vts/utils/OWNERS
@@ -0,0 +1,7 @@
+# Sensors team
+bduddie@google.com
+bstack@google.com
+
+# VTS team
+trong@google.com
+yim@google.com
diff --git a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
new file mode 100644
index 0000000..21c08d2
--- /dev/null
+++ b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SensorsHidlEnvironmentBase.h"
+
+void SensorsHidlEnvironmentBase::HidlSetUp() {
+    ASSERT_TRUE(resetHal()) << "could not get hidl service";
+
+    collectionEnabled = false;
+    startPollingThread();
+
+    // In case framework just stopped for test and there is sensor events in the pipe,
+    // wait some time for those events to be cleared to avoid them messing up the test.
+    std::this_thread::sleep_for(std::chrono::seconds(3));
+}
+
+void SensorsHidlEnvironmentBase::HidlTearDown() {
+    stopThread = true;
+    pollThread.detach();
+}
+
+void SensorsHidlEnvironmentBase::catEvents(std::vector<Event>* output) {
+    std::lock_guard<std::mutex> lock(events_mutex);
+    if (output) {
+        output->insert(output->end(), events.begin(), events.end());
+    }
+    events.clear();
+}
+
+void SensorsHidlEnvironmentBase::setCollection(bool enable) {
+    std::lock_guard<std::mutex> lock(events_mutex);
+    collectionEnabled = enable;
+}
+
+void SensorsHidlEnvironmentBase::addEvent(const Event& ev) {
+    std::lock_guard<std::mutex> lock(events_mutex);
+    if (collectionEnabled) {
+        events.push_back(ev);
+    }
+}
diff --git a/sensors/common/vts/utils/SensorsHidlTestBase.cpp b/sensors/common/vts/utils/SensorsHidlTestBase.cpp
new file mode 100644
index 0000000..b72fdfd
--- /dev/null
+++ b/sensors/common/vts/utils/SensorsHidlTestBase.cpp
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SensorsHidlTestBase.h"
+
+#include "sensors-vts-utils/GrallocWrapper.h"
+#include "sensors-vts-utils/SensorsTestSharedMemory.h"
+
+#include <hardware/sensors.h>  // for sensor type strings
+#include <log/log.h>
+#include <utils/SystemClock.h>
+
+#include <cinttypes>
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::sensors::V1_0::SensorFlagShift;
+using ::android::hardware::sensors::V1_0::SensorsEventFormatOffset;
+
+const Vec3NormChecker SensorsHidlTestBase::sAccelNormChecker(
+    Vec3NormChecker::byNominal(GRAVITY_EARTH, 1.0f /*m/s^2*/));
+const Vec3NormChecker SensorsHidlTestBase::sGyroNormChecker(
+    Vec3NormChecker::byNominal(0.f, 0.1f /*rad/s*/));
+
+std::vector<Event> SensorsHidlTestBase::collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
+                                                      bool clearBeforeStart,
+                                                      bool changeCollection) {
+    std::vector<Event> events;
+    constexpr useconds_t SLEEP_GRANULARITY = 100 * 1000;  // granularity 100 ms
+
+    ALOGI("collect max of %zu events for %d us, clearBeforeStart %d", nEventLimit, timeLimitUs,
+          clearBeforeStart);
+
+    if (changeCollection) {
+        getEnvironment()->setCollection(true);
+    }
+    if (clearBeforeStart) {
+        getEnvironment()->catEvents(nullptr);
+    }
+
+    while (timeLimitUs > 0) {
+        useconds_t duration = std::min(SLEEP_GRANULARITY, timeLimitUs);
+        usleep(duration);
+        timeLimitUs -= duration;
+
+        getEnvironment()->catEvents(&events);
+        if (events.size() >= nEventLimit) {
+            break;
+        }
+        ALOGV("time to go = %d, events to go = %d", (int)timeLimitUs,
+              (int)(nEventLimit - events.size()));
+    }
+
+    if (changeCollection) {
+        getEnvironment()->setCollection(false);
+    }
+    return events;
+}
+
+void SensorsHidlTestBase::assertTypeMatchStringType(SensorType type,
+                                                    const hidl_string& stringType) {
+    if (type >= SensorType::DEVICE_PRIVATE_BASE) {
+        return;
+    }
+
+    switch (type) {
+#define CHECK_TYPE_STRING_FOR_SENSOR_TYPE(type)                      \
+    case SensorType::type:                                           \
+        ASSERT_STREQ(SENSOR_STRING_TYPE_##type, stringType.c_str()); \
+        break;
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ACCELEROMETER_UNCALIBRATED);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ADDITIONAL_INFO);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(AMBIENT_TEMPERATURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DEVICE_ORIENTATION);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(DYNAMIC_SENSOR_META);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GAME_ROTATION_VECTOR);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GEOMAGNETIC_ROTATION_VECTOR);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GLANCE_GESTURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GRAVITY);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(GYROSCOPE_UNCALIBRATED);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_BEAT);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(HEART_RATE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LIGHT);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LINEAR_ACCELERATION);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(LOW_LATENCY_OFFBODY_DETECT);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MAGNETIC_FIELD_UNCALIBRATED);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(MOTION_DETECT);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ORIENTATION);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PICK_UP_GESTURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(POSE_6DOF);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PRESSURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(PROXIMITY);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(RELATIVE_HUMIDITY);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(ROTATION_VECTOR);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(SIGNIFICANT_MOTION);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STATIONARY_DETECT);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_COUNTER);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(STEP_DETECTOR);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TEMPERATURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(TILT_DETECTOR);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WAKE_GESTURE);
+        CHECK_TYPE_STRING_FOR_SENSOR_TYPE(WRIST_TILT_GESTURE);
+        default:
+            FAIL() << "Type " << static_cast<int>(type)
+                   << " in android defined range is not checked, "
+                   << "stringType = " << stringType;
+#undef CHECK_TYPE_STRING_FOR_SENSOR_TYPE
+    }
+}
+
+void SensorsHidlTestBase::assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode) {
+    if (type >= SensorType::DEVICE_PRIVATE_BASE) {
+        return;
+    }
+
+    SensorFlagBits expected = expectedReportModeForType(type);
+
+    ASSERT_TRUE(expected == (SensorFlagBits)-1 || expected == reportMode)
+        << "reportMode=" << static_cast<int>(reportMode)
+        << "expected=" << static_cast<int>(expected);
+}
+
+void SensorsHidlTestBase::assertDelayMatchReportMode(int32_t minDelay, int32_t maxDelay,
+                                                     SensorFlagBits reportMode) {
+    switch (reportMode) {
+        case SensorFlagBits::CONTINUOUS_MODE:
+            ASSERT_LT(0, minDelay);
+            ASSERT_LE(0, maxDelay);
+            break;
+        case SensorFlagBits::ON_CHANGE_MODE:
+            ASSERT_LE(0, minDelay);
+            ASSERT_LE(0, maxDelay);
+            break;
+        case SensorFlagBits::ONE_SHOT_MODE:
+            ASSERT_EQ(-1, minDelay);
+            ASSERT_EQ(0, maxDelay);
+            break;
+        case SensorFlagBits::SPECIAL_REPORTING_MODE:
+            // do not enforce anything for special reporting mode
+            break;
+        default:
+            FAIL() << "Report mode " << static_cast<int>(reportMode) << " not checked";
+    }
+}
+
+// return -1 means no expectation for this type
+SensorFlagBits SensorsHidlTestBase::expectedReportModeForType(SensorType type) {
+    switch (type) {
+        case SensorType::ACCELEROMETER:
+        case SensorType::ACCELEROMETER_UNCALIBRATED:
+        case SensorType::GYROSCOPE:
+        case SensorType::MAGNETIC_FIELD:
+        case SensorType::ORIENTATION:
+        case SensorType::PRESSURE:
+        case SensorType::TEMPERATURE:
+        case SensorType::GRAVITY:
+        case SensorType::LINEAR_ACCELERATION:
+        case SensorType::ROTATION_VECTOR:
+        case SensorType::MAGNETIC_FIELD_UNCALIBRATED:
+        case SensorType::GAME_ROTATION_VECTOR:
+        case SensorType::GYROSCOPE_UNCALIBRATED:
+        case SensorType::GEOMAGNETIC_ROTATION_VECTOR:
+        case SensorType::POSE_6DOF:
+        case SensorType::HEART_BEAT:
+            return SensorFlagBits::CONTINUOUS_MODE;
+
+        case SensorType::LIGHT:
+        case SensorType::PROXIMITY:
+        case SensorType::RELATIVE_HUMIDITY:
+        case SensorType::AMBIENT_TEMPERATURE:
+        case SensorType::HEART_RATE:
+        case SensorType::DEVICE_ORIENTATION:
+        case SensorType::STEP_COUNTER:
+        case SensorType::LOW_LATENCY_OFFBODY_DETECT:
+            return SensorFlagBits::ON_CHANGE_MODE;
+
+        case SensorType::SIGNIFICANT_MOTION:
+        case SensorType::WAKE_GESTURE:
+        case SensorType::GLANCE_GESTURE:
+        case SensorType::PICK_UP_GESTURE:
+        case SensorType::MOTION_DETECT:
+        case SensorType::STATIONARY_DETECT:
+            return SensorFlagBits::ONE_SHOT_MODE;
+
+        case SensorType::STEP_DETECTOR:
+        case SensorType::TILT_DETECTOR:
+        case SensorType::WRIST_TILT_GESTURE:
+        case SensorType::DYNAMIC_SENSOR_META:
+            return SensorFlagBits::SPECIAL_REPORTING_MODE;
+
+        default:
+            ALOGW("Type %d is not implemented in expectedReportModeForType", (int)type);
+            return (SensorFlagBits)-1;
+    }
+}
+
+bool SensorsHidlTestBase::isDirectReportRateSupported(SensorInfo sensor, RateLevel rate) {
+    unsigned int r = static_cast<unsigned int>(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT) >>
+                     static_cast<unsigned int>(SensorFlagShift::DIRECT_REPORT);
+    return r >= static_cast<unsigned int>(rate);
+}
+
+bool SensorsHidlTestBase::isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type) {
+    switch (type) {
+        case SharedMemType::ASHMEM:
+            return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_ASHMEM) != 0;
+        case SharedMemType::GRALLOC:
+            return (sensor.flags & SensorFlagBits::DIRECT_CHANNEL_GRALLOC) != 0;
+        default:
+            return false;
+    }
+}
+
+void SensorsHidlTestBase::testDirectReportOperation(SensorType type, SharedMemType memType,
+                                                    RateLevel rate,
+                                                    const SensorEventsChecker& checker) {
+    constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
+    constexpr size_t kNEvent = 4096;
+    constexpr size_t kMemSize = kEventSize * kNEvent;
+
+    constexpr float kNormalNominal = 50;
+    constexpr float kFastNominal = 200;
+    constexpr float kVeryFastNominal = 800;
+
+    constexpr float kNominalTestTimeSec = 1.f;
+    constexpr float kMaxTestTimeSec = kNominalTestTimeSec + 0.5f;  // 0.5 second for initialization
+
+    SensorInfo sensor = defaultSensorByType(type);
+
+    if (!isValidType(sensor.type)) {
+        // no default sensor of this type
+        return;
+    }
+
+    if (!isDirectReportRateSupported(sensor, rate)) {
+        return;
+    }
+
+    if (!isDirectChannelTypeSupported(sensor, memType)) {
+        return;
+    }
+
+    std::unique_ptr<SensorsTestSharedMemory> mem(
+        SensorsTestSharedMemory::create(memType, kMemSize));
+    ASSERT_NE(mem, nullptr);
+
+    char* buffer = mem->getBuffer();
+    // fill memory with data
+    for (size_t i = 0; i < kMemSize; ++i) {
+        buffer[i] = '\xcc';
+    }
+
+    int32_t channelHandle;
+    registerDirectChannel(mem->getSharedMemInfo(),
+                          [&channelHandle](auto result, auto channelHandle_) {
+                              ASSERT_EQ(result, Result::OK);
+                              channelHandle = channelHandle_;
+                          });
+
+    // check memory is zeroed
+    for (size_t i = 0; i < kMemSize; ++i) {
+        ASSERT_EQ(buffer[i], '\0');
+    }
+
+    int32_t eventToken;
+    configDirectReport(sensor.sensorHandle, channelHandle, rate,
+                       [&eventToken](auto result, auto token) {
+                           ASSERT_EQ(result, Result::OK);
+                           eventToken = token;
+                       });
+
+    usleep(static_cast<useconds_t>(kMaxTestTimeSec * 1e6f));
+    auto events = mem->parseEvents();
+
+    // find norminal rate
+    float nominalFreq = 0.f;
+    switch (rate) {
+        case RateLevel::NORMAL:
+            nominalFreq = kNormalNominal;
+            break;
+        case RateLevel::FAST:
+            nominalFreq = kFastNominal;
+            break;
+        case RateLevel::VERY_FAST:
+            nominalFreq = kVeryFastNominal;
+            break;
+        case RateLevel::STOP:
+            FAIL();
+    }
+
+    // allowed to be between 55% and 220% of nominal freq
+    ASSERT_GT(events.size(), static_cast<size_t>(nominalFreq * 0.55f * kNominalTestTimeSec));
+    ASSERT_LT(events.size(), static_cast<size_t>(nominalFreq * 2.2f * kMaxTestTimeSec));
+
+    int64_t lastTimestamp = 0;
+    bool typeErrorReported = false;
+    bool tokenErrorReported = false;
+    bool timestampErrorReported = false;
+    std::vector<Event> sensorEvents;
+    for (auto& e : events) {
+        if (!tokenErrorReported) {
+            EXPECT_EQ(eventToken, e.sensorHandle)
+                << (tokenErrorReported = true,
+                    "Event token does not match that retured from configDirectReport");
+        }
+
+        if (isMetaSensorType(e.sensorType)) {
+            continue;
+        }
+        sensorEvents.push_back(e);
+
+        if (!typeErrorReported) {
+            EXPECT_EQ(type, e.sensorType)
+                << (typeErrorReported = true,
+                    "Type in event does not match type of sensor registered.");
+        }
+        if (!timestampErrorReported) {
+            EXPECT_GT(e.timestamp, lastTimestamp)
+                << (timestampErrorReported = true, "Timestamp not monotonically increasing");
+        }
+        lastTimestamp = e.timestamp;
+    }
+
+    std::string s;
+    EXPECT_TRUE(checker.check(sensorEvents, &s)) << s;
+
+    // stop sensor and unregister channel
+    configDirectReport(sensor.sensorHandle, channelHandle, RateLevel::STOP,
+                       [](auto result, auto) { EXPECT_EQ(result, Result::OK); });
+    EXPECT_EQ(unregisterDirectChannel(channelHandle), Result::OK);
+}
+
+void SensorsHidlTestBase::testStreamingOperation(SensorType type,
+                                                 std::chrono::nanoseconds samplingPeriod,
+                                                 std::chrono::seconds duration,
+                                                 const SensorEventsChecker& checker) {
+    std::vector<Event> events;
+    std::vector<Event> sensorEvents;
+
+    const int64_t samplingPeriodInNs = samplingPeriod.count();
+    const int64_t batchingPeriodInNs = 0;  // no batching
+    const useconds_t minTimeUs = std::chrono::microseconds(duration).count();
+    const size_t minNEvent = duration / samplingPeriod;
+
+    SensorInfo sensor = defaultSensorByType(type);
+
+    if (!isValidType(sensor.type)) {
+        // no default sensor of this type
+        return;
+    }
+
+    if (std::chrono::microseconds(sensor.minDelay) > samplingPeriod) {
+        // rate not supported
+        return;
+    }
+
+    int32_t handle = sensor.sensorHandle;
+
+    ASSERT_EQ(batch(handle, samplingPeriodInNs, batchingPeriodInNs), Result::OK);
+    ASSERT_EQ(activate(handle, 1), Result::OK);
+    events = collectEvents(minTimeUs, minNEvent, true /*clearBeforeStart*/);
+    ASSERT_EQ(activate(handle, 0), Result::OK);
+
+    ALOGI("Collected %zu samples", events.size());
+
+    ASSERT_GT(events.size(), 0u);
+
+    bool handleMismatchReported = false;
+    bool metaSensorTypeErrorReported = false;
+    for (auto& e : events) {
+        if (e.sensorType == type) {
+            // avoid generating hundreds of error
+            if (!handleMismatchReported) {
+                EXPECT_EQ(e.sensorHandle, handle)
+                    << (handleMismatchReported = true,
+                        "Event of the same type must come from the sensor registered");
+            }
+            sensorEvents.push_back(e);
+        } else {
+            // avoid generating hundreds of error
+            if (!metaSensorTypeErrorReported) {
+                EXPECT_TRUE(isMetaSensorType(e.sensorType))
+                    << (metaSensorTypeErrorReported = true,
+                        "Only meta types are allowed besides the type registered");
+            }
+        }
+    }
+
+    std::string s;
+    EXPECT_TRUE(checker.check(sensorEvents, &s)) << s;
+
+    EXPECT_GE(sensorEvents.size(),
+              minNEvent / 2);  // make sure returned events are not all meta
+}
+
+void SensorsHidlTestBase::testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow) {
+    std::vector<Event> events1, events2;
+
+    constexpr int64_t batchingPeriodInNs = 0;          // no batching
+    constexpr int64_t collectionTimeoutUs = 60000000;  // 60s
+    constexpr size_t minNEvent = 50;
+
+    SensorInfo sensor = defaultSensorByType(type);
+
+    if (!isValidType(sensor.type)) {
+        // no default sensor of this type
+        return;
+    }
+
+    int32_t handle = sensor.sensorHandle;
+    int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll;
+    int64_t maxSamplingPeriodInNs = sensor.maxDelay * 1000ll;
+
+    if (minSamplingPeriodInNs == maxSamplingPeriodInNs) {
+        // only support single rate
+        return;
+    }
+
+    int64_t firstCollectionPeriod = fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs;
+    int64_t secondCollectionPeriod = !fastToSlow ? minSamplingPeriodInNs : maxSamplingPeriodInNs;
+
+    // first collection
+    ASSERT_EQ(batch(handle, firstCollectionPeriod, batchingPeriodInNs), Result::OK);
+    ASSERT_EQ(activate(handle, 1), Result::OK);
+
+    usleep(500000);  // sleep 0.5 sec to wait for change rate to happen
+    events1 = collectEvents(collectionTimeoutUs, minNEvent);
+
+    // second collection, without stop sensor
+    ASSERT_EQ(batch(handle, secondCollectionPeriod, batchingPeriodInNs), Result::OK);
+
+    usleep(500000);  // sleep 0.5 sec to wait for change rate to happen
+    events2 = collectEvents(collectionTimeoutUs, minNEvent);
+
+    // end of collection, stop sensor
+    ASSERT_EQ(activate(handle, 0), Result::OK);
+
+    ALOGI("Collected %zu fast samples and %zu slow samples", events1.size(), events2.size());
+
+    ASSERT_GT(events1.size(), 0u);
+    ASSERT_GT(events2.size(), 0u);
+
+    int64_t minDelayAverageInterval, maxDelayAverageInterval;
+    std::vector<Event>& minDelayEvents(fastToSlow ? events1 : events2);
+    std::vector<Event>& maxDelayEvents(fastToSlow ? events2 : events1);
+
+    size_t nEvent = 0;
+    int64_t prevTimestamp = -1;
+    int64_t timestampInterval = 0;
+    for (auto& e : minDelayEvents) {
+        if (e.sensorType == type) {
+            ASSERT_EQ(e.sensorHandle, handle);
+            if (prevTimestamp > 0) {
+                timestampInterval += e.timestamp - prevTimestamp;
+            }
+            prevTimestamp = e.timestamp;
+            ++nEvent;
+        }
+    }
+    ASSERT_GT(nEvent, 2u);
+    minDelayAverageInterval = timestampInterval / (nEvent - 1);
+
+    nEvent = 0;
+    prevTimestamp = -1;
+    timestampInterval = 0;
+    for (auto& e : maxDelayEvents) {
+        if (e.sensorType == type) {
+            ASSERT_EQ(e.sensorHandle, handle);
+            if (prevTimestamp > 0) {
+                timestampInterval += e.timestamp - prevTimestamp;
+            }
+            prevTimestamp = e.timestamp;
+            ++nEvent;
+        }
+    }
+    ASSERT_GT(nEvent, 2u);
+    maxDelayAverageInterval = timestampInterval / (nEvent - 1);
+
+    // change of rate is significant.
+    ALOGI("min/maxDelayAverageInterval = %" PRId64 " %" PRId64, minDelayAverageInterval,
+          maxDelayAverageInterval);
+    EXPECT_GT((maxDelayAverageInterval - minDelayAverageInterval), minDelayAverageInterval / 10);
+
+    // fastest rate sampling time is close to spec
+    EXPECT_LT(std::abs(minDelayAverageInterval - minSamplingPeriodInNs),
+              minSamplingPeriodInNs / 10);
+
+    // slowest rate sampling time is close to spec
+    EXPECT_LT(std::abs(maxDelayAverageInterval - maxSamplingPeriodInNs),
+              maxSamplingPeriodInNs / 10);
+}
+
+void SensorsHidlTestBase::testBatchingOperation(SensorType type) {
+    std::vector<Event> events;
+
+    constexpr int64_t maxBatchingTestTimeNs = 30ull * 1000 * 1000 * 1000;
+    constexpr int64_t oneSecondInNs = 1ull * 1000 * 1000 * 1000;
+
+    SensorInfo sensor = defaultSensorByType(type);
+
+    if (!isValidType(sensor.type)) {
+        // no default sensor of this type
+        return;
+    }
+
+    int32_t handle = sensor.sensorHandle;
+    int64_t minSamplingPeriodInNs = sensor.minDelay * 1000ll;
+    uint32_t minFifoCount = sensor.fifoReservedEventCount;
+    int64_t batchingPeriodInNs = minFifoCount * minSamplingPeriodInNs;
+
+    if (batchingPeriodInNs < oneSecondInNs) {
+        // batching size too small to test reliably
+        return;
+    }
+
+    batchingPeriodInNs = std::min(batchingPeriodInNs, maxBatchingTestTimeNs);
+
+    ALOGI("Test batching for %d ms", (int)(batchingPeriodInNs / 1000 / 1000));
+
+    int64_t allowedBatchDeliverTimeNs = std::max(oneSecondInNs, batchingPeriodInNs / 10);
+
+    ASSERT_EQ(batch(handle, minSamplingPeriodInNs, INT64_MAX), Result::OK);
+    ASSERT_EQ(activate(handle, 1), Result::OK);
+
+    usleep(500000);  // sleep 0.5 sec to wait for initialization
+    ASSERT_EQ(flush(handle), Result::OK);
+
+    // wait for 80% of the reserved batching period
+    // there should not be any significant amount of events
+    // since collection is not enabled all events will go down the drain
+    usleep(batchingPeriodInNs / 1000 * 8 / 10);
+
+    getEnvironment()->setCollection(true);
+    // clean existing collections
+    collectEvents(0 /*timeLimitUs*/, 0 /*nEventLimit*/, true /*clearBeforeStart*/,
+                  false /*change collection*/);
+
+    // 0.8 + 0.2 times the batching period
+    usleep(batchingPeriodInNs / 1000 * 8 / 10);
+    ASSERT_EQ(flush(handle), Result::OK);
+
+    // plus some time for the event to deliver
+    events = collectEvents(allowedBatchDeliverTimeNs / 1000, minFifoCount,
+                           false /*clearBeforeStart*/, false /*change collection*/);
+
+    getEnvironment()->setCollection(false);
+    ASSERT_EQ(activate(handle, 0), Result::OK);
+
+    size_t nEvent = 0;
+    for (auto& e : events) {
+        if (e.sensorType == type && e.sensorHandle == handle) {
+            ++nEvent;
+        }
+    }
+
+    // at least reach 90% of advertised capacity
+    ASSERT_GT(nEvent, (size_t)(minFifoCount * 9 / 10));
+}
diff --git a/sensors/common/vts/utils/SensorsTestSharedMemory.cpp b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
new file mode 100644
index 0000000..5096498
--- /dev/null
+++ b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SensorsTestSharedMemory.h"
+
+#include <log/log.h>
+
+#include <sys/mman.h>
+#include <cinttypes>
+
+using namespace ::android::hardware::sensors::V1_0;
+
+SharedMemInfo SensorsTestSharedMemory::getSharedMemInfo() const {
+    SharedMemInfo mem = {.type = mType,
+                         .format = SharedMemFormat::SENSORS_EVENT,
+                         .size = static_cast<uint32_t>(mSize),
+                         .memoryHandle = mNativeHandle};
+    return mem;
+}
+
+char* SensorsTestSharedMemory::getBuffer() const {
+    return mBuffer;
+}
+
+std::vector<Event> SensorsTestSharedMemory::parseEvents(int64_t lastCounter, size_t offset) const {
+    constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
+    constexpr size_t kOffsetSize = static_cast<size_t>(SensorsEventFormatOffset::SIZE_FIELD);
+    constexpr size_t kOffsetToken = static_cast<size_t>(SensorsEventFormatOffset::REPORT_TOKEN);
+    constexpr size_t kOffsetType = static_cast<size_t>(SensorsEventFormatOffset::SENSOR_TYPE);
+    constexpr size_t kOffsetAtomicCounter =
+        static_cast<size_t>(SensorsEventFormatOffset::ATOMIC_COUNTER);
+    constexpr size_t kOffsetTimestamp = static_cast<size_t>(SensorsEventFormatOffset::TIMESTAMP);
+    constexpr size_t kOffsetData = static_cast<size_t>(SensorsEventFormatOffset::DATA);
+
+    std::vector<Event> events;
+    std::vector<float> data(16);
+
+    while (offset + kEventSize <= mSize) {
+        int64_t atomicCounter =
+            *reinterpret_cast<uint32_t*>(mBuffer + offset + kOffsetAtomicCounter);
+        if (atomicCounter <= lastCounter) {
+            ALOGV("atomicCounter = %" PRId64 ", lastCounter = %" PRId64, atomicCounter,
+                  lastCounter);
+            break;
+        }
+
+        int32_t size = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetSize);
+        if (size != kEventSize) {
+            // unknown error, events parsed may be wrong, remove all
+            events.clear();
+            break;
+        }
+
+        int32_t token = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetToken);
+        int32_t type = *reinterpret_cast<int32_t*>(mBuffer + offset + kOffsetType);
+        int64_t timestamp = *reinterpret_cast<int64_t*>(mBuffer + offset + kOffsetTimestamp);
+
+        ALOGV("offset = %zu, cnt %" PRId64 ", token %" PRId32 ", type %" PRId32
+              ", timestamp %" PRId64,
+              offset, atomicCounter, token, type, timestamp);
+
+        Event event = {
+            .timestamp = timestamp,
+            .sensorHandle = token,
+            .sensorType = static_cast<SensorType>(type),
+        };
+        event.u.data = android::hardware::hidl_array<float, 16>(
+            reinterpret_cast<float*>(mBuffer + offset + kOffsetData));
+
+        events.push_back(event);
+
+        lastCounter = atomicCounter;
+        offset += kEventSize;
+    }
+
+    return events;
+}
+
+SensorsTestSharedMemory::SensorsTestSharedMemory(SharedMemType type, size_t size)
+    : mType(type), mSize(0), mBuffer(nullptr) {
+    native_handle_t* handle = nullptr;
+    char* buffer = nullptr;
+    switch (type) {
+        case SharedMemType::ASHMEM: {
+            int fd;
+            handle = ::native_handle_create(1 /*nFds*/, 0 /*nInts*/);
+            if (handle != nullptr) {
+                handle->data[0] = fd = ::ashmem_create_region("SensorsTestSharedMemory", size);
+                if (handle->data[0] > 0) {
+                    // memory is pinned by default
+                    buffer = static_cast<char*>(
+                        ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
+                    if (buffer != reinterpret_cast<char*>(MAP_FAILED)) {
+                        break;
+                    }
+                    ::native_handle_close(handle);
+                }
+                ::native_handle_delete(handle);
+                handle = nullptr;
+            }
+            break;
+        }
+        case SharedMemType::GRALLOC: {
+            mGrallocWrapper = std::make_unique<::android::GrallocWrapper>();
+            if (mGrallocWrapper->getAllocator() == nullptr ||
+                mGrallocWrapper->getMapper() == nullptr) {
+                break;
+            }
+            using android::hardware::graphics::common::V1_0::BufferUsage;
+            using android::hardware::graphics::common::V1_0::PixelFormat;
+            mapper2::IMapper::BufferDescriptorInfo buf_desc_info = {
+                .width = static_cast<uint32_t>(size),
+                .height = 1,
+                .layerCount = 1,
+                .usage = static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA |
+                                               BufferUsage::CPU_READ_OFTEN),
+                .format = PixelFormat::BLOB};
+
+            handle = const_cast<native_handle_t*>(mGrallocWrapper->allocate(buf_desc_info));
+            if (handle != nullptr) {
+                mapper2::IMapper::Rect region{0, 0, static_cast<int32_t>(buf_desc_info.width),
+                                              static_cast<int32_t>(buf_desc_info.height)};
+                buffer = static_cast<char*>(
+                    mGrallocWrapper->lock(handle, buf_desc_info.usage, region, /*fence=*/-1));
+                if (buffer != nullptr) {
+                    break;
+                }
+                mGrallocWrapper->freeBuffer(handle);
+                handle = nullptr;
+            }
+            break;
+        }
+        default:
+            break;
+    }
+
+    if (buffer != nullptr) {
+        mNativeHandle = handle;
+        mSize = size;
+        mBuffer = buffer;
+    }
+}
+
+SensorsTestSharedMemory::~SensorsTestSharedMemory() {
+    switch (mType) {
+        case SharedMemType::ASHMEM: {
+            if (mSize != 0) {
+                ::munmap(mBuffer, mSize);
+                mBuffer = nullptr;
+
+                ::native_handle_close(mNativeHandle);
+                ::native_handle_delete(mNativeHandle);
+
+                mNativeHandle = nullptr;
+                mSize = 0;
+            }
+            break;
+        }
+        case SharedMemType::GRALLOC: {
+            if (mSize != 0) {
+                mGrallocWrapper->unlock(mNativeHandle);
+                mGrallocWrapper->freeBuffer(mNativeHandle);
+
+                mNativeHandle = nullptr;
+                mSize = 0;
+            }
+            break;
+        }
+        default: {
+            if (mNativeHandle != nullptr || mSize != 0 || mBuffer != nullptr) {
+                ALOGE(
+                    "SensorsTestSharedMemory %p not properly destructed: "
+                    "type %d, native handle %p, size %zu, buffer %p",
+                    this, static_cast<int>(mType), mNativeHandle, mSize, mBuffer);
+            }
+            break;
+        }
+    }
+}
+
+SensorsTestSharedMemory* SensorsTestSharedMemory::create(SharedMemType type, size_t size) {
+    constexpr size_t kMaxSize = 128 * 1024 * 1024;  // sensor test should not need more than 128M
+    if (size == 0 || size >= kMaxSize) {
+        return nullptr;
+    }
+
+    auto m = new SensorsTestSharedMemory(type, size);
+    if (m->mSize != size || m->mBuffer == nullptr) {
+        delete m;
+        m = nullptr;
+    }
+    return m;
+}
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h b/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
new file mode 100644
index 0000000..3bd73c3
--- /dev/null
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef GRALLO_WRAPPER_H_
+#define GRALLO_WRAPPER_H_
+
+#include <unordered_set>
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+
+namespace allocator2 = ::android::hardware::graphics::allocator::V2_0;
+namespace mapper2 = ::android::hardware::graphics::mapper::V2_0;
+
+namespace android {
+
+// Modified from hardware/interfaces/graphics/mapper/2.0/vts/functional/
+class GrallocWrapper {
+   public:
+    GrallocWrapper();
+    ~GrallocWrapper();
+
+    sp<allocator2::IAllocator> getAllocator() const;
+    sp<mapper2::IMapper> getMapper() const;
+
+    std::string dumpDebugInfo();
+
+    // When import is false, this simply calls IAllocator::allocate. When import
+    // is true, the returned buffers are also imported into the mapper.
+    //
+    // Either case, the returned buffers must be freed with freeBuffer.
+    std::vector<const native_handle_t*> allocate(const mapper2::BufferDescriptor& descriptor,
+                                                 uint32_t count, bool import = true,
+                                                 uint32_t* outStride = nullptr);
+    const native_handle_t* allocate(const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo,
+                                    bool import = true, uint32_t* outStride = nullptr);
+
+    mapper2::BufferDescriptor createDescriptor(
+        const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo);
+
+    const native_handle_t* importBuffer(const hardware::hidl_handle& rawHandle);
+    void freeBuffer(const native_handle_t* bufferHandle);
+
+    // We use fd instead of hardware::hidl_handle in these functions to pass fences
+    // in and out of the mapper.  The ownership of the fd is always transferred
+    // with each of these functions.
+    void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
+               const mapper2::IMapper::Rect& accessRegion, int acquireFence);
+
+    int unlock(const native_handle_t* bufferHandle);
+
+   private:
+    void init();
+    const native_handle_t* cloneBuffer(const hardware::hidl_handle& rawHandle);
+
+    sp<allocator2::IAllocator> mAllocator;
+    sp<mapper2::IMapper> mMapper;
+
+    // Keep track of all cloned and imported handles.  When a test fails with
+    // ASSERT_*, the destructor will free the handles for the test.
+    std::unordered_set<const native_handle_t*> mClonedBuffers;
+    std::unordered_set<const native_handle_t*> mImportedBuffers;
+};
+
+}  // namespace android
+#endif  // GRALLO_WRAPPER_H_
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorEventsChecker.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorEventsChecker.h
new file mode 100644
index 0000000..b5daccc
--- /dev/null
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorEventsChecker.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SENSOR_EVENTS_CHECKER_H
+#define ANDROID_SENSOR_EVENTS_CHECKER_H
+
+#include <android/hardware/sensors/1.0/types.h>
+
+#include <cmath>
+
+class SensorEventsChecker {
+   public:
+    using Event = ::android::hardware::sensors::V1_0::Event;
+    virtual bool check(const std::vector<Event>& events, std::string* out) const = 0;
+    virtual ~SensorEventsChecker() {}
+};
+
+class NullChecker : public SensorEventsChecker {
+   public:
+    virtual bool check(const std::vector<Event>&, std::string*) const { return true; }
+};
+
+class SensorEventPerEventChecker : public SensorEventsChecker {
+   public:
+    virtual bool checkEvent(const Event& event, std::string* out) const = 0;
+    virtual bool check(const std::vector<Event>& events, std::string* out) const {
+        for (const auto& e : events) {
+            if (!checkEvent(e, out)) {
+                return false;
+            }
+        }
+        return true;
+    }
+};
+
+class Vec3NormChecker : public SensorEventPerEventChecker {
+   public:
+    Vec3NormChecker(float min, float max) : mLowerLimit(min), mUpperLimit(max) {}
+    static Vec3NormChecker byNominal(float nominal, float allowedError) {
+        return Vec3NormChecker(nominal - allowedError, nominal + allowedError);
+    }
+
+    virtual bool checkEvent(const Event& event, std::string* out) const {
+        android::hardware::sensors::V1_0::Vec3 v = event.u.vec3;
+        float norm = std::sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
+        if (norm < mLowerLimit || norm > mUpperLimit) {
+            if (out != nullptr) {
+                std::ostringstream ss;
+                ss << "Event @ " << event.timestamp << " (" << v.x << ", " << v.y << ", " << v.z
+                   << ")"
+                   << " has norm " << norm << ", which is beyond range"
+                   << " [" << mLowerLimit << ", " << mUpperLimit << "]";
+                *out = ss.str();
+            }
+            return false;
+        }
+        return true;
+    }
+
+   protected:
+    float mLowerLimit;
+    float mUpperLimit;
+};
+
+#endif  // ANDROID_SENSOR_EVENTS_CHECKER_H
\ No newline at end of file
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
new file mode 100644
index 0000000..96e6085
--- /dev/null
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlEnvironmentBase.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H
+#define ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H
+
+#include <VtsHalHidlTargetTestEnvBase.h>
+
+#include <android/hardware/sensors/1.0/types.h>
+
+#include <atomic>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+class SensorsHidlEnvironmentBase : public ::testing::VtsHalHidlTargetTestEnvBase {
+   public:
+    using Event = ::android::hardware::sensors::V1_0::Event;
+    virtual void HidlSetUp() override;
+    virtual void HidlTearDown() override;
+
+    // Get and clear all events collected so far (like "cat" shell command).
+    // If output is nullptr, it clears all collected events.
+    void catEvents(std::vector<Event>* output);
+
+    // set sensor event collection status
+    void setCollection(bool enable);
+
+   protected:
+    SensorsHidlEnvironmentBase() {}
+
+    void addEvent(const Event& ev);
+
+    virtual void startPollingThread() = 0;
+    virtual bool resetHal() = 0;
+
+    bool collectionEnabled;
+    std::atomic_bool stopThread;
+    std::thread pollThread;
+    std::vector<Event> events;
+    std::mutex events_mutex;
+
+    GTEST_DISALLOW_COPY_AND_ASSIGN_(SensorsHidlEnvironmentBase);
+};
+
+#endif  // ANDROID_SENSORS_HIDL_ENVIRONMENT_BASE_H
\ No newline at end of file
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
new file mode 100644
index 0000000..f4b259f
--- /dev/null
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsHidlTestBase.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SENSORS_HIDL_TEST_BASE_H
+#define ANDROID_SENSORS_HIDL_TEST_BASE_H
+
+#include "sensors-vts-utils/SensorEventsChecker.h"
+#include "sensors-vts-utils/SensorsHidlEnvironmentBase.h"
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <android/hardware/sensors/1.0/ISensors.h>
+#include <android/hardware/sensors/1.0/types.h>
+
+#include <unordered_set>
+#include <vector>
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::ISensors;
+using ::android::hardware::sensors::V1_0::RateLevel;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SensorFlagBits;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+using ::android::hardware::sensors::V1_0::SensorType;
+using ::android::hardware::sensors::V1_0::SharedMemInfo;
+using ::android::hardware::sensors::V1_0::SharedMemType;
+
+class SensorsHidlTestBase : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual SensorsHidlEnvironmentBase* getEnvironment() = 0;
+    virtual void SetUp() override {}
+
+    virtual void TearDown() override {
+        // stop all sensors
+        for (auto s : mSensorHandles) {
+            activate(s, false);
+        }
+        mSensorHandles.clear();
+
+        // stop all direct report and channels
+        for (auto c : mDirectChannelHandles) {
+            // disable all reports
+            configDirectReport(-1, c, RateLevel::STOP, [](auto, auto) {});
+            unregisterDirectChannel(c);
+        }
+        mDirectChannelHandles.clear();
+    }
+
+    // implementation wrapper
+    virtual SensorInfo defaultSensorByType(SensorType type) = 0;
+    virtual Return<void> getSensorsList(ISensors::getSensorsList_cb _hidl_cb) = 0;
+
+    virtual Return<Result> activate(int32_t sensorHandle, bool enabled) = 0;
+
+    virtual Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                                 int64_t maxReportLatencyNs) = 0;
+
+    virtual Return<Result> flush(int32_t sensorHandle) = 0;
+    virtual Return<Result> injectSensorData(const Event& event) = 0;
+    virtual Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                               ISensors::registerDirectChannel_cb _hidl_cb) = 0;
+    virtual Return<Result> unregisterDirectChannel(int32_t channelHandle) = 0;
+    virtual Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle,
+                                            RateLevel rate,
+                                            ISensors::configDirectReport_cb _hidl_cb) = 0;
+
+    std::vector<Event> collectEvents(useconds_t timeLimitUs, size_t nEventLimit,
+                                     bool clearBeforeStart = true, bool changeCollection = true);
+
+    inline static SensorFlagBits extractReportMode(uint64_t flag) {
+        return (SensorFlagBits)(flag & ((uint64_t)SensorFlagBits::CONTINUOUS_MODE |
+                                        (uint64_t)SensorFlagBits::ON_CHANGE_MODE |
+                                        (uint64_t)SensorFlagBits::ONE_SHOT_MODE |
+                                        (uint64_t)SensorFlagBits::SPECIAL_REPORTING_MODE));
+    }
+
+    inline static bool isMetaSensorType(SensorType type) {
+        return (type == SensorType::META_DATA || type == SensorType::DYNAMIC_SENSOR_META ||
+                type == SensorType::ADDITIONAL_INFO);
+    }
+
+    inline static bool isValidType(SensorType type) { return (int32_t)type > 0; }
+
+    void testStreamingOperation(SensorType type, std::chrono::nanoseconds samplingPeriod,
+                                std::chrono::seconds duration, const SensorEventsChecker& checker);
+    void testSamplingRateHotSwitchOperation(SensorType type, bool fastToSlow = true);
+    void testBatchingOperation(SensorType type);
+    void testDirectReportOperation(SensorType type, SharedMemType memType, RateLevel rate,
+                                   const SensorEventsChecker& checker);
+
+    static void assertTypeMatchStringType(SensorType type, const hidl_string& stringType);
+    static void assertTypeMatchReportMode(SensorType type, SensorFlagBits reportMode);
+    static void assertDelayMatchReportMode(int32_t minDelay, int32_t maxDelay,
+                                           SensorFlagBits reportMode);
+    static SensorFlagBits expectedReportModeForType(SensorType type);
+    static bool isDirectReportRateSupported(SensorInfo sensor, RateLevel rate);
+    static bool isDirectChannelTypeSupported(SensorInfo sensor, SharedMemType type);
+
+   protected:
+    // checkers
+    static const Vec3NormChecker sAccelNormChecker;
+    static const Vec3NormChecker sGyroNormChecker;
+
+    // all sensors and direct channnels used
+    std::unordered_set<int32_t> mSensorHandles;
+    std::unordered_set<int32_t> mDirectChannelHandles;
+};
+
+#endif  // ANDROID_SENSORS_HIDL_TEST_BASE_H
\ No newline at end of file
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h
new file mode 100644
index 0000000..055b8e7
--- /dev/null
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/SensorsTestSharedMemory.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SENSORS_TEST_SHARED_MEMORY_H
+#define ANDROID_SENSORS_TEST_SHARED_MEMORY_H
+
+#include "GrallocWrapper.h"
+
+#include <android-base/macros.h>
+#include <android/hardware/sensors/1.0/types.h>
+
+#include <cutils/ashmem.h>
+
+class SensorsTestSharedMemory {
+    using SharedMemType = ::android::hardware::sensors::V1_0::SharedMemType;
+    using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
+    using Event = ::android::hardware::sensors::V1_0::Event;
+
+   public:
+    static SensorsTestSharedMemory* create(SharedMemType type, size_t size);
+    SharedMemInfo getSharedMemInfo() const;
+    char* getBuffer() const;
+    std::vector<Event> parseEvents(int64_t lastCounter = -1, size_t offset = 0) const;
+    virtual ~SensorsTestSharedMemory();
+
+   private:
+    SensorsTestSharedMemory(SharedMemType type, size_t size);
+
+    SharedMemType mType;
+    native_handle_t* mNativeHandle;
+    size_t mSize;
+    char* mBuffer;
+    std::unique_ptr<::android::GrallocWrapper> mGrallocWrapper;
+
+    DISALLOW_COPY_AND_ASSIGN(SensorsTestSharedMemory);
+};
+
+#endif  // ANDROID_SENSORS_TEST_SHARED_MEMORY_H
diff --git a/wifi/1.2/default/OWNERS b/wifi/1.0/vts/OWNERS
similarity index 100%
copy from wifi/1.2/default/OWNERS
copy to wifi/1.0/vts/OWNERS
diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp
index 6522f4d..d0dd915 100644
--- a/wifi/1.0/vts/functional/Android.bp
+++ b/wifi/1.0/vts/functional/Android.bp
@@ -45,6 +45,8 @@
     static_libs: [
         "VtsHalWifiV1_0TargetTestUtil",
         "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
     ],
 }
 
diff --git a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
index a341028..a22cd72 100644
--- a/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_sta_iface_hidl_test.cpp
@@ -17,6 +17,7 @@
 #include <android-base/logging.h>
 
 #include <android/hardware/wifi/1.0/IWifiStaIface.h>
+#include <android/hardware/wifi/1.3/IWifiStaIface.h>
 
 #include <VtsHalHidlTargetTestBase.h>
 
@@ -143,6 +144,14 @@
         return;
     }
 
+    sp<::android::hardware::wifi::V1_3::IWifiStaIface> iface_converted =
+        ::android::hardware::wifi::V1_3::IWifiStaIface::castFrom(
+            wifi_sta_iface_);
+    if (iface_converted != nullptr) {
+        // Skip this test since this API is deprecated in this newer HAL version
+        return;
+    }
+
     // Enable link layer stats collection.
     EXPECT_EQ(WifiStatusCode::SUCCESS,
               HIDL_INVOKE(wifi_sta_iface_, enableLinkLayerStatsCollection, true)
diff --git a/wifi/1.2/default/OWNERS b/wifi/1.1/vts/OWNERS
similarity index 100%
copy from wifi/1.2/default/OWNERS
copy to wifi/1.1/vts/OWNERS
diff --git a/wifi/1.1/vts/functional/OWNERS b/wifi/1.1/vts/functional/OWNERS
deleted file mode 100644
index 2878acc..0000000
--- a/wifi/1.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-rpius@google.com
-quiche@google.com
diff --git a/wifi/1.2/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.2/default/tests/hidl_struct_util_unit_tests.cpp
deleted file mode 100644
index 1d6e9e4..0000000
--- a/wifi/1.2/default/tests/hidl_struct_util_unit_tests.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (C) 2017, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <gmock/gmock.h>
-
-#undef NAN
-#include "hidl_struct_util.h"
-
-using testing::Test;
-
-namespace {
-constexpr uint32_t kMacId1 = 1;
-constexpr uint32_t kMacId2 = 2;
-constexpr uint32_t kIfaceChannel1 = 3;
-constexpr uint32_t kIfaceChannel2 = 5;
-constexpr char kIfaceName1[] = "wlan0";
-constexpr char kIfaceName2[] = "wlan1";
-}  // namespace
-namespace android {
-namespace hardware {
-namespace wifi {
-namespace V1_2 {
-namespace implementation {
-using namespace android::hardware::wifi::V1_0;
-
-class HidlStructUtilTest : public Test {};
-
-TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithOneMac) {
-    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
-    legacy_hal::WifiMacInfo legacy_mac_info1 = {
-        .wlan_mac_id = kMacId1,
-        .mac_band =
-            legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_2_4_BAND};
-    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
-                                                    .channel = kIfaceChannel1};
-    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
-                                                    .channel = kIfaceChannel2};
-    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
-    legacy_mac_info1.iface_infos.push_back(legacy_iface_info2);
-    legacy_mac_infos.push_back(legacy_mac_info1);
-
-    std::vector<IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
-    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
-        legacy_mac_infos, &hidl_radio_mode_infos));
-
-    ASSERT_EQ(1u, hidl_radio_mode_infos.size());
-    auto hidl_radio_mode_info1 = hidl_radio_mode_infos[0];
-    EXPECT_EQ(legacy_mac_info1.wlan_mac_id, hidl_radio_mode_info1.radioId);
-    EXPECT_EQ(WifiBand::BAND_24GHZ_5GHZ, hidl_radio_mode_info1.bandInfo);
-    ASSERT_EQ(2u, hidl_radio_mode_info1.ifaceInfos.size());
-    auto hidl_iface_info1 = hidl_radio_mode_info1.ifaceInfos[0];
-    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
-              hidl_iface_info1.channel);
-    auto hidl_iface_info2 = hidl_radio_mode_info1.ifaceInfos[1];
-    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
-              hidl_iface_info2.channel);
-}
-
-TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithTwoMac) {
-    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
-    legacy_hal::WifiMacInfo legacy_mac_info1 = {
-        .wlan_mac_id = kMacId1, .mac_band = legacy_hal::WLAN_MAC_5_0_BAND};
-    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
-                                                    .channel = kIfaceChannel1};
-    legacy_hal::WifiMacInfo legacy_mac_info2 = {
-        .wlan_mac_id = kMacId2, .mac_band = legacy_hal::WLAN_MAC_2_4_BAND};
-    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
-                                                    .channel = kIfaceChannel2};
-    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
-    legacy_mac_infos.push_back(legacy_mac_info1);
-    legacy_mac_info2.iface_infos.push_back(legacy_iface_info2);
-    legacy_mac_infos.push_back(legacy_mac_info2);
-
-    std::vector<IWifiChipEventCallback::RadioModeInfo> hidl_radio_mode_infos;
-    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
-        legacy_mac_infos, &hidl_radio_mode_infos));
-
-    ASSERT_EQ(2u, hidl_radio_mode_infos.size());
-
-    // Find mac info 1.
-    const auto hidl_radio_mode_info1 = std::find_if(
-        hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
-        [&legacy_mac_info1](const IWifiChipEventCallback::RadioModeInfo& x) {
-            return x.radioId == legacy_mac_info1.wlan_mac_id;
-        });
-    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info1);
-    EXPECT_EQ(WifiBand::BAND_5GHZ, hidl_radio_mode_info1->bandInfo);
-    ASSERT_EQ(1u, hidl_radio_mode_info1->ifaceInfos.size());
-    auto hidl_iface_info1 = hidl_radio_mode_info1->ifaceInfos[0];
-    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
-              hidl_iface_info1.channel);
-
-    // Find mac info 2.
-    const auto hidl_radio_mode_info2 = std::find_if(
-        hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
-        [&legacy_mac_info2](const IWifiChipEventCallback::RadioModeInfo& x) {
-            return x.radioId == legacy_mac_info2.wlan_mac_id;
-        });
-    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info2);
-    EXPECT_EQ(WifiBand::BAND_24GHZ, hidl_radio_mode_info2->bandInfo);
-    ASSERT_EQ(1u, hidl_radio_mode_info2->ifaceInfos.size());
-    auto hidl_iface_info2 = hidl_radio_mode_info2->ifaceInfos[0];
-    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
-    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
-              hidl_iface_info2.channel);
-}
-}  // namespace implementation
-}  // namespace V1_2
-}  // namespace wifi
-}  // namespace hardware
-}  // namespace android
diff --git a/wifi/1.2/default/tests/runtests.sh b/wifi/1.2/default/tests/runtests.sh
deleted file mode 100755
index 966a6a7..0000000
--- a/wifi/1.2/default/tests/runtests.sh
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env bash
-
-# Copyright(C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0(the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http:// www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-if [ -z $ANDROID_BUILD_TOP ]; then
-  echo "You need to source and lunch before you can use this script"
-  exit 1
-fi
-
-echo "Running tests"
-set -e # fail early
-
-#NOTE We can't actually run these commands, since they rely on functions added by
-#build / envsetup.sh to the bash shell environment.
-echo "+ mmma -j32 $ANDROID_BUILD_TOP/"
-make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk \
-    MODULES-IN-hardware-interfaces-wifi-1.2-default
-
-set -x # print commands
-
-adb wait-for-device
-adb root
-adb wait-for-device
-
-#'disable-verity' will appear in 'adb remount' output if
-#dm - verity is enabled and needs to be disabled.
-if adb remount | grep 'disable-verity'; then
-  adb disable-verity
-  adb reboot
-  adb wait-for-device
-  adb root
-  adb wait-for-device
-  adb remount
-fi
-
-adb sync
-
-adb shell /data/nativetest/vendor/android.hardware.wifi@1.0-service-tests/android.hardware.wifi@1.0-service-tests
diff --git a/wifi/1.2/vts/OWNERS b/wifi/1.2/vts/OWNERS
index 811c857..8bfb148 100644
--- a/wifi/1.2/vts/OWNERS
+++ b/wifi/1.2/vts/OWNERS
@@ -1,4 +1,2 @@
 rpius@google.com
-quiche@google.com
-arabawy@google.com
-yim@google.com
\ No newline at end of file
+etancohen@google.com
diff --git a/wifi/1.3/Android.bp b/wifi/1.3/Android.bp
new file mode 100644
index 0000000..5e87c1c
--- /dev/null
+++ b/wifi/1.3/Android.bp
@@ -0,0 +1,26 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi@1.3",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IWifi.hal",
+        "IWifiStaIface.hal",
+    ],
+    interfaces: [
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+      "StaLinkLayerRadioStats",
+      "StaLinkLayerStats",
+    ],
+    gen_java: true,
+}
+
diff --git a/wifi/1.3/IWifi.hal b/wifi/1.3/IWifi.hal
new file mode 100644
index 0000000..298e722
--- /dev/null
+++ b/wifi/1.3/IWifi.hal
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.3;
+
+import @1.2::IWifi;
+
+/**
+ * This is the root of the HAL module and is the interface returned when
+ * loading an implementation of the Wi-Fi HAL. There must be at most one
+ * module loaded in the system.
+ * IWifi.getChip() must return @1.2::IWifiChip
+ */
+interface IWifi extends @1.2::IWifi {
+};
diff --git a/wifi/1.3/IWifiStaIface.hal b/wifi/1.3/IWifiStaIface.hal
new file mode 100644
index 0000000..0dc6128
--- /dev/null
+++ b/wifi/1.3/IWifiStaIface.hal
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.3;
+
+import @1.0::WifiStatus;
+import @1.2::IWifiStaIface;
+
+/**
+ * Interface used to represent a single STA iface.
+ *
+ * IWifiChip.createStaIface() may return a @1.3::IWifiStaIface when supported.
+ */
+interface IWifiStaIface extends @1.2::IWifiStaIface {
+    /**
+     * Retrieve the latest link layer stats.
+     * Must fail if |StaIfaceCapabilityMask.LINK_LAYER_STATS| is not set or if
+     * link layer stats collection hasn't been explicitly enabled.
+     *
+     * @return status WifiStatus of the operation.
+     *     Possible status codes:
+     *     |WifiStatusCode.SUCCESS|,
+     *     |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *     |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+     *     |WifiStatusCode.ERROR_NOT_STARTED|,
+     *     |WifiStatusCode.ERROR_NOT_AVAILABLE|,
+     *     |WifiStatusCode.ERROR_UNKNOWN|
+     * @return stats Instance of |LinkLayerStats|.
+     */
+    getLinkLayerStats_1_3() generates (WifiStatus status, StaLinkLayerStats stats);
+};
diff --git a/wifi/1.2/default/Android.mk b/wifi/1.3/default/Android.mk
similarity index 94%
rename from wifi/1.2/default/Android.mk
rename to wifi/1.3/default/Android.mk
index 3919690..541e5f0 100644
--- a/wifi/1.2/default/Android.mk
+++ b/wifi/1.3/default/Android.mk
@@ -58,7 +58,8 @@
     libwifi-system-iface \
     android.hardware.wifi@1.0 \
     android.hardware.wifi@1.1 \
-    android.hardware.wifi@1.2
+    android.hardware.wifi@1.2 \
+    android.hardware.wifi@1.3
 LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
 include $(BUILD_STATIC_LIBRARY)
 
@@ -84,7 +85,8 @@
     libwifi-system-iface \
     android.hardware.wifi@1.0 \
     android.hardware.wifi@1.1 \
-    android.hardware.wifi@1.2
+    android.hardware.wifi@1.2 \
+    android.hardware.wifi@1.3
 LOCAL_STATIC_LIBRARIES := \
     android.hardware.wifi@1.0-service-lib
 LOCAL_INIT_RC := android.hardware.wifi@1.0-service.rc
@@ -107,11 +109,11 @@
 LOCAL_STATIC_LIBRARIES := \
     libgmock \
     libgtest \
+    libhidlbase \
     android.hardware.wifi@1.0-service-lib
 LOCAL_SHARED_LIBRARIES := \
     libbase \
     libcutils \
-    libhidlbase \
     libhidltransport \
     liblog \
     libnl \
@@ -120,5 +122,6 @@
     libwifi-system-iface \
     android.hardware.wifi@1.0 \
     android.hardware.wifi@1.1 \
-    android.hardware.wifi@1.2
+    android.hardware.wifi@1.2 \
+    android.hardware.wifi@1.3
 include $(BUILD_NATIVE_TEST)
diff --git a/wifi/1.2/default/OWNERS b/wifi/1.3/default/OWNERS
similarity index 100%
rename from wifi/1.2/default/OWNERS
rename to wifi/1.3/default/OWNERS
diff --git a/wifi/1.2/default/THREADING.README b/wifi/1.3/default/THREADING.README
similarity index 100%
rename from wifi/1.2/default/THREADING.README
rename to wifi/1.3/default/THREADING.README
diff --git a/wifi/1.2/default/android.hardware.wifi@1.0-service.rc b/wifi/1.3/default/android.hardware.wifi@1.0-service.rc
similarity index 100%
rename from wifi/1.2/default/android.hardware.wifi@1.0-service.rc
rename to wifi/1.3/default/android.hardware.wifi@1.0-service.rc
diff --git a/wifi/1.2/default/hidl_callback_util.h b/wifi/1.3/default/hidl_callback_util.h
similarity index 98%
rename from wifi/1.2/default/hidl_callback_util.h
rename to wifi/1.3/default/hidl_callback_util.h
index 97f312a..a44af79 100644
--- a/wifi/1.2/default/hidl_callback_util.h
+++ b/wifi/1.3/default/hidl_callback_util.h
@@ -52,7 +52,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace hidl_callback_util {
 template <typename CallbackType>
@@ -117,7 +117,7 @@
 
 }  // namespace hidl_callback_util
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/hidl_return_util.h b/wifi/1.3/default/hidl_return_util.h
similarity index 98%
rename from wifi/1.2/default/hidl_return_util.h
rename to wifi/1.3/default/hidl_return_util.h
index 914c1b4..9707444 100644
--- a/wifi/1.2/default/hidl_return_util.h
+++ b/wifi/1.3/default/hidl_return_util.h
@@ -23,7 +23,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace hidl_return_util {
 using namespace android::hardware::wifi::V1_0;
@@ -113,7 +113,7 @@
 
 }  // namespace hidl_return_util
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/hidl_struct_util.cpp b/wifi/1.3/default/hidl_struct_util.cpp
similarity index 97%
rename from wifi/1.2/default/hidl_struct_util.cpp
rename to wifi/1.3/default/hidl_struct_util.cpp
index 39ac544..c88ddaa 100644
--- a/wifi/1.2/default/hidl_struct_util.cpp
+++ b/wifi/1.3/default/hidl_struct_util.cpp
@@ -22,7 +22,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace hidl_struct_util {
 
@@ -69,9 +69,9 @@
     return {};
 }
 
-IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
+V1_2::IWifiChip::ChipCapabilityMask convertLegacyFeatureToHidlChipCapability(
     uint32_t feature) {
-    using HidlChipCaps = IWifiChip::ChipCapabilityMask;
+    using HidlChipCaps = V1_2::IWifiChip::ChipCapabilityMask;
     switch (feature) {
         case WIFI_FEATURE_SET_TX_POWER_LIMIT:
             return HidlChipCaps::SET_TX_POWER_LIMIT;
@@ -139,9 +139,9 @@
                 convertLegacyLoggerFeatureToHidlChipCapability(feature);
         }
     }
-    for (const auto feature : {WIFI_FEATURE_SET_TX_POWER_LIMIT,
-                               WIFI_FEATURE_USE_BODY_HEAD_SAR,
-                               WIFI_FEATURE_D2D_RTT, WIFI_FEATURE_D2AP_RTT}) {
+    for (const auto feature :
+         {WIFI_FEATURE_SET_TX_POWER_LIMIT, WIFI_FEATURE_USE_BODY_HEAD_SAR,
+          WIFI_FEATURE_D2D_RTT, WIFI_FEATURE_D2AP_RTT}) {
         if (feature & legacy_feature_set) {
             *hidl_caps |= convertLegacyFeatureToHidlChipCapability(feature);
         }
@@ -267,26 +267,26 @@
     V1_1::IWifiChip::TxPowerScenario hidl_scenario) {
     switch (hidl_scenario) {
         // This is the only supported scenario for V1_1
-      case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
+        case V1_1::IWifiChip::TxPowerScenario::VOICE_CALL:
             return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
     };
     CHECK(false);
 }
 
 legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
-    IWifiChip::TxPowerScenario hidl_scenario) {
+    V1_2::IWifiChip::TxPowerScenario hidl_scenario) {
     switch (hidl_scenario) {
         // This is the only supported scenario for V1_1
-        case IWifiChip::TxPowerScenario::VOICE_CALL:
+        case V1_2::IWifiChip::TxPowerScenario::VOICE_CALL:
             return legacy_hal::WIFI_POWER_SCENARIO_VOICE_CALL;
         // Those are the supported scenarios for V1_2
-        case IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF:
+        case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_OFF:
             return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF;
-        case IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON:
+        case V1_2::IWifiChip::TxPowerScenario::ON_HEAD_CELL_ON:
             return legacy_hal::WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON;
-        case IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF:
+        case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_OFF:
             return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF;
-        case IWifiChip::TxPowerScenario::ON_BODY_CELL_ON:
+        case V1_2::IWifiChip::TxPowerScenario::ON_BODY_CELL_ON:
             return legacy_hal::WIFI_POWER_SCENARIO_ON_BODY_CELL_ON;
     };
     CHECK(false);
@@ -294,7 +294,7 @@
 
 bool convertLegacyWifiMacInfoToHidl(
     const legacy_hal::WifiMacInfo& legacy_mac_info,
-    IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
+    V1_2::IWifiChipEventCallback::RadioModeInfo* hidl_radio_mode_info) {
     if (!hidl_radio_mode_info) {
         return false;
     }
@@ -313,9 +313,9 @@
     } else {
         hidl_radio_mode_info->bandInfo = WifiBand::BAND_UNSPECIFIED;
     }
-    std::vector<IWifiChipEventCallback::IfaceInfo> iface_info_vec;
+    std::vector<V1_2::IWifiChipEventCallback::IfaceInfo> iface_info_vec;
     for (const auto& legacy_iface_info : legacy_mac_info.iface_infos) {
-        IWifiChipEventCallback::IfaceInfo iface_info;
+        V1_2::IWifiChipEventCallback::IfaceInfo iface_info;
         iface_info.name = legacy_iface_info.name;
         iface_info.channel = legacy_iface_info.channel;
         iface_info_vec.push_back(iface_info);
@@ -326,14 +326,15 @@
 
 bool convertLegacyWifiMacInfosToHidl(
     const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
-    std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos) {
+    std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>*
+        hidl_radio_mode_infos) {
     if (!hidl_radio_mode_infos) {
         return false;
     }
     *hidl_radio_mode_infos = {};
 
     for (const auto& legacy_mac_info : legacy_mac_infos) {
-        IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
+        V1_2::IWifiChipEventCallback::RadioModeInfo hidl_radio_mode_info;
         if (!convertLegacyWifiMacInfoToHidl(legacy_mac_info,
                                             &hidl_radio_mode_info)) {
             return false;
@@ -784,7 +785,7 @@
 
 bool convertLegacyLinkLayerStatsToHidl(
     const legacy_hal::LinkLayerStats& legacy_stats,
-    StaLinkLayerStats* hidl_stats) {
+    V1_3::StaLinkLayerStats* hidl_stats) {
     if (!hidl_stats) {
         return false;
     }
@@ -825,16 +826,26 @@
     hidl_stats->iface.wmeVoPktStats.retries =
         legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
     // radio legacy_stats conversion.
-    std::vector<StaLinkLayerRadioStats> hidl_radios_stats;
+    std::vector<V1_3::StaLinkLayerRadioStats> hidl_radios_stats;
     for (const auto& legacy_radio_stats : legacy_stats.radios) {
-        StaLinkLayerRadioStats hidl_radio_stats;
-        hidl_radio_stats.onTimeInMs = legacy_radio_stats.stats.on_time;
-        hidl_radio_stats.txTimeInMs = legacy_radio_stats.stats.tx_time;
-        hidl_radio_stats.rxTimeInMs = legacy_radio_stats.stats.rx_time;
-        hidl_radio_stats.onTimeInMsForScan =
+        V1_3::StaLinkLayerRadioStats hidl_radio_stats;
+        hidl_radio_stats.V1_0.onTimeInMs = legacy_radio_stats.stats.on_time;
+        hidl_radio_stats.V1_0.txTimeInMs = legacy_radio_stats.stats.tx_time;
+        hidl_radio_stats.V1_0.rxTimeInMs = legacy_radio_stats.stats.rx_time;
+        hidl_radio_stats.V1_0.onTimeInMsForScan =
             legacy_radio_stats.stats.on_time_scan;
-        hidl_radio_stats.txTimeInMsPerLevel =
+        hidl_radio_stats.V1_0.txTimeInMsPerLevel =
             legacy_radio_stats.tx_time_per_levels;
+        hidl_radio_stats.onTimeInMsForNanScan =
+            legacy_radio_stats.stats.on_time_nbd;
+        hidl_radio_stats.onTimeInMsForBgScan =
+            legacy_radio_stats.stats.on_time_gscan;
+        hidl_radio_stats.onTimeInMsForRoamScan =
+            legacy_radio_stats.stats.on_time_roam_scan;
+        hidl_radio_stats.onTimeInMsForPnoScan =
+            legacy_radio_stats.stats.on_time_pno_scan;
+        hidl_radio_stats.onTimeInMsForHs20Scan =
+            legacy_radio_stats.stats.on_time_hs20;
         hidl_radios_stats.push_back(hidl_radio_stats);
     }
     hidl_stats->radios = hidl_radios_stats;
@@ -1197,7 +1208,7 @@
 
 bool convertHidlNanEnableRequest_1_2ToLegacy(
     const NanEnableRequest& hidl_request1,
-    const NanConfigRequestSupplemental& hidl_request2,
+    const V1_2::NanConfigRequestSupplemental& hidl_request2,
     legacy_hal::NanEnableRequest* legacy_request) {
     if (!legacy_request) {
         LOG(ERROR)
@@ -1708,7 +1719,7 @@
 
 bool convertHidlNanConfigRequest_1_2ToLegacy(
     const NanConfigRequest& hidl_request1,
-    const NanConfigRequestSupplemental& hidl_request2,
+    const V1_2::NanConfigRequestSupplemental& hidl_request2,
     legacy_hal::NanConfigRequest* legacy_request) {
     if (!legacy_request) {
         LOG(ERROR) << "convertHidlNanConfigRequest_1_2ToLegacy: legacy_request "
@@ -2039,7 +2050,7 @@
 
 bool convertLegacyNdpChannelInfoToHidl(
     const legacy_hal::NanChannelInfo& legacy_struct,
-    NanDataPathChannelInfo* hidl_struct) {
+    V1_2::NanDataPathChannelInfo* hidl_struct) {
     if (!hidl_struct) {
         LOG(ERROR) << "convertLegacyNdpChannelInfoToHidl: hidl_struct is null";
         return false;
@@ -2056,7 +2067,7 @@
 
 bool convertLegacyNanDataPathConfirmIndToHidl(
     const legacy_hal::NanDataPathConfirmInd& legacy_ind,
-    NanDataPathConfirmInd* hidl_ind) {
+    V1_2::NanDataPathConfirmInd* hidl_ind) {
     if (!hidl_ind) {
         LOG(ERROR)
             << "convertLegacyNanDataPathConfirmIndToHidl: hidl_ind is null";
@@ -2077,9 +2088,9 @@
         convertLegacyNanStatusTypeToHidl(legacy_ind.reason_code);
     hidl_ind->V1_0.status.description = "";  // TODO: b/34059183
 
-    std::vector<NanDataPathChannelInfo> channelInfo;
+    std::vector<V1_2::NanDataPathChannelInfo> channelInfo;
     for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
-        NanDataPathChannelInfo hidl_struct;
+        V1_2::NanDataPathChannelInfo hidl_struct;
         if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
                                                &hidl_struct)) {
             return false;
@@ -2093,7 +2104,7 @@
 
 bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
     const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
-    NanDataPathScheduleUpdateInd* hidl_ind) {
+    V1_2::NanDataPathScheduleUpdateInd* hidl_ind) {
     if (!hidl_ind) {
         LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToHidl: "
                       "hidl_ind is null";
@@ -2103,9 +2114,9 @@
 
     hidl_ind->peerDiscoveryAddress =
         hidl_array<uint8_t, 6>(legacy_ind.peer_mac_addr);
-    std::vector<NanDataPathChannelInfo> channelInfo;
+    std::vector<V1_2::NanDataPathChannelInfo> channelInfo;
     for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
-        NanDataPathChannelInfo hidl_struct;
+        V1_2::NanDataPathChannelInfo hidl_struct;
         if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
                                                &hidl_struct)) {
             return false;
@@ -2616,7 +2627,7 @@
 }
 }  // namespace hidl_struct_util
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/hidl_struct_util.h b/wifi/1.3/default/hidl_struct_util.h
similarity index 94%
rename from wifi/1.2/default/hidl_struct_util.h
rename to wifi/1.3/default/hidl_struct_util.h
index 3c789c0..8df484d 100644
--- a/wifi/1.2/default/hidl_struct_util.h
+++ b/wifi/1.3/default/hidl_struct_util.h
@@ -24,6 +24,7 @@
 #include <android/hardware/wifi/1.2/IWifiChip.h>
 #include <android/hardware/wifi/1.2/IWifiChipEventCallback.h>
 #include <android/hardware/wifi/1.2/types.h>
+#include <android/hardware/wifi/1.3/types.h>
 
 #include "wifi_legacy_hal.h"
 
@@ -36,7 +37,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace hidl_struct_util {
 using namespace android::hardware::wifi::V1_0;
@@ -57,10 +58,11 @@
 legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy(
     V1_1::IWifiChip::TxPowerScenario hidl_scenario);
 legacy_hal::wifi_power_scenario convertHidlTxPowerScenarioToLegacy_1_2(
-    IWifiChip::TxPowerScenario hidl_scenario);
+    V1_2::IWifiChip::TxPowerScenario hidl_scenario);
 bool convertLegacyWifiMacInfosToHidl(
     const std::vector<legacy_hal::WifiMacInfo>& legacy_mac_infos,
-    std::vector<IWifiChipEventCallback::RadioModeInfo>* hidl_radio_mode_infos);
+    std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>*
+        hidl_radio_mode_infos);
 
 // STA iface conversion methods.
 bool convertLegacyFeaturesToHidlStaCapabilities(
@@ -88,7 +90,7 @@
     std::vector<StaScanData>* hidl_scan_datas);
 bool convertLegacyLinkLayerStatsToHidl(
     const legacy_hal::LinkLayerStats& legacy_stats,
-    StaLinkLayerStats* hidl_stats);
+    V1_3::StaLinkLayerStats* hidl_stats);
 bool convertLegacyRoamingCapabilitiesToHidl(
     const legacy_hal::wifi_roaming_capabilities& legacy_caps,
     StaRoamingCapabilities* hidl_caps);
@@ -115,11 +117,11 @@
     legacy_hal::NanConfigRequest* legacy_request);
 bool convertHidlNanEnableRequest_1_2ToLegacy(
     const NanEnableRequest& hidl_request1,
-    const NanConfigRequestSupplemental& hidl_request2,
+    const V1_2::NanConfigRequestSupplemental& hidl_request2,
     legacy_hal::NanEnableRequest* legacy_request);
 bool convertHidlNanConfigRequest_1_2ToLegacy(
     const NanConfigRequest& hidl_request1,
-    const NanConfigRequestSupplemental& hidl_request2,
+    const V1_2::NanConfigRequestSupplemental& hidl_request2,
     legacy_hal::NanConfigRequest* legacy_request);
 bool convertHidlNanPublishRequestToLegacy(
     const NanPublishRequest& hidl_request,
@@ -152,10 +154,10 @@
     NanDataPathRequestInd* hidl_ind);
 bool convertLegacyNanDataPathConfirmIndToHidl(
     const legacy_hal::NanDataPathConfirmInd& legacy_ind,
-    NanDataPathConfirmInd* hidl_ind);
+    V1_2::NanDataPathConfirmInd* hidl_ind);
 bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
     const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
-    NanDataPathScheduleUpdateInd* hidl_ind);
+    V1_2::NanDataPathScheduleUpdateInd* hidl_ind);
 
 // RTT controller conversion methods.
 bool convertHidlVectorOfRttConfigToLegacy(
@@ -184,7 +186,7 @@
     std::vector<RttResult>* hidl_results);
 }  // namespace hidl_struct_util
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/hidl_sync_util.cpp b/wifi/1.3/default/hidl_sync_util.cpp
similarity index 96%
rename from wifi/1.2/default/hidl_sync_util.cpp
rename to wifi/1.3/default/hidl_sync_util.cpp
index ad8448a..160727f 100644
--- a/wifi/1.2/default/hidl_sync_util.cpp
+++ b/wifi/1.3/default/hidl_sync_util.cpp
@@ -23,7 +23,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace hidl_sync_util {
 
@@ -33,7 +33,7 @@
 
 }  // namespace hidl_sync_util
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/hidl_sync_util.h b/wifi/1.3/default/hidl_sync_util.h
similarity index 96%
rename from wifi/1.2/default/hidl_sync_util.h
rename to wifi/1.3/default/hidl_sync_util.h
index 8381862..ebfb051 100644
--- a/wifi/1.2/default/hidl_sync_util.h
+++ b/wifi/1.3/default/hidl_sync_util.h
@@ -24,13 +24,13 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace hidl_sync_util {
 std::unique_lock<std::recursive_mutex> acquireGlobalLock();
 }  // namespace hidl_sync_util
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/ringbuffer.cpp b/wifi/1.3/default/ringbuffer.cpp
similarity index 97%
rename from wifi/1.2/default/ringbuffer.cpp
rename to wifi/1.3/default/ringbuffer.cpp
index c126b36..1294c52 100644
--- a/wifi/1.2/default/ringbuffer.cpp
+++ b/wifi/1.3/default/ringbuffer.cpp
@@ -21,7 +21,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 
 Ringbuffer::Ringbuffer(size_t maxSize) : size_(0), maxSize_(maxSize) {}
@@ -48,7 +48,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/ringbuffer.h b/wifi/1.3/default/ringbuffer.h
similarity index 97%
rename from wifi/1.2/default/ringbuffer.h
rename to wifi/1.3/default/ringbuffer.h
index 4808e40..d9f8df6 100644
--- a/wifi/1.2/default/ringbuffer.h
+++ b/wifi/1.3/default/ringbuffer.h
@@ -23,7 +23,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 
 /**
@@ -45,7 +45,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/service.cpp b/wifi/1.3/default/service.cpp
similarity index 83%
rename from wifi/1.2/default/service.cpp
rename to wifi/1.3/default/service.cpp
index 01d22bd..5fd83c1 100644
--- a/wifi/1.2/default/service.cpp
+++ b/wifi/1.3/default/service.cpp
@@ -26,10 +26,10 @@
 
 using android::hardware::configureRpcThreadpool;
 using android::hardware::joinRpcThreadpool;
-using android::hardware::wifi::V1_2::implementation::feature_flags::
+using android::hardware::wifi::V1_3::implementation::feature_flags::
     WifiFeatureFlags;
-using android::hardware::wifi::V1_2::implementation::legacy_hal::WifiLegacyHal;
-using android::hardware::wifi::V1_2::implementation::mode_controller::
+using android::hardware::wifi::V1_3::implementation::legacy_hal::WifiLegacyHal;
+using android::hardware::wifi::V1_3::implementation::mode_controller::
     WifiModeController;
 
 int main(int /*argc*/, char** argv) {
@@ -40,8 +40,8 @@
     configureRpcThreadpool(1, true /* callerWillJoin */);
 
     // Setup hwbinder service
-    android::sp<android::hardware::wifi::V1_2::IWifi> service =
-        new android::hardware::wifi::V1_2::implementation::Wifi(
+    android::sp<android::hardware::wifi::V1_3::IWifi> service =
+        new android::hardware::wifi::V1_3::implementation::Wifi(
             std::make_shared<WifiLegacyHal>(),
             std::make_shared<WifiModeController>(),
             std::make_shared<WifiFeatureFlags>());
diff --git a/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp b/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp
new file mode 100644
index 0000000..d600a2b
--- /dev/null
+++ b/wifi/1.3/default/tests/hidl_struct_util_unit_tests.cpp
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <gmock/gmock.h>
+
+#undef NAN
+#include "hidl_struct_util.h"
+
+using testing::Test;
+
+namespace {
+constexpr uint32_t kMacId1 = 1;
+constexpr uint32_t kMacId2 = 2;
+constexpr uint32_t kIfaceChannel1 = 3;
+constexpr uint32_t kIfaceChannel2 = 5;
+constexpr char kIfaceName1[] = "wlan0";
+constexpr char kIfaceName2[] = "wlan1";
+}  // namespace
+namespace android {
+namespace hardware {
+namespace wifi {
+namespace V1_3 {
+namespace implementation {
+using namespace android::hardware::wifi::V1_0;
+
+class HidlStructUtilTest : public Test {};
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithOneMac) {
+    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+    legacy_hal::WifiMacInfo legacy_mac_info1 = {
+        .wlan_mac_id = kMacId1,
+        .mac_band =
+            legacy_hal::WLAN_MAC_5_0_BAND | legacy_hal::WLAN_MAC_2_4_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
+                                                    .channel = kIfaceChannel1};
+    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
+                                                    .channel = kIfaceChannel2};
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info2);
+    legacy_mac_infos.push_back(legacy_mac_info1);
+
+    std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>
+        hidl_radio_mode_infos;
+    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
+        legacy_mac_infos, &hidl_radio_mode_infos));
+
+    ASSERT_EQ(1u, hidl_radio_mode_infos.size());
+    auto hidl_radio_mode_info1 = hidl_radio_mode_infos[0];
+    EXPECT_EQ(legacy_mac_info1.wlan_mac_id, hidl_radio_mode_info1.radioId);
+    EXPECT_EQ(WifiBand::BAND_24GHZ_5GHZ, hidl_radio_mode_info1.bandInfo);
+    ASSERT_EQ(2u, hidl_radio_mode_info1.ifaceInfos.size());
+    auto hidl_iface_info1 = hidl_radio_mode_info1.ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
+              hidl_iface_info1.channel);
+    auto hidl_iface_info2 = hidl_radio_mode_info1.ifaceInfos[1];
+    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
+              hidl_iface_info2.channel);
+}
+
+TEST_F(HidlStructUtilTest, CanConvertLegacyWifiMacInfosToHidlWithTwoMac) {
+    std::vector<legacy_hal::WifiMacInfo> legacy_mac_infos;
+    legacy_hal::WifiMacInfo legacy_mac_info1 = {
+        .wlan_mac_id = kMacId1, .mac_band = legacy_hal::WLAN_MAC_5_0_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info1 = {.name = kIfaceName1,
+                                                    .channel = kIfaceChannel1};
+    legacy_hal::WifiMacInfo legacy_mac_info2 = {
+        .wlan_mac_id = kMacId2, .mac_band = legacy_hal::WLAN_MAC_2_4_BAND};
+    legacy_hal::WifiIfaceInfo legacy_iface_info2 = {.name = kIfaceName2,
+                                                    .channel = kIfaceChannel2};
+    legacy_mac_info1.iface_infos.push_back(legacy_iface_info1);
+    legacy_mac_infos.push_back(legacy_mac_info1);
+    legacy_mac_info2.iface_infos.push_back(legacy_iface_info2);
+    legacy_mac_infos.push_back(legacy_mac_info2);
+
+    std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>
+        hidl_radio_mode_infos;
+    ASSERT_TRUE(hidl_struct_util::convertLegacyWifiMacInfosToHidl(
+        legacy_mac_infos, &hidl_radio_mode_infos));
+
+    ASSERT_EQ(2u, hidl_radio_mode_infos.size());
+
+    // Find mac info 1.
+    const auto hidl_radio_mode_info1 =
+        std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+                     [&legacy_mac_info1](
+                         const V1_2::IWifiChipEventCallback::RadioModeInfo& x) {
+                         return x.radioId == legacy_mac_info1.wlan_mac_id;
+                     });
+    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info1);
+    EXPECT_EQ(WifiBand::BAND_5GHZ, hidl_radio_mode_info1->bandInfo);
+    ASSERT_EQ(1u, hidl_radio_mode_info1->ifaceInfos.size());
+    auto hidl_iface_info1 = hidl_radio_mode_info1->ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info1.name, hidl_iface_info1.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info1.channel),
+              hidl_iface_info1.channel);
+
+    // Find mac info 2.
+    const auto hidl_radio_mode_info2 =
+        std::find_if(hidl_radio_mode_infos.begin(), hidl_radio_mode_infos.end(),
+                     [&legacy_mac_info2](
+                         const V1_2::IWifiChipEventCallback::RadioModeInfo& x) {
+                         return x.radioId == legacy_mac_info2.wlan_mac_id;
+                     });
+    ASSERT_NE(hidl_radio_mode_infos.end(), hidl_radio_mode_info2);
+    EXPECT_EQ(WifiBand::BAND_24GHZ, hidl_radio_mode_info2->bandInfo);
+    ASSERT_EQ(1u, hidl_radio_mode_info2->ifaceInfos.size());
+    auto hidl_iface_info2 = hidl_radio_mode_info2->ifaceInfos[0];
+    EXPECT_EQ(legacy_iface_info2.name, hidl_iface_info2.name);
+    EXPECT_EQ(static_cast<uint32_t>(legacy_iface_info2.channel),
+              hidl_iface_info2.channel);
+}
+
+TEST_F(HidlStructUtilTest, canConvertLegacyLinkLayerStatsToHidl) {
+    legacy_hal::LinkLayerStats legacy_stats{};
+    legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+    legacy_stats.radios.push_back(legacy_hal::LinkLayerRadioStats{});
+    legacy_stats.iface.beacon_rx = rand();
+    legacy_stats.iface.rssi_mgmt = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries = rand();
+
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries = rand();
+
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries = rand();
+
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost = rand();
+    legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries = rand();
+
+    for (auto& radio : legacy_stats.radios) {
+        radio.stats.on_time = rand();
+        radio.stats.tx_time = rand();
+        radio.stats.rx_time = rand();
+        radio.stats.on_time_scan = rand();
+        radio.stats.on_time_nbd = rand();
+        radio.stats.on_time_gscan = rand();
+        radio.stats.on_time_roam_scan = rand();
+        radio.stats.on_time_pno_scan = rand();
+        radio.stats.on_time_hs20 = rand();
+        for (int i = 0; i < 4; i++) {
+            radio.tx_time_per_levels.push_back(rand());
+        }
+    }
+
+    V1_3::StaLinkLayerStats converted{};
+    hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
+                                                        &converted);
+    EXPECT_EQ(legacy_stats.iface.beacon_rx, converted.iface.beaconRx);
+    EXPECT_EQ(legacy_stats.iface.rssi_mgmt, converted.iface.avgRssiMgmt);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].rx_mpdu,
+              converted.iface.wmeBePktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].tx_mpdu,
+              converted.iface.wmeBePktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].mpdu_lost,
+              converted.iface.wmeBePktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BE].retries,
+              converted.iface.wmeBePktStats.retries);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].rx_mpdu,
+              converted.iface.wmeBkPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].tx_mpdu,
+              converted.iface.wmeBkPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].mpdu_lost,
+              converted.iface.wmeBkPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_BK].retries,
+              converted.iface.wmeBkPktStats.retries);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].rx_mpdu,
+              converted.iface.wmeViPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].tx_mpdu,
+              converted.iface.wmeViPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].mpdu_lost,
+              converted.iface.wmeViPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VI].retries,
+              converted.iface.wmeViPktStats.retries);
+
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].rx_mpdu,
+              converted.iface.wmeVoPktStats.rxMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].tx_mpdu,
+              converted.iface.wmeVoPktStats.txMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].mpdu_lost,
+              converted.iface.wmeVoPktStats.lostMpdu);
+    EXPECT_EQ(legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries,
+              converted.iface.wmeVoPktStats.retries);
+
+    EXPECT_EQ(legacy_stats.radios.size(), converted.radios.size());
+    for (int i = 0; i < legacy_stats.radios.size(); i++) {
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time,
+                  converted.radios[i].V1_0.onTimeInMs);
+        EXPECT_EQ(legacy_stats.radios[i].stats.tx_time,
+                  converted.radios[i].V1_0.txTimeInMs);
+        EXPECT_EQ(legacy_stats.radios[i].stats.rx_time,
+                  converted.radios[i].V1_0.rxTimeInMs);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_scan,
+                  converted.radios[i].V1_0.onTimeInMsForScan);
+        EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels.size(),
+                  converted.radios[i].V1_0.txTimeInMsPerLevel.size());
+        for (int j = 0; j < legacy_stats.radios[i].tx_time_per_levels.size();
+             j++) {
+            EXPECT_EQ(legacy_stats.radios[i].tx_time_per_levels[j],
+                      converted.radios[i].V1_0.txTimeInMsPerLevel[j]);
+        }
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_nbd,
+                  converted.radios[i].onTimeInMsForNanScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_gscan,
+                  converted.radios[i].onTimeInMsForBgScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_roam_scan,
+                  converted.radios[i].onTimeInMsForRoamScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_pno_scan,
+                  converted.radios[i].onTimeInMsForPnoScan);
+        EXPECT_EQ(legacy_stats.radios[i].stats.on_time_hs20,
+                  converted.radios[i].onTimeInMsForHs20Scan);
+    }
+}
+}  // namespace implementation
+}  // namespace V1_3
+}  // namespace wifi
+}  // namespace hardware
+}  // namespace android
diff --git a/wifi/1.2/default/tests/main.cpp b/wifi/1.3/default/tests/main.cpp
similarity index 100%
rename from wifi/1.2/default/tests/main.cpp
rename to wifi/1.3/default/tests/main.cpp
diff --git a/wifi/1.2/default/tests/mock_wifi_feature_flags.cpp b/wifi/1.3/default/tests/mock_wifi_feature_flags.cpp
similarity index 96%
rename from wifi/1.2/default/tests/mock_wifi_feature_flags.cpp
rename to wifi/1.3/default/tests/mock_wifi_feature_flags.cpp
index 8d0b192..a393fdc 100644
--- a/wifi/1.2/default/tests/mock_wifi_feature_flags.cpp
+++ b/wifi/1.3/default/tests/mock_wifi_feature_flags.cpp
@@ -21,7 +21,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace feature_flags {
 
@@ -29,7 +29,7 @@
 
 }  // namespace feature_flags
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/tests/mock_wifi_feature_flags.h b/wifi/1.3/default/tests/mock_wifi_feature_flags.h
similarity index 96%
rename from wifi/1.2/default/tests/mock_wifi_feature_flags.h
rename to wifi/1.3/default/tests/mock_wifi_feature_flags.h
index 2a36dd5..86c50a7 100644
--- a/wifi/1.2/default/tests/mock_wifi_feature_flags.h
+++ b/wifi/1.3/default/tests/mock_wifi_feature_flags.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace feature_flags {
 
@@ -39,7 +39,7 @@
 
 }  // namespace feature_flags
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/tests/mock_wifi_legacy_hal.cpp b/wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp
similarity index 96%
rename from wifi/1.2/default/tests/mock_wifi_legacy_hal.cpp
rename to wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp
index 8381dde..4cd279d 100644
--- a/wifi/1.2/default/tests/mock_wifi_legacy_hal.cpp
+++ b/wifi/1.3/default/tests/mock_wifi_legacy_hal.cpp
@@ -24,14 +24,14 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace legacy_hal {
 
 MockWifiLegacyHal::MockWifiLegacyHal() : WifiLegacyHal() {}
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/tests/mock_wifi_legacy_hal.h b/wifi/1.3/default/tests/mock_wifi_legacy_hal.h
similarity index 97%
rename from wifi/1.2/default/tests/mock_wifi_legacy_hal.h
rename to wifi/1.3/default/tests/mock_wifi_legacy_hal.h
index 43370b4..deb3a5a 100644
--- a/wifi/1.2/default/tests/mock_wifi_legacy_hal.h
+++ b/wifi/1.3/default/tests/mock_wifi_legacy_hal.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace legacy_hal {
 
@@ -49,7 +49,7 @@
 };
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/tests/mock_wifi_mode_controller.cpp b/wifi/1.3/default/tests/mock_wifi_mode_controller.cpp
similarity index 96%
rename from wifi/1.2/default/tests/mock_wifi_mode_controller.cpp
rename to wifi/1.3/default/tests/mock_wifi_mode_controller.cpp
index 461a581..2b0ea36 100644
--- a/wifi/1.2/default/tests/mock_wifi_mode_controller.cpp
+++ b/wifi/1.3/default/tests/mock_wifi_mode_controller.cpp
@@ -24,14 +24,14 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace mode_controller {
 
 MockWifiModeController::MockWifiModeController() : WifiModeController() {}
 }  // namespace mode_controller
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/tests/mock_wifi_mode_controller.h b/wifi/1.3/default/tests/mock_wifi_mode_controller.h
similarity index 97%
rename from wifi/1.2/default/tests/mock_wifi_mode_controller.h
rename to wifi/1.3/default/tests/mock_wifi_mode_controller.h
index 50c3e35..c204059 100644
--- a/wifi/1.2/default/tests/mock_wifi_mode_controller.h
+++ b/wifi/1.3/default/tests/mock_wifi_mode_controller.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace mode_controller {
 
@@ -38,7 +38,7 @@
 };
 }  // namespace mode_controller
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/tests/ringbuffer_unit_tests.cpp b/wifi/1.3/default/tests/ringbuffer_unit_tests.cpp
similarity index 98%
rename from wifi/1.2/default/tests/ringbuffer_unit_tests.cpp
rename to wifi/1.3/default/tests/ringbuffer_unit_tests.cpp
index ad5289b..0cf1e4f 100644
--- a/wifi/1.2/default/tests/ringbuffer_unit_tests.cpp
+++ b/wifi/1.3/default/tests/ringbuffer_unit_tests.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 
 class RingbufferTest : public Test {
@@ -91,7 +91,7 @@
     EXPECT_EQ(input, buffer_.getData().front());
 }
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/default/tests/runtests.sh b/wifi/1.3/default/tests/runtests.sh
new file mode 100755
index 0000000..6bce3ef
--- /dev/null
+++ b/wifi/1.3/default/tests/runtests.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+# Copyright(C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0(the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http:// www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if [ -z $ANDROID_BUILD_TOP ]; then
+  echo "You need to source and lunch before you can use this script"
+  exit 1
+fi
+set -e
+
+$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode android.hardware.wifi@1.0-service-tests
+adb root
+adb sync data
+adb shell /data/nativetest64/vendor/android.hardware.wifi@1.0-service-tests/android.hardware.wifi@1.0-service-tests
diff --git a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp
similarity index 89%
rename from wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
rename to wifi/1.3/default/tests/wifi_chip_unit_tests.cpp
index 8722d0a..61060b5 100644
--- a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.3/default/tests/wifi_chip_unit_tests.cpp
@@ -38,7 +38,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 
 class WifiChipTest : public Test {
@@ -204,6 +204,19 @@
         }
     }
 
+    bool createRttController() {
+        bool success = false;
+        chip_->createRttController(
+            NULL, [&success](const WifiStatus& status,
+                             const sp<IWifiRttController>& rtt) {
+                if (WifiStatusCode::SUCCESS == status.code) {
+                    ASSERT_NE(rtt.get(), nullptr);
+                    success = true;
+                }
+            });
+        return success;
+    }
+
    public:
     void SetUp() override {
         chip_ = new WifiChip(chip_id_, legacy_hal_, mode_controller_,
@@ -386,6 +399,29 @@
     ASSERT_TRUE(createIface(IfaceType::NAN).empty());
 }
 
+TEST_F(WifiChipV1IfaceCombinationTest, RttControllerFlowStaModeNoSta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, RttControllerFlowStaModeWithSta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV1IfaceCombinationTest, RttControllerFlowApToSta) {
+    findModeAndConfigureForIfaceType(IfaceType::AP);
+    const auto ap_iface_name = createIface(IfaceType::AP);
+    ASSERT_FALSE(ap_iface_name.empty());
+    ASSERT_FALSE(createRttController());
+
+    removeIface(IfaceType::AP, ap_iface_name);
+
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createRttController());
+}
+
 ////////// V2 + Aware Iface Combinations ////////////
 // Mode 1 - STA + STA/AP
 //        - STA + P2P/NAN
@@ -540,40 +576,58 @@
     ASSERT_NE(sta_iface_name, ap_iface_name);
 }
 
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeNoSta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlowStaModeWithSta) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createRttController());
+}
+
+TEST_F(WifiChipV2_AwareIfaceCombinationTest, RttControllerFlow) {
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_FALSE(createIface(IfaceType::AP).empty());
+    ASSERT_TRUE(createRttController());
+}
+
 ////////// V1 Iface Combinations when AP creation is disabled //////////
 class WifiChipV1_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
- public:
-  void SetUp() override {
-    setupV1_AwareDisabledApIfaceCombination();
-    WifiChipTest::SetUp();
-  }
+   public:
+    void SetUp() override {
+        setupV1_AwareDisabledApIfaceCombination();
+        WifiChipTest::SetUp();
+    }
 };
 
 TEST_F(WifiChipV1_AwareDisabledApIfaceCombinationTest,
        StaMode_CreateSta_ShouldSucceed) {
-  findModeAndConfigureForIfaceType(IfaceType::STA);
-  ASSERT_FALSE(createIface(IfaceType::STA).empty());
-  ASSERT_TRUE(createIface(IfaceType::AP).empty());
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
 }
 
 ////////// V2 Iface Combinations when AP creation is disabled //////////
-class WifiChipV2_AwareDisabledApIfaceCombinationTest: public WifiChipTest {
- public:
-  void SetUp() override {
-    setupV2_AwareDisabledApIfaceCombination();
-    WifiChipTest::SetUp();
-  }
+class WifiChipV2_AwareDisabledApIfaceCombinationTest : public WifiChipTest {
+   public:
+    void SetUp() override {
+        setupV2_AwareDisabledApIfaceCombination();
+        WifiChipTest::SetUp();
+    }
 };
 
 TEST_F(WifiChipV2_AwareDisabledApIfaceCombinationTest,
        CreateSta_ShouldSucceed) {
-  findModeAndConfigureForIfaceType(IfaceType::STA);
-  ASSERT_FALSE(createIface(IfaceType::STA).empty());
-  ASSERT_TRUE(createIface(IfaceType::AP).empty());
+    findModeAndConfigureForIfaceType(IfaceType::STA);
+    ASSERT_FALSE(createIface(IfaceType::STA).empty());
+    ASSERT_TRUE(createIface(IfaceType::AP).empty());
 }
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi.cpp b/wifi/1.3/default/wifi.cpp
similarity index 99%
rename from wifi/1.2/default/wifi.cpp
rename to wifi/1.3/default/wifi.cpp
index 79f921f..e3af1ea 100644
--- a/wifi/1.2/default/wifi.cpp
+++ b/wifi/1.3/default/wifi.cpp
@@ -28,7 +28,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 using hidl_return_util::validateAndCallWithLock;
@@ -206,7 +206,7 @@
     return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi.h b/wifi/1.3/default/wifi.h
similarity index 96%
rename from wifi/1.2/default/wifi.h
rename to wifi/1.3/default/wifi.h
index 86919b1..e921424 100644
--- a/wifi/1.2/default/wifi.h
+++ b/wifi/1.3/default/wifi.h
@@ -20,7 +20,7 @@
 #include <functional>
 
 #include <android-base/macros.h>
-#include <android/hardware/wifi/1.2/IWifi.h>
+#include <android/hardware/wifi/1.3/IWifi.h>
 #include <utils/Looper.h>
 
 #include "hidl_callback_util.h"
@@ -32,13 +32,13 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 
 /**
  * Root HIDL interface object used to control the Wifi HAL.
  */
-class Wifi : public V1_2::IWifi {
+class Wifi : public V1_3::IWifi {
    public:
     Wifi(const std::shared_ptr<legacy_hal::WifiLegacyHal> legacy_hal,
          const std::shared_ptr<mode_controller::WifiModeController>
@@ -88,7 +88,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_ap_iface.cpp b/wifi/1.3/default/wifi_ap_iface.cpp
similarity index 98%
rename from wifi/1.2/default/wifi_ap_iface.cpp
rename to wifi/1.3/default/wifi_ap_iface.cpp
index 92b7b48..c203e47 100644
--- a/wifi/1.2/default/wifi_ap_iface.cpp
+++ b/wifi/1.3/default/wifi_ap_iface.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -93,7 +93,7 @@
     return {createWifiStatusFromLegacyError(legacy_status), valid_frequencies};
 }
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_ap_iface.h b/wifi/1.3/default/wifi_ap_iface.h
similarity index 98%
rename from wifi/1.2/default/wifi_ap_iface.h
rename to wifi/1.3/default/wifi_ap_iface.h
index 5363ec2..9f3d870 100644
--- a/wifi/1.2/default/wifi_ap_iface.h
+++ b/wifi/1.3/default/wifi_ap_iface.h
@@ -25,7 +25,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
@@ -65,7 +65,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_chip.cpp b/wifi/1.3/default/wifi_chip.cpp
similarity index 96%
rename from wifi/1.2/default/wifi_chip.cpp
rename to wifi/1.3/default/wifi_chip.cpp
index 3bd0557..faf1862 100644
--- a/wifi/1.2/default/wifi_chip.cpp
+++ b/wifi/1.3/default/wifi_chip.cpp
@@ -28,13 +28,13 @@
 #include "wifi_status_util.h"
 
 namespace {
+using android::sp;
 using android::base::unique_fd;
 using android::hardware::hidl_string;
 using android::hardware::hidl_vec;
 using android::hardware::wifi::V1_0::ChipModeId;
 using android::hardware::wifi::V1_0::IfaceType;
 using android::hardware::wifi::V1_0::IWifiChip;
-using android::sp;
 
 constexpr ChipModeId kInvalidModeId = UINT32_MAX;
 // These mode ID's should be unique (even across combo versions). Refer to
@@ -111,16 +111,16 @@
 bool removeOldFilesInternal() {
     time_t now = time(0);
     const time_t delete_files_before = now - kMaxRingBufferFileAgeSeconds;
-    DIR* dir_dump = opendir(kTombstoneFolderPath);
+    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(
+        opendir(kTombstoneFolderPath), closedir);
     if (!dir_dump) {
         LOG(ERROR) << "Failed to open directory: " << strerror(errno);
         return false;
     }
-    unique_fd dir_auto_closer(dirfd(dir_dump));
     struct dirent* dp;
     bool success = true;
     std::list<std::pair<const time_t, std::string>> valid_files;
-    while ((dp = readdir(dir_dump))) {
+    while ((dp = readdir(dir_dump.get()))) {
         if (dp->d_type != DT_REG) {
             continue;
         }
@@ -246,13 +246,13 @@
 size_t cpioArchiveFilesInDir(int out_fd, const char* input_dir) {
     struct dirent* dp;
     size_t n_error = 0;
-    DIR* dir_dump = opendir(input_dir);
+    std::unique_ptr<DIR, decltype(&closedir)> dir_dump(opendir(input_dir),
+                                                       closedir);
     if (!dir_dump) {
         LOG(ERROR) << "Failed to open directory: " << strerror(errno);
         return ++n_error;
     }
-    unique_fd dir_auto_closer(dirfd(dir_dump));
-    while ((dp = readdir(dir_dump))) {
+    while ((dp = readdir(dir_dump.get()))) {
         if (dp->d_type != DT_REG) {
             continue;
         }
@@ -304,7 +304,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 using hidl_return_util::validateAndCallWithLock;
@@ -335,7 +335,7 @@
 
 bool WifiChip::isValid() { return is_valid_; }
 
-std::set<sp<IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
+std::set<sp<V1_2::IWifiChipEventCallback>> WifiChip::getEventCallbacks() {
     return event_cb_handler_.getCallbacks();
 }
 
@@ -344,6 +344,7 @@
                            &WifiChip::getIdInternal, hidl_status_cb);
 }
 
+// Deprecated support for this callback
 Return<void> WifiChip::registerEventCallback(
     const sp<V1_0::IWifiChipEventCallback>& event_callback,
     registerEventCallback_cb hidl_status_cb) {
@@ -546,7 +547,8 @@
 }
 
 Return<void> WifiChip::selectTxPowerScenario(
-    V1_1::IWifiChip::TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
+    V1_1::IWifiChip::TxPowerScenario scenario,
+    selectTxPowerScenario_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
                            &WifiChip::selectTxPowerScenarioInternal,
                            hidl_status_cb, scenario);
@@ -560,7 +562,7 @@
 }
 
 Return<void> WifiChip::registerEventCallback_1_2(
-    const sp<IWifiChipEventCallback>& event_callback,
+    const sp<V1_2::IWifiChipEventCallback>& event_callback,
     registerEventCallback_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
                            &WifiChip::registerEventCallbackInternal_1_2,
@@ -568,9 +570,10 @@
 }
 
 Return<void> WifiChip::selectTxPowerScenario_1_2(
-        TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
+    TxPowerScenario scenario, selectTxPowerScenario_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
-            &WifiChip::selectTxPowerScenarioInternal_1_2, hidl_status_cb, scenario);
+                           &WifiChip::selectTxPowerScenarioInternal_1_2,
+                           hidl_status_cb, scenario);
 }
 
 Return<void> WifiChip::debug(const hidl_handle& handle,
@@ -927,6 +930,12 @@
 
 std::pair<WifiStatus, sp<IWifiRttController>>
 WifiChip::createRttControllerInternal(const sp<IWifiIface>& bound_iface) {
+    if (sta_ifaces_.size() == 0 &&
+        !canCurrentModeSupportIfaceOfType(IfaceType::STA)) {
+        LOG(ERROR) << "createRttControllerInternal: Chip cannot support STAs "
+                      "(and RTT by extension)";
+        return {createWifiStatus(WifiStatusCode::ERROR_NOT_AVAILABLE), {}};
+    }
     sp<WifiRttController> rtt =
         new WifiRttController(getWlan0IfaceName(), bound_iface, legacy_hal_);
     rtt_controllers_.emplace_back(rtt);
@@ -1036,7 +1045,7 @@
 }
 
 WifiStatus WifiChip::selectTxPowerScenarioInternal(
-        V1_1::IWifiChip::TxPowerScenario scenario) {
+    V1_1::IWifiChip::TxPowerScenario scenario) {
     auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
         getWlan0IfaceName(),
         hidl_struct_util::convertHidlTxPowerScenarioToLegacy(scenario));
@@ -1050,14 +1059,15 @@
 }
 
 WifiStatus WifiChip::registerEventCallbackInternal_1_2(
-    const sp<IWifiChipEventCallback>& event_callback) {
+    const sp<V1_2::IWifiChipEventCallback>& event_callback) {
     if (!event_cb_handler_.addCallback(event_callback)) {
         return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
     }
     return createWifiStatus(WifiStatusCode::SUCCESS);
 }
 
-WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario) {
+WifiStatus WifiChip::selectTxPowerScenarioInternal_1_2(
+    TxPowerScenario scenario) {
     auto legacy_status = legacy_hal_.lock()->selectTxPowerScenario(
         getWlan0IfaceName(),
         hidl_struct_util::convertHidlTxPowerScenarioToLegacy_1_2(scenario));
@@ -1156,7 +1166,7 @@
                 LOG(ERROR) << "Callback invoked on an invalid object";
                 return;
             }
-            std::vector<IWifiChipEventCallback::RadioModeInfo>
+            std::vector<V1_2::IWifiChipEventCallback::RadioModeInfo>
                 hidl_radio_mode_infos;
             if (!hidl_struct_util::convertLegacyWifiMacInfosToHidl(
                     mac_infos, &hidl_radio_mode_infos)) {
@@ -1212,15 +1222,14 @@
         const IWifiChip::ChipIfaceCombination chip_iface_combination_2 = {
             {chip_iface_combination_limit_1, chip_iface_combination_limit_3}};
         if (feature_flags_.lock()->isApDisabled()) {
-          const IWifiChip::ChipMode chip_mode = {
-              kV2ChipModeId,
-              {chip_iface_combination_2}};
-          modes_ = {chip_mode};
+            const IWifiChip::ChipMode chip_mode = {kV2ChipModeId,
+                                                   {chip_iface_combination_2}};
+            modes_ = {chip_mode};
         } else {
-          const IWifiChip::ChipMode chip_mode = {
-            kV2ChipModeId,
-            {chip_iface_combination_1, chip_iface_combination_2}};
-          modes_ = {chip_mode};
+            const IWifiChip::ChipMode chip_mode = {
+                kV2ChipModeId,
+                {chip_iface_combination_1, chip_iface_combination_2}};
+            modes_ = {chip_mode};
         }
     } else {
         // V1 Iface combinations for Mode Id = 0. (STA Mode)
@@ -1246,9 +1255,9 @@
         const IWifiChip::ChipMode ap_chip_mode = {kV1ApChipModeId,
                                                   {ap_chip_iface_combination}};
         if (feature_flags_.lock()->isApDisabled()) {
-          modes_ = {sta_chip_mode};
+            modes_ = {sta_chip_mode};
         } else {
-          modes_ = {sta_chip_mode, ap_chip_mode};
+            modes_ = {sta_chip_mode, ap_chip_mode};
         }
     }
 }
@@ -1415,7 +1424,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_chip.h b/wifi/1.3/default/wifi_chip.h
similarity index 95%
rename from wifi/1.2/default/wifi_chip.h
rename to wifi/1.3/default/wifi_chip.h
index ada9458..ba60a8e 100644
--- a/wifi/1.2/default/wifi_chip.h
+++ b/wifi/1.3/default/wifi_chip.h
@@ -37,7 +37,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
@@ -69,10 +69,11 @@
     // marked valid before processing them.
     void invalidate();
     bool isValid();
-    std::set<sp<IWifiChipEventCallback>> getEventCallbacks();
+    std::set<sp<V1_2::IWifiChipEventCallback>> getEventCallbacks();
 
     // HIDL methods exposed.
     Return<void> getId(getId_cb hidl_status_cb) override;
+    // Deprecated support for this callback
     Return<void> registerEventCallback(
         const sp<V1_0::IWifiChipEventCallback>& event_callback,
         registerEventCallback_cb hidl_status_cb) override;
@@ -137,18 +138,20 @@
     Return<void> resetTxPowerScenario(
         resetTxPowerScenario_cb hidl_status_cb) override;
     Return<void> registerEventCallback_1_2(
-        const sp<IWifiChipEventCallback>& event_callback,
+        const sp<V1_2::IWifiChipEventCallback>& event_callback,
         registerEventCallback_1_2_cb hidl_status_cb) override;
     Return<void> selectTxPowerScenario_1_2(
         TxPowerScenario scenario,
         selectTxPowerScenario_cb hidl_status_cb) override;
     Return<void> debug(const hidl_handle& handle,
                        const hidl_vec<hidl_string>& options) override;
+
    private:
     void invalidateAndRemoveAllIfaces();
 
     // Corresponding worker functions for the HIDL methods.
     std::pair<WifiStatus, ChipId> getIdInternal();
+    // Deprecated support for this callback
     WifiStatus registerEventCallbackInternal(
         const sp<V1_0::IWifiChipEventCallback>& event_callback);
     std::pair<WifiStatus, uint32_t> getCapabilitiesInternal();
@@ -195,10 +198,11 @@
     std::pair<WifiStatus, WifiDebugHostWakeReasonStats>
     getDebugHostWakeReasonStatsInternal();
     WifiStatus enableDebugErrorAlertsInternal(bool enable);
-    WifiStatus selectTxPowerScenarioInternal(V1_1::IWifiChip::TxPowerScenario scenario);
+    WifiStatus selectTxPowerScenarioInternal(
+        V1_1::IWifiChip::TxPowerScenario scenario);
     WifiStatus resetTxPowerScenarioInternal();
     WifiStatus registerEventCallbackInternal_1_2(
-        const sp<IWifiChipEventCallback>& event_callback);
+        const sp<V1_2::IWifiChipEventCallback>& event_callback);
     WifiStatus selectTxPowerScenarioInternal_1_2(TxPowerScenario scenario);
     WifiStatus handleChipConfiguration(
         std::unique_lock<std::recursive_mutex>* lock, ChipModeId mode_id);
@@ -236,14 +240,14 @@
     // registration mechanism. Use this to check if we have already
     // registered a callback.
     bool debug_ring_buffer_cb_registered_;
-    hidl_callback_util::HidlCallbackHandler<IWifiChipEventCallback>
+    hidl_callback_util::HidlCallbackHandler<V1_2::IWifiChipEventCallback>
         event_cb_handler_;
 
     DISALLOW_COPY_AND_ASSIGN(WifiChip);
 };
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_feature_flags.cpp b/wifi/1.3/default/wifi_feature_flags.cpp
similarity index 93%
rename from wifi/1.2/default/wifi_feature_flags.cpp
rename to wifi/1.3/default/wifi_feature_flags.cpp
index 778944d..8d48c36 100644
--- a/wifi/1.2/default/wifi_feature_flags.cpp
+++ b/wifi/1.3/default/wifi_feature_flags.cpp
@@ -38,7 +38,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace feature_flags {
 
@@ -47,13 +47,11 @@
 bool WifiFeatureFlags::isDualInterfaceSupported() {
     return wifiHidlFeatureDualInterface;
 }
-bool WifiFeatureFlags::isApDisabled() {
-  return wifiHidlFeatureDisableAp;
-}
+bool WifiFeatureFlags::isApDisabled() { return wifiHidlFeatureDisableAp; }
 
 }  // namespace feature_flags
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_feature_flags.h b/wifi/1.3/default/wifi_feature_flags.h
similarity index 96%
rename from wifi/1.2/default/wifi_feature_flags.h
rename to wifi/1.3/default/wifi_feature_flags.h
index 4a7b2d2..ce74e23 100644
--- a/wifi/1.2/default/wifi_feature_flags.h
+++ b/wifi/1.3/default/wifi_feature_flags.h
@@ -20,7 +20,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace feature_flags {
 
@@ -36,7 +36,7 @@
 
 }  // namespace feature_flags
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_legacy_hal.cpp b/wifi/1.3/default/wifi_legacy_hal.cpp
similarity index 99%
rename from wifi/1.2/default/wifi_legacy_hal.cpp
rename to wifi/1.3/default/wifi_legacy_hal.cpp
index 375204c..817c860 100644
--- a/wifi/1.2/default/wifi_legacy_hal.cpp
+++ b/wifi/1.3/default/wifi_legacy_hal.cpp
@@ -18,6 +18,7 @@
 #include <chrono>
 
 #include <android-base/logging.h>
+#include <cutils/properties.h>
 
 #include "hidl_sync_util.h"
 #include "wifi_legacy_hal.h"
@@ -35,6 +36,7 @@
 static constexpr uint32_t kMaxWakeReasonStatsArraySize = 32;
 static constexpr uint32_t kMaxRingBuffers = 10;
 static constexpr uint32_t kMaxStopCompleteWaitMs = 100;
+static constexpr char kDriverPropName[] = "wlan.driver.status";
 
 // Helper function to create a non-const char* for legacy Hal API's.
 std::vector<char> makeCharVec(const std::string& str) {
@@ -48,7 +50,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace legacy_hal {
 // Legacy HAL functions accept "C" style function pointers, so use global
@@ -366,6 +368,8 @@
         LOG(ERROR) << "Timed out awaiting driver ready";
         return status;
     }
+    property_set(kDriverPropName, "ok");
+
     LOG(DEBUG) << "Starting legacy HAL";
     if (!iface_tool_.SetWifiUpState(true)) {
         LOG(ERROR) << "Failed to set WiFi interface up";
@@ -1417,7 +1421,7 @@
 
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_legacy_hal.h b/wifi/1.3/default/wifi_legacy_hal.h
similarity index 98%
rename from wifi/1.2/default/wifi_legacy_hal.h
rename to wifi/1.3/default/wifi_legacy_hal.h
index 00dfeef..af654fa 100644
--- a/wifi/1.2/default/wifi_legacy_hal.h
+++ b/wifi/1.3/default/wifi_legacy_hal.h
@@ -27,14 +27,15 @@
 
 // HACK: The include inside the namespace below also transitively includes a
 // bunch of libc headers into the namespace, which leads to functions like
-// socketpair being defined in android::hardware::wifi::V1_1::implementation::legacy_hal.
-// Include this one particular header as a hacky workaround until that's fixed.
+// socketpair being defined in
+// android::hardware::wifi::V1_1::implementation::legacy_hal. Include this one
+// particular header as a hacky workaround until that's fixed.
 #include <sys/socket.h>
 
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 // This is in a separate namespace to prevent typename conflicts between
 // the legacy HAL types and the HIDL interface types.
@@ -106,7 +107,8 @@
         on_event_transmit_follow_up;
     std::function<void(const NanRangeRequestInd&)> on_event_range_request;
     std::function<void(const NanRangeReportInd&)> on_event_range_report;
-    std::function<void(const NanDataPathScheduleUpdateInd&)> on_event_schedule_update;
+    std::function<void(const NanDataPathScheduleUpdateInd&)>
+        on_event_schedule_update;
 };
 
 // Full scan results contain IE info and are hence passed by reference, to
@@ -389,7 +391,7 @@
 
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_legacy_hal_stubs.cpp b/wifi/1.3/default/wifi_legacy_hal_stubs.cpp
similarity index 99%
rename from wifi/1.2/default/wifi_legacy_hal_stubs.cpp
rename to wifi/1.3/default/wifi_legacy_hal_stubs.cpp
index fc28bb5..942df2a 100644
--- a/wifi/1.2/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/1.3/default/wifi_legacy_hal_stubs.cpp
@@ -20,7 +20,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace legacy_hal {
 template <typename>
@@ -141,7 +141,7 @@
 }
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_legacy_hal_stubs.h b/wifi/1.3/default/wifi_legacy_hal_stubs.h
similarity index 96%
rename from wifi/1.2/default/wifi_legacy_hal_stubs.h
rename to wifi/1.3/default/wifi_legacy_hal_stubs.h
index d560dd4..64854e0 100644
--- a/wifi/1.2/default/wifi_legacy_hal_stubs.h
+++ b/wifi/1.3/default/wifi_legacy_hal_stubs.h
@@ -20,7 +20,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace legacy_hal {
 #include <hardware_legacy/wifi_hal.h>
@@ -28,7 +28,7 @@
 bool initHalFuncTableWithStubs(wifi_hal_fn* hal_fn);
 }  // namespace legacy_hal
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_mode_controller.cpp b/wifi/1.3/default/wifi_mode_controller.cpp
similarity index 98%
rename from wifi/1.2/default/wifi_mode_controller.cpp
rename to wifi/1.3/default/wifi_mode_controller.cpp
index c286d24..c392486 100644
--- a/wifi/1.2/default/wifi_mode_controller.cpp
+++ b/wifi/1.3/default/wifi_mode_controller.cpp
@@ -48,7 +48,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace mode_controller {
 
@@ -85,7 +85,7 @@
 }
 }  // namespace mode_controller
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_mode_controller.h b/wifi/1.3/default/wifi_mode_controller.h
similarity index 97%
rename from wifi/1.2/default/wifi_mode_controller.h
rename to wifi/1.3/default/wifi_mode_controller.h
index 395aa5d..ace5a52 100644
--- a/wifi/1.2/default/wifi_mode_controller.h
+++ b/wifi/1.3/default/wifi_mode_controller.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 namespace mode_controller {
 using namespace android::hardware::wifi::V1_0;
@@ -55,7 +55,7 @@
 
 }  // namespace mode_controller
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_nan_iface.cpp b/wifi/1.3/default/wifi_nan_iface.cpp
similarity index 98%
rename from wifi/1.2/default/wifi_nan_iface.cpp
rename to wifi/1.3/default/wifi_nan_iface.cpp
index 566d36e..4325f44 100644
--- a/wifi/1.2/default/wifi_nan_iface.cpp
+++ b/wifi/1.3/default/wifi_nan_iface.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -420,7 +420,7 @@
                 LOG(ERROR) << "Callback invoked on an invalid object";
                 return;
             }
-            NanDataPathConfirmInd hidl_struct;
+            V1_2::NanDataPathConfirmInd hidl_struct;
             if (!hidl_struct_util::convertLegacyNanDataPathConfirmIndToHidl(
                     msg, &hidl_struct)) {
                 LOG(ERROR) << "Failed to convert nan capabilities response";
@@ -477,7 +477,7 @@
             LOG(ERROR) << "Callback invoked on an invalid object";
             return;
         }
-        NanDataPathScheduleUpdateInd hidl_struct;
+        V1_2::NanDataPathScheduleUpdateInd hidl_struct;
         if (!hidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToHidl(
                 msg, &hidl_struct)) {
             LOG(ERROR) << "Failed to convert nan capabilities response";
@@ -655,7 +655,7 @@
 }
 
 Return<void> WifiNanIface::registerEventCallback_1_2(
-    const sp<IWifiNanIfaceEventCallback>& callback,
+    const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
     registerEventCallback_1_2_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
                            &WifiNanIface::registerEventCallback_1_2Internal,
@@ -664,7 +664,7 @@
 
 Return<void> WifiNanIface::enableRequest_1_2(
     uint16_t cmd_id, const NanEnableRequest& msg1,
-    const NanConfigRequestSupplemental& msg2,
+    const V1_2::NanConfigRequestSupplemental& msg2,
     enableRequest_1_2_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
                            &WifiNanIface::enableRequest_1_2Internal,
@@ -673,7 +673,7 @@
 
 Return<void> WifiNanIface::configRequest_1_2(
     uint16_t cmd_id, const NanConfigRequest& msg1,
-    const NanConfigRequestSupplemental& msg2,
+    const V1_2::NanConfigRequestSupplemental& msg2,
     configRequest_1_2_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
                            &WifiNanIface::configRequest_1_2Internal,
@@ -832,7 +832,7 @@
 
 WifiStatus WifiNanIface::enableRequest_1_2Internal(
     uint16_t cmd_id, const NanEnableRequest& msg1,
-    const NanConfigRequestSupplemental& msg2) {
+    const V1_2::NanConfigRequestSupplemental& msg2) {
     legacy_hal::NanEnableRequest legacy_msg;
     if (!hidl_struct_util::convertHidlNanEnableRequest_1_2ToLegacy(
             msg1, msg2, &legacy_msg)) {
@@ -845,7 +845,7 @@
 
 WifiStatus WifiNanIface::configRequest_1_2Internal(
     uint16_t cmd_id, const NanConfigRequest& msg1,
-    const NanConfigRequestSupplemental& msg2) {
+    const V1_2::NanConfigRequestSupplemental& msg2) {
     legacy_hal::NanConfigRequest legacy_msg;
     if (!hidl_struct_util::convertHidlNanConfigRequest_1_2ToLegacy(
             msg1, msg2, &legacy_msg)) {
@@ -857,7 +857,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_nan_iface.h b/wifi/1.3/default/wifi_nan_iface.h
similarity index 95%
rename from wifi/1.2/default/wifi_nan_iface.h
rename to wifi/1.3/default/wifi_nan_iface.h
index dba527b..f735d61 100644
--- a/wifi/1.2/default/wifi_nan_iface.h
+++ b/wifi/1.3/default/wifi_nan_iface.h
@@ -27,7 +27,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
@@ -89,15 +89,15 @@
         terminateDataPathRequest_cb hidl_status_cb) override;
 
     Return<void> registerEventCallback_1_2(
-        const sp<IWifiNanIfaceEventCallback>& callback,
+        const sp<V1_2::IWifiNanIfaceEventCallback>& callback,
         registerEventCallback_1_2_cb hidl_status_cb) override;
     Return<void> enableRequest_1_2(
         uint16_t cmd_id, const NanEnableRequest& msg1,
-        const NanConfigRequestSupplemental& msg2,
+        const V1_2::NanConfigRequestSupplemental& msg2,
         enableRequest_1_2_cb hidl_status_cb) override;
     Return<void> configRequest_1_2(
         uint16_t cmd_id, const NanConfigRequest& msg1,
-        const NanConfigRequestSupplemental& msg2,
+        const V1_2::NanConfigRequestSupplemental& msg2,
         configRequest_1_2_cb hidl_status_cb) override;
 
    private:
@@ -135,10 +135,10 @@
         const sp<V1_2::IWifiNanIfaceEventCallback>& callback);
     WifiStatus enableRequest_1_2Internal(
         uint16_t cmd_id, const NanEnableRequest& msg1,
-        const NanConfigRequestSupplemental& msg2);
+        const V1_2::NanConfigRequestSupplemental& msg2);
     WifiStatus configRequest_1_2Internal(
         uint16_t cmd_id, const NanConfigRequest& msg,
-        const NanConfigRequestSupplemental& msg2);
+        const V1_2::NanConfigRequestSupplemental& msg2);
 
     // all 1_0 and descendant callbacks
     std::set<sp<V1_0::IWifiNanIfaceEventCallback>> getEventCallbacks();
@@ -157,7 +157,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_p2p_iface.cpp b/wifi/1.3/default/wifi_p2p_iface.cpp
similarity index 97%
rename from wifi/1.2/default/wifi_p2p_iface.cpp
rename to wifi/1.3/default/wifi_p2p_iface.cpp
index 92bbaee..b5d5886 100644
--- a/wifi/1.2/default/wifi_p2p_iface.cpp
+++ b/wifi/1.3/default/wifi_p2p_iface.cpp
@@ -23,7 +23,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -60,7 +60,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_p2p_iface.h b/wifi/1.3/default/wifi_p2p_iface.h
similarity index 97%
rename from wifi/1.2/default/wifi_p2p_iface.h
rename to wifi/1.3/default/wifi_p2p_iface.h
index 76120b1..8a7207a 100644
--- a/wifi/1.2/default/wifi_p2p_iface.h
+++ b/wifi/1.3/default/wifi_p2p_iface.h
@@ -25,7 +25,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
@@ -58,7 +58,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_rtt_controller.cpp b/wifi/1.3/default/wifi_rtt_controller.cpp
similarity index 99%
rename from wifi/1.2/default/wifi_rtt_controller.cpp
rename to wifi/1.3/default/wifi_rtt_controller.cpp
index b68445b..fa317e3 100644
--- a/wifi/1.2/default/wifi_rtt_controller.cpp
+++ b/wifi/1.3/default/wifi_rtt_controller.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -269,7 +269,7 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_rtt_controller.h b/wifi/1.3/default/wifi_rtt_controller.h
similarity index 98%
rename from wifi/1.2/default/wifi_rtt_controller.h
rename to wifi/1.3/default/wifi_rtt_controller.h
index 1ab01e1..9798b79 100644
--- a/wifi/1.2/default/wifi_rtt_controller.h
+++ b/wifi/1.3/default/wifi_rtt_controller.h
@@ -27,7 +27,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 
 /**
@@ -97,7 +97,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_sta_iface.cpp b/wifi/1.3/default/wifi_sta_iface.cpp
similarity index 97%
rename from wifi/1.2/default/wifi_sta_iface.cpp
rename to wifi/1.3/default/wifi_sta_iface.cpp
index daa5610..b0fa1ae 100644
--- a/wifi/1.2/default/wifi_sta_iface.cpp
+++ b/wifi/1.3/default/wifi_sta_iface.cpp
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 using hidl_return_util::validateAndCall;
 
@@ -152,6 +152,13 @@
                            hidl_status_cb);
 }
 
+Return<void> WifiStaIface::getLinkLayerStats_1_3(
+    getLinkLayerStats_1_3_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiStaIface::getLinkLayerStatsInternal_1_3,
+                           hidl_status_cb);
+}
+
 Return<void> WifiStaIface::startRssiMonitoring(
     uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
     startRssiMonitoring_cb hidl_status_cb) {
@@ -445,8 +452,13 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
-std::pair<WifiStatus, StaLinkLayerStats>
+std::pair<WifiStatus, V1_0::StaLinkLayerStats>
 WifiStaIface::getLinkLayerStatsInternal() {
+    return {createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED), {}};
+}
+
+std::pair<WifiStatus, V1_3::StaLinkLayerStats>
+WifiStaIface::getLinkLayerStatsInternal_1_3() {
     legacy_hal::wifi_error legacy_status;
     legacy_hal::LinkLayerStats legacy_stats;
     std::tie(legacy_status, legacy_stats) =
@@ -454,7 +466,7 @@
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
         return {createWifiStatusFromLegacyError(legacy_status), {}};
     }
-    StaLinkLayerStats hidl_stats;
+    V1_3::StaLinkLayerStats hidl_stats;
     if (!hidl_struct_util::convertLegacyLinkLayerStatsToHidl(legacy_stats,
                                                              &hidl_stats)) {
         return {createWifiStatus(WifiStatusCode::ERROR_UNKNOWN), {}};
@@ -622,7 +634,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_sta_iface.h b/wifi/1.3/default/wifi_sta_iface.h
similarity index 94%
rename from wifi/1.2/default/wifi_sta_iface.h
rename to wifi/1.3/default/wifi_sta_iface.h
index 71cd17d..bc3090f 100644
--- a/wifi/1.2/default/wifi_sta_iface.h
+++ b/wifi/1.3/default/wifi_sta_iface.h
@@ -19,7 +19,7 @@
 
 #include <android-base/macros.h>
 #include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
-#include <android/hardware/wifi/1.2/IWifiStaIface.h>
+#include <android/hardware/wifi/1.3/IWifiStaIface.h>
 
 #include <wifi_system/interface_tool.h>
 
@@ -29,14 +29,14 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
 /**
  * HIDL interface object used to control a STA Iface instance.
  */
-class WifiStaIface : public V1_2::IWifiStaIface {
+class WifiStaIface : public V1_3::IWifiStaIface {
    public:
     WifiStaIface(const std::string& ifname,
                  const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
@@ -75,6 +75,8 @@
         disableLinkLayerStatsCollection_cb hidl_status_cb) override;
     Return<void> getLinkLayerStats(
         getLinkLayerStats_cb hidl_status_cb) override;
+    Return<void> getLinkLayerStats_1_3(
+        getLinkLayerStats_1_3_cb hidl_status_cb) override;
     Return<void> startRssiMonitoring(
         uint32_t cmd_id, int32_t max_rssi, int32_t min_rssi,
         startRssiMonitoring_cb hidl_status_cb) override;
@@ -130,7 +132,9 @@
     WifiStatus stopBackgroundScanInternal(uint32_t cmd_id);
     WifiStatus enableLinkLayerStatsCollectionInternal(bool debug);
     WifiStatus disableLinkLayerStatsCollectionInternal();
-    std::pair<WifiStatus, StaLinkLayerStats> getLinkLayerStatsInternal();
+    std::pair<WifiStatus, V1_0::StaLinkLayerStats> getLinkLayerStatsInternal();
+    std::pair<WifiStatus, V1_3::StaLinkLayerStats>
+    getLinkLayerStatsInternal_1_3();
     WifiStatus startRssiMonitoringInternal(uint32_t cmd_id, int32_t max_rssi,
                                            int32_t min_rssi);
     WifiStatus stopRssiMonitoringInternal(uint32_t cmd_id);
@@ -163,7 +167,7 @@
 };
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_status_util.cpp b/wifi/1.3/default/wifi_status_util.cpp
similarity index 98%
rename from wifi/1.2/default/wifi_status_util.cpp
rename to wifi/1.3/default/wifi_status_util.cpp
index dd37b6b..0a5bb13 100644
--- a/wifi/1.2/default/wifi_status_util.cpp
+++ b/wifi/1.3/default/wifi_status_util.cpp
@@ -19,7 +19,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 
 std::string legacyErrorToString(legacy_hal::wifi_error error) {
@@ -100,7 +100,7 @@
 }
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.2/default/wifi_status_util.h b/wifi/1.3/default/wifi_status_util.h
similarity index 97%
rename from wifi/1.2/default/wifi_status_util.h
rename to wifi/1.3/default/wifi_status_util.h
index e9136b3..bc8baa9 100644
--- a/wifi/1.2/default/wifi_status_util.h
+++ b/wifi/1.3/default/wifi_status_util.h
@@ -24,7 +24,7 @@
 namespace android {
 namespace hardware {
 namespace wifi {
-namespace V1_2 {
+namespace V1_3 {
 namespace implementation {
 using namespace android::hardware::wifi::V1_0;
 
@@ -37,7 +37,7 @@
 WifiStatus createWifiStatusFromLegacyError(legacy_hal::wifi_error error);
 
 }  // namespace implementation
-}  // namespace V1_2
+}  // namespace V1_3
 }  // namespace wifi
 }  // namespace hardware
 }  // namespace android
diff --git a/wifi/1.3/types.hal b/wifi/1.3/types.hal
new file mode 100644
index 0000000..4585ff3
--- /dev/null
+++ b/wifi/1.3/types.hal
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.3;
+
+import @1.0::StaLinkLayerRadioStats;
+import @1.0::StaLinkLayerIfaceStats;
+import @1.0::TimeStampInMs;
+
+struct StaLinkLayerRadioStats {
+    /**
+     * Baseline information as defined in HAL 1.0.
+     */
+    @1.0::StaLinkLayerRadioStats V1_0;
+
+    /**
+     * Total time for which the radio is awake due to NAN scan since boot or crash.
+     */
+    uint32_t onTimeInMsForNanScan;
+
+    /**
+     * Total time for which the radio is awake due to background scan since boot or crash.
+     */
+    uint32_t onTimeInMsForBgScan;
+
+    /**
+     * Total time for which the radio is awake due to roam scan since boot or crash.
+     */
+    uint32_t onTimeInMsForRoamScan;
+
+    /**
+     * Total time for which the radio is awake due to PNO scan since boot or crash.
+     */
+    uint32_t onTimeInMsForPnoScan;
+
+    /**
+     * Total time for which the radio is awake due to Hotspot 2.0 scans and GAS exchange since boot
+     * or crash.
+     */
+    uint32_t onTimeInMsForHs20Scan;
+};
+
+/**
+ * Link layer stats retrieved via |getLinkLayerStats|.
+ */
+struct StaLinkLayerStats {
+    StaLinkLayerIfaceStats iface;
+    vec<StaLinkLayerRadioStats> radios;
+    /**
+     * TimeStamp for each stats sample.
+     * This is the absolute milliseconds from boot when these stats were
+     * sampled.
+     */
+    TimeStampInMs timeStampInMs;
+};
\ No newline at end of file
diff --git a/wifi/1.2/default/OWNERS b/wifi/1.3/vts/OWNERS
similarity index 100%
copy from wifi/1.2/default/OWNERS
copy to wifi/1.3/vts/OWNERS
diff --git a/wifi/1.3/vts/functional/Android.bp b/wifi/1.3/vts/functional/Android.bp
new file mode 100644
index 0000000..dbe77bd
--- /dev/null
+++ b/wifi/1.3/vts/functional/Android.bp
@@ -0,0 +1,30 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalWifiV1_3TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "VtsHalWifiV1_3TargetTest.cpp",
+    ],
+    static_libs: [
+        "VtsHalWifiV1_0TargetTestUtil",
+        "android.hardware.wifi@1.0",
+        "android.hardware.wifi@1.1",
+        "android.hardware.wifi@1.2",
+        "android.hardware.wifi@1.3",
+    ],
+}
diff --git a/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp
new file mode 100644
index 0000000..b410a48
--- /dev/null
+++ b/wifi/1.3/vts/functional/VtsHalWifiV1_3TargetTest.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/logging.h>
+#include <android/hardware/wifi/1.3/IWifi.h>
+
+#include "wifi_hidl_test_utils.h"
+
+// Test environment for Wifi HIDL HAL.
+class WifiHidlEnvironment_1_3 : public WifiHidlEnvironment {
+   public:
+    // get the test environment singleton
+    static WifiHidlEnvironment_1_3* Instance() {
+        static WifiHidlEnvironment_1_3* instance = new WifiHidlEnvironment_1_3;
+        return instance;
+    }
+
+    virtual void registerTestServices() override {
+        registerTestService<android::hardware::wifi::V1_3::IWifi>();
+    }
+
+   private:
+    WifiHidlEnvironment_1_3() {}
+};
+
+WifiHidlEnvironment_1_3* gEnv = WifiHidlEnvironment_1_3::Instance();
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(gEnv);
+    ::testing::InitGoogleTest(&argc, argv);
+    gEnv->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
diff --git a/wifi/hostapd/1.1/Android.bp b/wifi/hostapd/1.1/Android.bp
new file mode 100644
index 0000000..d4170b6
--- /dev/null
+++ b/wifi/hostapd/1.1/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi.hostapd@1.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IHostapd.hal",
+        "IHostapdCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.wifi.hostapd@1.0",
+        "android.hardware.wifi.supplicant@1.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
+
diff --git a/wifi/hostapd/1.1/IHostapd.hal b/wifi/hostapd/1.1/IHostapd.hal
new file mode 100644
index 0000000..4e59ffc
--- /dev/null
+++ b/wifi/hostapd/1.1/IHostapd.hal
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.hostapd@1.1;
+
+import @1.0::IHostapd;
+import @1.0::HostapdStatus;
+
+import IHostapdCallback;
+
+/**
+ * Top-level object for managing SoftAPs.
+ */
+interface IHostapd extends @1.0::IHostapd {
+    /**
+     * Register for callbacks from the hostapd service.
+     *
+     * These callbacks are invoked for global events that are not specific
+     * to any interface or network. Registration of multiple callback
+     * objects is supported. These objects must be deleted when the corresponding
+     * client process is dead.
+     *
+     * @param callback An instance of the |IHostapdCallback| HIDL interface
+     *     object.
+     * @return status Status of the operation.
+     *     Possible status codes:
+     *     |HostapdStatusCode.SUCCESS|,
+     *     |HostapdStatusCode.FAILURE_UNKNOWN|
+     */
+    registerCallback(IHostapdCallback callback)
+        generates (HostapdStatus status);
+};
diff --git a/wifi/hostapd/1.1/IHostapdCallback.hal b/wifi/hostapd/1.1/IHostapdCallback.hal
new file mode 100644
index 0000000..1d314fe
--- /dev/null
+++ b/wifi/hostapd/1.1/IHostapdCallback.hal
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.hostapd@1.1;
+
+/**
+ * Top-level object for managing SoftAPs.
+ */
+interface IHostapdCallback {
+    /**
+     * Invoked when an asynchronous failure is encountered in one of the access
+     * points added via |IHostapd.addAccessPoint|.
+     *
+     * @param ifaceName Name of the interface.
+     */
+    oneway onFailure(string ifaceName);
+};