Merge "Add VTS test for ISoundTriggerHw::loadSoundModel"
diff --git a/audio/2.0/default/StreamOut.cpp b/audio/2.0/default/StreamOut.cpp
index cdc8ded..6ccdbcd 100644
--- a/audio/2.0/default/StreamOut.cpp
+++ b/audio/2.0/default/StreamOut.cpp
@@ -79,10 +79,6 @@
         ssize_t writeResult = mStream->write(mStream, &mBuffer[0], availToRead);
         if (writeResult >= 0) {
             mStatus.reply.written = writeResult;
-            // Diagnostics of the cause of b/35813113.
-            ALOGE_IF(writeResult > availToRead,
-                    "legacy hal reports more bytes written than asked for: %lld > %lld",
-                    (long long)writeResult, (long long)availToRead);
         } else {
             mStatus.retval = Stream::analyzeStatus("write", writeResult);
         }
diff --git a/audio/common/2.0/types.hal b/audio/common/2.0/types.hal
index ae7f545..93b898b 100644
--- a/audio/common/2.0/types.hal
+++ b/audio/common/2.0/types.hal
@@ -537,6 +537,7 @@
     /* audio bus implemented by the audio system (e.g an MOST stereo channel) */
     OUT_BUS                       = 0x1000000,
     OUT_PROXY                     = 0x2000000,
+    OUT_USB_HEADSET               = 0x4000000,
     OUT_DEFAULT                   = BIT_DEFAULT,
     OUT_ALL      = (OUT_EARPIECE |
             OUT_SPEAKER |
@@ -603,6 +604,7 @@
     /* audio bus implemented by the audio system (e.g an MOST stereo channel) */
     IN_BUS                   = BIT_IN | 0x100000,
     IN_PROXY                 = BIT_IN | 0x1000000,
+    IN_USB_HEADSET           = BIT_IN | 0x2000000,
     IN_DEFAULT               = BIT_IN | BIT_DEFAULT,
 
     IN_ALL     = (IN_COMMUNICATION |
@@ -670,6 +672,7 @@
     DIRECT_PCM = 0x2000,     // Audio stream containing PCM data that needs
                              // to pass through compress path for DSP post proc.
     MMAP_NOIRQ = 0x4000, // output operates in MMAP no IRQ mode.
+    VOIP_CALL_RX = 0x8000, // preferred output for VoIP calls.
 };
 
 /*
@@ -680,12 +683,13 @@
  */
 @export(name="audio_input_flags_t", value_prefix="AUDIO_INPUT_FLAG_")
 enum AudioInputFlag : int32_t {
-    NONE       = 0x0,  // no attributes
-    FAST       = 0x1,  // prefer an input that supports "fast tracks"
-    HW_HOTWORD = 0x2,  // prefer an input that captures from hw hotword source
-    RAW        = 0x4,  // minimize signal processing
-    SYNC       = 0x8,  // synchronize I/O streams
-    MMAP_NOIRQ = 0x10, // input operates in MMAP no IRQ mode.
+    NONE         = 0x0,  // no attributes
+    FAST         = 0x1,  // prefer an input that supports "fast tracks"
+    HW_HOTWORD   = 0x2,  // prefer an input that captures from hw hotword source
+    RAW          = 0x4,  // minimize signal processing
+    SYNC         = 0x8,  // synchronize I/O streams
+    MMAP_NOIRQ   = 0x10, // input operates in MMAP no IRQ mode.
+    VOIP_CALL_TX = 0x20, // preferred input for VoIP calls.
 };
 
 @export(name="audio_usage_t", value_prefix="AUDIO_USAGE_")
diff --git a/automotive/vehicle/2.0/Android.mk b/automotive/vehicle/2.0/Android.mk
index f976c39..d093017 100644
--- a/automotive/vehicle/2.0/Android.mk
+++ b/automotive/vehicle/2.0/Android.mk
@@ -910,44 +910,6 @@
 LOCAL_GENERATED_SOURCES += $(GEN)
 
 #
-# Build types.hal (VmsMessageIntegerValuesIndex)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsMessageIntegerValuesIndex.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VmsMessageIntegerValuesIndex
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VmsMessageType)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsMessageType.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VmsMessageType
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
 # Build types.hal (Wheel)
 #
 GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Wheel.java
@@ -1920,44 +1882,6 @@
 LOCAL_GENERATED_SOURCES += $(GEN)
 
 #
-# Build types.hal (VmsMessageIntegerValuesIndex)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsMessageIntegerValuesIndex.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VmsMessageIntegerValuesIndex
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
-# Build types.hal (VmsMessageType)
-#
-GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/VmsMessageType.java
-$(GEN): $(HIDL)
-$(GEN): PRIVATE_HIDL := $(HIDL)
-$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
-$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
-$(GEN): PRIVATE_CUSTOM_TOOL = \
-        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
-        -Ljava \
-        -randroid.hardware:hardware/interfaces \
-        -randroid.hidl:system/libhidl/transport \
-        android.hardware.automotive.vehicle@2.0::types.VmsMessageType
-
-$(GEN): $(LOCAL_PATH)/types.hal
-	$(transform-generated-source)
-LOCAL_GENERATED_SOURCES += $(GEN)
-
-#
 # Build types.hal (Wheel)
 #
 GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_0/Wheel.java
diff --git a/automotive/vehicle/2.0/default/Android.mk b/automotive/vehicle/2.0/default/Android.mk
index ba4a6cd..9b3323d 100644
--- a/automotive/vehicle/2.0/default/Android.mk
+++ b/automotive/vehicle/2.0/default/Android.mk
@@ -118,6 +118,7 @@
 
 LOCAL_SRC_FILES:= \
     tests/AccessControlConfigParser_test.cpp \
+    tests/RecurrentTimer_test.cpp \
     tests/SubscriptionManager_test.cpp \
     tests/VehicleHalManager_test.cpp \
     tests/VehicleObjectPool_test.cpp \
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h
new file mode 100644
index 0000000..be25adc
--- /dev/null
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/RecurrentTimer.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H_
+#define android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H_
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <functional>
+#include <list>
+#include <mutex>
+#include <set>
+#include <thread>
+#include <unordered_map>
+
+/**
+ * This class allows to specify multiple time intervals to receive
+ * notifications. A single thread is used internally.
+ */
+class RecurrentTimer {
+private:
+    using Nanos = std::chrono::nanoseconds;
+    using Clock = std::chrono::steady_clock;
+    using TimePoint = std::chrono::time_point<Clock, Nanos>;
+public:
+    using Action = std::function<void(const std::vector<int32_t>& cookies)>;
+
+    RecurrentTimer(const Action& action) : mAction(action) {
+        mTimerThread = std::thread(&RecurrentTimer::loop, this, action);
+    }
+
+    virtual ~RecurrentTimer() {
+        stop();
+    }
+
+    /**
+     * Registers recurrent event for a given interval. Registred events are distinguished by
+     * cookies thus calling this method multiple times with the same cookie will override the
+     * interval provided before.
+     */
+    void registerRecurrentEvent(std::chrono::nanoseconds interval, int32_t cookie) {
+        TimePoint now = Clock::now();
+        // Align event time point among all intervals. Thus if we have two intervals 1ms and 2ms,
+        // during every second wake-up both intervals will be triggered.
+        TimePoint absoluteTime = now - Nanos(now.time_since_epoch().count() % interval.count());
+
+        {
+            std::lock_guard<std::mutex> g(mLock);
+            mCookieToEventsMap[cookie] = { interval, cookie, absoluteTime };
+        }
+        mCond.notify_one();
+    }
+
+    void unregisterRecurrentEvent(int32_t cookie) {
+        {
+            std::lock_guard<std::mutex> g(mLock);
+            mCookieToEventsMap.erase(cookie);
+        }
+        mCond.notify_one();
+    }
+
+
+private:
+
+    struct RecurrentEvent {
+        Nanos interval;
+        int32_t cookie;
+        TimePoint absoluteTime;  // Absolute time of the next event.
+
+        void updateNextEventTime(TimePoint now) {
+            // We want to move time to next event by adding some number of intervals (usually 1)
+            // to previous absoluteTime.
+            int intervalMultiplier = (now - absoluteTime) / interval;
+            if (intervalMultiplier <= 0) intervalMultiplier = 1;
+            absoluteTime += intervalMultiplier * interval;
+        }
+    };
+
+    void loop(const Action& action) {
+        static constexpr auto kInvalidTime = TimePoint(Nanos::max());
+
+        std::vector<int32_t> cookies;
+
+        while (!mStopRequested) {
+            auto now = Clock::now();
+            auto nextEventTime = kInvalidTime;
+            cookies.clear();
+
+            {
+                std::unique_lock<std::mutex> g(mLock);
+
+                for (auto&& it : mCookieToEventsMap) {
+                    RecurrentEvent& event = it.second;
+                    if (event.absoluteTime <= now) {
+                        event.updateNextEventTime(now);
+                        cookies.push_back(event.cookie);
+                    }
+
+                    if (nextEventTime > event.absoluteTime) {
+                        nextEventTime = event.absoluteTime;
+                    }
+                }
+            }
+
+            if (cookies.size() != 0) {
+                action(cookies);
+            }
+
+            std::unique_lock<std::mutex> g(mLock);
+            mCond.wait_until(g, nextEventTime);  // nextEventTime can be nanoseconds::max()
+        }
+    }
+
+    void stop() {
+        mStopRequested = true;
+        {
+            std::lock_guard<std::mutex> g(mLock);
+            mCookieToEventsMap.clear();
+        }
+        mCond.notify_one();
+        if (mTimerThread.joinable()) {
+            mTimerThread.join();
+        }
+    }
+private:
+    mutable std::mutex mLock;
+    std::thread mTimerThread;
+    std::condition_variable mCond;
+    std::atomic_bool mStopRequested { false };
+    Action mAction;
+    std::unordered_map<int32_t, RecurrentEvent> mCookieToEventsMap;
+};
+
+
+#endif  // android_hardware_automotive_vehicle_V2_0_RecurrentTimer_H
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
index 6a12b77..a808c66 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/SubscriptionManager.h
@@ -23,6 +23,7 @@
 #include <list>
 
 #include <android/log.h>
+#include <hidl/HidlSupport.h>
 #include <hwbinder/IPCThreadState.h>
 
 #include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
@@ -50,10 +51,8 @@
     }
 
     void addOrUpdateSubscription(const SubscribeOptions &opts);
-
-    bool isSubscribed(int32_t propId,
-                      int32_t areaId,
-                      SubscribeFlags flags);
+    bool isSubscribed(int32_t propId, int32_t areaId, SubscribeFlags flags);
+    std::vector<int32_t> getSubscribedProperties() const;
 
 private:
     const sp<IVehicleCallback> mCallback;
