Merge "Block data call" into main
diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING
index 3e06595..81c99f7 100644
--- a/audio/aidl/TEST_MAPPING
+++ b/audio/aidl/TEST_MAPPING
@@ -4,6 +4,9 @@
       "name": "VtsHalAudioCoreTargetTest"
     },
     {
+      "name": "audio_policy_config_xml_converter_tests"
+    },
+    {
       "name": "VtsHalAudioEffectFactoryTargetTest"
     },
     {
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index e9294cf..78b59d4 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -144,6 +144,50 @@
     ],
 }
 
+cc_test {
+    name: "audio_policy_config_xml_converter_tests",
+    vendor_available: true,
+    defaults: [
+        "latest_android_media_audio_common_types_ndk_static",
+        "latest_android_hardware_audio_core_ndk_static",
+    ],
+    shared_libs: [
+        "libaudio_aidl_conversion_common_ndk",
+        "libaudioaidlcommon",
+        "libaudioutils",
+        "libbase",
+        "libbinder_ndk",
+        "libcutils",
+        "libmedia_helper",
+        "libstagefright_foundation",
+        "libutils",
+        "libxml2",
+    ],
+    header_libs: [
+        "libaudio_system_headers",
+        "libaudioaidl_headers",
+        "libxsdc-utils",
+    ],
+    generated_sources: [
+        "audio_policy_configuration_aidl_default",
+    ],
+    generated_headers: [
+        "audio_policy_configuration_aidl_default",
+    ],
+    srcs: [
+        "AudioPolicyConfigXmlConverter.cpp",
+        "tests/AudioPolicyConfigXmlConverterTest.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Wextra",
+        "-Werror",
+        "-Wthread-safety",
+        "-DBACKEND_NDK",
+    ],
+    test_suites: ["general-tests"],
+}
+
 cc_defaults {
     name: "aidlaudioeffectservice_defaults",
     defaults: [
diff --git a/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp
index 2848d71..7452c8e 100644
--- a/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp
+++ b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp
@@ -137,7 +137,7 @@
                     SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS),
                     SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_HD),
                     SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_HD_MA),
-                    SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_UHD),
+                    SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_UHD_P1),
                     SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DTS_UHD_P2),
                     SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_DOLBY_TRUEHD),
                     SIMPLE_FORMAT(MEDIA_MIMETYPE_AUDIO_EAC3_JOC),
diff --git a/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h
index 94501a8..090d585 100644
--- a/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h
+++ b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h
@@ -38,9 +38,10 @@
     const ::aidl::android::media::audio::common::AudioHalEngineConfig& getAidlEngineConfig();
     const SurroundSoundConfig& getSurroundSoundConfig();
 
-  private:
+    // Public for testing purposes.
     static const SurroundSoundConfig& getDefaultSurroundSoundConfig();
 
+  private:
     const std::optional<::android::audio::policy::configuration::AudioPolicyConfiguration>&
     getXsdcConfig() const {
         return mConverter.getXsdcConfig();
diff --git a/audio/aidl/default/tests/AudioPolicyConfigXmlConverterTest.cpp b/audio/aidl/default/tests/AudioPolicyConfigXmlConverterTest.cpp
new file mode 100644
index 0000000..572bc5a
--- /dev/null
+++ b/audio/aidl/default/tests/AudioPolicyConfigXmlConverterTest.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 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 <memory>
+// #include <string>
+// #include <vector>
+
+#include <android-base/macros.h>
+#include <gtest/gtest.h>
+#define LOG_TAG "AudioPolicyConfigXmlConverterTest"
+#include <log/log.h>
+
+#include <core-impl/AudioPolicyConfigXmlConverter.h>
+#include <media/AidlConversionCppNdk.h>
+
+using aidl::android::hardware::audio::core::internal::AudioPolicyConfigXmlConverter;
+using aidl::android::media::audio::common::AudioFormatDescription;
+
+namespace {
+
+void ValidateAudioFormatDescription(const AudioFormatDescription& format) {
+    auto conv = ::aidl::android::aidl2legacy_AudioFormatDescription_audio_format_t(format);
+    ASSERT_TRUE(conv.ok()) << format.toString();
+}
+
+}  // namespace
+
+TEST(AudioPolicyConfigXmlConverterTest, DefaultSurroundSoundConfigIsValid) {
+    auto config = AudioPolicyConfigXmlConverter::getDefaultSurroundSoundConfig();
+    for (const auto& family : config.formatFamilies) {
+        EXPECT_NO_FATAL_FAILURE(ValidateAudioFormatDescription(family.primaryFormat));
+        SCOPED_TRACE(family.primaryFormat.toString());
+        for (const auto& sub : family.subFormats) {
+            EXPECT_NO_FATAL_FAILURE(ValidateAudioFormatDescription(sub));
+        }
+    }
+}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index 94e4ef7..4934771 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -1833,6 +1833,7 @@
 
 void FakeVehicleHardware::registerOnPropertySetErrorEvent(
         std::unique_ptr<const PropertySetErrorCallback> callback) {
+    // In FakeVehicleHardware, we will never use mOnPropertySetErrorCallback.
     if (mOnPropertySetErrorCallback != nullptr) {
         ALOGE("registerOnPropertySetErrorEvent must only be called once");
         return;
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
index 141efc1..62046f3 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/RecurrentTimerTest.cpp
@@ -18,6 +18,7 @@
 
 #include <android-base/thread_annotations.h>
 #include <gtest/gtest.h>
+#include <condition_variable>
 
 #include <chrono>
 #include <memory>
@@ -28,6 +29,8 @@
 namespace automotive {
 namespace vehicle {
 
+using ::android::base::ScopedLockAssertion;
+
 class RecurrentTimerTest : public testing::Test {
   public:
     std::shared_ptr<RecurrentTimer::Callback> getCallback(size_t token) {
@@ -35,6 +38,15 @@
             std::scoped_lock<std::mutex> lockGuard(mLock);
 
             mCallbacks.push_back(token);
+            mCond.notify_all();
+        });
+    }
+
+    bool waitForCalledCallbacks(size_t count, size_t timeoutInMs) {
+        std::unique_lock<std::mutex> uniqueLock(mLock);
+        return mCond.wait_for(uniqueLock, std::chrono::milliseconds(timeoutInMs), [this, count] {
+            ScopedLockAssertion lockAssertion(mLock);
+            return mCallbacks.size() >= count;
         });
     }
 
@@ -54,6 +66,7 @@
     }
 
   private:
+    std::condition_variable mCond;
     std::mutex mLock;
     std::vector<size_t> mCallbacks GUARDED_BY(mLock);
 };
@@ -66,12 +79,11 @@
     auto action = getCallback(0);
     timer.registerTimerCallback(interval, action);
 
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    // Should only takes 1s, use 5s as timeout to be safe.
+    ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 10u, /* timeoutInMs= */ 5000))
+            << "Not enough callbacks called before timeout";
 
     timer.unregisterTimerCallback(action);
-
-    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
-    ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
 }
 
 TEST_F(RecurrentTimerTest, testRegisterUnregisterRegister) {
@@ -92,10 +104,11 @@
 
     timer.registerTimerCallback(interval, action);
 
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    // Should only takes 1s, use 5s as timeout to be safe.
+    ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 10u, /* timeoutInMs= */ 5000))
+            << "Not enough callbacks called before timeout";
 
-    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
-    ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
+    timer.unregisterTimerCallback(action);
 }
 
 TEST_F(RecurrentTimerTest, testDestroyTimerWithCallback) {
@@ -114,7 +127,9 @@
 
     std::this_thread::sleep_for(std::chrono::milliseconds(200));
 
-    ASSERT_TRUE(getCalledCallbacks().empty());
+    // Should be 0, but in rare cases there might be 1 events in the queue while the timer is
+    // being destroyed.
+    ASSERT_LE(getCalledCallbacks().size(), 1u);
 }
 
 TEST_F(RecurrentTimerTest, testRegisterMultipleCallbacks) {
@@ -132,7 +147,11 @@
     auto action3 = getCallback(3);
     timer.registerTimerCallback(interval3, action3);
 
-    std::this_thread::sleep_for(std::chrono::seconds(1));
+    // In 1s, we should generate 10 + 20 + 33 = 63 events.
+    // Here we are waiting for more events to make sure we receive enough events for each actions.
+    // Use 5s as timeout to be safe.
+    ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 70u, /* timeoutInMs= */ 5000))
+            << "Not enough callbacks called before timeout";
 
     timer.unregisterTimerCallback(action1);
     timer.unregisterTimerCallback(action2);
@@ -152,20 +171,18 @@
             action3Count++;
         }
     }
