Merge "camera: Add external flash mode key"
diff --git a/audio/2.0/Android.bp b/audio/2.0/Android.bp
index 1643c12..d6e481f 100644
--- a/audio/2.0/Android.bp
+++ b/audio/2.0/Android.bp
@@ -18,6 +18,7 @@
     ],
     interfaces: [
         "android.hardware.audio.common@2.0",
+        "android.hardware.audio.effect@2.0",
         "android.hidl.base@1.0",
     ],
     types: [
diff --git a/authsecret/1.0/Android.bp b/authsecret/1.0/Android.bp
new file mode 100644
index 0000000..9cde99a
--- /dev/null
+++ b/authsecret/1.0/Android.bp
@@ -0,0 +1,17 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.authsecret@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "IAuthSecret.hal",
+    ],
+    interfaces: [
+        "android.hidl.base@1.0",
+    ],
+    gen_java: true,
+}
+
diff --git a/authsecret/1.0/IAuthSecret.hal b/authsecret/1.0/IAuthSecret.hal
new file mode 100644
index 0000000..d2cb5da
--- /dev/null
+++ b/authsecret/1.0/IAuthSecret.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.authsecret@1.0;
+
+/**
+ * This security HAL allows vendor components to be cryptographically tied to
+ * the primary user's credential. For example, security hardware could require
+ * proof that the credential is known before applying updates.
+ *
+ * This HAL is optional so does not require an implementation on device.
+ */
+interface IAuthSecret {
+    /**
+     * When the primary user correctly enters their credential, this method is
+     * passed a secret derived from that credential to prove that their
+     * credential is known.
+     *
+     * The first time this is called, the secret must be used to provision state
+     * that depends on the primary user's credential. The same secret is passed
+     * on each call until a factory reset after which there must be a new
+     * secret.
+     *
+     * The secret must be at lesat 16 bytes.
+     *
+     * @param secret blob derived from the primary user's credential.
+     */
+    primaryUserCredential(vec<uint8_t> secret);
+
+    /**
+     * Called from recovery during factory reset. The secret is now lost and can
+     * no longer be derived. Any data linked to the secret must be destroyed and
+     * any dependence on the secret must be removed.
+     */
+    factoryReset();
+};
diff --git a/authsecret/1.0/default/Android.bp b/authsecret/1.0/default/Android.bp
new file mode 100644
index 0000000..5c3234f
--- /dev/null
+++ b/authsecret/1.0/default/Android.bp
@@ -0,0 +1,21 @@
+cc_binary {
+    name: "android.hardware.authsecret@1.0-service",
+    init_rc: ["android.hardware.authsecret@1.0-service.rc"],
+    relative_install_path: "hw",
+    vendor: true,
+    srcs: [
+        "service.cpp",
+        "AuthSecret.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+        "android.hardware.authsecret@1.0",
+    ],
+}
diff --git a/authsecret/1.0/default/AuthSecret.cpp b/authsecret/1.0/default/AuthSecret.cpp
new file mode 100644
index 0000000..46a3ec1
--- /dev/null
+++ b/authsecret/1.0/default/AuthSecret.cpp
@@ -0,0 +1,47 @@
+#include "AuthSecret.h"
+
+namespace android {
+namespace hardware {
+namespace authsecret {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::authsecret::V1_0::IAuthSecret follow.
+Return<void> AuthSecret::primaryUserCredential(const hidl_vec<uint8_t>& secret) {
+    (void)secret;
+
+    // To create a dependency on the credential, it is recommended to derive a
+    // different value from the provided secret for each purpose e.g.
+    //
+    //     purpose1_secret = hash( "purpose1" || secret )
+    //     purpose2_secret = hash( "purpose2" || secret )
+    //
+    // The derived values can then be used as cryptographic keys or stored
+    // securely for comparison in a future call.
+    //
+    // For example, a security module might require that the credential has been
+    // entered before it applies any updates. This can be achieved by storing a
+    // derived value in the module and only applying updates when the same
+    // derived value is presented again.
+    //
+    // This implementation does nothing.
+
+    return Void();
+}
+
+Return<void> AuthSecret::factoryReset() {
+    // Clear all dependency on the secret.
+    //
+    // With the example of updating a security module, the stored value must be
+    // cleared so that the new primary user enrolled as the approver of updates.
+    //
+    // This implementation does nothing as there is no dependence on the secret.
+
+    return Void();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace authsecret
+}  // namespace hardware
+}  // namespace android
diff --git a/authsecret/1.0/default/AuthSecret.h b/authsecret/1.0/default/AuthSecret.h
new file mode 100644
index 0000000..edb49b8
--- /dev/null
+++ b/authsecret/1.0/default/AuthSecret.h
@@ -0,0 +1,36 @@
+#ifndef ANDROID_HARDWARE_AUTHSECRET_V1_0_AUTHSECRET_H
+#define ANDROID_HARDWARE_AUTHSECRET_V1_0_AUTHSECRET_H
+
+#include <android/hardware/authsecret/1.0/IAuthSecret.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace authsecret {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+struct AuthSecret : public IAuthSecret {
+    // Methods from ::android::hardware::authsecret::V1_0::IAuthSecret follow.
+    Return<void> primaryUserCredential(const hidl_vec<uint8_t>& secret) override;
+    Return<void> factoryReset() override;
+
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace authsecret
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_AUTHSECRET_V1_0_AUTHSECRET_H
diff --git a/authsecret/1.0/default/android.hardware.authsecret@1.0-service.rc b/authsecret/1.0/default/android.hardware.authsecret@1.0-service.rc
new file mode 100644
index 0000000..e82da7e
--- /dev/null
+++ b/authsecret/1.0/default/android.hardware.authsecret@1.0-service.rc
@@ -0,0 +1,4 @@
+service vendor.authsecret-1-0 /vendor/bin/hw/android.hardware.authsecret@1.0-service
+    class hal
+    user system
+    group system
diff --git a/authsecret/1.0/default/service.cpp b/authsecret/1.0/default/service.cpp
new file mode 100644
index 0000000..4acd16c
--- /dev/null
+++ b/authsecret/1.0/default/service.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.1
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "android.hardware.authsecret@1.0-service"
+
+#include <android/hardware/authsecret/1.0/IAuthSecret.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "AuthSecret.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::authsecret::V1_0::IAuthSecret;
+using android::hardware::authsecret::V1_0::implementation::AuthSecret;
+using android::sp;
+using android::status_t;
+using android::OK;
+
+int main() {
+    configureRpcThreadpool(1, true);
+
+    sp<IAuthSecret> authSecret = new AuthSecret;
+    status_t status = authSecret->registerAsService();
+    LOG_ALWAYS_FATAL_IF(status != OK, "Could not register IAuthSecret");
+
+    joinRpcThreadpool();
+    return 0;
+}
diff --git a/authsecret/1.0/vts/functional/Android.bp b/authsecret/1.0/vts/functional/Android.bp
new file mode 100644
index 0000000..de9f560
--- /dev/null
+++ b/authsecret/1.0/vts/functional/Android.bp
@@ -0,0 +1,22 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalAuthSecretV1_0TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalAuthSecretV1_0TargetTest.cpp"],
+    static_libs: ["android.hardware.authsecret@1.0"],
+}
diff --git a/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp b/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
new file mode 100644
index 0000000..b0cbd91
--- /dev/null
+++ b/authsecret/1.0/vts/functional/VtsHalAuthSecretV1_0TargetTest.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/authsecret/1.0/IAuthSecret.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::authsecret::V1_0::IAuthSecret;
+using ::android::sp;
+
+/**
+ * There is no expected behaviour that can be tested so these tests check the
+ * HAL doesn't crash with different execution orders.
+ */
+struct AuthSecretHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+    virtual void SetUp() override {
+        authsecret = ::testing::VtsHalHidlTargetTestBase::getService<IAuthSecret>();
+        ASSERT_NE(authsecret, nullptr);
+        authsecret->factoryReset();
+    }
+
+    sp<IAuthSecret> authsecret;
+};
+
+/* Provision the primary user with a secret. */
+TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredential) {
+    hidl_vec<uint8_t> secret{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+    authsecret->primaryUserCredential(secret);
+}
+
+/* Provision the primary user with a large secret. */
+TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialWithLargeSecret) {
+    hidl_vec<uint8_t> secret{89,  233, 52,  29,  130, 210, 229, 170, 124, 102, 56,  238, 198,
+                             199, 246, 152, 185, 123, 155, 215, 29,  252, 30,  70,  118, 29,
+                             149, 36,  222, 203, 163, 7,   72,  56,  247, 19,  198, 76,  71,
+                             37,  120, 201, 220, 70,  150, 18,  23,  22,  236, 57,  184, 86,
+                             190, 122, 210, 207, 74,  51,  222, 157, 74,  196, 86,  208};
+    authsecret->primaryUserCredential(secret);
+}
+
+/* Provision the primary user with a secret and pass the secret again. */
+TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgain) {
+    hidl_vec<uint8_t> secret{64, 2, 3, 0, 5, 6, 7, 172, 9, 10, 11, 255, 13, 14, 15, 83};
+    authsecret->primaryUserCredential(secret);
+    authsecret->primaryUserCredential(secret);
+}
+
+/* Provision the primary user with a secret and pass the secret again repeatedly. */
+TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndPassAgainMultipleTimes) {
+    hidl_vec<uint8_t> secret{1, 2, 34, 4, 5, 6, 7, 8, 9, 105, 11, 12, 13, 184, 15, 16};
+    authsecret->primaryUserCredential(secret);
+    constexpr int N = 5;
+    for (int i = 0; i < N; ++i) {
+        authsecret->primaryUserCredential(secret);
+    }
+}
+
+/* Factory reset before provisioning the primary user with a secret. */
+TEST_F(AuthSecretHidlTest, factoryResetWithoutProvisioningPrimaryUserCredential) {
+    authsecret->factoryReset();
+}
+
+/* Provision the primary user with a secret then factory reset. */
+TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialAndFactoryReset) {
+    hidl_vec<uint8_t> secret{1, 24, 124, 240, 5, 6, 7, 8, 9, 13, 11, 12, 189, 14, 195, 16};
+    authsecret->primaryUserCredential(secret);
+    authsecret->factoryReset();
+}
+
+/* Provision the primary differently after factory reset. */
+TEST_F(AuthSecretHidlTest, provisionPrimaryUserCredentialDifferentlyAfterFactoryReset) {
+    {
+        hidl_vec<uint8_t> secret1{19, 0, 65, 20, 65, 12, 7, 8, 9, 13, 29, 12, 189, 32, 195, 16};
+        authsecret->primaryUserCredential(secret1);
+    }
+
+    authsecret->factoryReset();
+
+    {
+        hidl_vec<uint8_t> secret2{61, 93, 124, 240, 5, 0, 7, 201, 9, 129, 11, 12, 0, 14, 0, 16};
+        authsecret->primaryUserCredential(secret2);
+    }
+}
diff --git a/automotive/vehicle/2.0/Android.bp b/automotive/vehicle/2.0/Android.bp
index 7ab2387..ffe012e 100644
--- a/automotive/vehicle/2.0/Android.bp
+++ b/automotive/vehicle/2.0/Android.bp
@@ -42,19 +42,6 @@
         "VehicleAreaSeat",
         "VehicleAreaWindow",
         "VehicleAreaZone",
-        "VehicleAudioContextFlag",
-        "VehicleAudioExtFocusFlag",
-        "VehicleAudioFocusIndex",
-        "VehicleAudioFocusRequest",
-        "VehicleAudioFocusState",
-        "VehicleAudioHwVariantConfigFlag",
-        "VehicleAudioRoutingPolicyIndex",
-        "VehicleAudioStream",
-        "VehicleAudioStreamFlag",
-        "VehicleAudioVolumeCapabilityFlag",
-        "VehicleAudioVolumeIndex",
-        "VehicleAudioVolumeLimitIndex",
-        "VehicleAudioVolumeState",
         "VehicleDisplay",
         "VehicleDrivingStatus",
         "VehicleGear",
diff --git a/automotive/vehicle/2.0/IVehicle.hal b/automotive/vehicle/2.0/IVehicle.hal
index d962de0..1b1d391 100644
--- a/automotive/vehicle/2.0/IVehicle.hal
+++ b/automotive/vehicle/2.0/IVehicle.hal
@@ -43,7 +43,7 @@
    * For VehiclePropertyChangeMode::ON_CHANGE properties, it must return the
    * latest available value.
    *
-   * Some properties like AUDIO_VOLUME requires to pass additional data in
+   * Some properties like RADIO_PRESET requires to pass additional data in
    * GET request in VehiclePropValue object.
    *
    * If there is no data available yet, which can happen during initial stage,
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 1690163..6a254a5 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -46,6 +46,7 @@
         "common/src/VehicleObjectPool.cpp",
         "common/src/VehiclePropertyStore.cpp",
         "common/src/VehicleUtils.cpp",
+        "common/src/VmsUtils.cpp",
     ],
     local_include_dirs: ["common/include/vhal_v2_0"],
     export_include_dirs: ["common/include"],
@@ -93,6 +94,7 @@
         "tests/VehicleHalManager_test.cpp",
         "tests/VehicleObjectPool_test.cpp",
         "tests/VehiclePropConfigIndex_test.cpp",
+        "tests/VmsUtils_test.cpp",
     ],
     header_libs: ["libbase_headers"],
 }
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
new file mode 100644
index 0000000..9e32bb5
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VmsUtils.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_VmsUtils_H_
+#define android_hardware_automotive_vehicle_V2_0_VmsUtils_H_
+
+#include <memory>
+#include <string>
+
+#include <android/hardware/automotive/vehicle/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace vms {
+
+// VmsUtils are a set of abstractions for creating and parsing Vehicle Property
+// updates to VehicleProperty::VEHICLE_MAP_SERVICE. The format for parsing a
+// VehiclePropValue update with a VMS message is specified in the Vehicle HIDL.
+//
+// This interface is meant for use by HAL clients of VMS; corresponding
+// functionality is also provided by VMS in the embedded car service.
+
+// A VmsLayer is comprised of a type, subtype, and version.
+struct VmsLayer {
+    VmsLayer(int type, int subtype, int version) : type(type), subtype(subtype), version(version) {}
+    int type;
+    int subtype;
+    int version;
+};
+
+struct VmsLayerAndPublisher {
+    VmsLayer layer;
+    int publisher_id;
+};
+
+// A VmsAssociatedLayer is used by subscribers to specify which publisher IDs
+// are acceptable for a given layer.
+struct VmsAssociatedLayer {
+    VmsLayer layer;
+    std::vector<int> publisher_ids;
+};
+
+// A VmsLayerOffering refers to a single layer that can be published, along with
+// its dependencies. Dependencies can be empty.
+struct VmsLayerOffering {
+    VmsLayerOffering(VmsLayer layer, std::vector<VmsLayer> dependencies)
+        : layer(layer), dependencies(dependencies) {}
+    VmsLayerOffering(VmsLayer layer) : layer(layer), dependencies() {}
+    VmsLayer layer;
+    std::vector<VmsLayer> dependencies;
+};
+
+// A VmsSubscriptionsState is delivered in response to a
+// VmsMessageType.SUBSCRIPTIONS_REQUEST or on the first SUBSCRIBE or last
+// UNSUBSCRIBE for a layer. It indicates which layers or associated_layers are
+// currently being subscribed to in the system.
+struct VmsSubscriptionsState {
+    int sequence_number;
+    std::vector<VmsLayer> layers;
+    std::vector<VmsAssociatedLayer> associated_layers;
+};
+
+struct VmsAvailabilityState {
+    int sequence_number;
+    std::vector<VmsAssociatedLayer> associated_layers;
+};
+
+// Creates a VehiclePropValue containing a message of type
+// VmsMessageType.SUBSCRIBE, specifying to the VMS service
+// which layer to subscribe to.
+std::unique_ptr<VehiclePropValue> createSubscribeMessage(const VmsLayer& layer);
+
+// Creates a VehiclePropValue containing a message of type
+// VmsMessageType.SUBSCRIBE_TO_PUBLISHER, specifying to the VMS service
+// which layer and publisher_id to subscribe to.
+std::unique_ptr<VehiclePropValue> createSubscribeToPublisherMessage(
+    const VmsLayerAndPublisher& layer);
+
+// Creates a VehiclePropValue containing a message of type
+// VmsMessageType.UNSUBSCRIBE, specifying to the VMS service
+// which layer to unsubscribe from.
+std::unique_ptr<VehiclePropValue> createUnsubscribeMessage(const VmsLayer& layer);
+
+// Creates a VehiclePropValue containing a message of type
+// VmsMessageType.UNSUBSCRIBE_TO_PUBLISHER, specifying to the VMS service
+// which layer and publisher_id to unsubscribe from.
+std::unique_ptr<VehiclePropValue> createUnsubscribeToPublisherMessage(
+    const VmsLayerAndPublisher& layer);
+
+// Creates a VehiclePropValue containing a message of type
+// VmsMessageType.OFFERING, specifying to the VMS service which layers are being
+// offered and their dependencies, if any.
+std::unique_ptr<VehiclePropValue> createOfferingMessage(
+    const std::vector<VmsLayerOffering>& offering);
+
+// Creates a VehiclePropValue containing a message of type
+// VmsMessageType.AVAILABILITY_REQUEST.
+std::unique_ptr<VehiclePropValue> createAvailabilityRequest();
+
+// Creates a VehiclePropValue containing a message of type
+// VmsMessageType.AVAILABILITY_REQUEST.
+std::unique_ptr<VehiclePropValue> createSubscriptionsRequest();
+
+// Creates a VehiclePropValue containing a message of type VmsMessageType.DATA.
+// Returns a nullptr if the byte string in bytes is empty.
+//
+// For example, to build a VehiclePropMessage containing a proto, the caller
+// should convert the proto to a byte string using the SerializeToString proto
+// API, then use this inteface to build the VehicleProperty.
+std::unique_ptr<VehiclePropValue> createDataMessage(const std::string& bytes);
+
+// Returns true if the VehiclePropValue pointed to by value contains a valid Vms
+// message, i.e. the VehicleProperty, VehicleArea, and VmsMessageType are all
+// valid. Note: If the VmsMessageType enum is extended, this function will
+// return false for any new message types added.
+bool isValidVmsMessage(const VehiclePropValue& value);
+
+// Returns the message type. Expects that the VehiclePropValue contains a valid
+// Vms message, as verified by isValidVmsMessage.
+VmsMessageType parseMessageType(const VehiclePropValue& value);
+
+// Constructs a string byte array from a message of type VmsMessageType.DATA.
+// Returns an empty string if the message type doesn't match or if the
+// VehiclePropValue does not contain a byte array.
+//
+// A proto message can then be constructed by passing the result of this
+// function to ParseFromString.
+std::string parseData(const VehiclePropValue& value);
+
+// TODO(aditin): Need to implement additional parsing functions per message
+// type.
+
+}  // namespace vms
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
+
+#endif  // android_hardware_automotive_vehicle_V2_0_VmsUtils_H_
diff --git a/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
new file mode 100644
index 0000000..abf425f
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/src/VmsUtils.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VmsUtils.h"
+
+#include <common/include/vhal_v2_0/VehicleUtils.h>
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace vms {
+
+static constexpr int kMessageIndex = toInt(VmsBaseMessageIntegerValuesIndex::MESSAGE_TYPE);
+static constexpr int kMessageTypeSize = 1;
+static constexpr int kLayerNumberSize = 1;
+static constexpr int kLayerSize = 3;
+static constexpr int kLayerAndPublisherSize = 4;
+
+// TODO(aditin): We should extend the VmsMessageType enum to include a first and
+// last, which would prevent breakages in this API. However, for all of the
+// functions in this module, we only need to guarantee that the message type is
+// between SUBSCRIBE and DATA.
+static constexpr int kFirstMessageType = toInt(VmsMessageType::SUBSCRIBE);
+static constexpr int kLastMessageType = toInt(VmsMessageType::DATA);
+
+std::unique_ptr<VehiclePropValue> createBaseVmsMessage(size_t message_size) {
+    auto result = createVehiclePropValue(VehiclePropertyType::INT32, message_size);
+    result->prop = toInt(VehicleProperty::VEHICLE_MAP_SERVICE);
+    result->areaId = toInt(VehicleArea::GLOBAL);
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createSubscribeMessage(const VmsLayer& layer) {
+    auto result = createBaseVmsMessage(kMessageTypeSize + kLayerSize);
+    result->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::SUBSCRIBE), layer.type,
+                                                  layer.subtype, layer.version};
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createSubscribeToPublisherMessage(
+    const VmsLayerAndPublisher& layer_publisher) {
+    auto result = createBaseVmsMessage(kMessageTypeSize + kLayerAndPublisherSize);
+    result->value.int32Values = hidl_vec<int32_t>{
+        toInt(VmsMessageType::SUBSCRIBE_TO_PUBLISHER), layer_publisher.layer.type,
+        layer_publisher.layer.subtype, layer_publisher.layer.version, layer_publisher.publisher_id};
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createUnsubscribeMessage(const VmsLayer& layer) {
+    auto result = createBaseVmsMessage(kMessageTypeSize + kLayerSize);
+    result->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::UNSUBSCRIBE), layer.type,
+                                                  layer.subtype, layer.version};
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createUnsubscribeToPublisherMessage(
+    const VmsLayerAndPublisher& layer_publisher) {
+    auto result = createBaseVmsMessage(kMessageTypeSize + kLayerAndPublisherSize);
+    result->value.int32Values = hidl_vec<int32_t>{
+        toInt(VmsMessageType::UNSUBSCRIBE_TO_PUBLISHER), layer_publisher.layer.type,
+        layer_publisher.layer.subtype, layer_publisher.layer.version, layer_publisher.publisher_id};
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createOfferingMessage(
+    const std::vector<VmsLayerOffering>& offering) {
+    int message_size = kMessageTypeSize + kLayerNumberSize;
+    for (const auto& offer : offering) {
+        message_size += kLayerNumberSize + (1 + offer.dependencies.size()) * kLayerSize;
+    }
+    auto result = createBaseVmsMessage(message_size);
+
+    std::vector<int32_t> offers = {toInt(VmsMessageType::OFFERING),
+                                   static_cast<int>(offering.size())};
+    for (const auto& offer : offering) {
+        std::vector<int32_t> layer_vector = {offer.layer.type, offer.layer.subtype,
+                                             offer.layer.version,
+                                             static_cast<int32_t>(offer.dependencies.size())};
+        for (const auto& dependency : offer.dependencies) {
+            std::vector<int32_t> dependency_layer = {dependency.type, dependency.subtype,
+                                                     dependency.version};
+            layer_vector.insert(layer_vector.end(), dependency_layer.begin(),
+                                dependency_layer.end());
+        }
+        offers.insert(offers.end(), layer_vector.begin(), layer_vector.end());
+    }
+    result->value.int32Values = offers;
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createAvailabilityRequest() {
+    auto result = createBaseVmsMessage(kMessageTypeSize);
+    result->value.int32Values = hidl_vec<int32_t>{
+        toInt(VmsMessageType::AVAILABILITY_REQUEST),
+    };
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createSubscriptionsRequest() {
+    auto result = createBaseVmsMessage(kMessageTypeSize);
+    result->value.int32Values = hidl_vec<int32_t>{
+        toInt(VmsMessageType::SUBSCRIPTIONS_REQUEST),
+    };
+    return result;
+}
+
+std::unique_ptr<VehiclePropValue> createDataMessage(const std::string& bytes) {
+    auto result = createBaseVmsMessage(kMessageTypeSize);
+    result->value.int32Values = hidl_vec<int32_t>{toInt(VmsMessageType::DATA)};
+    result->value.bytes = std::vector<uint8_t>(bytes.begin(), bytes.end());
+    return result;
+}
+
+bool verifyPropertyAndArea(const VehiclePropValue& value) {
+    return (value.prop == toInt(VehicleProperty::VEHICLE_MAP_SERVICE) &&
+            value.areaId == toInt(VehicleArea::GLOBAL));
+}
+
+bool verifyMessageType(const VehiclePropValue& value) {
+    return (value.value.int32Values.size() > 0 &&
+            value.value.int32Values[kMessageIndex] >= kFirstMessageType &&
+            value.value.int32Values[kMessageIndex] <= kLastMessageType);
+}
+
+bool isValidVmsMessage(const VehiclePropValue& value) {
+    return (verifyPropertyAndArea(value) && verifyMessageType(value));
+}
+
+VmsMessageType parseMessageType(const VehiclePropValue& value) {
+    return static_cast<VmsMessageType>(value.value.int32Values[kMessageIndex]);
+}
+
+std::string parseData(const VehiclePropValue& value) {
+    if (isValidVmsMessage(value) && parseMessageType(value) == VmsMessageType::DATA &&
+        value.value.bytes.size() > 0) {
+        return std::string(value.value.bytes.begin(), value.value.bytes.end());
+    } else {
+        return std::string();
+    }
+}
+
+}  // namespace vms
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
new file mode 100644
index 0000000..c102ce8
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/VmsUtils_test.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <gtest/gtest.h>
+
+#include "VehicleHalTestUtils.h"
+#include "vhal_v2_0/VmsUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+namespace vms {
+
+namespace {
+
+TEST(VmsUtilsTest, subscribeMessage) {
+    VmsLayer layer(1, 0, 2);
+    auto message = createSubscribeMessage(layer);
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
+    EXPECT_EQ(message->value.int32Values.size(), 0x4ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::SUBSCRIBE);
+
+    // Layer
+    EXPECT_EQ(message->value.int32Values[1], 1);
+    EXPECT_EQ(message->value.int32Values[2], 0);
+    EXPECT_EQ(message->value.int32Values[3], 2);
+}
+
+TEST(VmsUtilsTest, unsubscribeMessage) {
+    VmsLayer layer(1, 0, 2);
+    auto message = createUnsubscribeMessage(layer);
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
+    EXPECT_EQ(message->value.int32Values.size(), 0x4ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::UNSUBSCRIBE);
+
+    // Layer
+    EXPECT_EQ(message->value.int32Values[1], 1);
+    EXPECT_EQ(message->value.int32Values[2], 0);
+    EXPECT_EQ(message->value.int32Values[3], 2);
+}
+
+TEST(VmsUtilsTest, singleOfferingMessage) {
+    std::vector<VmsLayerOffering> offering = {VmsLayerOffering(VmsLayer(1, 0, 2))};
+    auto message = createOfferingMessage(offering);
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
+    EXPECT_EQ(message->value.int32Values.size(), 0x6ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::OFFERING);
+
+    // Number of layer offerings
+    EXPECT_EQ(message->value.int32Values[1], 1);
+
+    // Layer
+    EXPECT_EQ(message->value.int32Values[2], 1);
+    EXPECT_EQ(message->value.int32Values[3], 0);
+    EXPECT_EQ(message->value.int32Values[4], 2);
+
+    // Number of dependencies
+    EXPECT_EQ(message->value.int32Values[5], 0);
+}
+
+TEST(VmsUtilsTest, offeringWithDependencies) {
+    VmsLayer layer(1, 0, 2);
+    std::vector<VmsLayer> dependencies = {VmsLayer(2, 0, 2)};
+    std::vector<VmsLayerOffering> offering = {VmsLayerOffering(layer, dependencies)};
+    auto message = createOfferingMessage(offering);
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
+    EXPECT_EQ(message->value.int32Values.size(), 0x9ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::OFFERING);
+
+    // Number of layer offerings
+    EXPECT_EQ(message->value.int32Values[1], 1);
+
+    // Layer
+    EXPECT_EQ(message->value.int32Values[2], 1);
+    EXPECT_EQ(message->value.int32Values[3], 0);
+    EXPECT_EQ(message->value.int32Values[4], 2);
+
+    // Number of dependencies
+    EXPECT_EQ(message->value.int32Values[5], 1);
+
+    // Dependency 1
+    EXPECT_EQ(message->value.int32Values[6], 2);
+    EXPECT_EQ(message->value.int32Values[7], 0);
+    EXPECT_EQ(message->value.int32Values[8], 2);
+}
+
+TEST(VmsUtilsTest, availabilityMessage) {
+    auto message = createAvailabilityRequest();
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
+    EXPECT_EQ(message->value.int32Values.size(), 0x1ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::AVAILABILITY_REQUEST);
+}
+
+TEST(VmsUtilsTest, subscriptionsMessage) {
+    auto message = createSubscriptionsRequest();
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
+    EXPECT_EQ(message->value.int32Values.size(), 0x1ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::SUBSCRIPTIONS_REQUEST);
+}
+
+TEST(VmsUtilsTest, dataMessage) {
+    std::string bytes = "aaa";
+    auto message = createDataMessage(bytes);
+    ASSERT_NE(message, nullptr);
+    EXPECT_TRUE(isValidVmsMessage(*message));
+    EXPECT_EQ(message->prop, toInt(VehicleProperty::VEHICLE_MAP_SERVICE));
+    EXPECT_EQ(message->areaId, toInt(VehicleArea::GLOBAL));
+    EXPECT_EQ(message->value.int32Values.size(), 0x1ul);
+    EXPECT_EQ(parseMessageType(*message), VmsMessageType::DATA);
+    EXPECT_EQ(message->value.bytes.size(), bytes.size());
+    EXPECT_EQ(memcmp(message->value.bytes.data(), bytes.data(), bytes.size()), 0);
+}
+
+TEST(VmsUtilsTest, emptyMessageInvalid) {
+    VehiclePropValue empty_prop;
+    EXPECT_FALSE(isValidVmsMessage(empty_prop));
+}
+
+TEST(VmsUtilsTest, invalidMessageType) {
+    VmsLayer layer(1, 0, 2);
+    auto message = createSubscribeMessage(layer);
+    message->value.int32Values[0] = 0;
+
+    EXPECT_FALSE(isValidVmsMessage(*message));
+}
+
+TEST(VmsUtilsTest, parseDataMessage) {
+    std::string bytes = "aaa";
+    auto message = createDataMessage(bytes);
+    auto data_str = parseData(*message);
+    ASSERT_FALSE(data_str.empty());
+    EXPECT_EQ(data_str, bytes);
+}
+
+TEST(VmsUtilsTest, parseInvalidDataMessage) {
+    VmsLayer layer(1, 0, 2);
+    auto message = createSubscribeMessage(layer);
+    auto data_str = parseData(*message);
+    EXPECT_TRUE(data_str.empty());
+}
+
+}  // namespace
+
+}  // namespace vms
+}  // namespace V2_0
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 8e1b164..7e42781 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -906,346 +906,6 @@
         | VehicleArea:GLOBAL),
 
     /**
-     * Represents audio focus state of Android side. Note that car's audio
-     * module must own audio focus and grant audio focus to Android side when
-     * requested by Android side. The focus has both per stream characteristics
-     * and global characteristics.
-     *
-     * Focus request (get of this property) must take the following form with indices defined
-     * by VehicleAudioFocusIndex:
-     *   int32Values[0]: VehicleAudioFocusRequest type
-     *   int32Values[1]: bit flags of streams requested by this focus request.
-     *                   There can be up to 32 streams.
-     *   int32Values[2]: External focus state flags. For request, only flag like
-     *                   VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG or
-     *                   VehicleAudioExtFocusFlag#MUTE_MEDIA_FLAG can be
-     *                   used.
-     *                   VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG is for case
-     *                   like radio where android side app still needs to hold
-     *                   focus but playback is done outside Android.
-     *                   VehicleAudioExtFocusFlag#MUTE_MEDIA_FLAG is for
-     *                   muting media channel including radio.
-     *                   VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG can be set
-     *                   even if android side releases focus (request type
-     *                   REQUEST_RELEASE). In that case, audio module must
-     *                   maintain mute state until user's explicit action to
-     *                   play some media.
-     *   int32Values[3]: Audio contexts wishing to be active. Use combination of
-     *                   flags from VehicleAudioContextFlag.
-     *                   This can be used as a hint to adjust audio policy or
-     *                   other policy decision.
-     *                   Note that there can be multiple context active at the
-     *                   same time. And android can send the same focus request
-     *                   type gain due to change in audio contexts.
-     * Note that each focus request can request multiple streams that is
-     * expected to be used for the current request. But focus request itself
-     * is global behavior as GAIN or GAIN_TRANSIENT expects all sounds played
-     * by car's audio module to stop. Note that stream already allocated to
-     * android before this focus request must not be affected by focus
-     * request.
-     *
-     * Focus response (set and subscription callback for this property) must
-     * take the following form with indices defined by VehicleAudioFocusIndex:
-     *   int32Values[0]: VehicleAudioFocusState type
-     *   int32Values[1]: bit flags of streams allowed.
-     *   int32Values[2]: External focus state: bit flags of currently active
-     *                   audio focus in car side (outside Android). Active
-     *                   audio focus does not necessarily mean currently
-     *                   playing, but represents the state of having focus or
-     *                   waiting for focus (pause state).
-     *                   One or combination of flags from
-     *                   VehicleAudioExtFocusFlag.
-     *                   0 means no active audio focus holder outside Android.
-     *                   The state must have following values for each
-     *                   VehicleAudioFocusState:
-     *                   GAIN: VehicleAudioExtFocusFlag#PLAY_ONLY_FLAG
-     *                       when radio is active in Android side. Otherwise,
-     *                       VehicleAudioExtFocusFlag#NONE_FLAG.
-     *                   GAIN_TRANSIENT: Can be
-     *                       VehicleAudioExtFocusFlag#PERMANENT_FLAG or
-     *                       VehicleAudioExtFocusFlag#TRANSIENT_FLAG if android
-     *                       side has requested
-     *                       REQUEST_GAIN_TRANSIENT_MAY_DUCK and car side is
-     *                       ducking. Otherwise
-     *                       VehicleAudioExtFocusFlag#NONE_FLAG.
-     *                   LOSS: VehicleAudioExtFocusFlag#NONE_FLAG when no focus
-     *                       is active in car side.
-     *                       VehicleAudioExtFocusFlag#PERMANENT_FLAG when car
-     *                       side is playing something permanent.
-     *                   LOSS_TRANSIENT: must always be
-     *                       VehicleAudioExtFocusFlag#PERMANENT_FLAG
-     *   int32Values[3]: Audio context(s) allowed to be active. When responding positively to a
-     *                   focus request from Android, the request's original context must be
-     *                   repeated here. When taking focus away, or denying a request, the
-     *                   rejected or stopped context would have its corresponding bit cleared.
-     *
-     * A focus response must be sent per each focus request even if there is
-     * no change in focus state. This can happen in case like focus request
-     * only involving context change where android side still needs matching
-     * focus response to confirm that audio module has made necessary changes.
-     *
-     * If car does not support AUDIO_FOCUS, focus is assumed to be granted
-     * always.
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     */
-    AUDIO_FOCUS = (
-        0x0900
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * A property to allow external component to control audio focus. Depending on
-     * H/W architecture, audio HAL may need to control audio focus while vehicle
-     * HAL is still interacting with upper layer. In such case, audio HAL may set
-     * this property and vehicle HAL may use this property value to decide
-     * response sent through AUDIO_FOCUS property.
-     * Data format is the same as AUDIO_FOCUS property.
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     */
-    AUDIO_FOCUS_EXT_SYNC = (
-        0x0910
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Property to control audio volume of each audio context.
-     *
-     * VehiclePropConfig
-     *   configArray[0] : bit flags of all supported audio contexts from
-     *                    VehicleAudioContextFlag. If this is 0, audio volume
-     *                    is controlled per physical stream.
-     *   configArray[1] : flags defined in VehicleAudioVolumeCapabilityFlag to
-     *                    represent audio module's capability.
-     *   configArray[2..3] : reserved
-     *   configArray[4..N+3] : maximum values for each audio context, where N is
-     *                         the number of audio contexts provided in
-     *                         configArray[0], minimum value is always 0 which
-     *                         indicates mute state.
-     *
-     * Data type looks like:
-     *   int32Values[0] : audio context as defined in VehicleAudioContextFlag.
-     *                    If only physical stream is supported
-     *                    (configArray[0] == 0), this must represent physical
-     *                    stream number.
-     *   int32Values[1] : volume level, valid range is 0 (mute) to max level
-     *                    defined in the config.
-     *   int32Values[2] : One of VehicleAudioVolumeState.
-     *
-     * HAL implementations must check the incoming value of audio context
-     * field in get call to return the right volume.
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     * @config_flags all audio contexts supported.
-     */
-    AUDIO_VOLUME = (
-        0x0901
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Property to allow audio volume sync from external components like audio HAL.
-     * Some vehicle HAL implementation may get volume control from audio HAL and in such
-     * case, setting AUDIO_VOLUME_EXT_SYNC property may trigger event in AUDIO_VOLUME property.
-     * Data format for this property is the same as AUDIO_VOLUME property.
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     * @config_flags all audio contexts supported.
-     */
-    AUDIO_VOLUME_EXT_SYNC = (
-        0x0911
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Property for handling volume limit set by user. This limits maximum
-     * volume that can be set per each context or physical stream.
-     *
-     * VehiclePropConfig
-     *   configArray[0] : bit flags of all supported audio contexts. If this is
-     *                    0, audio volume is controlled per physical stream.
-     *   configArray[1] : flags defined in VehicleAudioVolumeCapabilityFlag
-     *                    to represent audio module's capability.
-     *
-     * Data type looks like:
-     *   int32Values[0] : audio context as defined in VehicleAudioContextFlag.
-     *                    If only physical stream is supported
-     *                    (configArray[0] == 0), this must represent physical
-     *                    stream number.
-     *   int32Values[1] : maximum volume set to the stream. If there is no
-     *                    restriction, this value must be equal to
-     *                    AUDIO_VOLUME's max value.
-     *
-     * If car does not support this feature, this property must not be
-     * populated by HAL.
-     * HAL implementations must check the incoming value of audio context
-     * field in get call to return the right volume.
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     * @config_flags all audio contexts supported.
-     */
-    AUDIO_VOLUME_LIMIT = (
-        0x0902
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Property to share audio routing policy of android side. This property is
-     * set at startup to pass audio policy in android side down to
-     * vehicle HAL and car audio module.
-     *
-     *   int32Values[0] : audio stream where the audio for the application
-     *                    context must be routed by default. Note that this is
-     *                    the default setting from system, but each app may
-     *                    still use different audio stream for whatever reason.
-     *   int32Values[1] : All audio contexts that must be sent through the
-     *                     physical stream. Flag is defined in
-     *                     VehicleAudioContextFlag.
-
-     * Setting of this property must be done for all available physical streams
-     * based on audio H/W variant information acquired from AUDIO_HW_VARIANT
-     * property.
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:WRITE
-     */
-    AUDIO_ROUTING_POLICY = (
-        0x0903
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Property to return audio H/W variant type used in this car. This is a
-     * zero based index into the set of audio routing policies defined in
-     * R.array.audioRoutingPolicy on CarService, which  may be overlaid to
-     * support multiple variants. If this property does not exist, the default
-     * audio policy must be used.
-     *
-     * @change_mode VehiclePropertyChangeMode:STATIC
-     * @access VehiclePropertyAccess:READ
-     * @config_flags Additional info on audio H/W. Must use
-     *               VehicleAudioHwVariantConfigFlag for this.
-     */
-    AUDIO_HW_VARIANT = (
-        0x0904
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Property to pass hint on external audio routing. When android side
-     * request focus with VehicleAudioExtFocusflag, this
-     * property must be set before setting AUDIO_FOCUS property as a hint for
-     * external audio source routing.
-     * Note that setting this property alone must not trigger any change.
-     * Audio routing must be changed only when AUDIO_FOCUS property is set.
-     * Note that this property allows passing custom value as long as it is
-     * defined in VehiclePropConfig#configString. This allows supporting
-     * non-standard routing options through this property.
-     * It is recommended to use separate name space for custom property to
-     * prevent conflict in future android releases.
-     * Enabling each external routing option is done by enabling each bit flag
-     * for the routing.
-     * This property can support up to 128 external routings.
-     * To give full flexibility, there is no standard definition for each bit
-     * flag and assigning each bit flag to specific routing type is decided by
-     * VehiclePropConfig#configString.  VehiclePropConfig#configString has
-     * format of each entry separated by ',' and each entry has format of
-     * bitFlagPositon:typeString[:physicalStreamNumber].
-     *  bitFlagPosition: represents which bit flag will be set to enable this
-     *    routing. 0 means LSB in int32Values[0]. 31 will be MSB in
-     *    int32Values[0]. 127 will MSB in int32Values[3].
-     *  typeString: string representation of external routing. Some types are
-     *    already defined in AUDIO_EXT_ROUTING_SOURCE_* and use them first
-     *    before adding something custom. Applications will find each routing
-     *    using this string.
-     *  physicalStreamNumber: This part is optional and represents physical
-     *    stream to android which will be disabled when this routing is enabled.
-     *    If not specified, this routing must not affect physical streams to
-     *    android.
-     * As an example, let's assume a system with two physical streams, 0 for
-     * media and 1 for nav guidance. And let's assume external routing option
-     * of am fm radio, external navigation guidance, satellite radio, and one
-     * custom. Let's assume that radio and satellite replaces physical stream 0
-     * and external navigation replaces physical stream 1. And bit flag will be
-     * assigned in the order listed above. This configuration will look like
-     * this in config_string:
-     *  "0:RADIO_AM_FM:0,1:EXT_NAV_GUIDANCE:1,2:RADIO_SATELLITE:0,3:com.test.SOMETHING_CUSTOM"
-     * When android requests RADIO_AM_FM, int32Values[0] will be set to 0x1.
-     * When android requests RADIO_SATELLITE + EXT_NAV_GUIDANCE, int32Values[0]
-     * will be set to 0x2|0x4.
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     * @config_string List of all avaiable external source in the system.
-     */
-    AUDIO_EXT_ROUTING_HINT = (
-        0x0905
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Represents state of audio stream. Audio HAL should set this when a stream is starting or
-     * ending. Car service can request focus for audio played without focus. If such feature
-     * is not required, this property does not need to be implemented.
-     * Car service only monitors setting of this property. It is up to each vehicle HAL
-     * implementation to add necessary action but default implementation will be doing nothing on
-     * this propery's set from audio HAL.
-     * Actual streaming of data should be done only after getting focus for the given stream from
-     * car audio module. Focus can be already granted when stream is started. Focus state can be
-     * monitored by monitoring AUDIO_FOCUS property. If car does not support
-     * AUDIO_FOCUS property, there is no need to monitor focus as focus is assumed to be
-     * granted always.
-     * Data has the following format:
-     *   int32_array[0] : vehicle_audio_stream_state, 0: stopped, 1: started
-     *   int32_array[1] : stream number like 0, 1, 2, ...
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     */
-    AUDIO_STREAM_STATE  = (
-        0x0906
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:INT32_VEC
-        | VehicleArea:GLOBAL),
-
-    /**
-     * Property to control car specific audio parameters. Each parameter is defined as string key-
-     * value pair.
-     * set and event notification can pass multiple parameters using the
-     * following format:
-     *   key1=value1;key2=value2;...
-     * get call can request multiple parameters using the following format:
-     *   key1;key2;...
-     * Response for get call has the same format as set.
-     *
-     * VehiclePropConfig
-     *   configString: give list of all supported keys with ; as separator. For example:
-     *     key1;key2;...
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     */
-    AUDIO_PARAMETERS = (
-        0x907
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:STRING
-        | VehicleArea:GLOBAL),
-
-    /**
      * Property to control power state of application processor
      *
      * It is assumed that AP's power state is controller by separate power
@@ -2243,256 +1903,6 @@
     VEHICLE_RADIO_PRESET_MIN_VALUE = 1,
 };
 
-enum VehicleAudioFocusRequest : int32_t {
-    REQUEST_GAIN = 0x1,
-    REQUEST_GAIN_TRANSIENT = 0x2,
-    REQUEST_GAIN_TRANSIENT_MAY_DUCK = 0x3,
-    /**
-     * This is for the case where android side plays sound like UI feedback
-     * and car side does not need to duck existing playback as long as
-     * requested stream is available.
-     */
-    REQUEST_GAIN_TRANSIENT_NO_DUCK = 0x4,
-    REQUEST_RELEASE = 0x5,
-};
-
-enum VehicleAudioFocusState : int32_t {
-    /**
-     * Android side has permanent focus and can play allowed streams.
-     */
-    STATE_GAIN = 0x1,
-
-    /**
-     * Android side has transient focus and can play allowed streams.
-     */
-    STATE_GAIN_TRANSIENT = 0x2,
-
-    /**
-     * Car audio module is playing guidance kind of sound outside Android.
-     * Android side can still play through allowed streams with ducking.
-     */
-    STATE_LOSS_TRANSIENT_CAN_DUCK = 0x3,
-
-    /**
-     * Car audio module is playing transient sound outside Android. Android side
-     * must stop playing any sounds.
-     */
-    STATE_LOSS_TRANSIENT = 0x4,
-
-    /**
-     * Android side has lost focus and cannot play any sound.
-     */
-    STATE_LOSS = 0x5,
-
-    /**
-     * car audio module is playing safety critical sound, and Android side cannot
-     * request focus until the current state is finished. car audio module
-     * restore it to the previous state when it can allow Android to play.
-     */
-    STATE_LOSS_TRANSIENT_EXLCUSIVE = 0x6,
-};
-
-/**
- * Flags to represent multiple streams by combining these.
- */
-enum VehicleAudioStreamFlag : int32_t {
-    STREAM0_FLAG = (0x1 << 0),
-    STREAM1_FLAG = (0x1 << 1),
-    STREAM2_FLAG = (0x1 << 2),
-};
-
-/**
- * Represents stream number (always 0 to N -1 where N is max number of streams).
- * Can be used for audio related property expecting one stream.
- */
-enum VehicleAudioStream : int32_t {
-    STREAM0 = 0,
-    STREAM1 = 1,
-};
-
-/**
- * Flag to represent external focus state (outside Android).
- */
-enum VehicleAudioExtFocusFlag : int32_t {
-    /**
-     * No external focus holder.
-     */
-    NONE_FLAG = 0x0,
-
-    /**
-     * Car side (outside Android) has component holding GAIN kind of focus state.
-     */
-    PERMANENT_FLAG = 0x1,
-
-    /**
-     * Car side (outside Android) has component holding GAIN_TRANSIENT kind of
-     * focus state.
-     */
-    TRANSIENT_FLAG = 0x2,
-
-    /**
-     * Car side is expected to play something while focus is held by Android side.
-     * One example can be radio attached in car side. But Android's radio app
-     * still must have focus, and Android side must be in GAIN state, but
-     * media stream will not be allocated to Android side and car side can play
-     * radio any time while this flag is active.
-     */
-    PLAY_ONLY_FLAG = 0x4,
-
-    /**
-     * Car side must mute any media including radio. This can be used with any
-     * focus request including GAIN* and RELEASE.
-     */
-    MUTE_MEDIA_FLAG = 0x8,
-};
-
-/**
- * Index in int32Values for VehicleProperty#AUDIO_FOCUS property.
- */
-enum VehicleAudioFocusIndex : int32_t {
-    FOCUS = 0,
-    STREAMS = 1,
-    EXTERNAL_FOCUS_STATE = 2,
-    AUDIO_CONTEXTS = 3,
-};
-
-/**
- * Flags to tell the current audio context.
- */
-enum VehicleAudioContextFlag : int32_t {
-    /** Music playback is currently active. */
-    MUSIC_FLAG = 0x1,
-
-    /** Navigation is currently running. */
-    NAVIGATION_FLAG = 0x2,
-
-    /** Voice command session is currently running. */
-    VOICE_COMMAND_FLAG = 0x4,
-
-    /** Voice call is currently active. */
-    CALL_FLAG = 0x8,
-
-    /**
-     * Alarm is active.
-     * This must be only used in VehicleProperty#AUDIO_ROUTING_POLICY.
-     */
-    ALARM_FLAG = 0x10,
-
-    /**
-     * Notification sound is active.
-     * This must be only used in VehicleProperty#AUDIO_ROUTING_POLICY.
-     */
-    NOTIFICATION_FLAG = 0x20,
-
-    /**
-     * Context unknown. Only used for VehicleProperty#AUDIO_ROUTING_POLICY to
-     * represent default stream for unknown contents.
-     */
-    UNKNOWN_FLAG = 0x40,
-
-    /** Safety alert / warning is played. */
-    SAFETY_ALERT_FLAG = 0x80,
-
-    /** CD / DVD kind of audio is played */
-    CD_ROM_FLAG = 0x100,
-
-    /** Aux audio input is played */
-    AUX_AUDIO_FLAG = 0x200,
-
-    /** system sound like UI feedback */
-    SYSTEM_SOUND_FLAG = 0x400,
-
-    /** Radio is played */
-    RADIO_FLAG = 0x800,
-
-    /** Ext source is played. This is for tagging generic ext sources. */
-    EXT_SOURCE_FLAG = 0x1000,
-
-    /** The phone ring tone is played */
-    RINGTONE_FLAG = 0x2000
-};
-
-/**
- * flags to represent capability of audio volume property.
- * used in configArray[1] of VehiclePropConfig.
- */
-enum VehicleAudioVolumeCapabilityFlag : int32_t {
-    /**
-     * External audio module or vehicle hal has persistent storage to keep the
-     * volume level. When this is set, the audio volume level for each context
-     * will be retrieved from the property when the system starts up.
-     * And external audio module is also expected to adjust volume automatically
-     * whenever there is an audio context change.
-     * When this flag is not set, android side will assume that there is no
-     * persistent storage and the value stored in the android side will be used to
-     * initialize the volume level, and android side will set volume level
-     * of each physical stream whenever there is an audio context change.
-     */
-    PERSISTENT_STORAGE = 0x1,
-
-    /**
-     * [DEPRECATED]
-     * When this flag is set, the H/W can support only single master volume for
-     * all streams. There is no way to set volume level differently for each stream
-     * or context.
-     */
-    MASTER_VOLUME_ONLY = 0x2,
-};
-
-/**
- * enum to represent audio volume state.
- */
-enum VehicleAudioVolumeState : int32_t {
-    STATE_OK = 0,
-
-    /**
-     * Audio volume has reached volume limit set in
-     * VehicleProperty#AUDIO_VOLUME_LIMIT and user's request to increase volume
-     * further is not allowed.
-     */
-    STATE_LIMIT_REACHED = 1,
-};
-
-/**
- * Index in int32Values for VehicleProperty#AUDIO_VOLUME property.
- */
-enum VehicleAudioVolumeIndex : int32_t {
-    STREAM = 0,
-    VOLUME = 1,
-    STATE = 2,
-};
-
-/**
- * Index in int32Values for VehicleProperty#AUDIO_VOLUME_LIMIT property.
- */
-enum VehicleAudioVolumeLimitIndex : int32_t {
-    STREAM = 0,
-    MAX_VOLUME = 1,
-};
-
-/**
- * Index in int32Values for VehicleProperty#AUDIO_ROUTING_POLICY property.
- */
-enum VehicleAudioRoutingPolicyIndex : int32_t {
-    STREAM = 0,
-    CONTEXTS = 1,
-};
-
-/**
- * Flag to be used in VehiclePropConfig#configFlags for
- * VehicleProperty#AUDIO_HW_VARIANT.
- */
-enum VehicleAudioHwVariantConfigFlag : int32_t {
-  /**
-   * Flag to tell that radio is internal to android and radio must
-   * be treated like other android stream like media.
-   * When this flag is not set or AUDIO_HW_VARIANT does not exist,
-   * radio is treated as external module. This may affect audio focus
-   * handling as well.
-   */
-  INTERNAL_RADIO_FLAG = 0x1,
-};
-
 enum VehicleApPowerStateConfigFlag : int32_t /* NOTE: type is guessed */ {
     /**
      * AP can enter deep sleep state. If not set, AP will always shutdown from
diff --git a/broadcastradio/2.0/Android.bp b/broadcastradio/2.0/Android.bp
index 7409005..2434fdc 100644
--- a/broadcastradio/2.0/Android.bp
+++ b/broadcastradio/2.0/Android.bp
@@ -8,7 +8,7 @@
     },
     srcs: [
         "types.hal",
-        "IAnnouncementObserver.hal",
+        "IAnnouncementListener.hal",
         "IBroadcastRadio.hal",
         "ICloseHandle.hal",
         "ITunerCallback.hal",
diff --git a/broadcastradio/2.0/IAnnouncementObserver.hal b/broadcastradio/2.0/IAnnouncementListener.hal
similarity index 85%
rename from broadcastradio/2.0/IAnnouncementObserver.hal
rename to broadcastradio/2.0/IAnnouncementListener.hal
index c91e29a..1b4960c 100644
--- a/broadcastradio/2.0/IAnnouncementObserver.hal
+++ b/broadcastradio/2.0/IAnnouncementListener.hal
@@ -16,11 +16,11 @@
 package android.hardware.broadcastradio@2.0;
 
 /**
- * Callback interface for announcement observer.
+ * Callback interface for announcement listener.
  *
- * For typical configuration, the observer is a broadcast radio service.
+ * For typical configuration, the listener is a broadcast radio service.
  */
-interface IAnnouncementObserver {
+interface IAnnouncementListener {
     /**
      * Called whenever announcement list has changed.
      *
diff --git a/broadcastradio/2.0/IBroadcastRadio.hal b/broadcastradio/2.0/IBroadcastRadio.hal
index 7578f44..bedc362 100644
--- a/broadcastradio/2.0/IBroadcastRadio.hal
+++ b/broadcastradio/2.0/IBroadcastRadio.hal
@@ -15,7 +15,7 @@
 
 package android.hardware.broadcastradio@2.0;
 
-import IAnnouncementObserver;
+import IAnnouncementListener;
 import ICloseHandle;
 import ITunerCallback;
 import ITunerSession;
@@ -104,7 +104,7 @@
     getImage(uint32_t id) generates (vec<uint8_t> image);
 
     /**
-     * Registers announcement observer.
+     * Registers announcement listener.
      *
      * If there is at least one observer registered, HAL implementation must
      * notify about announcements even if no sessions are active.
@@ -113,15 +113,15 @@
      * automatically.
      *
      * @param enabled The list of announcement types to watch for.
-     * @param cb The callback interface.
+     * @param listener The listener interface.
      * @return result OK in case of success.
      *                NOT_SUPPORTED if the tuner doesn't support announcements.
      * @return closeHandle A handle to unregister observer,
      *                     nullptr if result was not OK.
      */
-    registerAnnouncementObserver(
+    registerAnnouncementListener(
             vec<AnnouncementType> enabled,
-            IAnnouncementObserver cb
+            IAnnouncementListener listener
         ) generates (
             Result result,
             ICloseHandle closeHandle
diff --git a/broadcastradio/2.0/default/BroadcastRadio.cpp b/broadcastradio/2.0/default/BroadcastRadio.cpp
index d16aaff..aa5afad 100644
--- a/broadcastradio/2.0/default/BroadcastRadio.cpp
+++ b/broadcastradio/2.0/default/BroadcastRadio.cpp
@@ -141,9 +141,9 @@
     return {};
 }
 
-Return<void> BroadcastRadio::registerAnnouncementObserver(
-    const hidl_vec<AnnouncementType>& enabled, const sp<IAnnouncementObserver>& /* cb */,
-    registerAnnouncementObserver_cb _hidl_cb) {
+Return<void> BroadcastRadio::registerAnnouncementListener(
+    const hidl_vec<AnnouncementType>& enabled, const sp<IAnnouncementListener>& /* listener */,
+    registerAnnouncementListener_cb _hidl_cb) {
     ALOGV("%s(%s)", __func__, toString(enabled).c_str());
 
     _hidl_cb(Result::NOT_SUPPORTED, nullptr);
diff --git a/broadcastradio/2.0/default/BroadcastRadio.h b/broadcastradio/2.0/default/BroadcastRadio.h
index 7904946..8c14d9e 100644
--- a/broadcastradio/2.0/default/BroadcastRadio.h
+++ b/broadcastradio/2.0/default/BroadcastRadio.h
@@ -36,9 +36,9 @@
     Return<void> getDabRegionConfig(getDabRegionConfig_cb _hidl_cb);
     Return<void> openSession(const sp<ITunerCallback>& callback, openSession_cb _hidl_cb) override;
     Return<void> getImage(uint32_t id, getImage_cb _hidl_cb);
-    Return<void> registerAnnouncementObserver(const hidl_vec<AnnouncementType>& enabled,
-                                              const sp<IAnnouncementObserver>& cb,
-                                              registerAnnouncementObserver_cb _hidl_cb);
+    Return<void> registerAnnouncementListener(const hidl_vec<AnnouncementType>& enabled,
+                                              const sp<IAnnouncementListener>& listener,
+                                              registerAnnouncementListener_cb _hidl_cb);
 
     std::reference_wrapper<const VirtualRadio> mVirtualRadio;
     Properties mProperties;
diff --git a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
index 1111478..8d9d622 100644
--- a/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
+++ b/broadcastradio/2.0/vts/functional/VtsHalBroadcastradioV2_0TargetTest.cpp
@@ -90,7 +90,7 @@
     utils::ProgramInfoSet mProgramList;
 };
 
-struct AnnouncementObserverMock : public IAnnouncementObserver {
+struct AnnouncementListenerMock : public IAnnouncementListener {
     MOCK_METHOD1(onListUpdated, Return<void>(const hidl_vec<Announcement>&));
 };
 
@@ -702,15 +702,15 @@
 }
 
 /**
- * Test announcement observer registration.
+ * Test announcement listener registration.
  *
  * Verifies that:
- *  - registerAnnouncementObserver either succeeds or returns NOT_SUPPORTED;
+ *  - registerAnnouncementListener either succeeds or returns NOT_SUPPORTED;
  *  - if it succeeds, it returns a valid close handle (which is a nullptr otherwise);
  *  - closing handle does not crash.
  */
-TEST_F(BroadcastRadioHalTest, AnnouncementObserverRegistration) {
-    sp<AnnouncementObserverMock> observer = new AnnouncementObserverMock();
+TEST_F(BroadcastRadioHalTest, AnnouncementListenerRegistration) {
+    sp<AnnouncementListenerMock> listener = new AnnouncementListenerMock();
 
     Result halResult = Result::UNKNOWN_ERROR;
     sp<ICloseHandle> closeHandle = nullptr;
@@ -720,7 +720,7 @@
     };
 
     auto hidlResult =
-        mModule->registerAnnouncementObserver({AnnouncementType::EMERGENCY}, observer, cb);
+        mModule->registerAnnouncementListener({AnnouncementType::EMERGENCY}, listener, cb);
     ASSERT_TRUE(hidlResult.isOk());
 
     if (halResult == Result::NOT_SUPPORTED) {
diff --git a/camera/device/3.2/default/CameraDevice.cpp b/camera/device/3.2/default/CameraDevice.cpp
index 295ee32..dfbb976 100644
--- a/camera/device/3.2/default/CameraDevice.cpp
+++ b/camera/device/3.2/default/CameraDevice.cpp
@@ -40,9 +40,11 @@
         mCameraDeviceNames(cameraDeviceNames) {
     mCameraIdInt = atoi(mCameraId.c_str());
     // Should not reach here as provider also validate ID
-    if (mCameraIdInt < 0 || mCameraIdInt >= module->getNumberOfCameras()) {
+    if (mCameraIdInt < 0) {
         ALOGE("%s: Invalid camera id: %s", __FUNCTION__, mCameraId.c_str());
         mInitFail = true;
+    } else if (mCameraIdInt >= mModule->getNumberOfCameras()) {
+        ALOGI("%s: Adding a new camera id: %s", __FUNCTION__, mCameraId.c_str());
     }
 
     mDeviceVersion = mModule->getDeviceVersion(mCameraIdInt);
diff --git a/camera/metadata/3.3/types.hal b/camera/metadata/3.3/types.hal
index 09e0a9c..5c01e35 100644
--- a/camera/metadata/3.3/types.hal
+++ b/camera/metadata/3.3/types.hal
@@ -53,6 +53,15 @@
 
     ANDROID_LENS_END_3_3,
 
+    /** android.request.availableSessionKeys [static, int32[], ndk_public]
+     *
+     * <p>A subset of the available request keys that the camera device
+     * can pass as part of the capture session initialization.</p>
+     */
+    ANDROID_REQUEST_AVAILABLE_SESSION_KEYS = android.hardware.camera.metadata@3.2::CameraMetadataTag:ANDROID_REQUEST_END,
+
+    ANDROID_REQUEST_END_3_3,
+
     /** android.info.version [static, byte, public]
      *
      * <p>A short string for manufacturer version information about the camera device, such as
diff --git a/camera/provider/2.4/default/CameraProvider.cpp b/camera/provider/2.4/default/CameraProvider.cpp
index ed974a5..e9588a7 100644
--- a/camera/provider/2.4/default/CameraProvider.cpp
+++ b/camera/provider/2.4/default/CameraProvider.cpp
@@ -66,6 +66,46 @@
 using ::android::hardware::camera::common::V1_0::CameraMetadataType;
 using ::android::hardware::camera::common::V1_0::Status;
 
+void CameraProvider::addDeviceNames(int camera_id, CameraDeviceStatus status, bool cam_new)
+{
+    char cameraId[kMaxCameraIdLen];
+    snprintf(cameraId, sizeof(cameraId), "%d", camera_id);
+    std::string cameraIdStr(cameraId);
+
+    mCameraIds.add(cameraIdStr);
+
+    // initialize mCameraDeviceNames and mOpenLegacySupported
+    mOpenLegacySupported[cameraIdStr] = false;
+    int deviceVersion = mModule->getDeviceVersion(camera_id);
+    auto deviceNamePair = std::make_pair(cameraIdStr,
+                                         getHidlDeviceName(cameraIdStr, deviceVersion));
+    mCameraDeviceNames.add(deviceNamePair);
+    if (cam_new) {
+        mCallbacks->cameraDeviceStatusChange(deviceNamePair.second, status);
+    }
+    if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_2 &&
+            mModule->isOpenLegacyDefined()) {
+        // try open_legacy to see if it actually works
+        struct hw_device_t* halDev = nullptr;
+        int ret = mModule->openLegacy(cameraId, CAMERA_DEVICE_API_VERSION_1_0, &halDev);
+        if (ret == 0) {
+            mOpenLegacySupported[cameraIdStr] = true;
+            halDev->close(halDev);
+            deviceNamePair = std::make_pair(cameraIdStr,
+                            getHidlDeviceName(cameraIdStr, CAMERA_DEVICE_API_VERSION_1_0));
+            mCameraDeviceNames.add(deviceNamePair);
+            if (cam_new) {
+                mCallbacks->cameraDeviceStatusChange(deviceNamePair.second, status);
+            }
+        } else if (ret == -EBUSY || ret == -EUSERS) {
+            // Looks like this provider instance is not initialized during
+            // system startup and there are other camera users already.
+            // Not a good sign but not fatal.
+            ALOGW("%s: open_legacy try failed!", __FUNCTION__);
+        }
+    }
+}
+
 /**
  * static callback forwarding methods from HAL to instance
  */
@@ -75,6 +115,7 @@
         int new_status) {
     CameraProvider* cp = const_cast<CameraProvider*>(
             static_cast<const CameraProvider*>(callbacks));
+    bool found = false;
 
     if (cp == nullptr) {
         ALOGE("%s: callback ops is null", __FUNCTION__);
@@ -92,8 +133,13 @@
             if (cameraIdStr.compare(deviceNamePair.first) == 0) {
                 cp->mCallbacks->cameraDeviceStatusChange(
                         deviceNamePair.second, status);
+                found = true;
             }
         }
+
+        if (!found) {
+            cp->addDeviceNames(camera_id, status, true);
+        }
     }
 }
 
@@ -251,32 +297,8 @@
         snprintf(cameraId, sizeof(cameraId), "%d", i);
         std::string cameraIdStr(cameraId);
         mCameraStatusMap[cameraIdStr] = CAMERA_DEVICE_STATUS_PRESENT;
-        mCameraIds.add(cameraIdStr);
 
-        // initialize mCameraDeviceNames and mOpenLegacySupported
-        mOpenLegacySupported[cameraIdStr] = false;
-        int deviceVersion = mModule->getDeviceVersion(i);
-        mCameraDeviceNames.add(
-                std::make_pair(cameraIdStr,
-                               getHidlDeviceName(cameraIdStr, deviceVersion)));
-        if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_2 &&
-                mModule->isOpenLegacyDefined()) {
-            // try open_legacy to see if it actually works
-            struct hw_device_t* halDev = nullptr;
-            int ret = mModule->openLegacy(cameraId, CAMERA_DEVICE_API_VERSION_1_0, &halDev);
-            if (ret == 0) {
-                mOpenLegacySupported[cameraIdStr] = true;
-                halDev->close(halDev);
-                mCameraDeviceNames.add(
-                        std::make_pair(cameraIdStr,
-                                getHidlDeviceName(cameraIdStr, CAMERA_DEVICE_API_VERSION_1_0)));
-            } else if (ret == -EBUSY || ret == -EUSERS) {
-                // Looks like this provider instance is not initialized during
-                // system startup and there are other camera users already.
-                // Not a good sign but not fatal.
-                ALOGW("%s: open_legacy try failed!", __FUNCTION__);
-            }
-        }
+        addDeviceNames(i);
     }
 
     return false; // mInitFailed
diff --git a/camera/provider/2.4/default/CameraProvider.h b/camera/provider/2.4/default/CameraProvider.h
index 4980711..2cf251e 100644
--- a/camera/provider/2.4/default/CameraProvider.h
+++ b/camera/provider/2.4/default/CameraProvider.h
@@ -112,6 +112,9 @@
         const struct camera_module_callbacks* callbacks,
         const char* camera_id,
         int new_status);
+
+    void addDeviceNames(int camera_id, CameraDeviceStatus status = CameraDeviceStatus::PRESENT,
+                        bool cam_new = false);
 };
 
 extern "C" ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name);
diff --git a/compatibility_matrices/Android.mk b/compatibility_matrices/Android.mk
new file mode 100644
index 0000000..2a01480
--- /dev/null
+++ b/compatibility_matrices/Android.mk
@@ -0,0 +1,138 @@
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+# Install all compatibility_matrix.*.xml to /system/etc/vintf
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := framework_compatibility_matrix.legacy.xml
+LOCAL_MODULE_STEM := compatibility_matrix.legacy.xml
+LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/vintf
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := framework_compatibility_matrix.1.xml
+LOCAL_MODULE_STEM := compatibility_matrix.1.xml
+LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/vintf
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := framework_compatibility_matrix.2.xml
+LOCAL_MODULE_STEM := compatibility_matrix.2.xml
+LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/vintf
+include $(BUILD_PREBUILT)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := framework_compatibility_matrix.current.xml
+LOCAL_MODULE_STEM := compatibility_matrix.current.xml
+LOCAL_SRC_FILES := $(LOCAL_MODULE_STEM)
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/vintf
+include $(BUILD_PREBUILT)
+
+# Framework Compatibility Matrix without HALs
+include $(CLEAR_VARS)
+LOCAL_MODULE        := framework_compatibility_matrix.empty.xml
+LOCAL_MODULE_STEM   := compatibility_matrix.empty.xml
+LOCAL_MODULE_CLASS  := ETC
+LOCAL_MODULE_PATH   := $(TARGET_OUT)/etc/vintf
+
+GEN := $(local-generated-sources-dir)/$(LOCAL_MODULE_STEM)
+
+$(GEN): PRIVATE_FLAGS :=
+
+ifeq (true,$(BOARD_AVB_ENABLE))
+$(GEN): $(AVBTOOL)
+# INTERNAL_AVB_SYSTEM_SIGNING_ARGS consists of BOARD_AVB_SYSTEM_KEY_PATH and
+# BOARD_AVB_SYSTEM_ALGORITHM. We should add the dependency of key path, which
+# is a file, here.
+$(GEN): $(BOARD_AVB_SYSTEM_KEY_PATH)
+# Use deferred assignment (=) instead of immediate assignment (:=).
+# Otherwise, cannot get INTERNAL_AVB_SYSTEM_SIGNING_ARGS.
+$(GEN): FRAMEWORK_VBMETA_VERSION = $$("$(AVBTOOL)" add_hashtree_footer \
+                           --print_required_libavb_version \
+                           $(INTERNAL_AVB_SYSTEM_SIGNING_ARGS) \
+                           $(BOARD_AVB_SYSTEM_ADD_HASHTREE_FOOTER_ARGS))
+else
+$(GEN): FRAMEWORK_VBMETA_VERSION := 0.0
+endif
+
+# Specify kernel versions that the current framework supports. These versions,
+# along with kernel configurations, are written to the framework compatibility
+# matrix.
+$(GEN): KERNEL_VERSIONS := 3.18 4.4 4.9
+
+# Specify the location of android-base*.cfg files.
+$(GEN): KERNEL_CONFIG_DATA := kernel/configs
+
+$(GEN): $(foreach version,$(KERNEL_VERSIONS),\
+	$(wildcard $(KERNEL_CONFIG_DATA)/android-$(version)/android-base*.cfg))
+$(GEN): PRIVATE_FLAGS += $(foreach version,$(KERNEL_VERSIONS),\
+	--kernel=$(version):$(call normalize-path-list,\
+		$(wildcard $(KERNEL_CONFIG_DATA)/android-$(version)/android-base*.cfg)))
+
+$(GEN): $(LOCAL_PATH)/compatibility_matrix.empty.xml $(HOST_OUT_EXECUTABLES)/assemble_vintf
+	POLICYVERS=$(POLICYVERS) \
+		BOARD_SEPOLICY_VERS=$(BOARD_SEPOLICY_VERS) \
+		FRAMEWORK_VBMETA_VERSION=$(FRAMEWORK_VBMETA_VERSION) \
+		$(HOST_OUT_EXECUTABLES)/assemble_vintf \
+		-i $< -o $@ $(PRIVATE_FLAGS)
+LOCAL_PREBUILT_MODULE_FILE := $(GEN)
+include $(BUILD_PREBUILT)
+
+# Framework Compatibility Matrix
+include $(CLEAR_VARS)
+LOCAL_MODULE        := framework_compatibility_matrix.xml
+LOCAL_MODULE_STEM   := compatibility_matrix.xml
+LOCAL_MODULE_CLASS  := ETC
+LOCAL_MODULE_PATH   := $(TARGET_OUT)
+
+LOCAL_REQUIRED_MODULES := \
+    framework_compatibility_matrix.legacy.xml \
+    framework_compatibility_matrix.1.xml \
+    framework_compatibility_matrix.2.xml \
+    framework_compatibility_matrix.current.xml \
+    framework_compatibility_matrix.empty.xml
+
+GEN := $(local-generated-sources-dir)/compatibility_matrix.xml
+
+$(GEN): PRIVATE_FLAGS :=
+
+ifdef BUILT_VENDOR_MANIFEST
+$(GEN): $(BUILT_VENDOR_MANIFEST)
+$(GEN): PRIVATE_FLAGS += -c "$(BUILT_VENDOR_MANIFEST)"
+endif
+
+MATRIX_SRC_FILES := $(call module-installed-files,$(LOCAL_REQUIRED_MODULES))
+$(GEN): PRIVATE_MATRIX_SRC_FILES := $(MATRIX_SRC_FILES)
+$(GEN): $(MATRIX_SRC_FILES) $(HOST_OUT_EXECUTABLES)/assemble_vintf
+	PRODUCT_ENFORCE_VINTF_MANIFEST=$(PRODUCT_ENFORCE_VINTF_MANIFEST) \
+		$(HOST_OUT_EXECUTABLES)/assemble_vintf \
+		-i $(call normalize-path-list,$(PRIVATE_MATRIX_SRC_FILES)) \
+		-o $@ $(PRIVATE_FLAGS)
+
+MATRIX_SRC_FILES :=
+
+LOCAL_PREBUILT_MODULE_FILE := $(GEN)
+include $(BUILD_PREBUILT)
+BUILT_SYSTEM_COMPATIBILITY_MATRIX := $(LOCAL_BUILT_MODULE)
diff --git a/compatibility_matrix.1.xml b/compatibility_matrices/compatibility_matrix.1.xml
similarity index 100%
rename from compatibility_matrix.1.xml
rename to compatibility_matrices/compatibility_matrix.1.xml
diff --git a/compatibility_matrix.2.xml b/compatibility_matrices/compatibility_matrix.2.xml
similarity index 100%
rename from compatibility_matrix.2.xml
rename to compatibility_matrices/compatibility_matrix.2.xml
diff --git a/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
similarity index 97%
rename from compatibility_matrix.current.xml
rename to compatibility_matrices/compatibility_matrix.current.xml
index 9287d67..c444dde 100644
--- a/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -16,6 +16,14 @@
         </interface>
     </hal>
     <hal format="hidl" optional="true">
+        <name>android.hardware.authsecret</name>
+        <version>1.0</version>
+        <interface>
+            <name>IAuthSecret</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+    <hal format="hidl" optional="true">
         <name>android.hardware.automotive.evs</name>
         <version>1.0</version>
         <interface>
@@ -221,7 +229,7 @@
     </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.power</name>
-        <version>1.0-1</version>
+        <version>1.0-2</version>
         <interface>
             <name>IPower</name>
             <instance>default</instance>
diff --git a/compatibility_matrices/compatibility_matrix.empty.xml b/compatibility_matrices/compatibility_matrix.empty.xml
new file mode 100644
index 0000000..216f5f1
--- /dev/null
+++ b/compatibility_matrices/compatibility_matrix.empty.xml
@@ -0,0 +1 @@
+<compatibility-matrix version="1.0" type="framework" />
diff --git a/compatibility_matrix.legacy.xml b/compatibility_matrices/compatibility_matrix.legacy.xml
similarity index 100%
rename from compatibility_matrix.legacy.xml
rename to compatibility_matrices/compatibility_matrix.legacy.xml
diff --git a/graphics/allocator/2.0/default/Android.bp b/graphics/allocator/2.0/default/Android.bp
index 9968f41..ed2ecbb 100644
--- a/graphics/allocator/2.0/default/Android.bp
+++ b/graphics/allocator/2.0/default/Android.bp
@@ -1,10 +1,15 @@
 cc_library_shared {
     name: "android.hardware.graphics.allocator@2.0-impl",
     defaults: ["hidl_defaults"],
-    proprietary: true,
+    vendor: true,
     relative_install_path: "hw",
-    srcs: ["Gralloc.cpp", "Gralloc0Allocator.cpp", "Gralloc1Allocator.cpp"],
-    cppflags: ["-Wall", "-Wextra"],
+    srcs: ["passthrough.cpp"],
+    static_libs: [
+        "android.hardware.graphics.allocator@2.0-passthrough",
+    ],
+    header_libs: [
+        "android.hardware.graphics.allocator@2.0-hal",
+    ],
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
         "libbase",
@@ -15,9 +20,6 @@
         "liblog",
         "libutils",
     ],
-    header_libs: [
-        "libgrallocmapperincludes",
-    ],
 }
 
 cc_binary {
@@ -36,13 +38,3 @@
         "libutils",
     ],
 }
-
-cc_library_static {
-    name: "libgralloc1-adapter",
-    defaults: ["hidl_defaults"],
-    srcs: ["gralloc1-adapter.cpp", "Gralloc1On0Adapter.cpp"],
-    include_dirs: ["system/core/libsync/include"],
-    cflags: ["-Wall", "-Wextra"],
-    export_include_dirs: ["."],
-    whole_static_libs: ["libgrallocusage"],
-}
diff --git a/graphics/allocator/2.0/default/Gralloc.cpp b/graphics/allocator/2.0/default/Gralloc.cpp
deleted file mode 100644
index 273d3f5..0000000
--- a/graphics/allocator/2.0/default/Gralloc.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "GrallocPassthrough"
-
-#include "Gralloc.h"
-#include "Gralloc0Allocator.h"
-#include "Gralloc1Allocator.h"
-
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace allocator {
-namespace V2_0 {
-namespace implementation {
-
-IAllocator* HIDL_FETCH_IAllocator(const char* /* name */) {
-    const hw_module_t* module = nullptr;
-    int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
-    if (err) {
-        ALOGE("failed to get gralloc module");
-        return nullptr;
-    }
-
-    uint8_t major = (module->module_api_version >> 8) & 0xff;
-    switch (major) {
-        case 1:
-            return new Gralloc1Allocator(module);
-        case 0:
-            return new Gralloc0Allocator(module);
-        default:
-            ALOGE("unknown gralloc module major version %d", major);
-            return nullptr;
-    }
-}
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace allocator
-} // namespace graphics
-} // namespace hardware
-} // namespace android
diff --git a/graphics/allocator/2.0/default/Gralloc.h b/graphics/allocator/2.0/default/Gralloc.h
deleted file mode 100644
index c79eeaa..0000000
--- a/graphics/allocator/2.0/default/Gralloc.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC_H
-#define ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC_H
-
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace allocator {
-namespace V2_0 {
-namespace implementation {
-
-extern "C" IAllocator* HIDL_FETCH_IAllocator(const char* name);
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace allocator
-} // namespace graphics
-} // namespace hardware
-} // namespace android
-
-#endif // ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC_H
diff --git a/graphics/allocator/2.0/default/Gralloc0Allocator.cpp b/graphics/allocator/2.0/default/Gralloc0Allocator.cpp
deleted file mode 100644
index 3b62bb3..0000000
--- a/graphics/allocator/2.0/default/Gralloc0Allocator.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Gralloc0Allocator"
-
-#include "Gralloc0Allocator.h"
-#include "GrallocBufferDescriptor.h"
-
-#include <vector>
-
-#include <string.h>
-
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace allocator {
-namespace V2_0 {
-namespace implementation {
-
-using android::hardware::graphics::mapper::V2_0::implementation::
-    grallocDecodeBufferDescriptor;
-
-Gralloc0Allocator::Gralloc0Allocator(const hw_module_t* module) {
-    int result = gralloc_open(module, &mDevice);
-    if (result) {
-        LOG_ALWAYS_FATAL("failed to open gralloc0 device: %s",
-                         strerror(-result));
-    }
-}
-
-Gralloc0Allocator::~Gralloc0Allocator() {
-    gralloc_close(mDevice);
-}
-
-Return<void> Gralloc0Allocator::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
-    char buf[4096] = {};
-    if (mDevice->dump) {
-        mDevice->dump(mDevice, buf, sizeof(buf));
-        buf[sizeof(buf) - 1] = '\0';
-    }
-
-    hidl_cb(hidl_string(buf));
-
-    return Void();
-}
-
-Return<void> Gralloc0Allocator::allocate(const BufferDescriptor& descriptor,
-                                         uint32_t count, allocate_cb hidl_cb) {
-    IMapper::BufferDescriptorInfo descriptorInfo;
-    if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
-        hidl_cb(Error::BAD_DESCRIPTOR, 0, hidl_vec<hidl_handle>());
-        return Void();
-    }
-
-    Error error = Error::NONE;
-    uint32_t stride = 0;
-    std::vector<hidl_handle> buffers;
-    buffers.reserve(count);
-
-    // allocate the buffers
-    for (uint32_t i = 0; i < count; i++) {
-        buffer_handle_t tmpBuffer;
-        uint32_t tmpStride;
-        error = allocateOne(descriptorInfo, &tmpBuffer, &tmpStride);
-        if (error != Error::NONE) {
-            break;
-        }
-
-        if (stride == 0) {
-            stride = tmpStride;
-        } else if (stride != tmpStride) {
-            // non-uniform strides
-            mDevice->free(mDevice, tmpBuffer);
-            stride = 0;
-            error = Error::UNSUPPORTED;
-            break;
-        }
-
-        buffers.emplace_back(hidl_handle(tmpBuffer));
-    }
-
-    // return the buffers
-    hidl_vec<hidl_handle> hidl_buffers;
-    if (error == Error::NONE) {
-        hidl_buffers.setToExternal(buffers.data(), buffers.size());
-    }
-    hidl_cb(error, stride, hidl_buffers);
-
-    // free the buffers
-    for (const auto& buffer : buffers) {
-        mDevice->free(mDevice, buffer.getNativeHandle());
-    }
-
-    return Void();
-}
-
-Error Gralloc0Allocator::allocateOne(const IMapper::BufferDescriptorInfo& info,
-                                     buffer_handle_t* outBuffer,
-                                     uint32_t* outStride) {
-    if (info.layerCount > 1 || (info.usage >> 32) != 0) {
-        return Error::BAD_VALUE;
-    }
-
-    buffer_handle_t buffer = nullptr;
-    int stride = 0;
-    int result = mDevice->alloc(mDevice, info.width, info.height,
-                                static_cast<int>(info.format), info.usage,
-                                &buffer, &stride);
-    if (result) {
-        switch (result) {
-            case -EINVAL:
-                return Error::BAD_VALUE;
-            default:
-                return Error::NO_RESOURCES;
-        }
-    }
-
-    *outBuffer = buffer;
-    *outStride = stride;
-
-    return Error::NONE;
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace allocator
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
diff --git a/graphics/allocator/2.0/default/Gralloc0Allocator.h b/graphics/allocator/2.0/default/Gralloc0Allocator.h
deleted file mode 100644
index 0e90527..0000000
--- a/graphics/allocator/2.0/default/Gralloc0Allocator.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC0ALLOCATOR_H
-#define ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC0ALLOCATOR_H
-
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <hardware/gralloc.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace allocator {
-namespace V2_0 {
-namespace implementation {
-
-using android::hardware::graphics::mapper::V2_0::IMapper;
-using android::hardware::graphics::mapper::V2_0::BufferDescriptor;
-using android::hardware::graphics::mapper::V2_0::Error;
-
-class Gralloc0Allocator : public IAllocator {
-   public:
-    Gralloc0Allocator(const hw_module_t* module);
-    virtual ~Gralloc0Allocator();
-
-    // IAllocator interface
-    Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
-    Return<void> allocate(const BufferDescriptor& descriptor, uint32_t count,
-                          allocate_cb hidl_cb) override;
-
-   private:
-    Error allocateOne(const IMapper::BufferDescriptorInfo& info,
-                      buffer_handle_t* outBuffer, uint32_t* outStride);
-
-    alloc_device_t* mDevice;
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace allocator
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC0ALLOCATOR_H
diff --git a/graphics/allocator/2.0/default/Gralloc1Allocator.cpp b/graphics/allocator/2.0/default/Gralloc1Allocator.cpp
deleted file mode 100644
index 6cbb791..0000000
--- a/graphics/allocator/2.0/default/Gralloc1Allocator.cpp
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "Gralloc1Allocator"
-
-#include "Gralloc1Allocator.h"
-#include "GrallocBufferDescriptor.h"
-
-#include <vector>
-
-#include <string.h>
-
-#include <log/log.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace allocator {
-namespace V2_0 {
-namespace implementation {
-
-using android::hardware::graphics::common::V1_0::BufferUsage;
-using android::hardware::graphics::mapper::V2_0::implementation::
-    grallocDecodeBufferDescriptor;
-
-Gralloc1Allocator::Gralloc1Allocator(const hw_module_t* module)
-    : mDevice(nullptr), mCapabilities(), mDispatch() {
-    int result = gralloc1_open(module, &mDevice);
-    if (result) {
-        LOG_ALWAYS_FATAL("failed to open gralloc1 device: %s",
-                         strerror(-result));
-    }
-
-    initCapabilities();
-    initDispatch();
-}
-
-Gralloc1Allocator::~Gralloc1Allocator() {
-    gralloc1_close(mDevice);
-}
-
-void Gralloc1Allocator::initCapabilities() {
-    uint32_t count = 0;
-    mDevice->getCapabilities(mDevice, &count, nullptr);
-
-    std::vector<int32_t> capabilities(count);
-    mDevice->getCapabilities(mDevice, &count, capabilities.data());
-    capabilities.resize(count);
-
-    for (auto capability : capabilities) {
-        if (capability == GRALLOC1_CAPABILITY_LAYERED_BUFFERS) {
-            mCapabilities.layeredBuffers = true;
-            break;
-        }
-    }
-}
-
-template <typename T>
-void Gralloc1Allocator::initDispatch(gralloc1_function_descriptor_t desc,
-                                     T* outPfn) {
-    auto pfn = mDevice->getFunction(mDevice, desc);
-    if (!pfn) {
-        LOG_ALWAYS_FATAL("failed to get gralloc1 function %d", desc);
-    }
-
-    *outPfn = reinterpret_cast<T>(pfn);
-}
-
-void Gralloc1Allocator::initDispatch() {
-    initDispatch(GRALLOC1_FUNCTION_DUMP, &mDispatch.dump);
-    initDispatch(GRALLOC1_FUNCTION_CREATE_DESCRIPTOR,
-                 &mDispatch.createDescriptor);
-    initDispatch(GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR,
-                 &mDispatch.destroyDescriptor);
-    initDispatch(GRALLOC1_FUNCTION_SET_DIMENSIONS, &mDispatch.setDimensions);
-    initDispatch(GRALLOC1_FUNCTION_SET_FORMAT, &mDispatch.setFormat);
-    if (mCapabilities.layeredBuffers) {
-        initDispatch(GRALLOC1_FUNCTION_SET_LAYER_COUNT,
-                     &mDispatch.setLayerCount);
-    }
-    initDispatch(GRALLOC1_FUNCTION_SET_CONSUMER_USAGE,
-                 &mDispatch.setConsumerUsage);
-    initDispatch(GRALLOC1_FUNCTION_SET_PRODUCER_USAGE,
-                 &mDispatch.setProducerUsage);
-    initDispatch(GRALLOC1_FUNCTION_GET_STRIDE, &mDispatch.getStride);
-    initDispatch(GRALLOC1_FUNCTION_ALLOCATE, &mDispatch.allocate);
-    initDispatch(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release);
-}
-
-Return<void> Gralloc1Allocator::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
-    uint32_t len = 0;
-    mDispatch.dump(mDevice, &len, nullptr);
-
-    std::vector<char> buf(len + 1);
-    mDispatch.dump(mDevice, &len, buf.data());
-    buf.resize(len + 1);
-    buf[len] = '\0';
-
-    hidl_string reply;
-    reply.setToExternal(buf.data(), len);
-    hidl_cb(reply);
-
-    return Void();
-}
-
-Return<void> Gralloc1Allocator::allocate(const BufferDescriptor& descriptor,
-                                         uint32_t count, allocate_cb hidl_cb) {
-    IMapper::BufferDescriptorInfo descriptorInfo;
-    if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
-        hidl_cb(Error::BAD_DESCRIPTOR, 0, hidl_vec<hidl_handle>());
-        return Void();
-    }
-
-    gralloc1_buffer_descriptor_t desc;
-    Error error = createDescriptor(descriptorInfo, &desc);
-    if (error != Error::NONE) {
-        hidl_cb(error, 0, hidl_vec<hidl_handle>());
-        return Void();
-    }
-
-    uint32_t stride = 0;
-    std::vector<hidl_handle> buffers;
-    buffers.reserve(count);
-
-    // allocate the buffers
-    for (uint32_t i = 0; i < count; i++) {
-        buffer_handle_t tmpBuffer;
-        uint32_t tmpStride;
-        error = allocateOne(desc, &tmpBuffer, &tmpStride);
-        if (error != Error::NONE) {
-            break;
-        }
-
-        if (stride == 0) {
-            stride = tmpStride;
-        } else if (stride != tmpStride) {
-            // non-uniform strides
-            mDispatch.release(mDevice, tmpBuffer);
-            stride = 0;
-            error = Error::UNSUPPORTED;
-            break;
-        }
-
-        buffers.emplace_back(hidl_handle(tmpBuffer));
-    }
-
-    mDispatch.destroyDescriptor(mDevice, desc);
-
-    // return the buffers
-    hidl_vec<hidl_handle> hidl_buffers;
-    if (error == Error::NONE) {
-        hidl_buffers.setToExternal(buffers.data(), buffers.size());
-    }
-    hidl_cb(error, stride, hidl_buffers);
-
-    // free the buffers
-    for (const auto& buffer : buffers) {
-        mDispatch.release(mDevice, buffer.getNativeHandle());
-    }
-
-    return Void();
-}
-
-Error Gralloc1Allocator::toError(int32_t error) {
-    switch (error) {
-        case GRALLOC1_ERROR_NONE:
-            return Error::NONE;
-        case GRALLOC1_ERROR_BAD_DESCRIPTOR:
-            return Error::BAD_DESCRIPTOR;
-        case GRALLOC1_ERROR_BAD_HANDLE:
-            return Error::BAD_BUFFER;
-        case GRALLOC1_ERROR_BAD_VALUE:
-            return Error::BAD_VALUE;
-        case GRALLOC1_ERROR_NOT_SHARED:
-            return Error::NONE;  // this is fine
-        case GRALLOC1_ERROR_NO_RESOURCES:
-            return Error::NO_RESOURCES;
-        case GRALLOC1_ERROR_UNDEFINED:
-        case GRALLOC1_ERROR_UNSUPPORTED:
-        default:
-            return Error::UNSUPPORTED;
-    }
-}
-
-uint64_t Gralloc1Allocator::toProducerUsage(uint64_t usage) {
-    // this is potentially broken as we have no idea which private flags
-    // should be filtered out
-    uint64_t producerUsage =
-        usage &
-        ~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
-                               BufferUsage::GPU_DATA_BUFFER);
-
-    switch (usage & BufferUsage::CPU_WRITE_MASK) {
-        case static_cast<uint64_t>(BufferUsage::CPU_WRITE_RARELY):
-            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
-            break;
-        case static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN):
-            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN;
-            break;
-        default:
-            break;
-    }
-
-    switch (usage & BufferUsage::CPU_READ_MASK) {
-        case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
-            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ;
-            break;
-        case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
-            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN;
-            break;
-        default:
-            break;
-    }
-
-    // BufferUsage::GPU_DATA_BUFFER is always filtered out
-
-    return producerUsage;
-}
-
-uint64_t Gralloc1Allocator::toConsumerUsage(uint64_t usage) {
-    // this is potentially broken as we have no idea which private flags
-    // should be filtered out
-    uint64_t consumerUsage =
-        usage &
-        ~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
-                               BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::GPU_DATA_BUFFER);
-
-    switch (usage & BufferUsage::CPU_READ_MASK) {
-        case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
-            consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ;
-            break;
-        case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
-            consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN;
-            break;
-        default:
-            break;
-    }
-
-    // BufferUsage::SENSOR_DIRECT_DATA is always filtered out
-
-    if (usage & BufferUsage::GPU_DATA_BUFFER) {
-        consumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER;
-    }
-
-    return consumerUsage;
-}
-
-Error Gralloc1Allocator::createDescriptor(
-    const IMapper::BufferDescriptorInfo& info,
-    gralloc1_buffer_descriptor_t* outDescriptor) {
-    gralloc1_buffer_descriptor_t descriptor;
-
-    int32_t error = mDispatch.createDescriptor(mDevice, &descriptor);
-
-    if (error == GRALLOC1_ERROR_NONE) {
-        error = mDispatch.setDimensions(mDevice, descriptor, info.width,
-                                        info.height);
-    }
-    if (error == GRALLOC1_ERROR_NONE) {
-        error = mDispatch.setFormat(mDevice, descriptor,
-                                    static_cast<int32_t>(info.format));
-    }
-    if (error == GRALLOC1_ERROR_NONE) {
-        if (mCapabilities.layeredBuffers) {
-            error =
-                mDispatch.setLayerCount(mDevice, descriptor, info.layerCount);
-        } else if (info.layerCount > 1) {
-            error = GRALLOC1_ERROR_UNSUPPORTED;
-        }
-    }
-    if (error == GRALLOC1_ERROR_NONE) {
-        error = mDispatch.setProducerUsage(mDevice, descriptor,
-                                           toProducerUsage(info.usage));
-    }
-    if (error == GRALLOC1_ERROR_NONE) {
-        error = mDispatch.setConsumerUsage(mDevice, descriptor,
-                                           toConsumerUsage(info.usage));
-    }
-
-    if (error == GRALLOC1_ERROR_NONE) {
-        *outDescriptor = descriptor;
-    } else {
-        mDispatch.destroyDescriptor(mDevice, descriptor);
-    }
-
-    return toError(error);
-}
-
-Error Gralloc1Allocator::allocateOne(gralloc1_buffer_descriptor_t descriptor,
-                                     buffer_handle_t* outBuffer,
-                                     uint32_t* outStride) {
-    buffer_handle_t buffer = nullptr;
-    int32_t error = mDispatch.allocate(mDevice, 1, &descriptor, &buffer);
-    if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_NOT_SHARED) {
-        return toError(error);
-    }
-
-    uint32_t stride = 0;
-    error = mDispatch.getStride(mDevice, buffer, &stride);
-    if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_UNDEFINED) {
-        mDispatch.release(mDevice, buffer);
-        return toError(error);
-    }
-
-    *outBuffer = buffer;
-    *outStride = stride;
-
-    return Error::NONE;
-}
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace allocator
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
diff --git a/graphics/allocator/2.0/default/Gralloc1Allocator.h b/graphics/allocator/2.0/default/Gralloc1Allocator.h
deleted file mode 100644
index 7b5a966..0000000
--- a/graphics/allocator/2.0/default/Gralloc1Allocator.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC1ALLOCATOR_H
-#define ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC1ALLOCATOR_H
-
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-#include <hardware/gralloc1.h>
-
-namespace android {
-namespace hardware {
-namespace graphics {
-namespace allocator {
-namespace V2_0 {
-namespace implementation {
-
-using android::hardware::graphics::mapper::V2_0::IMapper;
-using android::hardware::graphics::mapper::V2_0::BufferDescriptor;
-using android::hardware::graphics::mapper::V2_0::Error;
-
-class Gralloc1Allocator : public IAllocator {
-   public:
-    Gralloc1Allocator(const hw_module_t* module);
-    virtual ~Gralloc1Allocator();
-
-    // IAllocator interface
-    Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
-    Return<void> allocate(const BufferDescriptor& descriptor, uint32_t count,
-                          allocate_cb hidl_cb) override;
-
-   private:
-    void initCapabilities();
-
-    template <typename T>
-    void initDispatch(gralloc1_function_descriptor_t desc, T* outPfn);
-    void initDispatch();
-
-    static Error toError(int32_t error);
-    static uint64_t toProducerUsage(uint64_t usage);
-    static uint64_t toConsumerUsage(uint64_t usage);
-
-    Error createDescriptor(const IMapper::BufferDescriptorInfo& info,
-                           gralloc1_buffer_descriptor_t* outDescriptor);
-    Error allocateOne(gralloc1_buffer_descriptor_t descriptor,
-                      buffer_handle_t* outBuffer, uint32_t* outStride);
-
-    gralloc1_device_t* mDevice;
-
-    struct {
-        bool layeredBuffers;
-    } mCapabilities;
-
-    struct {
-        GRALLOC1_PFN_DUMP dump;
-        GRALLOC1_PFN_CREATE_DESCRIPTOR createDescriptor;
-        GRALLOC1_PFN_DESTROY_DESCRIPTOR destroyDescriptor;
-        GRALLOC1_PFN_SET_DIMENSIONS setDimensions;
-        GRALLOC1_PFN_SET_FORMAT setFormat;
-        GRALLOC1_PFN_SET_LAYER_COUNT setLayerCount;
-        GRALLOC1_PFN_SET_CONSUMER_USAGE setConsumerUsage;
-        GRALLOC1_PFN_SET_PRODUCER_USAGE setProducerUsage;
-        GRALLOC1_PFN_GET_STRIDE getStride;
-        GRALLOC1_PFN_ALLOCATE allocate;
-        GRALLOC1_PFN_RELEASE release;
-    } mDispatch;
-};
-
-}  // namespace implementation
-}  // namespace V2_0
-}  // namespace allocator
-}  // namespace graphics
-}  // namespace hardware
-}  // namespace android
-
-#endif  // ANDROID_HARDWARE_GRAPHICS_ALLOCATOR_V2_0_GRALLOC1ALLOCATOR_H
diff --git a/graphics/allocator/2.0/default/passthrough.cpp b/graphics/allocator/2.0/default/passthrough.cpp
new file mode 100644
index 0000000..132cab3
--- /dev/null
+++ b/graphics/allocator/2.0/default/passthrough.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <allocator-passthrough/2.0/GrallocLoader.h>
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+
+using android::hardware::graphics::allocator::V2_0::IAllocator;
+using android::hardware::graphics::allocator::V2_0::passthrough::GrallocLoader;
+
+extern "C" IAllocator* HIDL_FETCH_IAllocator(const char* /* name */) {
+    return GrallocLoader::load();
+}
diff --git a/graphics/allocator/2.0/default/service.cpp b/graphics/allocator/2.0/default/service.cpp
index 99f462c..bc0539a 100644
--- a/graphics/allocator/2.0/default/service.cpp
+++ b/graphics/allocator/2.0/default/service.cpp
@@ -20,8 +20,8 @@
 
 #include <hidl/LegacySupport.h>
 
-using android::hardware::graphics::allocator::V2_0::IAllocator;
 using android::hardware::defaultPassthroughServiceImplementation;
+using android::hardware::graphics::allocator::V2_0::IAllocator;
 
 int main() {
     return defaultPassthroughServiceImplementation<IAllocator>(4);
diff --git a/graphics/allocator/2.0/utils/OWNERS b/graphics/allocator/2.0/utils/OWNERS
new file mode 100644
index 0000000..3aa5fa1
--- /dev/null
+++ b/graphics/allocator/2.0/utils/OWNERS
@@ -0,0 +1,4 @@
+# Graphics team
+jessehall@google.com
+olv@google.com
+stoza@google.com
diff --git a/graphics/allocator/2.0/utils/gralloc1-adapter/Android.bp b/graphics/allocator/2.0/utils/gralloc1-adapter/Android.bp
new file mode 100644
index 0000000..9cb53e3
--- /dev/null
+++ b/graphics/allocator/2.0/utils/gralloc1-adapter/Android.bp
@@ -0,0 +1,10 @@
+cc_library_static {
+    name: "libgralloc1-adapter",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    srcs: ["gralloc1-adapter.cpp", "Gralloc1On0Adapter.cpp"],
+    include_dirs: ["system/core/libsync/include"],
+    export_include_dirs: ["."],
+    whole_static_libs: ["libgrallocusage"],
+    shared_libs: ["libhardware", "liblog"],
+}
diff --git a/graphics/allocator/2.0/default/Gralloc1On0Adapter.cpp b/graphics/allocator/2.0/utils/gralloc1-adapter/Gralloc1On0Adapter.cpp
similarity index 99%
rename from graphics/allocator/2.0/default/Gralloc1On0Adapter.cpp
rename to graphics/allocator/2.0/utils/gralloc1-adapter/Gralloc1On0Adapter.cpp
index 041ce77..b7ed58c 100644
--- a/graphics/allocator/2.0/default/Gralloc1On0Adapter.cpp
+++ b/graphics/allocator/2.0/utils/gralloc1-adapter/Gralloc1On0Adapter.cpp
@@ -29,6 +29,7 @@
 #include <sync/sync.h>
 
 #include <inttypes.h>
+#include <unistd.h>
 
 template <typename PFN, typename T>
 static gralloc1_function_pointer_t asFP(T function)
diff --git a/graphics/allocator/2.0/default/Gralloc1On0Adapter.h b/graphics/allocator/2.0/utils/gralloc1-adapter/Gralloc1On0Adapter.h
similarity index 100%
rename from graphics/allocator/2.0/default/Gralloc1On0Adapter.h
rename to graphics/allocator/2.0/utils/gralloc1-adapter/Gralloc1On0Adapter.h
diff --git a/graphics/allocator/2.0/default/gralloc1-adapter.cpp b/graphics/allocator/2.0/utils/gralloc1-adapter/gralloc1-adapter.cpp
similarity index 100%
rename from graphics/allocator/2.0/default/gralloc1-adapter.cpp
rename to graphics/allocator/2.0/utils/gralloc1-adapter/gralloc1-adapter.cpp
diff --git a/graphics/allocator/2.0/default/gralloc1-adapter.h b/graphics/allocator/2.0/utils/gralloc1-adapter/gralloc1-adapter.h
similarity index 100%
rename from graphics/allocator/2.0/default/gralloc1-adapter.h
rename to graphics/allocator/2.0/utils/gralloc1-adapter/gralloc1-adapter.h
diff --git a/graphics/allocator/2.0/utils/hal/Android.bp b/graphics/allocator/2.0/utils/hal/Android.bp
new file mode 100644
index 0000000..ac642ce
--- /dev/null
+++ b/graphics/allocator/2.0/utils/hal/Android.bp
@@ -0,0 +1,14 @@
+cc_library_headers {
+    name: "android.hardware.graphics.allocator@2.0-hal",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    shared_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+    ],
+    export_include_dirs: ["include"],
+}
diff --git a/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/Allocator.h b/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/Allocator.h
new file mode 100644
index 0000000..2f3022e
--- /dev/null
+++ b/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/Allocator.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 "Allocator.h included without LOG_TAG"
+#endif
+
+#include <memory>
+
+#include <allocator-hal/2.0/AllocatorHal.h>
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace hal {
+
+using mapper::V2_0::BufferDescriptor;
+using mapper::V2_0::Error;
+
+namespace detail {
+
+// AllocatorImpl implements IAllocator on top of AllocatorHal
+template <typename IALLOCATOR, typename ALLOCATOR_HAL>
+class AllocatorImpl : public IALLOCATOR {
+   public:
+    bool init(std::unique_ptr<ALLOCATOR_HAL> hal) {
+        mHal = std::move(hal);
+        return true;
+    }
+
+    // IAllocator 2.0 interface
+    Return<void> dumpDebugInfo(IAllocator::dumpDebugInfo_cb hidl_cb) override {
+        hidl_cb(mHal->dumpDebugInfo());
+        return Void();
+    }
+
+    Return<void> allocate(const BufferDescriptor& descriptor, uint32_t count,
+                          IAllocator::allocate_cb hidl_cb) override {
+        uint32_t stride;
+        std::vector<const native_handle_t*> buffers;
+        Error error = mHal->allocateBuffers(descriptor, count, &stride, &buffers);
+        if (error != Error::NONE) {
+            hidl_cb(error, 0, hidl_vec<hidl_handle>());
+            return Void();
+        }
+
+        hidl_vec<hidl_handle> hidlBuffers(buffers.cbegin(), buffers.cend());
+        hidl_cb(Error::NONE, stride, hidlBuffers);
+
+        // free the local handles
+        mHal->freeBuffers(buffers);
+
+        return Void();
+    }
+
+   protected:
+    std::unique_ptr<ALLOCATOR_HAL> mHal;
+};
+
+}  // namespace detail
+
+using Allocator = detail::AllocatorImpl<IAllocator, AllocatorHal>;
+
+}  // namespace hal
+}  // namespace V2_0
+}  // namespace allocator
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/AllocatorHal.h b/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/AllocatorHal.h
new file mode 100644
index 0000000..dec377a
--- /dev/null
+++ b/graphics/allocator/2.0/utils/hal/include/allocator-hal/2.0/AllocatorHal.h
@@ -0,0 +1,56 @@
+/*
+ * 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 <string>
+#include <vector>
+
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace hal {
+
+using mapper::V2_0::BufferDescriptor;
+using mapper::V2_0::Error;
+
+class AllocatorHal {
+   public:
+    virtual ~AllocatorHal() = default;
+
+    // dump the debug information
+    virtual std::string dumpDebugInfo() = 0;
+
+    // allocate buffers
+    virtual Error allocateBuffers(const BufferDescriptor& descriptor, uint32_t count,
+                                  uint32_t* outStride,
+                                  std::vector<const native_handle_t*>* outBuffers) = 0;
+
+    // free buffers
+    virtual void freeBuffers(const std::vector<const native_handle_t*>& buffers) = 0;
+};
+
+}  // namespace hal
+}  // namespace V2_0
+}  // namespace allocator
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/allocator/2.0/utils/passthrough/Android.bp b/graphics/allocator/2.0/utils/passthrough/Android.bp
new file mode 100644
index 0000000..b956565
--- /dev/null
+++ b/graphics/allocator/2.0/utils/passthrough/Android.bp
@@ -0,0 +1,29 @@
+cc_library_static {
+    name: "android.hardware.graphics.allocator@2.0-passthrough",
+    defaults: ["hidl_defaults"],
+    vendor: true,
+    srcs: [
+        "Gralloc0Hal.cpp",
+        "Gralloc1Hal.cpp",
+        "GrallocLoader.cpp",
+    ],
+    shared_libs: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+        "libhardware",
+    ],
+    export_shared_lib_headers: [
+        "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.mapper@2.0",
+        "libhardware",
+    ],
+    header_libs: [
+        "android.hardware.graphics.allocator@2.0-hal",
+        "libgrallocmapperincludes",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.graphics.allocator@2.0-hal",
+    ],
+    export_include_dirs: ["include"],
+    cflags: ["-DLOG_TAG=\"AllocatorHal\""],
+}
diff --git a/graphics/allocator/2.0/utils/passthrough/Gralloc0Hal.cpp b/graphics/allocator/2.0/utils/passthrough/Gralloc0Hal.cpp
new file mode 100644
index 0000000..8edb7dc
--- /dev/null
+++ b/graphics/allocator/2.0/utils/passthrough/Gralloc0Hal.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <allocator-passthrough/2.0/Gralloc0Hal.h>
+
+#include <string.h>
+
+#include <GrallocBufferDescriptor.h>
+#include <hardware/gralloc.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace passthrough {
+
+using mapper::V2_0::implementation::grallocDecodeBufferDescriptor;
+
+Gralloc0Hal::~Gralloc0Hal() {
+    if (mDevice) {
+        gralloc_close(mDevice);
+    }
+}
+
+bool Gralloc0Hal::initWithModule(const hw_module_t* module) {
+    int result = gralloc_open(module, &mDevice);
+    if (result) {
+        ALOGE("failed to open gralloc0 device: %s", strerror(-result));
+        mDevice = nullptr;
+        return false;
+    }
+
+    return true;
+}
+
+std::string Gralloc0Hal::dumpDebugInfo() {
+    char buf[4096] = {};
+    if (mDevice->dump) {
+        mDevice->dump(mDevice, buf, sizeof(buf));
+        buf[sizeof(buf) - 1] = '\0';
+    }
+
+    return buf;
+}
+
+Error Gralloc0Hal::allocateBuffers(const BufferDescriptor& descriptor, uint32_t count,
+                                   uint32_t* outStride,
+                                   std::vector<const native_handle_t*>* outBuffers) {
+    mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo;
+    if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
+        return Error::BAD_DESCRIPTOR;
+    }
+
+    Error error = Error::NONE;
+    uint32_t stride = 0;
+    std::vector<const native_handle_t*> buffers;
+    buffers.reserve(count);
+
+    // allocate the buffers
+    for (uint32_t i = 0; i < count; i++) {
+        const native_handle_t* tmpBuffer;
+        uint32_t tmpStride;
+        error = allocateOneBuffer(descriptorInfo, &tmpBuffer, &tmpStride);
+        if (error != Error::NONE) {
+            break;
+        }
+
+        buffers.push_back(tmpBuffer);
+
+        if (stride == 0) {
+            stride = tmpStride;
+        } else if (stride != tmpStride) {
+            // non-uniform strides
+            error = Error::UNSUPPORTED;
+            break;
+        }
+    }
+
+    if (error != Error::NONE) {
+        freeBuffers(buffers);
+        return error;
+    }
+
+    *outStride = stride;
+    *outBuffers = std::move(buffers);
+
+    return Error::NONE;
+}
+
+void Gralloc0Hal::freeBuffers(const std::vector<const native_handle_t*>& buffers) {
+    for (auto buffer : buffers) {
+        int result = mDevice->free(mDevice, buffer);
+        if (result != 0) {
+            ALOGE("failed to free buffer %p: %d", buffer, result);
+        }
+    }
+}
+
+Error Gralloc0Hal::allocateOneBuffer(const mapper::V2_0::IMapper::BufferDescriptorInfo& info,
+                                     const native_handle_t** outBuffer, uint32_t* outStride) {
+    if (info.layerCount > 1 || (info.usage >> 32) != 0) {
+        return Error::BAD_VALUE;
+    }
+
+    const native_handle_t* buffer = nullptr;
+    int stride = 0;
+    int result = mDevice->alloc(mDevice, info.width, info.height, static_cast<int>(info.format),
+                                info.usage, &buffer, &stride);
+    switch (result) {
+        case 0:
+            *outBuffer = buffer;
+            *outStride = stride;
+            return Error::NONE;
+        case -EINVAL:
+            return Error::BAD_VALUE;
+        default:
+            return Error::NO_RESOURCES;
+    }
+}
+
+}  // namespace passthrough
+}  // namespace V2_0
+}  // namespace allocator
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/allocator/2.0/utils/passthrough/Gralloc1Hal.cpp b/graphics/allocator/2.0/utils/passthrough/Gralloc1Hal.cpp
new file mode 100644
index 0000000..e343ecd
--- /dev/null
+++ b/graphics/allocator/2.0/utils/passthrough/Gralloc1Hal.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <allocator-passthrough/2.0/Gralloc1Hal.h>
+
+#include <string.h>
+
+#include <GrallocBufferDescriptor.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace passthrough {
+
+using android::hardware::graphics::common::V1_0::BufferUsage;
+using mapper::V2_0::implementation::grallocDecodeBufferDescriptor;
+
+Gralloc1Hal::~Gralloc1Hal() {
+    if (mDevice) {
+        gralloc1_close(mDevice);
+    }
+}
+
+bool Gralloc1Hal::initWithModule(const hw_module_t* module) {
+    int result = gralloc1_open(module, &mDevice);
+    if (result) {
+        ALOGE("failed to open gralloc1 device: %s", strerror(-result));
+        mDevice = nullptr;
+        return false;
+    }
+
+    initCapabilities();
+    if (!initDispatch()) {
+        gralloc1_close(mDevice);
+        mDevice = nullptr;
+        return false;
+    }
+
+    return true;
+}
+
+void Gralloc1Hal::initCapabilities() {
+    uint32_t count = 0;
+    mDevice->getCapabilities(mDevice, &count, nullptr);
+
+    std::vector<int32_t> capabilities(count);
+    mDevice->getCapabilities(mDevice, &count, capabilities.data());
+    capabilities.resize(count);
+
+    for (auto capability : capabilities) {
+        if (capability == GRALLOC1_CAPABILITY_LAYERED_BUFFERS) {
+            mCapabilities.layeredBuffers = true;
+            break;
+        }
+    }
+}
+
+gralloc1_function_pointer_t Gralloc1Hal::getDispatchFunction(
+    gralloc1_function_descriptor_t desc) const {
+    auto pfn = mDevice->getFunction(mDevice, desc);
+    if (!pfn) {
+        ALOGE("failed to get gralloc1 function %d", desc);
+        return nullptr;
+    }
+    return pfn;
+}
+
+bool Gralloc1Hal::initDispatch() {
+    if (!initDispatchFunction(GRALLOC1_FUNCTION_DUMP, &mDispatch.dump) ||
+        !initDispatchFunction(GRALLOC1_FUNCTION_CREATE_DESCRIPTOR, &mDispatch.createDescriptor) ||
+        !initDispatchFunction(GRALLOC1_FUNCTION_DESTROY_DESCRIPTOR, &mDispatch.destroyDescriptor) ||
+        !initDispatchFunction(GRALLOC1_FUNCTION_SET_DIMENSIONS, &mDispatch.setDimensions) ||
+        !initDispatchFunction(GRALLOC1_FUNCTION_SET_FORMAT, &mDispatch.setFormat) ||
+        !initDispatchFunction(GRALLOC1_FUNCTION_SET_CONSUMER_USAGE, &mDispatch.setConsumerUsage) ||
+        !initDispatchFunction(GRALLOC1_FUNCTION_SET_PRODUCER_USAGE, &mDispatch.setProducerUsage) ||
+        !initDispatchFunction(GRALLOC1_FUNCTION_GET_STRIDE, &mDispatch.getStride) ||
+        !initDispatchFunction(GRALLOC1_FUNCTION_ALLOCATE, &mDispatch.allocate) ||
+        !initDispatchFunction(GRALLOC1_FUNCTION_RELEASE, &mDispatch.release)) {
+        return false;
+    }
+
+    if (mCapabilities.layeredBuffers) {
+        if (!initDispatchFunction(GRALLOC1_FUNCTION_SET_LAYER_COUNT, &mDispatch.setLayerCount)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+std::string Gralloc1Hal::dumpDebugInfo() {
+    uint32_t len = 0;
+    mDispatch.dump(mDevice, &len, nullptr);
+
+    std::vector<char> buf(len + 1);
+    mDispatch.dump(mDevice, &len, buf.data());
+    buf.resize(len + 1);
+    buf[len] = '\0';
+
+    return buf.data();
+}
+
+Error Gralloc1Hal::allocateBuffers(const BufferDescriptor& descriptor, uint32_t count,
+                                   uint32_t* outStride,
+                                   std::vector<const native_handle_t*>* outBuffers) {
+    mapper::V2_0::IMapper::BufferDescriptorInfo descriptorInfo;
+    if (!grallocDecodeBufferDescriptor(descriptor, &descriptorInfo)) {
+        return Error::BAD_DESCRIPTOR;
+    }
+
+    gralloc1_buffer_descriptor_t desc;
+    Error error = createDescriptor(descriptorInfo, &desc);
+    if (error != Error::NONE) {
+        return error;
+    }
+
+    uint32_t stride = 0;
+    std::vector<const native_handle_t*> buffers;
+    buffers.reserve(count);
+
+    // allocate the buffers
+    for (uint32_t i = 0; i < count; i++) {
+        const native_handle_t* tmpBuffer;
+        uint32_t tmpStride;
+        error = allocateOneBuffer(desc, &tmpBuffer, &tmpStride);
+        if (error != Error::NONE) {
+            break;
+        }
+
+        buffers.push_back(tmpBuffer);
+
+        if (stride == 0) {
+            stride = tmpStride;
+        } else if (stride != tmpStride) {
+            // non-uniform strides
+            error = Error::UNSUPPORTED;
+            break;
+        }
+    }
+
+    mDispatch.destroyDescriptor(mDevice, desc);
+
+    if (error != Error::NONE) {
+        freeBuffers(buffers);
+        return error;
+    }
+
+    *outStride = stride;
+    *outBuffers = std::move(buffers);
+
+    return Error::NONE;
+}
+
+void Gralloc1Hal::freeBuffers(const std::vector<const native_handle_t*>& buffers) {
+    for (auto buffer : buffers) {
+        int32_t error = mDispatch.release(mDevice, buffer);
+        if (error != GRALLOC1_ERROR_NONE) {
+            ALOGE("failed to free buffer %p: %d", buffer, error);
+        }
+    }
+}
+
+Error Gralloc1Hal::toError(int32_t error) {
+    switch (error) {
+        case GRALLOC1_ERROR_NONE:
+            return Error::NONE;
+        case GRALLOC1_ERROR_BAD_DESCRIPTOR:
+            return Error::BAD_DESCRIPTOR;
+        case GRALLOC1_ERROR_BAD_HANDLE:
+            return Error::BAD_BUFFER;
+        case GRALLOC1_ERROR_BAD_VALUE:
+            return Error::BAD_VALUE;
+        case GRALLOC1_ERROR_NOT_SHARED:
+            return Error::NONE;  // this is fine
+        case GRALLOC1_ERROR_NO_RESOURCES:
+            return Error::NO_RESOURCES;
+        case GRALLOC1_ERROR_UNDEFINED:
+        case GRALLOC1_ERROR_UNSUPPORTED:
+        default:
+            return Error::UNSUPPORTED;
+    }
+}
+
+uint64_t Gralloc1Hal::toProducerUsage(uint64_t usage) {
+    // this is potentially broken as we have no idea which private flags
+    // should be filtered out
+    uint64_t producerUsage =
+        usage & ~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
+                                       BufferUsage::GPU_DATA_BUFFER);
+
+    switch (usage & BufferUsage::CPU_WRITE_MASK) {
+        case static_cast<uint64_t>(BufferUsage::CPU_WRITE_RARELY):
+            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE;
+            break;
+        case static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN):
+            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_WRITE_OFTEN;
+            break;
+        default:
+            break;
+    }
+
+    switch (usage & BufferUsage::CPU_READ_MASK) {
+        case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
+            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ;
+            break;
+        case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
+            producerUsage |= GRALLOC1_PRODUCER_USAGE_CPU_READ_OFTEN;
+            break;
+        default:
+            break;
+    }
+
+    // BufferUsage::GPU_DATA_BUFFER is always filtered out
+
+    return producerUsage;
+}
+
+uint64_t Gralloc1Hal::toConsumerUsage(uint64_t usage) {
+    // this is potentially broken as we have no idea which private flags
+    // should be filtered out
+    uint64_t consumerUsage =
+        usage &
+        ~static_cast<uint64_t>(BufferUsage::CPU_READ_MASK | BufferUsage::CPU_WRITE_MASK |
+                               BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::GPU_DATA_BUFFER);
+
+    switch (usage & BufferUsage::CPU_READ_MASK) {
+        case static_cast<uint64_t>(BufferUsage::CPU_READ_RARELY):
+            consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ;
+            break;
+        case static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN):
+            consumerUsage |= GRALLOC1_CONSUMER_USAGE_CPU_READ_OFTEN;
+            break;
+        default:
+            break;
+    }
+
+    // BufferUsage::SENSOR_DIRECT_DATA is always filtered out
+
+    if (usage & BufferUsage::GPU_DATA_BUFFER) {
+        consumerUsage |= GRALLOC1_CONSUMER_USAGE_GPU_DATA_BUFFER;
+    }
+
+    return consumerUsage;
+}
+
+Error Gralloc1Hal::createDescriptor(const mapper::V2_0::IMapper::BufferDescriptorInfo& info,
+                                    gralloc1_buffer_descriptor_t* outDescriptor) {
+    gralloc1_buffer_descriptor_t descriptor;
+
+    int32_t error = mDispatch.createDescriptor(mDevice, &descriptor);
+
+    if (error == GRALLOC1_ERROR_NONE) {
+        error = mDispatch.setDimensions(mDevice, descriptor, info.width, info.height);
+    }
+    if (error == GRALLOC1_ERROR_NONE) {
+        error = mDispatch.setFormat(mDevice, descriptor, static_cast<int32_t>(info.format));
+    }
+    if (error == GRALLOC1_ERROR_NONE) {
+        if (mCapabilities.layeredBuffers) {
+            error = mDispatch.setLayerCount(mDevice, descriptor, info.layerCount);
+        } else if (info.layerCount > 1) {
+            error = GRALLOC1_ERROR_UNSUPPORTED;
+        }
+    }
+    if (error == GRALLOC1_ERROR_NONE) {
+        error = mDispatch.setProducerUsage(mDevice, descriptor, toProducerUsage(info.usage));
+    }
+    if (error == GRALLOC1_ERROR_NONE) {
+        error = mDispatch.setConsumerUsage(mDevice, descriptor, toConsumerUsage(info.usage));
+    }
+
+    if (error == GRALLOC1_ERROR_NONE) {
+        *outDescriptor = descriptor;
+    } else {
+        mDispatch.destroyDescriptor(mDevice, descriptor);
+    }
+
+    return toError(error);
+}
+
+Error Gralloc1Hal::allocateOneBuffer(gralloc1_buffer_descriptor_t descriptor,
+                                     const native_handle_t** outBuffer, uint32_t* outStride) {
+    const native_handle_t* buffer = nullptr;
+    int32_t error = mDispatch.allocate(mDevice, 1, &descriptor, &buffer);
+    if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_NOT_SHARED) {
+        return toError(error);
+    }
+
+    uint32_t stride = 0;
+    error = mDispatch.getStride(mDevice, buffer, &stride);
+    if (error != GRALLOC1_ERROR_NONE && error != GRALLOC1_ERROR_UNDEFINED) {
+        mDispatch.release(mDevice, buffer);
+        return toError(error);
+    }
+
+    *outBuffer = buffer;
+    *outStride = stride;
+
+    return Error::NONE;
+}
+
+}  // namespace passthrough
+}  // namespace V2_0
+}  // namespace allocator
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/allocator/2.0/utils/passthrough/GrallocLoader.cpp b/graphics/allocator/2.0/utils/passthrough/GrallocLoader.cpp
new file mode 100644
index 0000000..dae7a78
--- /dev/null
+++ b/graphics/allocator/2.0/utils/passthrough/GrallocLoader.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <allocator-passthrough/2.0/GrallocLoader.h>
+
+#include <allocator-hal/2.0/Allocator.h>
+#include <allocator-hal/2.0/AllocatorHal.h>
+#include <allocator-passthrough/2.0/Gralloc0Hal.h>
+#include <allocator-passthrough/2.0/Gralloc1Hal.h>
+#include <hardware/gralloc.h>
+#include <hardware/hardware.h>
+#include <log/log.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace passthrough {
+
+const hw_module_t* GrallocLoader::loadModule() {
+    const hw_module_t* module;
+    int error = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module);
+    if (error) {
+        ALOGE("failed to get gralloc module");
+        return nullptr;
+    }
+
+    return module;
+}
+
+int GrallocLoader::getModuleMajorApiVersion(const hw_module_t* module) {
+    return (module->module_api_version >> 8) & 0xff;
+}
+
+std::unique_ptr<hal::AllocatorHal> GrallocLoader::createHal(const hw_module_t* module) {
+    int major = getModuleMajorApiVersion(module);
+    switch (major) {
+        case 1: {
+            auto hal = std::make_unique<Gralloc1Hal>();
+            return hal->initWithModule(module) ? std::move(hal) : nullptr;
+        }
+        case 0: {
+            auto hal = std::make_unique<Gralloc0Hal>();
+            return hal->initWithModule(module) ? std::move(hal) : nullptr;
+        }
+        default:
+            ALOGE("unknown gralloc module major version %d", major);
+            return nullptr;
+    }
+}
+
+IAllocator* GrallocLoader::createAllocator(std::unique_ptr<hal::AllocatorHal> hal) {
+    auto allocator = std::make_unique<hal::Allocator>();
+    return allocator->init(std::move(hal)) ? allocator.release() : nullptr;
+}
+
+}  // namespace passthrough
+}  // namespace V2_0
+}  // namespace allocator
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc0Hal.h b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc0Hal.h
new file mode 100644
index 0000000..8f433b0
--- /dev/null
+++ b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc0Hal.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <allocator-hal/2.0/AllocatorHal.h>
+
+struct alloc_device_t;
+struct hw_module_t;
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace passthrough {
+
+using mapper::V2_0::BufferDescriptor;
+using mapper::V2_0::Error;
+
+class Gralloc0Hal : public virtual hal::AllocatorHal {
+   public:
+    ~Gralloc0Hal();
+    bool initWithModule(const hw_module_t* module);
+
+    std::string dumpDebugInfo() override;
+
+    Error allocateBuffers(const BufferDescriptor& descriptor, uint32_t count, uint32_t* outStride,
+                          std::vector<const native_handle_t*>* outBuffers) override;
+
+    void freeBuffers(const std::vector<const native_handle_t*>& buffers) override;
+
+   protected:
+    Error allocateOneBuffer(const mapper::V2_0::IMapper::BufferDescriptorInfo& info,
+                            const native_handle_t** outBuffer, uint32_t* outStride);
+
+    alloc_device_t* mDevice = nullptr;
+};
+
+}  // namespace passthrough
+}  // namespace V2_0
+}  // namespace allocator
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc1Hal.h b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc1Hal.h
new file mode 100644
index 0000000..3126e91
--- /dev/null
+++ b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/Gralloc1Hal.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <allocator-hal/2.0/AllocatorHal.h>
+#include <hardware/gralloc1.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace passthrough {
+
+using mapper::V2_0::BufferDescriptor;
+using mapper::V2_0::Error;
+
+class Gralloc1Hal : public virtual hal::AllocatorHal {
+   public:
+    ~Gralloc1Hal();
+    bool initWithModule(const hw_module_t* module);
+
+    std::string dumpDebugInfo() override;
+
+    Error allocateBuffers(const BufferDescriptor& descriptor, uint32_t count, uint32_t* outStride,
+                          std::vector<const native_handle_t*>* outBuffers) override;
+
+    void freeBuffers(const std::vector<const native_handle_t*>& buffers) override;
+
+   protected:
+    template <typename T>
+    bool initDispatchFunction(gralloc1_function_descriptor_t desc, T* outPfn) {
+        auto pfn = getDispatchFunction(desc);
+        if (pfn) {
+            *outPfn = reinterpret_cast<T>(pfn);
+            return true;
+        } else {
+            return false;
+        }
+    }
+    gralloc1_function_pointer_t getDispatchFunction(gralloc1_function_descriptor_t desc) const;
+
+    virtual void initCapabilities();
+    virtual bool initDispatch();
+
+    static Error toError(int32_t error);
+    static uint64_t toProducerUsage(uint64_t usage);
+    static uint64_t toConsumerUsage(uint64_t usage);
+
+    Error createDescriptor(const mapper::V2_0::IMapper::BufferDescriptorInfo& info,
+                           gralloc1_buffer_descriptor_t* outDescriptor);
+
+    Error allocateOneBuffer(gralloc1_buffer_descriptor_t descriptor,
+                            const native_handle_t** outBuffer, uint32_t* outStride);
+
+    gralloc1_device_t* mDevice = nullptr;
+
+    struct {
+        bool layeredBuffers;
+    } mCapabilities = {};
+
+    struct {
+        GRALLOC1_PFN_DUMP dump;
+        GRALLOC1_PFN_CREATE_DESCRIPTOR createDescriptor;
+        GRALLOC1_PFN_DESTROY_DESCRIPTOR destroyDescriptor;
+        GRALLOC1_PFN_SET_DIMENSIONS setDimensions;
+        GRALLOC1_PFN_SET_FORMAT setFormat;
+        GRALLOC1_PFN_SET_LAYER_COUNT setLayerCount;
+        GRALLOC1_PFN_SET_CONSUMER_USAGE setConsumerUsage;
+        GRALLOC1_PFN_SET_PRODUCER_USAGE setProducerUsage;
+        GRALLOC1_PFN_GET_STRIDE getStride;
+        GRALLOC1_PFN_ALLOCATE allocate;
+        GRALLOC1_PFN_RELEASE release;
+    } mDispatch = {};
+};
+
+}  // namespace passthrough
+}  // namespace V2_0
+}  // namespace allocator
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/GrallocLoader.h b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/GrallocLoader.h
new file mode 100644
index 0000000..a0b9503
--- /dev/null
+++ b/graphics/allocator/2.0/utils/passthrough/include/allocator-passthrough/2.0/GrallocLoader.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <allocator-hal/2.0/AllocatorHal.h>
+
+struct hw_module_t;
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace allocator {
+namespace V2_0 {
+namespace passthrough {
+
+class GrallocLoader {
+   public:
+    static IAllocator* load() {
+        const hw_module_t* module = loadModule();
+        if (!module) {
+            return nullptr;
+        }
+        auto hal = createHal(module);
+        if (!hal) {
+            return nullptr;
+        }
+        return createAllocator(std::move(hal));
+    }
+
+    // load the gralloc module
+    static const hw_module_t* loadModule();
+
+    // return the major api version of the module
+    static int getModuleMajorApiVersion(const hw_module_t* module);
+
+    // create an AllocatorHal instance
+    static std::unique_ptr<hal::AllocatorHal> createHal(const hw_module_t* module);
+
+    // create an IAllocator instance
+    static IAllocator* createAllocator(std::unique_ptr<hal::AllocatorHal> hal);
+};
+
+}  // namespace passthrough
+}  // namespace V2_0
+}  // namespace allocator
+}  // namespace graphics
+}  // namespace hardware
+}  // namespace android
diff --git a/graphics/composer/2.1/default/ComposerClient.cpp b/graphics/composer/2.1/default/ComposerClient.cpp
index 4e6dd4f..8aa9af0 100644
--- a/graphics/composer/2.1/default/ComposerClient.cpp
+++ b/graphics/composer/2.1/default/ComposerClient.cpp
@@ -299,10 +299,17 @@
     Error err = mHal.createLayer(display, &layer);
     if (err == Error::NONE) {
         std::lock_guard<std::mutex> lock(mDisplayDataMutex);
-
         auto dpy = mDisplayData.find(display);
-        auto ly = dpy->second.Layers.emplace(layer, LayerBuffers()).first;
-        ly->second.Buffers.resize(bufferSlotCount);
+        // The display entry may have already been removed by onHotplug.
+        if (dpy != mDisplayData.end()) {
+            auto ly = dpy->second.Layers.emplace(layer, LayerBuffers()).first;
+            ly->second.Buffers.resize(bufferSlotCount);
+        } else {
+            err = Error::BAD_DISPLAY;
+            // Note: We do not destroy the layer on this error as the hotplug
+            // disconnect invalidates the display id. The implementation should
+            // ensure all layers for the display are destroyed.
+        }
     }
 
     hidl_cb(err, layer);
@@ -316,7 +323,10 @@
         std::lock_guard<std::mutex> lock(mDisplayDataMutex);
 
         auto dpy = mDisplayData.find(display);
-        dpy->second.Layers.erase(layer);
+        // The display entry may have already been removed by onHotplug.
+        if (dpy != mDisplayData.end()) {
+            dpy->second.Layers.erase(layer);
+        }
     }
 
     return err;
diff --git a/health/2.0/Android.bp b/health/2.0/Android.bp
index 1080df1..c444165 100644
--- a/health/2.0/Android.bp
+++ b/health/2.0/Android.bp
@@ -17,6 +17,10 @@
     ],
     types: [
         "Result",
+        "DiskStats",
+        "HealthInfo",
+        "StorageAttribute",
+        "StorageInfo",
     ],
     gen_java: true,
 }
diff --git a/health/2.0/IHealth.hal b/health/2.0/IHealth.hal
index 3e10701..230b5d0 100644
--- a/health/2.0/IHealth.hal
+++ b/health/2.0/IHealth.hal
@@ -69,7 +69,7 @@
      *                NOT_SUPPORTED if this property is not supported
      *                 (e.g. the file that stores this property does not exist),
      *                UNKNOWN for other errors.
-     * @return value battery capacity, or INT32_MIN if not successful.
+     * @return value battery capacity, or 0 if not successful.
      */
     getChargeCounter() generates (Result result, int32_t value);
 
@@ -84,7 +84,7 @@
      *                NOT_SUPPORTED if this property is not supported
      *                 (e.g. the file that stores this property does not exist),
      *                UNKNOWN for other errors.
-     * @return value instantaneous battery current, or INT32_MIN if not
+     * @return value instantaneous battery current, or 0 if not
      *               successful.
      */
     getCurrentNow() generates (Result result, int32_t value);
@@ -101,7 +101,7 @@
      *                NOT_SUPPORTED if this property is not supported
      *                 (e.g. the file that stores this property does not exist),
      *                UNKNOWN for other errors.
-     * @return value average battery current, or INT32_MIN if not successful.
+     * @return value average battery current, or 0 if not successful.
      */
     getCurrentAverage() generates (Result result, int32_t value);
 
@@ -113,7 +113,7 @@
      *                NOT_SUPPORTED if this property is not supported
      *                 (e.g. the file that stores this property does not exist),
      *                UNKNOWN for other errors.
-     * @return value remaining battery capacity, or INT32_MIN if not successful.
+     * @return value remaining battery capacity, or 0 if not successful.
      */
     getCapacity() generates (Result result, int32_t value);
 
@@ -123,7 +123,7 @@
      * @return result SUCCESS if successful,
      *                NOT_SUPPORTED if this property is not supported,
      *                UNKNOWN for other errors.
-     * @return value remaining energy, or INT64_MIN if not successful.
+     * @return value remaining energy, or 0 if not successful.
      */
     getEnergyCounter() generates (Result result, int64_t value);
 
@@ -137,4 +137,38 @@
      * @return value charge status, or UNKNOWN if not successful.
      */
     getChargeStatus() generates (Result result, BatteryStatus value);
+
+    /**
+     * Get storage info.
+     *
+     * @return result SUCCESS if successful,
+     *                NOT_SUPPORTED if this property is not supported,
+     *                UNKNOWN other errors.
+     * @return value vector of StorageInfo structs, to be ignored if result is not
+     *               SUCCESS.
+     */
+    getStorageInfo() generates (Result result, vec<StorageInfo> value);
+
+    /**
+     * Gets disk statistics (number of reads/writes processed, number of I/O
+     * operations in flight etc).
+     *
+     * @return result SUCCESS if successful,
+     *                NOT_SUPPORTED if this property is not supported,
+     *                UNKNOWN other errors.
+     * @return value vector of disk statistics, to be ignored if result is not SUCCESS.
+     *               The mapping is index 0->sda, 1->sdb and so on.
+     */
+    getDiskStats() generates (Result result, vec<DiskStats> value);
+
+    /**
+     * Get Health Information.
+     *
+     * @return result SUCCESS if successful,
+     *                NOT_SUPPORTED if this API is not supported,
+     *                UNKNOWN for other errors.
+     * @return value  Health information, to be ignored if result is not
+     *                SUCCESS.
+     */
+    getHealthInfo() generates (Result result, @2.0::HealthInfo value);
 };
diff --git a/health/2.0/IHealthInfoCallback.hal b/health/2.0/IHealthInfoCallback.hal
index 8e17bb9..15352ee 100644
--- a/health/2.0/IHealthInfoCallback.hal
+++ b/health/2.0/IHealthInfoCallback.hal
@@ -16,8 +16,6 @@
 
 package android.hardware.health@2.0;
 
-import @1.0::HealthInfo;
-
 /**
  * IHealthInfoCallback is the callback interface to
  * {@link IHealthInfoBus.registerCallback}.
diff --git a/health/2.0/default/Health.cpp b/health/2.0/default/Health.cpp
index 4710c90..7a3e650 100644
--- a/health/2.0/default/Health.cpp
+++ b/health/2.0/default/Health.cpp
@@ -1,8 +1,24 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 #define LOG_TAG "android.hardware.health@2.0-impl"
 #include <android-base/logging.h>
 
 #include <health2/Health.h>
 
+#include <hal_conversion.h>
 #include <hidl/HidlTransportSupport.h>
 
 extern void healthd_battery_update_internal(bool);
@@ -93,27 +109,27 @@
 }
 
 Return<void> Health::getChargeCounter(getChargeCounter_cb _hidl_cb) {
-    getProperty(battery_monitor_, BATTERY_PROP_CHARGE_COUNTER, INT32_MIN, _hidl_cb);
+    getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CHARGE_COUNTER, 0, _hidl_cb);
     return Void();
 }
 
 Return<void> Health::getCurrentNow(getCurrentNow_cb _hidl_cb) {
-    getProperty(battery_monitor_, BATTERY_PROP_CURRENT_NOW, INT32_MIN, _hidl_cb);
+    getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CURRENT_NOW, 0, _hidl_cb);
     return Void();
 }
 
 Return<void> Health::getCurrentAverage(getCurrentAverage_cb _hidl_cb) {
-    getProperty(battery_monitor_, BATTERY_PROP_CURRENT_AVG, INT32_MIN, _hidl_cb);
+    getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CURRENT_AVG, 0, _hidl_cb);
     return Void();
 }
 
 Return<void> Health::getCapacity(getCapacity_cb _hidl_cb) {
-    getProperty(battery_monitor_, BATTERY_PROP_CAPACITY, INT32_MIN, _hidl_cb);
+    getProperty<int32_t>(battery_monitor_, BATTERY_PROP_CAPACITY, 0, _hidl_cb);
     return Void();
 }
 
 Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
-    getProperty(battery_monitor_, BATTERY_PROP_ENERGY_COUNTER, INT64_MIN, _hidl_cb);
+    getProperty<int64_t>(battery_monitor_, BATTERY_PROP_ENERGY_COUNTER, 0, _hidl_cb);
     return Void();
 }
 
@@ -139,10 +155,28 @@
     return Result::SUCCESS;
 }
 
-void Health::notifyListeners(const HealthInfo& info) {
+void Health::notifyListeners(HealthInfo* healthInfo) {
+    std::vector<StorageInfo> info;
+    get_storage_info(info);
+
+    std::vector<DiskStats> stats;
+    get_disk_stats(stats);
+
+    int32_t currentAvg = 0;
+
+    struct BatteryProperty prop;
+    status_t ret = battery_monitor_->getProperty(BATTERY_PROP_CURRENT_AVG, &prop);
+    if (ret == OK) {
+        currentAvg = static_cast<int32_t>(prop.valueInt64);
+    }
+
+    healthInfo->batteryCurrentAverage = currentAvg;
+    healthInfo->diskStats = stats;
+    healthInfo->storageInfos = info;
+
     std::lock_guard<std::mutex> _lock(callbacks_lock_);
     for (auto it = callbacks_.begin(); it != callbacks_.end();) {
-        auto ret = (*it)->healthInfoChanged(info);
+        auto ret = (*it)->healthInfoChanged(*healthInfo);
         if (!ret.isOk() && ret.isDeadObject()) {
             it = callbacks_.erase(it);
         } else {
@@ -160,6 +194,63 @@
     return Void();
 }
 
+Return<void> Health::getStorageInfo(getStorageInfo_cb _hidl_cb) {
+    std::vector<struct StorageInfo> info;
+    get_storage_info(info);
+    hidl_vec<struct StorageInfo> info_vec(info);
+    if (!info.size()) {
+        _hidl_cb(Result::NOT_SUPPORTED, info_vec);
+    } else {
+        _hidl_cb(Result::SUCCESS, info_vec);
+    }
+    return Void();
+}
+
+Return<void> Health::getDiskStats(getDiskStats_cb _hidl_cb) {
+    std::vector<struct DiskStats> stats;
+    get_disk_stats(stats);
+    hidl_vec<struct DiskStats> stats_vec(stats);
+    if (!stats.size()) {
+        _hidl_cb(Result::NOT_SUPPORTED, stats_vec);
+    } else {
+        _hidl_cb(Result::SUCCESS, stats_vec);
+    }
+    return Void();
+}
+
+Return<void> Health::getHealthInfo(getHealthInfo_cb _hidl_cb) {
+    using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
+
+    update();
+    struct android::BatteryProperties p = getBatteryProperties(battery_monitor_.get());
+
+    V1_0::HealthInfo batteryInfo;
+    convertToHealthInfo(&p, batteryInfo);
+
+    std::vector<StorageInfo> info;
+    get_storage_info(info);
+
+    std::vector<DiskStats> stats;
+    get_disk_stats(stats);
+
+    int32_t currentAvg = 0;
+
+    struct BatteryProperty prop;
+    status_t ret = battery_monitor_->getProperty(BATTERY_PROP_CURRENT_AVG, &prop);
+    if (ret == OK) {
+        currentAvg = static_cast<int32_t>(prop.valueInt64);
+    }
+
+    V2_0::HealthInfo healthInfo = {};
+    healthInfo.legacy = std::move(batteryInfo);
+    healthInfo.batteryCurrentAverage = currentAvg;
+    healthInfo.diskStats = stats;
+    healthInfo.storageInfos = info;
+
+    _hidl_cb(Result::SUCCESS, healthInfo);
+    return Void();
+}
+
 void Health::serviceDied(uint64_t /* cookie */, const wp<IBase>& who) {
     (void)unregisterCallbackInternal(who.promote());
 }
diff --git a/health/2.0/default/include/health2/Health.h b/health/2.0/default/include/health2/Health.h
index ab42ae7..134cdc6 100644
--- a/health/2.0/default/include/health2/Health.h
+++ b/health/2.0/default/include/health2/Health.h
@@ -9,6 +9,12 @@
 #include <healthd/BatteryMonitor.h>
 #include <hidl/Status.h>
 
+using android::hardware::health::V2_0::StorageInfo;
+using android::hardware::health::V2_0::DiskStats;
+
+void get_storage_info(std::vector<struct StorageInfo>& info);
+void get_disk_stats(std::vector<struct DiskStats>& stats);
+
 namespace android {
 namespace hardware {
 namespace health {
@@ -16,7 +22,6 @@
 namespace implementation {
 
 using V1_0::BatteryStatus;
-using V1_0::HealthInfo;
 
 using ::android::hidl::base::V1_0::IBase;
 
@@ -32,7 +37,7 @@
     Health(struct healthd_config* c);
 
     // TODO(b/62229583): clean up and hide these functions after update() logic is simplified.
-    void notifyListeners(const HealthInfo& info);
+    void notifyListeners(HealthInfo* info);
 
     // Methods from IHealth follow.
     Return<Result> registerCallback(const sp<IHealthInfoCallback>& callback) override;
@@ -44,6 +49,9 @@
     Return<void> getCapacity(getCapacity_cb _hidl_cb) override;
     Return<void> getEnergyCounter(getEnergyCounter_cb _hidl_cb) override;
     Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override;
+    Return<void> getStorageInfo(getStorageInfo_cb _hidl_cb) override;
+    Return<void> getDiskStats(getDiskStats_cb _hidl_cb) override;
+    Return<void> getHealthInfo(getHealthInfo_cb _hidl_cb) override;
 
     // Methods from ::android::hidl::base::V1_0::IBase follow.
     Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
diff --git a/health/2.0/libhealthhalutils/Android.bp b/health/2.0/libhealthhalutils/Android.bp
new file mode 100644
index 0000000..5686520
--- /dev/null
+++ b/health/2.0/libhealthhalutils/Android.bp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Convenience library for (hwbinder) clients to choose the correct health
+// service instance.
+cc_library_static {
+    name: "libhealthhalutils",
+    srcs: ["HealthHalUtils.cpp"],
+    cflags: ["-Wall", "-Werror"],
+    vendor_available: true,
+    export_include_dirs: ["include"],
+    shared_libs: [
+        "android.hardware.health@2.0",
+        "libbase",
+        "libhidlbase",
+    ],
+}
diff --git a/health/2.0/libhealthhalutils/HealthHalUtils.cpp b/health/2.0/libhealthhalutils/HealthHalUtils.cpp
new file mode 100644
index 0000000..9e1cc70
--- /dev/null
+++ b/health/2.0/libhealthhalutils/HealthHalUtils.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "HealthHalUtils"
+
+#include <android-base/logging.h>
+#include <healthhalutils/HealthHalUtils.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_0 {
+
+sp<IHealth> get_health_service() {
+    for (auto&& instanceName : {"default", "backup"}) {
+        auto ret = IHealth::getService(instanceName);
+        if (ret != nullptr) {
+            return ret;
+        }
+        LOG(INFO) << "health: cannot get " << instanceName << " service";
+    }
+    return nullptr;
+}
+
+}  // namespace V2_0
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/2.0/libhealthhalutils/include/healthhalutils/HealthHalUtils.h b/health/2.0/libhealthhalutils/include/healthhalutils/HealthHalUtils.h
new file mode 100644
index 0000000..66acc7c
--- /dev/null
+++ b/health/2.0/libhealthhalutils/include/healthhalutils/HealthHalUtils.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HEALTHD_HEALTH_HAL_UTILS_H
+#define HEALTHD_HEALTH_HAL_UTILS_H
+
+#include <android/hardware/health/2.0/IHealth.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_0 {
+
+// Simplified version of BatteryService.HealthServiceWrapper.init().
+// Returns the "default" health instance when it is available, and "backup" instance
+// otherwise. Before health 1.0 HAL is removed, this function should be used instead
+// of IHealth::getService().
+sp<IHealth> get_health_service();
+
+}  // namespace V2_0
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HEALTHD_HEALTH_HAL_UTILS_H
diff --git a/health/2.0/libstoragehealthdefault/Android.bp b/health/2.0/libstoragehealthdefault/Android.bp
new file mode 100644
index 0000000..cef04fe
--- /dev/null
+++ b/health/2.0/libstoragehealthdefault/Android.bp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Default implementation for (passthrough) clients that statically links to
+// android.hardware.health@2.0-impl but do no query for storage related
+// information.
+cc_library_static {
+    srcs: ["StorageHealthDefault.cpp"],
+    name: "libhealthstoragedefault",
+    vendor_available: true,
+    cflags: ["-Werror"],
+    shared_libs: [
+        "android.hardware.health@2.0",
+    ],
+}
diff --git a/health/2.0/libstoragehealthdefault/StorageHealthDefault.cpp b/health/2.0/libstoragehealthdefault/StorageHealthDefault.cpp
new file mode 100644
index 0000000..aba6cc3
--- /dev/null
+++ b/health/2.0/libstoragehealthdefault/StorageHealthDefault.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "include/StorageHealthDefault.h"
+
+void get_storage_info(std::vector<struct StorageInfo>&) {
+    // Use defaults.
+}
+
+void get_disk_stats(std::vector<struct DiskStats>&) {
+    // Use defaults
+}
diff --git a/health/2.0/libstoragehealthdefault/include/StorageHealthDefault.h b/health/2.0/libstoragehealthdefault/include/StorageHealthDefault.h
new file mode 100644
index 0000000..85eb210
--- /dev/null
+++ b/health/2.0/libstoragehealthdefault/include/StorageHealthDefault.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_HARDWARE_HEALTH_V2_0_STORAGE_HEALTH_H
+#define ANDROID_HARDWARE_HEALTH_V2_0_STORAGE_HEALTH_H
+
+#include <android/hardware/health/2.0/types.h>
+
+using android::hardware::health::V2_0::StorageInfo;
+using android::hardware::health::V2_0::DiskStats;
+
+/*
+ * Get storage information.
+ */
+void get_storage_info(std::vector<struct StorageInfo>& info);
+
+/*
+ * Get disk statistics.
+ */
+void get_disk_stats(std::vector<struct DiskStats>& stats);
+
+#endif  // ANDROID_HARDWARE_HEALTH_V2_0_STORAGE_HEALTH_H
diff --git a/health/2.0/types.hal b/health/2.0/types.hal
index 8c6d88f..fe33c88 100644
--- a/health/2.0/types.hal
+++ b/health/2.0/types.hal
@@ -26,3 +26,129 @@
     NOT_FOUND,
     CALLBACK_DIED,
 };
+
+/*
+ * Identification attributes for a storage device.
+ */
+struct StorageAttribute {
+    /**
+     * Set to true if internal storage
+     */
+    bool isInternal;
+    /**
+     * Set to true if this is the boot device.
+     */
+    bool isBootDevice;
+    /**
+     * Name of the storage device.
+     */
+    string name;
+};
+
+/*
+ * Information on storage device including life time estimates, end of life
+ * information and other attributes.
+ */
+struct StorageInfo {
+    /**
+     * Attributes of the storage device whose info is contained by the struct.
+     */
+    StorageAttribute attr;
+    /**
+     * pre-eol (end of life) information. Follows JEDEC standard No.84-B50.
+     */
+    uint16_t eol;
+    /**
+     * device life time estimation (type A). Follows JEDEC standard No.84-B50.
+     */
+    uint16_t lifetimeA;
+    /**
+     * device life time estimation (type B). Follows JEDEC standard No.84-B50.
+     */
+    uint16_t lifetimeB;
+    /**
+     * version string
+     */
+    string version;
+};
+/*
+ * Disk statistics since boot.
+ */
+struct DiskStats {
+    /**
+     * Number of reads processed.
+     */
+    uint64_t reads;
+    /**
+     * number of read I/Os merged with in-queue I/Os.
+     */
+    uint64_t readMerges;
+    /**
+     * number of sectors read.
+     */
+    uint64_t readSectors;
+    /**
+     * total wait time for read requests.
+     */
+    uint64_t readTicks;
+    /**
+     * number of writes processed.
+     */
+    uint64_t writes;
+    /**
+     * number of writes merged with in-queue I/Os.
+     */
+    uint64_t writeMerges;
+    /**
+     * number of sectors written.
+     */
+    uint64_t writeSectors;
+    /**
+     * total wait time for write requests.
+     */
+    uint64_t writeTicks;
+    /**
+     * number of I/Os currently in flight.
+     */
+    uint64_t ioInFlight;
+    /**
+     * total time this block device has been active.
+     */
+    uint64_t ioTicks;
+    /**
+     * total wait time for all requests.
+     */
+    uint64_t ioInQueue;
+    /**
+     * Attributes of the memory device.
+     */
+    StorageAttribute attr;
+};
+
+/**
+ * Combined Health Information.
+ */
+struct HealthInfo {
+    /**
+     * V1.0 HealthInfo.
+     * If a member is unsupported, it is filled with:
+     * - 0 (for integers);
+     * - false (for booleans);
+     * - empty string (for strings);
+     * - UNKNOWN (for BatteryStatus and BatteryHealth).
+     */
+    @1.0::HealthInfo legacy;
+    /**
+     * Average battery current in uA. Will be 0 if unsupported.
+     */
+    int32_t batteryCurrentAverage;
+    /**
+     * Disk Statistics. Will be an empty vector if unsupported.
+     */
+    vec<DiskStats> diskStats;
+    /**
+     * Information on storage devices. Will be an empty vector if
+     * unsupported.
+     */
+    vec<StorageInfo> storageInfos;
+};
diff --git a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
index bf8548c..972bc7f 100644
--- a/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
+++ b/health/2.0/vts/functional/VtsHalHealthV2_0TargetTest.cpp
@@ -35,7 +35,6 @@
 namespace V2_0 {
 
 using V1_0::BatteryStatus;
-using V1_0::HealthInfo;
 
 // Test environment for graphics.composer
 class HealthHidlEnvironment : public VtsHalHidlTargetTestEnvBase {
@@ -180,6 +179,66 @@
     return AssertionFailure() << "Result is not SUCCESS or NOT_SUPPORTED: " << toString(res);
 }
 
+bool verifyStorageInfo(const hidl_vec<struct StorageInfo>& info) {
+    for (size_t i = 0; i < info.size(); i++) {
+        if (!(0 <= info[i].eol && info[i].eol <= 3 && 0 <= info[i].lifetimeA &&
+              info[i].lifetimeA <= 0x0B && 0 <= info[i].lifetimeB && info[i].lifetimeB <= 0x0B)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool verifyDiskStats(const hidl_vec<struct DiskStats>& stats) {
+    for (size_t i = 0; i < stats.size(); i++) {
+        if (!(stats[i].reads > 0 && stats[i].readMerges > 0 && stats[i].readSectors > 0 &&
+              stats[i].readTicks > 0 && stats[i].writes > 0 && stats[i].writeMerges > 0 &&
+              stats[i].writeSectors > 0 && stats[i].writeTicks > 0 && stats[i].ioTicks > 0)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+template <typename T>
+bool verifyEnum(T value) {
+    for (auto it : hidl_enum_iterator<T>()) {
+        if (it == value) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool verifyHealthInfo(const HealthInfo& health_info) {
+    if (!verifyStorageInfo(health_info.storageInfos) || !verifyDiskStats(health_info.diskStats)) {
+        return false;
+    }
+
+    using V1_0::BatteryStatus;
+    using V1_0::BatteryHealth;
+
+    if (!((health_info.legacy.batteryChargeCounter > 0) &&
+          (health_info.legacy.batteryCurrent != INT32_MIN) &&
+          (0 <= health_info.legacy.batteryLevel && health_info.legacy.batteryLevel <= 100) &&
+          verifyEnum<BatteryHealth>(health_info.legacy.batteryHealth) &&
+          (health_info.legacy.batteryStatus != BatteryStatus::UNKNOWN) &&
+          verifyEnum<BatteryStatus>(health_info.legacy.batteryStatus))) {
+        return false;
+    }
+
+    return true;
+}
+
+/*
+ * Tests the values returned by getChargeCounter(),
+ * getCurrentNow(), getCurrentAverage(), getCapacity(), getEnergyCounter(),
+ * getChargeStatus(), getStorageInfo(), getDiskStats() and getHealthInfo() from
+ * interface IHealth.
+ */
 TEST_F(HealthHidlTest, Properties) {
     EXPECT_OK(mHealth->getChargeCounter([](auto result, auto value) {
         EXPECT_VALID_OR_UNSUPPORTED_PROP(result, std::to_string(value), value > 0);
@@ -199,8 +258,16 @@
     EXPECT_OK(mHealth->getChargeStatus([](auto result, auto value) {
         EXPECT_VALID_OR_UNSUPPORTED_PROP(
             result, toString(value),
-            value == BatteryStatus::CHARGING || value == BatteryStatus::DISCHARGING ||
-                value == BatteryStatus::NOT_CHARGING || value == BatteryStatus::FULL);
+            value != BatteryStatus::UNKNOWN && verifyEnum<BatteryStatus>(value));
+    }));
+    EXPECT_OK(mHealth->getStorageInfo([](auto result, auto& value) {
+        EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyStorageInfo(value));
+    }));
+    EXPECT_OK(mHealth->getDiskStats([](auto result, auto& value) {
+        EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyDiskStats(value));
+    }));
+    EXPECT_OK(mHealth->getHealthInfo([](auto result, auto& value) {
+        EXPECT_VALID_OR_UNSUPPORTED_PROP(result, toString(value), verifyHealthInfo(value));
     }));
 }
 
diff --git a/keymaster/4.0/support/Android.bp b/keymaster/4.0/support/Android.bp
index 748fed3..6b8dcdc 100644
--- a/keymaster/4.0/support/Android.bp
+++ b/keymaster/4.0/support/Android.bp
@@ -26,11 +26,18 @@
         "attestation_record.cpp",
         "authorization_set.cpp",
         "key_param_output.cpp",
+        "Keymaster3.cpp",
+        "Keymaster4.cpp",
     ],
     export_include_dirs: ["include"],
     shared_libs: [
+        "android.hardware.keymaster@3.0",
         "android.hardware.keymaster@4.0",
+        "libbase",
         "libcrypto",
+        "libhardware",
         "libhidlbase",
+        "libhidltransport",
+        "libutils",
     ]
 }
diff --git a/keymaster/4.0/support/Keymaster3.cpp b/keymaster/4.0/support/Keymaster3.cpp
new file mode 100644
index 0000000..6dfe85b
--- /dev/null
+++ b/keymaster/4.0/support/Keymaster3.cpp
@@ -0,0 +1,325 @@
+/*
+ **
+ ** Copyright 2017, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include <keymasterV4_0/Keymaster3.h>
+
+#include <android-base/logging.h>
+#include <hardware/hw_auth_token.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+using android::hardware::details::StatusOf;
+
+namespace {
+
+ErrorCode convert(V3_0::ErrorCode error) {
+    return static_cast<ErrorCode>(error);
+}
+
+V3_0::KeyPurpose convert(KeyPurpose purpose) {
+    return static_cast<V3_0::KeyPurpose>(purpose);
+}
+
+V3_0::KeyFormat convert(KeyFormat purpose) {
+    return static_cast<V3_0::KeyFormat>(purpose);
+}
+
+V3_0::KeyParameter convert(const KeyParameter& param) {
+    V3_0::KeyParameter converted;
+    converted.tag = static_cast<V3_0::Tag>(param.tag);
+    static_assert(sizeof(converted.f) == sizeof(param.f), "This function assumes sizes match");
+    memcpy(&converted.f, &param.f, sizeof(param.f));
+    converted.blob = param.blob;
+    return converted;
+}
+
+KeyParameter convert(const V3_0::KeyParameter& param) {
+    KeyParameter converted;
+    converted.tag = static_cast<Tag>(param.tag);
+    static_assert(sizeof(converted.f) == sizeof(param.f), "This function assumes sizes match");
+    memcpy(&converted.f, &param.f, sizeof(param.f));
+    converted.blob = param.blob;
+    return converted;
+}
+
+hidl_vec<V3_0::KeyParameter> convert(const hidl_vec<KeyParameter>& params) {
+    hidl_vec<V3_0::KeyParameter> converted(params.size());
+    for (size_t i = 0; i < params.size(); ++i) {
+        converted[i] = convert(params[i]);
+    }
+    return converted;
+}
+
+hidl_vec<KeyParameter> convert(const hidl_vec<V3_0::KeyParameter>& params) {
+    hidl_vec<KeyParameter> converted(params.size());
+    for (size_t i = 0; i < params.size(); ++i) {
+        converted[i] = convert(params[i]);
+    }
+    return converted;
+}
+
+template <typename T, typename OutIter>
+inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) {
+    const uint8_t* value_ptr = reinterpret_cast<const uint8_t*>(&value);
+    return std::copy(value_ptr, value_ptr + sizeof(value), dest);
+}
+
+constexpr size_t kHmacSize = 32;
+
+inline static hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token) {
+    static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) +
+                          sizeof(token.authenticatorId) + sizeof(token.authenticatorType) +
+                          sizeof(token.timestamp) + kHmacSize ==
+                      sizeof(hw_auth_token_t),
+                  "HardwareAuthToken content size does not match hw_auth_token_t size");
+
+    hidl_vec<uint8_t> result;
+    result.resize(sizeof(hw_auth_token_t));
+    auto pos = result.begin();
+    *pos++ = 0;  // Version byte
+    pos = copy_bytes_to_iterator(token.challenge, pos);
+    pos = copy_bytes_to_iterator(token.userId, pos);
+    pos = copy_bytes_to_iterator(token.authenticatorId, pos);
+    auto auth_type = htonl(static_cast<uint32_t>(token.authenticatorType));
+    pos = copy_bytes_to_iterator(auth_type, pos);
+    auto timestamp = htonq(token.timestamp);
+    pos = copy_bytes_to_iterator(timestamp, pos);
+    if (token.mac.size() != kHmacSize) {
+        std::fill(pos, pos + kHmacSize, 0);
+    } else {
+        std::copy(token.mac.begin(), token.mac.end(), pos);
+    }
+
+    return result;
+}
+
+hidl_vec<V3_0::KeyParameter> convertAndAddAuthToken(const hidl_vec<KeyParameter>& params,
+                                                    const HardwareAuthToken& authToken) {
+    hidl_vec<V3_0::KeyParameter> converted(params.size() + 1);
+    for (size_t i = 0; i < params.size(); ++i) {
+        converted[i] = convert(params[i]);
+    }
+    converted[params.size()].tag = V3_0::Tag::AUTH_TOKEN;
+    converted[params.size()].blob = authToken2HidlVec(authToken);
+
+    return converted;
+}
+
+KeyCharacteristics convert(const V3_0::KeyCharacteristics& chars) {
+    KeyCharacteristics converted;
+    converted.hardwareEnforced = convert(chars.teeEnforced);
+    converted.softwareEnforced = convert(chars.softwareEnforced);
+    return converted;
+}
+
+}  // namespace
+
+void Keymaster3::getVersionIfNeeded() {
+    if (haveVersion_) return;
+
+    auto rc = km3_dev_->getHardwareFeatures(
+        [&](bool isSecure, bool supportsEllipticCurve, bool supportsSymmetricCryptography,
+            bool supportsAttestation, bool supportsAllDigests, const hidl_string& keymasterName,
+            const hidl_string& keymasterAuthorName) {
+            securityLevel_ =
+                isSecure ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE;
+            supportsEllipticCurve_ = supportsEllipticCurve;
+            supportsSymmetricCryptography_ = supportsSymmetricCryptography;
+            supportsAttestation_ = supportsAttestation;
+            supportsAllDigests_ = supportsAllDigests;
+            keymasterName_ = keymasterName;
+            authorName_ = keymasterAuthorName;
+        });
+
+    CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware features";
+
+    if (securityLevel_ == SecurityLevel::SOFTWARE) {
+        majorVersion_ = 3;
+    } else if (supportsAttestation_) {
+        majorVersion_ = 3;  // Could be 2, doesn't matter.
+    } else if (supportsSymmetricCryptography_) {
+        majorVersion_ = 1;
+    } else {
+        majorVersion_ = 0;
+    }
+}
+
+Keymaster::VersionResult Keymaster3::halVersion() {
+    getVersionIfNeeded();
+    return {ErrorCode::OK, majorVersion_, securityLevel_, supportsEllipticCurve_};
+}
+
+Return<void> Keymaster3::getHardwareInfo(Keymaster3::getHardwareInfo_cb _hidl_cb) {
+    getVersionIfNeeded();
+    _hidl_cb(securityLevel_, keymasterName_ + " (wrapped by keystore::Keymaster3)", authorName_);
+    return Void();
+}
+
+Return<ErrorCode> Keymaster3::addRngEntropy(const hidl_vec<uint8_t>& data) {
+    auto rc = km3_dev_->addRngEntropy(data);
+    if (!rc.isOk()) {
+        return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+    }
+    return convert(rc);
+}
+
+Return<void> Keymaster3::generateKey(const hidl_vec<KeyParameter>& keyParams,
+                                     generateKey_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
+                  const V3_0::KeyCharacteristics& characteristics) {
+        _hidl_cb(convert(error), keyBlob, convert(characteristics));
+    };
+    auto rc = km3_dev_->generateKey(convert(keyParams), cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<void> Keymaster3::getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+                                               const hidl_vec<uint8_t>& clientId,
+                                               const hidl_vec<uint8_t>& appData,
+                                               getKeyCharacteristics_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const V3_0::KeyCharacteristics& chars) {
+        _hidl_cb(convert(error), convert(chars));
+    };
+
+    auto rc = km3_dev_->getKeyCharacteristics(keyBlob, clientId, appData, cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<void> Keymaster3::importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+                                   const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& keyBlob,
+                  const V3_0::KeyCharacteristics& chars) {
+        _hidl_cb(convert(error), keyBlob, convert(chars));
+    };
+    auto rc = km3_dev_->importKey(convert(params), convert(keyFormat), keyData, cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<void> Keymaster3::exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+                                   const hidl_vec<uint8_t>& clientId,
+                                   const hidl_vec<uint8_t>& appData, exportKey_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& keyMaterial) {
+        _hidl_cb(convert(error), keyMaterial);
+    };
+    auto rc = km3_dev_->exportKey(convert(exportFormat), keyBlob, clientId, appData, cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<void> Keymaster3::attestKey(const hidl_vec<uint8_t>& keyToAttest,
+                                   const hidl_vec<KeyParameter>& attestParams,
+                                   attestKey_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
+        _hidl_cb(convert(error), certChain);
+    };
+    auto rc = km3_dev_->attestKey(keyToAttest, convert(attestParams), cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<void> Keymaster3::upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+                                    const hidl_vec<KeyParameter>& upgradeParams,
+                                    upgradeKey_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const hidl_vec<uint8_t>& upgradedKeyBlob) {
+        _hidl_cb(convert(error), upgradedKeyBlob);
+    };
+    auto rc = km3_dev_->upgradeKey(keyBlobToUpgrade, convert(upgradeParams), cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<ErrorCode> Keymaster3::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
+    auto rc = km3_dev_->deleteKey(keyBlob);
+    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+    return convert(rc);
+}
+
+Return<ErrorCode> Keymaster3::deleteAllKeys() {
+    auto rc = km3_dev_->deleteAllKeys();
+    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+    return convert(rc);
+}
+
+Return<ErrorCode> Keymaster3::destroyAttestationIds() {
+    auto rc = km3_dev_->destroyAttestationIds();
+    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+    return convert(rc);
+}
+
+Return<void> Keymaster3::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+                               const hidl_vec<KeyParameter>& inParams,
+                               const HardwareAuthToken& authToken, begin_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const hidl_vec<V3_0::KeyParameter>& outParams,
+                  OperationHandle operationHandle) {
+        _hidl_cb(convert(error), convert(outParams), operationHandle);
+    };
+
+    auto rc =
+        km3_dev_->begin(convert(purpose), key, convertAndAddAuthToken(inParams, authToken), cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<void> Keymaster3::update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                                const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+                                const VerificationToken& /* verificationToken */,
+                                update_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, uint32_t inputConsumed,
+                  const hidl_vec<V3_0::KeyParameter>& outParams, const hidl_vec<uint8_t>& output) {
+        _hidl_cb(convert(error), inputConsumed, convert(outParams), output);
+    };
+
+    auto rc =
+        km3_dev_->update(operationHandle, convertAndAddAuthToken(inParams, authToken), input, cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<void> Keymaster3::finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                                const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+                                const HardwareAuthToken& authToken,
+                                const VerificationToken& /* verificationToken */,
+                                finish_cb _hidl_cb) {
+    auto cb = [&](V3_0::ErrorCode error, const hidl_vec<V3_0::KeyParameter>& outParams,
+                  const hidl_vec<uint8_t>& output) {
+        _hidl_cb(convert(error), convert(outParams), output);
+    };
+
+    auto rc = km3_dev_->finish(operationHandle, convertAndAddAuthToken(inParams, authToken), input,
+                               signature, cb);
+    rc.isOk();  // move ctor prereq
+    return rc;
+}
+
+Return<ErrorCode> Keymaster3::abort(uint64_t operationHandle) {
+    auto rc = km3_dev_->abort(operationHandle);
+    if (!rc.isOk()) return StatusOf<V3_0::ErrorCode, ErrorCode>(rc);
+    return convert(rc);
+}
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.0/support/Keymaster4.cpp b/keymaster/4.0/support/Keymaster4.cpp
new file mode 100644
index 0000000..fdf78ae
--- /dev/null
+++ b/keymaster/4.0/support/Keymaster4.cpp
@@ -0,0 +1,48 @@
+/*
+**
+** Copyright 2017, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <keymasterV4_0/Keymaster4.h>
+
+#include <android-base/logging.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+void Keymaster4::getVersionIfNeeded() {
+    if (haveVersion_) return;
+
+    auto rc = dev_->getHardwareInfo([&](SecurityLevel securityLevel, auto...) {
+        securityLevel_ = securityLevel;
+        haveVersion_ = true;
+    });
+
+    CHECK(rc.isOk()) << "Got error " << rc.description() << " trying to get hardware info";
+}
+
+Keymaster::VersionResult Keymaster4::halVersion() {
+    getVersionIfNeeded();
+    return {ErrorCode::OK, halMajorVersion(), securityLevel_, true};
+}
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
diff --git a/keymaster/4.0/support/authorization_set.cpp b/keymaster/4.0/support/authorization_set.cpp
index de3e270..81cf365 100644
--- a/keymaster/4.0/support/authorization_set.cpp
+++ b/keymaster/4.0/support/authorization_set.cpp
@@ -441,6 +441,11 @@
     return Authorization(TAG_KEY_SIZE, key_size);
 }
 
+AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesKey(uint32_t key_size) {
+    Authorization(TAG_ALGORITHM, Algorithm::TRIPLE_DES);
+    return Authorization(TAG_KEY_SIZE, key_size);
+}
+
 AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) {
     Authorization(TAG_ALGORITHM, Algorithm::HMAC);
     Authorization(TAG_KEY_SIZE, key_size);
@@ -474,6 +479,11 @@
     return EncryptionKey();
 }
 
+AuthorizationSetBuilder& AuthorizationSetBuilder::TripleDesEncryptionKey(uint32_t key_size) {
+    TripleDesKey(key_size);
+    return EncryptionKey();
+}
+
 AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() {
     Authorization(TAG_PURPOSE, KeyPurpose::SIGN);
     return Authorization(TAG_PURPOSE, KeyPurpose::VERIFY);
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
new file mode 100644
index 0000000..2686fcd
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster.h
@@ -0,0 +1,58 @@
+/*
+ **
+ ** Copyright 2017, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
+
+#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+/**
+ * Keymaster abstracts the underlying V4_0::IKeymasterDevice.  There is one implementation
+ * (Keymaster4) which is a trivial passthrough and one that wraps a V3_0::IKeymasterDevice.
+ *
+ * The reason for adding this additional layer, rather than simply using the latest HAL directly and
+ * subclassing it to wrap any older HAL, is because this provides a place to put additional methods
+ * which clients can use when they need to distinguish between different underlying HAL versions,
+ * while still having to use only the latest interface.
+ */
+class Keymaster : public IKeymasterDevice {
+   public:
+    virtual ~Keymaster() {}
+
+    struct VersionResult {
+        ErrorCode error;
+        uint8_t majorVersion;
+        SecurityLevel securityLevel;
+        bool supportsEc;
+    };
+
+    virtual VersionResult halVersion() = 0;
+};
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
new file mode 100644
index 0000000..051e570
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster3.h
@@ -0,0 +1,129 @@
+/*
+ **
+ ** Copyright 2017, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
+
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
+
+#include "Keymaster.h"
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+using IKeymaster3Device = ::android::hardware::keymaster::V3_0::IKeymasterDevice;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::details::return_status;
+
+class Keymaster3 : public Keymaster {
+   public:
+    using WrappedIKeymasterDevice = IKeymaster3Device;
+    Keymaster3(sp<IKeymaster3Device> km3_dev) : km3_dev_(km3_dev), haveVersion_(false) {}
+
+    VersionResult halVersion() override;
+
+    Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb);
+
+    Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
+        _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+        return Void();
+    }
+
+    Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>&,
+                                   computeSharedHmac_cb _hidl_cb) override {
+        _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+        return Void();
+    }
+
+    Return<void> verifyAuthorization(uint64_t, const hidl_vec<KeyParameter>&,
+                                     const HardwareAuthToken&,
+                                     verifyAuthorization_cb _hidl_cb) override {
+        _hidl_cb(ErrorCode::UNIMPLEMENTED, {});
+        return Void();
+    }
+
+    Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
+    Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+                             generateKey_cb _hidl_cb) override;
+    Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+                                       const hidl_vec<uint8_t>& clientId,
+                                       const hidl_vec<uint8_t>& appData,
+                                       getKeyCharacteristics_cb _hidl_cb) override;
+    Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+                           const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override;
+
+    Return<void> importWrappedKey(const hidl_vec<uint8_t>&, const hidl_vec<uint8_t>&,
+                                  const hidl_vec<uint8_t>&, importWrappedKey_cb _hidl_cb) {
+        _hidl_cb(ErrorCode::UNIMPLEMENTED, {}, {});
+        return Void();
+    }
+
+    Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+                           const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+                           exportKey_cb _hidl_cb) override;
+    Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
+                           const hidl_vec<KeyParameter>& attestParams,
+                           attestKey_cb _hidl_cb) override;
+    Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+                            const hidl_vec<KeyParameter>& upgradeParams,
+                            upgradeKey_cb _hidl_cb) override;
+    Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
+    Return<ErrorCode> deleteAllKeys() override;
+    Return<ErrorCode> destroyAttestationIds() override;
+    Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+                       const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+                       begin_cb _hidl_cb) override;
+    Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                        const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+                        const VerificationToken& verificationToken, update_cb _hidl_cb) override;
+    Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                        const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+                        const HardwareAuthToken& authToken,
+                        const VerificationToken& verificationToken, finish_cb _hidl_cb) override;
+    Return<ErrorCode> abort(uint64_t operationHandle) override;
+
+   private:
+    void getVersionIfNeeded();
+
+    sp<IKeymaster3Device> km3_dev_;
+
+    bool haveVersion_;
+    uint8_t majorVersion_;
+    SecurityLevel securityLevel_;
+    bool supportsEllipticCurve_;
+    bool supportsSymmetricCryptography_;
+    bool supportsAttestation_;
+    bool supportsAllDigests_;
+    std::string keymasterName_;
+    std::string authorName_;
+};
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_3_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h b/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
new file mode 100644
index 0000000..ffddcac
--- /dev/null
+++ b/keymaster/4.0/support/include/keymasterV4_0/Keymaster4.h
@@ -0,0 +1,153 @@
+/*
+ **
+ ** Copyright 2017, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
+#define HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
+
+#include "Keymaster.h"
+
+namespace android {
+namespace hardware {
+namespace keymaster {
+namespace V4_0 {
+namespace support {
+
+using android::sp;
+using IKeymaster4Device = ::android::hardware::keymaster::V4_0::IKeymasterDevice;
+
+class Keymaster4 : public Keymaster {
+   public:
+    using WrappedIKeymasterDevice = IKeymaster4Device;
+    Keymaster4(sp<IKeymasterDevice> km4_dev) : haveVersion_(false), dev_(km4_dev) {}
+
+    uint8_t halMajorVersion() { return 4; }
+
+    VersionResult halVersion() override;
+
+    Return<void> getHardwareInfo(getHardwareInfo_cb _hidl_cb) override {
+        return dev_->getHardwareInfo(_hidl_cb);
+    }
+
+    Return<void> getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb) override {
+        return dev_->getHmacSharingParameters(_hidl_cb);
+    }
+
+    Return<void> computeSharedHmac(const hidl_vec<HmacSharingParameters>& params,
+                                   computeSharedHmac_cb _hidl_cb) override {
+        return dev_->computeSharedHmac(params, _hidl_cb);
+    }
+
+    Return<void> verifyAuthorization(uint64_t operationHandle, const hidl_vec<KeyParameter>& params,
+                                     const HardwareAuthToken& authToken,
+                                     verifyAuthorization_cb _hidl_cb) override {
+        return dev_->verifyAuthorization(operationHandle, params, authToken, _hidl_cb);
+    }
+
+    Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override {
+        return dev_->addRngEntropy(data);
+    }
+
+    Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+                             generateKey_cb _hidl_cb) override {
+        return dev_->generateKey(keyParams, _hidl_cb);
+    }
+
+    Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+                                       const hidl_vec<uint8_t>& clientId,
+                                       const hidl_vec<uint8_t>& appData,
+                                       getKeyCharacteristics_cb _hidl_cb) override {
+        return dev_->getKeyCharacteristics(keyBlob, clientId, appData, _hidl_cb);
+    }
+
+    Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+                           const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override {
+        return dev_->importKey(params, keyFormat, keyData, _hidl_cb);
+    }
+
+    Return<void> importWrappedKey(const hidl_vec<uint8_t>& wrappedKeyData,
+                                  const hidl_vec<uint8_t>& wrappingKeyBlob,
+                                  const hidl_vec<uint8_t>& maskingKey,
+                                  importWrappedKey_cb _hidl_cb) {
+        return dev_->importWrappedKey(wrappedKeyData, wrappingKeyBlob, maskingKey, _hidl_cb);
+    }
+
+    Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+                           const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+                           exportKey_cb _hidl_cb) override {
+        return dev_->exportKey(exportFormat, keyBlob, clientId, appData, _hidl_cb);
+    }
+
+    Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
+                           const hidl_vec<KeyParameter>& attestParams,
+                           attestKey_cb _hidl_cb) override {
+        return dev_->attestKey(keyToAttest, attestParams, _hidl_cb);
+    }
+
+    Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+                            const hidl_vec<KeyParameter>& upgradeParams,
+                            upgradeKey_cb _hidl_cb) override {
+        return dev_->upgradeKey(keyBlobToUpgrade, upgradeParams, _hidl_cb);
+    }
+
+    Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override {
+        return dev_->deleteKey(keyBlob);
+    }
+
+    Return<ErrorCode> deleteAllKeys() override { return dev_->deleteAllKeys(); }
+
+    Return<ErrorCode> destroyAttestationIds() override { return dev_->destroyAttestationIds(); }
+
+    Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+                       const hidl_vec<KeyParameter>& inParams, const HardwareAuthToken& authToken,
+                       begin_cb _hidl_cb) override {
+        return dev_->begin(purpose, key, inParams, authToken, _hidl_cb);
+    }
+
+    Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                        const hidl_vec<uint8_t>& input, const HardwareAuthToken& authToken,
+                        const VerificationToken& verificationToken, update_cb _hidl_cb) override {
+        return dev_->update(operationHandle, inParams, input, authToken, verificationToken,
+                            _hidl_cb);
+    }
+
+    Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+                        const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+                        const HardwareAuthToken& authToken,
+                        const VerificationToken& verificationToken, finish_cb _hidl_cb) override {
+        return dev_->finish(operationHandle, inParams, input, signature, authToken,
+                            verificationToken, _hidl_cb);
+    }
+
+    Return<ErrorCode> abort(uint64_t operationHandle) override {
+        return dev_->abort(operationHandle);
+    }
+
+   private:
+    void getVersionIfNeeded();
+
+    bool haveVersion_;
+    SecurityLevel securityLevel_;
+    sp<IKeymaster4Device> dev_;
+};
+
+}  // namespace support
+}  // namespace V4_0
+}  // namespace keymaster
+}  // namespace hardware
+}  // namespace android
+
+#endif  // HARDWARE_INTERFACES_KEYMASTER_40_SUPPORT_KEYMASTER_4_H_
diff --git a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
index f67f192..09a06fe 100644
--- a/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
+++ b/keymaster/4.0/support/include/keymasterV4_0/authorization_set.h
@@ -258,6 +258,7 @@
     AuthorizationSetBuilder& EcdsaKey(uint32_t key_size);
     AuthorizationSetBuilder& EcdsaKey(EcCurve curve);
     AuthorizationSetBuilder& AesKey(uint32_t key_size);
+    AuthorizationSetBuilder& TripleDesKey(uint32_t key_size);
     AuthorizationSetBuilder& HmacKey(uint32_t key_size);
 
     AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent);
@@ -265,6 +266,7 @@
     AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size);
     AuthorizationSetBuilder& EcdsaSigningKey(EcCurve curve);
     AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size);
+    AuthorizationSetBuilder& TripleDesEncryptionKey(uint32_t key_size);
 
     AuthorizationSetBuilder& SigningKey();
     AuthorizationSetBuilder& EncryptionKey();
diff --git a/keymaster/4.0/types.hal b/keymaster/4.0/types.hal
index 0c890bd..e31804d 100644
--- a/keymaster/4.0/types.hal
+++ b/keymaster/4.0/types.hal
@@ -136,6 +136,51 @@
                                                 * if device is still on-body (requires secure
                                                 * on-body sensor. */
 
+    /**
+     * TRUSTED_USER_PRESENCE_REQUIRED is an optional feature that specifies that this key must be
+     * unusable except when the user has provided proof of physical presence.  Proof of physical
+     * presence must be a signal that cannot be triggered by an attacker who doesn't have one of:
+     *
+     *    a) Physical control of the device or
+     *
+     *    b) Control of the secure environment that holds the key.
+     *
+     * For instance, proof of user identity may be considered proof of presence if it meets the
+     * requirements.  However, proof of identity established in one security domain (e.g. TEE) does
+     * not constitute proof of presence in another security domain (e.g. StrongBox), and no
+     * mechanism analogous to the authentication token is defined for communicating proof of
+     * presence across security domains.
+     *
+     * Some examples:
+     *
+     *     A hardware button hardwired to a pin on a StrongBox device in such a way that nothing
+     *     other than a button press can trigger the signal constitutes proof of physical presence
+     *     for StrongBox keys.
+     *
+     *     Fingerprint authentication provides proof of presence (and identity) for TEE keys if the
+     *     TEE has exclusive control of the fingerprint scanner and performs fingerprint matching.
+     *
+     *     Password authentication does not provide proof of presence to either TEE or StrongBox,
+     *     even if TEE or StrongBox does the password matching, because password input is handled by
+     *     the non-secure world, which means an attacker who has compromised Android can spoof
+     *     password authentication.
+     *
+     * Note that no mechanism is defined for delivering proof of presence to Keymaster,
+     * except perhaps as implied by an auth token.  This means that Keymaster must be able to check
+     * proof of presence some other way.  Further, the proof of presence must be performed between
+     * begin() and the first call to update() or finish().  If the first update() or the finish()
+     * call is made without proof of presence, the keymaster method must return
+     * ErrorCode::PROOF_OF_PRESENCE_REQUIRED and abort the operation.  The caller must delay the
+     * update() or finish() call until proof of presence has been provided, which means the caller
+     * must also have some mechanism for verifying that the proof has been provided.
+     *
+     * Only one operation requiring TUP may be in flight at a time.  If begin() has already been
+     * called on one key with TRUSTED_USER_PRESENCE_REQUIRED, and another begin() comes in for that
+     * key or another with TRUSTED_USER_PRESENCE_REQUIRED, Keymaster must return
+     * ErrorCode::CONCURRENT_PROOF_OF_PRESENCE_REQUESTED.
+     */
+    TRUSTED_USER_PRESENCE_REQUIRED = TagType:BOOL | 507,
+
     /* Application access control */
     APPLICATION_ID = TagType:BYTES | 601, /* Byte string identifying the authorized application. */
 
@@ -195,6 +240,7 @@
 
     /** Block ciphers algorithms */
     AES = 32,
+    TRIPLE_DES = 33,
 
     /** MAC algorithms */
     HMAC = 128,
@@ -381,6 +427,8 @@
     CANNOT_ATTEST_IDS = -66,
     ROLLBACK_RESISTANCE_UNAVAILABLE = -67,
     HARDWARE_TYPE_UNAVAILABLE = -68,
+    PROOF_OF_PRESENCE_REQUIRED = -69,
+    CONCURRENT_PROOF_OF_PRESENCE_REQUESTED = -70,
 
     UNIMPLEMENTED = -100,
     VERSION_MISMATCH = -101,
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index c8858de..b0bb68e 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -75,6 +75,7 @@
         case Tag::ALLOW_WHILE_ON_BODY:
         case Tag::ROLLBACK_RESISTANCE:
         case Tag::RESET_SINCE_ID_ROTATION:
+        case Tag::TRUSTED_USER_PRESENCE_REQUIRED:
             return true;
 
         /* Integer tags */
@@ -512,6 +513,26 @@
         return ImportKey(key_desc, format, key_material, &key_blob_, &key_characteristics_);
     }
 
+    ErrorCode ImportWrappedKey(string wrapped_key, string wrapping_key,
+                               const AuthorizationSet& wrapping_key_desc, string masking_key) {
+        ErrorCode error;
+
+        ImportKey(wrapping_key_desc, KeyFormat::PKCS8, wrapping_key);
+
+        EXPECT_TRUE(keymaster_
+                        ->importWrappedKey(HidlBuf(wrapped_key), key_blob_, HidlBuf(masking_key),
+                                           [&](ErrorCode hidl_error, const HidlBuf& hidl_key_blob,
+                                               const KeyCharacteristics& hidl_key_characteristics) {
+                                               error = hidl_error;
+                                               key_blob_ = hidl_key_blob;
+                                               key_characteristics_ = hidl_key_characteristics;
+
+                                           })
+                        .isOk());
+
+        return error;
+    }
+
     ErrorCode ExportKey(KeyFormat format, const HidlBuf& key_blob, const HidlBuf& client_id,
                         const HidlBuf& app_data, HidlBuf* key_material) {
         ErrorCode error;
@@ -674,6 +695,8 @@
         return error;
     }
 
+    ErrorCode Finish(string* output) { return Finish(string(), output); }
+
     ErrorCode Finish(const string& message, const string& signature, string* output) {
         SCOPED_TRACE("Finish");
         AuthorizationSet out_params;
@@ -803,6 +826,24 @@
         EXPECT_EQ(expected_ciphertext, ciphertext);
     }
 
+    void CheckTripleDesTestVector(KeyPurpose purpose, BlockMode block_mode,
+                                  PaddingMode padding_mode, const string& key, const string& iv,
+                                  const string& input, const string& expected_output) {
+        auto authset = AuthorizationSetBuilder()
+                           .TripleDesEncryptionKey(key.size() * 7)
+                           .BlockMode(block_mode)
+                           .Padding(padding_mode);
+        if (iv.size()) authset.Authorization(TAG_CALLER_NONCE);
+
+        ASSERT_EQ(ErrorCode::OK, ImportKey(authset, KeyFormat::RAW, key));
+
+        auto begin_params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding_mode);
+        if (iv.size()) begin_params.Authorization(TAG_NONCE, iv.data(), iv.size());
+        AuthorizationSet output_params;
+        string output = ProcessMessage(key_blob_, purpose, input, begin_params, &output_params);
+        EXPECT_EQ(expected_output, output);
+    }
+
     void VerifyMessage(const HidlBuf& key_blob, const string& message, const string& signature,
                        const AuthorizationSet& params) {
         SCOPED_TRACE("VerifyMessage");
@@ -847,6 +888,41 @@
         return ciphertext;
     }
 
+    string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding) {
+        SCOPED_TRACE("EncryptMessage");
+        auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding);
+        AuthorizationSet out_params;
+        string ciphertext = EncryptMessage(message, params, &out_params);
+        EXPECT_TRUE(out_params.empty())
+            << "Output params should be empty. Contained: " << out_params;
+        return ciphertext;
+    }
+
+    string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
+                          HidlBuf* iv) {
+        SCOPED_TRACE("EncryptMessage");
+        auto params = AuthorizationSetBuilder().BlockMode(block_mode).Padding(padding);
+        AuthorizationSet out_params;
+        string ciphertext = EncryptMessage(message, params, &out_params);
+        EXPECT_EQ(1U, out_params.size());
+        auto ivVal = out_params.GetTagValue(TAG_NONCE);
+        EXPECT_TRUE(ivVal.isOk());
+        *iv = ivVal.value();
+        return ciphertext;
+    }
+
+    string EncryptMessage(const string& message, BlockMode block_mode, PaddingMode padding,
+                          const HidlBuf& iv) {
+        SCOPED_TRACE("EncryptMessage");
+        auto params = AuthorizationSetBuilder()
+                          .BlockMode(block_mode)
+                          .Padding(padding)
+                          .Authorization(TAG_NONCE, iv);
+        AuthorizationSet out_params;
+        string ciphertext = EncryptMessage(message, params, &out_params);
+        return ciphertext;
+    }
+
     string DecryptMessage(const HidlBuf& key_blob, const string& ciphertext,
                           const AuthorizationSet& params) {
         SCOPED_TRACE("DecryptMessage");
@@ -862,6 +938,16 @@
         return DecryptMessage(key_blob_, ciphertext, params);
     }
 
+    string DecryptMessage(const string& ciphertext, BlockMode block_mode, PaddingMode padding_mode,
+                          const HidlBuf& iv) {
+        SCOPED_TRACE("DecryptMessage");
+        auto params = AuthorizationSetBuilder()
+                          .BlockMode(block_mode)
+                          .Padding(padding_mode)
+                          .Authorization(TAG_NONCE, iv);
+        return DecryptMessage(key_blob_, ciphertext, params);
+    }
+
     std::pair<ErrorCode, HidlBuf> UpgradeKey(const HidlBuf& key_blob) {
         std::pair<ErrorCode, HidlBuf> retval;
         keymaster_->upgradeKey(key_blob, hidl_vec<KeyParameter>(),
@@ -2421,6 +2507,111 @@
     VerifyMessage(message, signature, AuthorizationSetBuilder().Digest(Digest::SHA_2_256));
 }
 
+auto wrapped_key = hex2str(
+    "30820173020100048201006F5C273914D9E7EAB667FE62456A57DE64BED4A57DB3EFBB77E6907C82CC36B0BD12CB8A"
+    "85F3F8BC08A26C58186DB5C35636063388A04AE5579D3BDC057F9BB0EB6FDDA5E836DBB1F18A4546A64BA06E3D0132"
+    "AAA3306676638C786FAF0722E6E4145E0C91B009C422691F9F42F9F179DA93E16E7793DE5960E77A387433F0B43E49"
+    "3A7CF77ECA25BA724CC02F916D5792CAA76BC0756D3DB5D110D209B8B30285E9653D91FD89E953F351D82ACE1422CC"
+    "A146F8BD0C2F4CC32D1F81D894F4650043DB46109869696319A1A011BB003F2EBD8FA20B4A43F3226C1F182A39AE81"
+    "A35B9B7590A48B6A6874C9CC0EE0CD9528FB908688B4111932DF478CD7A92B50040CD796B02C370F1FA4CC0124F130"
+    "280201033023A1083106020100020101A203020120A30402020100A4053103020101A60531030201400420CCD54085"
+    "5F833A5E1480BFD2D36FAF3AEEE15DF5BEABE2691BC82DDE2A7AA91004107CB81BDDCD09E8F4DF575726279F3229");
+
+auto wrapped_key_masked = hex2str(
+    "30820173020100048201009059BB6E48F8036ABE1800D9C74F3DB5F20448F035C2C78AFBCC28AF26581061298CAC78"
+    "A8CA5B79721B60B74490555168488ED696C8930D00463C6FC81BF0B6E4E26C93E018D0E3DC8754C6B261E0A7C3A6DA"
+    "1A223EB59ACA8E13348F14B9E944AF3C224906C1ABFE21ADDEE81FC641D45E092C6B0A75A9BA56C05529AE47ECA0D5"
+    "CD3568501CF04D47391FC695EDE19A3022B347D1BDC6C792A08AA014F87DD4BBD44777B14D7D2273191DDCFE4E8512"
+    "EFA677A14E68E5D820C5513331D687C08B6317FA64D404231D05C74CDD9AEB89D253FBE07154B2080CF4ACA5E1EFCB"
+    "53EB193E8A01DD5F9634B65EF9B49899003E245FDA6A3B137FAC1263E55A6E1D040C6D9721D08589581AB49204A330"
+    "280201033023A1083106020100020101A203020120A30402020100A4053103020101A60531030201400420A61C6E24"
+    "7E25B3E6E69AA78EB03C2D4AC20D1F99A9A024A76F35C8E2CAB9B68D04101FF7A0E793B9EE4AECEBB9AC4C545254");
+
+auto wrapping_key = hex2str(
+    "308204be020100300d06092a864886f70d0101010500048204a8308204a40201000282010100aec367931d8900ce56"
+    "b0067f7d70e1fc653f3f34d194c1fed50018fb43db937b06e673a837313d56b1c725150a3fef86acbddc41bb759c28"
+    "54eae32d35841efb5c18d82bc90a1cb5c1d55adf245b02911f0b7cda88c421ff0ebafe7c0d23be312d7bd5921ffaea"
+    "1347c157406fef718f682643e4e5d33c6703d61c0cf7ac0bf4645c11f5c1374c3886427411c449796792e0bef75dec"
+    "858a2123c36753e02a95a96d7c454b504de385a642e0dfc3e60ac3a7ee4991d0d48b0172a95f9536f02ba13cecccb9"
+    "2b727db5c27e5b2f5cec09600b286af5cf14c42024c61ddfe71c2a8d7458f185234cb00e01d282f10f8fc6721d2aed"
+    "3f4833cca2bd8fa62821dd55020301000102820100431447b6251908112b1ee76f99f3711a52b6630960046c2de70d"
+    "e188d833f8b8b91e4d785caeeeaf4f0f74414e2cda40641f7fe24f14c67a88959bdb27766df9e710b630a03adc683b"
+    "5d2c43080e52bee71e9eaeb6de297a5fea1072070d181c822bccff087d63c940ba8a45f670feb29fb4484d1c95e6d2"
+    "579ba02aae0a00900c3ebf490e3d2cd7ee8d0e20c536e4dc5a5097272888cddd7e91f228b1c4d7474c55b8fcd618c4"
+    "a957bbddd5ad7407cc312d8d98a5caf7e08f4a0d6b45bb41c652659d5a5ba05b663737a8696281865ba20fbdd7f851"
+    "e6c56e8cbe0ddbbf24dc03b2d2cb4c3d540fb0af52e034a2d06698b128e5f101e3b51a34f8d8b4f8618102818100de"
+    "392e18d682c829266cc3454e1d6166242f32d9a1d10577753e904ea7d08bff841be5bac82a164c5970007047b8c517"
+    "db8f8f84e37bd5988561bdf503d4dc2bdb38f885434ae42c355f725c9a60f91f0788e1f1a97223b524b5357fdf72e2"
+    "f696bab7d78e32bf92ba8e1864eab1229e91346130748a6e3c124f9149d71c743502818100c95387c0f9d35f137b57"
+    "d0d65c397c5e21cc251e47008ed62a542409c8b6b6ac7f8967b3863ca645fcce49582a9aa17349db6c4a95affdae0d"
+    "ae612e1afac99ed39a2d934c880440aed8832f9843163a47f27f392199dc1202f9a0f9bd08308007cb1e4e7f583093"
+    "66a7de25f7c3c9b880677c068e1be936e81288815252a8a102818057ff8ca1895080b2cae486ef0adfd791fb0235c0"
+    "b8b36cd6c136e52e4085f4ea5a063212a4f105a3764743e53281988aba073f6e0027298e1c4378556e0efca0e14ece"
+    "1af76ad0b030f27af6f0ab35fb73a060d8b1a0e142fa2647e93b32e36d8282ae0a4de50ab7afe85500a16f43a64719"
+    "d6e2b9439823719cd08bcd03178102818100ba73b0bb28e3f81e9bd1c568713b101241acc607976c4ddccc90e65b65"
+    "56ca31516058f92b6e09f3b160ff0e374ec40d78ae4d4979fde6ac06a1a400c61dd31254186af30b22c10582a8a43e"
+    "34fe949c5f3b9755bae7baa7b7b7a6bd03b38cef55c86885fc6c1978b9cee7ef33da507c9df6b9277cff1e6aaa5d57"
+    "aca528466102818100c931617c77829dfb1270502be9195c8f2830885f57dba869536811e6864236d0c4736a0008a1"
+    "45af36b8357a7c3d139966d04c4e00934ea1aede3bb6b8ec841dc95e3f579751e2bfdfe27ae778983f959356210723"
+    "287b0affcc9f727044d48c373f1babde0724fa17a4fd4da0902c7c9b9bf27ba61be6ad02dfddda8f4e6822");
+
+string zero_masking_key =
+    hex2str("0000000000000000000000000000000000000000000000000000000000000000");
+string masking_key = hex2str("D796B02C370F1FA4CC0124F14EC8CBEBE987E825246265050F399A51FD477DFC");
+
+class ImportWrappedKeyTest : public KeymasterHidlTest {};
+
+TEST_F(ImportWrappedKeyTest, Success) {
+    auto wrapping_key_desc = AuthorizationSetBuilder()
+                                 .RsaEncryptionKey(2048, 65537)
+                                 .Digest(Digest::SHA1)
+                                 .Padding(PaddingMode::RSA_OAEP)
+                                 .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
+
+    ASSERT_EQ(ErrorCode::OK,
+              ImportWrappedKey(wrapped_key, wrapping_key, wrapping_key_desc, zero_masking_key));
+
+    string message = "Hello World!";
+    auto params = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+    string ciphertext = EncryptMessage(message, params);
+    string plaintext = DecryptMessage(ciphertext, params);
+    EXPECT_EQ(message, plaintext);
+}
+
+TEST_F(ImportWrappedKeyTest, SuccessMasked) {
+    auto wrapping_key_desc = AuthorizationSetBuilder()
+                                 .RsaEncryptionKey(2048, 65537)
+                                 .Digest(Digest::SHA1)
+                                 .Padding(PaddingMode::RSA_OAEP)
+                                 .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
+
+    ASSERT_EQ(ErrorCode::OK,
+              ImportWrappedKey(wrapped_key_masked, wrapping_key, wrapping_key_desc, masking_key));
+}
+
+TEST_F(ImportWrappedKeyTest, WrongMask) {
+    auto wrapping_key_desc = AuthorizationSetBuilder()
+                                 .RsaEncryptionKey(2048, 65537)
+                                 .Digest(Digest::SHA1)
+                                 .Padding(PaddingMode::RSA_OAEP)
+                                 .Authorization(TAG_PURPOSE, KeyPurpose::WRAP_KEY);
+
+    ASSERT_EQ(
+        ErrorCode::VERIFICATION_FAILED,
+        ImportWrappedKey(wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key));
+}
+
+TEST_F(ImportWrappedKeyTest, WrongPurpose) {
+    auto wrapping_key_desc = AuthorizationSetBuilder()
+                                 .RsaEncryptionKey(2048, 65537)
+                                 .Digest(Digest::SHA1)
+                                 .Padding(PaddingMode::RSA_OAEP);
+
+    ASSERT_EQ(
+        ErrorCode::INCOMPATIBLE_PURPOSE,
+        ImportWrappedKey(wrapped_key_masked, wrapping_key, wrapping_key_desc, zero_masking_key));
+}
+
 typedef KeymasterHidlTest EncryptionOperationsTest;
 
 /*
@@ -3712,6 +3903,535 @@
     EXPECT_TRUE(finish_out_params.empty());
 }
 
+/*
+ * EncryptionOperationsTest.TripleDesEcbRoundTripSuccess
+ *
+ * Verifies that 3DES is basically functional.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesEcbRoundTripSuccess) {
+    std::cout << "Hello" << std::endl;
+
+    auto auths = AuthorizationSetBuilder()
+                     .TripleDesEncryptionKey(112)
+                     .BlockMode(BlockMode::ECB)
+                     .Padding(PaddingMode::NONE);
+
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(auths));
+    // Two-block message.
+    string message = "1234567890123456";
+    auto inParams = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+    string ciphertext1 = EncryptMessage(message, inParams);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    string ciphertext2 = EncryptMessage(string(message), inParams);
+    EXPECT_EQ(message.size(), ciphertext2.size());
+
+    // ECB is deterministic.
+    EXPECT_EQ(ciphertext1, ciphertext2);
+
+    string plaintext = DecryptMessage(ciphertext1, inParams);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbNotAuthorized
+ *
+ * Verifies that CBC keys reject ECB usage.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesEcbNotAuthorized) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+
+    auto inParams = AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_BLOCK_MODE, Begin(KeyPurpose::ENCRYPT, inParams));
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbPkcs7Padding
+ *
+ * Tests ECB mode with PKCS#7 padding, various message sizes.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesEcbPkcs7Padding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::ECB)
+                                             .Padding(PaddingMode::PKCS7)));
+
+    for (size_t i = 0; i < 32; ++i) {
+        string message(i, 'a');
+        auto inParams =
+            AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+        string ciphertext = EncryptMessage(message, inParams);
+        EXPECT_EQ(i + 8 - (i % 8), ciphertext.size());
+        string plaintext = DecryptMessage(ciphertext, inParams);
+        EXPECT_EQ(message, plaintext);
+    }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbNoPaddingKeyWithPkcs7Padding
+ *
+ * Verifies that keys configured for no padding reject PKCS7 padding
+ */
+TEST_F(EncryptionOperationsTest, TripleDesEcbNoPaddingKeyWithPkcs7Padding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::ECB)
+                                             .Padding(PaddingMode::NONE)));
+    for (size_t i = 0; i < 32; ++i) {
+        auto inParams =
+            AuthorizationSetBuilder().BlockMode(BlockMode::ECB).Padding(PaddingMode::PKCS7);
+        EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, inParams));
+    }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesEcbPkcs7PaddingCorrupted
+ *
+ * Verifies that corrupted padding is detected.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesEcbPkcs7PaddingCorrupted) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::ECB)
+                                             .Padding(PaddingMode::PKCS7)));
+
+    string message = "a";
+    string ciphertext = EncryptMessage(message, BlockMode::ECB, PaddingMode::PKCS7);
+    EXPECT_EQ(8U, ciphertext.size());
+    EXPECT_NE(ciphertext, message);
+    ++ciphertext[ciphertext.size() / 2];
+
+    AuthorizationSetBuilder begin_params;
+    begin_params.push_back(TAG_BLOCK_MODE, BlockMode::ECB);
+    begin_params.push_back(TAG_PADDING, PaddingMode::PKCS7);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+    string plaintext;
+    size_t input_consumed;
+    EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
+}
+
+struct TripleDesTestVector {
+    const char* name;
+    const KeyPurpose purpose;
+    const BlockMode block_mode;
+    const PaddingMode padding_mode;
+    const char* key;
+    const char* iv;
+    const char* input;
+    const char* output;
+};
+
+// These test vectors are from NIST CAVP, plus a few custom variants to test padding, since all of
+// the NIST vectors are multiples of the block size.
+static const TripleDesTestVector kTripleDesTestVectors[] = {
+    {
+        "TECBMMT2 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "ad192fd064b5579e7a4fb3c8f794f22a",  // key
+        "",                                  // IV
+        "13bad542f3652d67",                  // input
+        "908e543cf2cb254f",                  // output
+    },
+    {
+        "TECBMMT2 Encrypt 0 PKCS7", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::PKCS7,
+        "ad192fd064b5579e7a4fb3c8f794f22a",  // key
+        "",                                  // IV
+        "13bad542f3652d6700",                // input
+        "908e543cf2cb254fc40165289a89008c",  // output
+    },
+    {
+        "TECBMMT2 Encrypt 0 PKCS7 decrypted", KeyPurpose::DECRYPT, BlockMode::ECB,
+        PaddingMode::PKCS7,
+        "ad192fd064b5579e7a4fb3c8f794f22a",  // key
+        "",                                  // IV
+        "908e543cf2cb254fc40165289a89008c",  // input
+        "13bad542f3652d6700",                // output
+    },
+    {
+        "TECBMMT2 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "259df16e7af804fe83b90e9bf7c7e557",  // key
+        "",                                  // IV
+        "a4619c433bbd6787c07c81728f9ac9fa",  // input
+        "9e06de155c483c6bcfd834dbc8bd5830",  // output
+    },
+    {
+        "TECBMMT2 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "b32ff42092024adf2076b9d3d9f19e6d",  // key
+        "",                                  // IV
+        "2f3f2a49bba807a5",                  // input
+        "2249973fa135fb52",                  // output
+    },
+    {
+        "TECBMMT2 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "023dfbe6621aa17cc219eae9cdecd923",  // key
+        "",                                  // IV
+        "54045dc71d8d565b227ec19f06fef912",  // input
+        "9b071622181e6412de6066429401410d",  // output
+    },
+    {
+        "TECBMMT3 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "a2b5bc67da13dc92cd9d344aa238544a0e1fa79ef76810cd",  // key
+        "",                                                  // IV
+        "329d86bdf1bc5af4",                                  // input
+        "d946c2756d78633f",                                  // output
+    },
+    {
+        "TECBMMT3 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "49e692290d2a5e46bace79b9648a4c5d491004c262dc9d49",  // key
+        "",                                                  // IV
+        "6b1540781b01ce1997adae102dbf3c5b",                  // input
+        "4d0dc182d6e481ac4a3dc6ab6976ccae",                  // output
+    },
+    {
+        "TECBMMT3 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "52daec2ac7dc1958377392682f37860b2cc1ea2304bab0e9",  // key
+        "",                                                  // IV
+        "6daad94ce08acfe7",                                  // input
+        "660e7d32dcc90e79",                                  // output
+    },
+    {
+        "TECBMMT3 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::ECB, PaddingMode::NONE,
+        "7f8fe3d3f4a48394fb682c2919926d6ddfce8932529229ce",  // key
+        "",                                                  // IV
+        "e9653a0a1f05d31b9acd12d73aa9879d",                  // input
+        "9b2ae9d998efe62f1b592e7e1df8ff38",                  // output
+    },
+    {
+        "TCBCMMT2 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "34a41a8c293176c1b30732ecfe38ae8a",  // key
+        "f55b4855228bd0b4",                  // IV
+        "7dd880d2a9ab411c",                  // input
+        "c91892948b6cadb4",                  // output
+    },
+    {
+        "TCBCMMT2 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "70a88fa1dfb9942fa77f40157ffef2ad",  // key
+        "ece08ce2fdc6ce80",                  // IV
+        "bc225304d5a3a5c9918fc5006cbc40cc",  // input
+        "27f67dc87af7ddb4b68f63fa7c2d454a",  // output
+    },
+    {
+        "TCBCMMT2 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "4ff47fda89209bda8c85f7fe80192007",  // key
+        "d5bc4891dabe48b9",                  // IV
+        "7e154b28c353adef",                  // input
+        "712b961ea9a1d0af",                  // output
+    },
+    {
+        "TCBCMMT2 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "464092cdbf736d38fb1fe6a12a94ae0e",  // key
+        "5423455f00023b01",                  // IV
+        "3f6050b74ed64416bc23d53b0469ed7a",  // input
+        "9cbe7d1b5cdd1864c3095ba810575960",  // output
+    },
+    {
+        "TCBCMMT3 Encrypt 0", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "b5cb1504802326c73df186e3e352a20de643b0d63ee30e37",  // key
+        "43f791134c5647ba",                                  // IV
+        "dcc153cef81d6f24",                                  // input
+        "92538bd8af18d3ba",                                  // output
+    },
+    {
+        "TCBCMMT3 Encrypt 1", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358",  // key
+        "c2e999cb6249023c",                                  // IV
+        "c689aee38a301bb316da75db36f110b5",                  // input
+        "e9afaba5ec75ea1bbe65506655bb4ecb",                  // output
+    },
+    {
+        "TCBCMMT3 Encrypt 1 PKCS7 variant", KeyPurpose::ENCRYPT, BlockMode::CBC, PaddingMode::PKCS7,
+        "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358",  // key
+        "c2e999cb6249023c",                                  // IV
+        "c689aee38a301bb316da75db36f110b500",                // input
+        "e9afaba5ec75ea1bbe65506655bb4ecb825aa27ec0656156",  // output
+    },
+    {
+        "TCBCMMT3 Encrypt 1 PKCS7 decrypted", KeyPurpose::DECRYPT, BlockMode::CBC,
+        PaddingMode::PKCS7,
+        "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358",  // key
+        "c2e999cb6249023c",                                  // IV
+        "e9afaba5ec75ea1bbe65506655bb4ecb825aa27ec0656156",  // input
+        "c689aee38a301bb316da75db36f110b500",                // output
+    },
+    {
+        "TCBCMMT3 Decrypt 0", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "5eb6040d46082c7aa7d06dfd08dfeac8c18364c1548c3ba1",  // key
+        "41746c7e442d3681",                                  // IV
+        "c53a7b0ec40600fe",                                  // input
+        "d4f00eb455de1034",                                  // output
+    },
+    {
+        "TCBCMMT3 Decrypt 1", KeyPurpose::DECRYPT, BlockMode::CBC, PaddingMode::NONE,
+        "5b1cce7c0dc1ec49130dfb4af45785ab9179e567f2c7d549",  // key
+        "3982bc02c3727d45",                                  // IV
+        "6006f10adef52991fcc777a1238bbb65",                  // input
+        "edae09288e9e3bc05746d872b48e3b29",                  // output
+    },
+};
+
+/*
+ * EncryptionOperationsTest.TripleDesTestVector
+ *
+ * Verifies that NIST (plus a few extra) test vectors produce the correct results.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesTestVector) {
+    constexpr size_t num_tests = sizeof(kTripleDesTestVectors) / sizeof(TripleDesTestVector);
+    for (auto* test = kTripleDesTestVectors; test < kTripleDesTestVectors + num_tests; ++test) {
+        SCOPED_TRACE(test->name);
+        CheckTripleDesTestVector(test->purpose, test->block_mode, test->padding_mode,
+                                 hex2str(test->key), hex2str(test->iv), hex2str(test->input),
+                                 hex2str(test->output));
+    }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcRoundTripSuccess
+ *
+ * Validates CBC mode functionality.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcRoundTripSuccess) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+    // Two-block message.
+    string message = "1234567890123456";
+    HidlBuf iv1;
+    string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv1);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+
+    HidlBuf iv2;
+    string ciphertext2 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv2);
+    EXPECT_EQ(message.size(), ciphertext2.size());
+
+    // IVs should be random, so ciphertexts should differ.
+    EXPECT_NE(iv1, iv2);
+    EXPECT_NE(ciphertext1, ciphertext2);
+
+    string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv1);
+    EXPECT_EQ(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCallerIv
+ *
+ * Validates that 3DES keys can allow caller-specified IVs, and use them correctly.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCallerIv) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Authorization(TAG_CALLER_NONCE)
+                                             .Padding(PaddingMode::NONE)));
+    string message = "1234567890123456";
+    HidlBuf iv;
+    // Don't specify IV, should get a random one.
+    string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+    EXPECT_EQ(8U, iv.size());
+
+    string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv);
+    EXPECT_EQ(message, plaintext);
+
+    // Now specify an IV, should also work.
+    iv = HidlBuf("abcdefgh");
+    string ciphertext2 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, iv);
+
+    // Decrypt with correct IV.
+    plaintext = DecryptMessage(ciphertext2, BlockMode::CBC, PaddingMode::NONE, iv);
+    EXPECT_EQ(message, plaintext);
+
+    // Now try with wrong IV.
+    plaintext = DecryptMessage(ciphertext2, BlockMode::CBC, PaddingMode::NONE, HidlBuf("aaaaaaaa"));
+    EXPECT_NE(message, plaintext);
+}
+
+/*
+ * EncryptionOperationsTest, TripleDesCallerNonceProhibited.
+ *
+ * Verifies that 3DES keys without TAG_CALLER_NONCE do not allow caller-specified IVS.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCallerNonceProhibited) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+
+    string message = "12345678901234567890123456789012";
+    HidlBuf iv;
+    // Don't specify nonce, should get a random one.
+    string ciphertext1 = EncryptMessage(message, BlockMode::CBC, PaddingMode::NONE, &iv);
+    EXPECT_EQ(message.size(), ciphertext1.size());
+    EXPECT_EQ(8U, iv.size());
+
+    string plaintext = DecryptMessage(ciphertext1, BlockMode::CBC, PaddingMode::NONE, iv);
+    EXPECT_EQ(message, plaintext);
+
+    // Now specify a nonce, should fail.
+    auto input_params = AuthorizationSetBuilder()
+                            .Authorization(TAG_NONCE, HidlBuf("abcdefgh"))
+                            .BlockMode(BlockMode::CBC)
+                            .Padding(PaddingMode::NONE);
+    AuthorizationSet output_params;
+    EXPECT_EQ(ErrorCode::CALLER_NONCE_PROHIBITED,
+              Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcNotAuthorized
+ *
+ * Verifies that 3DES ECB-only keys do not allow CBC usage.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcNotAuthorized) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::ECB)
+                                             .Padding(PaddingMode::NONE)));
+    // Two-block message.
+    string message = "1234567890123456";
+    auto begin_params =
+        AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    EXPECT_EQ(ErrorCode::INCOMPATIBLE_BLOCK_MODE, Begin(KeyPurpose::ENCRYPT, begin_params));
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcNoPaddingWrongInputSize
+ *
+ * Verifies that unpadded CBC operations reject inputs that are not a multiple of block size.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcNoPaddingWrongInputSize) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+    // Message is slightly shorter than two blocks.
+    string message = "123456789012345";
+
+    auto begin_params =
+        AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    AuthorizationSet output_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, begin_params, &output_params));
+    string ciphertext;
+    EXPECT_EQ(ErrorCode::INVALID_INPUT_LENGTH, Finish(message, "", &ciphertext));
+}
+
+/*
+ * EncryptionOperationsTest, TripleDesCbcPkcs7Padding.
+ *
+ * Verifies that PKCS7 padding works correctly in CBC mode.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcPkcs7Padding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::PKCS7)));
+
+    // Try various message lengths; all should work.
+    for (size_t i = 0; i < 32; ++i) {
+        string message(i, 'a');
+        HidlBuf iv;
+        string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv);
+        EXPECT_EQ(i + 8 - (i % 8), ciphertext.size());
+        string plaintext = DecryptMessage(ciphertext, BlockMode::CBC, PaddingMode::PKCS7, iv);
+        EXPECT_EQ(message, plaintext);
+    }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcNoPaddingKeyWithPkcs7Padding
+ *
+ * Verifies that a key that requires PKCS7 padding cannot be used in unpadded mode.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcNoPaddingKeyWithPkcs7Padding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+
+    // Try various message lengths; all should fail.
+    for (size_t i = 0; i < 32; ++i) {
+        auto begin_params =
+            AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::PKCS7);
+        EXPECT_EQ(ErrorCode::INCOMPATIBLE_PADDING_MODE, Begin(KeyPurpose::ENCRYPT, begin_params));
+    }
+}
+
+/*
+ * EncryptionOperationsTest.TripleDesCbcPkcs7PaddingCorrupted
+ *
+ * Verifies that corrupted PKCS7 padding is rejected during decryption.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcPkcs7PaddingCorrupted) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::PKCS7)));
+
+    string message = "a";
+    HidlBuf iv;
+    string ciphertext = EncryptMessage(message, BlockMode::CBC, PaddingMode::PKCS7, &iv);
+    EXPECT_EQ(8U, ciphertext.size());
+    EXPECT_NE(ciphertext, message);
+    ++ciphertext[ciphertext.size() / 2];
+
+    auto begin_params = AuthorizationSetBuilder()
+                            .BlockMode(BlockMode::CBC)
+                            .Padding(PaddingMode::PKCS7)
+                            .Authorization(TAG_NONCE, iv);
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, begin_params));
+    string plaintext;
+    size_t input_consumed;
+    EXPECT_EQ(ErrorCode::OK, Update(ciphertext, &plaintext, &input_consumed));
+    EXPECT_EQ(ciphertext.size(), input_consumed);
+    EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, Finish(&plaintext));
+}
+
+/*
+ * EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding.
+ *
+ * Verifies that 3DES CBC works with many different input sizes.
+ */
+TEST_F(EncryptionOperationsTest, TripleDesCbcIncrementalNoPadding) {
+    ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+                                             .TripleDesEncryptionKey(112)
+                                             .BlockMode(BlockMode::CBC)
+                                             .Padding(PaddingMode::NONE)));
+
+    int increment = 7;
+    string message(240, 'a');
+    AuthorizationSet input_params =
+        AuthorizationSetBuilder().BlockMode(BlockMode::CBC).Padding(PaddingMode::NONE);
+    AuthorizationSet output_params;
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::ENCRYPT, input_params, &output_params));
+
+    string ciphertext;
+    size_t input_consumed;
+    for (size_t i = 0; i < message.size(); i += increment)
+        EXPECT_EQ(ErrorCode::OK,
+                  Update(message.substr(i, increment), &ciphertext, &input_consumed));
+    EXPECT_EQ(ErrorCode::OK, Finish(&ciphertext));
+    EXPECT_EQ(message.size(), ciphertext.size());
+
+    // Move TAG_NONCE into input_params
+    input_params = output_params;
+    input_params.push_back(TAG_BLOCK_MODE, BlockMode::CBC);
+    input_params.push_back(TAG_PADDING, PaddingMode::NONE);
+    output_params.Clear();
+
+    EXPECT_EQ(ErrorCode::OK, Begin(KeyPurpose::DECRYPT, input_params, &output_params));
+    string plaintext;
+    for (size_t i = 0; i < ciphertext.size(); i += increment)
+        EXPECT_EQ(ErrorCode::OK,
+                  Update(ciphertext.substr(i, increment), &plaintext, &input_consumed));
+    EXPECT_EQ(ErrorCode::OK, Finish(&plaintext));
+    EXPECT_EQ(ciphertext.size(), plaintext.size());
+    EXPECT_EQ(message, plaintext);
+}
+
 typedef KeymasterHidlTest MaxOperationsTest;
 
 /*
diff --git a/radio/1.2/IRadioIndication.hal b/radio/1.2/IRadioIndication.hal
index 4aae74d..e87bb5b 100644
--- a/radio/1.2/IRadioIndication.hal
+++ b/radio/1.2/IRadioIndication.hal
@@ -37,4 +37,13 @@
      *        the device
      */
     oneway simSlotsStatusChanged(RadioIndicationType type, vec<SimSlotStatus> slotStatus);
+
+    /**
+     * Request all of the current cell information known to the radio.
+     * Same information as returned by getCellInfoList() in 1.0::IRadio.
+     *
+     * @param type Type of radio indication
+     * @param records Current cell information known to radio
+     */
+     oneway cellInfoList_1_2(RadioIndicationType type, vec<CellInfo> records);
 };
diff --git a/soundtrigger/2.0/default/Android.bp b/soundtrigger/2.0/default/Android.bp
new file mode 100644
index 0000000..cc20f91
--- /dev/null
+++ b/soundtrigger/2.0/default/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "android.hardware.soundtrigger@2.0-core",
+    defaults: ["hidl_defaults"],
+    vendor_available: true,
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "SoundTriggerHalImpl.cpp",
+    ],
+
+    export_include_dirs: ["."],
+
+    shared_libs: [
+        "libhidlbase",
+        "libhidltransport",
+        "liblog",
+        "libutils",
+        "libhardware",
+        "android.hardware.soundtrigger@2.0",
+        "android.hardware.audio.common@2.0",
+    ],
+
+    header_libs: [
+        "libaudio_system_headers",
+        "libhardware_headers",
+    ],
+}
diff --git a/soundtrigger/2.0/default/Android.mk b/soundtrigger/2.0/default/Android.mk
index 9262858..835a020 100644
--- a/soundtrigger/2.0/default/Android.mk
+++ b/soundtrigger/2.0/default/Android.mk
@@ -18,23 +18,20 @@
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := android.hardware.soundtrigger@2.0-impl
-LOCAL_PROPRIETARY_MODULE := true
+LOCAL_VENDOR_MODULE := true
 LOCAL_MODULE_RELATIVE_PATH := hw
 LOCAL_SRC_FILES := \
-    SoundTriggerHalImpl.cpp
+    FetchISoundTriggerHw.cpp
 
 LOCAL_CFLAGS := -Wall -Werror
 
 LOCAL_SHARED_LIBRARIES := \
-        libhidlbase \
-        libhidltransport \
-        liblog \
-        libutils \
         libhardware \
+        libutils \
         android.hardware.soundtrigger@2.0 \
-        android.hardware.audio.common@2.0
+        android.hardware.soundtrigger@2.0-core
 
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+LOCAL_C_INCLUDE_DIRS := $(LOCAL_PATH)
 
 ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
 LOCAL_MULTILIB := 32
diff --git a/soundtrigger/2.0/default/FetchISoundTriggerHw.cpp b/soundtrigger/2.0/default/FetchISoundTriggerHw.cpp
new file mode 100644
index 0000000..bd99221
--- /dev/null
+++ b/soundtrigger/2.0/default/FetchISoundTriggerHw.cpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SoundTriggerHalImpl.h"
+
+extern "C" ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(
+    const char* /* name */) {
+    return (new ::android::hardware::soundtrigger::V2_0::implementation::SoundTriggerHalImpl())
+        ->getInterface();
+}
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp b/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
index f963fb1..612772c 100644
--- a/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
+++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.cpp
@@ -17,9 +17,8 @@
 #define LOG_TAG "SoundTriggerHalImpl"
 //#define LOG_NDEBUG 0
 
-#include <android/log.h>
 #include "SoundTriggerHalImpl.h"
-
+#include <android/log.h>
 
 namespace android {
 namespace hardware {
@@ -28,64 +27,45 @@
 namespace implementation {
 
 // static
-void SoundTriggerHalImpl::soundModelCallback(struct sound_trigger_model_event *halEvent,
-                                               void *cookie)
-{
+void SoundTriggerHalImpl::soundModelCallback(struct sound_trigger_model_event* halEvent,
+                                             void* cookie) {
     if (halEvent == NULL) {
         ALOGW("soundModelCallback called with NULL event");
         return;
     }
     sp<SoundModelClient> client =
-            wp<SoundModelClient>(static_cast<SoundModelClient *>(cookie)).promote();
+        wp<SoundModelClient>(static_cast<SoundModelClient*>(cookie)).promote();
     if (client == 0) {
         ALOGW("soundModelCallback called on stale client");
         return;
     }
-    if (halEvent->model != client->mHalHandle) {
+    if (halEvent->model != client->getHalHandle()) {
         ALOGW("soundModelCallback call with wrong handle %d on client with handle %d",
-              (int)halEvent->model, (int)client->mHalHandle);
+              (int)halEvent->model, (int)client->getHalHandle());
         return;
     }
 
-    ISoundTriggerHwCallback::ModelEvent event;
-    convertSoundModelEventFromHal(&event, halEvent);
-    event.model = client->mId;
-
-    client->mCallback->soundModelCallback(event, client->mCookie);
+    client->soundModelCallback(halEvent);
 }
 
 // static
-void SoundTriggerHalImpl::recognitionCallback(struct sound_trigger_recognition_event *halEvent,
-                                               void *cookie)
-{
+void SoundTriggerHalImpl::recognitionCallback(struct sound_trigger_recognition_event* halEvent,
+                                              void* cookie) {
     if (halEvent == NULL) {
         ALOGW("recognitionCallback call NULL event");
         return;
     }
     sp<SoundModelClient> client =
-            wp<SoundModelClient>(static_cast<SoundModelClient *>(cookie)).promote();
+        wp<SoundModelClient>(static_cast<SoundModelClient*>(cookie)).promote();
     if (client == 0) {
         ALOGW("soundModelCallback called on stale client");
         return;
     }
 
-    ISoundTriggerHwCallback::RecognitionEvent *event = convertRecognitionEventFromHal(halEvent);
-    event->model = client->mId;
-    if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
-        client->mCallback->phraseRecognitionCallback(
-                *(reinterpret_cast<ISoundTriggerHwCallback::PhraseRecognitionEvent *>(event)),
-                client->mCookie);
-    } else {
-        client->mCallback->recognitionCallback(*event, client->mCookie);
-    }
-    delete event;
+    client->recognitionCallback(halEvent);
 }
 
-
-
-// Methods from ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw follow.
-Return<void> SoundTriggerHalImpl::getProperties(getProperties_cb _hidl_cb)
-{
+Return<void> SoundTriggerHalImpl::getProperties(ISoundTriggerHw::getProperties_cb _hidl_cb) {
     ALOGV("getProperties() mHwDevice %p", mHwDevice);
     int ret;
     struct sound_trigger_properties halProperties;
@@ -100,8 +80,8 @@
 
     convertPropertiesFromHal(&properties, &halProperties);
 
-    ALOGV("getProperties implementor %s recognitionModes %08x",
-          properties.implementor.c_str(), properties.recognitionModes);
+    ALOGV("getProperties implementor %s recognitionModes %08x", properties.implementor.c_str(),
+          properties.recognitionModes);
 
 exit:
     _hidl_cb(ret, properties);
@@ -109,14 +89,9 @@
 }
 
 int SoundTriggerHalImpl::doLoadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
-                                                 const sp<ISoundTriggerHwCallback>& callback,
-                                                 ISoundTriggerHwCallback::CallbackCookie cookie,
-                                                 uint32_t *modelId)
-{
+                                          sp<SoundModelClient> client) {
     int32_t ret = 0;
-    struct sound_trigger_sound_model *halSoundModel;
-    *modelId = 0;
-    sp<SoundModelClient> client;
+    struct sound_trigger_sound_model* halSoundModel;
 
     ALOGV("doLoadSoundModel() data size %zu", soundModel.data.size());
 
@@ -131,19 +106,9 @@
         goto exit;
     }
 
-    {
-        AutoMutex lock(mLock);
-        do {
-            *modelId = nextUniqueId();
-        } while (mClients.valueFor(*modelId) != 0 && *modelId != 0);
-    }
-    LOG_ALWAYS_FATAL_IF(*modelId == 0,
-                        "wrap around in sound model IDs, num loaded models %zu", mClients.size());
-
-    client = new SoundModelClient(*modelId, callback, cookie);
-
-    ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback,
-                                          client.get(), &client->mHalHandle);
+    sound_model_handle_t halHandle;
+    ret = mHwDevice->load_sound_model(mHwDevice, halSoundModel, soundModelCallback, client.get(),
+                                      &halHandle);
 
     free(halSoundModel);
 
@@ -151,9 +116,10 @@
         goto exit;
     }
 
+    client->setHalHandle(halHandle);
     {
         AutoMutex lock(mLock);
-        mClients.add(*modelId, client);
+        mClients.add(client->getId(), client);
     }
 
 exit:
@@ -163,31 +129,23 @@
 Return<void> SoundTriggerHalImpl::loadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
                                                  const sp<ISoundTriggerHwCallback>& callback,
                                                  ISoundTriggerHwCallback::CallbackCookie cookie,
-                                                 loadSoundModel_cb _hidl_cb)
-{
-    uint32_t modelId = 0;
-    int32_t ret = doLoadSoundModel(soundModel, callback, cookie, &modelId);
-
-    _hidl_cb(ret, modelId);
+                                                 ISoundTriggerHw::loadSoundModel_cb _hidl_cb) {
+    sp<SoundModelClient> client = new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback);
+    _hidl_cb(doLoadSoundModel(soundModel, client), client->getId());
     return Void();
 }
 
 Return<void> SoundTriggerHalImpl::loadPhraseSoundModel(
-                                            const ISoundTriggerHw::PhraseSoundModel& soundModel,
-                                            const sp<ISoundTriggerHwCallback>& callback,
-                                            ISoundTriggerHwCallback::CallbackCookie cookie,
-                                            ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb)
-{
-    uint32_t modelId = 0;
-    int32_t ret = doLoadSoundModel((const ISoundTriggerHw::SoundModel&)soundModel,
-                                   callback, cookie, &modelId);
-
-    _hidl_cb(ret, modelId);
+    const ISoundTriggerHw::PhraseSoundModel& soundModel,
+    const sp<ISoundTriggerHwCallback>& callback, ISoundTriggerHwCallback::CallbackCookie cookie,
+    ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb) {
+    sp<SoundModelClient> client = new SoundModelClient_2_0(nextUniqueModelId(), cookie, callback);
+    _hidl_cb(doLoadSoundModel((const ISoundTriggerHw::SoundModel&)soundModel, client),
+             client->getId());
     return Void();
 }
 
-Return<int32_t> SoundTriggerHalImpl::unloadSoundModel(SoundModelHandle modelHandle)
-{
+Return<int32_t> SoundTriggerHalImpl::unloadSoundModel(SoundModelHandle modelHandle) {
     int32_t ret;
     sp<SoundModelClient> client;
 
@@ -205,7 +163,7 @@
         }
     }
 
-    ret = mHwDevice->unload_sound_model(mHwDevice, client->mHalHandle);
+    ret = mHwDevice->unload_sound_model(mHwDevice, client->getHalHandle());
 
     mClients.removeItem(modelHandle);
 
@@ -213,14 +171,11 @@
     return ret;
 }
 
-Return<int32_t> SoundTriggerHalImpl::startRecognition(SoundModelHandle modelHandle,
-                                           const ISoundTriggerHw::RecognitionConfig& config,
-                                           const sp<ISoundTriggerHwCallback>& callback __unused,
-                                           ISoundTriggerHwCallback::CallbackCookie cookie __unused)
-{
+Return<int32_t> SoundTriggerHalImpl::startRecognition(
+    SoundModelHandle modelHandle, const ISoundTriggerHw::RecognitionConfig& config) {
     int32_t ret;
     sp<SoundModelClient> client;
-    struct sound_trigger_recognition_config *halConfig;
+    struct sound_trigger_recognition_config* halConfig;
 
     if (mHwDevice == NULL) {
         ret = -ENODEV;
@@ -236,15 +191,14 @@
         }
     }
 
-
     halConfig = convertRecognitionConfigToHal(&config);
 
     if (halConfig == NULL) {
         ret = -EINVAL;
         goto exit;
     }
-    ret = mHwDevice->start_recognition(mHwDevice, client->mHalHandle, halConfig,
-                                 recognitionCallback, client.get());
+    ret = mHwDevice->start_recognition(mHwDevice, client->getHalHandle(), halConfig,
+                                       recognitionCallback, client.get());
 
     free(halConfig);
 
@@ -252,8 +206,7 @@
     return ret;
 }
 
-Return<int32_t> SoundTriggerHalImpl::stopRecognition(SoundModelHandle modelHandle)
-{
+Return<int32_t> SoundTriggerHalImpl::stopRecognition(SoundModelHandle modelHandle) {
     int32_t ret;
     sp<SoundModelClient> client;
     if (mHwDevice == NULL) {
@@ -270,14 +223,13 @@
         }
     }
 
-    ret = mHwDevice->stop_recognition(mHwDevice, client->mHalHandle);
+    ret = mHwDevice->stop_recognition(mHwDevice, client->getHalHandle());
 
 exit:
     return ret;
 }
 
-Return<int32_t> SoundTriggerHalImpl::stopAllRecognitions()
-{
+Return<int32_t> SoundTriggerHalImpl::stopAllRecognitions() {
     int32_t ret;
     if (mHwDevice == NULL) {
         ret = -ENODEV;
@@ -285,7 +237,7 @@
     }
 
     if (mHwDevice->common.version >= SOUND_TRIGGER_DEVICE_API_VERSION_1_1 &&
-            mHwDevice->stop_all_recognitions) {
+        mHwDevice->stop_all_recognitions) {
         ret = mHwDevice->stop_all_recognitions(mHwDevice);
     } else {
         ret = -ENOSYS;
@@ -295,19 +247,16 @@
 }
 
 SoundTriggerHalImpl::SoundTriggerHalImpl()
-    : mModuleName("primary"), mHwDevice(NULL), mNextModelId(1)
-{
-}
+    : mModuleName("primary"), mHwDevice(NULL), mNextModelId(1) {}
 
-void SoundTriggerHalImpl::onFirstRef()
-{
-    const hw_module_t *mod;
+void SoundTriggerHalImpl::onFirstRef() {
+    const hw_module_t* mod;
     int rc;
 
     rc = hw_get_module_by_class(SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, &mod);
     if (rc != 0) {
-        ALOGE("couldn't load sound trigger module %s.%s (%s)",
-              SOUND_TRIGGER_HARDWARE_MODULE_ID, mModuleName, strerror(-rc));
+        ALOGE("couldn't load sound trigger module %s.%s (%s)", SOUND_TRIGGER_HARDWARE_MODULE_ID,
+              mModuleName, strerror(-rc));
         return;
     }
     rc = sound_trigger_hw_device_open(mod, &mHwDevice);
@@ -318,7 +267,7 @@
         return;
     }
     if (mHwDevice->common.version < SOUND_TRIGGER_DEVICE_API_VERSION_1_0 ||
-            mHwDevice->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
+        mHwDevice->common.version > SOUND_TRIGGER_DEVICE_API_VERSION_CURRENT) {
         ALOGE("wrong sound trigger hw device version %04x", mHwDevice->common.version);
         sound_trigger_hw_device_close(mHwDevice);
         mHwDevice = NULL;
@@ -328,22 +277,27 @@
     ALOGI("onFirstRef() mModuleName %s mHwDevice %p", mModuleName, mHwDevice);
 }
 
-SoundTriggerHalImpl::~SoundTriggerHalImpl()
-{
+SoundTriggerHalImpl::~SoundTriggerHalImpl() {
     if (mHwDevice != NULL) {
         sound_trigger_hw_device_close(mHwDevice);
     }
 }
 
-uint32_t SoundTriggerHalImpl::nextUniqueId()
-{
-    return (uint32_t) atomic_fetch_add_explicit(&mNextModelId,
-                (uint_fast32_t) 1, memory_order_acq_rel);
+uint32_t SoundTriggerHalImpl::nextUniqueModelId() {
+    uint32_t modelId = 0;
+    {
+        AutoMutex lock(mLock);
+        do {
+            modelId =
+                atomic_fetch_add_explicit(&mNextModelId, (uint_fast32_t)1, memory_order_acq_rel);
+        } while (mClients.valueFor(modelId) != 0 && modelId != 0);
+    }
+    LOG_ALWAYS_FATAL_IF(modelId == 0, "wrap around in sound model IDs, num loaded models %zu",
+                        mClients.size());
+    return modelId;
 }
 
-void SoundTriggerHalImpl::convertUuidFromHal(Uuid *uuid,
-                                             const sound_trigger_uuid_t *halUuid)
-{
+void SoundTriggerHalImpl::convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid) {
     uuid->timeLow = halUuid->timeLow;
     uuid->timeMid = halUuid->timeMid;
     uuid->versionAndTimeHigh = halUuid->timeHiAndVersion;
@@ -351,9 +305,7 @@
     memcpy(&uuid->node[0], &halUuid->node[0], 6);
 }
 
-void SoundTriggerHalImpl::convertUuidToHal(sound_trigger_uuid_t *halUuid,
-                                           const Uuid *uuid)
-{
+void SoundTriggerHalImpl::convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid) {
     halUuid->timeLow = uuid->timeLow;
     halUuid->timeMid = uuid->timeMid;
     halUuid->timeHiAndVersion = uuid->versionAndTimeHigh;
@@ -362,9 +314,7 @@
 }
 
 void SoundTriggerHalImpl::convertPropertiesFromHal(
-        ISoundTriggerHw::Properties *properties,
-        const struct sound_trigger_properties *halProperties)
-{
+    ISoundTriggerHw::Properties* properties, const struct sound_trigger_properties* halProperties) {
     properties->implementor = halProperties->implementor;
     properties->description = halProperties->description;
     properties->version = halProperties->version;
@@ -378,13 +328,10 @@
     properties->concurrentCapture = halProperties->concurrent_capture;
     properties->triggerInEvent = halProperties->trigger_in_event;
     properties->powerConsumptionMw = halProperties->power_consumption_mw;
-
 }
 
-void SoundTriggerHalImpl::convertTriggerPhraseToHal(
-        struct sound_trigger_phrase *halTriggerPhrase,
-        const ISoundTriggerHw::Phrase *triggerPhrase)
-{
+void SoundTriggerHalImpl::convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase,
+                                                    const ISoundTriggerHw::Phrase* triggerPhrase) {
     halTriggerPhrase->id = triggerPhrase->id;
     halTriggerPhrase->recognition_mode = triggerPhrase->recognitionModes;
     unsigned int i;
@@ -395,39 +342,35 @@
         halTriggerPhrase->users[i] = triggerPhrase->users[i];
     }
 
-    strlcpy(halTriggerPhrase->locale,
-            triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN);
-    strlcpy(halTriggerPhrase->text,
-            triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
+    strlcpy(halTriggerPhrase->locale, triggerPhrase->locale.c_str(), SOUND_TRIGGER_MAX_LOCALE_LEN);
+    strlcpy(halTriggerPhrase->text, triggerPhrase->text.c_str(), SOUND_TRIGGER_MAX_STRING_LEN);
 }
 
-struct sound_trigger_sound_model *SoundTriggerHalImpl::convertSoundModelToHal(
-        const ISoundTriggerHw::SoundModel *soundModel)
-{
-    struct sound_trigger_sound_model *halModel = NULL;
+struct sound_trigger_sound_model* SoundTriggerHalImpl::convertSoundModelToHal(
+    const ISoundTriggerHw::SoundModel* soundModel) {
+    struct sound_trigger_sound_model* halModel = NULL;
     if (soundModel->type == SoundModelType::KEYPHRASE) {
         size_t allocSize =
-                sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size();
-        struct sound_trigger_phrase_sound_model *halKeyPhraseModel =
-                static_cast<struct sound_trigger_phrase_sound_model *>(malloc(allocSize));
+            sizeof(struct sound_trigger_phrase_sound_model) + soundModel->data.size();
+        struct sound_trigger_phrase_sound_model* halKeyPhraseModel =
+            static_cast<struct sound_trigger_phrase_sound_model*>(malloc(allocSize));
         LOG_ALWAYS_FATAL_IF(halKeyPhraseModel == NULL,
-                        "malloc failed for size %zu in convertSoundModelToHal PHRASE", allocSize);
+                            "malloc failed for size %zu in convertSoundModelToHal PHRASE",
+                            allocSize);
 
-        const ISoundTriggerHw::PhraseSoundModel *keyPhraseModel =
-                reinterpret_cast<const ISoundTriggerHw::PhraseSoundModel *>(soundModel);
+        const ISoundTriggerHw::PhraseSoundModel* keyPhraseModel =
+            reinterpret_cast<const ISoundTriggerHw::PhraseSoundModel*>(soundModel);
 
         size_t i;
         for (i = 0; i < keyPhraseModel->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
-            convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i],
-                                      &keyPhraseModel->phrases[i]);
+            convertTriggerPhraseToHal(&halKeyPhraseModel->phrases[i], &keyPhraseModel->phrases[i]);
         }
         halKeyPhraseModel->num_phrases = (unsigned int)i;
-        halModel = reinterpret_cast<struct sound_trigger_sound_model *>(halKeyPhraseModel);
+        halModel = reinterpret_cast<struct sound_trigger_sound_model*>(halKeyPhraseModel);
         halModel->data_offset = sizeof(struct sound_trigger_phrase_sound_model);
     } else {
-        size_t allocSize =
-                sizeof(struct sound_trigger_sound_model) + soundModel->data.size();
-        halModel = static_cast<struct sound_trigger_sound_model *>(malloc(allocSize));
+        size_t allocSize = sizeof(struct sound_trigger_sound_model) + soundModel->data.size();
+        halModel = static_cast<struct sound_trigger_sound_model*>(malloc(allocSize));
         LOG_ALWAYS_FATAL_IF(halModel == NULL,
                             "malloc failed for size %zu in convertSoundModelToHal GENERIC",
                             allocSize);
@@ -438,17 +381,15 @@
     convertUuidToHal(&halModel->uuid, &soundModel->uuid);
     convertUuidToHal(&halModel->vendor_uuid, &soundModel->vendorUuid);
     halModel->data_size = soundModel->data.size();
-    uint8_t *dst = reinterpret_cast<uint8_t *>(halModel) + halModel->data_offset;
-    const uint8_t *src = reinterpret_cast<const uint8_t *>(&soundModel->data[0]);
+    uint8_t* dst = reinterpret_cast<uint8_t*>(halModel) + halModel->data_offset;
+    const uint8_t* src = reinterpret_cast<const uint8_t*>(&soundModel->data[0]);
     memcpy(dst, src, soundModel->data.size());
 
     return halModel;
 }
 
 void SoundTriggerHalImpl::convertPhraseRecognitionExtraToHal(
-        struct sound_trigger_phrase_recognition_extra *halExtra,
-        const PhraseRecognitionExtra *extra)
-{
+    struct sound_trigger_phrase_recognition_extra* halExtra, const PhraseRecognitionExtra* extra) {
     halExtra->id = extra->id;
     halExtra->recognition_modes = extra->recognitionModes;
     halExtra->confidence_level = extra->confidenceLevel;
@@ -461,16 +402,14 @@
     halExtra->num_levels = i;
 }
 
-struct sound_trigger_recognition_config *SoundTriggerHalImpl::convertRecognitionConfigToHal(
-        const ISoundTriggerHw::RecognitionConfig *config)
-{
+struct sound_trigger_recognition_config* SoundTriggerHalImpl::convertRecognitionConfigToHal(
+    const ISoundTriggerHw::RecognitionConfig* config) {
     size_t allocSize = sizeof(struct sound_trigger_recognition_config) + config->data.size();
-    struct sound_trigger_recognition_config *halConfig =
-            static_cast<struct sound_trigger_recognition_config *>(malloc(allocSize));
+    struct sound_trigger_recognition_config* halConfig =
+        static_cast<struct sound_trigger_recognition_config*>(malloc(allocSize));
 
     LOG_ALWAYS_FATAL_IF(halConfig == NULL,
-                        "malloc failed for size %zu in convertRecognitionConfigToHal",
-                        allocSize);
+                        "malloc failed for size %zu in convertRecognitionConfigToHal", allocSize);
 
     halConfig->capture_handle = (audio_io_handle_t)config->captureHandle;
     halConfig->capture_device = (audio_devices_t)config->captureDevice;
@@ -478,57 +417,43 @@
 
     unsigned int i;
     for (i = 0; i < config->phrases.size() && i < SOUND_TRIGGER_MAX_PHRASES; i++) {
-        convertPhraseRecognitionExtraToHal(&halConfig->phrases[i],
-                                  &config->phrases[i]);
+        convertPhraseRecognitionExtraToHal(&halConfig->phrases[i], &config->phrases[i]);
     }
     halConfig->num_phrases = i;
 
     halConfig->data_offset = sizeof(struct sound_trigger_recognition_config);
     halConfig->data_size = config->data.size();
-    uint8_t *dst = reinterpret_cast<uint8_t *>(halConfig) + halConfig->data_offset;
-    const uint8_t *src = reinterpret_cast<const uint8_t *>(&config->data[0]);
+    uint8_t* dst = reinterpret_cast<uint8_t*>(halConfig) + halConfig->data_offset;
+    const uint8_t* src = reinterpret_cast<const uint8_t*>(&config->data[0]);
     memcpy(dst, src, config->data.size());
     return halConfig;
 }
 
 // static
-void SoundTriggerHalImpl::convertSoundModelEventFromHal(ISoundTriggerHwCallback::ModelEvent *event,
-                                                const struct sound_trigger_model_event *halEvent)
-{
+void SoundTriggerHalImpl::convertSoundModelEventFromHal(
+    ISoundTriggerHwCallback::ModelEvent* event, const struct sound_trigger_model_event* halEvent) {
     event->status = (ISoundTriggerHwCallback::SoundModelStatus)halEvent->status;
     // event->model to be remapped by called
     event->data.setToExternal(
-            const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(halEvent)) + halEvent->data_offset,
-            halEvent->data_size);
+        const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) + halEvent->data_offset,
+        halEvent->data_size);
 }
 
 // static
-ISoundTriggerHwCallback::RecognitionEvent *SoundTriggerHalImpl::convertRecognitionEventFromHal(
-                                            const struct sound_trigger_recognition_event *halEvent)
-{
-    ISoundTriggerHwCallback::RecognitionEvent * event;
-
-    if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
-        const struct sound_trigger_phrase_recognition_event *halPhraseEvent =
-                reinterpret_cast<const struct sound_trigger_phrase_recognition_event *>(halEvent);
-        ISoundTriggerHwCallback::PhraseRecognitionEvent *phraseEvent =
-                new ISoundTriggerHwCallback::PhraseRecognitionEvent();
-
-        PhraseRecognitionExtra *phraseExtras =
-                new PhraseRecognitionExtra[halPhraseEvent->num_phrases];
-        for (unsigned int i = 0; i < halPhraseEvent->num_phrases; i++) {
-            convertPhraseRecognitionExtraFromHal(&phraseExtras[i],
-                                                 &halPhraseEvent->phrase_extras[i]);
-        }
-        phraseEvent->phraseExtras.setToExternal(phraseExtras, halPhraseEvent->num_phrases);
-        // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
-        phraseEvent->phraseExtras.resize(halPhraseEvent->num_phrases);
-        delete[] phraseExtras;
-        event = reinterpret_cast<ISoundTriggerHwCallback::RecognitionEvent *>(phraseEvent);
-    } else {
-        event = new ISoundTriggerHwCallback::RecognitionEvent();
+void SoundTriggerHalImpl::convertPhaseRecognitionEventFromHal(
+    ISoundTriggerHwCallback::PhraseRecognitionEvent* event,
+    const struct sound_trigger_phrase_recognition_event* halEvent) {
+    event->phraseExtras.resize(halEvent->num_phrases);
+    for (unsigned int i = 0; i < halEvent->num_phrases; i++) {
+        convertPhraseRecognitionExtraFromHal(&event->phraseExtras[i], &halEvent->phrase_extras[i]);
     }
+    convertRecognitionEventFromHal(&event->common, &halEvent->common);
+}
 
+// static
+void SoundTriggerHalImpl::convertRecognitionEventFromHal(
+    ISoundTriggerHwCallback::RecognitionEvent* event,
+    const struct sound_trigger_recognition_event* halEvent) {
     event->status = static_cast<ISoundTriggerHwCallback::RecognitionStatus>(halEvent->status);
     event->type = static_cast<SoundModelType>(halEvent->type);
     // event->model to be remapped by called
@@ -539,45 +464,53 @@
     event->triggerInData = halEvent->trigger_in_data;
     event->audioConfig.sampleRateHz = halEvent->audio_config.sample_rate;
     event->audioConfig.channelMask =
-            (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask;
+        (audio::common::V2_0::AudioChannelMask)halEvent->audio_config.channel_mask;
     event->audioConfig.format = (audio::common::V2_0::AudioFormat)halEvent->audio_config.format;
     event->data.setToExternal(
-            const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(halEvent)) + halEvent->data_offset,
-            halEvent->data_size);
-
-    return event;
+        const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(halEvent)) + halEvent->data_offset,
+        halEvent->data_size);
 }
 
 // static
 void SoundTriggerHalImpl::convertPhraseRecognitionExtraFromHal(
-        PhraseRecognitionExtra *extra,
-        const struct sound_trigger_phrase_recognition_extra *halExtra)
-{
+    PhraseRecognitionExtra* extra, const struct sound_trigger_phrase_recognition_extra* halExtra) {
     extra->id = halExtra->id;
     extra->recognitionModes = halExtra->recognition_modes;
     extra->confidenceLevel = halExtra->confidence_level;
 
-    ConfidenceLevel *levels =
-            new ConfidenceLevel[halExtra->num_levels];
-    for (unsigned int i = 0; i < halExtra->num_levels; i++) {
-        levels[i].userId = halExtra->levels[i].user_id;
-        levels[i].levelPercent = halExtra->levels[i].level;
-    }
-    extra->levels.setToExternal(levels, halExtra->num_levels);
-    // FIXME: transfer buffer ownership. should have a method for that in hidl_vec
     extra->levels.resize(halExtra->num_levels);
-    delete[] levels;
+    for (unsigned int i = 0; i < halExtra->num_levels; i++) {
+        extra->levels[i].userId = halExtra->levels[i].user_id;
+        extra->levels[i].levelPercent = halExtra->levels[i].level;
+    }
 }
 
-ISoundTriggerHw *HIDL_FETCH_ISoundTriggerHw(const char* /* name */)
-{
-    return new SoundTriggerHalImpl();
+void SoundTriggerHalImpl::SoundModelClient_2_0::recognitionCallback(
+    struct sound_trigger_recognition_event* halEvent) {
+    if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+        ISoundTriggerHwCallback::PhraseRecognitionEvent event;
+        convertPhaseRecognitionEventFromHal(
+            &event, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent));
+        event.common.model = mId;
+        mCallback->phraseRecognitionCallback(event, mCookie);
+    } else {
+        ISoundTriggerHwCallback::RecognitionEvent event;
+        convertRecognitionEventFromHal(&event, halEvent);
+        event.model = mId;
+        mCallback->recognitionCallback(event, mCookie);
+    }
 }
-} // namespace implementation
+
+void SoundTriggerHalImpl::SoundModelClient_2_0::soundModelCallback(
+    struct sound_trigger_model_event* halEvent) {
+    ISoundTriggerHwCallback::ModelEvent event;
+    convertSoundModelEventFromHal(&event, halEvent);
+    event.model = mId;
+    mCallback->soundModelCallback(event, mCookie);
+}
+
+}  // namespace implementation
 }  // namespace V2_0
 }  // namespace soundtrigger
 }  // namespace hardware
 }  // namespace android
-
-
-
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.h b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
index 4769590..5a9f0e1 100644
--- a/soundtrigger/2.0/default/SoundTriggerHalImpl.h
+++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
@@ -19,12 +19,12 @@
 
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
+#include <hardware/sound_trigger.h>
 #include <hidl/Status.h>
 #include <stdatomic.h>
-#include <utils/threads.h>
-#include <utils/KeyedVector.h>
 #include <system/sound_trigger.h>
-#include <hardware/sound_trigger.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
 
 namespace android {
 namespace hardware {
@@ -35,96 +35,144 @@
 using ::android::hardware::audio::common::V2_0::Uuid;
 using ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
 
+class SoundTriggerHalImpl : public RefBase {
+   public:
+    SoundTriggerHalImpl();
+    ISoundTriggerHw* getInterface() { return new TrampolineSoundTriggerHw_2_0(this); }
 
-class SoundTriggerHalImpl : public ISoundTriggerHw {
-public:
-        SoundTriggerHalImpl();
+   protected:
+    class SoundModelClient : public RefBase {
+       public:
+        SoundModelClient(uint32_t id, ISoundTriggerHwCallback::CallbackCookie cookie)
+            : mId(id), mCookie(cookie) {}
+        virtual ~SoundModelClient() {}
+
+        uint32_t getId() const { return mId; }
+        sound_model_handle_t getHalHandle() const { return mHalHandle; }
+        void setHalHandle(sound_model_handle_t handle) { mHalHandle = handle; }
+
+        virtual void recognitionCallback(struct sound_trigger_recognition_event* halEvent) = 0;
+        virtual void soundModelCallback(struct sound_trigger_model_event* halEvent) = 0;
+
+       protected:
+        const uint32_t mId;
+        sound_model_handle_t mHalHandle;
+        ISoundTriggerHwCallback::CallbackCookie mCookie;
+    };
+
+    static void convertPhaseRecognitionEventFromHal(
+        ISoundTriggerHwCallback::PhraseRecognitionEvent* event,
+        const struct sound_trigger_phrase_recognition_event* halEvent);
+    static void convertRecognitionEventFromHal(
+        ISoundTriggerHwCallback::RecognitionEvent* event,
+        const struct sound_trigger_recognition_event* halEvent);
+    static void convertSoundModelEventFromHal(ISoundTriggerHwCallback::ModelEvent* event,
+                                              const struct sound_trigger_model_event* halEvent);
+
+    virtual ~SoundTriggerHalImpl();
+
+    Return<void> getProperties(ISoundTriggerHw::getProperties_cb _hidl_cb);
+    Return<void> loadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
+                                const sp<ISoundTriggerHwCallback>& callback,
+                                ISoundTriggerHwCallback::CallbackCookie cookie,
+                                ISoundTriggerHw::loadSoundModel_cb _hidl_cb);
+    Return<void> loadPhraseSoundModel(const ISoundTriggerHw::PhraseSoundModel& soundModel,
+                                      const sp<ISoundTriggerHwCallback>& callback,
+                                      ISoundTriggerHwCallback::CallbackCookie cookie,
+                                      ISoundTriggerHw::loadPhraseSoundModel_cb _hidl_cb);
+    Return<int32_t> unloadSoundModel(SoundModelHandle modelHandle);
+    Return<int32_t> startRecognition(SoundModelHandle modelHandle,
+                                     const ISoundTriggerHw::RecognitionConfig& config);
+    Return<int32_t> stopRecognition(SoundModelHandle modelHandle);
+    Return<int32_t> stopAllRecognitions();
+
+    uint32_t nextUniqueModelId();
+    int doLoadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
+                         sp<SoundModelClient> client);
+
+    // RefBase
+    void onFirstRef() override;
+
+   private:
+    struct TrampolineSoundTriggerHw_2_0 : public ISoundTriggerHw {
+        explicit TrampolineSoundTriggerHw_2_0(sp<SoundTriggerHalImpl> impl) : mImpl(impl) {}
 
         // Methods from ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw follow.
-        Return<void> getProperties(getProperties_cb _hidl_cb)  override;
+        Return<void> getProperties(getProperties_cb _hidl_cb) override {
+            return mImpl->getProperties(_hidl_cb);
+        }
         Return<void> loadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
                                     const sp<ISoundTriggerHwCallback>& callback,
                                     ISoundTriggerHwCallback::CallbackCookie cookie,
-                                    loadSoundModel_cb _hidl_cb)  override;
+                                    loadSoundModel_cb _hidl_cb) override {
+            return mImpl->loadSoundModel(soundModel, callback, cookie, _hidl_cb);
+        }
         Return<void> loadPhraseSoundModel(const ISoundTriggerHw::PhraseSoundModel& soundModel,
-                                    const sp<ISoundTriggerHwCallback>& callback,
-                                    ISoundTriggerHwCallback::CallbackCookie cookie,
-                                    loadPhraseSoundModel_cb _hidl_cb)  override;
+                                          const sp<ISoundTriggerHwCallback>& callback,
+                                          ISoundTriggerHwCallback::CallbackCookie cookie,
+                                          loadPhraseSoundModel_cb _hidl_cb) override {
+            return mImpl->loadPhraseSoundModel(soundModel, callback, cookie, _hidl_cb);
+        }
+        Return<int32_t> unloadSoundModel(SoundModelHandle modelHandle) override {
+            return mImpl->unloadSoundModel(modelHandle);
+        }
+        Return<int32_t> startRecognition(
+            SoundModelHandle modelHandle, const ISoundTriggerHw::RecognitionConfig& config,
+            const sp<ISoundTriggerHwCallback>& /*callback*/,
+            ISoundTriggerHwCallback::CallbackCookie /*cookie*/) override {
+            return mImpl->startRecognition(modelHandle, config);
+        }
+        Return<int32_t> stopRecognition(SoundModelHandle modelHandle) override {
+            return mImpl->stopRecognition(modelHandle);
+        }
+        Return<int32_t> stopAllRecognitions() override { return mImpl->stopAllRecognitions(); }
 
-        Return<int32_t> unloadSoundModel(SoundModelHandle modelHandle)  override;
-        Return<int32_t> startRecognition(SoundModelHandle modelHandle,
-                                      const ISoundTriggerHw::RecognitionConfig& config,
-                                      const sp<ISoundTriggerHwCallback>& callback,
-                                      ISoundTriggerHwCallback::CallbackCookie cookie)  override;
-        Return<int32_t> stopRecognition(SoundModelHandle modelHandle)  override;
-        Return<int32_t> stopAllRecognitions()  override;
+       private:
+        sp<SoundTriggerHalImpl> mImpl;
+    };
 
-        // RefBase
-        virtual     void        onFirstRef();
+    class SoundModelClient_2_0 : public SoundModelClient {
+       public:
+        SoundModelClient_2_0(uint32_t id, ISoundTriggerHwCallback::CallbackCookie cookie,
+                             sp<ISoundTriggerHwCallback> callback)
+            : SoundModelClient(id, cookie), mCallback(callback) {}
 
-        static void soundModelCallback(struct sound_trigger_model_event *halEvent,
-                                       void *cookie);
-        static void recognitionCallback(struct sound_trigger_recognition_event *halEvent,
-                                        void *cookie);
+        void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override;
+        void soundModelCallback(struct sound_trigger_model_event* halEvent) override;
 
-private:
+       private:
+        sp<ISoundTriggerHwCallback> mCallback;
+    };
 
-        class SoundModelClient : public RefBase {
-        public:
-            SoundModelClient(uint32_t id, sp<ISoundTriggerHwCallback> callback,
-                             ISoundTriggerHwCallback::CallbackCookie cookie)
-                : mId(id), mCallback(callback), mCookie(cookie) {}
-            virtual ~SoundModelClient() {}
+    void convertUuidFromHal(Uuid* uuid, const sound_trigger_uuid_t* halUuid);
+    void convertUuidToHal(sound_trigger_uuid_t* halUuid, const Uuid* uuid);
+    void convertPropertiesFromHal(ISoundTriggerHw::Properties* properties,
+                                  const struct sound_trigger_properties* halProperties);
+    void convertTriggerPhraseToHal(struct sound_trigger_phrase* halTriggerPhrase,
+                                   const ISoundTriggerHw::Phrase* triggerPhrase);
+    // returned HAL sound model must be freed by caller
+    struct sound_trigger_sound_model* convertSoundModelToHal(
+        const ISoundTriggerHw::SoundModel* soundModel);
+    void convertPhraseRecognitionExtraToHal(struct sound_trigger_phrase_recognition_extra* halExtra,
+                                            const PhraseRecognitionExtra* extra);
+    // returned recognition config must be freed by caller
+    struct sound_trigger_recognition_config* convertRecognitionConfigToHal(
+        const ISoundTriggerHw::RecognitionConfig* config);
 
-            uint32_t mId;
-            sound_model_handle_t mHalHandle;
-            sp<ISoundTriggerHwCallback> mCallback;
-            ISoundTriggerHwCallback::CallbackCookie mCookie;
-        };
+    static void convertPhraseRecognitionExtraFromHal(
+        PhraseRecognitionExtra* extra,
+        const struct sound_trigger_phrase_recognition_extra* halExtra);
 
-        uint32_t nextUniqueId();
-        void convertUuidFromHal(Uuid *uuid,
-                                const sound_trigger_uuid_t *halUuid);
-        void convertUuidToHal(sound_trigger_uuid_t *halUuid,
-                              const Uuid *uuid);
-        void convertPropertiesFromHal(ISoundTriggerHw::Properties *properties,
-                                      const struct sound_trigger_properties *halProperties);
-        void convertTriggerPhraseToHal(struct sound_trigger_phrase *halTriggerPhrase,
-                                       const ISoundTriggerHw::Phrase *triggerPhrase);
-        // returned HAL sound model must be freed by caller
-        struct sound_trigger_sound_model *convertSoundModelToHal(
-                    const ISoundTriggerHw::SoundModel *soundModel);
-        void convertPhraseRecognitionExtraToHal(
-                struct sound_trigger_phrase_recognition_extra *halExtra,
-                const PhraseRecognitionExtra *extra);
-        // returned recognition config must be freed by caller
-        struct sound_trigger_recognition_config *convertRecognitionConfigToHal(
-                const ISoundTriggerHw::RecognitionConfig *config);
+    static void soundModelCallback(struct sound_trigger_model_event* halEvent, void* cookie);
+    static void recognitionCallback(struct sound_trigger_recognition_event* halEvent, void* cookie);
 
-
-        static void convertSoundModelEventFromHal(ISoundTriggerHwCallback::ModelEvent *event,
-                                            const struct sound_trigger_model_event *halEvent);
-        static ISoundTriggerHwCallback::RecognitionEvent *convertRecognitionEventFromHal(
-                                            const struct sound_trigger_recognition_event *halEvent);
-        static void convertPhraseRecognitionExtraFromHal(PhraseRecognitionExtra *extra,
-                                    const struct sound_trigger_phrase_recognition_extra *halExtra);
-
-        int doLoadSoundModel(const ISoundTriggerHw::SoundModel& soundModel,
-                             const sp<ISoundTriggerHwCallback>& callback,
-                             ISoundTriggerHwCallback::CallbackCookie cookie,
-                             uint32_t *modelId);
-
-        virtual             ~SoundTriggerHalImpl();
-
-        const char *                                        mModuleName;
-        struct sound_trigger_hw_device*                     mHwDevice;
-        volatile atomic_uint_fast32_t                       mNextModelId;
-        DefaultKeyedVector<int32_t, sp<SoundModelClient> >  mClients;
-        Mutex                                               mLock;
+    const char* mModuleName;
+    struct sound_trigger_hw_device* mHwDevice;
+    volatile atomic_uint_fast32_t mNextModelId;
+    DefaultKeyedVector<int32_t, sp<SoundModelClient> > mClients;
+    Mutex mLock;
 };
 
-extern "C" ISoundTriggerHw *HIDL_FETCH_ISoundTriggerHw(const char *name);
-
 }  // namespace implementation
 }  // namespace V2_0
 }  // namespace soundtrigger
@@ -132,4 +180,3 @@
 }  // namespace android
 
 #endif  // ANDROID_HARDWARE_SOUNDTRIGGER_V2_0_IMPLEMENTATION_H
-
diff --git a/soundtrigger/2.1/Android.bp b/soundtrigger/2.1/Android.bp
new file mode 100644
index 0000000..ed1ec3d
--- /dev/null
+++ b/soundtrigger/2.1/Android.bp
@@ -0,0 +1,20 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.soundtrigger@2.1",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "ISoundTriggerHw.hal",
+        "ISoundTriggerHwCallback.hal",
+    ],
+    interfaces: [
+        "android.hardware.audio.common@2.0",
+        "android.hardware.soundtrigger@2.0",
+        "android.hidl.base@1.0",
+    ],
+    gen_java: false,
+}
+
diff --git a/soundtrigger/2.1/ISoundTriggerHw.hal b/soundtrigger/2.1/ISoundTriggerHw.hal
new file mode 100644
index 0000000..2f2e73a
--- /dev/null
+++ b/soundtrigger/2.1/ISoundTriggerHw.hal
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.soundtrigger@2.1;
+
+import @2.0::ISoundTriggerHw;
+import @2.0::ISoundTriggerHwCallback.CallbackCookie;
+import @2.0::SoundModelHandle;
+
+import ISoundTriggerHwCallback;
+
+/**
+ * SoundTrigger HAL interface. Used for hardware recognition of hotwords.
+ */
+interface ISoundTriggerHw extends @2.0::ISoundTriggerHw {
+
+    /**
+     * Base sound model descriptor. This struct is the header of a larger block
+     * passed to loadSoundModel_2_1() and contains the binary data of the
+     * sound model.
+     */
+    struct SoundModel {
+        /** Sound model header. Any data contained in the 'header.data' field
+         * is ignored */
+        @2.0::ISoundTriggerHw.SoundModel header;
+        /** Opaque data transparent to Android framework */
+        memory data;
+    };
+
+    /**
+     * Specialized sound model for key phrase detection.
+     * Proprietary representation of key phrases in binary data must match
+     * information indicated by phrases field.
+     */
+    struct PhraseSoundModel {
+        /** Common part of sound model descriptor */
+        SoundModel  common;
+        /** List of descriptors for key phrases supported by this sound model */
+        vec<Phrase> phrases;
+    };
+
+    /**
+     * Configuration for sound trigger capture session passed to
+     * startRecognition_2_1() method.
+     */
+    struct RecognitionConfig {
+        /** Configuration header. Any data contained in the 'header.data' field
+         * is ignored */
+        @2.0::ISoundTriggerHw.RecognitionConfig header;
+        /** Opaque capture configuration data transparent to the framework */
+        memory data;
+    };
+
+    /**
+     * Load a sound model. Once loaded, recognition of this model can be
+     * started and stopped. Only one active recognition per model at a time.
+     * The SoundTrigger service must handle concurrent recognition requests by
+     * different users/applications on the same model.
+     * The implementation returns a unique handle used by other functions
+     * (unloadSoundModel(), startRecognition*(), etc...
+     *
+     * Must have the exact same semantics as loadSoundModel from
+     * ISoundTriggerHw@2.0 except that the SoundModel uses shared memory
+     * instead of data.
+     *
+     * @param soundModel A SoundModel structure describing the sound model
+     *     to load.
+     * @param callback The callback interface on which the soundmodelCallback*()
+     *     method must be called upon completion.
+     * @param cookie The value of the cookie argument passed to the completion
+     *     callback. This unique context information is assigned and
+     *     used only by the framework.
+     * @return retval Operation completion status: 0 in case of success,
+     *     -EINVAL in case of invalid sound model (e.g 0 data size),
+     *     -ENOSYS in case of invalid operation (e.g max number of models
+     *             exceeded),
+     *     -ENOMEM in case of memory allocation failure,
+     *     -ENODEV in case of initialization error.
+     * @return modelHandle A unique handle assigned by the HAL for use by the
+     *     framework when controlling activity for this sound model.
+     */
+    @callflow(next={"startRecognition_2_1", "setSoundModelParameters", "unloadSoundModel"})
+    loadSoundModel_2_1(SoundModel soundModel,
+                   ISoundTriggerHwCallback callback,
+                   CallbackCookie cookie)
+            generates (int32_t retval, SoundModelHandle modelHandle);
+
+    /**
+     * Load a key phrase sound model. Once loaded, recognition of this model can
+     * be started and stopped. Only one active recognition per model at a time.
+     * The SoundTrigger service must handle concurrent recognition requests by
+     * different users/applications on the same model.
+     * The implementation returns a unique handle used by other functions
+     * (unloadSoundModel(), startRecognition*(), etc...
+     *
+     * Must have the exact same semantics as loadPhraseSoundModel from
+     * ISoundTriggerHw@2.0 except that the PhraseSoundModel uses shared memory
+     * instead of data.
+     *
+     * @param soundModel A PhraseSoundModel structure describing the sound model
+     *     to load.
+     * @param callback The callback interface on which the soundmodelCallback*()
+     *     method must be called upon completion.
+     * @param cookie The value of the cookie argument passed to the completion
+     *     callback. This unique context information is assigned and
+     *     used only by the framework.
+     * @return retval Operation completion status: 0 in case of success,
+     *     -EINVAL in case of invalid sound model (e.g 0 data size),
+     *     -ENOSYS in case of invalid operation (e.g max number of models
+     *             exceeded),
+     *     -ENOMEM in case of memory allocation failure,
+     *     -ENODEV in case of initialization error.
+     * @return modelHandle A unique handle assigned by the HAL for use by the
+     *     framework when controlling activity for this sound model.
+     */
+    @callflow(next={"startRecognition_2_1", "setSoundModelParameters", "unloadSoundModel"})
+    loadPhraseSoundModel_2_1(PhraseSoundModel soundModel,
+                   ISoundTriggerHwCallback callback,
+                   CallbackCookie cookie)
+            generates (int32_t retval, SoundModelHandle modelHandle);
+
+    /**
+     * Start recognition on a given model. Only one recognition active
+     * at a time per model. Once recognition succeeds of fails, the callback
+     * is called.
+     *
+     * Must have the exact same semantics as startRecognition from
+     * ISoundTriggerHw@2.0 except that the RecognitionConfig uses shared memory
+     * instead of data.
+     *
+     * @param modelHandle the handle of the sound model to use for recognition
+     * @param config A RecognitionConfig structure containing attributes of the
+     *     recognition to perform
+     * @param callback The callback interface on which the recognitionCallback()
+     *     method must be called upon recognition.
+     * @param cookie The value of the cookie argument passed to the recognition
+     *     callback. This unique context information is assigned and
+     *     used only by the framework.
+     * @return retval Operation completion status: 0 in case of success,
+     *     -EINVAL in case of invalid recognition attributes,
+     *     -ENOSYS in case of invalid model handle,
+     *     -ENOMEM in case of memory allocation failure,
+     *     -ENODEV in case of initialization error.
+     */
+    @callflow(next={"stopRecognition", "stopAllRecognitions"})
+    startRecognition_2_1(SoundModelHandle modelHandle,
+                     RecognitionConfig config,
+                     ISoundTriggerHwCallback callback,
+                     CallbackCookie cookie)
+            generates (int32_t retval);
+
+
+    struct ParameterValue {
+        string key;
+        string value;
+    };
+
+    /**
+     * Generic method for retrieving vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * @param keys parameter keys.
+     * @return retval Operation completion status: 0 in case of success,
+     *     -EINVAL in case of invalid keys,
+     *     -ENOSYS in case if this operation is not supported,
+     *     -ENOMEM in case of memory allocation failure,
+     *     -ENODEV in case of initialization error.
+     * @return parameters parameter key value pairs.
+     */
+    getParameters(vec<string> keys)
+            generates (int32_t retval, vec<ParameterValue> parameters);
+
+    /**
+     * Generic method for setting vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * @param parameters parameter key value pairs.
+     * @return retval Operation completion status: 0 in case of success,
+     *     -EINVAL in case of invalid keys,
+     *     -ENOSYS in case if this operation is not supported,
+     *     -ENOMEM in case of memory allocation failure,
+     *     -ENODEV in case of initialization error.
+     */
+    setParameters(vec<ParameterValue> parameters) generates (int32_t retval);
+
+    /**
+     * Generic method for retrieving vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * @param modelHandle the handle of the sound model to get parameters about.
+     * @param keys parameter keys.
+     * @return retval Operation completion status: 0 in case of success,
+     *     -EINVAL in case of invalid keys,
+     *     -ENOSYS in case if this operation is not supported,
+     *     -ENOMEM in case of memory allocation failure,
+     *     -ENODEV in case of initialization error.
+     * @return parameters parameter key value pairs.
+     */
+    getSoundModelParameters(SoundModelHandle modelHandle, vec<string> keys)
+            generates (int32_t retval, vec<ParameterValue> parameters);
+
+    /**
+     * Generic method for setting vendor-specific parameter values.
+     * The framework does not interpret the parameters, they are passed
+     * in an opaque manner between a vendor application and HAL.
+     *
+     * @param modelHandle the handle of the sound model to set parameters for.
+     * @param parameters parameter key value pairs.
+     * @return retval Operation completion status: 0 in case of success,
+     *     -EINVAL in case of invalid keys,
+     *     -ENOSYS in case if this operation is not supported,
+     *     -ENOMEM in case of memory allocation failure,
+     *     -ENODEV in case of initialization error.
+     */
+    setSoundModelParameters(
+            SoundModelHandle modelHandle, vec<ParameterValue> parameters)
+            generates (int32_t retval);
+};
diff --git a/soundtrigger/2.1/ISoundTriggerHwCallback.hal b/soundtrigger/2.1/ISoundTriggerHwCallback.hal
new file mode 100644
index 0000000..42e851b
--- /dev/null
+++ b/soundtrigger/2.1/ISoundTriggerHwCallback.hal
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.soundtrigger@2.1;
+
+import @2.0::ISoundTriggerHwCallback;
+import @2.0::PhraseRecognitionExtra;
+
+/**
+ * SoundTrigger HAL Callback interface. Obtained during SoundTrigger setup.
+ */
+@hidl_callback
+interface ISoundTriggerHwCallback extends @2.0::ISoundTriggerHwCallback {
+
+    /**
+     * Generic recognition event sent via recognition callback.
+     */
+    struct RecognitionEvent {
+        /** Event header. Any data contained in the 'header.data' field
+         * is ignored */
+        @2.0::ISoundTriggerHwCallback.RecognitionEvent header;
+        /** Opaque event data */
+        memory data;
+    };
+
+    /**
+     * Specialized recognition event for key phrase recognitions.
+     */
+    struct PhraseRecognitionEvent {
+        /** Common part of the recognition event */
+        RecognitionEvent common;
+        /** List of descriptors for each recognized key phrase */
+        vec<PhraseRecognitionExtra> phraseExtras;
+    };
+
+    /**
+     * Event sent via load sound model callback.
+     */
+    struct ModelEvent {
+        /** Event header. Any data contained in the 'header.data' field
+         * is ignored */
+        @2.0::ISoundTriggerHwCallback.ModelEvent header;
+        /** Opaque event data, passed transparently by the framework */
+        memory data;
+    };
+
+    /**
+     * Callback method called by the HAL when the sound recognition triggers.
+     *
+     * @param event A RecognitionEvent structure containing detailed results
+     *     of the recognition triggered
+     * @param cookie The cookie passed by the framework when recognition was
+     *     started (see ISoundtriggerHw.startRecognition*())
+     */
+    recognitionCallback_2_1(RecognitionEvent event, CallbackCookie cookie);
+
+    /**
+     * Callback method called by the HAL when the sound recognition triggers
+     * for a key phrase sound model.
+     *
+     * @param event A RecognitionEvent structure containing detailed results
+     *     of the recognition triggered
+     * @param cookie The cookie passed by the framework when recognition was
+     *     started (see ISoundtriggerHw.startRecognition*())
+     */
+    phraseRecognitionCallback_2_1(PhraseRecognitionEvent event,
+                                  CallbackCookie cookie);
+
+    /**
+     * Callback method called by the HAL when the sound model loading completes.
+     *
+     * @param event A ModelEvent structure containing detailed results of the
+     *     model loading operation
+     * @param cookie The cookie passed by the framework when loading was
+     *     initiated (see ISoundtriggerHw.loadSoundModel*())
+     */
+    soundModelCallback_2_1(ModelEvent event, CallbackCookie cookie);
+};
diff --git a/soundtrigger/2.1/default/Android.mk b/soundtrigger/2.1/default/Android.mk
new file mode 100644
index 0000000..5851d63
--- /dev/null
+++ b/soundtrigger/2.1/default/Android.mk
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := android.hardware.soundtrigger@2.1-impl
+LOCAL_VENDOR_MODULE := true
+LOCAL_MODULE_RELATIVE_PATH := hw
+LOCAL_SRC_FILES := \
+    SoundTriggerHw.cpp
+
+LOCAL_CFLAGS := -Wall -Werror
+
+LOCAL_SHARED_LIBRARIES := \
+        libhardware \
+        libhidlbase \
+        libhidlmemory \
+        libhidltransport \
+        liblog \
+        libutils \
+        android.hardware.soundtrigger@2.1 \
+        android.hardware.soundtrigger@2.0 \
+        android.hardware.soundtrigger@2.0-core \
+        android.hidl.allocator@1.0 \
+        android.hidl.memory@1.0
+
+LOCAL_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
+LOCAL_MULTILIB := 32
+else
+LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
+endif
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/soundtrigger/2.1/default/SoundTriggerHw.cpp b/soundtrigger/2.1/default/SoundTriggerHw.cpp
new file mode 100644
index 0000000..246d2bc
--- /dev/null
+++ b/soundtrigger/2.1/default/SoundTriggerHw.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SoundTriggerHw"
+
+#include "SoundTriggerHw.h"
+
+#include <utility>
+
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/log.h>
+#include <hidlmemory/mapping.h>
+
+using android::hardware::hidl_memory;
+using android::hidl::allocator::V1_0::IAllocator;
+using android::hidl::memory::V1_0::IMemory;
+
+namespace android {
+namespace hardware {
+namespace soundtrigger {
+namespace V2_1 {
+namespace implementation {
+
+namespace {
+
+// Backs up by the vector with the contents of shared memory.
+// It is assumed that the passed hidl_vector is empty, so it's
+// not cleared if the memory is a null object.
+// The caller needs to keep the returned sp<IMemory> as long as
+// the data is needed.
+std::pair<bool, sp<IMemory>> memoryAsVector(const hidl_memory& m, hidl_vec<uint8_t>* vec) {
+    sp<IMemory> memory;
+    if (m.size() == 0) {
+        return std::make_pair(true, memory);
+    }
+    memory = mapMemory(m);
+    if (memory != nullptr) {
+        memory->read();
+        vec->setToExternal(static_cast<uint8_t*>(static_cast<void*>(memory->getPointer())),
+                           memory->getSize());
+        return std::make_pair(true, memory);
+    }
+    ALOGE("%s: Could not map HIDL memory to IMemory", __func__);
+    return std::make_pair(false, memory);
+}
+
+// Moves the data from the vector into allocated shared memory,
+// emptying the vector.
+// It is assumed that the passed hidl_memory is a null object, so it's
+// not reset if the vector is empty.
+// The caller needs to keep the returned sp<IMemory> as long as
+// the data is needed.
+std::pair<bool, sp<IMemory>> moveVectorToMemory(hidl_vec<uint8_t>* v, hidl_memory* mem) {
+    sp<IMemory> memory;
+    if (v->size() == 0) {
+        return std::make_pair(true, memory);
+    }
+    sp<IAllocator> ashmem = IAllocator::getService("ashmem");
+    if (ashmem == 0) {
+        ALOGE("Failed to retrieve ashmem allocator service");
+        return std::make_pair(false, memory);
+    }
+    bool success = false;
+    Return<void> r = ashmem->allocate(v->size(), [&](bool s, const hidl_memory& m) {
+        success = s;
+        if (success) *mem = m;
+    });
+    if (r.isOk() && success) {
+        memory = hardware::mapMemory(*mem);
+        if (memory != 0) {
+            memory->update();
+            memcpy(memory->getPointer(), v->data(), v->size());
+            memory->commit();
+            v->resize(0);
+            return std::make_pair(true, memory);
+        } else {
+            ALOGE("Failed to map allocated ashmem");
+        }
+    } else {
+        ALOGE("Failed to allocate %llu bytes from ashmem", (unsigned long long)v->size());
+    }
+    return std::make_pair(false, memory);
+}
+
+}  // namespace
+
+Return<void> SoundTriggerHw::loadSoundModel_2_1(
+    const V2_1::ISoundTriggerHw::SoundModel& soundModel,
+    const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+    V2_1::ISoundTriggerHw::loadSoundModel_2_1_cb _hidl_cb) {
+    // It is assumed that legacy data vector is empty, thus making copy is cheap.
+    V2_0::ISoundTriggerHw::SoundModel soundModel_2_0(soundModel.header);
+    auto result = memoryAsVector(soundModel.data, &soundModel_2_0.data);
+    if (result.first) {
+        sp<SoundModelClient> client =
+            new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback);
+        _hidl_cb(doLoadSoundModel(soundModel_2_0, client), client->getId());
+        return Void();
+    }
+    _hidl_cb(-ENOMEM, 0);
+    return Void();
+}
+
+Return<void> SoundTriggerHw::loadPhraseSoundModel_2_1(
+    const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
+    const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+    V2_1::ISoundTriggerHw::loadPhraseSoundModel_2_1_cb _hidl_cb) {
+    V2_0::ISoundTriggerHw::PhraseSoundModel soundModel_2_0;
+    // It is assumed that legacy data vector is empty, thus making copy is cheap.
+    soundModel_2_0.common = soundModel.common.header;
+    // Avoid copying phrases data.
+    soundModel_2_0.phrases.setToExternal(
+        const_cast<V2_0::ISoundTriggerHw::Phrase*>(soundModel.phrases.data()),
+        soundModel.phrases.size());
+    auto result = memoryAsVector(soundModel.common.data, &soundModel_2_0.common.data);
+    if (result.first) {
+        sp<SoundModelClient> client =
+            new SoundModelClient_2_1(nextUniqueModelId(), cookie, callback);
+        _hidl_cb(doLoadSoundModel((const V2_0::ISoundTriggerHw::SoundModel&)soundModel_2_0, client),
+                 client->getId());
+        return Void();
+    }
+    _hidl_cb(-ENOMEM, 0);
+    return Void();
+}
+
+Return<int32_t> SoundTriggerHw::startRecognition_2_1(
+    int32_t modelHandle, const V2_1::ISoundTriggerHw::RecognitionConfig& config) {
+    // It is assumed that legacy data vector is empty, thus making copy is cheap.
+    V2_0::ISoundTriggerHw::RecognitionConfig config_2_0(config.header);
+    auto result = memoryAsVector(config.data, &config_2_0.data);
+    return result.first ? startRecognition(modelHandle, config_2_0) : Return<int32_t>(-ENOMEM);
+}
+
+void SoundTriggerHw::SoundModelClient_2_1::recognitionCallback(
+    struct sound_trigger_recognition_event* halEvent) {
+    if (halEvent->type == SOUND_MODEL_TYPE_KEYPHRASE) {
+        V2_0::ISoundTriggerHwCallback::PhraseRecognitionEvent event_2_0;
+        convertPhaseRecognitionEventFromHal(
+            &event_2_0, reinterpret_cast<sound_trigger_phrase_recognition_event*>(halEvent));
+        event_2_0.common.model = mId;
+        V2_1::ISoundTriggerHwCallback::PhraseRecognitionEvent event;
+        event.phraseExtras.setToExternal(event_2_0.phraseExtras.data(),
+                                         event_2_0.phraseExtras.size());
+        auto result = moveVectorToMemory(&event_2_0.common.data, &event.common.data);
+        if (result.first) {
+            // The data vector is now empty, thus copying is cheap.
+            event.common.header = event_2_0.common;
+            mCallback->phraseRecognitionCallback_2_1(event, mCookie);
+        }
+    } else {
+        V2_1::ISoundTriggerHwCallback::RecognitionEvent event;
+        convertRecognitionEventFromHal(&event.header, halEvent);
+        event.header.model = mId;
+        auto result = moveVectorToMemory(&event.header.data, &event.data);
+        if (result.first) {
+            mCallback->recognitionCallback_2_1(event, mCookie);
+        }
+    }
+}
+
+void SoundTriggerHw::SoundModelClient_2_1::soundModelCallback(
+    struct sound_trigger_model_event* halEvent) {
+    V2_1::ISoundTriggerHwCallback::ModelEvent event;
+    convertSoundModelEventFromHal(&event.header, halEvent);
+    event.header.model = mId;
+    auto result = moveVectorToMemory(&event.header.data, &event.data);
+    if (result.first) {
+        mCallback->soundModelCallback_2_1(event, mCookie);
+    }
+}
+
+ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* /* name */) {
+    return (new SoundTriggerHw())->getInterface();
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace soundtrigger
+}  // namespace hardware
+}  // namespace android
diff --git a/soundtrigger/2.1/default/SoundTriggerHw.h b/soundtrigger/2.1/default/SoundTriggerHw.h
new file mode 100644
index 0000000..855d1a6
--- /dev/null
+++ b/soundtrigger/2.1/default/SoundTriggerHw.h
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_SOUNDTRIGGER_V2_1_SOUNDTRIGGERHW_H
+#define ANDROID_HARDWARE_SOUNDTRIGGER_V2_1_SOUNDTRIGGERHW_H
+
+#include <SoundTriggerHalImpl.h>
+#include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace soundtrigger {
+namespace V2_1 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+struct SoundTriggerHw : public V2_0::implementation::SoundTriggerHalImpl {
+    SoundTriggerHw() = default;
+    ISoundTriggerHw* getInterface() { return new TrampolineSoundTriggerHw_2_1(this); }
+
+   protected:
+    virtual ~SoundTriggerHw() = default;
+
+    Return<void> loadSoundModel_2_1(const V2_1::ISoundTriggerHw::SoundModel& soundModel,
+                                    const sp<V2_1::ISoundTriggerHwCallback>& callback,
+                                    int32_t cookie,
+                                    V2_1::ISoundTriggerHw::loadSoundModel_2_1_cb _hidl_cb);
+    Return<void> loadPhraseSoundModel_2_1(
+        const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
+        const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+        V2_1::ISoundTriggerHw::loadPhraseSoundModel_2_1_cb _hidl_cb);
+    Return<int32_t> startRecognition_2_1(int32_t modelHandle,
+                                         const V2_1::ISoundTriggerHw::RecognitionConfig& config);
+
+   private:
+    struct TrampolineSoundTriggerHw_2_1 : public ISoundTriggerHw {
+        explicit TrampolineSoundTriggerHw_2_1(sp<SoundTriggerHw> impl) : mImpl(impl) {}
+
+        // Methods from ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw follow.
+        Return<void> getProperties(getProperties_cb _hidl_cb) override {
+            return mImpl->getProperties(_hidl_cb);
+        }
+        Return<void> loadSoundModel(const V2_0::ISoundTriggerHw::SoundModel& soundModel,
+                                    const sp<V2_0::ISoundTriggerHwCallback>& callback,
+                                    int32_t cookie, loadSoundModel_cb _hidl_cb) override {
+            return mImpl->loadSoundModel(soundModel, callback, cookie, _hidl_cb);
+        }
+        Return<void> loadPhraseSoundModel(const V2_0::ISoundTriggerHw::PhraseSoundModel& soundModel,
+                                          const sp<V2_0::ISoundTriggerHwCallback>& callback,
+                                          int32_t cookie,
+                                          loadPhraseSoundModel_cb _hidl_cb) override {
+            return mImpl->loadPhraseSoundModel(soundModel, callback, cookie, _hidl_cb);
+        }
+        Return<int32_t> unloadSoundModel(V2_0::SoundModelHandle modelHandle) override {
+            return mImpl->unloadSoundModel(modelHandle);
+        }
+        Return<int32_t> startRecognition(int32_t modelHandle,
+                                         const V2_0::ISoundTriggerHw::RecognitionConfig& config,
+                                         const sp<V2_0::ISoundTriggerHwCallback>& /*callback*/,
+                                         int32_t /*cookie*/) override {
+            return mImpl->startRecognition(modelHandle, config);
+        }
+        Return<int32_t> stopRecognition(V2_0::SoundModelHandle modelHandle) override {
+            return mImpl->stopRecognition(modelHandle);
+        }
+        Return<int32_t> stopAllRecognitions() override { return mImpl->stopAllRecognitions(); }
+
+        // Methods from V2_1::ISoundTriggerHw follow.
+        Return<void> loadSoundModel_2_1(const V2_1::ISoundTriggerHw::SoundModel& soundModel,
+                                        const sp<V2_1::ISoundTriggerHwCallback>& callback,
+                                        int32_t cookie, loadSoundModel_2_1_cb _hidl_cb) override {
+            return mImpl->loadSoundModel_2_1(soundModel, callback, cookie, _hidl_cb);
+        }
+        Return<void> loadPhraseSoundModel_2_1(
+            const V2_1::ISoundTriggerHw::PhraseSoundModel& soundModel,
+            const sp<V2_1::ISoundTriggerHwCallback>& callback, int32_t cookie,
+            loadPhraseSoundModel_2_1_cb _hidl_cb) override {
+            return mImpl->loadPhraseSoundModel_2_1(soundModel, callback, cookie, _hidl_cb);
+        }
+        Return<int32_t> startRecognition_2_1(int32_t modelHandle,
+                                             const V2_1::ISoundTriggerHw::RecognitionConfig& config,
+                                             const sp<V2_1::ISoundTriggerHwCallback>& /*callback*/,
+                                             int32_t /*cookie*/) override {
+            return mImpl->startRecognition_2_1(modelHandle, config);
+        }
+        Return<void> getParameters(const hidl_vec<hidl_string>& /*keys*/,
+                                   getParameters_cb _hidl_cb) override {
+            _hidl_cb(-ENOSYS, hidl_vec<ParameterValue>());
+            return Void();
+        }
+        Return<int32_t> setParameters(
+            const hidl_vec<V2_1::ISoundTriggerHw::ParameterValue>& /*parameters*/) override {
+            return -ENOSYS;
+        }
+        Return<void> getSoundModelParameters(int32_t /*modelHandle*/,
+                                             const hidl_vec<hidl_string>& /*keys*/,
+                                             getSoundModelParameters_cb _hidl_cb) override {
+            _hidl_cb(-ENOSYS, hidl_vec<ParameterValue>());
+            return Void();
+        }
+        Return<int32_t> setSoundModelParameters(
+            int32_t /*modelHandle*/,
+            const hidl_vec<V2_1::ISoundTriggerHw::ParameterValue>& /*parameters*/) override {
+            return -ENOSYS;
+        }
+
+       private:
+        sp<SoundTriggerHw> mImpl;
+    };
+
+    class SoundModelClient_2_1 : public SoundModelClient {
+       public:
+        SoundModelClient_2_1(uint32_t id, V2_1::ISoundTriggerHwCallback::CallbackCookie cookie,
+                             sp<V2_1::ISoundTriggerHwCallback> callback)
+            : SoundModelClient(id, cookie), mCallback(callback) {}
+
+        void recognitionCallback(struct sound_trigger_recognition_event* halEvent) override;
+        void soundModelCallback(struct sound_trigger_model_event* halEvent) override;
+
+       private:
+        sp<V2_1::ISoundTriggerHwCallback> mCallback;
+    };
+};
+
+extern "C" ISoundTriggerHw* HIDL_FETCH_ISoundTriggerHw(const char* name);
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace soundtrigger
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_SOUNDTRIGGER_V2_1_SOUNDTRIGGERHW_H
diff --git a/soundtrigger/2.1/vts/functional/Android.bp b/soundtrigger/2.1/vts/functional/Android.bp
new file mode 100644
index 0000000..925a17c
--- /dev/null
+++ b/soundtrigger/2.1/vts/functional/Android.bp
@@ -0,0 +1,28 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+cc_test {
+    name: "VtsHalSoundtriggerV2_1TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: ["VtsHalSoundtriggerV2_1TargetTest.cpp"],
+    static_libs: [
+                 "android.hidl.allocator@1.0",
+                 "android.hidl.memory@1.0",
+                 "android.hardware.soundtrigger@2.0",
+                 "android.hardware.soundtrigger@2.1",
+                 "libhidlmemory"
+                 ],
+}
diff --git a/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
new file mode 100644
index 0000000..9876cdd
--- /dev/null
+++ b/soundtrigger/2.1/vts/functional/VtsHalSoundtriggerV2_1TargetTest.cpp
@@ -0,0 +1,558 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SoundTriggerHidlHalTest"
+#include <stdlib.h>
+#include <time.h>
+
+#include <condition_variable>
+#include <mutex>
+
+#include <android/log.h>
+#include <cutils/native_handle.h>
+#include <log/log.h>
+
+#include <android/hardware/audio/common/2.0/types.h>
+#include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
+#include <android/hardware/soundtrigger/2.0/types.h>
+#include <android/hardware/soundtrigger/2.1/ISoundTriggerHw.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <hidlmemory/mapping.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#define SHORT_TIMEOUT_PERIOD (1)
+
+using ::android::sp;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::audio::common::V2_0::AudioDevice;
+using ::android::hardware::soundtrigger::V2_0::PhraseRecognitionExtra;
+using ::android::hardware::soundtrigger::V2_0::RecognitionMode;
+using ::android::hardware::soundtrigger::V2_0::SoundModelHandle;
+using ::android::hardware::soundtrigger::V2_0::SoundModelType;
+using V2_0_ISoundTriggerHw = ::android::hardware::soundtrigger::V2_0::ISoundTriggerHw;
+using V2_0_ISoundTriggerHwCallback =
+    ::android::hardware::soundtrigger::V2_0::ISoundTriggerHwCallback;
+using ::android::hardware::soundtrigger::V2_1::ISoundTriggerHw;
+using ParameterValue = ::android::hardware::soundtrigger::V2_1::ISoundTriggerHw::ParameterValue;
+using ::android::hardware::soundtrigger::V2_1::ISoundTriggerHwCallback;
+using ::android::hidl::allocator::V1_0::IAllocator;
+using ::android::hidl::memory::V1_0::IMemory;
+
+/**
+ * Test code uses this class to wait for notification from callback.
+ */
+class Monitor {
+   public:
+    Monitor() : mCount(0) {}
+
+    /**
+     * Adds 1 to the internal counter and unblocks one of the waiting threads.
+     */
+    void notify() {
+        std::unique_lock<std::mutex> lock(mMtx);
+        mCount++;
+        mCv.notify_one();
+    }
+
+    /**
+     * Blocks until the internal counter becomes greater than 0.
+     *
+     * If notified, this method decreases the counter by 1 and returns true.
+     * If timeout, returns false.
+     */
+    bool wait(int timeoutSeconds) {
+        auto deadline = std::chrono::system_clock::now() + std::chrono::seconds(timeoutSeconds);
+        std::unique_lock<std::mutex> lock(mMtx);
+        if (!mCv.wait_until(lock, deadline, [& count = mCount] { return count > 0; })) {
+            return false;
+        }
+        mCount--;
+        return true;
+    }
+
+   private:
+    std::mutex mMtx;
+    std::condition_variable mCv;
+    int mCount;
+};
+
+// The main test class for Sound Trigger HIDL HAL.
+class SoundTriggerHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+   public:
+    virtual void SetUp() override {
+        mSoundTriggerHal = ::testing::VtsHalHidlTargetTestBase::getService<ISoundTriggerHw>();
+        ASSERT_NE(nullptr, mSoundTriggerHal.get());
+        mCallback = new SoundTriggerHwCallback(*this);
+        ASSERT_NE(nullptr, mCallback.get());
+    }
+
+    static void SetUpTestCase() { srand(1234); }
+
+    class SoundTriggerHwCallback : public ISoundTriggerHwCallback {
+       private:
+        SoundTriggerHidlTest& mParent;
+
+       public:
+        SoundTriggerHwCallback(SoundTriggerHidlTest& parent) : mParent(parent) {}
+
+        Return<void> recognitionCallback(const V2_0_ISoundTriggerHwCallback::RecognitionEvent& event
+                                             __unused,
+                                         int32_t cookie __unused) override {
+            ALOGI("%s", __FUNCTION__);
+            return Void();
+        };
+
+        Return<void> phraseRecognitionCallback(
+            const V2_0_ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused,
+            int32_t cookie __unused) override {
+            ALOGI("%s", __FUNCTION__);
+            return Void();
+        };
+
+        Return<void> soundModelCallback(const V2_0_ISoundTriggerHwCallback::ModelEvent& event,
+                                        int32_t cookie __unused) override {
+            ALOGI("%s", __FUNCTION__);
+            mParent.lastModelEvent_2_0 = event;
+            mParent.monitor.notify();
+            return Void();
+        }
+
+        Return<void> recognitionCallback_2_1(const ISoundTriggerHwCallback::RecognitionEvent& event
+                                                 __unused,
+                                             int32_t cookie __unused) override {
+            ALOGI("%s", __FUNCTION__);
+            return Void();
+        }
+
+        Return<void> phraseRecognitionCallback_2_1(
+            const ISoundTriggerHwCallback::PhraseRecognitionEvent& event __unused,
+            int32_t cookie __unused) override {
+            ALOGI("%s", __FUNCTION__);
+            return Void();
+        }
+
+        Return<void> soundModelCallback_2_1(const ISoundTriggerHwCallback::ModelEvent& event,
+                                            int32_t cookie __unused) {
+            ALOGI("%s", __FUNCTION__);
+            mParent.lastModelEvent = event;
+            mParent.monitor.notify();
+            return Void();
+        }
+    };
+
+    virtual void TearDown() override {}
+
+    Monitor monitor;
+    // updated by soundModelCallback()
+    V2_0_ISoundTriggerHwCallback::ModelEvent lastModelEvent_2_0;
+    // updated by soundModelCallback_2_1()
+    ISoundTriggerHwCallback::ModelEvent lastModelEvent;
+
+   protected:
+    sp<ISoundTriggerHw> mSoundTriggerHal;
+    sp<SoundTriggerHwCallback> mCallback;
+};
+
+/**
+ * Test ISoundTriggerHw::getProperties() method
+ *
+ * Verifies that:
+ *  - the implementation implements the method
+ *  - the method returns 0 (no error)
+ *  - the implementation supports at least one sound model and one key phrase
+ *  - the implementation supports at least VOICE_TRIGGER recognition mode
+ */
+TEST_F(SoundTriggerHidlTest, GetProperties) {
+    ISoundTriggerHw::Properties halProperties;
+    Return<void> hidlReturn;
+    int ret = -ENODEV;
+
+    hidlReturn = mSoundTriggerHal->getProperties([&](int rc, auto res) {
+        ret = rc;
+        halProperties = res;
+    });
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_EQ(0, ret);
+    EXPECT_GT(halProperties.maxSoundModels, 0u);
+    EXPECT_GT(halProperties.maxKeyPhrases, 0u);
+    EXPECT_NE(0u, (halProperties.recognitionModes & (uint32_t)RecognitionMode::VOICE_TRIGGER));
+}
+
+/**
+ * Test ISoundTriggerHw::loadPhraseSoundModel() method
+ *
+ * Verifies that:
+ *  - the implementation implements the method
+ *  - the implementation returns an error when passed a malformed sound model
+ *
+ * There is no way to verify that implementation actually can load a sound model because each
+ * sound model is vendor specific.
+ */
+TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail) {
+    Return<void> hidlReturn;
+    int ret = -ENODEV;
+    V2_0_ISoundTriggerHw::PhraseSoundModel model;
+    SoundModelHandle handle;
+
+    model.common.type = SoundModelType::UNKNOWN;
+
+    hidlReturn =
+        mSoundTriggerHal->loadPhraseSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) {
+            ret = retval;
+            handle = res;
+        });
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_NE(0, ret);
+    EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadPhraseSoundModel_2_1() method
+ *
+ * Verifies that:
+ *  - the implementation implements the method
+ *  - the implementation returns an error when passed a malformed sound model
+ *
+ * There is no way to verify that implementation actually can load a sound model because each
+ * sound model is vendor specific.
+ */
+TEST_F(SoundTriggerHidlTest, LoadInvalidModelFail_2_1) {
+    Return<void> hidlReturn;
+    int ret = -ENODEV;
+    ISoundTriggerHw::PhraseSoundModel model;
+    SoundModelHandle handle;
+
+    model.common.header.type = SoundModelType::UNKNOWN;
+
+    hidlReturn = mSoundTriggerHal->loadPhraseSoundModel_2_1(model, mCallback, 0,
+                                                            [&](int32_t retval, auto res) {
+                                                                ret = retval;
+                                                                handle = res;
+                                                            });
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_NE(0, ret);
+    EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadSoundModel() method
+ *
+ * Verifies that:
+ *  - the implementation returns an error when passed an empty sound model
+ */
+TEST_F(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail) {
+    int ret = -ENODEV;
+    V2_0_ISoundTriggerHw::SoundModel model;
+    SoundModelHandle handle = 0;
+
+    model.type = SoundModelType::GENERIC;
+
+    Return<void> loadReturn =
+        mSoundTriggerHal->loadSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) {
+            ret = retval;
+            handle = res;
+        });
+
+    EXPECT_TRUE(loadReturn.isOk());
+    EXPECT_NE(0, ret);
+    EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadSoundModel() method
+ *
+ * Verifies that:
+ *  - the implementation returns error when passed a sound model with random data.
+ */
+TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail) {
+    int ret = -ENODEV;
+    V2_0_ISoundTriggerHw::SoundModel model;
+    SoundModelHandle handle = 0;
+
+    model.type = SoundModelType::GENERIC;
+    model.data.resize(100);
+    for (auto& d : model.data) {
+        d = rand();
+    }
+
+    Return<void> loadReturn =
+        mSoundTriggerHal->loadSoundModel(model, mCallback, 0, [&](int32_t retval, auto res) {
+            ret = retval;
+            handle = res;
+        });
+
+    EXPECT_TRUE(loadReturn.isOk());
+    EXPECT_NE(0, ret);
+    EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadSoundModel_2_1() method
+ *
+ * Verifies that:
+ *  - the implementation returns error when passed a sound model with random data.
+ */
+TEST_F(SoundTriggerHidlTest, LoadEmptyGenericSoundModelFail_2_1) {
+    int ret = -ENODEV;
+    ISoundTriggerHw::SoundModel model;
+    SoundModelHandle handle = 0;
+
+    model.header.type = SoundModelType::GENERIC;
+
+    Return<void> loadReturn =
+        mSoundTriggerHal->loadSoundModel_2_1(model, mCallback, 0, [&](int32_t retval, auto res) {
+            ret = retval;
+            handle = res;
+        });
+
+    EXPECT_TRUE(loadReturn.isOk());
+    EXPECT_NE(0, ret);
+    EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::loadSoundModel_2_1() method
+ *
+ * Verifies that:
+ *  - the implementation returns error when passed a sound model with random data.
+ */
+TEST_F(SoundTriggerHidlTest, LoadGenericSoundModelFail_2_1) {
+    int ret = -ENODEV;
+    ISoundTriggerHw::SoundModel model;
+    SoundModelHandle handle = 0;
+
+    model.header.type = SoundModelType::GENERIC;
+    sp<IAllocator> ashmem = IAllocator::getService("ashmem");
+    ASSERT_NE(nullptr, ashmem.get());
+    hidl_memory hmemory;
+    int size = 100;
+    Return<void> allocReturn = ashmem->allocate(size, [&](bool success, const hidl_memory& m) {
+        ASSERT_TRUE(success);
+        hmemory = m;
+    });
+    sp<IMemory> memory = ::android::hardware::mapMemory(hmemory);
+    ASSERT_NE(nullptr, memory.get());
+    memory->update();
+    for (uint8_t *p = static_cast<uint8_t*>(static_cast<void*>(memory->getPointer())); size >= 0;
+         p++, size--) {
+        *p = rand();
+    }
+
+    Return<void> loadReturn =
+        mSoundTriggerHal->loadSoundModel_2_1(model, mCallback, 0, [&](int32_t retval, auto res) {
+            ret = retval;
+            handle = res;
+        });
+
+    EXPECT_TRUE(loadReturn.isOk());
+    EXPECT_NE(0, ret);
+    EXPECT_FALSE(monitor.wait(SHORT_TIMEOUT_PERIOD));
+}
+
+/**
+ * Test ISoundTriggerHw::unloadSoundModel() method
+ *
+ * Verifies that:
+ *  - the implementation implements the method
+ *  - the implementation returns an error when called without a valid loaded sound model
+ *
+ */
+TEST_F(SoundTriggerHidlTest, UnloadModelNoModelFail) {
+    Return<int32_t> hidlReturn(0);
+    SoundModelHandle halHandle = 0;
+
+    hidlReturn = mSoundTriggerHal->unloadSoundModel(halHandle);
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_NE(0, hidlReturn);
+}
+
+/**
+ * Test ISoundTriggerHw::startRecognition() method
+ *
+ * Verifies that:
+ *  - the implementation implements the method
+ *  - the implementation returns an error when called without a valid loaded sound model
+ *
+ * There is no way to verify that implementation actually starts recognition because no model can
+ * be loaded.
+ */
+TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail) {
+    Return<int32_t> hidlReturn(0);
+    SoundModelHandle handle = 0;
+    PhraseRecognitionExtra phrase;
+    V2_0_ISoundTriggerHw::RecognitionConfig config;
+
+    config.captureHandle = 0;
+    config.captureDevice = AudioDevice::IN_BUILTIN_MIC;
+    phrase.id = 0;
+    phrase.recognitionModes = (uint32_t)RecognitionMode::VOICE_TRIGGER;
+    phrase.confidenceLevel = 0;
+
+    config.phrases.setToExternal(&phrase, 1);
+
+    hidlReturn = mSoundTriggerHal->startRecognition(handle, config, mCallback, 0);
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_NE(0, hidlReturn);
+}
+
+/**
+ * Test ISoundTriggerHw::startRecognition_2_1() method
+ *
+ * Verifies that:
+ *  - the implementation implements the method
+ *  - the implementation returns an error when called without a valid loaded sound model
+ *
+ * There is no way to verify that implementation actually starts recognition because no model can
+ * be loaded.
+ */
+TEST_F(SoundTriggerHidlTest, StartRecognitionNoModelFail_2_1) {
+    Return<int32_t> hidlReturn(0);
+    SoundModelHandle handle = 0;
+    PhraseRecognitionExtra phrase;
+    ISoundTriggerHw::RecognitionConfig config;
+
+    config.header.captureHandle = 0;
+    config.header.captureDevice = AudioDevice::IN_BUILTIN_MIC;
+    phrase.id = 0;
+    phrase.recognitionModes = (uint32_t)RecognitionMode::VOICE_TRIGGER;
+    phrase.confidenceLevel = 0;
+
+    config.header.phrases.setToExternal(&phrase, 1);
+
+    hidlReturn = mSoundTriggerHal->startRecognition_2_1(handle, config, mCallback, 0);
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_NE(0, hidlReturn);
+}
+
+/**
+ * Test ISoundTriggerHw::stopRecognition() method
+ *
+ * Verifies that:
+ *  - the implementation implements the method
+ *  - the implementation returns an error when called without an active recognition running
+ *
+ */
+TEST_F(SoundTriggerHidlTest, StopRecognitionNoAStartFail) {
+    Return<int32_t> hidlReturn(0);
+    SoundModelHandle handle = 0;
+
+    hidlReturn = mSoundTriggerHal->stopRecognition(handle);
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_NE(0, hidlReturn);
+}
+
+/**
+ * Test ISoundTriggerHw::stopAllRecognitions() method
+ *
+ * Verifies that:
+ *  - the implementation implements this optional method or indicates it is not supported by
+ *  returning -ENOSYS
+ */
+TEST_F(SoundTriggerHidlTest, stopAllRecognitions) {
+    Return<int32_t> hidlReturn(0);
+
+    hidlReturn = mSoundTriggerHal->stopAllRecognitions();
+
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
+}
+
+/**
+ * Test ISoundTriggerHw::getParameters() and setParameters() methods
+ *
+ * Verifies that:
+ *  - the implementation implements these optional methods or indicates it is not supported by
+ *  returning -ENOSYS
+ */
+TEST_F(SoundTriggerHidlTest, getAndSetParameters) {
+    hidl_vec<hidl_string> keys;
+    hidl_vec<ParameterValue> values;
+
+    int32_t ret = -ENODEV;
+    Return<void> hidlReturn =
+        mSoundTriggerHal->getParameters(keys, [&](int32_t retval, auto params) {
+            ret = retval;
+            values = params;
+        });
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_TRUE(ret == 0 || ret == -ENOSYS);
+    if (ret == 0) {
+        Return<int32_t> hidlReturn = mSoundTriggerHal->setParameters(values);
+        EXPECT_TRUE(hidlReturn.isOk());
+        EXPECT_EQ(0, hidlReturn);
+    }
+}
+
+/**
+ * Test ISoundTriggerHw::setParameters() method
+ *
+ * Verifies that:
+ *  - the implementation accepts empty parameters to be set or indicates it is not supported by
+ *  returning -ENOSYS
+ */
+TEST_F(SoundTriggerHidlTest, setParameters) {
+    hidl_vec<ParameterValue> values;
+    Return<int32_t> hidlReturn = mSoundTriggerHal->setParameters(values);
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_TRUE(hidlReturn == 0 || hidlReturn == -ENOSYS);
+}
+
+/**
+ * Test ISoundTriggerHw::getSoundModelParameters() and setSoundModelParameters() methods
+ *
+ * Verifies that:
+ *  - the implementation implements these optional methods or indicates it is not supported by
+ *  returning -ENOSYS;
+ *  - if the methods are supported, the implementation returns an error when called without
+ *  an active recognition running.
+ *
+ */
+TEST_F(SoundTriggerHidlTest, getAndSetSoundModelParameters) {
+    SoundModelHandle handle = 0;
+    hidl_vec<hidl_string> keys;
+    hidl_vec<ParameterValue> values;
+
+    {
+        int32_t ret = 0;
+        Return<void> hidlReturn = mSoundTriggerHal->getSoundModelParameters(
+            handle, keys, [&](int32_t retval, auto params) {
+                ret = retval;
+                values = params;
+            });
+        EXPECT_TRUE(hidlReturn.isOk());
+        EXPECT_NE(0, ret);
+        EXPECT_EQ(0u, values.size());
+    }
+
+    values.resize(0);
+    {
+        Return<int32_t> hidlReturn = mSoundTriggerHal->setSoundModelParameters(handle, values);
+        EXPECT_TRUE(hidlReturn.isOk());
+        EXPECT_NE(0, hidlReturn);
+    }
+}
diff --git a/wifi/1.2/Android.bp b/wifi/1.2/Android.bp
index 49752a1..100b36b 100644
--- a/wifi/1.2/Android.bp
+++ b/wifi/1.2/Android.bp
@@ -7,14 +7,23 @@
         enabled: true,
     },
     srcs: [
+        "types.hal",
         "IWifi.hal",
         "IWifiChip.hal",
+        "IWifiNanIface.hal",
+        "IWifiNanIfaceEventCallback.hal",
     ],
     interfaces: [
         "android.hardware.wifi@1.0",
         "android.hardware.wifi@1.1",
         "android.hidl.base@1.0",
     ],
+    types: [
+        "NanConfigRequestSupplemental",
+        "NanDataPathChannelInfo",
+        "NanDataPathConfirmInd",
+        "NanDataPathScheduleUpdateInd",
+    ],
     gen_java: true,
 }
 
diff --git a/wifi/1.2/IWifiNanIface.hal b/wifi/1.2/IWifiNanIface.hal
new file mode 100644
index 0000000..0260162
--- /dev/null
+++ b/wifi/1.2/IWifiNanIface.hal
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.2;
+
+import @1.0::CommandIdShort;
+import @1.0::IWifiNanIface;
+import @1.0::NanConfigRequest;
+import @1.0::NanEnableRequest;
+import @1.0::WifiStatus;
+import IWifiNanIfaceEventCallback;
+
+/**
+ * Interface used to represent a single NAN (Neighbour Aware Network) iface.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+interface IWifiNanIface extends @1.0::IWifiNanIface {
+    /**
+     * Requests notifications of significant events on this iface. Multiple calls
+     * to this must register multiple callbacks each of which must receive all
+     * events.
+     *
+     * Note: supersedes the @1.0::IWifiNanIface.registerEventCallback() method which is deprecated
+     * as of HAL version 1.2.
+     *
+     * @param callback An instance of the |IWifiNanIfaceEventCallback| HIDL interface
+     *        object.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|
+     */
+    registerEventCallback_1_2(IWifiNanIfaceEventCallback callback)
+        generates (WifiStatus status);
+
+    /**
+     * Enable NAN: configures and activates NAN clustering (does not start
+     * a discovery session or set up data-interfaces or data-paths). Use the
+     * |IWifiNanIface.configureRequest| method to change the configuration of an already enabled
+     * NAN interface.
+     * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyEnableResponse|.
+     *
+     * Note: supersedes the @1.0::IWifiNanIface.enableRequest() method which is deprecated as of
+     * HAL version 1.2.
+     *
+     * @param cmdId command Id to use for this invocation.
+     * @param msg1 Instance of |NanEnableRequest|.
+     * @param msg2 Instance of |NanConfigRequestSupplemental|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    enableRequest_1_2(CommandIdShort cmdId, NanEnableRequest msg1,
+                      NanConfigRequestSupplemental msg2)
+        generates (WifiStatus status);
+
+    /**
+     * Configure NAN: configures an existing NAN functionality (i.e. assumes
+     * |IWifiNanIface.enableRequest| already submitted and succeeded).
+     * Asynchronous response is with |IWifiNanIfaceEventCallback.notifyConfigResponse|.
+     *
+     * Note: supersedes the @1.0::IWifiNanIface.configRequest() method which is deprecated as of
+     * HAL version 1.2.
+     *
+     * @param cmdId command Id to use for this invocation.
+     * @param msg1 Instance of |NanConfigRequest|.
+     * @param msg1 Instance of |NanConfigRequestSupplemental|.
+     * @return status WifiStatus of the operation.
+     *         Possible status codes:
+     *         |WifiStatusCode.SUCCESS|,
+     *         |WifiStatusCode.ERROR_WIFI_IFACE_INVALID|,
+     *         |WifiStatusCode.ERROR_INVALID_ARGS|,
+     *         |WifiStatusCode.ERROR_UNKNOWN|
+     */
+    configRequest_1_2(CommandIdShort cmdId, NanConfigRequest msg1,
+                      NanConfigRequestSupplemental msg2)
+        generates (WifiStatus status);
+};
diff --git a/wifi/1.2/IWifiNanIfaceEventCallback.hal b/wifi/1.2/IWifiNanIfaceEventCallback.hal
new file mode 100644
index 0000000..efd5479
--- /dev/null
+++ b/wifi/1.2/IWifiNanIfaceEventCallback.hal
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.2;
+
+import @1.0::IWifiNanIfaceEventCallback;
+
+/**
+ * NAN Response and Asynchronous Event Callbacks.
+ *
+ * References to "NAN Spec" are to the Wi-Fi Alliance "Wi-Fi Neighbor Awareness
+ * Networking (NAN) Technical Specification".
+ */
+interface IWifiNanIfaceEventCallback extends @1.0::IWifiNanIfaceEventCallback {
+    /**
+     * Asynchronous callback indicating a data-path (NDP) setup has been completed: received by
+     * both Initiator and Responder.
+     *
+     * Note: supersedes the @1.0::IWifiNanIfaceEventCallback.eventDataPathConfirm() method which is
+     * deprecated as of HAL version 1.2.
+     *
+     * @param event: NanDataPathConfirmInd containing event details.
+     */
+    oneway eventDataPathConfirm_1_2(NanDataPathConfirmInd event);
+
+    /**
+     * Asynchronous callback indicating a data-path (NDP) schedule has been updated (e.g. channels
+     * have been changed).
+     *
+     * @param event: NanDataPathScheduleUpdateInd containing event details.
+     */
+    oneway eventDataPathScheduleUpdate(NanDataPathScheduleUpdateInd event);
+};
\ No newline at end of file
diff --git a/wifi/1.2/default/hidl_struct_util.cpp b/wifi/1.2/default/hidl_struct_util.cpp
index 5d48109..3ca35f7 100644
--- a/wifi/1.2/default/hidl_struct_util.cpp
+++ b/wifi/1.2/default/hidl_struct_util.cpp
@@ -1118,6 +1118,33 @@
     return true;
 }
 
+bool convertHidlNanEnableRequest_1_2ToLegacy(
+    const NanEnableRequest& hidl_request1,
+    const NanConfigRequestSupplemental& hidl_request2,
+    legacy_hal::NanEnableRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR)
+            << "convertHidlNanEnableRequest_1_2ToLegacy: null legacy_request";
+        return false;
+    }
+
+    *legacy_request = {};
+    if (!convertHidlNanEnableRequestToLegacy(hidl_request1, legacy_request)) {
+        return false;
+    }
+
+    legacy_request->config_discovery_beacon_int = 1;
+    legacy_request->discovery_beacon_interval =
+        hidl_request2.discoveryBeaconIntervalMs;
+    legacy_request->config_nss = 1;
+    legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
+    legacy_request->config_dw_early_termination = 1;
+    legacy_request->enable_dw_termination =
+        hidl_request2.enableDiscoveryWindowEarlyTermination;
+
+    return true;
+}
+
 bool convertHidlNanPublishRequestToLegacy(
     const NanPublishRequest& hidl_request,
     legacy_hal::NanPublishRequest* legacy_request) {
@@ -1600,6 +1627,33 @@
     return true;
 }
 
+bool convertHidlNanConfigRequest_1_2ToLegacy(
+    const NanConfigRequest& hidl_request1,
+    const NanConfigRequestSupplemental& hidl_request2,
+    legacy_hal::NanConfigRequest* legacy_request) {
+    if (!legacy_request) {
+        LOG(ERROR) << "convertHidlNanConfigRequest_1_2ToLegacy: legacy_request "
+                      "is null";
+        return false;
+    }
+
+    *legacy_request = {};
+    if (!convertHidlNanConfigRequestToLegacy(hidl_request1, legacy_request)) {
+        return false;
+    }
+
+    legacy_request->config_discovery_beacon_int = 1;
+    legacy_request->discovery_beacon_interval =
+        hidl_request2.discoveryBeaconIntervalMs;
+    legacy_request->config_nss = 1;
+    legacy_request->nss = hidl_request2.numberOfSpatialStreamsInDiscovery;
+    legacy_request->config_dw_early_termination = 1;
+    legacy_request->enable_dw_termination =
+        hidl_request2.enableDiscoveryWindowEarlyTermination;
+
+    return true;
+}
+
 bool convertHidlNanDataPathInitiatorRequestToLegacy(
     const NanInitiateDataPathRequest& hidl_request,
     legacy_hal::NanDataPathInitiatorRequest* legacy_request) {
@@ -1902,6 +1956,22 @@
     return true;
 }
 
+bool convertLegacyNdpChannelInfoToHidl(
+    const legacy_hal::NanChannelInfo& legacy_struct,
+    NanDataPathChannelInfo* hidl_struct) {
+    if (!hidl_struct) {
+        LOG(ERROR) << "convertLegacyNdpChannelInfoToHidl: hidl_struct is null";
+        return false;
+    }
+    *hidl_struct = {};
+
+    hidl_struct->channelFreq = legacy_struct.channel;
+    hidl_struct->channelBandwidth = legacy_struct.bandwidth;
+    hidl_struct->numSpatialStreams = legacy_struct.nss;
+
+    return true;
+}
+
 bool convertLegacyNanDataPathConfirmIndToHidl(
     const legacy_hal::NanDataPathConfirmInd& legacy_ind,
     NanDataPathConfirmInd* hidl_ind) {
@@ -1912,18 +1982,60 @@
     }
     *hidl_ind = {};
 
-    hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
-    hidl_ind->dataPathSetupSuccess =
+    hidl_ind->V1_0.ndpInstanceId = legacy_ind.ndp_instance_id;
+    hidl_ind->V1_0.dataPathSetupSuccess =
         legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT;
-    hidl_ind->peerNdiMacAddr =
+    hidl_ind->V1_0.peerNdiMacAddr =
         hidl_array<uint8_t, 6>(legacy_ind.peer_ndi_mac_addr);
-    hidl_ind->appInfo =
+    hidl_ind->V1_0.appInfo =
         std::vector<uint8_t>(legacy_ind.app_info.ndp_app_info,
                              legacy_ind.app_info.ndp_app_info +
                                  legacy_ind.app_info.ndp_app_info_len);
-    hidl_ind->status.status =
+    hidl_ind->V1_0.status.status =
         convertLegacyNanStatusTypeToHidl(legacy_ind.reason_code);
-    hidl_ind->status.description = "";  // TODO: b/34059183
+    hidl_ind->V1_0.status.description = "";  // TODO: b/34059183
+
+    std::vector<NanDataPathChannelInfo> channelInfo;
+    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+        NanDataPathChannelInfo hidl_struct;
+        if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
+                                               &hidl_struct)) {
+            return false;
+        }
+        channelInfo.push_back(hidl_struct);
+    }
+    hidl_ind->channelInfo = channelInfo;
+
+    return true;
+}
+
+bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
+    const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+    NanDataPathScheduleUpdateInd* hidl_ind) {
+    if (!hidl_ind) {
+        LOG(ERROR) << "convertLegacyNanDataPathScheduleUpdateIndToHidl: "
+                      "hidl_ind is null";
+        return false;
+    }
+    *hidl_ind = {};
+
+    hidl_ind->peerDiscoveryAddress =
+        hidl_array<uint8_t, 6>(legacy_ind.peer_mac_addr);
+    std::vector<NanDataPathChannelInfo> channelInfo;
+    for (unsigned int i = 0; i < legacy_ind.num_channels; ++i) {
+        NanDataPathChannelInfo hidl_struct;
+        if (!convertLegacyNdpChannelInfoToHidl(legacy_ind.channel_info[i],
+                                               &hidl_struct)) {
+            return false;
+        }
+        channelInfo.push_back(hidl_struct);
+    }
+    hidl_ind->channelInfo = channelInfo;
+    std::vector<uint32_t> ndpInstanceIds;
+    for (unsigned int i = 0; i < legacy_ind.num_ndp_instances; ++i) {
+        ndpInstanceIds.push_back(legacy_ind.ndp_instance_id[i]);
+    }
+    hidl_ind->ndpInstanceIds = ndpInstanceIds;
 
     return true;
 }
diff --git a/wifi/1.2/default/hidl_struct_util.h b/wifi/1.2/default/hidl_struct_util.h
index 6766b0f..1208afd 100644
--- a/wifi/1.2/default/hidl_struct_util.h
+++ b/wifi/1.2/default/hidl_struct_util.h
@@ -22,6 +22,7 @@
 #include <android/hardware/wifi/1.0/IWifiChip.h>
 #include <android/hardware/wifi/1.0/types.h>
 #include <android/hardware/wifi/1.1/IWifiChip.h>
+#include <android/hardware/wifi/1.2/types.h>
 
 #include "wifi_legacy_hal.h"
 
@@ -106,6 +107,14 @@
 bool convertHidlNanConfigRequestToLegacy(
     const NanConfigRequest& hidl_request,
     legacy_hal::NanConfigRequest* legacy_request);
+bool convertHidlNanEnableRequest_1_2ToLegacy(
+    const NanEnableRequest& hidl_request1,
+    const NanConfigRequestSupplemental& hidl_request2,
+    legacy_hal::NanEnableRequest* legacy_request);
+bool convertHidlNanConfigRequest_1_2ToLegacy(
+    const NanConfigRequest& hidl_request1,
+    const NanConfigRequestSupplemental& hidl_request2,
+    legacy_hal::NanConfigRequest* legacy_request);
 bool convertHidlNanPublishRequestToLegacy(
     const NanPublishRequest& hidl_request,
     legacy_hal::NanPublishRequest* legacy_request);
@@ -138,6 +147,9 @@
 bool convertLegacyNanDataPathConfirmIndToHidl(
     const legacy_hal::NanDataPathConfirmInd& legacy_ind,
     NanDataPathConfirmInd* hidl_ind);
+bool convertLegacyNanDataPathScheduleUpdateIndToHidl(
+    const legacy_hal::NanDataPathScheduleUpdateInd& legacy_ind,
+    NanDataPathScheduleUpdateInd* hidl_ind);
 
 // RTT controller conversion methods.
 bool convertHidlVectorOfRttConfigToLegacy(
diff --git a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
index f73869b..1b082d0 100644
--- a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
@@ -117,8 +117,10 @@
             });
         } else if (type == IfaceType::NAN) {
             chip_->createNanIface(
-                [&iface_name](const WifiStatus& status,
-                              const sp<IWifiNanIface>& iface) {
+                [&iface_name](
+                    const WifiStatus& status,
+                    const sp<android::hardware::wifi::V1_0::IWifiNanIface>&
+                        iface) {
                     if (WifiStatusCode::SUCCESS == status.code) {
                         ASSERT_NE(iface.get(), nullptr);
                         iface->getName([&iface_name](const WifiStatus& status,
diff --git a/wifi/1.2/default/wifi_chip.cpp b/wifi/1.2/default/wifi_chip.cpp
index adba054..8d9cfc6 100644
--- a/wifi/1.2/default/wifi_chip.cpp
+++ b/wifi/1.2/default/wifi_chip.cpp
@@ -387,7 +387,8 @@
     std::tie(legacy_status, legacy_logger_feature_set) =
         legacy_hal_.lock()->getLoggerSupportedFeatureSet(getWlan0IfaceName());
     if (legacy_status != legacy_hal::WIFI_SUCCESS) {
-        return {createWifiStatusFromLegacyError(legacy_status), 0};
+        // some devices don't support querying logger feature set
+        legacy_logger_feature_set = 0;
     }
     uint32_t hidl_caps;
     if (!hidl_struct_util::convertLegacyFeaturesToHidlChipCapabilities(
diff --git a/wifi/1.2/default/wifi_nan_iface.cpp b/wifi/1.2/default/wifi_nan_iface.cpp
index 12e4d7b..535e3d3 100644
--- a/wifi/1.2/default/wifi_nan_iface.cpp
+++ b/wifi/1.2/default/wifi_nan_iface.cpp
@@ -428,7 +428,7 @@
             }
 
             for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
-                if (!callback->eventDataPathConfirm(hidl_struct).isOk()) {
+                if (!callback->eventDataPathConfirm_1_2(hidl_struct).isOk()) {
                     LOG(ERROR) << "Failed to invoke the callback";
                 }
             }
@@ -467,10 +467,28 @@
             LOG(ERROR) << "on_event_range_report - should not be called";
         };
 
-    callback_handlers.on_event_schedule_update =
-        [weak_ptr_this](const legacy_hal::NanDataPathScheduleUpdateInd& /* msg */) {
-            LOG(ERROR) << "on_event_schedule_update - should not be called";
-        };
+    callback_handlers
+        .on_event_schedule_update = [weak_ptr_this](
+                                        const legacy_hal::
+                                            NanDataPathScheduleUpdateInd& msg) {
+        const auto shared_ptr_this = weak_ptr_this.promote();
+        if (!shared_ptr_this.get() || !shared_ptr_this->isValid()) {
+            LOG(ERROR) << "Callback invoked on an invalid object";
+            return;
+        }
+        NanDataPathScheduleUpdateInd hidl_struct;
+        if (!hidl_struct_util::convertLegacyNanDataPathScheduleUpdateIndToHidl(
+                msg, &hidl_struct)) {
+            LOG(ERROR) << "Failed to convert nan capabilities response";
+            return;
+        }
+
+        for (const auto& callback : shared_ptr_this->getEventCallbacks()) {
+            if (!callback->eventDataPathScheduleUpdate(hidl_struct).isOk()) {
+                LOG(ERROR) << "Failed to invoke the callback";
+            }
+        }
+    };
 
     legacy_hal::wifi_error legacy_status =
         legacy_hal_.lock()->nanRegisterCallbackHandlers(ifname_,
@@ -511,7 +529,7 @@
 }
 
 Return<void> WifiNanIface::registerEventCallback(
-    const sp<IWifiNanIfaceEventCallback>& callback,
+    const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
     registerEventCallback_cb hidl_status_cb) {
     return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
                            &WifiNanIface::registerEventCallbackInternal,
@@ -628,6 +646,32 @@
                            hidl_status_cb, cmd_id, ndpInstanceId);
 }
 
+Return<void> WifiNanIface::registerEventCallback_1_2(
+    const sp<IWifiNanIfaceEventCallback>& callback,
+    registerEventCallback_1_2_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::registerEventCallback_1_2Internal,
+                           hidl_status_cb, callback);
+}
+
+Return<void> WifiNanIface::enableRequest_1_2(
+    uint16_t cmd_id, const NanEnableRequest& msg1,
+    const NanConfigRequestSupplemental& msg2,
+    enableRequest_1_2_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::enableRequest_1_2Internal,
+                           hidl_status_cb, cmd_id, msg1, msg2);
+}
+
+Return<void> WifiNanIface::configRequest_1_2(
+    uint16_t cmd_id, const NanConfigRequest& msg1,
+    const NanConfigRequestSupplemental& msg2,
+    configRequest_1_2_cb hidl_status_cb) {
+    return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+                           &WifiNanIface::configRequest_1_2Internal,
+                           hidl_status_cb, cmd_id, msg1, msg2);
+}
+
 std::pair<WifiStatus, std::string> WifiNanIface::getNameInternal() {
     return {createWifiStatus(WifiStatusCode::SUCCESS), ifname_};
 }
@@ -637,11 +681,8 @@
 }
 
 WifiStatus WifiNanIface::registerEventCallbackInternal(
-    const sp<IWifiNanIfaceEventCallback>& callback) {
-    if (!event_cb_handler_.addCallback(callback)) {
-        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
-    }
-    return createWifiStatus(WifiStatusCode::SUCCESS);
+    const sp<V1_0::IWifiNanIfaceEventCallback>& /*callback*/) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
 }
 
 WifiStatus WifiNanIface::getCapabilitiesRequestInternal(uint16_t cmd_id) {
@@ -650,28 +691,14 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
-WifiStatus WifiNanIface::enableRequestInternal(uint16_t cmd_id,
-                                               const NanEnableRequest& msg) {
-    legacy_hal::NanEnableRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanEnableRequestToLegacy(msg,
-                                                               &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanEnableRequest(ifname_, cmd_id, legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
+WifiStatus WifiNanIface::enableRequestInternal(
+    uint16_t /* cmd_id */, const NanEnableRequest& /* msg */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
 }
 
-WifiStatus WifiNanIface::configRequestInternal(uint16_t cmd_id,
-                                               const NanConfigRequest& msg) {
-    legacy_hal::NanConfigRequest legacy_msg;
-    if (!hidl_struct_util::convertHidlNanConfigRequestToLegacy(msg,
-                                                               &legacy_msg)) {
-        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
-    }
-    legacy_hal::wifi_error legacy_status =
-        legacy_hal_.lock()->nanConfigRequest(ifname_, cmd_id, legacy_msg);
-    return createWifiStatusFromLegacyError(legacy_status);
+WifiStatus WifiNanIface::configRequestInternal(
+    uint16_t /* cmd_id */, const NanConfigRequest& /* msg */) {
+    return createWifiStatus(WifiStatusCode::ERROR_NOT_SUPPORTED);
 }
 
 WifiStatus WifiNanIface::disableRequestInternal(uint16_t cmd_id) {
@@ -780,6 +807,40 @@
     return createWifiStatusFromLegacyError(legacy_status);
 }
 
+WifiStatus WifiNanIface::registerEventCallback_1_2Internal(
+    const sp<IWifiNanIfaceEventCallback>& callback) {
+    if (!event_cb_handler_.addCallback(callback)) {
+        return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
+    }
+    return createWifiStatus(WifiStatusCode::SUCCESS);
+}
+
+WifiStatus WifiNanIface::enableRequest_1_2Internal(
+    uint16_t cmd_id, const NanEnableRequest& msg1,
+    const NanConfigRequestSupplemental& msg2) {
+    legacy_hal::NanEnableRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanEnableRequest_1_2ToLegacy(
+            msg1, msg2, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanEnableRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
+WifiStatus WifiNanIface::configRequest_1_2Internal(
+    uint16_t cmd_id, const NanConfigRequest& msg1,
+    const NanConfigRequestSupplemental& msg2) {
+    legacy_hal::NanConfigRequest legacy_msg;
+    if (!hidl_struct_util::convertHidlNanConfigRequest_1_2ToLegacy(
+            msg1, msg2, &legacy_msg)) {
+        return createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS);
+    }
+    legacy_hal::wifi_error legacy_status =
+        legacy_hal_.lock()->nanConfigRequest(ifname_, cmd_id, legacy_msg);
+    return createWifiStatusFromLegacyError(legacy_status);
+}
+
 }  // namespace implementation
 }  // namespace V1_2
 }  // namespace wifi
diff --git a/wifi/1.2/default/wifi_nan_iface.h b/wifi/1.2/default/wifi_nan_iface.h
index 6fa7b0c..a2dcf3a 100644
--- a/wifi/1.2/default/wifi_nan_iface.h
+++ b/wifi/1.2/default/wifi_nan_iface.h
@@ -18,8 +18,8 @@
 #define WIFI_NAN_IFACE_H_
 
 #include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiNanIface.h>
 #include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
+#include <android/hardware/wifi/1.2/IWifiNanIface.h>
 
 #include "hidl_callback_util.h"
 #include "wifi_legacy_hal.h"
@@ -34,7 +34,7 @@
 /**
  * HIDL interface object used to control a NAN Iface instance.
  */
-class WifiNanIface : public V1_0::IWifiNanIface {
+class WifiNanIface : public V1_2::IWifiNanIface {
    public:
     WifiNanIface(const std::string& ifname,
                  const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
@@ -47,7 +47,7 @@
     Return<void> getName(getName_cb hidl_status_cb) override;
     Return<void> getType(getType_cb hidl_status_cb) override;
     Return<void> registerEventCallback(
-        const sp<IWifiNanIfaceEventCallback>& callback,
+        const sp<V1_0::IWifiNanIfaceEventCallback>& callback,
         registerEventCallback_cb hidl_status_cb) override;
     Return<void> getCapabilitiesRequest(
         uint16_t cmd_id, getCapabilitiesRequest_cb hidl_status_cb) override;
@@ -88,12 +88,24 @@
         uint16_t cmd_id, uint32_t ndpInstanceId,
         terminateDataPathRequest_cb hidl_status_cb) override;
 
+    Return<void> registerEventCallback_1_2(
+        const sp<IWifiNanIfaceEventCallback>& callback,
+        registerEventCallback_1_2_cb hidl_status_cb) override;
+    Return<void> enableRequest_1_2(
+        uint16_t cmd_id, const NanEnableRequest& msg1,
+        const NanConfigRequestSupplemental& msg2,
+        enableRequest_1_2_cb hidl_status_cb) override;
+    Return<void> configRequest_1_2(
+        uint16_t cmd_id, const NanConfigRequest& msg1,
+        const NanConfigRequestSupplemental& msg2,
+        configRequest_1_2_cb hidl_status_cb) override;
+
    private:
     // Corresponding worker functions for the HIDL methods.
     std::pair<WifiStatus, std::string> getNameInternal();
     std::pair<WifiStatus, IfaceType> getTypeInternal();
     WifiStatus registerEventCallbackInternal(
-        const sp<IWifiNanIfaceEventCallback>& callback);
+        const sp<V1_0::IWifiNanIfaceEventCallback>& callback);
     WifiStatus getCapabilitiesRequestInternal(uint16_t cmd_id);
     WifiStatus enableRequestInternal(uint16_t cmd_id,
                                      const NanEnableRequest& msg);
@@ -119,6 +131,15 @@
     WifiStatus terminateDataPathRequestInternal(uint16_t cmd_id,
                                                 uint32_t ndpInstanceId);
 
+    WifiStatus registerEventCallback_1_2Internal(
+        const sp<IWifiNanIfaceEventCallback>& callback);
+    WifiStatus enableRequest_1_2Internal(
+        uint16_t cmd_id, const NanEnableRequest& msg1,
+        const NanConfigRequestSupplemental& msg2);
+    WifiStatus configRequest_1_2Internal(
+        uint16_t cmd_id, const NanConfigRequest& msg,
+        const NanConfigRequestSupplemental& msg2);
+
     std::set<sp<IWifiNanIfaceEventCallback>> getEventCallbacks();
 
     std::string ifname_;
diff --git a/wifi/1.2/types.hal b/wifi/1.2/types.hal
new file mode 100644
index 0000000..60f4b1f
--- /dev/null
+++ b/wifi/1.2/types.hal
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi@1.2;
+
+import @1.0::MacAddress;
+import @1.0::NanDataPathConfirmInd;
+import @1.0::WifiChannelInMhz;
+
+/**
+ * NAN configuration request parameters added in the 1.2 HAL. These are supplemental to previous
+ * versions.
+ */
+struct NanConfigRequestSupplemental {
+    /**
+     * Specify the Discovery Beacon interval in ms. Specification only applicable if the device
+     * transmits Discovery Beacons (based on the Wi-Fi Aware protocol selection criteria). The value
+     * can be increased to reduce power consumption (on devices which would transmit Discovery
+     * Beacons), however - cluster synchronization time will likely increase.
+     * Values are:
+     *  - A value of 0 indicates that the HAL sets the interval to a default (implementation specific)
+     *  - A positive value
+     */
+    uint32_t discoveryBeaconIntervalMs;
+    /**
+     * The number of spatial streams to be used for transmitting NAN management frames (does NOT apply
+     * to data-path packets). A small value may reduce power consumption for small discovery packets.
+     * Values are:
+     *  - A value of 0 indicates that the HAL sets the number to a default (implementation specific)
+     *  - A positive value
+     */
+    uint32_t numberOfSpatialStreamsInDiscovery;
+    /**
+     * Controls whether the device may terminate listening on a Discovery Window (DW) earlier than the
+     * DW termination (16ms) if no information is received. Enabling the feature will result in
+     * lower power consumption, but may result in some missed messages and hence increased latency.
+     */
+    bool enableDiscoveryWindowEarlyTermination;
+};
+
+/**
+ * NAN data path channel information provided to the framework.
+ */
+struct NanDataPathChannelInfo {
+    /**
+     * Channel frequency in MHz.
+     */
+    WifiChannelInMhz channelFreq;
+    /**
+     * Channel bandwidth in MHz.
+     */
+    uint32_t channelBandwidth;
+    /**
+     * Number of spatial streams used in the channel.
+     */
+    uint32_t numSpatialStreams;
+};
+
+/**
+ * NAN Data path confirmation Indication structure.
+ * Event indication is received on both initiator and responder side when negotiation for a
+ * data-path finish: on success or failure.
+ */
+struct NanDataPathConfirmInd {
+    /**
+     * Baseline information as defined in HAL 1.0.
+     */
+    @1.0::NanDataPathConfirmInd V1_0;
+    /**
+     * The channel(s) on which the NDP is scheduled to operate.
+     * Updates to the operational channels are provided using the |eventDataPathScheduleUpdate|
+     * event.
+     */
+    vec<NanDataPathChannelInfo> channelInfo;
+};
+
+/**
+ * NAN data path channel information update indication structure.
+ * Event indication is received by all NDP owners whenever the channels on which the NDP operates
+ * are updated.
+ * Note: multiple NDPs may share the same schedule, the indication specifies all NDPs to which it
+ * applies.
+ */
+struct NanDataPathScheduleUpdateInd {
+    /**
+     * The discovery address (NMI) of the peer to which the NDP is connected.
+     */
+    MacAddress peerDiscoveryAddress;
+    /**
+     * The updated channel(s) information.
+     */
+    vec<NanDataPathChannelInfo> channelInfo;
+    /**
+     * The list of NDPs to which this update applies.
+     */
+    vec<uint32_t> ndpInstanceIds;
+};
diff --git a/wifi/hostapd/1.0/Android.bp b/wifi/hostapd/1.0/Android.bp
new file mode 100644
index 0000000..a17e153
--- /dev/null
+++ b/wifi/hostapd/1.0/Android.bp
@@ -0,0 +1,23 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.wifi.hostapd@1.0",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IHostapd.hal",
+    ],
+    interfaces: [
+        "android.hardware.wifi.supplicant@1.0",
+        "android.hidl.base@1.0",
+    ],
+    types: [
+        "HostapdStatus",
+        "HostapdStatusCode",
+    ],
+    gen_java: true,
+}
+
diff --git a/wifi/hostapd/1.0/IHostapd.hal b/wifi/hostapd/1.0/IHostapd.hal
new file mode 100644
index 0000000..4dc7bf8
--- /dev/null
+++ b/wifi/hostapd/1.0/IHostapd.hal
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.hostapd@1.0;
+
+import android.hardware.wifi.supplicant@1.0::Ssid;
+
+/**
+ * Top-level object for managing SoftAPs.
+ */
+interface IHostapd {
+    /**
+     * Size limits for some of the params used in this interface.
+     */
+    enum ParamSizeLimits : uint32_t {
+        /** Max length of SSID param. */
+        SSID_MAX_LEN_IN_BYTES = 32,
+
+        /** Min length of PSK passphrase param. */
+        WPA2_PSK_PASSPHRASE_MIN_LEN_IN_BYTES = 8,
+
+        /** Max length of PSK passphrase param. */
+        WPA2_PSK_PASSPHRASE_MAX_LEN_IN_BYTES = 63,
+    };
+
+    /** Possble Security types. */
+    enum EncryptionType : uint32_t {
+        NONE,
+        WPA,
+        WPA2
+    };
+
+    /**
+     * Band to use for the SoftAp operations.
+     * When using ACS, special value |BAND_ANY| can be
+     * used to indicate that any supported band can be used. This special
+     * case is currently supported only with drivers with which
+     * offloaded ACS is used.
+     */
+    enum Band : uint32_t {
+        BAND_2_4_GHZ,
+        BAND_5_GHZ,
+        BAND_ANY
+    };
+
+    /**
+     * Parameters to control the HW mode for the interface.
+     */
+    struct HwModeParams {
+        /**
+         * Whether IEEE 802.11n (HT) is enabled or not.
+         * Note: hwMode=G (2.4 GHz) and hwMode=A (5 GHz) is used to specify
+         * the band.
+         */
+        bool enable80211N;
+         /**
+          * Whether IEEE 802.11ac (VHT) is enabled or not.
+          * Note: hw_mode=a is used to specify that 5 GHz band is used with VHT.
+          */
+        bool enable80211AC;
+    };
+
+    /**
+     * Parameters to control the channel selection for the interface.
+     */
+    struct ChannelParams {
+        /**
+         * Whether to enable ACS (Automatic Channel Selection) or not.
+         * The channel can be selected automatically at run time by setting
+         * this flag, which must enable the ACS survey based algorithm.
+         */
+        bool enableAcs;
+        /**
+         * This option can be used to exclude all DFS channels from the ACS
+         * channel list in cases where the driver supports DFS channels.
+         **/
+        bool acsShouldExcludeDfs;
+        /**
+         * Channel number (IEEE 802.11) to use for the interface.
+         * If ACS is enabled, this field is ignored.
+         */
+        uint32_t channel;
+        /**
+         * Band to use for the SoftAp operations.
+         */
+        Band band;
+    };
+
+    /**
+     * Parameters to use for setting up the access point interface.
+     */
+    struct IfaceParams {
+        /** Name of the interface */
+        string ifaceName;
+        /** Hw mode params for the interface */
+        HwModeParams hwModeParams;
+        /** Chanel params for the interface */
+        ChannelParams channelParams;
+    };
+
+    /**
+     * Parameters to use for setting up the access point network.
+     */
+    struct NetworkParams {
+        /** SSID to set for the network */
+        Ssid ssid;
+        /** Whether the network needs to be hidden or not. */
+        bool isHidden;
+        /** Key management mask for the network. */
+        EncryptionType encryptionType;
+        /** Passphrase for WPA_PSK network. */
+        string pskPassphrase;
+    };
+
+    /**
+     * Adds a new access point for hostapd to control.
+     *
+     * This should trigger the setup of an access point with the specified
+     * interface and network params.
+     *
+     * @param ifaceParams AccessPoint Params for the access point.
+     * @param nwParams Network Params for the access point.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |HostapdStatusCode.SUCCESS|,
+     *         |HostapdStatusCode.FAILURE_ARGS_INVALID|,
+     *         |HostapdStatusCode.FAILURE_UNKNOWN|,
+     *         |HostapdStatusCode.FAILURE_IFACE_EXISTS|
+     */
+    addAccessPoint(IfaceParams ifaceParams, NetworkParams nwParams)
+        generates(HostapdStatus status);
+
+    /**
+     * Removes an existing access point from hostapd.
+     *
+     * This should bring down the access point previously setup on the
+     * interface.
+     *
+     * @param ifaceName Name of the interface.
+     * @return status Status of the operation.
+     *         Possible status codes:
+     *         |HostapdStatusCode.SUCCESS|,
+     *         |HostapdStatusCode.FAILURE_UNKNOWN|,
+     *         |HostapdStatusCode.FAILURE_IFACE_UNKNOWN|
+     */
+    removeAccessPoint(string ifaceName) generates(HostapdStatus status);
+};
diff --git a/wifi/hostapd/1.0/types.hal b/wifi/hostapd/1.0/types.hal
new file mode 100644
index 0000000..31bbc34
--- /dev/null
+++ b/wifi/hostapd/1.0/types.hal
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.hostapd@1.0;
+/**
+ * Enum values indicating the status of any hostapd operation.
+ */
+enum HostapdStatusCode : uint32_t {
+  /** No errors. */
+  SUCCESS,
+  /** Unknown failure occured. */
+  FAILURE_UNKNOWN,
+  /** One or more of the incoming args is invalid. */
+  FAILURE_ARGS_INVALID,
+  /** Iface with the provided name does not exist. */
+  FAILURE_IFACE_UNKNOWN,
+  /** Iface with the provided name already exists. */
+  FAILURE_IFACE_EXISTS
+};
+
+/**
+ * Generic structure to return the status of any hostapd operation.
+ */
+struct HostapdStatus {
+  HostapdStatusCode code;
+  /**
+   * A vendor-specific error message to provide more information beyond the
+   * status code.
+   * This must be used for debugging purposes only.
+   */
+  string debugMessage;
+};