@@ -85,15 +84,29 @@
 
 class SubscriptionManager {
 public:
-    virtual ~SubscriptionManager() {}
+    using OnPropertyUnsubscribed = std::function<void(int32_t)>;
+
+    /**
+     * Constructs SubscriptionManager
+     *
+     * @param onPropertyUnsubscribed - this callback function will be called when there are no
+     *                                    more client subscribed to particular property.
+     */
+    SubscriptionManager(const OnPropertyUnsubscribed& onPropertyUnsubscribed)
+            : mOnPropertyUnsubscribed(onPropertyUnsubscribed),
+                mCallbackDeathRecipient(new DeathRecipient(
+                    std::bind(&SubscriptionManager::onCallbackDead, this, std::placeholders::_1)))
+    {}
+
+    ~SubscriptionManager() = default;
 
     /**
      * Updates subscription. Returns the vector of properties subscription that
      * needs to be updated in VehicleHAL.
      */
-    std::list<SubscribeOptions> addOrUpdateSubscription(
-            const sp<IVehicleCallback>& callback,
-            const hidl_vec<SubscribeOptions>& optionList);
+    StatusCode addOrUpdateSubscription(const sp<IVehicleCallback>& callback,
+                                       const hidl_vec<SubscribeOptions>& optionList,
+                                       std::list<SubscribeOptions>* outUpdatedOptions);
 
     /**
      * Returns a list of IVehicleCallback -> list of VehiclePropValue ready for
@@ -103,30 +116,48 @@
             const std::vector<recyclable_ptr<VehiclePropValue>>& propValues,
             SubscribeFlags flags) const;
 
-    std::list<sp<HalClient>> getSubscribedClients(
-        int32_t propId, int32_t area, SubscribeFlags flags) const;
-
+    std::list<sp<HalClient>> getSubscribedClients(int32_t propId,
+                                                  int32_t area,
+                                                  SubscribeFlags flags) const;
     /**
-     * Returns true the client was unsubscribed successfully and there are
-     * no more clients subscribed to given propId.
+     * If there are no clients subscribed to given properties than callback function provided
+     * in the constructor will be called.
      */
-    bool unsubscribe(const sp<IVehicleCallback>& callback,
-                     int32_t propId);
+    void unsubscribe(const sp<IVehicleCallback>& callback, int32_t propId);
 private:
-    std::list<sp< HalClient>> getSubscribedClientsLocked(
-            int32_t propId, int32_t area, SubscribeFlags flags) const;
+    std::list<sp<HalClient>> getSubscribedClientsLocked(int32_t propId,
+                                                        int32_t area,
+                                                        SubscribeFlags flags) const;
 
-    bool updateHalEventSubscriptionLocked(const SubscribeOptions &opts,
-                                          SubscribeOptions *out);
+    bool updateHalEventSubscriptionLocked(const SubscribeOptions &opts, SubscribeOptions* out);
 
-    void addClientToPropMapLocked(int32_t propId,
-                                  const sp<HalClient> &client);
+    void addClientToPropMapLocked(int32_t propId, const sp<HalClient>& client);
 
-    sp<HalClientVector> getClientsForPropertyLocked(
-            int32_t propId) const;
+    sp<HalClientVector> getClientsForPropertyLocked(int32_t propId) const;
 
-    sp<HalClient> getOrCreateHalClientLocked(
-            const sp<IVehicleCallback> &callback);
+    sp<HalClient> getOrCreateHalClientLocked(const sp<IVehicleCallback> &callback);
+
+    void onCallbackDead(uint64_t cookie);
+
+private:
+    using OnClientDead = std::function<void(uint64_t)>;
+
+    class DeathRecipient : public hidl_death_recipient {
+    public:
+        DeathRecipient(const OnClientDead& onClientDead)
+            : mOnClientDead(onClientDead) {}
+        ~DeathRecipient() = default;
+
+        DeathRecipient(const DeathRecipient& ) = delete;
+        DeathRecipient& operator=(const DeathRecipient&) = delete;
+
+        void serviceDied(uint64_t cookie,
+                         const wp<::android::hidl::base::V1_0::IBase>& /* who */) override {
+            mOnClientDead(cookie);
+        }
+    private:
+        OnClientDead mOnClientDead;
+    };
 
 private:
     using MuxGuard = std::lock_guard<std::mutex>;
@@ -136,6 +167,9 @@
     std::map<sp<IVehicleCallback>, sp<HalClient>> mClients;
     std::map<int32_t, sp<HalClientVector>> mPropToClients;
     std::map<int32_t, SubscribeOptions> mHalEventSubscribeOptions;
+
+    OnPropertyUnsubscribed mOnPropertyUnsubscribed;
+    sp<DeathRecipient> mCallbackDeathRecipient;
 };
 
 
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
index 4bff4d1..b8ab309 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h
@@ -56,7 +56,9 @@
 class VehicleHalManager : public IVehicle {
 public:
     VehicleHalManager(VehicleHal* vehicleHal)
-        : mHal(vehicleHal) {
+        : mHal(vehicleHal),
+          mSubscriptionManager(std::bind(&VehicleHalManager::onAllClientsUnsubscribed,
+                                         this, std::placeholders::_1)) {
         init();
     }
 
@@ -105,6 +107,8 @@
                   int32_t propertyId,
                   VehiclePropertyAccess requiredAccess) const;
 
+    void onAllClientsUnsubscribed(int32_t propertyId);
+
     static bool isSubscribable(const VehiclePropConfig& config,
                                SubscribeFlags flags);
     static bool isSampleRateFixed(VehiclePropertyChangeMode mode);
diff --git a/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp b/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
index f6f2758..4493a41 100644
--- a/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/SubscriptionManager.cpp
@@ -19,6 +19,7 @@
 #include "SubscriptionManager.h"
 
 #include <cmath>
+#include <inttypes.h>
 
 #include <android/log.h>
 
@@ -58,6 +59,8 @@
 }
 
 void HalClient::addOrUpdateSubscription(const SubscribeOptions &opts)  {
+    ALOGI("%s opts.propId: 0x%x", __func__, opts.propId);
+
     auto it = mSubscriptions.find(opts.propId);
     if (it == mSubscriptions.end()) {
         mSubscriptions.emplace(opts.propId, opts);
@@ -84,17 +87,33 @@
     return res;
 }
 
-std::list<SubscribeOptions> SubscriptionManager::addOrUpdateSubscription(
+std::vector<int32_t> HalClient::getSubscribedProperties() const {
+    std::vector<int32_t> props;
+    for (const auto& subscription : mSubscriptions) {
+        ALOGI("%s propId: 0x%x, propId: 0x%x", __func__, subscription.first, subscription.second.propId);
+        props.push_back(subscription.first);
+    }
+    return props;
+}
+
+StatusCode SubscriptionManager::addOrUpdateSubscription(
         const sp<IVehicleCallback> &callback,
-        const hidl_vec<SubscribeOptions> &optionList) {
-    std::list<SubscribeOptions> updatedSubscriptions;
+        const hidl_vec<SubscribeOptions> &optionList,
+        std::list<SubscribeOptions>* outUpdatedSubscriptions) {
+    outUpdatedSubscriptions->clear();
 
     MuxGuard g(mLock);
 
+    ALOGI("SubscriptionManager::addOrUpdateSubscription, callback: %p", callback.get());
+
     const sp<HalClient>& client = getOrCreateHalClientLocked(callback);
+    if (client.get() == nullptr) {
+        return StatusCode::INTERNAL_ERROR;
+    }
 
     for (size_t i = 0; i < optionList.size(); i++) {
         const SubscribeOptions& opts = optionList[i];
+        ALOGI("SubscriptionManager::addOrUpdateSubscription, prop: 0x%x", opts.propId);
         client->addOrUpdateSubscription(opts);
 
         addClientToPropMapLocked(opts.propId, client);
@@ -102,12 +121,12 @@
         if (SubscribeFlags::HAL_EVENT & opts.flags) {
             SubscribeOptions updated;
             if (updateHalEventSubscriptionLocked(opts, &updated)) {
-                updatedSubscriptions.push_back(updated);
+                outUpdatedSubscriptions->push_back(updated);
             }
         }
     }
 
-    return updatedSubscriptions;
+    return StatusCode::OK;
 }
 
 std::list<HalClientValues> SubscriptionManager::distributeValuesToClients(
@@ -205,6 +224,14 @@
         const sp<IVehicleCallback>& callback) {
     auto it = mClients.find(callback);
     if (it == mClients.end()) {
+        uint64_t cookie = reinterpret_cast<uint64_t>(callback.get());
+        ALOGI("Creating new client and linking to death recipient, cookie: 0x%" PRIx64, cookie);
+        auto res = callback->linkToDeath(mCallbackDeathRecipient, cookie);
+        if (!res.isOk()) {  // Client is already dead?
+            ALOGW("%s failed to link to death, client %p, err: %s",
+                  __func__, callback.get(), res.description().c_str());
+            return nullptr;
+        }
         IPCThreadState* self = IPCThreadState::self();
         pid_t pid = self->getCallingPid();
         uid_t uid = self->getCallingUid();
@@ -216,7 +243,7 @@
     }
 }
 
-bool SubscriptionManager::unsubscribe(const sp<IVehicleCallback>& callback,
+void SubscriptionManager::unsubscribe(const sp<IVehicleCallback>& callback,
                                       int32_t propId) {
     MuxGuard g(mLock);
     auto propertyClients = getClientsForPropertyLocked(propId);
@@ -243,13 +270,39 @@
         }
 
         if (!isClientSubscribedToOtherProps) {
+            auto res = client->getCallback()->unlinkToDeath(mCallbackDeathRecipient);
+            if (!res.isOk()) {
+                ALOGW("%s failed to unlink to death, client: %p, err: %s",
+                      __func__, client->getCallback().get(), res.description().c_str());
+            }
             mClients.erase(clientIter);
         }
     }
 
-    return (propertyClients == nullptr || propertyClients->isEmpty())
-            ? mHalEventSubscribeOptions.erase(propId) == 1
-            : false;
+    if (propertyClients == nullptr || propertyClients->isEmpty()) {
+        mHalEventSubscribeOptions.erase(propId);
+        mOnPropertyUnsubscribed(propId);
+    }
+}
+
+void SubscriptionManager::onCallbackDead(uint64_t cookie) {
+    ALOGI("%s, cookie: 0x%" PRIx64, __func__, cookie);
+    IVehicleCallback* callback = reinterpret_cast<IVehicleCallback*>(cookie);
+
+    std::vector<int32_t> props;
+    {
+        MuxGuard g(mLock);
+        const auto& it = mClients.find(callback);
+        if (it == mClients.end()) {
+            return;  // Nothing to do here, client wasn't subscribed to any properties.
+        }
+        const auto& halClient = it->second;
+        props = halClient->getSubscribedProperties();
+    }
+
+    for (int32_t propId : props) {
+        unsubscribe(callback, propId);
+    }
 }
 
 
diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
index 3a5e504..8906f6e 100644
--- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp
@@ -43,8 +43,7 @@
  */
 constexpr auto kMaxHidlVecOfVehiclPropValuePoolSize = 20;
 
-Return<void> VehicleHalManager::getAllPropConfigs(
-        getAllPropConfigs_cb _hidl_cb) {
+Return<void> VehicleHalManager::getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) {
     ALOGI("getAllPropConfigs called");
     hidl_vec<VehiclePropConfig> hidlConfigs;
     auto& halConfig = mConfigIndex->getAllConfigs();
@@ -58,9 +57,8 @@
     return Void();
 }
 
-Return<void> VehicleHalManager::getPropConfigs(
-        const hidl_vec<int32_t> &properties,
-        getPropConfigs_cb _hidl_cb) {
+Return<void> VehicleHalManager::getPropConfigs(const hidl_vec<int32_t> &properties,
+                                               getPropConfigs_cb _hidl_cb) {
     std::vector<VehiclePropConfig> configs;
     for (size_t i = 0; i < properties.size(); i++) {
         auto prop = properties[i];
@@ -77,8 +75,7 @@
     return Void();
 }
 
-Return<void> VehicleHalManager::get(
-        const VehiclePropValue& requestedPropValue, get_cb _hidl_cb) {
+Return<void> VehicleHalManager::get(const VehiclePropValue& requestedPropValue, get_cb _hidl_cb) {
     const auto* config = getPropConfigOrNull(requestedPropValue.prop);
     if (config == nullptr) {
         ALOGE("Failed to get value: config not found, property: 0x%x",
@@ -119,9 +116,8 @@
     return Return<StatusCode>(status);
 }
 
-Return<StatusCode> VehicleHalManager::subscribe(
-        const sp<IVehicleCallback> &callback,
-        const hidl_vec<SubscribeOptions> &options) {
+Return<StatusCode> VehicleHalManager::subscribe(const sp<IVehicleCallback> &callback,
+                                                const hidl_vec<SubscribeOptions> &options) {
     hidl_vec<SubscribeOptions> verifiedOptions(options);
     auto caller = getCaller();
     for (size_t i = 0; i < verifiedOptions.size(); i++) {
@@ -135,6 +131,11 @@
             return StatusCode::INVALID_ARG;
         }
 
+        if (ops.flags == SubscribeFlags::UNDEFINED) {
+            ALOGE("Failed to subscribe: undefined flag in options provided");
+            return StatusCode::INVALID_ARG;
+        }
+
         if (!checkAcl(caller.uid, config->prop, VehiclePropertyAccess::READ)) {
             return StatusCode::ACCESS_DENIED;
         }
@@ -157,22 +158,24 @@
         ops.sampleRate = checkSampleRate(*config, ops.sampleRate);
     }
 
-    std::list<SubscribeOptions> updatedOptions =
-        mSubscriptionManager.addOrUpdateSubscription(callback, verifiedOptions);
+    std::list<SubscribeOptions> updatedOptions;
+    auto res = mSubscriptionManager.addOrUpdateSubscription(callback, verifiedOptions,
+                                                            &updatedOptions);
+    if (StatusCode::OK != res) {
+        ALOGW("%s failed to subscribe, error code: %d", __func__, res);
+        return res;
+    }
 
     for (auto opt : updatedOptions) {
         mHal->subscribe(opt.propId, opt.vehicleAreas, opt.sampleRate);
     }
-    // TODO(pavelm): link to death callback (not implemented yet in HIDL)
 
     return StatusCode::OK;
 }
 
-Return<StatusCode> VehicleHalManager::unsubscribe(
-        const sp<IVehicleCallback>& callback, int32_t propId) {
-    if (mSubscriptionManager.unsubscribe(callback, propId)) {
-        mHal->unsubscribe(propId);
-    }
+Return<StatusCode> VehicleHalManager::unsubscribe(const sp<IVehicleCallback>& callback,
+                                                  int32_t propId) {
+    mSubscriptionManager.unsubscribe(callback, propId);
     return StatusCode::OK;
 }
 
@@ -239,8 +242,7 @@
     }
 }
 
-void VehicleHalManager::onBatchHalEvent(
-        const std::vector<VehiclePropValuePtr>& values) {
+void VehicleHalManager::onBatchHalEvent(const std::vector<VehiclePropValuePtr>& values) {
     const auto& clientValues = mSubscriptionManager.distributeValuesToClients(
             values, SubscribeFlags::HAL_EVENT);
 
@@ -257,7 +259,12 @@
         for (VehiclePropValue* pValue : cv.values) {
             shallowCopy(&(vec)[i++], *pValue);
         }
-        cv.client->getCallback()->onPropertyEvent(vec);
+        auto status = cv.client->getCallback()->onPropertyEvent(vec);
+        if (!status.isOk()) {
+            ALOGE("Failed to notify client %s, err: %s",
+                  toString(cv.client->getCallback()).c_str(),
+                  status.description().c_str());
+        }
     }
 }
 
@@ -379,6 +386,10 @@
     }
 }
 
+void VehicleHalManager::onAllClientsUnsubscribed(int32_t propertyId) {
+    mHal->unsubscribe(propertyId);
+}
+
 }  // namespace V2_0
 }  // namespace vehicle
 }  // namespace automotive
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 9591689..596ad85 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -147,6 +147,15 @@
     },
 
     {
+        .prop = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE),
+        .access = VehiclePropertyAccess::READ,
+        // TODO(bryaneyler): Support ON_CHANGE as well.
+        .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+        .minSampleRate = 1.0f,
+        .maxSampleRate = 2.0f,
+    },
+
+    {
         .prop = toInt(VehicleProperty::NIGHT_MODE),
         .access = VehiclePropertyAccess::READ,
         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
@@ -192,6 +201,14 @@
         .prop = toInt(VehicleProperty::IGNITION_STATE),
         .access = VehiclePropertyAccess::READ,
         .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+    },