-    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
-    ASSERT_GE(action1Count, static_cast<size_t>(9));
-    // Theoretically trigger 20 times, but check for at least 15 times to be stable.
-    ASSERT_GE(action2Count, static_cast<size_t>(15));
-    // Theoretically trigger 33 times, but check for at least 25 times to be stable.
-    ASSERT_GE(action3Count, static_cast<size_t>(25));
+
+    ASSERT_GE(action1Count, static_cast<size_t>(10));
+    ASSERT_GE(action2Count, static_cast<size_t>(20));
+    ASSERT_GE(action3Count, static_cast<size_t>(33));
 }
 
 TEST_F(RecurrentTimerTest, testRegisterSameCallbackMultipleTimes) {
     RecurrentTimer timer;
-    // 0.02s
-    int64_t interval1 = 20000000;
-    // 0.01s
-    int64_t interval2 = 10000000;
+    // 0.2s
+    int64_t interval1 = 200'000'000;
+    // 0.1s
+    int64_t interval2 = 100'000'000;
 
     auto action = getCallback(0);
     for (int i = 0; i < 10; i++) {
@@ -175,10 +192,9 @@
 
     clearCalledCallbacks();
 
-    std::this_thread::sleep_for(std::chrono::milliseconds(100));
-
-    // Theoretically trigger 10 times, but check for at least 9 times to be stable.
-    ASSERT_GE(getCalledCallbacks().size(), static_cast<size_t>(9));
+    // Should only takes 1s, use 5s as timeout to be safe.
+    ASSERT_TRUE(waitForCalledCallbacks(/* count= */ 10u, /* timeoutInMs= */ 5000))
+            << "Not enough callbacks called before timeout";
 
     timer.unregisterTimerCallback(action);
 
diff --git a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
index 2e7298f..addc901 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/ConnectedClient.h
@@ -99,35 +99,23 @@
     std::shared_ptr<const std::function<void(std::vector<ResultType>)>> mResultCallback;
 };
 
-// A class to represent a client that calls {@code IVehicle.subscribe}.
-class SubscriptionClient final : public ConnectedClient {
+class SubscriptionClient {
   public:
-    SubscriptionClient(std::shared_ptr<PendingRequestPool> requestPool, CallbackType callback);
+    using CallbackType =
+            std::shared_ptr<aidl::android::hardware::automotive::vehicle::IVehicleCallback>;
 
-    // Gets the callback to be called when the request for this client has finished.
-    std::shared_ptr<const IVehicleHardware::GetValuesCallback> getResultCallback();
-
-    // Marshals the updated values into largeParcelable and sents it through {@code onPropertyEvent}
+    // Marshals the updated values into largeParcelable and sends it through {@code onPropertyEvent}
     // callback.
     static void sendUpdatedValues(
             CallbackType callback,
             std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&&
                     updatedValues);
-
-  protected:
-    // Gets the callback to be called when the request for this client has timeout.
-    std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> getTimeoutCallback() override;
-
-  private:
-    // The following members are only initialized during construction.
-    std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc> mTimeoutCallback;
-    std::shared_ptr<const IVehicleHardware::GetValuesCallback> mResultCallback;
-    std::shared_ptr<const IVehicleHardware::PropertyChangeCallback> mPropertyChangeCallback;
-
-    static void onGetValueResults(
-            const void* clientId, CallbackType callback,
-            std::shared_ptr<PendingRequestPool> requestPool,
-            std::vector<aidl::android::hardware::automotive::vehicle::GetValueResult> results);
+    // Marshals the set property error events into largeParcelable and sends it through
+    // {@code onPropertySetError} callback.
+    static void sendPropertySetErrors(
+            CallbackType callback,
+            std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>&&
+                    vehiclePropErrors);
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
index 2c2cf1a..419e16b 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/DefaultVehicleHal.h
@@ -90,39 +90,6 @@
             GetSetValuesClient<aidl::android::hardware::automotive::vehicle::SetValueResult,
                                aidl::android::hardware::automotive::vehicle::SetValueResults>;
 
-    // A thread safe class to maintain an increasing request ID for each subscribe client. This
-    // class is safe to pass to async callbacks.
-    class SubscribeIdByClient {
-      public:
-        int64_t getId(const CallbackType& callback);
-
-      private:
-        std::mutex mLock;
-        std::unordered_map<const AIBinder*, int64_t> mIds GUARDED_BY(mLock);
-    };
-
-    // A thread safe class to store all subscribe clients. This class is safe to pass to async
-    // callbacks.
-    class SubscriptionClients {
-      public:
-        SubscriptionClients(std::shared_ptr<PendingRequestPool> pool) : mPendingRequestPool(pool) {}
-
-        std::shared_ptr<SubscriptionClient> maybeAddClient(const CallbackType& callback);
-
-        std::shared_ptr<SubscriptionClient> getClient(const CallbackType& callback);
-
-        void removeClient(const AIBinder* clientId);
-
-        size_t countClients();
-
-      private:
-        std::mutex mLock;
-        std::unordered_map<const AIBinder*, std::shared_ptr<SubscriptionClient>> mClients
-                GUARDED_BY(mLock);
-        // PendingRequestPool is thread-safe.
-        std::shared_ptr<PendingRequestPool> mPendingRequestPool;
-    };
-
     // A wrapper for binder lifecycle operations to enable stubbing for test.
     class BinderLifecycleInterface {
       public:
@@ -185,8 +152,6 @@
             GUARDED_BY(mLock);
     std::unordered_map<const AIBinder*, std::shared_ptr<SetValuesClient>> mSetValuesClients
             GUARDED_BY(mLock);
-    // SubscriptionClients is thread-safe.
-    std::shared_ptr<SubscriptionClients> mSubscriptionClients;
     // mBinderLifecycleHandler is only going to be changed in test.
     std::unique_ptr<BinderLifecycleInterface> mBinderLifecycleHandler;
 
@@ -242,6 +207,8 @@
     // mBinderEvents.
     void onBinderDiedUnlinkedHandler();
 
+    size_t countSubscribeClients();
+
     // Gets or creates a {@code T} object for the client to or from {@code clients}.
     template <class T>
     static std::shared_ptr<T> getOrCreateClient(
@@ -249,10 +216,14 @@
             const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
 
     static void onPropertyChangeEvent(
-            std::weak_ptr<SubscriptionManager> subscriptionManager,
+            const std::weak_ptr<SubscriptionManager>& subscriptionManager,
             const std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
                     updatedValues);
 
+    static void onPropertySetErrorEvent(
+            const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+            const std::vector<SetValueErrorEvent>& errorEvents);
+
     static void checkHealth(IVehicleHardware* hardware,
                             std::weak_ptr<SubscriptionManager> subscriptionManager);
 
diff --git a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
index 14799d9..512d906 100644
--- a/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
+++ b/automotive/vehicle/aidl/impl/vhal/include/SubscriptionManager.h
@@ -99,6 +99,15 @@
             const std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropValue>&
                     updatedValues);
 
+    // For a list of set property error events, returns a map that maps clients subscribing to the
+    // properties to a list of errors for each client.
+    std::unordered_map<CallbackType,
+                       std::vector<aidl::android::hardware::automotive::vehicle::VehiclePropError>>
+    getSubscribedClientsForErrorEvents(const std::vector<SetValueErrorEvent>& errorEvents);
+
+    // Returns the number of subscribed clients.
+    size_t countClients();
+
     // Checks whether the sample rate is valid.
     static bool checkSampleRateHz(float sampleRateHz);
 
diff --git a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
index 81d231c..35b93d2 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/ConnectedClient.cpp
@@ -38,6 +38,8 @@
 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
 using ::aidl::android::hardware::automotive::vehicle::SetValueResults;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValues;
 using ::android::base::Result;
@@ -248,36 +250,6 @@
 template class GetSetValuesClient<GetValueResult, GetValueResults>;
 template class GetSetValuesClient<SetValueResult, SetValueResults>;
 
-SubscriptionClient::SubscriptionClient(std::shared_ptr<PendingRequestPool> requestPool,
-                                       std::shared_ptr<IVehicleCallback> callback)
-    : ConnectedClient(requestPool, callback) {
-    mTimeoutCallback = std::make_shared<const PendingRequestPool::TimeoutCallbackFunc>(
-            [](std::unordered_set<int64_t> timeoutIds) {
-                for (int64_t id : timeoutIds) {
-                    ALOGW("subscribe: requests with IDs: %" PRId64
-                          " has timed-out, not client informed, "
-                          "possibly one of recurrent requests for this subscription failed",
-                          id);
-                }
-            });
-    auto requestPoolCopy = mRequestPool;
-    const void* clientId = reinterpret_cast<const void*>(this);
-    mResultCallback = std::make_shared<const IVehicleHardware::GetValuesCallback>(
-            [clientId, callback, requestPoolCopy](std::vector<GetValueResult> results) {
-                onGetValueResults(clientId, callback, requestPoolCopy, results);
-            });
-}
-
-std::shared_ptr<const std::function<void(std::vector<GetValueResult>)>>
-SubscriptionClient::getResultCallback() {
-    return mResultCallback;
-}
-
-std::shared_ptr<const PendingRequestPool::TimeoutCallbackFunc>
-SubscriptionClient::getTimeoutCallback() {
-    return mTimeoutCallback;
-}
-
 void SubscriptionClient::sendUpdatedValues(std::shared_ptr<IVehicleCallback> callback,
                                            std::vector<VehiclePropValue>&& updatedValues) {
     if (updatedValues.empty()) {
@@ -300,48 +272,38 @@
     if (ScopedAStatus callbackStatus =
                 callback->onPropertyEvent(vehiclePropValues, sharedMemoryFileCount);
         !callbackStatus.isOk()) {
-        ALOGE("subscribe: failed to call UpdateValues callback, client ID: %p, error: %s, "
+        ALOGE("subscribe: failed to call onPropertyEvent callback, client ID: %p, error: %s, "
               "exception: %d, service specific error: %d",
               callback->asBinder().get(), callbackStatus.getMessage(),
               callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
     }
 }
 
-void SubscriptionClient::onGetValueResults(const void* clientId,
-                                           std::shared_ptr<IVehicleCallback> callback,
-                                           std::shared_ptr<PendingRequestPool> requestPool,
-                                           std::vector<GetValueResult> results) {
-    std::unordered_set<int64_t> requestIds;
-    for (const auto& result : results) {
-        requestIds.insert(result.requestId);
+void SubscriptionClient::sendPropertySetErrors(std::shared_ptr<IVehicleCallback> callback,
+                                               std::vector<VehiclePropError>&& vehiclePropErrors) {
+    if (vehiclePropErrors.empty()) {
+        return;
     }
 
-    auto finishedRequests = requestPool->tryFinishRequests(clientId, requestIds);
-    std::vector<VehiclePropValue> propValues;
-    for (auto& result : results) {
-        int64_t requestId = result.requestId;
-        if (finishedRequests.find(requestId) == finishedRequests.end()) {
-            ALOGE("subscribe[%" PRId64
-                  "]: no pending request for the result from hardware, "
-                  "possibly already time-out",
-                  requestId);
-            continue;
-        }
-        if (result.status != StatusCode::OK) {
-            ALOGE("subscribe[%" PRId64
-                  "]: hardware returns non-ok status for getValues, status: "
-                  "%d",
-                  requestId, toInt(result.status));
-            continue;
-        }
-        if (!result.prop.has_value()) {
-            ALOGE("subscribe[%" PRId64 "]: no prop value in getValues result", requestId);
-            continue;
-        }
-        propValues.push_back(std::move(result.prop.value()));
+    VehiclePropErrors vehiclePropErrorsLargeParcelable;
+    ScopedAStatus status = vectorToStableLargeParcelable(std::move(vehiclePropErrors),
+                                                         &vehiclePropErrorsLargeParcelable);
+    if (!status.isOk()) {
+        int statusCode = status.getServiceSpecificError();
+        ALOGE("subscribe: failed to marshal result into large parcelable, error: "
+              "%s, code: %d",
+              status.getMessage(), statusCode);
+        return;
     }
 
-    sendUpdatedValues(callback, std::move(propValues));
+    if (ScopedAStatus callbackStatus =
+                callback->onPropertySetError(vehiclePropErrorsLargeParcelable);
+        !callbackStatus.isOk()) {
+        ALOGE("subscribe: failed to call onPropertySetError callback, client ID: %p, error: %s, "
+              "exception: %d, service specific error: %d",
+              callback->asBinder().get(), callbackStatus.getMessage(),
+              callbackStatus.getExceptionCode(), callbackStatus.getServiceSpecificError());
+    }
 }
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
index 98cfc39..f3eba2e 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/DefaultVehicleHal.cpp
@@ -92,39 +92,6 @@
 
 }  // namespace
 
-std::shared_ptr<SubscriptionClient> DefaultVehicleHal::SubscriptionClients::maybeAddClient(
-        const CallbackType& callback) {
-    std::scoped_lock<std::mutex> lockGuard(mLock);
-    return getOrCreateClient(&mClients, callback, mPendingRequestPool);
-}
-
-std::shared_ptr<SubscriptionClient> DefaultVehicleHal::SubscriptionClients::getClient(
-        const CallbackType& callback) {
-    std::scoped_lock<std::mutex> lockGuard(mLock);
-    const AIBinder* clientId = callback->asBinder().get();
-    if (mClients.find(clientId) == mClients.end()) {
-        return nullptr;
-    }
-    return mClients[clientId];
-}
-
-int64_t DefaultVehicleHal::SubscribeIdByClient::getId(const CallbackType& callback) {
-    std::scoped_lock<std::mutex> lockGuard(mLock);
-    // This would be initialized to 0 if callback does not exist in the map.
-    int64_t subscribeId = (mIds[callback->asBinder().get()])++;
-    return subscribeId;
-}
-
-void DefaultVehicleHal::SubscriptionClients::removeClient(const AIBinder* clientId) {
-    std::scoped_lock<std::mutex> lockGuard(mLock);
-    mClients.erase(clientId);
-}
-
-size_t DefaultVehicleHal::SubscriptionClients::countClients() {
-    std::scoped_lock<std::mutex> lockGuard(mLock);
-    return mClients.size();
-}
-
 DefaultVehicleHal::DefaultVehicleHal(std::unique_ptr<IVehicleHardware> vehicleHardware)
     : mVehicleHardware(std::move(vehicleHardware)),
       mPendingRequestPool(std::make_shared<PendingRequestPool>(TIMEOUT_IN_NANO)) {
@@ -132,9 +99,6 @@
         return;
     }
 
-    mSubscriptionClients = std::make_shared<SubscriptionClients>(mPendingRequestPool);
-
-    auto subscribeIdByClient = std::make_shared<SubscribeIdByClient>();
     IVehicleHardware* vehicleHardwarePtr = mVehicleHardware.get();
     mSubscriptionManager = std::make_shared<SubscriptionManager>(vehicleHardwarePtr);
 
@@ -144,6 +108,11 @@
                     [subscriptionManagerCopy](std::vector<VehiclePropValue> updatedValues) {
                         onPropertyChangeEvent(subscriptionManagerCopy, updatedValues);
                     }));
+    mVehicleHardware->registerOnPropertySetErrorEvent(
+            std::make_unique<IVehicleHardware::PropertySetErrorCallback>(
+                    [subscriptionManagerCopy](std::vector<SetValueErrorEvent> errorEvents) {
+                        onPropertySetErrorEvent(subscriptionManagerCopy, errorEvents);
+                    }));
 
     // Register heartbeat event.
     mRecurrentAction = std::make_shared<std::function<void()>>(
@@ -177,7 +146,7 @@
 }
 
 void DefaultVehicleHal::onPropertyChangeEvent(
-        std::weak_ptr<SubscriptionManager> subscriptionManager,
+        const std::weak_ptr<SubscriptionManager>& subscriptionManager,
         const std::vector<VehiclePropValue>& updatedValues) {
     auto manager = subscriptionManager.lock();
     if (manager == nullptr) {
@@ -194,6 +163,20 @@
     }
 }
 
+void DefaultVehicleHal::onPropertySetErrorEvent(
+        const std::weak_ptr<SubscriptionManager>& subscriptionManager,
+        const std::vector<SetValueErrorEvent>& errorEvents) {
+    auto manager = subscriptionManager.lock();
+    if (manager == nullptr) {
+        ALOGW("the SubscriptionManager is destroyed, DefaultVehicleHal is ending");
+        return;
+    }
+    auto vehiclePropErrorsByClient = manager->getSubscribedClientsForErrorEvents(errorEvents);
+    for (auto& [callback, vehiclePropErrors] : vehiclePropErrorsByClient) {
+        SubscriptionClient::sendPropertySetErrors(callback, std::move(vehiclePropErrors));
+    }
+}
+
 template <class T>
 std::shared_ptr<T> DefaultVehicleHal::getOrCreateClient(
         std::unordered_map<const AIBinder*, std::shared_ptr<T>>* clients,
@@ -243,7 +226,6 @@
     ALOGD("binder died, client ID: %p", clientId);
     mSetValuesClients.erase(clientId);
     mGetValuesClients.erase(clientId);
-    mSubscriptionClients->removeClient(clientId);
     mSubscriptionManager->unsubscribe(clientId);
 }
 
@@ -282,10 +264,6 @@
 DefaultVehicleHal::getOrCreateClient<DefaultVehicleHal::SetValuesClient>(
         std::unordered_map<const AIBinder*, std::shared_ptr<SetValuesClient>>* clients,
         const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
-template std::shared_ptr<SubscriptionClient>
-DefaultVehicleHal::getOrCreateClient<SubscriptionClient>(
-        std::unordered_map<const AIBinder*, std::shared_ptr<SubscriptionClient>>* clients,
-        const CallbackType& callback, std::shared_ptr<PendingRequestPool> pendingRequestPool);
 
 void DefaultVehicleHal::setTimeout(int64_t timeoutInNano) {
     mPendingRequestPool = std::make_unique<PendingRequestPool>(timeoutInNano);
@@ -689,18 +667,19 @@
                                                                "client died");
         }
 
-        // Create a new SubscriptionClient if there isn't an existing one.
-        mSubscriptionClients->maybeAddClient(callback);
-
-        // Since we have already check the sample rates, the following functions must succeed.
         if (!onChangeSubscriptions.empty()) {
-            return toScopedAStatus(mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
-                                                                   /*isContinuousProperty=*/false));
+            auto result = mSubscriptionManager->subscribe(callback, onChangeSubscriptions,
+                                                          /*isContinuousProperty=*/false);
+            if (!result.ok()) {
+                return toScopedAStatus(result);
+            }
         }
         if (!continuousSubscriptions.empty()) {
-            return toScopedAStatus(mSubscriptionManager->subscribe(callback,
-                                                                   continuousSubscriptions,
-                                                                   /*isContinuousProperty=*/true));
+            auto result = mSubscriptionManager->subscribe(callback, continuousSubscriptions,
+                                                          /*isContinuousProperty=*/true);
+            if (!result.ok()) {
+                return toScopedAStatus(result);
+            }
         }
     }
     return ScopedAStatus::ok();
@@ -819,12 +798,15 @@
         dprintf(fd, "Containing %zu property configs\n", mConfigsByPropId.size());
         dprintf(fd, "Currently have %zu getValues clients\n", mGetValuesClients.size());
         dprintf(fd, "Currently have %zu setValues clients\n", mSetValuesClients.size());
-        dprintf(fd, "Currently have %zu subscription clients\n",
-                mSubscriptionClients->countClients());
+        dprintf(fd, "Currently have %zu subscribe clients\n", countSubscribeClients());
     }
     return STATUS_OK;
 }
 
+size_t DefaultVehicleHal::countSubscribeClients() {
+    return mSubscriptionManager->countClients();
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
index bba730f..17683ae 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/SubscriptionManager.cpp
@@ -36,6 +36,7 @@
 using ::aidl::android::hardware::automotive::vehicle::IVehicleCallback;
 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 using ::android::base::Error;
 using ::android::base::Result;
@@ -269,11 +270,42 @@
     return clients;
 }
 
+std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropError>>
+SubscriptionManager::getSubscribedClientsForErrorEvents(
+        const std::vector<SetValueErrorEvent>& errorEvents) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    std::unordered_map<std::shared_ptr<IVehicleCallback>, std::vector<VehiclePropError>> clients;
+
+    for (const auto& errorEvent : errorEvents) {
+        PropIdAreaId propIdAreaId{
+                .propId = errorEvent.propId,
+                .areaId = errorEvent.areaId,
+        };
+        if (mClientsByPropIdArea.find(propIdAreaId) == mClientsByPropIdArea.end()) {
+            continue;
+        }
+
+        for (const auto& [_, client] : mClientsByPropIdArea[propIdAreaId]) {
+            clients[client].push_back({
+                    .propId = errorEvent.propId,
+                    .areaId = errorEvent.areaId,
+                    .errorCode = errorEvent.errorCode,
+            });
+        }
+    }
+    return clients;
+}
+
 bool SubscriptionManager::isEmpty() {
     std::scoped_lock<std::mutex> lockGuard(mLock);
     return mSubscribedPropsByClient.empty() && mClientsByPropIdArea.empty();
 }
 
+size_t SubscriptionManager::countClients() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mSubscribedPropsByClient.size();
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
index 05e569a..fb14373 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/DefaultVehicleHalTest.cpp
@@ -62,6 +62,7 @@
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaWindow;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfigs;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropError;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropErrors;
 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
@@ -349,7 +350,7 @@
     size_t countClients() {
         std::scoped_lock<std::mutex> lockGuard(mVhal->mLock);
         return mVhal->mGetValuesClients.size() + mVhal->mSetValuesClients.size() +
-               mVhal->mSubscriptionClients->countClients();
+               mVhal->countSubscribeClients();
     }
 
     std::shared_ptr<PendingRequestPool> getPool() { return mVhal->mPendingRequestPool; }
@@ -1653,6 +1654,63 @@
     ASSERT_EQ(msg.find("Vehicle HAL State: "), std::string::npos);
 }
 
+TEST_F(DefaultVehicleHalTest, testOnPropertySetErrorEvent) {
+    std::vector<SubscribeOptions> options = {
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+                    .areaIds = {0},
+            },
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .areaIds = {0},
+                    .sampleRate = 1,
+            },
+    };
+    auto status = getClient()->subscribe(getCallbackClient(), options, 0);
+    ASSERT_TRUE(status.isOk()) << "subscribe failed: " << status.getMessage();
+    std::vector<SetValueErrorEvent> errorEvents = {
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::INTERNAL_ERROR,
+            },
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::ACCESS_DENIED,
+            },
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::INVALID_ARG,
+            },
+    };
+    std::vector<VehiclePropError> expectedResults = {
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::INTERNAL_ERROR,
+            },
+            {
+                    .propId = GLOBAL_ON_CHANGE_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::ACCESS_DENIED,
+            },
+            {
+                    .propId = GLOBAL_CONTINUOUS_PROP,
+                    .areaId = 0,
+                    .errorCode = StatusCode::INVALID_ARG,
+            },
+    };
+    getHardware()->sendOnPropertySetErrorEvent(errorEvents);
+
+    ASSERT_EQ(getCallback()->countOnPropertySetErrorResults(), 1u);
+    auto maybeVehiclePropErrors = getCallback()->nextOnPropertySetErrorResults();
+    ASSERT_TRUE(maybeVehiclePropErrors.has_value());
+    const auto& vehiclePropErrors = maybeVehiclePropErrors.value();
+    ASSERT_THAT(vehiclePropErrors.payloads, UnorderedElementsAreArray(expectedResults));
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
index f51ce5c..54fede1 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.cpp
@@ -81,8 +81,14 @@
     return result;
 }
 
-ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors&) {
-    return ScopedAStatus::ok();
+ScopedAStatus MockVehicleCallback::onPropertySetError(const VehiclePropErrors& results) {
+    ScopedAStatus result;
+    {
+        std::scoped_lock<std::mutex> lockGuard(mLock);
+        result = storeResults(results, &mOnPropertySetErrorResults);
+    }
+    mCond.notify_all();
+    return result;
 }
 
 std::optional<GetValueResults> MockVehicleCallback::nextGetValueResults() {
@@ -105,6 +111,16 @@
     return mOnPropertyEventResults.size();
 }
 
+std::optional<VehiclePropErrors> MockVehicleCallback::nextOnPropertySetErrorResults() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return pop(mOnPropertySetErrorResults);
+}
+
+size_t MockVehicleCallback::countOnPropertySetErrorResults() {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    return mOnPropertySetErrorResults.size();
+}
+
 bool MockVehicleCallback::waitForSetValueResults(size_t size, size_t timeoutInNano) {
     std::unique_lock lk(mLock);
     return mCond.wait_for(lk, std::chrono::nanoseconds(timeoutInNano), [this, size] {
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
index f17b273..1545eae 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleCallback.h
@@ -63,6 +63,9 @@
     nextSetValueResults();
     std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropValues>
     nextOnPropertyEventResults();
+    size_t countOnPropertySetErrorResults();
+    std::optional<aidl::android::hardware::automotive::vehicle::VehiclePropErrors>
+    nextOnPropertySetErrorResults();
     size_t countOnPropertyEventResults();
     bool waitForSetValueResults(size_t size, size_t timeoutInNano);
     bool waitForGetValueResults(size_t size, size_t timeoutInNano);
@@ -77,6 +80,8 @@
     std::list<aidl::android::hardware::automotive::vehicle::VehiclePropValues>
             mOnPropertyEventResults GUARDED_BY(mLock);
     int32_t mSharedMemoryFileCount GUARDED_BY(mLock);
+    std::list<aidl::android::hardware::automotive::vehicle::VehiclePropErrors>
+            mOnPropertySetErrorResults GUARDED_BY(mLock);
 };
 
 }  // namespace vehicle
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
index 4df4e1a..ba0d33d 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.cpp
@@ -131,8 +131,9 @@
 }
 
 void MockVehicleHardware::registerOnPropertySetErrorEvent(
-        std::unique_ptr<const PropertySetErrorCallback>) {
-    // TODO(b/200737967): mock this.
+        std::unique_ptr<const PropertySetErrorCallback> callback) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    mPropertySetErrorCallback = std::move(callback);
 }
 
 void MockVehicleHardware::setPropertyConfigs(const std::vector<VehiclePropConfig>& configs) {
@@ -254,6 +255,12 @@
         std::list<std::vector<SetValueRequest>>* storedRequests,
         std::list<std::vector<SetValueResult>>* storedResponses) const;
 
+void MockVehicleHardware::sendOnPropertySetErrorEvent(
+        const std::vector<SetValueErrorEvent>& errorEvents) {
+    std::scoped_lock<std::mutex> lockGuard(mLock);
+    (*mPropertySetErrorCallback)(errorEvents);
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
index 743841c..46b30b9 100644
--- a/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/vhal/test/MockVehicleHardware.h
@@ -85,6 +85,7 @@
                    aidl::android::hardware::automotive::vehicle::StatusCode status);
     void setSleepTime(int64_t timeInNano);
     void setDumpResult(DumpResult result);
+    void sendOnPropertySetErrorEvent(const std::vector<SetValueErrorEvent>& errorEvents);
 
   private:
     mutable std::mutex mLock;
@@ -104,6 +105,7 @@
             mStatusByFunctions GUARDED_BY(mLock);
     int64_t mSleepTime GUARDED_BY(mLock) = 0;
     std::unique_ptr<const PropertyChangeCallback> mPropertyChangeCallback GUARDED_BY(mLock);
+    std::unique_ptr<const PropertySetErrorCallback> mPropertySetErrorCallback GUARDED_BY(mLock);
     std::function<aidl::android::hardware::automotive::vehicle::StatusCode(
             std::shared_ptr<const GetValuesCallback>,
             const std::vector<aidl::android::hardware::automotive::vehicle::GetValueRequest>&)>
diff --git a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
index d9c6de7..28bacb0 100644
--- a/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl_property/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -345,6 +345,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     FUEL_DOOR_OPEN = 0x0308 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -383,6 +384,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     EV_CHARGE_PORT_OPEN = 0x030A + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -476,6 +478,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     ENGINE_IDLE_AUTO_STOP_ENABLED =
             0x0320 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -560,6 +563,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     EV_BRAKE_REGENERATION_LEVEL =
             0x040C + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -648,6 +652,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum EvStoppingMode
      */
     EV_STOPPING_MODE =
@@ -696,8 +701,9 @@
      *     and passenger side, an alternative mapping would be:
      *      - ROW_1_LEFT
      *      - ROW_1_RIGHT
-     *
-     *
+     */
+
+    /**
      * Fan speed setting
      *
      * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined.
@@ -713,6 +719,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     HVAC_FAN_SPEED = 0x0500 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -724,6 +731,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleHvacFanDirection
      */
     HVAC_FAN_DIRECTION = 0x0501 + 0x10000000 + 0x05000000
@@ -763,6 +771,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:CELSIUS
      */
     HVAC_TEMPERATURE_SET = 0x0503 + 0x10000000 + 0x05000000
@@ -775,6 +784,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     HVAC_DEFROSTER = 0x0504 + 0x10000000 + 0x03000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:BOOLEAN
@@ -786,6 +796,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @config_flags Supported areaIds
      */
     HVAC_AC_ON = 0x0505 + 0x10000000 + 0x05000000
@@ -803,6 +814,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     HVAC_MAX_AC_ON = 0x0506 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -825,6 +837,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     HVAC_MAX_DEFROST_ON = 0x0507 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -841,6 +854,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     HVAC_RECIRC_ON = 0x0508 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -879,6 +893,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     HVAC_DUAL_ON = 0x0509 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -900,6 +915,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     HVAC_AUTO_ON = 0x050A + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -921,6 +937,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     HVAC_SEAT_TEMPERATURE = 0x050B + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -943,6 +960,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     HVAC_SIDE_MIRROR_HEAT = 0x050C + 0x10000000 + 0x04000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:MIRROR,VehiclePropertyType:INT32
@@ -965,6 +983,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     HVAC_STEERING_WHEEL_HEAT = 0x050D + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -989,6 +1008,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
      */
     HVAC_TEMPERATURE_DISPLAY_UNITS = 0x050E + 0x10000000 + 0x01000000
@@ -1043,6 +1063,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     HVAC_POWER_ON = 0x0510 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -1077,6 +1098,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     HVAC_AUTO_RECIRC_ON = 0x0512 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -1101,6 +1123,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     HVAC_SEAT_VENTILATION = 0x0513 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -1112,6 +1135,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     HVAC_ELECTRIC_DEFROSTER_ON = 0x0514 + 0x10000000 + 0x03000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:BOOLEAN
@@ -1175,6 +1199,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
      */
     DISTANCE_DISPLAY_UNITS = 0x0600 + 0x10000000 + 0x01000000
@@ -1198,6 +1223,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
      */
     FUEL_VOLUME_DISPLAY_UNITS = 0x0601 + 0x10000000 + 0x01000000
@@ -1222,6 +1248,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
      */
     TIRE_PRESSURE_DISPLAY_UNITS = 0x0602 + 0x10000000 + 0x01000000
@@ -1246,6 +1273,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleUnit
      */
     EV_BATTERY_DISPLAY_UNITS = 0x0603 + 0x10000000 + 0x01000000
@@ -1262,6 +1290,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     FUEL_CONSUMPTION_UNITS_DISTANCE_OVER_VOLUME = 0x0604 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -1284,6 +1313,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     VEHICLE_SPEED_DISPLAY_UNITS = 0x0605 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -1633,6 +1663,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     DOOR_POS = 0x0B00 + 0x10000000 + 0x06000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:DOOR,VehiclePropertyType:INT32
@@ -1657,6 +1688,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     DOOR_MOVE = 0x0B01 + 0x10000000 + 0x06000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:DOOR,VehiclePropertyType:INT32
@@ -1670,6 +1702,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     DOOR_LOCK = 0x0B02 + 0x10000000 + 0x06000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:DOOR,VehiclePropertyType:BOOLEAN
@@ -1685,6 +1718,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     DOOR_CHILD_LOCK_ENABLED =
             0x0B03 + VehiclePropertyGroup.SYSTEM + VehicleArea.DOOR + VehiclePropertyType.BOOLEAN,
@@ -1710,6 +1744,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     MIRROR_Z_POS = 0x0B40 + 0x10000000 + 0x04000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:MIRROR,VehiclePropertyType:INT32
@@ -1735,6 +1770,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     MIRROR_Z_MOVE = 0x0B41 + 0x10000000 + 0x04000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:MIRROR,VehiclePropertyType:INT32
@@ -1760,6 +1796,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     MIRROR_Y_POS = 0x0B42 + 0x10000000 + 0x04000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:MIRROR,VehiclePropertyType:INT32
@@ -1784,6 +1821,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     MIRROR_Y_MOVE = 0x0B43 + 0x10000000 + 0x04000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:MIRROR,VehiclePropertyType:INT32
@@ -1797,6 +1835,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     MIRROR_LOCK = 0x0B44 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -1810,6 +1849,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     MIRROR_FOLD = 0x0B45 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -1826,6 +1866,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
 
     MIRROR_AUTO_FOLD_ENABLED =
@@ -1843,6 +1884,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
 
     MIRROR_AUTO_TILT_ENABLED =
@@ -1891,6 +1933,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_BELT_BUCKLED = 0x0B82 + 0x10000000 + 0x05000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:BOOLEAN
@@ -1915,6 +1958,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_BELT_HEIGHT_POS = 0x0B83 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -1942,6 +1986,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_BELT_HEIGHT_MOVE = 0x0B84 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -1966,6 +2011,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_FORE_AFT_POS = 0x0B85 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -1992,6 +2038,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_FORE_AFT_MOVE = 0x0B86 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2018,6 +2065,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_BACKREST_ANGLE_1_POS = 0x0B87 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2044,6 +2092,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_BACKREST_ANGLE_1_MOVE = 0x0B88 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2072,6 +2121,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_BACKREST_ANGLE_2_POS = 0x0B89 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2098,6 +2148,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_BACKREST_ANGLE_2_MOVE = 0x0B8A + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2120,6 +2171,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_HEIGHT_POS = 0x0B8B + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2144,6 +2196,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_HEIGHT_MOVE = 0x0B8C + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2171,6 +2224,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_DEPTH_POS = 0x0B8D + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2196,6 +2250,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_DEPTH_MOVE = 0x0B8E + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2222,6 +2277,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_TILT_POS = 0x0B8F + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2248,6 +2304,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_TILT_MOVE = 0x0B90 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2272,6 +2329,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_LUMBAR_FORE_AFT_POS = 0x0B91 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2299,6 +2357,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_LUMBAR_FORE_AFT_MOVE = 0x0B92 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2323,6 +2382,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_LUMBAR_SIDE_SUPPORT_POS = 0x0B93 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2350,6 +2410,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_LUMBAR_SIDE_SUPPORT_MOVE = 0x0B94 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2369,6 +2430,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_HEADREST_HEIGHT_POS = 0x0B95 + 0x10000000 + 0x01000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:INT32
@@ -2395,6 +2457,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_HEADREST_HEIGHT_POS_V2 =
             0x0BA4 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2423,6 +2486,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_HEADREST_HEIGHT_MOVE = 0x0B96 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2445,6 +2509,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_HEADREST_ANGLE_POS = 0x0B97 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2472,6 +2537,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_HEADREST_ANGLE_MOVE = 0x0B98 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2494,6 +2560,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_HEADREST_FORE_AFT_POS = 0x0B99 + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2521,6 +2588,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_HEADREST_FORE_AFT_MOVE = 0x0B9A + 0x10000000 + 0x05000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:SEAT,VehiclePropertyType:INT32