+
+    {
+        .prop = toInt(VehicleProperty::ENGINE_OIL_TEMP),
+        .access = VehiclePropertyAccess::READ,
+        .changeMode = VehiclePropertyChangeMode::CONTINUOUS,
+        .minSampleRate = 0.1, // 0.1 Hz, every 10 seconds
+        .maxSampleRate = 10,  // 10 Hz, every 100 ms
     }
 };
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
index 7a66c04..2214100 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.cpp
@@ -118,6 +118,7 @@
 
     val.prop = protoVal.prop();
     val.areaId = protoVal.area_id();
+    val.timestamp = elapsedRealtimeNano();
 
     // Copy value data if it is set.  This automatically handles complex data types if needed.
     if (protoVal.has_string_value()) {
@@ -176,7 +177,7 @@
     if (prop != mProps.end()) {
         return prop->second.get();
     }
-    ALOGW("%s: Property not found:  propId = 0x%x, areaId = 0x%x", __FUNCTION__, propId, areaId);
+    ALOGW("%s: Property not found:  propId = 0x%x, areaId = 0x%x", __func__, propId, areaId);
     return nullptr;
 }
 
@@ -202,7 +203,7 @@
             doSetProperty(rxMsg, respMsg);
             break;
         default:
-            ALOGW("%s: Unknown message received, type = %d", __FUNCTION__, rxMsg.msg_type());
+            ALOGW("%s: Unknown message received, type = %d", __func__, rxMsg.msg_type());
             respMsg.set_status(emulator::ERROR_UNIMPLEMENTED_CMD);
             break;
         }
@@ -210,7 +211,7 @@
         // Send the reply
         txMsg(respMsg);
     } else {
-        ALOGE("%s: ParseFromString() failed. msgSize=%d", __FUNCTION__, static_cast<int>(msg.size()));
+        ALOGE("%s: ParseFromString() failed. msgSize=%d", __func__, static_cast<int>(msg.size()));
     }
 }
 
@@ -266,7 +267,7 @@
         }
         break;
     default:
-        ALOGW("%s: Unknown property type:  0x%x", __FUNCTION__, toInt(getPropType(cfg.prop)));
+        ALOGW("%s: Unknown property type:  0x%x", __func__, toInt(getPropType(cfg.prop)));
         break;
     }
 
@@ -317,7 +318,7 @@
             parseRxProtoBuf(msg);
         } else {
             // This happens when connection is closed
-            ALOGD("%s: numBytes=%d, msgSize=%d", __FUNCTION__, numBytes,
+            ALOGD("%s: numBytes=%d, msgSize=%d", __func__, numBytes,
                   static_cast<int32_t>(msg.size()));
             break;
         }
@@ -396,6 +397,9 @@
     case toInt(VehicleProperty::HVAC_TEMPERATURE_SET):
         prop->value.floatValues[0] = 16;
         break;
+    case toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE):
+        prop->value.floatValues[0] = 25;
+        break;
     case toInt(VehicleProperty::NIGHT_MODE):
         prop->value.int32Values[0] = 0;
         break;
@@ -408,6 +412,9 @@
     case toInt(VehicleProperty::INFO_FUEL_CAPACITY):
         prop->value.floatValues[0] = 0.75f;
         break;
+    case toInt(VehicleProperty::ENGINE_OIL_TEMP):
+        prop->value.floatValues[0] = 101;
+        break;
     case toInt(VehicleProperty::DISPLAY_BRIGHTNESS):
         prop->value.int32Values[0] = 7;
         break;
@@ -415,7 +422,7 @@
         prop->value.int32Values[0] = toInt(VehicleIgnitionState::ON);
         break;
     default:
-        ALOGW("%s: propId=0x%x not found", __FUNCTION__, prop->prop);
+        ALOGW("%s: propId=0x%x not found", __func__, prop->prop);
         break;
     }
 }
@@ -434,10 +441,10 @@
         }
 
         if (retVal < 0) {
-            ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __FUNCTION__, retVal, errno);
+            ALOGE("%s: Failed to tx message: retval=%d, errno=%d", __func__, retVal, errno);
         }
     } else {
-        ALOGE("%s: SerializeToString failed!", __FUNCTION__);
+        ALOGE("%s: SerializeToString failed!", __func__);
     }
 }
 
@@ -453,7 +460,7 @@
         VehiclePropValue* internalPropValue = getVehiclePropValueLocked(propId, areaId);
         if (internalPropValue != nullptr) {
             internalPropValue->value = propValue.value;
-            internalPropValue->timestamp = elapsedRealtimeNano();
+            internalPropValue->timestamp = propValue.timestamp;
             status = StatusCode::OK;
         }
     }
@@ -566,10 +573,8 @@
                 break;
             }
             continue;
-            break;
-        case VehiclePropertyType::MASK:
         default:
-            ALOGW("%s: propType=0x%x not found", __FUNCTION__, propType);
+            ALOGE("%s: propType=0x%x not found", __func__, propType);
             vecSize = 0;
             break;
         }
@@ -602,6 +607,69 @@
     mThread = std::thread(&DefaultVehicleHal::rxThread, this);
 }
 
+void DefaultVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) {
+    VehiclePropValuePtr v;
+
+    auto& pool = *getValuePool();
+
+    for (int32_t property : properties) {
+        if (isContinuousProperty(property)) {
+            // In real implementation this value should be read from sensor, random
+            // value used for testing purpose only.
+            std::lock_guard<std::mutex> lock(mPropsMutex);
+
+            VehiclePropValue *internalPropValue = getVehiclePropValueLocked(property);
+            if (internalPropValue != nullptr) {
+                v = pool.obtain(*internalPropValue);
+            }
+            if (VehiclePropertyType::FLOAT == getPropType(property)) {
+                // Just get some randomness to continuous properties to see slightly differnt values
+                // on the other end.
+                v->value.floatValues[0] = v->value.floatValues[0] + std::rand() % 5;
+            }
+        } else {
+            ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
+        }
+
+        if (v.get()) {
+            v->timestamp = elapsedRealtimeNano();
+            doHalEvent(std::move(v));
+        }
+    }
+}
+
+StatusCode DefaultVehicleHal::subscribe(int32_t property, int32_t,
+                                        float sampleRate) {
+    ALOGI("subscribe called for property: 0x%x, sampleRate: %f", property, sampleRate);
+
+    if (isContinuousProperty(property)) {
+        mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
+    }
+    return StatusCode::OK;
+}
+
+StatusCode DefaultVehicleHal::unsubscribe(int32_t property) {
+    ALOGI("%s propId: 0x%x", __func__, property);
+    if (isContinuousProperty(property)) {
+        mRecurrentTimer.unregisterRecurrentEvent(property);
+    }
+    return StatusCode::OK;
+}
+
+const VehiclePropConfig* DefaultVehicleHal::getPropConfig(int32_t propId) const {
+    auto it = mPropConfigMap.find(propId);
+    return it == mPropConfigMap.end() ? nullptr : it->second;
+}
+
+bool DefaultVehicleHal::isContinuousProperty(int32_t propId) const {
+    const VehiclePropConfig* config = getPropConfig(propId);
+    if (config == nullptr) {
+        ALOGW("Config not found for property: 0x%x", propId);
+        return false;
+    }
+    return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS;
+}
+
 }  // impl
 
 }  // namespace V2_0
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
index 1ad8702..98eef27 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultVehicleHal.h
@@ -28,6 +28,7 @@
 #include "CommBase.h"
 #include "VehicleHalProto.pb.h"
 
+#include <vhal_v2_0/RecurrentTimer.h>
 #include <vhal_v2_0/VehicleHal.h>
 
 #include "DefaultConfig.h"
@@ -43,7 +44,13 @@
 
 class DefaultVehicleHal : public VehicleHal {
 public:
-    DefaultVehicleHal() : mThread() {}
+    DefaultVehicleHal() : mRecurrentTimer(
+            std::bind(&DefaultVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)) {
+        for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
+            mPropConfigMap[kVehicleProperties->prop] = &kVehicleProperties[i];
+        }
+    }
+
     ~DefaultVehicleHal() override {
         // Notify thread to finish and wait for it to terminate
         mExit = 1;
@@ -66,16 +73,9 @@
 
     StatusCode set(const VehiclePropValue& propValue) override;
 
-    StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) {
-        ALOGD("%s: not implemented: prop=0x%x, areas=0x%x, rate=%f", __FUNCTION__, property,
-              areas, sampleRate);
-        return StatusCode::OK;
-    }
+    StatusCode subscribe(int32_t property, int32_t areas, float sampleRate) override;
 
-    StatusCode unsubscribe(int32_t property) {
-        ALOGD("%s: not implemented: prop=0x%x", __FUNCTION__, property);
-        return StatusCode::OK;
-    }
+    StatusCode unsubscribe(int32_t property) override;
 
 private:
     void doGetConfig(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
@@ -83,7 +83,9 @@
     void doGetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
     void doGetPropertyAll(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
     void doSetProperty(emulator::EmulatorMessage& rxMsg, emulator::EmulatorMessage& respMsg);
-    VehiclePropValue* getVehiclePropValueLocked(int32_t propId, int32_t areaId);
+    VehiclePropValue* getVehiclePropValueLocked(int32_t propId, int32_t areaId = 0);
+    const VehiclePropConfig* getPropConfig(int32_t propId) const;
+    bool isContinuousProperty(int32_t propId) const;
     void parseRxProtoBuf(std::vector<uint8_t>& msg);
     void populateProtoVehicleConfig(emulator::VehiclePropConfig* protoCfg,
                                     const VehiclePropConfig& cfg);
@@ -94,6 +96,13 @@
     void rxThread();
     void txMsg(emulator::EmulatorMessage& txMsg);
     StatusCode updateProperty(const VehiclePropValue& propValue);
+
+    constexpr std::chrono::nanoseconds hertzToNanoseconds(float hz) const {
+        return std::chrono::nanoseconds(static_cast<int64_t>(1000000000L / hz));
+    }
+
+    void onContinuousPropertyTimer(const std::vector<int32_t>& properties);
+
 private:
     std::map<
         std::pair<int32_t /*VehicleProperty*/, int32_t /*areaId*/>,
@@ -103,6 +112,8 @@
     std::mutex mPropsMutex;
     std::thread mThread;
     std::unique_ptr<CommBase> mComm{nullptr};
+    RecurrentTimer mRecurrentTimer;
+    std::unordered_map<int32_t, const VehiclePropConfig*> mPropConfigMap;
 };
 
 }  // impl