@@ -2565,6 +2633,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
      */
     SEAT_FOOTWELL_LIGHTS_SWITCH =
@@ -2581,6 +2650,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_EASY_ACCESS_ENABLED =
             0x0B9D + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
@@ -2600,6 +2670,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_AIRBAG_ENABLED =
             0x0B9E + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
@@ -2624,6 +2695,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_CUSHION_SIDE_SUPPORT_POS =
             0x0B9F + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2651,6 +2723,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_CUSHION_SIDE_SUPPORT_MOVE =
             0x0BA0 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2673,6 +2746,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_LUMBAR_VERTICAL_POS =
             0x0BA1 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2698,6 +2772,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_LUMBAR_VERTICAL_MOVE =
             0x0BA2 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2723,6 +2798,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     SEAT_WALK_IN_POS =
             0x0BA3 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -2770,6 +2846,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     WINDOW_POS = 0x0BC0 + 0x10000000 + 0x03000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
@@ -2811,6 +2888,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     WINDOW_MOVE = 0x0BC1 + 0x10000000 + 0x03000000
             + 0x00400000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:INT32
@@ -2824,6 +2902,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     WINDOW_LOCK = 0x0BC4 + 0x10000000 + 0x03000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WINDOW,VehiclePropertyType:BOOLEAN
@@ -2889,6 +2968,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum WindshieldWipersSwitch
      */
     WINDSHIELD_WIPERS_SWITCH =
@@ -2915,6 +2995,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     STEERING_WHEEL_DEPTH_POS =
             0x0BE0 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -2940,6 +3021,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     STEERING_WHEEL_DEPTH_MOVE =
             0x0BE1 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -2962,6 +3044,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     STEERING_WHEEL_HEIGHT_POS =
             0x0BE2 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -2987,6 +3070,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     STEERING_WHEEL_HEIGHT_MOVE =
             0x0BE3 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.INT32,
@@ -3001,6 +3085,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     STEERING_WHEEL_THEFT_LOCK_ENABLED =
             0x0BE4 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -3014,6 +3099,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     STEERING_WHEEL_LOCKED =
             0x0BE5 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -3028,6 +3114,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     STEERING_WHEEL_EASY_ACCESS_ENABLED =
             0x0BE6 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -3054,6 +3141,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     GLOVE_BOX_DOOR_POS =
             0x0BF0 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
@@ -3072,6 +3160,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     GLOVE_BOX_LOCKED =
             0x0BF1 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.BOOLEAN,
@@ -3291,6 +3380,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
      */
     HEADLIGHTS_SWITCH = 0x0E10 + 0x10000000 + 0x01000000
@@ -3305,6 +3395,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
      */
     HIGH_BEAM_LIGHTS_SWITCH = 0x0E11 + 0x10000000 + 0x01000000
@@ -3335,6 +3426,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
      */
     FOG_LIGHTS_SWITCH = 0x0E12 + 0x10000000 + 0x01000000
@@ -3349,6 +3441,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
      */
     HAZARD_LIGHTS_SWITCH = 0x0E13 + 0x10000000 + 0x01000000
@@ -3377,6 +3470,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
      */
     CABIN_LIGHTS_SWITCH = 0x0F02 + 0x10000000 + 0x01000000
@@ -3405,6 +3499,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
      */
     READING_LIGHTS_SWITCH = 0x0F04 + 0x10000000 + 0x05000000
@@ -3450,6 +3545,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
      */
     STEERING_WHEEL_LIGHTS_SWITCH =
@@ -4119,6 +4215,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
      */
     FRONT_FOG_LIGHTS_SWITCH = 0x0F3C + 0x10000000 + 0x01000000
@@ -4150,6 +4247,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum VehicleLightSwitch
      */
     REAR_FOG_LIGHTS_SWITCH = 0x0F3E + 0x10000000 + 0x01000000
@@ -4166,6 +4264,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:AMPERE
      */
     EV_CHARGE_CURRENT_DRAW_LIMIT = 0x0F3F + 0x10000000 + 0x01000000
@@ -4187,6 +4286,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     EV_CHARGE_PERCENT_LIMIT = 0x0F40 + 0x10000000 + 0x01000000
             + 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:FLOAT
@@ -4214,6 +4314,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     EV_CHARGE_SWITCH = 0x0F42 + 0x10000000 + 0x01000000
             + 0x00200000, // VehiclePropertyGroup:SYSTEM,VehicleArea:GLOBAL,VehiclePropertyType:BOOLEAN
@@ -4377,6 +4478,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     VEHICLE_IN_USE =
             0x0F4A + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4403,6 +4505,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     AUTOMATIC_EMERGENCY_BRAKING_ENABLED =
             0x1000 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4445,6 +4548,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     FORWARD_COLLISION_WARNING_ENABLED =
             0x1002 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4484,6 +4588,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     BLIND_SPOT_WARNING_ENABLED =
             0x1004 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4524,6 +4629,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     LANE_DEPARTURE_WARNING_ENABLED =
             0x1006 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4568,6 +4674,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     LANE_KEEP_ASSIST_ENABLED =
             0x1008 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4616,6 +4723,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     LANE_CENTERING_ASSIST_ENABLED =
             0x100A + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4690,6 +4798,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     EMERGENCY_LANE_KEEP_ASSIST_ENABLED =
             0x100D + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4733,6 +4842,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     CRUISE_CONTROL_ENABLED =
             0x100F + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
@@ -4758,6 +4868,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @data_enum CruiseControlType
      * @data_enum ErrorState
      */
@@ -4855,6 +4966,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      * @unit VehicleUnit:MILLI_SECS
      */
     ADAPTIVE_CRUISE_CONTROL_TARGET_TIME_GAP =
@@ -4906,6 +5018,7 @@
      *
      * @change_mode VehiclePropertyChangeMode.ON_CHANGE
      * @access VehiclePropertyAccess.READ_WRITE
+     * @access VehiclePropertyAccess.READ
      */
     HANDS_ON_DETECTION_ENABLED =
             0x1016 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
diff --git a/automotive/vehicle/tools/generate_annotation_enums.py b/automotive/vehicle/tools/generate_annotation_enums.py
index cfae607..7276fe6 100755
--- a/automotive/vehicle/tools/generate_annotation_enums.py
+++ b/automotive/vehicle/tools/generate_annotation_enums.py
@@ -189,11 +189,12 @@
                     continue
                 if RE_COMMENT_BEGIN.match(line):
                     in_comment = True
+                    annotation = None
                 if RE_COMMENT_END.match(line):
                     in_comment = False
                 if in_comment:
                     match = self.annotation_re.match(line)
-                    if match:
+                    if match and not annotation:
                         annotation = match.group(1)
                 else:
                     match = RE_VALUE.match(line)
diff --git a/bluetooth/audio/OWNERS b/bluetooth/audio/OWNERS
index a8e9bda..f3657ca 100644
--- a/bluetooth/audio/OWNERS
+++ b/bluetooth/audio/OWNERS
@@ -1,4 +1,6 @@
+# Bug component: 27441
+
 include platform/packages/modules/Bluetooth:/OWNERS
 
-cheneyni@google.com
 aliceypkuo@google.com
+quocbaodo@google.com
diff --git a/bluetooth/audio/aidl/vts/Android.bp b/bluetooth/audio/aidl/vts/Android.bp
index e03fb58..3e6953f 100644
--- a/bluetooth/audio/aidl/vts/Android.bp
+++ b/bluetooth/audio/aidl/vts/Android.bp
@@ -15,16 +15,20 @@
     ],
     tidy_timeout_srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
     srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
-    shared_libs: [
+    static_libs: [
         "android.hardware.audio.common-V1-ndk",
         "android.hardware.bluetooth.audio-V3-ndk",
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
+        "android.media.audio.common.types-V2-ndk",
+    ],
+    shared_libs: [
         "libbase",
         "libbinder_ndk",
         "libcutils",
         "libfmq",
     ],
+    test_config: "VtsHalBluetoothAudioTargetTest.xml",
     test_suites: [
         "general-tests",
         "vts",
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.xml b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.xml
new file mode 100644
index 0000000..7b02685
--- /dev/null
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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.
+-->
+<configuration description="Runs VtsHalBluetoothAudioTargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController">
+        <!-- Skips test module if ro.product.first_api_level < 33. -->
+        <option name="min-api-level" value="33" />
+    </object>
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalBluetoothAudioTargetTest->/data/local/tmp/VtsHalBluetoothAudioTargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalBluetoothAudioTargetTest" />
+    </test>
+</configuration>
diff --git a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
index 356673f..8bee1b2 100644
--- a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
+++ b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
@@ -32,11 +32,11 @@
 #include <aidl/Gtest.h>
 #include <aidl/Vintf.h>
 #include <broadcastradio-utils-aidl/Utils.h>
-#include <broadcastradio-vts-utils/mock-timeout.h>
 #include <cutils/bitops.h>
 #include <gmock/gmock.h>
 
 #include <chrono>
+#include <condition_variable>
 #include <optional>
 #include <regex>
 
@@ -61,11 +61,6 @@
 
 namespace bcutils = ::aidl::android::hardware::broadcastradio::utils;
 
-inline constexpr std::chrono::seconds kTuneTimeoutSec =
-        std::chrono::seconds(IBroadcastRadio::TUNER_TIMEOUT_MS * 1000);
-inline constexpr std::chrono::seconds kProgramListScanTimeoutSec =
-        std::chrono::seconds(IBroadcastRadio::LIST_COMPLETE_TIMEOUT_MS * 1000);
-
 const ConfigFlag kConfigFlagValues[] = {
         ConfigFlag::FORCE_MONO,
         ConfigFlag::FORCE_ANALOG,
@@ -108,20 +103,68 @@
 
 }  // namespace
 
-class TunerCallbackMock : public BnTunerCallback {
+class CallbackFlag final {
   public:
-    TunerCallbackMock();
+    CallbackFlag(int timeoutMs) { mTimeoutMs = timeoutMs; }
+    /**
+     * Notify that the callback is called.
+     */
+    void notify() {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mCalled = true;
+        lock.unlock();
+        mCv.notify_all();
+    };
+
+    /**
+     * Wait for the timeout passed into the constructor.
+     */
+    bool wait() {
+        std::unique_lock<std::mutex> lock(mMutex);
+        return mCv.wait_for(lock, std::chrono::milliseconds(mTimeoutMs),
+                            [this] { return mCalled; });
+    };
+
+    /**
+     * Reset the callback to not called.
+     */
+    void reset() {
+        std::unique_lock<std::mutex> lock(mMutex);
+        mCalled = false;
+    }
+
+  private:
+    std::mutex mMutex;
+    bool mCalled GUARDED_BY(mMutex) = false;
+    std::condition_variable mCv;
+    int mTimeoutMs;
+};
+
+class TunerCallbackImpl final : public BnTunerCallback {
+  public:
+    TunerCallbackImpl();
     ScopedAStatus onTuneFailed(Result result, const ProgramSelector& selector) override;
-    MOCK_TIMEOUT_METHOD1(onCurrentProgramInfoChangedMock, ScopedAStatus(const ProgramInfo&));
     ScopedAStatus onCurrentProgramInfoChanged(const ProgramInfo& info) override;
     ScopedAStatus onProgramListUpdated(const ProgramListChunk& chunk) override;
-    MOCK_METHOD1(onAntennaStateChange, ScopedAStatus(bool connected));
-    MOCK_METHOD1(onParametersUpdated, ScopedAStatus(const vector<VendorKeyValue>& parameters));
-    MOCK_METHOD2(onConfigFlagUpdated, ScopedAStatus(ConfigFlag in_flag, bool in_value));
-    MOCK_TIMEOUT_METHOD0(onProgramListReady, void());
+    ScopedAStatus onParametersUpdated(const vector<VendorKeyValue>& parameters) override;
+    ScopedAStatus onAntennaStateChange(bool connected) override;
+    ScopedAStatus onConfigFlagUpdated(ConfigFlag in_flag, bool in_value) override;
 
+    bool waitOnCurrentProgramInfoChangedCallback();
+    bool waitProgramReady();
+    void reset();
+
+    bool getAntennaConnectionState();
+    ProgramInfo getCurrentProgramInfo();
+    bcutils::ProgramInfoSet getProgramList();
+
+  private:
     std::mutex mLock;
+    bool mAntennaConnectionState GUARDED_BY(mLock);
+    ProgramInfo mCurrentProgramInfo GUARDED_BY(mLock);
     bcutils::ProgramInfoSet mProgramList GUARDED_BY(mLock);
+    CallbackFlag mOnCurrentProgramInfoChangedFlag = CallbackFlag(IBroadcastRadio::TUNER_TIMEOUT_MS);
+    CallbackFlag mOnProgramListReadyFlag = CallbackFlag(IBroadcastRadio::LIST_COMPLETE_TIMEOUT_MS);
 };
 
 struct AnnouncementListenerMock : public BnAnnouncementListener {
@@ -139,7 +182,7 @@
 
     std::shared_ptr<IBroadcastRadio> mModule;
     Properties mProperties;
-    std::shared_ptr<TunerCallbackMock> mCallback = SharedRefBase::make<TunerCallbackMock>();
+    std::shared_ptr<TunerCallbackImpl> mCallback;
 };
 
 MATCHER_P(InfoHasId, id, string(negation ? "does not contain" : "contains") + " " + id.toString()) {
@@ -147,20 +190,18 @@
     return ids.end() != find(ids.begin(), ids.end(), id.value);
 }
 
-TunerCallbackMock::TunerCallbackMock() {
-    EXPECT_TIMEOUT_CALL(*this, onCurrentProgramInfoChangedMock, _).Times(AnyNumber());
-
-    // we expect the antenna is connected through the whole test
-    EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0);
+TunerCallbackImpl::TunerCallbackImpl() {
+    mAntennaConnectionState = true;
 }
 
-ScopedAStatus TunerCallbackMock::onTuneFailed(Result result, const ProgramSelector& selector) {
+ScopedAStatus TunerCallbackImpl::onTuneFailed(Result result, const ProgramSelector& selector) {
     LOG(DEBUG) << "Tune failed for selector" << selector.toString();
     EXPECT_TRUE(result == Result::CANCELED);
     return ndk::ScopedAStatus::ok();
 }
 
-ScopedAStatus TunerCallbackMock::onCurrentProgramInfoChanged(const ProgramInfo& info) {
+ScopedAStatus TunerCallbackImpl::onCurrentProgramInfoChanged(const ProgramInfo& info) {
+    LOG(DEBUG) << "onCurrentProgramInfoChanged called";
     for (const auto& id : info.selector) {
         EXPECT_NE(id.type, IdentifierType::INVALID);
     }
@@ -196,21 +237,75 @@
         }
     }
 
-    return onCurrentProgramInfoChangedMock(info);
+    {
+        std::lock_guard<std::mutex> lk(mLock);
+        mCurrentProgramInfo = info;
+    }
+
+    mOnCurrentProgramInfoChangedFlag.notify();
+    return ndk::ScopedAStatus::ok();
 }
 
-ScopedAStatus TunerCallbackMock::onProgramListUpdated(const ProgramListChunk& chunk) {
-    std::lock_guard<std::mutex> lk(mLock);
-
-    updateProgramList(chunk, &mProgramList);
+ScopedAStatus TunerCallbackImpl::onProgramListUpdated(const ProgramListChunk& chunk) {
+    LOG(DEBUG) << "onProgramListUpdated called";
+    {
+        std::lock_guard<std::mutex> lk(mLock);
+        updateProgramList(chunk, &mProgramList);
+    }
 
     if (chunk.complete) {
-        onProgramListReady();
+        mOnProgramListReadyFlag.notify();
     }
 
     return ndk::ScopedAStatus::ok();
 }
 
+ScopedAStatus TunerCallbackImpl::onParametersUpdated(
+        [[maybe_unused]] const vector<VendorKeyValue>& parameters) {
+    return ndk::ScopedAStatus::ok();
+}
+
+ScopedAStatus TunerCallbackImpl::onAntennaStateChange(bool connected) {
+    if (!connected) {
+        std::lock_guard<std::mutex> lk(mLock);
+        mAntennaConnectionState = false;
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ScopedAStatus TunerCallbackImpl::onConfigFlagUpdated([[maybe_unused]] ConfigFlag in_flag,
+                                                     [[maybe_unused]] bool in_value) {
+    return ndk::ScopedAStatus::ok();
+}
+
+bool TunerCallbackImpl::waitOnCurrentProgramInfoChangedCallback() {
+    return mOnCurrentProgramInfoChangedFlag.wait();
+}
+
+bool TunerCallbackImpl::waitProgramReady() {
+    return mOnProgramListReadyFlag.wait();
+}
+
+void TunerCallbackImpl::reset() {
+    mOnCurrentProgramInfoChangedFlag.reset();
+    mOnProgramListReadyFlag.reset();
+}
+
+bool TunerCallbackImpl::getAntennaConnectionState() {
+    std::lock_guard<std::mutex> lk(mLock);
+    return mAntennaConnectionState;
+}
+
+ProgramInfo TunerCallbackImpl::getCurrentProgramInfo() {
+    std::lock_guard<std::mutex> lk(mLock);
+    return mCurrentProgramInfo;
+}
+
+bcutils::ProgramInfoSet TunerCallbackImpl::getProgramList() {
+    std::lock_guard<std::mutex> lk(mLock);
+    return mProgramList;
+}
+
 void BroadcastRadioHalTest::SetUp() {
     EXPECT_EQ(mModule.get(), nullptr) << "Module is already open";
 
@@ -228,6 +323,8 @@
     EXPECT_FALSE(mProperties.product.empty());
     EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u);
 
+    mCallback = SharedRefBase::make<TunerCallbackImpl>();
+
     // set callback
     EXPECT_TRUE(mModule->setTunerCallback(mCallback).isOk());
 }
@@ -236,6 +333,11 @@
     if (mModule) {
         ASSERT_TRUE(mModule->unsetTunerCallback().isOk());
     }
+    if (mCallback) {
+        // we expect the antenna is connected through the whole test
+        EXPECT_TRUE(mCallback->getAntennaConnectionState());
+        mCallback = nullptr;
+    }
 }
 
 bool BroadcastRadioHalTest::getAmFmRegionConfig(bool full, AmFmRegionConfig* config) {
@@ -256,7 +358,7 @@
 
 std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList(
         const ProgramFilter& filter) {
-    EXPECT_TIMEOUT_CALL(*mCallback, onProgramListReady).Times(AnyNumber());
+    mCallback->reset();
 
     auto startResult = mModule->startProgramListUpdates(filter);
 
@@ -268,13 +370,13 @@
     if (!startResult.isOk()) {
         return std::nullopt;
     }
-    EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onProgramListReady, kProgramListScanTimeoutSec);
+    EXPECT_TRUE(mCallback->waitProgramReady());
 
     auto stopResult = mModule->stopProgramListUpdates();
 
     EXPECT_TRUE(stopResult.isOk());
 
-    return mCallback->mProgramList;
+    return mCallback->getProgramList();
 }
 
 /**
@@ -456,7 +558,7 @@
  *  - if it is supported, the test is ignored;
  */
 TEST_P(BroadcastRadioHalTest, TuneFailsWithNotSupported) {
-    LOG(DEBUG) << "TuneFailsWithInvalid Test";
+    LOG(DEBUG) << "TuneFailsWithNotSupported Test";
 
     vector<ProgramIdentifier> supportTestId = {
             makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 0),           // invalid
@@ -477,9 +579,9 @@
     for (const auto& id : supportTestId) {
         ProgramSelector sel{id, {}};
 
-        auto result = mModule->tune(sel);
-
         if (!bcutils::isSupported(mProperties, sel)) {
+            auto result = mModule->tune(sel);
+
             EXPECT_EQ(result.getServiceSpecificError(), notSupportedError);
         }
     }
@@ -508,9 +610,9 @@
     for (const auto& id : invalidId) {
         ProgramSelector sel{id, {}};
 
-        auto result = mModule->tune(sel);
-
         if (bcutils::isSupported(mProperties, sel)) {
+            auto result = mModule->tune(sel);
+
             EXPECT_EQ(result.getServiceSpecificError(), invalidArgumentsError);
         }
     }
@@ -549,13 +651,7 @@
     int64_t freq = 90900;  // 90.9 FM
     ProgramSelector sel = makeSelectorAmfm(freq);
     // try tuning
-    ProgramInfo infoCb = {};
-    EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock,
-                        InfoHasId(makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, freq)))
-            .Times(AnyNumber())
-            .WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(ndk::ScopedAStatus::ok()))))
-            .WillRepeatedly(testing::InvokeWithoutArgs([] { return ndk::ScopedAStatus::ok(); }));
-
+    mCallback->reset();
     auto result = mModule->tune(sel);
 
     // expect a failure if it's not supported