diff --git a/automotive/vehicle/2.0/default/tests/RecurrentTimer_test.cpp b/automotive/vehicle/2.0/default/tests/RecurrentTimer_test.cpp
new file mode 100644
index 0000000..9353baa
--- /dev/null
+++ b/automotive/vehicle/2.0/default/tests/RecurrentTimer_test.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <thread>
+
+#include <gtest/gtest.h>
+
+#include "vhal_v2_0/RecurrentTimer.h"
+
+namespace {
+
+using std::chrono::nanoseconds;
+using std::chrono::milliseconds;
+
+#define ASSERT_EQ_WITH_TOLERANCE(val1, val2, tolerance) \
+ASSERT_LE(val1 - tolerance, val2); \
+ASSERT_GE(val1 + tolerance, val2); \
+
+
+TEST(RecurrentTimerTest, oneInterval) {
+    std::atomic<int64_t> counter { 0L };
+    auto counterRef = std::ref(counter);
+    RecurrentTimer timer([&counterRef](const std::vector<int32_t>& cookies) {
+        ASSERT_EQ(1u, cookies.size());
+        ASSERT_EQ(0xDeadBeef, cookies.front());
+        counterRef.get()++;
+    });
+
+    timer.registerRecurrentEvent(milliseconds(1), 0xDeadBeef);
+    std::this_thread::sleep_for(milliseconds(100));
+    ASSERT_EQ_WITH_TOLERANCE(100, counter.load(), 20);
+}
+
+TEST(RecurrentTimerTest, multipleIntervals) {
+    std::atomic<int64_t> counter1ms { 0L };
+    std::atomic<int64_t> counter5ms { 0L };
+    auto counter1msRef = std::ref(counter1ms);
+    auto counter5msRef = std::ref(counter5ms);
+    RecurrentTimer timer(
+            [&counter1msRef, &counter5msRef](const std::vector<int32_t>& cookies) {
+        for (int32_t cookie : cookies) {
+            if (cookie == 0xdead) {
+                counter1msRef.get()++;
+            } else if (cookie == 0xbeef) {
+                counter5msRef.get()++;
+            } else {
+                FAIL();
+            }
+        }
+    });
+
+    timer.registerRecurrentEvent(milliseconds(1), 0xdead);
+    timer.registerRecurrentEvent(milliseconds(5), 0xbeef);
+
+    std::this_thread::sleep_for(milliseconds(100));
+    ASSERT_EQ_WITH_TOLERANCE(100, counter1ms.load(), 20);
+    ASSERT_EQ_WITH_TOLERANCE(20, counter5ms.load(), 5);
+}
+
+}  // anonymous namespace
diff --git a/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
index e13d003..7ec9b79 100644
--- a/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/SubscriptionManager_test.cpp
@@ -14,8 +14,9 @@
  * limitations under the License.
  */
 
-#include <unordered_map>
+#include <functional>
 #include <iostream>
+#include <unordered_map>
 
 #include <gtest/gtest.h>
 
@@ -35,8 +36,9 @@
 
 class SubscriptionManagerTest : public ::testing::Test {
 public:
-    SubscriptionManager manager;
+    SubscriptionManagerTest() : manager(([this](int x) { onPropertyUnsubscribed(x); })) {}
 
+    SubscriptionManager manager;
     static constexpr int32_t PROP1 = toInt(VehicleProperty::HVAC_FAN_SPEED);
     static constexpr int32_t PROP2 = toInt(VehicleProperty::DISPLAY_BRIGHTNESS);
 
@@ -44,6 +46,10 @@
     sp<IVehicleCallback> cb2 = new MockedVehicleCallback();
     sp<IVehicleCallback> cb3 = new MockedVehicleCallback();
 
+    void SetUp() override {
+        lastUnsubscribedProperty = -1;
+    }
+
     hidl_vec<SubscribeOptions> subscrToProp1 = {
         SubscribeOptions {
             .propId = PROP1,
@@ -90,12 +96,31 @@
         return manager.getSubscribedClients(PROP2, 0,
                                             SubscribeFlags::DEFAULT);
     }
+
+    void onPropertyUnsubscribed(int propertyId) {
+        // Called when there are no clients who subscribed to particular property. This can happen
+        // because of explict unsubscribe call or when client (IVehicleCallback) was disconnected.
+        lastUnsubscribedProperty = propertyId;
+    }
+
+    void assertOnPropertyUnsubscribedNotCalled() {
+        ASSERT_EQ(-1, lastUnsubscribedProperty);
+    }
+
+    void assertLastUnsubscribedProperty(int expectedPropertyId) {
+        ASSERT_EQ(expectedPropertyId, lastUnsubscribedProperty);
+        lastUnsubscribedProperty = -1;
+    }
+
+private:
+    int lastUnsubscribedProperty;
 };
 
 
 TEST_F(SubscriptionManagerTest, multipleClients) {
-    manager.addOrUpdateSubscription(cb1, subscrToProp1);
-    manager.addOrUpdateSubscription(cb2, subscrToProp1);
+    std::list<SubscribeOptions> updatedOptions;
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb2, subscrToProp1, &updatedOptions));
 
     auto clients = manager.getSubscribedClients(
             PROP1,
@@ -106,7 +131,8 @@
 }
 
 TEST_F(SubscriptionManagerTest, negativeCases) {
-    manager.addOrUpdateSubscription(cb1, subscrToProp1);
+    std::list<SubscribeOptions> updatedOptions;
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
 
     // Wrong zone
     auto clients = manager.getSubscribedClients(
@@ -131,7 +157,8 @@
 }
 
 TEST_F(SubscriptionManagerTest, mulipleSubscriptions) {
-    manager.addOrUpdateSubscription(cb1, subscrToProp1);
+    std::list<SubscribeOptions> updatedOptions;
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
 
     auto clients = manager.getSubscribedClients(
             PROP1,
@@ -142,13 +169,13 @@
 
     // Same property, but different zone, to make sure we didn't unsubscribe
     // from previous zone.
-    manager.addOrUpdateSubscription(cb1, {
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, {
         SubscribeOptions {
                 .propId = PROP1,
                 .vehicleAreas = toInt(VehicleAreaZone::ROW_2),
                 .flags = SubscribeFlags::DEFAULT
             }
-        });
+        }, &updatedOptions));
 
     clients = manager.getSubscribedClients(PROP1,
                                            toInt(VehicleAreaZone::ROW_1_LEFT),
@@ -162,31 +189,38 @@
 }
 
 TEST_F(SubscriptionManagerTest, unsubscribe) {
-    manager.addOrUpdateSubscription(cb1, subscrToProp1);
-    manager.addOrUpdateSubscription(cb2, subscrToProp2);
-    manager.addOrUpdateSubscription(cb3, subscrToProp1and2);
+    std::list<SubscribeOptions> updatedOptions;
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb1, subscrToProp1, &updatedOptions));
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb2, subscrToProp2, &updatedOptions));
+    ASSERT_EQ(StatusCode::OK, manager.addOrUpdateSubscription(cb3, subscrToProp1and2,
+                                                              &updatedOptions));
 
     ASSERT_ALL_EXISTS({cb1, cb3}, extractCallbacks(clientsToProp1()));
     ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
 
-    ASSERT_FALSE(manager.unsubscribe(cb1, PROP1));
+    manager.unsubscribe(cb1, PROP1);
+    assertOnPropertyUnsubscribedNotCalled();
     ASSERT_ALL_EXISTS({cb3}, extractCallbacks(clientsToProp1()));
 
     // Make sure nothing changed in PROP2 so far.
     ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
 
     // No one subscribed to PROP1, subscription for PROP2 is not affected.
-    ASSERT_TRUE(manager.unsubscribe(cb3, PROP1));
+    manager.unsubscribe(cb3, PROP1);
+    assertLastUnsubscribedProperty(PROP1);
     ASSERT_ALL_EXISTS({cb2, cb3}, extractCallbacks(clientsToProp2()));
 
-    ASSERT_FALSE(manager.unsubscribe(cb3, PROP2));
+    manager.unsubscribe(cb3, PROP2);
+    assertOnPropertyUnsubscribedNotCalled();
     ASSERT_ALL_EXISTS({cb2}, extractCallbacks(clientsToProp2()));
 
     // The last client unsubscribed from this property.
-    ASSERT_TRUE(manager.unsubscribe(cb2, PROP2));
+    manager.unsubscribe(cb2, PROP2);
+    assertLastUnsubscribedProperty(PROP2);
 
-    // No one was subscribed, return false.
-    ASSERT_FALSE(manager.unsubscribe(cb1, PROP1));
+    // No one subscribed anymore
+    manager.unsubscribe(cb1, PROP1);
+    assertLastUnsubscribedProperty(PROP1);
 }
 
 }  // namespace anonymous
diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
index f637344..b5cdf5c 100644
--- a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
+++ b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp
@@ -68,15 +68,16 @@
                     pValue = getValuePool()->obtainFloat(42.42);
                 }
                 break;
-            case VehicleProperty::VEHICLE_MAP_SERVICE:
-                pValue = getValuePool()->obtainComplex();
-                pValue->value.int32Values = hidl_vec<int32_t> { 10, 20 };
-                pValue->value.int64Values = hidl_vec<int64_t> { 30, 40 };
-                pValue->value.floatValues = hidl_vec<float_t> { 1.1, 2.2 };
-                pValue->value.bytes = hidl_vec<uint8_t> { 1, 2, 3 };
-                pValue->value.stringValue = kCarMake;
-                break;
             default:
+                if (requestedPropValue.prop == kCustomComplexProperty) {
+                    pValue = getValuePool()->obtainComplex();
+                    pValue->value.int32Values = hidl_vec<int32_t> { 10, 20 };
+                    pValue->value.int64Values = hidl_vec<int64_t> { 30, 40 };
+                    pValue->value.floatValues = hidl_vec<float_t> { 1.1, 2.2 };
+                    pValue->value.bytes = hidl_vec<uint8_t> { 1, 2, 3 };
+                    pValue->value.stringValue = kCarMake;
+                    break;
+                }
                 auto key = makeKey(toInt(property), areaId);
                 if (mValues.count(key) == 0) {
                     ALOGW("");
@@ -318,10 +319,10 @@
 }
 
 TEST_F(VehicleHalManagerTest, get_Complex) {
-    invokeGet(toInt(VehicleProperty::VEHICLE_MAP_SERVICE), 0);
+    invokeGet(kCustomComplexProperty, 0);
 
     ASSERT_EQ(StatusCode::OK, actualStatusCode);
-    ASSERT_EQ(toInt(VehicleProperty::VEHICLE_MAP_SERVICE), actualValue.prop);
+    ASSERT_EQ(kCustomComplexProperty, actualValue.prop);
 
     ASSERT_EQ(3u, actualValue.value.bytes.size());
     ASSERT_EQ(1, actualValue.value.bytes[0]);
diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h b/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h
index ce1ed7d..28e1a5a 100644
--- a/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h
+++ b/automotive/vehicle/2.0/default/tests/VehicleHalTestUtils.h
@@ -29,6 +29,11 @@
 namespace vehicle {
 namespace V2_0 {
 
+constexpr int32_t kCustomComplexProperty = 0xbeef
+        | VehiclePropertyGroup::VENDOR
+        | VehiclePropertyType::COMPLEX
+        | VehicleArea::GLOBAL;
+
 const VehiclePropConfig kVehicleProperties[] = {
     {
         .prop = toInt(VehicleProperty::INFO_MAKE),
@@ -109,7 +114,7 @@
 
     // Complex data type.
     {
-        .prop = toInt(VehicleProperty::VEHICLE_MAP_SERVICE),
+        .prop = kCustomComplexProperty,
         .access = VehiclePropertyAccess::READ_WRITE,
         .changeMode = VehiclePropertyChangeMode::ON_CHANGE
     }
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 0d2dfdd..b33b6ee 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -1790,26 +1790,6 @@
         | VehiclePropertyGroup:SYSTEM
         | VehiclePropertyType:BOOLEAN
         | VehicleArea:GLOBAL),
-
-    /*
-     * Vehicle Maps Service (VMS) message
-     *
-     * This property uses COMPLEX data to communicate vms messages.
-     *
-     * Its contents are to be interpreted as follows:
-     * the indices defined in VmsMessageIntegerValuesIndex are to be used to
-     * read from int32Values;
-     * bytes is a serialized VMS message as defined in the vms protocol
-     * which is opaque to the framework;
-     *
-     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
-     * @access VehiclePropertyAccess:READ_WRITE
-     */
-    VEHICLE_MAP_SERVICE = (
-        0x0C00
-        | VehiclePropertyGroup:SYSTEM
-        | VehiclePropertyType:COMPLEX
-        | VehicleArea:GLOBAL),
 };
 
 /*
@@ -2707,35 +2687,3 @@
     LEFT_REAR = 0x4,
     RIGHT_REAR = 0x8,
 };
-
-/*
- * This enum lists the types of supported VMS messages.
- */
-enum VmsMessageType : int32_t {
-  /* A client subscribes to a layer. */
-  SUBSCRIBE = 1,
-
-  /* A client unsubscribes from a layer. */
-  UNSUBSCRIBE = 2,
-
-  /* A client publishes a data packet. */
-  DATA = 3,
-};
-
-/*
- * This enum provides the canonical mapping for VMS properties that have an
- * integer value.
- */
-enum VmsMessageIntegerValuesIndex : int32_t {
-  /* The message type as enumerated by VmsMessageType enum. */
-  VMS_MESSAGE_TYPE = 0,
-
-  /* The layer ID as defined in the vms protocol. */
-  VMS_LAYER_ID = 1,
-
-  /* The version of the VMS layer. */
-  VMS_LAYER_VERSION = 2,
-
-  /* The number of bytes in the payload */
-  VMS_PAYLOAD_SIZE_BYTES = 3,
-};
diff --git a/automotive/vehicle/2.1/Android.mk b/automotive/vehicle/2.1/Android.mk
index f5a121d..f030af08 100644
--- a/automotive/vehicle/2.1/Android.mk
+++ b/automotive/vehicle/2.1/Android.mk
@@ -208,6 +208,44 @@
 LOCAL_GENERATED_SOURCES += $(GEN)
 
 #
+# Build types.hal (VmsMessageIntegerValuesIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsMessageIntegerValuesIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.automotive.vehicle@2.1::types.VmsMessageIntegerValuesIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VmsMessageType)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsMessageType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.automotive.vehicle@2.1::types.VmsMessageType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
 # Build IVehicle.hal
 #
 GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/IVehicle.java
@@ -434,6 +472,44 @@
 LOCAL_GENERATED_SOURCES += $(GEN)
 
 #
+# Build types.hal (VmsMessageIntegerValuesIndex)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsMessageIntegerValuesIndex.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.automotive.vehicle@2.1::types.VmsMessageIntegerValuesIndex
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
+# Build types.hal (VmsMessageType)
+#
+GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/VmsMessageType.java
+$(GEN): $(HIDL)
+$(GEN): PRIVATE_HIDL := $(HIDL)
+$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/types.hal
+$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)
+$(GEN): PRIVATE_CUSTOM_TOOL = \
+        $(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \
+        -Ljava \
+        -randroid.hardware:hardware/interfaces \
+        -randroid.hidl:system/libhidl/transport \
+        android.hardware.automotive.vehicle@2.1::types.VmsMessageType
+
+$(GEN): $(LOCAL_PATH)/types.hal
+	$(transform-generated-source)
+LOCAL_GENERATED_SOURCES += $(GEN)
+
+#
 # Build IVehicle.hal
 #
 GEN := $(intermediates)/android/hardware/automotive/vehicle/V2_1/IVehicle.java
diff --git a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h
index 769ae6d..6bdec59 100644
--- a/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h
+++ b/automotive/vehicle/2.1/default/impl/vhal_v2_1/DefaultConfig.h
@@ -59,6 +59,12 @@
         .prop = V2_0::toInt(V2_1::VehicleProperty::OBD2_FREEZE_FRAME_CLEAR),
         .access = V2_0::VehiclePropertyAccess::WRITE,
         .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE
+    },
+
+    {
+        .prop = V2_0::toInt(VehicleProperty::VEHICLE_MAP_SERVICE),
+        .access = V2_0::VehiclePropertyAccess::READ_WRITE,
+        .changeMode = V2_0::VehiclePropertyChangeMode::ON_CHANGE
     }
 };
 
diff --git a/automotive/vehicle/2.1/types.hal b/automotive/vehicle/2.1/types.hal
index f0dd95f..9b219b2 100644
--- a/automotive/vehicle/2.1/types.hal
+++ b/automotive/vehicle/2.1/types.hal
@@ -174,6 +174,26 @@
       | VehiclePropertyGroup:SYSTEM
       | VehiclePropertyType:COMPLEX
       | VehicleArea:GLOBAL),