@@ -566,7 +662,8 @@
 
     // expect a callback if it succeeds
     EXPECT_TRUE(result.isOk());
-    EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
+    EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
+    ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
 
     LOG(DEBUG) << "Current program info: " << infoCb.toString();
 
@@ -638,12 +735,6 @@
     }
 
     // try tuning
-    ProgramInfo infoCb = {};
-    EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock,
-                        InfoHasId(makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, freq)))
-            .Times(AnyNumber())
-            .WillOnce(
-                    DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(ndk::ScopedAStatus::ok()))));
 
     auto result = mModule->tune(sel);
 
@@ -655,7 +746,9 @@
 
     // expect a callback if it succeeds
     EXPECT_TRUE(result.isOk());
-    EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
+    EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
+    ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
+
     LOG(DEBUG) << "Current program info: " << infoCb.toString();
 
     // it should tune exactly to what was requested
@@ -669,13 +762,13 @@
  *
  * Verifies that:
  *  - the method succeeds;
- *  - the program info is changed within kTuneTimeoutSec;
+ *  - the program info is changed within kTuneTimeoutMs;
  *  - works both directions and with or without skipping sub-channel.
  */
 TEST_P(BroadcastRadioHalTest, Seek) {
     LOG(DEBUG) << "Seek Test";
 
-    EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber());
+    mCallback->reset();
 
     auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
 
@@ -685,14 +778,14 @@
     }
 
     EXPECT_TRUE(result.isOk());
-    EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
+    EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
 
-    EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber());
+    mCallback->reset();
 
     result = mModule->seek(/* in_directionUp= */ false, /* in_skipSubChannel= */ false);
 
     EXPECT_TRUE(result.isOk());
-    EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
+    EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
 }
 
 /**
@@ -720,13 +813,13 @@
  *
  * Verifies that:
  *  - the method succeeds or returns NOT_SUPPORTED;
- *  - the program info is changed within kTuneTimeoutSec if the method succeeded;
+ *  - the program info is changed within kTuneTimeoutMs if the method succeeded;
  *  - works both directions.
  */
 TEST_P(BroadcastRadioHalTest, Step) {
     LOG(DEBUG) << "Step Test";
 
-    EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber());
+    mCallback->reset();
 
     auto result = mModule->step(/* in_directionUp= */ true);
 
@@ -735,14 +828,14 @@
         return;
     }
     EXPECT_TRUE(result.isOk());
-    EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
+    EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
 
-    EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber());
+    mCallback->reset();
 
     result = mModule->step(/* in_directionUp= */ false);
 
     EXPECT_TRUE(result.isOk());
-    EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
+    EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
 }
 
 /**
@@ -955,7 +1048,7 @@
  *
  * Verifies that:
  * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
- * - the complete list is fetched within kProgramListScanTimeoutSec;
+ * - the complete list is fetched within kProgramListScanTimeoutMs;
  * - stopProgramListUpdates does not crash.
  */
 TEST_P(BroadcastRadioHalTest, GetProgramListFromEmptyFilter) {
@@ -969,7 +1062,7 @@
  *
  * Verifies that:
  * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
- * - the complete list is fetched within kProgramListScanTimeoutSec;
+ * - the complete list is fetched within kProgramListScanTimeoutMs;
  * - stopProgramListUpdates does not crash;
  * - result for startProgramListUpdates using a filter with AMFM_FREQUENCY_KHZ value of the first
  *   AMFM program matches the expected result.
@@ -1017,7 +1110,7 @@
  *
  * Verifies that:
  * - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
- * - the complete list is fetched within kProgramListScanTimeoutSec;
+ * - the complete list is fetched within kProgramListScanTimeoutMs;
  * - stopProgramListUpdates does not crash;
  * - result for startProgramListUpdates using a filter with DAB_ENSEMBLE value of the first DAB
  *   program matches the expected result.
diff --git a/compatibility_matrices/bump.py b/compatibility_matrices/bump.py
new file mode 100755
index 0000000..88b7a42
--- /dev/null
+++ b/compatibility_matrices/bump.py
@@ -0,0 +1,158 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 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.
+#
+"""
+Creates the next compatibility matrix.
+
+Requires libvintf Level.h to be updated before executing this script.
+"""
+
+import argparse
+import os
+import pathlib
+import shutil
+import subprocess
+import textwrap
+
+
+def check_call(*args, **kwargs):
+    print(args)
+    subprocess.check_call(*args, **kwargs)
+
+
+def check_output(*args, **kwargs):
+    print(args)
+    return subprocess.check_output(*args, **kwargs)
+
+
+class Bump(object):
+
+    def __init__(self, cmdline_args):
+        self.top = pathlib.Path(os.environ["ANDROID_BUILD_TOP"])
+        self.interfaces_dir = self.top / "hardware/interfaces"
+
+        self.current_level = cmdline_args.current
+        self.current_module_name = f"framework_compatibility_matrix.{self.current_level}.xml"
+        self.current_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.current_level}.xml"
+
+        self.next_level = cmdline_args.next
+        self.next_module_name = f"framework_compatibility_matrix.{self.next_level}.xml"
+        self.next_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.next_level}.xml"
+
+        self.level_to_letter = self.get_level_to_letter_mapping()
+        print("Found level mapping in libvintf Level.h:", self.level_to_letter)
+
+    def run(self):
+        self.bump_kernel_configs()
+        self.copy_matrix()
+        self.edit_android_bp()
+        self.edit_android_mk()
+
+    def get_level_to_letter_mapping(self):
+        levels_file = self.top / "system/libvintf/include/vintf/Level.h"
+        with open(levels_file) as f:
+            lines = f.readlines()
+            pairs = [
+                line.split("=", maxsplit=2) for line in lines if "=" in line
+            ]
+            return {
+                level.strip().removesuffix(","): letter.strip()
+                for letter, level in pairs
+            }
+
+    def bump_kernel_configs(self):
+        check_call([
+            self.top / "kernel/configs/tools/bump.py",
+            self.level_to_letter[self.current_level].lower(),
+            self.level_to_letter[self.next_level].lower(),
+        ])
+
+    def copy_matrix(self):
+        shutil.copyfile(self.current_xml, self.next_xml)
+
+    def edit_android_bp(self):
+        android_bp = self.interfaces_dir / "compatibility_matrices/Android.bp"
+
+        with open(android_bp, "r+") as f:
+            if self.next_module_name not in f.read():
+                f.seek(0, 2)  # end of file
+                f.write("\n")
+                f.write(
+                    textwrap.dedent(f"""\
+                        vintf_compatibility_matrix {{
+                            name: "{self.next_module_name}",
+                        }}
+                    """))
+
+        next_kernel_configs = check_output(
+            """grep -rh name: | sed -E 's/^.*"(.*)".*/\\1/g'""",
+            cwd=self.top / "kernel/configs" /
+            self.level_to_letter[self.next_level].lower(),
+            text=True,
+            shell=True,
+        ).splitlines()
+        print(next_kernel_configs)
+
+        check_call([
+            "bpmodify", "-w", "-m", self.next_module_name, "-property", "stem",
+            "-str", self.next_xml.name, android_bp
+        ])
+
+        check_call([
+            "bpmodify", "-w", "-m", self.next_module_name, "-property", "srcs",
+            "-a",
+            self.next_xml.relative_to(android_bp.parent), android_bp
+        ])
+
+        check_call([
+            "bpmodify", "-w", "-m", self.next_module_name, "-property",
+            "kernel_configs", "-a", " ".join(next_kernel_configs), android_bp
+        ])
+
+    def edit_android_mk(self):
+        android_mk = self.interfaces_dir / "compatibility_matrices/Android.mk"
+        with open(android_mk) as f:
+            if self.next_module_name in f.read():
+                return
+            f.seek(0)
+            lines = f.readlines()
+        current_module_line_number = None
+        for line_number, line in enumerate(lines):
+            if self.current_module_name in line:
+                current_module_line_number = line_number
+                break
+        assert current_module_line_number is not None
+        lines.insert(current_module_line_number + 1,
+                     f"    {self.next_module_name} \\\n")
+        with open(android_mk, "w") as f:
+            f.write("".join(lines))
+
+
+def main():
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument("current",
+                        type=str,
+                        help="VINTF level of the current version (e.g. 9)")
+    parser.add_argument("next",
+                        type=str,
+                        help="VINTF level of the next version (e.g. 10)")
+    cmdline_args = parser.parse_args()
+
+    Bump(cmdline_args).run()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/compatibility_matrices/compatibility_matrix.8.xml b/compatibility_matrices/compatibility_matrix.8.xml
index c04a499..4aa832b 100644
--- a/compatibility_matrices/compatibility_matrix.8.xml
+++ b/compatibility_matrices/compatibility_matrix.8.xml
@@ -114,7 +114,7 @@
             <instance>default</instance>
         </interface>
     </hal>