+
+    /*
+     * Vehicle Maps Service (VMS) message
+     *
+     * This property uses COMPLEX data to communicate vms messages.
+     *
+     * Its contents are to be interpreted as follows:
+     * the indices defined in VmsMessageIntegerValuesIndex are to be used to
+     * read from int32Values;
+     * bytes is a serialized VMS message as defined in the vms protocol
+     * which is opaque to the framework;
+     *
+     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
+     * @access VehiclePropertyAccess:READ_WRITE
+     */
+    VEHICLE_MAP_SERVICE = (
+        0x0C00
+        | VehiclePropertyGroup:SYSTEM
+        | VehiclePropertyType:COMPLEX
+        | VehicleArea:GLOBAL),
 };
 
 /* The status of a fuel system as described by the OBD2 specification. */
@@ -551,3 +571,35 @@
 
   LAST_SYSTEM_INDEX = ENGINE_FUEL_RATE,
 };
+
+/*
+ * This enum lists the types of supported VMS messages.
+ */
+enum VmsMessageType : int32_t {
+  /* A client subscribes to a layer. */
+  SUBSCRIBE = 1,
+
+  /* A client unsubscribes from a layer. */
+  UNSUBSCRIBE = 2,
+
+  /* A client publishes a data packet. */
+  DATA = 3,
+};
+
+/*
+ * This enum provides the canonical mapping for VMS properties that have an
+ * integer value.
+ */
+enum VmsMessageIntegerValuesIndex : int32_t {
+  /* The message type as enumerated by VmsMessageType enum. */
+  VMS_MESSAGE_TYPE = 0,
+
+  /* The layer ID as defined in the vms protocol. */
+  VMS_LAYER_ID = 1,
+
+  /* The version of the VMS layer. */
+  VMS_LAYER_VERSION = 2,
+
+  /* The number of bytes in the payload */
+  VMS_PAYLOAD_SIZE_BYTES = 3,
+};
diff --git a/benchmarks/Android.bp b/benchmarks/Android.bp
deleted file mode 100644
index ab0f308..0000000
--- a/benchmarks/Android.bp
+++ /dev/null
@@ -1,4 +0,0 @@
-// This is an autogenerated file, do not edit.
-subdirs = [
-    "msgq/1.0",
-]
diff --git a/benchmarks/msgq/1.0/Android.bp b/benchmarks/msgq/1.0/Android.bp
deleted file mode 100644
index 7f8ea99..0000000
--- a/benchmarks/msgq/1.0/Android.bp
+++ /dev/null
@@ -1,59 +0,0 @@
-// This file is autogenerated by hidl-gen. Do not edit manually.
-
-filegroup {
-    name: "android.hardware.benchmarks.msgq@1.0_hal",
-    srcs: [
-        "IBenchmarkMsgQ.hal",
-    ],
-}
-
-genrule {
-    name: "android.hardware.benchmarks.msgq@1.0_genc++",
-    tools: ["hidl-gen"],
-    cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.benchmarks.msgq@1.0",
-    srcs: [
-        ":android.hardware.benchmarks.msgq@1.0_hal",
-    ],
-    out: [
-        "android/hardware/benchmarks/msgq/1.0/BenchmarkMsgQAll.cpp",
-    ],
-}
-
-genrule {
-    name: "android.hardware.benchmarks.msgq@1.0_genc++_headers",
-    tools: ["hidl-gen"],
-    cmd: "$(location hidl-gen) -o $(genDir) -Lc++ -randroid.hardware:hardware/interfaces -randroid.hidl:system/libhidl/transport android.hardware.benchmarks.msgq@1.0",
-    srcs: [
-        ":android.hardware.benchmarks.msgq@1.0_hal",
-    ],
-    out: [
-        "android/hardware/benchmarks/msgq/1.0/IBenchmarkMsgQ.h",
-        "android/hardware/benchmarks/msgq/1.0/IHwBenchmarkMsgQ.h",
-        "android/hardware/benchmarks/msgq/1.0/BnHwBenchmarkMsgQ.h",
-        "android/hardware/benchmarks/msgq/1.0/BpHwBenchmarkMsgQ.h",
-        "android/hardware/benchmarks/msgq/1.0/BsBenchmarkMsgQ.h",
-    ],
-}
-
-cc_library_shared {
-    name: "android.hardware.benchmarks.msgq@1.0",
-    generated_sources: ["android.hardware.benchmarks.msgq@1.0_genc++"],
-    generated_headers: ["android.hardware.benchmarks.msgq@1.0_genc++_headers"],
-    export_generated_headers: ["android.hardware.benchmarks.msgq@1.0_genc++_headers"],
-    shared_libs: [
-        "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
-        "liblog",
-        "libutils",
-        "libcutils",
-        "android.hidl.base@1.0",
-    ],
-    export_shared_lib_headers: [
-        "libhidlbase",
-        "libhidltransport",
-        "libhwbinder",
-        "libutils",
-        "android.hidl.base@1.0",
-    ],
-}
diff --git a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
index 4212729..0e5f1fb 100644
--- a/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
+++ b/broadcastradio/1.0/vts/functional/VtsHalBroadcastradioV1_0TargetTest.cpp
@@ -305,6 +305,40 @@
 }
 
 /**
+ * Test IBroadcastRadio::openTuner() after ITuner disposal.
+ *
+ * Verifies that:
+ *  - ITuner destruction gets propagated through HAL
+ *  - the openTuner method works well when called for the second time
+ */
+TEST_F(BroadcastRadioHidlTest, ReopenTuner) {
+    EXPECT_TRUE(openTuner());
+    mTuner.clear();
+    EXPECT_TRUE(openTuner());
+}
+
+/**
+ * Test IBroadcastRadio::openTuner() method called twice.
+ *
+ * Verifies that:
+ *  - the openTuner method fails when called for the second time without deleting previous
+ *    ITuner instance
+ */
+TEST_F(BroadcastRadioHidlTest, OpenTunerTwice) {
+    EXPECT_TRUE(openTuner());
+
+    Result halResult = Result::NOT_INITIALIZED;
+    Return<void> hidlReturn =
+            mRadio->openTuner(mHalProperties.bands[0], true, mTunerCallback,
+                              [&](Result result, const sp<ITuner>&) {
+                    halResult = result;
+                });
+    EXPECT_TRUE(hidlReturn.isOk());
+    EXPECT_EQ(Result::INVALID_STATE, halResult);
+    EXPECT_TRUE(waitForCallback(kConfigCallbacktimeoutNs));
+}
+
+/**
  * Test ITuner::setConfiguration() and getConfiguration methods
  *
  * Verifies that:
diff --git a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
index c5eea89..40a05e6 100644
--- a/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
+++ b/contexthub/1.0/vts/functional/VtsHalContexthubV1_0TargetTest.cpp
@@ -42,8 +42,6 @@
 using ::android::hardware::contexthub::V1_0::TransactionResult;
 using ::android::sp;
 
-#define CONTEXTHUB_SERVICE_NAME "contexthub"
-
 #define ASSERT_OK(result) ASSERT_EQ(result, Result::OK)
 #define EXPECT_OK(result) EXPECT_EQ(result, Result::OK)
 
@@ -80,7 +78,7 @@
   static std::vector<uint32_t> hubIds;
 
   if (hubIds.size() == 0) {
-    sp<IContexthub> hubApi = ::testing::VtsHalHidlTargetBaseTest::getService<IContexthub>(CONTEXTHUB_SERVICE_NAME);
+    sp<IContexthub> hubApi = ::testing::VtsHalHidlTargetBaseTest::getService<IContexthub>();
 
     if (hubApi != nullptr) {
       for (ContextHub hub : getHubsSync(hubApi)) {
@@ -98,7 +96,7 @@
 class ContexthubHidlTestBase : public ::testing::VtsHalHidlTargetBaseTest {
  public:
   virtual void SetUp() override {
-    hubApi = ::testing::VtsHalHidlTargetBaseTest::getService<IContexthub>(CONTEXTHUB_SERVICE_NAME);
+    hubApi = ::testing::VtsHalHidlTargetBaseTest::getService<IContexthub>();
     ASSERT_NE(hubApi, nullptr);
 
     // getHubs() must be called at least once for proper initialization of the
diff --git a/graphics/common/1.0/types.hal b/graphics/common/1.0/types.hal
index 7663701..1ddd892 100644
--- a/graphics/common/1.0/types.hal
+++ b/graphics/common/1.0/types.hal
@@ -792,7 +792,7 @@
     TRANSFER_GAMMA2_8 = 6 << TRANSFER_SHIFT,
 
     /*
-     * SMPTE ST 2084
+     * SMPTE ST 2084 (Dolby Perceptual Quantizer)
      *
      * Transfer characteristic curve:
      *  E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
@@ -1068,6 +1068,15 @@
      */
     BT2020 = STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL,
 
+    /*
+     * ITU-R Recommendation 2020 (BT.2020)
+     *
+     * Ultra High-definition television
+     *
+     * Use full range, SMPTE 2084 (PQ) transfer and BT2020 standard
+     */
+    BT2020_PQ = STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL,
+
 
     /*
      * Data spaces for non-color formats
diff --git a/media/omx/1.0/IGraphicBufferSource.hal b/media/omx/1.0/IGraphicBufferSource.hal
index 4dbfd32..62073ad 100644
--- a/media/omx/1.0/IGraphicBufferSource.hal
+++ b/media/omx/1.0/IGraphicBufferSource.hal
@@ -29,25 +29,25 @@
  */
 interface IGraphicBufferSource {
 
-    configure(IOmxNode omxNode, Dataspace dataspace);
+    configure(IOmxNode omxNode, Dataspace dataspace) generates (Status status);
 
-    setSuspend(bool suspend, int64_t timeUs);
+    setSuspend(bool suspend, int64_t timeUs) generates (Status status);
 
-    setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs);
+    setRepeatPreviousFrameDelayUs(int64_t repeatAfterUs) generates (Status status);
 
-    setMaxFps(float maxFps);
+    setMaxFps(float maxFps) generates (Status status);
 
-    setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs);
+    setTimeLapseConfig(int64_t timePerFrameUs, int64_t timePerCaptureUs) generates (Status status);
 
-    setStartTimeUs(int64_t startTimeUs);
+    setStartTimeUs(int64_t startTimeUs) generates (Status status);
 
-    setStopTimeUs(int64_t stopTimeUs);
+    setStopTimeUs(int64_t stopTimeUs) generates (Status status);
 
-    setColorAspects(ColorAspects aspects);
+    setColorAspects(ColorAspects aspects) generates (Status status);
 
-    setTimeOffsetUs(int64_t timeOffsetUs);
+    setTimeOffsetUs(int64_t timeOffsetUs) generates (Status status);
 
-    signalEndOfInputStream();
+    signalEndOfInputStream() generates (Status status);
 
 };
 
diff --git a/radio/1.0/IRadio.hal b/radio/1.0/IRadio.hal
index a8c9d93..b3e3e98 100644
--- a/radio/1.0/IRadio.hal
+++ b/radio/1.0/IRadio.hal
@@ -731,20 +731,6 @@
     oneway getDataCallList(int32_t serial);
 
     /*
-     * Indicates the current state of the screen. When the screen is off, the
-     * Radio must notify the baseband to suppress certain notifications (eg,
-     * signal strength and changes in LAC/CID or BID/SID/NID/latitude/longitude)
-     * in an effort to conserve power. These notifications must resume when the
-     * screen is on.
-     *
-     * @param serial Serial number of request.
-     * @param enable true = screen on, false = screen off.
-     *
-     * Response function is IRadioResponse.sendScreenStateResponse()
-     */
-    oneway sendScreenState(int32_t serial, bool enable);
-
-    /*
      * Enables/disables supplementary service related notifications from the network.
      * Notifications are reported via unsolSuppSvcNotification().
      *
diff --git a/radio/1.0/IRadioResponse.hal b/radio/1.0/IRadioResponse.hal
index 11a1d03..cd0899a 100644
--- a/radio/1.0/IRadioResponse.hal
+++ b/radio/1.0/IRadioResponse.hal
@@ -928,17 +928,6 @@
      *   RadioError:NONE
      *   RadioError:RADIO_NOT_AVAILABLE
      *   RadioError:INVALID_ARGUMENTS
-     *   RadioError:GENERIC_FAILURE
-     */
-    oneway sendScreenStateResponse(RadioResponseInfo info);
-
-    /*
-     * @param info Response info struct containing response type, serial no. and error
-     *
-     * Valid errors returned:
-     *   RadioError:NONE
-     *   RadioError:RADIO_NOT_AVAILABLE
-     *   RadioError:INVALID_ARGUMENTS
      *   RadioError:SIM_BUSY
      *   RadioError:NO_MEMORY
      *   RadioError:SYSTEM_ERR
diff --git a/radio/1.0/vts/functional/radio_hidl_hal_utils.h b/radio/1.0/vts/functional/radio_hidl_hal_utils.h
index 0429226..1c58a97 100644
--- a/radio/1.0/vts/functional/radio_hidl_hal_utils.h
+++ b/radio/1.0/vts/functional/radio_hidl_hal_utils.h
@@ -234,8 +234,6 @@
     Return<void> sendOemRilRequestStringsResponse(const RadioResponseInfo& info,
             const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& data);
 
-    Return<void> sendScreenStateResponse(const RadioResponseInfo& info);
-
     Return<void> setSuppServiceNotificationsResponse(
             const RadioResponseInfo& info);
 
diff --git a/radio/1.0/vts/functional/radio_response.cpp b/radio/1.0/vts/functional/radio_response.cpp
index 2b4f10f..64b09c9 100644
--- a/radio/1.0/vts/functional/radio_response.cpp
+++ b/radio/1.0/vts/functional/radio_response.cpp
@@ -314,11 +314,6 @@
     return Void();
 }
 
-Return<void> RadioResponse::sendScreenStateResponse(
-        const RadioResponseInfo& /*info*/) {
-    return Void();
-}
-
 Return<void> RadioResponse::setSuppServiceNotificationsResponse(
         const RadioResponseInfo& /*info*/) {
     return Void();
diff --git a/soundtrigger/2.0/default/SoundTriggerHalImpl.h b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
index 4e0d01d..8aa9285 100644
--- a/soundtrigger/2.0/default/SoundTriggerHalImpl.h
+++ b/soundtrigger/2.0/default/SoundTriggerHalImpl.h
@@ -20,6 +20,7 @@
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHw.h>
 #include <android/hardware/soundtrigger/2.0/ISoundTriggerHwCallback.h>
 #include <hidl/Status.h>
+#include <stdatomic.h>
 #include <utils/threads.h>
 #include <utils/KeyedVector.h>
 #include <system/sound_trigger.h>
diff --git a/tests/msgq/1.0/Android.bp b/tests/msgq/1.0/Android.bp
index d17efe4..2d42699 100644
--- a/tests/msgq/1.0/Android.bp
+++ b/tests/msgq/1.0/Android.bp
@@ -3,6 +3,7 @@
 filegroup {
     name: "android.hardware.tests.msgq@1.0_hal",
     srcs: [
+        "IBenchmarkMsgQ.hal",
         "ITestMsgQ.hal",
     ],
 }
@@ -15,6 +16,7 @@
         ":android.hardware.tests.msgq@1.0_hal",
     ],
     out: [
+        "android/hardware/tests/msgq/1.0/BenchmarkMsgQAll.cpp",
         "android/hardware/tests/msgq/1.0/TestMsgQAll.cpp",
     ],
 }