-    <hal format="aidl" optional="true">
+    <hal format="aidl" optional="true" updatable-via-apex="true">
         <name>android.hardware.biometrics.face</name>
         <version>3</version>
         <interface>
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
index a4e19a8..14b9210 100644
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ b/compatibility_matrices/compatibility_matrix.9.xml
@@ -185,7 +185,7 @@
     </hal>
     <hal format="aidl" optional="true">
         <name>android.hardware.contexthub</name>
-        <version>2</version>
+        <version>3</version>
         <interface>
             <name>IContextHub</name>
             <instance>default</instance>
diff --git a/contexthub/aidl/Android.bp b/contexthub/aidl/Android.bp
index a0315d0..cf10529 100644
--- a/contexthub/aidl/Android.bp
+++ b/contexthub/aidl/Android.bp
@@ -49,6 +49,6 @@
         },
 
     ],
-    frozen: true,
+    frozen: false,
 
 }
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
index 6163cfc..d0099ff 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
@@ -39,5 +39,6 @@
   void handleContextHubAsyncEvent(in android.hardware.contexthub.AsyncEventType evt);
   void handleTransactionResult(in int transactionId, in boolean success);
   void handleNanSessionRequest(in android.hardware.contexthub.NanSessionRequest request);
+  byte[16] getUuid();
   const int CONTEXTHUB_NAN_TRANSACTION_TIMEOUT_MS = 10000;
 }
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
index bfcb51e..41fb266 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
@@ -91,6 +91,14 @@
     void handleNanSessionRequest(in NanSessionRequest request);
 
     /**
+     * This callback is passed to the HAL implementation to allow the HAL to request a UUID that
+     * uniquely identifies an IContextHubCallback.
+     *
+     * @return a byte array representating the UUID
+     */
+    byte[16] getUuid();
+
+    /**
      * Amount of time, in milliseconds, that a handleNanSessionRequest can be pending before the
      * Contexthub service must respond.
      */
diff --git a/contexthub/aidl/default/Android.bp b/contexthub/aidl/default/Android.bp
index 6ee7407..74bac69 100644
--- a/contexthub/aidl/default/Android.bp
+++ b/contexthub/aidl/default/Android.bp
@@ -29,7 +29,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.contexthub-V2-ndk",
+        "android.hardware.contexthub-V3-ndk",
     ],
     export_include_dirs: ["include"],
     srcs: [
@@ -50,7 +50,7 @@
     shared_libs: [
         "libbase",
         "libbinder_ndk",
-        "android.hardware.contexthub-V2-ndk",
+        "android.hardware.contexthub-V3-ndk",
     ],
     static_libs: [
         "libcontexthubexampleimpl",
diff --git a/contexthub/aidl/default/contexthub-default.xml b/contexthub/aidl/default/contexthub-default.xml
index 930f672..2f8ddc8 100644
--- a/contexthub/aidl/default/contexthub-default.xml
+++ b/contexthub/aidl/default/contexthub-default.xml
@@ -1,7 +1,7 @@
 <manifest version="1.0" type="device">
     <hal format="aidl">
         <name>android.hardware.contexthub</name>
-        <version>2</version>
+        <version>3</version>
         <interface>
             <name>IContextHub</name>
             <instance>default</instance>
diff --git a/contexthub/aidl/vts/Android.bp b/contexthub/aidl/vts/Android.bp
index 1534b40..b166baf 100644
--- a/contexthub/aidl/vts/Android.bp
+++ b/contexthub/aidl/vts/Android.bp
@@ -32,7 +32,7 @@
         "libbinder",
     ],
     static_libs: [
-        "android.hardware.contexthub-V2-cpp",
+        "android.hardware.contexthub-V3-cpp",
         "VtsHalContexthubUtils",
     ],
     test_suites: [
diff --git a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
index c1cc07c..e780857 100644
--- a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
+++ b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
@@ -48,6 +48,10 @@
 using ::android::hardware::contexthub::vts_utils::kNonExistentAppId;
 using ::android::hardware::contexthub::vts_utils::waitForCallback;
 
+// 6612b522-b717-41c8-b48d-c0b1cc64e142
+const std::array<uint8_t, 16> kUuid = {0x66, 0x12, 0xb5, 0x22, 0xb7, 0x17, 0x41, 0xc8,
+                                       0xb4, 0x8d, 0xc0, 0xb1, 0xcc, 0x64, 0xe1, 0x42};
+
 class ContextHubAidl : public testing::TestWithParam<std::tuple<std::string, int32_t>> {
   public:
     virtual void SetUp() override {
@@ -126,6 +130,11 @@
     Status handleNanSessionRequest(const NanSessionRequest& /* request */) override {
         return Status::ok();
     }
+
+    Status getUuid(std::array<uint8_t, 16>* out_uuid) override {
+        *out_uuid = kUuid;
+        return Status::ok();
+    }
 };
 
 TEST_P(ContextHubAidl, TestRegisterCallback) {
@@ -157,6 +166,11 @@
         return Status::ok();
     }
 
+    Status getUuid(std::array<uint8_t, 16>* out_uuid) override {
+        *out_uuid = kUuid;
+        return Status::ok();
+    }
+
     std::promise<std::vector<NanoappInfo>> promise;
 };
 
@@ -223,6 +237,11 @@
         return Status::ok();
     }
 
+    Status getUuid(std::array<uint8_t, 16>* out_uuid) override {
+        *out_uuid = kUuid;
+        return Status::ok();
+    }
+
     uint32_t expectedTransactionId = 0;
     std::promise<bool> promise;
 };
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
index 50aa2b7..7194ebe 100644
--- a/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
@@ -23,7 +23,14 @@
 @VintfStability
 parcelable BufferDescriptorInfo {
     /**
-     * The name of the buffer in ASCII. Useful for debugging/tracing.
+     * The name of the buffer in null-terminated ASCII. Useful for debugging/tracing.
+     *
+     * NOTE: While a well behaved client will ensure it passes a null-terminated string
+     *       within the 128-byte limit, the IAllocator service implementation should be
+     *       be defensive against malformed input. As such, it is recommended that
+     *       IAllocator implementations proactively do `name[127] = 0` upon receiving
+     *       an allocation request to enusre that the string is definitely
+     *       null-terminated regardless of what the client sent.
      */
     byte[128] name;
 
diff --git a/health/aidl/default/Health.cpp b/health/aidl/default/Health.cpp
index acdd336..4ad8f50 100644
--- a/health/aidl/default/Health.cpp
+++ b/health/aidl/default/Health.cpp
@@ -273,7 +273,11 @@
 
     {
         std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
-        callbacks_.emplace_back(LinkedCallback::Make(ref<Health>(), callback));
+        auto linked_callback_result = LinkedCallback::Make(ref<Health>(), callback);
+        if (!linked_callback_result.ok()) {
+            return ndk::ScopedAStatus::fromStatus(-linked_callback_result.error().code());
+        }
+        callbacks_.emplace_back(std::move(*linked_callback_result));
         // unlock
     }
 
diff --git a/health/aidl/default/LinkedCallback.cpp b/health/aidl/default/LinkedCallback.cpp
index 2985ffe..26e99f9 100644
--- a/health/aidl/default/LinkedCallback.cpp
+++ b/health/aidl/default/LinkedCallback.cpp
@@ -24,7 +24,7 @@
 
 namespace aidl::android::hardware::health {
 
-std::unique_ptr<LinkedCallback> LinkedCallback::Make(
+::android::base::Result<std::unique_ptr<LinkedCallback>> LinkedCallback::Make(
         std::shared_ptr<Health> service, std::shared_ptr<IHealthInfoCallback> callback) {
     std::unique_ptr<LinkedCallback> ret(new LinkedCallback());
     binder_status_t linkRet =
@@ -32,7 +32,7 @@
                                  reinterpret_cast<void*>(ret.get()));
     if (linkRet != ::STATUS_OK) {
         LOG(WARNING) << __func__ << "Cannot link to death: " << linkRet;
-        return nullptr;
+        return ::android::base::Error(-linkRet);
     }
     ret->service_ = service;
     ret->callback_ = std::move(callback);
diff --git a/health/aidl/default/LinkedCallback.h b/health/aidl/default/LinkedCallback.h
index 82490a7..da494c9 100644
--- a/health/aidl/default/LinkedCallback.h
+++ b/health/aidl/default/LinkedCallback.h
@@ -20,6 +20,7 @@
 
 #include <aidl/android/hardware/health/IHealthInfoCallback.h>
 #include <android-base/macros.h>
+#include <android-base/result.h>
 #include <android/binder_auto_utils.h>
 
 #include <health-impl/Health.h>
@@ -34,8 +35,8 @@
     // service->death_reciepient() should be from CreateDeathRecipient().
     // Not using a strong reference to |service| to avoid circular reference. The lifetime
     // of |service| must be longer than this LinkedCallback object.
-    static std::unique_ptr<LinkedCallback> Make(std::shared_ptr<Health> service,
-                                                std::shared_ptr<IHealthInfoCallback> callback);
+    static ::android::base::Result<std::unique_ptr<LinkedCallback>> Make(
+            std::shared_ptr<Health> service, std::shared_ptr<IHealthInfoCallback> callback);
 
     // Automatically unlinkToDeath upon destruction. So, it is always safe to reinterpret_cast
     // the cookie back to the LinkedCallback object.
diff --git a/radio/1.0/vts/functional/vts_test_util.cpp b/radio/1.0/vts/functional/vts_test_util.cpp
index 5b31acc..0515778 100644
--- a/radio/1.0/vts/functional/vts_test_util.cpp
+++ b/radio/1.0/vts/functional/vts_test_util.cpp
@@ -138,3 +138,7 @@
     count_--;
     return status;
 }
+
+bool isLteConnected(){
+    return testing::checkSubstringInCommandOutput("getprop gsm.network.type", "LTE");
+}
diff --git a/radio/1.0/vts/functional/vts_test_util.h b/radio/1.0/vts/functional/vts_test_util.h
index fa338a3..39c7545 100644
--- a/radio/1.0/vts/functional/vts_test_util.h
+++ b/radio/1.0/vts/functional/vts_test_util.h
@@ -104,6 +104,11 @@
  */
 bool isVoiceInService(RegState state);
 
+/*
+ * Check if device is in Lte Connected status.
+ */
+bool isLteConnected();
+
 /**
  * Used when waiting for an asynchronous response from the HAL.
  */
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index fd44e93..3d3abe4 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -597,7 +597,7 @@
     } else if (cardStatus.base.base.base.cardState == CardState::PRESENT) {
         // Modems support 3GPP RAT family need to
         // support scanning requests combined with some parameters.
-        if (deviceSupportsFeature(FEATURE_TELEPHONY_GSM)) {
+        if (deviceSupportsFeature(FEATURE_TELEPHONY_GSM) && isLteConnected()) {
             ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_5->rspInfo.error,
                                          {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED}));
         } else {
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.cpp b/radio/aidl/vts/radio_aidl_hal_utils.cpp
index 64969de..1515201 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.cpp
+++ b/radio/aidl/vts/radio_aidl_hal_utils.cpp
@@ -240,3 +240,7 @@
         slotStatus = radioConfigRsp->simSlotStatus[physicalSlotId];
     }
 }
+
+bool isLteConnected(){
+    return testing::checkSubstringInCommandOutput("getprop gsm.network.type", "LTE");
+}
diff --git a/radio/aidl/vts/radio_aidl_hal_utils.h b/radio/aidl/vts/radio_aidl_hal_utils.h
index 906247e..1690e89 100644
--- a/radio/aidl/vts/radio_aidl_hal_utils.h
+++ b/radio/aidl/vts/radio_aidl_hal_utils.h
@@ -131,6 +131,11 @@
  */
 bool isServiceValidForDeviceConfiguration(std::string& serviceName);
 
+/*
+ * Check if device is in Lte Connected status.
+ */
+bool isLteConnected();
+
 /**
  * RadioServiceTest base class
  */
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index e5da050..2beb249 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -886,7 +886,7 @@
     if (cardStatus.cardState == CardStatus::STATE_ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error, {RadioError::SIM_ABSENT}));
     } else if (cardStatus.cardState == CardStatus::STATE_PRESENT) {
-        if (deviceSupportsFeature(FEATURE_TELEPHONY_GSM)) {
+        if (deviceSupportsFeature(FEATURE_TELEPHONY_GSM) && isLteConnected()) {
             // Modems support 3GPP RAT family need to
             // support scanning requests combined with some parameters.
             ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 051ace4..1e61a18 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -2070,7 +2070,8 @@
                         builder, &key_blob, &key_characteristics);
             }
         }
-        ASSERT_EQ(error, ErrorCode::CANNOT_ATTEST_IDS);
+
+        device_id_attestation_check_acceptable_error(tag.tag, error);
     }
 }
 
diff --git a/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl b/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
index e4d4cbe..607ceb3 100644
--- a/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
+++ b/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
@@ -36,10 +36,9 @@
 interface IThreadChip {
   void open(in android.hardware.threadnetwork.IThreadChipCallback callback);
   void close();
-  void reset();
+  void hardwareReset();
   void sendSpinelFrame(in byte[] frame);
   const int ERROR_FAILED = 1;
-  const int ERROR_INVALID_ARGS = 2;
-  const int ERROR_NO_BUFS = 3;
-  const int ERROR_BUSY = 4;
+  const int ERROR_NO_BUFS = 2;
+  const int ERROR_BUSY = 3;
 }
diff --git a/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
index eebaa46..e695623 100644
--- a/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
+++ b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
@@ -30,19 +30,14 @@
     const int ERROR_FAILED = 1;
 
     /**
-     * The invalid arguments.
-     */
-    const int ERROR_INVALID_ARGS = 2;
-
-    /**
      * Insufficient buffers available to send frames.
      */
-    const int ERROR_NO_BUFS = 3;
+    const int ERROR_NO_BUFS = 2;
 
     /**
      * Service is busy and could not service the operation.
      */
-    const int ERROR_BUSY = 4;
+    const int ERROR_BUSY = 3;
 
     /**
      * This method initializes the Thread HAL instance. If open completes
@@ -51,9 +46,10 @@
      *
      * @param callback  A IThreadChipCallback callback instance.
      *
+     * @throws EX_ILLEGAL_ARGUMENT  if the callback handle is invalid (for example, it is null).
+     *
      * @throws ServiceSpecificException with one of the following values:
      *     - ERROR_FAILED        The interface cannot be opened due to an internal error.
-     *     - ERROR_INVALID_ARGS  The callback handle is invalid (for example, it is null).
      *     - ERROR_BUSY          This interface is in use.
      */
     void open(in IThreadChipCallback callback);
@@ -64,11 +60,14 @@
     void close();
 
     /**
-     * This method resets the Thread HAL internal state. The callback registered by
-     * `open()` won’t be reset and the resource allocated by `open()` won’t be free.
+     * This method hardware resets the Thread radio chip via the physical reset pin.
+     * The callback registered by `open()` won’t be reset and the resource allocated
+     * by `open()` won’t be free.
+     *
+     * @throws EX_UNSUPPORTED_OPERATION  if the Thread radio chip doesn't support the hardware reset.
      *
      */
-    void reset();
+    void hardwareReset();
 
     /**
      * This method sends a spinel frame to the Thread HAL.
diff --git a/threadnetwork/aidl/default/Android.bp b/threadnetwork/aidl/default/Android.bp
index 8b938d2..bcd5704 100644
--- a/threadnetwork/aidl/default/Android.bp
+++ b/threadnetwork/aidl/default/Android.bp
@@ -79,7 +79,6 @@
         "fuzzer.cpp",
     ],
 
-    required: ["ot-rcp"],
     fuzz_config: {
         cc: [
             "zhanglongxia@google.com",
diff --git a/threadnetwork/aidl/default/fuzzer.cpp b/threadnetwork/aidl/default/fuzzer.cpp
index 512708d..fb6e548 100644
--- a/threadnetwork/aidl/default/fuzzer.cpp
+++ b/threadnetwork/aidl/default/fuzzer.cpp
@@ -22,7 +22,7 @@
 using android::fuzzService;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-    char url[] = "spinel+hdlc+forkpty:///vendor/bin/ot-rcp?forkpty-arg=2";
+    char url[] = "spinel+hdlc+null:///dev/null";
     auto service = ndk::SharedRefBase::make<ThreadChip>(url);
 
     fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
diff --git a/threadnetwork/aidl/default/thread_chip.cpp b/threadnetwork/aidl/default/thread_chip.cpp
index 94d1e93..3d38cb8 100644
--- a/threadnetwork/aidl/default/thread_chip.cpp
+++ b/threadnetwork/aidl/default/thread_chip.cpp
@@ -17,6 +17,8 @@
 #include "thread_chip.hpp"
 
 #include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder.h>
 #include <android/binder_manager.h>
 #include <android/binder_process.h>
 #include <utils/Log.h>
@@ -46,20 +48,36 @@
         mSpinelInterface = std::make_shared<ot::Posix::HdlcInterface>(handleReceivedFrameJump, this,
                                                                       mRxFrameBuffer);
     } else {
-        ALOGE("The protocol \"%s\" is not supported!", protocol);
-        exit(1);
+        ALOGE("The protocol \"%s\" is not supported", protocol);
+        exit(EXIT_FAILURE);
     }
 
     CHECK_NE(mSpinelInterface, nullptr);
+
+    mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
+            AIBinder_DeathRecipient_new(ThreadChip::onBinderDiedJump));
+    AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), ThreadChip::onBinderUnlinkedJump);
 }
 
-void ThreadChip::clientDeathCallback(void* context) {
-    reinterpret_cast<ThreadChip*>(context)->clientDeathCallback();
+ThreadChip::~ThreadChip() {
+    AIBinder_DeathRecipient_delete(mDeathRecipient.get());
 }
 
-void ThreadChip::clientDeathCallback(void) {
-    ALOGW("Thread Network HAL client is dead.");
-    close();
+void ThreadChip::onBinderDiedJump(void* context) {
+    reinterpret_cast<ThreadChip*>(context)->onBinderDied();
+}
+
+void ThreadChip::onBinderDied(void) {
+    ALOGW("Thread Network HAL client is dead");
+}
+
+void ThreadChip::onBinderUnlinkedJump(void* context) {
+    reinterpret_cast<ThreadChip*>(context)->onBinderUnlinked();
+}
+
+void ThreadChip::onBinderUnlinked(void) {
+    ALOGW("ThreadChip binder is unlinked");
+    deinitChip();
 }
 
 void ThreadChip::handleReceivedFrameJump(void* context) {
@@ -76,75 +94,83 @@
 }
 
 ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr<IThreadChipCallback>& in_callback) {
-    ndk::ScopedAStatus status;
-    AIBinder* binder;
+    ndk::ScopedAStatus status = initChip(in_callback);
 
-    VerifyOrExit(mCallback == nullptr,
-                 status = errorStatus(ERROR_BUSY, "Interface is already opened"));
-    VerifyOrExit(in_callback != nullptr,
-                 status = errorStatus(ERROR_INVALID_ARGS, "The callback is NULL"));
-    binder = in_callback->asBinder().get();
-    VerifyOrExit(binder != nullptr,
-                 status = errorStatus(ERROR_FAILED, "Failed to get the callback binder"));
-    mBinderDeathRecipient = AIBinder_DeathRecipient_new(clientDeathCallback);
-    VerifyOrExit(AIBinder_linkToDeath(binder, mBinderDeathRecipient, this) == STATUS_OK,
-                 status = errorStatus(ERROR_FAILED, "Failed to link the binder to death"));
-    VerifyOrExit(mSpinelInterface->Init(mUrl) == OT_ERROR_NONE,
-                 status = errorStatus(ERROR_FAILED, "Failed to initialize the interface"));
-
-    mCallback = in_callback;
-    ot::Posix::Mainloop::Manager::Get().Add(*this);
-    status = ndk::ScopedAStatus::ok();
-
-exit:
-    if (!status.isOk()) {
-        if (mBinderDeathRecipient != nullptr) {
-            AIBinder_DeathRecipient_delete(mBinderDeathRecipient);
-            mBinderDeathRecipient = nullptr;
-        }
-        ALOGW("Open failed, error: %s", status.getDescription().c_str());
+    if (status.isOk()) {
+        AIBinder_linkToDeath(in_callback->asBinder().get(), mDeathRecipient.get(), this);
+        ALOGI("Open IThreadChip successfully");
     } else {
-        ALOGI("open()");
+        ALOGW("Failed to open IThreadChip: %s", status.getDescription().c_str());
     }
 
     return status;
 }
 
+ndk::ScopedAStatus ThreadChip::initChip(const std::shared_ptr<IThreadChipCallback>& in_callback) {
+    if (in_callback == nullptr) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+    } else if (mCallback == nullptr) {
+        if (mSpinelInterface->Init(mUrl) != OT_ERROR_NONE) {
+            return errorStatus(ERROR_FAILED, "Failed to initialize the interface");
+        }
+
+        mCallback = in_callback;
+        ot::Posix::Mainloop::Manager::Get().Add(*this);
+        return ndk::ScopedAStatus::ok();
+    } else {
+        return errorStatus(ERROR_BUSY, "Interface has been opened");
+    }
+}
+
 ndk::ScopedAStatus ThreadChip::close() {
-    VerifyOrExit(mCallback != nullptr);
-    mCallback = nullptr;
-    mSpinelInterface->Deinit();
+    ndk::ScopedAStatus status;
+    std::shared_ptr<IThreadChipCallback> callback = mCallback;
 
-    ot::Posix::Mainloop::Manager::Get().Remove(*this);
+    status = deinitChip();
+    if (status.isOk()) {
+        if (callback != nullptr) {
+            AIBinder_unlinkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this);
+        }
 
-    AIBinder_DeathRecipient_delete(mBinderDeathRecipient);
-    mBinderDeathRecipient = nullptr;
+        ALOGI("Close IThreadChip successfully");
+    } else {
+        ALOGW("Failed to close IThreadChip: %s", status.getDescription().c_str());
+    }
 
-exit:
-    ALOGI("close()");
-    return ndk::ScopedAStatus::ok();
+    return status;
+}
+
+ndk::ScopedAStatus ThreadChip::deinitChip() {
+    if (mCallback != nullptr) {
+        mSpinelInterface->Deinit();
+        ot::Posix::Mainloop::Manager::Get().Remove(*this);
+        mCallback = nullptr;
+        return ndk::ScopedAStatus::ok();
+    }
+
+    return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
 }
 
 ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector<uint8_t>& in_frame) {
     ndk::ScopedAStatus status;
     otError error;
 
-    VerifyOrExit(mCallback != nullptr,
-                 status = errorStatus(ERROR_FAILED, "The interface is not open"));
-
-    error = mSpinelInterface->SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
-                                        in_frame.size());
-    if (error == OT_ERROR_NONE) {
-        status = ndk::ScopedAStatus::ok();
-    } else if (error == OT_ERROR_NO_BUFS) {
-        status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send");
-    } else if (error == OT_ERROR_BUSY) {
-        status = errorStatus(ERROR_BUSY, "The interface is busy");
+    if (mCallback == nullptr) {
+        status = errorStatus(ERROR_FAILED, "The interface is not open");
     } else {
-        status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame");
+        error = mSpinelInterface->SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
+                                            in_frame.size());
+        if (error == OT_ERROR_NONE) {
+            status = ndk::ScopedAStatus::ok();
+        } else if (error == OT_ERROR_NO_BUFS) {
+            status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send");
+        } else if (error == OT_ERROR_BUSY) {
+            status = errorStatus(ERROR_BUSY, "The interface is busy");
+        } else {
+            status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame");
+        }
     }
 
-exit:
     if (!status.isOk()) {
         ALOGW("Send spinel frame failed, error: %s", status.getDescription().c_str());
     }
@@ -152,8 +178,11 @@
     return status;
 }
 
-ndk::ScopedAStatus ThreadChip::reset() {
-    mSpinelInterface->HardwareReset();
+ndk::ScopedAStatus ThreadChip::hardwareReset() {
+    if (mSpinelInterface->HardwareReset() == OT_ERROR_NOT_IMPLEMENTED) {
+        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    }
+
     ALOGI("reset()");
     return ndk::ScopedAStatus::ok();
 }
diff --git a/threadnetwork/aidl/default/thread_chip.hpp b/threadnetwork/aidl/default/thread_chip.hpp
index 294190a..1ab6d54 100644
--- a/threadnetwork/aidl/default/thread_chip.hpp
+++ b/threadnetwork/aidl/default/thread_chip.hpp
@@ -22,6 +22,7 @@
 #include "lib/spinel/spinel_interface.hpp"
 #include "mainloop.hpp"
 
+#include <android/binder_auto_utils.h>
 #include <android/binder_ibinder.h>
 #include <utils/Mutex.h>
 
@@ -33,26 +34,31 @@
 class ThreadChip : public BnThreadChip, ot::Posix::Mainloop::Source {
   public:
     ThreadChip(char* url);
+    ~ThreadChip();
 
     ndk::ScopedAStatus open(const std::shared_ptr<IThreadChipCallback>& in_callback) override;
     ndk::ScopedAStatus close() override;
     ndk::ScopedAStatus sendSpinelFrame(const std::vector<uint8_t>& in_frame) override;
-    ndk::ScopedAStatus reset() override;
+    ndk::ScopedAStatus hardwareReset() override;
     void Update(otSysMainloopContext& context) override;
     void Process(const otSysMainloopContext& context) override;
 
   private:
-    static void clientDeathCallback(void* context);
-    void clientDeathCallback(void);
+    static void onBinderDiedJump(void* context);
+    void onBinderDied(void);
+    static void onBinderUnlinkedJump(void* context);
+    void onBinderUnlinked(void);
     static void handleReceivedFrameJump(void* context);
     void handleReceivedFrame(void);
     ndk::ScopedAStatus errorStatus(int32_t error, const char* message);
+    ndk::ScopedAStatus initChip(const std::shared_ptr<IThreadChipCallback>& in_callback);
+    ndk::ScopedAStatus deinitChip();
 
     ot::Url::Url mUrl;
     std::shared_ptr<ot::Spinel::SpinelInterface> mSpinelInterface;
     ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer;
     std::shared_ptr<IThreadChipCallback> mCallback;
-    AIBinder_DeathRecipient* mBinderDeathRecipient;
+    ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
 };
 
 }  // namespace threadnetwork
diff --git a/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
index 04c6dea..5925b54 100644
--- a/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
+++ b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
@@ -91,7 +91,7 @@
             ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
 
     EXPECT_TRUE(thread_chip->open(callback).isOk());
-    EXPECT_TRUE(thread_chip->reset().isOk());
+    EXPECT_TRUE(thread_chip->hardwareReset().isOk());
 }
 
 TEST_P(ThreadNetworkAidl, SendSpinelFrame) {
diff --git a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp
index bebad7c..95bcec7 100644
--- a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp
+++ b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp
@@ -76,18 +76,10 @@
 
     void TearDown() override { stopWifiService(getInstanceName()); }
 
-    // Used as a mechanism to inform the test about data/event callbacks.
-    inline void notify() {
-        std::unique_lock<std::mutex> lock(mtx_);
-        count_++;
-        cv_.notify_one();
-    }
-
     enum CallbackType {
-        INVALID = -2,
-        ANY_CALLBACK = -1,
+        INVALID = 0,
 
-        NOTIFY_CAPABILITIES_RESPONSE = 0,
+        NOTIFY_CAPABILITIES_RESPONSE = 1,
         NOTIFY_ENABLE_RESPONSE,
         NOTIFY_CONFIG_RESPONSE,
         NOTIFY_DISABLE_RESPONSE,
@@ -128,310 +120,278 @@
         EVENT_SUSPENSION_MODE_CHANGE,
     };
 
+    // Used as a mechanism to inform the test about data/event callbacks.
+    inline void notify(CallbackType callbackType) {
+        std::unique_lock<std::mutex> lock(mtx_);
+        callback_event_bitmap_ |= (0x1 << callbackType);
+        cv_.notify_one();
+    }
+
     // Test code calls this function to wait for data/event callback.
-    // Must set callbackType = INVALID before calling this function.
+    // Must set callback_event_bitmap_ to 0 before calling this function.
     inline std::cv_status wait(CallbackType waitForCallbackType) {
         std::unique_lock<std::mutex> lock(mtx_);
         EXPECT_NE(INVALID, waitForCallbackType);
 
         std::cv_status status = std::cv_status::no_timeout;
         auto now = std::chrono::system_clock::now();
-        while (count_ == 0) {
+        while (!(receivedCallback(waitForCallbackType))) {
             status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
             if (status == std::cv_status::timeout) return status;
-            if (waitForCallbackType != ANY_CALLBACK && callback_type_ != INVALID &&
-                callback_type_ != waitForCallbackType) {
-                count_--;
-            }
         }
-        count_--;
         return status;
     }
 
+    inline bool receivedCallback(CallbackType waitForCallbackType) {
+        return callback_event_bitmap_ & (0x1 << waitForCallbackType);
+    }
+
     class WifiNanIfaceEventCallback : public BnWifiNanIfaceEventCallback {
       public:
         WifiNanIfaceEventCallback(WifiNanIfaceAidlTest& parent) : parent_(parent){};
 
         ::ndk::ScopedAStatus eventClusterEvent(const NanClusterEventInd& event) override {
-            parent_.callback_type_ = EVENT_CLUSTER_EVENT;
             parent_.nan_cluster_event_ind_ = event;
-            parent_.notify();
+            parent_.notify(EVENT_CLUSTER_EVENT);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventDataPathConfirm(const NanDataPathConfirmInd& event) override {
-            parent_.callback_type_ = EVENT_DATA_PATH_CONFIRM;
             parent_.nan_data_path_confirm_ind_ = event;
-            parent_.notify();
+            parent_.notify(EVENT_DATA_PATH_CONFIRM);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventDataPathRequest(const NanDataPathRequestInd& event) override {
-            parent_.callback_type_ = EVENT_DATA_PATH_REQUEST;
             parent_.nan_data_path_request_ind_ = event;
-            parent_.notify();
+            parent_.notify(EVENT_DATA_PATH_REQUEST);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventDataPathScheduleUpdate(
                 const NanDataPathScheduleUpdateInd& event) override {
-            parent_.callback_type_ = EVENT_DATA_PATH_SCHEDULE_UPDATE;
             parent_.nan_data_path_schedule_update_ind_ = event;
-            parent_.notify();
+            parent_.notify(EVENT_DATA_PATH_SCHEDULE_UPDATE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventDataPathTerminated(int32_t ndpInstanceId) override {
-            parent_.callback_type_ = EVENT_DATA_PATH_TERMINATED;
             parent_.ndp_instance_id_ = ndpInstanceId;
-            parent_.notify();
+            parent_.notify(EVENT_DATA_PATH_TERMINATED);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventDisabled(const NanStatus& status) override {
-            parent_.callback_type_ = EVENT_DISABLED;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(EVENT_DISABLED);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventFollowupReceived(const NanFollowupReceivedInd& event) override {
-            parent_.callback_type_ = EVENT_FOLLOWUP_RECEIVED;
             parent_.nan_followup_received_ind_ = event;
-            parent_.notify();
+            parent_.notify(EVENT_FOLLOWUP_RECEIVED);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventMatch(const NanMatchInd& event) override {
-            parent_.callback_type_ = EVENT_MATCH;
             parent_.nan_match_ind_ = event;
-            parent_.notify();
+            parent_.notify(EVENT_MATCH);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventMatchExpired(int8_t discoverySessionId, int32_t peerId) override {
-            parent_.callback_type_ = EVENT_MATCH_EXPIRED;
             parent_.session_id_ = discoverySessionId;
             parent_.peer_id_ = peerId;
-            parent_.notify();
+            parent_.notify(EVENT_MATCH_EXPIRED);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventPublishTerminated(int8_t sessionId,
                                                     const NanStatus& status) override {
-            parent_.callback_type_ = EVENT_PUBLISH_TERMINATED;
             parent_.session_id_ = sessionId;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(EVENT_PUBLISH_TERMINATED);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventSubscribeTerminated(int8_t sessionId,
                                                       const NanStatus& status) override {
-            parent_.callback_type_ = EVENT_SUBSCRIBE_TERMINATED;
             parent_.session_id_ = sessionId;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(EVENT_SUBSCRIBE_TERMINATED);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventTransmitFollowup(char16_t id, const NanStatus& status) override {
-            parent_.callback_type_ = EVENT_TRANSMIT_FOLLOWUP;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(EVENT_TRANSMIT_FOLLOWUP);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventPairingConfirm(const NanPairingConfirmInd& event) override {
-            parent_.callback_type_ = EVENT_PAIRING_CONFIRM;
             parent_.nan_pairing_confirm_ind_ = event;
-            parent_.notify();
+            parent_.notify(EVENT_PAIRING_CONFIRM);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventPairingRequest(const NanPairingRequestInd& event) override {
-            parent_.callback_type_ = EVENT_PAIRING_REQUEST;
             parent_.nan_pairing_request_ind_ = event;
-            parent_.notify();
+            parent_.notify(EVENT_PAIRING_REQUEST);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventBootstrappingConfirm(
                 const NanBootstrappingConfirmInd& event) override {
-            parent_.callback_type_ = EVENT_BOOTSTRAPPING_CONFIRM;
             parent_.nan_bootstrapping_confirm_ind_ = event;
-            parent_.notify();
+            parent_.notify(EVENT_BOOTSTRAPPING_CONFIRM);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventBootstrappingRequest(
                 const NanBootstrappingRequestInd& event) override {
-            parent_.callback_type_ = EVENT_BOOTSTRAPPING_REQUEST;
             parent_.nan_bootstrapping_request_ind_ = event;
-            parent_.notify();
+            parent_.notify(EVENT_BOOTSTRAPPING_REQUEST);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus eventSuspensionModeChanged(
                 const NanSuspensionModeChangeInd& event) override {
-            parent_.callback_type_ = EVENT_SUSPENSION_MODE_CHANGE;
             parent_.nan_suspension_mode_change_ind_ = event;
-            parent_.notify();
+            parent_.notify(EVENT_SUSPENSION_MODE_CHANGE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyCapabilitiesResponse(
                 char16_t id, const NanStatus& status,
                 const NanCapabilities& capabilities) override {
-            parent_.callback_type_ = NOTIFY_CAPABILITIES_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
             parent_.capabilities_ = capabilities;
-            parent_.notify();
+            parent_.notify(NOTIFY_CAPABILITIES_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyConfigResponse(char16_t id, const NanStatus& status) override {
-            parent_.callback_type_ = NOTIFY_CONFIG_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(NOTIFY_CONFIG_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyCreateDataInterfaceResponse(char16_t id,
                                                                const NanStatus& status) override {
-            parent_.callback_type_ = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(NOTIFY_CREATE_DATA_INTERFACE_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyDeleteDataInterfaceResponse(char16_t id,
                                                                const NanStatus& status) override {
-            parent_.callback_type_ = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(NOTIFY_DELETE_DATA_INTERFACE_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyDisableResponse(char16_t id, const NanStatus& status) override {
-            parent_.callback_type_ = NOTIFY_DISABLE_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(NOTIFY_DISABLE_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyEnableResponse(char16_t id, const NanStatus& status) override {
-            parent_.callback_type_ = NOTIFY_ENABLE_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(NOTIFY_ENABLE_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyInitiateDataPathResponse(char16_t id, const NanStatus& status,
                                                             int32_t ndpInstanceId) override {
-            parent_.callback_type_ = NOTIFY_INITIATE_DATA_PATH_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
             parent_.ndp_instance_id_ = ndpInstanceId;
-            parent_.notify();
+            parent_.notify(NOTIFY_INITIATE_DATA_PATH_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyRespondToDataPathIndicationResponse(
                 char16_t id, const NanStatus& status) override {
-            parent_.callback_type_ = NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyStartPublishResponse(char16_t id, const NanStatus& status,
                                                         int8_t sessionId) override {
-            parent_.callback_type_ = NOTIFY_START_PUBLISH_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
             parent_.session_id_ = sessionId;
-            parent_.notify();
+            parent_.notify(NOTIFY_START_PUBLISH_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyStartSubscribeResponse(char16_t id, const NanStatus& status,
                                                           int8_t sessionId) override {
-            parent_.callback_type_ = NOTIFY_START_SUBSCRIBE_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
             parent_.session_id_ = sessionId;
-            parent_.notify();
+            parent_.notify(NOTIFY_START_SUBSCRIBE_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyStopPublishResponse(char16_t id,
                                                        const NanStatus& status) override {
-            parent_.callback_type_ = NOTIFY_STOP_PUBLISH_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(NOTIFY_STOP_PUBLISH_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyStopSubscribeResponse(char16_t id,
                                                          const NanStatus& status) override {
-            parent_.callback_type_ = NOTIFY_STOP_SUBSCRIBE_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(NOTIFY_STOP_SUBSCRIBE_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyTerminateDataPathResponse(char16_t id,
                                                              const NanStatus& status) override {
-            parent_.callback_type_ = NOTIFY_TERMINATE_DATA_PATH_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(NOTIFY_TERMINATE_DATA_PATH_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifySuspendResponse(char16_t id, const NanStatus& status) override {
-            parent_.callback_type_ = NOTIFY_SUSPEND_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(NOTIFY_SUSPEND_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyResumeResponse(char16_t id, const NanStatus& status) override {
-            parent_.callback_type_ = NOTIFY_RESUME_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(NOTIFY_RESUME_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyTransmitFollowupResponse(char16_t id,
                                                             const NanStatus& status) override {
-            parent_.callback_type_ = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyInitiatePairingResponse(char16_t id, const NanStatus& status,
                                                            int32_t pairingInstanceId) override {
-            parent_.callback_type_ = NOTIFY_INITIATE_PAIRING_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
             parent_.pairing_instance_id_ = pairingInstanceId;
-            parent_.notify();
+            parent_.notify(NOTIFY_INITIATE_PAIRING_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyRespondToPairingIndicationResponse(
                 char16_t id, const NanStatus& status) override {
-            parent_.callback_type_ = NOTIFY_RESPOND_TO_PAIRING_INDICATION_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(NOTIFY_RESPOND_TO_PAIRING_INDICATION_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyInitiateBootstrappingResponse(
                 char16_t id, const NanStatus& status, int32_t bootstrapppingInstanceId) override {
-            parent_.callback_type_ = NOTIFY_INITIATE_BOOTSTRAPPING_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
             parent_.bootstrappping_instance_id_ = bootstrapppingInstanceId;
-            parent_.notify();
+            parent_.notify(NOTIFY_INITIATE_BOOTSTRAPPING_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyRespondToBootstrappingIndicationResponse(
                 char16_t id, const NanStatus& status) override {
-            parent_.callback_type_ = NOTIFY_RESPOND_TO_BOOTSTRAPPING_INDICATION_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(NOTIFY_RESPOND_TO_BOOTSTRAPPING_INDICATION_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
         ::ndk::ScopedAStatus notifyTerminatePairingResponse(char16_t id,
                                                             const NanStatus& status) override {
-            parent_.callback_type_ = NOTIFY_TERMINATE_PAIRING_RESPONSE;
             parent_.id_ = id;
             parent_.status_ = status;
-            parent_.notify();
+            parent_.notify(NOTIFY_TERMINATE_PAIRING_RESPONSE);
             return ndk::ScopedAStatus::ok();
         }
 
@@ -441,7 +401,7 @@
 
   protected:
     std::shared_ptr<IWifiNanIface> wifi_nan_iface_;
-    CallbackType callback_type_;
+    uint64_t callback_event_bitmap_;
     uint16_t id_;
     uint8_t session_id_;
     uint32_t ndp_instance_id_;
@@ -468,7 +428,6 @@
     // synchronization objects
     std::mutex mtx_;
     std::condition_variable cv_;
-    int count_ = 0;
 };
 
 /*
@@ -488,7 +447,7 @@
  */
 TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidArgs) {
     uint16_t inputCmdId = 10;
-    callback_type_ = INVALID;
+    callback_event_bitmap_ = 0;
     NanEnableRequest nanEnableRequest = {};
     NanConfigRequestSupplemental nanConfigRequestSupp = {};
     auto status =
@@ -498,7 +457,7 @@
 
         // Wait for a callback.
         ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
-        ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_);
+        ASSERT_TRUE(receivedCallback(NOTIFY_ENABLE_RESPONSE));
         ASSERT_EQ(id_, inputCmdId);
         ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS);
     }