@@ -27,6 +29,11 @@
         ":android.hardware.tests.msgq@1.0_hal",
     ],
     out: [
+        "android/hardware/tests/msgq/1.0/IBenchmarkMsgQ.h",
+        "android/hardware/tests/msgq/1.0/IHwBenchmarkMsgQ.h",
+        "android/hardware/tests/msgq/1.0/BnHwBenchmarkMsgQ.h",
+        "android/hardware/tests/msgq/1.0/BpHwBenchmarkMsgQ.h",
+        "android/hardware/tests/msgq/1.0/BsBenchmarkMsgQ.h",
         "android/hardware/tests/msgq/1.0/ITestMsgQ.h",
         "android/hardware/tests/msgq/1.0/IHwTestMsgQ.h",
         "android/hardware/tests/msgq/1.0/BnHwTestMsgQ.h",
diff --git a/benchmarks/msgq/1.0/IBenchmarkMsgQ.hal b/tests/msgq/1.0/IBenchmarkMsgQ.hal
similarity index 98%
rename from benchmarks/msgq/1.0/IBenchmarkMsgQ.hal
rename to tests/msgq/1.0/IBenchmarkMsgQ.hal
index c4b9d95..81754a4 100644
--- a/benchmarks/msgq/1.0/IBenchmarkMsgQ.hal
+++ b/tests/msgq/1.0/IBenchmarkMsgQ.hal
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.hardware.benchmarks.msgq@1.0;
+package android.hardware.tests.msgq@1.0;
 
 interface IBenchmarkMsgQ {
     /*
diff --git a/wifi/1.0/default/android.hardware.wifi@1.0-service.rc b/wifi/1.0/default/android.hardware.wifi@1.0-service.rc
index c0ae4d4..696b1f9 100644
--- a/wifi/1.0/default/android.hardware.wifi@1.0-service.rc
+++ b/wifi/1.0/default/android.hardware.wifi@1.0-service.rc
@@ -1,4 +1,4 @@
 service wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service
     class hal
     user wifi
-    group wifi
+    group wifi gps
diff --git a/wifi/1.0/default/hidl_struct_util.cpp b/wifi/1.0/default/hidl_struct_util.cpp
index 82364cb..485ae7e 100644
--- a/wifi/1.0/default/hidl_struct_util.cpp
+++ b/wifi/1.0/default/hidl_struct_util.cpp
@@ -96,7 +96,7 @@
   if (!hidl_caps) {
     return false;
   }
-  *hidl_caps = 0;
+  *hidl_caps = {};
   using HidlChipCaps = IWifiChip::ChipCapabilityMask;
   for (const auto feature : {legacy_hal::WIFI_LOGGER_MEMORY_DUMP_SUPPORTED,
                              legacy_hal::WIFI_LOGGER_DRIVER_DUMP_SUPPORTED,
@@ -133,6 +133,7 @@
   if (!hidl_status) {
     return false;
   }
+  *hidl_status = {};
   hidl_status->ringName = reinterpret_cast<const char*>(legacy_status.name);
   hidl_status->flags = 0;
   for (const auto flag : {WIFI_RING_BUFFER_FLAG_HAS_BINARY_ENTRIES,
@@ -165,7 +166,7 @@
   if (!hidl_status_vec) {
     return false;
   }
-  hidl_status_vec->clear();
+  *hidl_status_vec = {};
   for (const auto& legacy_status : legacy_status_vec) {
     WifiDebugRingBufferStatus hidl_status;
     if (!convertLegacyDebugRingBufferStatusToHidl(legacy_status,
@@ -183,6 +184,7 @@
   if (!hidl_stats) {
     return false;
   }
+  *hidl_stats = {};
   hidl_stats->totalCmdEventWakeCnt =
       legacy_stats.wake_reason_cnt.total_cmd_event_wake;
   hidl_stats->cmdEventWakeCntPerType = legacy_stats.cmd_event_wake_cnt;
@@ -227,6 +229,7 @@
   if (!hidl_caps) {
     return false;
   }
+  *hidl_caps = {};
   *hidl_caps = 0;
   using HidlStaIfaceCaps = IWifiStaIface::StaIfaceCapabilityMask;
   for (const auto feature : {legacy_hal::WIFI_LOGGER_PACKET_FATE_SUPPORTED}) {
@@ -263,6 +266,7 @@
   if (!hidl_caps) {
     return false;
   }
+  *hidl_caps = {};
   hidl_caps->version = legacy_caps.version;
   hidl_caps->maxLength = legacy_caps.max_len;
   return true;
@@ -299,6 +303,7 @@
   if (!hidl_caps) {
     return false;
   }
+  *hidl_caps = {};
   hidl_caps->maxCacheSize = legacy_caps.max_scan_cache_size;
   hidl_caps->maxBuckets = legacy_caps.max_scan_buckets;
   hidl_caps->maxApCachePerScan = legacy_caps.max_ap_cache_per_scan;
@@ -332,6 +337,7 @@
   if (!legacy_scan_params) {
     return false;
   }
+  *legacy_scan_params = {};
   legacy_scan_params->base_period = hidl_scan_params.basePeriodInMs;
   legacy_scan_params->max_ap_per_scan = hidl_scan_params.maxApPerScan;
   legacy_scan_params->report_threshold_percent =
@@ -350,7 +356,7 @@
         legacy_scan_params->buckets[bucket_idx];
     legacy_bucket_spec.bucket = bucket_idx;
     legacy_bucket_spec.band =
-        static_cast<legacy_hal::wifi_band>(hidl_bucket_spec.band);
+        convertHidlWifiBandToLegacy(hidl_bucket_spec.band);
     legacy_bucket_spec.period = hidl_bucket_spec.periodInMs;
     legacy_bucket_spec.max_period = hidl_bucket_spec.exponentialMaxPeriodInMs;
     legacy_bucket_spec.base = hidl_bucket_spec.exponentialBase;
@@ -384,6 +390,7 @@
   if (!hidl_ie) {
     return false;
   }
+  *hidl_ie = {};
   hidl_ie->id = legacy_ie.id;
   hidl_ie->data =
       std::vector<uint8_t>(legacy_ie.data, legacy_ie.data + legacy_ie.len);
@@ -396,6 +403,7 @@
   if (!ie_blob || !hidl_ies) {
     return false;
   }
+  *hidl_ies = {};
   const uint8_t* ies_begin = ie_blob;
   const uint8_t* ies_end = ie_blob + ie_blob_len;
   const uint8_t* next_ie = ies_begin;
@@ -426,10 +434,11 @@
   if (!hidl_scan_result) {
     return false;
   }
+  *hidl_scan_result = {};
   hidl_scan_result->timeStampInUs = legacy_scan_result.ts;
   hidl_scan_result->ssid = std::vector<uint8_t>(
       legacy_scan_result.ssid,
-      legacy_scan_result.ssid + sizeof(legacy_scan_result.ssid));
+      legacy_scan_result.ssid + strlen(legacy_scan_result.ssid));
   memcpy(hidl_scan_result->bssid.data(),
          legacy_scan_result.bssid,
          hidl_scan_result->bssid.size());
@@ -456,6 +465,7 @@
   if (!hidl_scan_data) {
     return false;
   }
+  *hidl_scan_data = {};
   hidl_scan_data->flags = 0;
   for (const auto flag : {legacy_hal::WIFI_SCAN_FLAG_INTERRUPTED}) {
     if (legacy_cached_scan_result.flags & flag) {
@@ -492,7 +502,7 @@
   if (!hidl_scan_datas) {
     return false;
   }
-  hidl_scan_datas->clear();
+  *hidl_scan_datas = {};
   for (const auto& legacy_cached_scan_result : legacy_cached_scan_results) {
     StaScanData hidl_scan_data;
     if (!convertLegacyCachedGscanResultsToHidl(legacy_cached_scan_result,
@@ -579,6 +589,7 @@
   if (!hidl_frame) {
     return false;
   }
+  *hidl_frame = {};
   hidl_frame->frameType =
       convertLegacyDebugPacketFateFrameTypeToHidl(legacy_frame.payload_type);
   hidl_frame->frameLen = legacy_frame.frame_len;
@@ -597,6 +608,7 @@
   if (!hidl_fate) {
     return false;
   }
+  *hidl_fate = {};
   hidl_fate->fate = convertLegacyDebugTxPacketFateToHidl(legacy_fate.fate);
   return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
                                                  &hidl_fate->frameInfo);
@@ -608,7 +620,7 @@
   if (!hidl_fates) {
     return false;
   }
-  hidl_fates->clear();
+  *hidl_fates = {};
   for (const auto& legacy_fate : legacy_fates) {
     WifiDebugTxPacketFateReport hidl_fate;
     if (!convertLegacyDebugTxPacketFateToHidl(legacy_fate, &hidl_fate)) {
@@ -625,6 +637,7 @@
   if (!hidl_fate) {
     return false;
   }
+  *hidl_fate = {};
   hidl_fate->fate = convertLegacyDebugRxPacketFateToHidl(legacy_fate.fate);
   return convertLegacyDebugPacketFateFrameToHidl(legacy_fate.frame_inf,
                                                  &hidl_fate->frameInfo);
@@ -636,7 +649,7 @@
   if (!hidl_fates) {
     return false;
   }
-  hidl_fates->clear();
+  *hidl_fates = {};
   for (const auto& legacy_fate : legacy_fates) {
     WifiDebugRxPacketFateReport hidl_fate;
     if (!convertLegacyDebugRxPacketFateToHidl(legacy_fate, &hidl_fate)) {
@@ -653,6 +666,7 @@
   if (!hidl_stats) {
     return false;
   }
+  *hidl_stats = {};
   // iface legacy_stats conversion.
   hidl_stats->iface.beaconRx = legacy_stats.iface.beacon_rx;
   hidl_stats->iface.avgRssiMgmt = legacy_stats.iface.rssi_mgmt;
@@ -706,6 +720,7 @@
   if (!hidl_caps) {
     return false;
   }
+  *hidl_caps = {};
   hidl_caps->maxBlacklistSize = legacy_caps.max_blacklist_size;
   hidl_caps->maxWhitelistSize = legacy_caps.max_whitelist_size;
   return true;
@@ -717,6 +732,7 @@
   if (!legacy_config) {
     return false;
   }
+  *legacy_config = {};
   if (hidl_config.bssidBlacklist.size() > MAX_BLACKLIST_BSSID ||
       hidl_config.ssidWhitelist.size() > MAX_WHITELIST_SSID) {
     return false;
@@ -762,7 +778,7 @@
     LOG(ERROR) << "convertHidlNanEnableRequestToLegacy: null legacy_request";
     return false;
   }
-  memset(legacy_request, 0, sizeof(legacy_hal::NanEnableRequest));
+  *legacy_request = {};
 
   legacy_request->config_2dot4g_support = 1;
   legacy_request->support_2dot4g_val = hidl_request.operateInBand[
@@ -892,7 +908,7 @@
     LOG(ERROR) << "convertHidlNanPublishRequestToLegacy: null legacy_request";
     return false;
   }
-  memset(legacy_request, 0, sizeof(legacy_hal::NanPublishRequest));
+  *legacy_request = {};
 
   legacy_request->publish_id = hidl_request.baseConfigs.sessionId;
   legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
@@ -984,7 +1000,7 @@
     LOG(ERROR) << "convertHidlNanSubscribeRequestToLegacy: legacy_request is null";
     return false;
   }
-  memset(legacy_request, 0, sizeof(legacy_hal::NanSubscribeRequest));
+  *legacy_request = {};
 
   legacy_request->subscribe_id = hidl_request.baseConfigs.sessionId;
   legacy_request->ttl = hidl_request.baseConfigs.ttlSec;
@@ -1089,7 +1105,7 @@
     LOG(ERROR) << "convertHidlNanTransmitFollowupRequestToLegacy: legacy_request is null";
     return false;
   }
-  memset(legacy_request, 0, sizeof(legacy_hal::NanTransmitFollowupRequest));
+  *legacy_request = {};
 
   legacy_request->publish_subscribe_id = hidl_request.discoverySessionId;
   legacy_request->requestor_instance_id = hidl_request.peerId;
@@ -1128,7 +1144,7 @@
     LOG(ERROR) << "convertHidlNanConfigRequestToLegacy: legacy_request is null";
     return false;
   }
-  memset(legacy_request, 0, sizeof(legacy_hal::NanConfigRequest));
+  *legacy_request = {};
 
   // TODO: b/34059183 tracks missing configurations in legacy HAL or uknown defaults
   legacy_request->master_pref = hidl_request.masterPref;
@@ -1218,7 +1234,7 @@
     LOG(ERROR) << "convertHidlNanDataPathInitiatorRequestToLegacy: legacy_request is null";
     return false;
   }
-  memset(legacy_request, 0, sizeof(legacy_hal::NanDataPathInitiatorRequest));
+  *legacy_request = {};
 
   legacy_request->requestor_instance_id = hidl_request.peerId;
   memcpy(legacy_request->peer_disc_mac_addr, hidl_request.peerDiscMacAddr.data(), 6);
@@ -1253,7 +1269,7 @@
     LOG(ERROR) << "convertHidlNanDataPathIndicationResponseToLegacy: legacy_request is null";
     return false;
   }
-  memset(legacy_request, 0, sizeof(legacy_hal::NanDataPathIndicationResponse));
+  *legacy_request = {};
 
   legacy_request->rsp_code = hidl_request.acceptRequest ?
         legacy_hal::NAN_DP_REQUEST_ACCEPT : legacy_hal::NAN_DP_REQUEST_REJECT;
@@ -1286,9 +1302,10 @@
     LOG(ERROR) << "convertLegacyNanResponseHeaderToHidl: wifiNanStatus is null";
     return false;
   }
+  *wifiNanStatus = {};
+
   wifiNanStatus->status = convertLegacyNanStatusTypeToHidl(legacy_response.status);
   wifiNanStatus->description = legacy_response.nan_error;
-
   return true;
 }
 
@@ -1299,6 +1316,8 @@
     LOG(ERROR) << "convertLegacyNanCapabilitiesResponseToHidl: hidl_response is null";
     return false;
   }
+  *hidl_response = {};
+
   hidl_response->maxConcurrentClusters = legacy_response.max_concurrent_nan_clusters;
   hidl_response->maxPublishes = legacy_response.max_publishes;
   hidl_response->maxSubscribes = legacy_response.max_subscribes;
@@ -1325,6 +1344,8 @@
     LOG(ERROR) << "convertLegacyNanMatchIndToHidl: hidl_ind is null";
     return false;
   }
+  *hidl_ind = {};
+
   hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
   hidl_ind->peerId = legacy_ind.requestor_instance_id;
   hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
@@ -1356,6 +1377,8 @@
     LOG(ERROR) << "convertLegacyNanFollowupIndToHidl: hidl_ind is null";
     return false;
   }
+  *hidl_ind = {};
+
   hidl_ind->discoverySessionId = legacy_ind.publish_subscribe_id;
   hidl_ind->peerId = legacy_ind.requestor_instance_id;
   hidl_ind->addr = hidl_array<uint8_t, 6>(legacy_ind.addr);
@@ -1376,6 +1399,8 @@
     LOG(ERROR) << "convertLegacyNanDataPathRequestIndToHidl: hidl_ind is null";
     return false;
   }
+  *hidl_ind = {};
+
   hidl_ind->discoverySessionId = legacy_ind.service_instance_id;
   hidl_ind->peerDiscMacAddr = hidl_array<uint8_t, 6>(legacy_ind.peer_disc_mac_addr);
   hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
@@ -1394,6 +1419,8 @@
     LOG(ERROR) << "convertLegacyNanDataPathConfirmIndToHidl: hidl_ind is null";
     return false;
   }
+  *hidl_ind = {};
+
   hidl_ind->ndpInstanceId = legacy_ind.ndp_instance_id;
   hidl_ind->dataPathSetupSuccess = legacy_ind.rsp_code == legacy_hal::NAN_DP_REQUEST_ACCEPT;
   hidl_ind->peerNdiMacAddr = hidl_array<uint8_t, 6>(legacy_ind.peer_ndi_mac_addr);
@@ -1635,6 +1662,7 @@
   if (!legacy_info) {
     return false;
   }
+  *legacy_info = {};
   legacy_info->width = convertHidlWifiChannelWidthToLegacy(hidl_info.width);
   legacy_info->center_freq = hidl_info.centerFreq;
   legacy_info->center_freq0 = hidl_info.centerFreq0;
@@ -1648,6 +1676,7 @@
   if (!hidl_info) {
     return false;
   }
+  *hidl_info = {};
   hidl_info->width = convertLegacyWifiChannelWidthToHidl(legacy_info.width);
   hidl_info->centerFreq = legacy_info.center_freq;
   hidl_info->centerFreq0 = legacy_info.center_freq0;
@@ -1660,6 +1689,7 @@
   if (!legacy_config) {
     return false;
   }
+  *legacy_config = {};
   CHECK(hidl_config.addr.size() == sizeof(legacy_config->addr));
   memcpy(legacy_config->addr, hidl_config.addr.data(), hidl_config.addr.size());
   legacy_config->type = convertHidlRttTypeToLegacy(hidl_config.type);
@@ -1688,7 +1718,7 @@
   if (!legacy_configs) {
     return false;
   }
-  legacy_configs->clear();
+  *legacy_configs = {};
   for (const auto& hidl_config : hidl_configs) {
     legacy_hal::wifi_rtt_config legacy_config;
     if (!convertHidlRttConfigToLegacy(hidl_config, &legacy_config)) {
@@ -1705,6 +1735,7 @@
   if (!legacy_info) {
     return false;
   }
+  *legacy_info = {};
   legacy_info->latitude = hidl_info.latitude;
   legacy_info->longitude = hidl_info.longitude;
   legacy_info->altitude = hidl_info.altitude;
@@ -1725,6 +1756,7 @@
   if (!legacy_info) {
     return false;
   }
+  *legacy_info = {};
   CHECK(hidl_info.countryCode.size() == sizeof(legacy_info->country_code));
   memcpy(legacy_info->country_code,
          hidl_info.countryCode.data(),
@@ -1745,6 +1777,7 @@
   if (!legacy_responder) {
     return false;
   }
+  *legacy_responder = {};
   if (!convertHidlWifiChannelInfoToLegacy(hidl_responder.channel,
                                           &legacy_responder->channel)) {
     return false;
@@ -1760,6 +1793,7 @@
   if (!hidl_responder) {
     return false;
   }
+  *hidl_responder = {};
   if (!convertLegacyWifiChannelInfoToHidl(legacy_responder.channel,
                                           &hidl_responder->channel)) {
     return false;
@@ -1775,6 +1809,7 @@
   if (!hidl_capabilities) {
     return false;
   }
+  *hidl_capabilities = {};
   hidl_capabilities->rttOneSidedSupported =
       legacy_capabilities.rtt_one_sided_supported;
   hidl_capabilities->rttFtmSupported = legacy_capabilities.rtt_ftm_supported;
@@ -1814,6 +1849,7 @@
   if (!hidl_rate) {
     return false;
   }
+  *hidl_rate = {};
   hidl_rate->preamble =
       convertLegacyWifiRatePreambleToHidl(legacy_rate.preamble);
   hidl_rate->nss = convertLegacyWifiRateNssToHidl(legacy_rate.nss);
@@ -1829,6 +1865,7 @@
   if (!hidl_result) {
     return false;
   }
+  *hidl_result = {};
   CHECK(sizeof(legacy_result.addr) == hidl_result->addr.size());
   memcpy(
       hidl_result->addr.data(), legacy_result.addr, sizeof(legacy_result.addr));
@@ -1873,7 +1910,7 @@
   if (!hidl_results) {
     return false;
   }
-  hidl_results->clear();
+  *hidl_results = {};
   for (const auto legacy_result : legacy_results) {
     RttResult hidl_result;
     if (!convertLegacyRttResultToHidl(*legacy_result, &hidl_result)) {
diff --git a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
index 9042075..e0c92fe 100644
--- a/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
+++ b/wifi/1.0/vts/functional/wifi_hidl_test_utils.cpp
@@ -36,11 +36,12 @@
 using ::android::hardware::hidl_vec;
 
 void stopFramework() {
-    ASSERT_EQ(std::system("svc wifi disable"), 0);
+    ASSERT_EQ(std::system("stop"), 0);
+    stopWifi();
     sleep(5);
 }
 
-void startFramework() { ASSERT_EQ(std::system("svc wifi enable"), 0); }
+void startFramework() { ASSERT_EQ(std::system("start"), 0); }
 
 sp<IWifi> getWifi() {
     sp<IWifi> wifi = ::testing::VtsHalHidlTargetBaseTest::getService<IWifi>();
diff --git a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
index eb482c9..95c0e5d 100644
--- a/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
+++ b/wifi/1.0/vts/functional/wifi_nan_iface_hidl_test.cpp
@@ -17,24 +17,427 @@
 #include <android-base/logging.h>
 
 #include <android/hardware/wifi/1.0/IWifiNanIface.h>
+#include <android/hardware/wifi/1.0/IWifiNanIfaceEventCallback.h>
 
 #include <VtsHalHidlTargetBaseTest.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
 
+#include "wifi_hidl_call_util.h"
 #include "wifi_hidl_test_utils.h"
 
-using ::android::hardware::wifi::V1_0::IWifiNanIface;
+using namespace ::android::hardware::wifi::V1_0;
+
+using ::android::hardware::Return;
+using ::android::hardware::Void;
 using ::android::sp;
 
+#define TIMEOUT_PERIOD 10
+
 /**
  * Fixture to use for all NAN Iface HIDL interface tests.
  */
 class WifiNanIfaceHidlTest : public ::testing::VtsHalHidlTargetBaseTest {
-   public:
-    virtual void SetUp() override {}
+  public:
+    virtual void SetUp() override {
+      iwifiNanIface = getWifiNanIface();
+      ASSERT_NE(nullptr, iwifiNanIface.get());
+      ASSERT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(iwifiNanIface, registerEventCallback,
+            new WifiNanIfaceEventCallback(*this)).code);
+    }
 
-    virtual void TearDown() override { stopWifi(); }
+    virtual void TearDown() override {
+      stopWifi();
+    }
 
-   protected:
+    /* Used as a mechanism to inform the test about data/event callback */
+    inline void notify() {
+      std::unique_lock<std::mutex> lock(mtx_);
+      count_++;
+      cv_.notify_one();
+    }
+
+    enum CallbackType {
+        INVALID = -2,
+        ANY_CALLBACK = -1,
+
+        NOTIFY_CAPABILITIES_RESPONSE = 0,
+        NOTIFY_ENABLE_RESPONSE,
+        NOTIFY_CONFIG_RESPONSE,
+        NOTIFY_DISABLE_RESPONSE,
+        NOTIFY_START_PUBLISH_RESPONSE,
+        NOTIFY_STOP_PUBLISH_RESPONSE,
+        NOTIFY_START_SUBSCRIBE_RESPONSE,
+        NOTIFY_STOP_SUBSCRIBE_RESPONSE,
+        NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE,
+        NOTIFY_CREATE_DATA_INTERFACE_RESPONSE,
+        NOTIFY_DELETE_DATA_INTERFACE_RESPONSE,
+        NOTIFY_INITIATE_DATA_PATH_RESPONSE,
+        NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE,
+        NOTIFY_TERMINATE_DATA_PATH_RESPONSE,
+
+        EVENT_CLUSTER_EVENT,
+        EVENT_DISABLED,
+        EVENT_PUBLISH_TERMINATED,
+        EVENT_SUBSCRIBE_TERMINATED,
+        EVENT_MATCH,
+        EVENT_MATCH_EXPIRED,
+        EVENT_FOLLOWUP_RECEIVED,
+        EVENT_TRANSMIT_FOLLOWUP,
+        EVENT_DATA_PATH_REQUEST,
+        EVENT_DATA_PATH_CONFIRM,
+        EVENT_DATA_PATH_TERMINATED
+    };
+
+    /* Test code calls this function to wait for data/event callback */
+    inline std::cv_status wait(CallbackType waitForCallbackType) {
+      std::unique_lock<std::mutex> lock(mtx_);
+
+      EXPECT_NE(INVALID, waitForCallbackType); // can't ASSERT in a non-void-returning method
+
+      callbackType = INVALID;
+      std::cv_status status = std::cv_status::no_timeout;
+      auto now = std::chrono::system_clock::now();
+      while (count_ == 0) {
+        status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+        if (status == std::cv_status::timeout) return status;
+        if (waitForCallbackType != ANY_CALLBACK && callbackType != INVALID
+            && callbackType != waitForCallbackType) {
+          count_--;
+        }
+      }
+      count_--;
+      return status;
+    }
+
+    class WifiNanIfaceEventCallback: public IWifiNanIfaceEventCallback {
+      WifiNanIfaceHidlTest& parent_;
+
+     public:
+      WifiNanIfaceEventCallback(WifiNanIfaceHidlTest& parent) : parent_(parent) {};
+
+      virtual ~WifiNanIfaceEventCallback() = default;
+
+      Return<void> notifyCapabilitiesResponse(
+            uint16_t id,
+            const WifiNanStatus& status,
+            const NanCapabilities& capabilities) override {
+        parent_.callbackType = NOTIFY_CAPABILITIES_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+        parent_.capabilities = capabilities;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyEnableResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_ENABLE_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyConfigResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_CONFIG_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyDisableResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_DISABLE_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyStartPublishResponse(
+            uint16_t id,
+            const WifiNanStatus& status,
+            uint8_t sessionId) override {
+        parent_.callbackType = NOTIFY_START_PUBLISH_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+        parent_.sessionId = sessionId;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyStopPublishResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_STOP_PUBLISH_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyStartSubscribeResponse(
+            uint16_t id,
+            const WifiNanStatus& status,
+            uint8_t sessionId) override {
+        parent_.callbackType = NOTIFY_START_SUBSCRIBE_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+        parent_.sessionId = sessionId;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyStopSubscribeResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_STOP_SUBSCRIBE_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyTransmitFollowupResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyCreateDataInterfaceResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyDeleteDataInterfaceResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyInitiateDataPathResponse(
+            uint16_t id,
+            const WifiNanStatus& status,
+            uint32_t ndpInstanceId) override {
+        parent_.callbackType = NOTIFY_INITIATE_DATA_PATH_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+        parent_.ndpInstanceId = ndpInstanceId;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyRespondToDataPathIndicationResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> notifyTerminateDataPathResponse(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = NOTIFY_TERMINATE_DATA_PATH_RESPONSE;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventClusterEvent(
+            const NanClusterEventInd& event) override {
+        parent_.callbackType = EVENT_CLUSTER_EVENT;
+
+        parent_.nanClusterEventInd = event;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventDisabled(
+            const WifiNanStatus& status) override {
+        parent_.callbackType = EVENT_DISABLED;
+
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventPublishTerminated(
+            uint8_t sessionId,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = EVENT_PUBLISH_TERMINATED;
+
+        parent_.sessionId = sessionId;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventSubscribeTerminated(
+            uint8_t sessionId,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = EVENT_SUBSCRIBE_TERMINATED;
+
+        parent_.sessionId = sessionId;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventMatch(
+            const NanMatchInd& event) override {
+        parent_.callbackType = EVENT_MATCH;
+
+        parent_.nanMatchInd = event;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventMatchExpired(
+            uint8_t discoverySessionId,
+            uint32_t peerId) override {
+        parent_.callbackType = EVENT_MATCH_EXPIRED;
+
+        parent_.sessionId = discoverySessionId;
+        parent_.peerId = peerId;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventFollowupReceived(
+            const NanFollowupReceivedInd& event) override {
+        parent_.callbackType = EVENT_FOLLOWUP_RECEIVED;
+
+        parent_.nanFollowupReceivedInd = event;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventTransmitFollowup(
+            uint16_t id,
+            const WifiNanStatus& status) override {
+        parent_.callbackType = EVENT_TRANSMIT_FOLLOWUP;
+
+        parent_.id = id;
+        parent_.status = status;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventDataPathRequest(
+            const NanDataPathRequestInd& event) override {
+        parent_.callbackType = EVENT_DATA_PATH_REQUEST;
+
+        parent_.nanDataPathRequestInd = event;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventDataPathConfirm(
+            const NanDataPathConfirmInd& event) override {
+        parent_.callbackType = EVENT_DATA_PATH_CONFIRM;
+
+        parent_.nanDataPathConfirmInd = event;
+
+        parent_.notify();
+        return Void();
+      }
+
+      Return<void> eventDataPathTerminated(
+            uint32_t ndpInstanceId) override {
+        parent_.callbackType = EVENT_DATA_PATH_TERMINATED;
+
+        parent_.ndpInstanceId = ndpInstanceId;
+
+        parent_.notify();
+        return Void();
+      }
+    };
+
+    private:
+      // synchronization objects
+      std::mutex mtx_;
+      std::condition_variable cv_;
+      int count_;
+
+    protected:
+      android::sp<IWifiNanIface> iwifiNanIface;
+
+      // Data from IWifiNanIfaceEventCallback callbacks: this is the collection of all
+      // arguments to all callbacks. They are set by the callback (notifications or
+      // events) and can be retrieved by tests.
+      CallbackType callbackType;
+      uint16_t id;
+      WifiNanStatus status;
+      NanCapabilities capabilities;
+      uint8_t sessionId;
+      uint32_t ndpInstanceId;
+      NanClusterEventInd nanClusterEventInd;
+      NanMatchInd nanMatchInd;
+      uint32_t peerId;
+      NanFollowupReceivedInd nanFollowupReceivedInd;
+      NanDataPathRequestInd nanDataPathRequestInd;
+      NanDataPathConfirmInd nanDataPathConfirmInd;
 };
 
 /*
@@ -43,6 +446,49 @@
  * successfully created.
  */
 TEST(WifiNanIfaceHidlTestNoFixture, Create) {
-    EXPECT_NE(nullptr, getWifiNanIface().get());
-    stopWifi();
+  ASSERT_NE(nullptr, getWifiNanIface().get());
+  stopWifi();
+}
+
+/*
+ * Fail: use past destruction
+ * Ensure that API calls fail with ERROR_WIFI_IFACE_INVALID when using an interface once wifi
+ * is disabled.
+ */
+TEST(WifiNanIfaceHidlTestNoFixture, FailOnIfaceInvalid) {
+  android::sp<IWifiNanIface> iwifiNanIface = getWifiNanIface();
+  ASSERT_NE(nullptr, iwifiNanIface.get());
+  stopWifi();
+  sleep(5); // make sure that all chips/interfaces are invalidated
+  ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+          HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, 0).code);
+}
+
+/*
+ * getCapabilitiesRequest: validate that returns capabilities.
+ */
+TEST_F(WifiNanIfaceHidlTest, getCapabilitiesRequest) {
+  uint16_t inputCmdId = 10;
+  ASSERT_EQ(WifiStatusCode::SUCCESS,
+        HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, inputCmdId).code);
+  // wait for a callback
+  ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE));
+  ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callbackType);
+  ASSERT_EQ(id, inputCmdId);
+
+  // check for reasonable capability values
+  EXPECT_GT(capabilities.maxConcurrentClusters, (unsigned int) 0);
+  EXPECT_GT(capabilities.maxPublishes, (unsigned int) 0);
+  EXPECT_GT(capabilities.maxSubscribes, (unsigned int) 0);
+  EXPECT_EQ(capabilities.maxServiceNameLen, (unsigned int) 255);
+  EXPECT_EQ(capabilities.maxMatchFilterLen, (unsigned int) 255);
+  EXPECT_GT(capabilities.maxTotalMatchFilterLen, (unsigned int) 255);
+  EXPECT_EQ(capabilities.maxServiceSpecificInfoLen, (unsigned int) 255);
+  EXPECT_GE(capabilities.maxExtendedServiceSpecificInfoLen, (unsigned int) 255);
+  EXPECT_GT(capabilities.maxNdiInterfaces, (unsigned int) 0);
+  EXPECT_GT(capabilities.maxNdpSessions, (unsigned int) 0);
+  EXPECT_GT(capabilities.maxAppInfoLen, (unsigned int) 0);
+  EXPECT_GT(capabilities.maxQueuedTransmitFollowupMsgs, (unsigned int) 0);
+  EXPECT_GT(capabilities.maxSubscribeInterfaceAddresses, (unsigned int) 0);
+  EXPECT_NE(capabilities.supportedCipherSuites, (unsigned int) 0);
 }