@@ -509,7 +468,7 @@
  */
 TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidArgs) {
     uint16_t inputCmdId = 10;
-    callback_type_ = INVALID;
+    callback_event_bitmap_ = 0;
     NanConfigRequest nanConfigRequest = {};
     NanConfigRequestSupplemental nanConfigRequestSupp = {};
     auto status =
@@ -520,7 +479,7 @@
 
         // Wait for a callback.
         ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE));
-        ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callback_type_);
+        ASSERT_TRUE(receivedCallback(NOTIFY_CONFIG_RESPONSE));
         ASSERT_EQ(id_, inputCmdId);
         ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS);
     }
@@ -561,12 +520,12 @@
  */
 TEST_P(WifiNanIfaceAidlTest, NotifyCapabilitiesResponse) {
     uint16_t inputCmdId = 10;
-    callback_type_ = INVALID;
+    callback_event_bitmap_ = 0;
     EXPECT_TRUE(wifi_nan_iface_->getCapabilitiesRequest(inputCmdId).isOk());
 
     // Wait for a callback.
     ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE));
-    ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callback_type_);
+    ASSERT_TRUE(receivedCallback(NOTIFY_CAPABILITIES_RESPONSE));
     ASSERT_EQ(id_, inputCmdId);
     ASSERT_EQ(status_.status, NanStatusCode::SUCCESS);
 
@@ -654,14 +613,14 @@
     nanConfigRequestSupp.numberOfSpatialStreamsInDiscovery = 0;
     nanConfigRequestSupp.enableDiscoveryWindowEarlyTermination = false;
 
-    callback_type_ = INVALID;
+    callback_event_bitmap_ = 0;
     auto status = wifi_nan_iface_->enableRequest(inputCmdId, req, nanConfigRequestSupp);
     if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
         ASSERT_TRUE(status.isOk());
 
         // Wait for a callback.
         ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
-        ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_);
+        ASSERT_TRUE(receivedCallback(NOTIFY_ENABLE_RESPONSE));
         ASSERT_EQ(id_, inputCmdId);
         ASSERT_EQ(status_.status, NanStatusCode::SUCCESS);
     }
@@ -688,7 +647,7 @@
 
         // Wait for a callback.
         ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_START_PUBLISH_RESPONSE));
-        ASSERT_EQ(NOTIFY_START_PUBLISH_RESPONSE, callback_type_);
+        ASSERT_TRUE(receivedCallback(NOTIFY_START_PUBLISH_RESPONSE));
         ASSERT_EQ(id_, inputCmdId + 1);
         ASSERT_EQ(status_.status, NanStatusCode::SUCCESS);
     }
@@ -699,7 +658,7 @@
  */
 TEST_P(WifiNanIfaceAidlTest, RespondToDataPathIndicationRequest_InvalidArgs) {
     uint16_t inputCmdId = 10;
-    callback_type_ = INVALID;
+    callback_event_bitmap_ = 0;
     NanRespondToDataPathIndicationRequest nanRespondToDataPathIndicationRequest = {};
     nanRespondToDataPathIndicationRequest.ifaceName = "AwareInterfaceNameTooLong";
     auto status = wifi_nan_iface_->respondToDataPathIndicationRequest(
@@ -716,7 +675,7 @@
  */
 TEST_P(WifiNanIfaceAidlTest, InitiateDataPathRequest_InvalidArgs) {
     uint16_t inputCmdId = 10;
-    callback_type_ = INVALID;
+    callback_event_bitmap_ = 0;
     NanInitiateDataPathRequest nanInitiateDataPathRequest = {};
     nanInitiateDataPathRequest.ifaceName = "AwareInterfaceNameTooLong";
     auto status = wifi_nan_iface_->initiateDataPathRequest(inputCmdId, nanInitiateDataPathRequest);