Merge "Allow old gralloc implementations to skip P010 support." into tm-dev
diff --git a/automotive/audiocontrol/aidl/default/Android.bp b/automotive/audiocontrol/aidl/default/Android.bp
index 1439cce..6bf4b9d 100644
--- a/automotive/audiocontrol/aidl/default/Android.bp
+++ b/automotive/audiocontrol/aidl/default/Android.bp
@@ -29,8 +29,9 @@
     vendor: true,
     shared_libs: [
         "android.hardware.audio.common@7.0-enums",
+        "android.hardware.audio.common-V1-ndk",
         "android.frameworks.automotive.powerpolicy-V1-ndk",
-        "android.hardware.automotive.audiocontrol-V1-ndk",
+        "android.hardware.automotive.audiocontrol-V2-ndk",
         "libbase",
         "libbinder_ndk",
         "libcutils",
diff --git a/automotive/audiocontrol/aidl/default/AudioControl.cpp b/automotive/audiocontrol/aidl/default/AudioControl.cpp
index c0bc796..a121f8b 100644
--- a/automotive/audiocontrol/aidl/default/AudioControl.cpp
+++ b/automotive/audiocontrol/aidl/default/AudioControl.cpp
@@ -30,6 +30,8 @@
 #include <android_audio_policy_configuration_V7_0-enums.h>
 #include <private/android_filesystem_config.h>
 
+#include <numeric>
+
 #include <stdio.h>
 
 namespace aidl::android::hardware::automotive::audiocontrol {
@@ -147,6 +149,47 @@
     return ndk::ScopedAStatus::ok();
 }
 
+template <typename aidl_type>
+static inline std::string toString(const std::vector<aidl_type>& in_values) {
+    return std::accumulate(std::begin(in_values), std::end(in_values), std::string{},
+                           [](std::string& ls, const aidl_type& rs) {
+                               return ls += (ls.empty() ? "" : ",") + rs.toString();
+                           });
+}
+template <typename aidl_enum_type>
+static inline std::string toEnumString(const std::vector<aidl_enum_type>& in_values) {
+    return std::accumulate(std::begin(in_values), std::end(in_values), std::string{},
+                           [](std::string& ls, const aidl_enum_type& rs) {
+                               return ls += (ls.empty() ? "" : ",") + toString(rs);
+                           });
+}
+
+ndk::ScopedAStatus AudioControl::onAudioFocusChangeWithMetaData(
+        const audiohalcommon::PlaybackTrackMetadata& in_playbackMetaData, int32_t in_zoneId,
+        AudioFocusChange in_focusChange) {
+    LOG(INFO) << "Focus changed: " << toString(in_focusChange).c_str() << " for metadata "
+              << in_playbackMetaData.toString().c_str() << " in zone " << in_zoneId;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AudioControl::setAudioDeviceGainsChanged(
+        const std::vector<Reasons>& in_reasons, const std::vector<AudioGainConfigInfo>& in_gains) {
+    LOG(INFO) << "Audio Device Gains changed: resons:" << toEnumString(in_reasons).c_str()
+              << " for devices: " << toString(in_gains).c_str();
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AudioControl::registerGainCallback(
+        const std::shared_ptr<IAudioGainCallback>& in_callback) {
+    LOG(DEBUG) << ": " << __func__;
+    if (in_callback) {
+        std::atomic_store(&mAudioGainCallback, in_callback);
+    } else {
+        LOG(ERROR) << "Unexpected nullptr for audio gain callback resulting in no-op.";
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
 binder_status_t AudioControl::dump(int fd, const char** args, uint32_t numArgs) {
     if (numArgs == 0) {
         return dumpsys(fd);
@@ -159,6 +202,12 @@
         return cmdRequestFocus(fd, args, numArgs);
     } else if (EqualsIgnoreCase(option, "--abandon")) {
         return cmdAbandonFocus(fd, args, numArgs);
+    } else if (EqualsIgnoreCase(option, "--requestFocusWithMetaData")) {
+        return cmdRequestFocusWithMetaData(fd, args, numArgs);
+    } else if (EqualsIgnoreCase(option, "--abandonFocusWithMetaData")) {
+        return cmdAbandonFocusWithMetaData(fd, args, numArgs);
+    } else if (EqualsIgnoreCase(option, "--audioGainCallback")) {
+        return cmdOnAudioDeviceGainsChanged(fd, args, numArgs);
     } else {
         dprintf(fd, "Invalid option: %s\n", option.c_str());
         return STATUS_BAD_VALUE;
@@ -171,20 +220,49 @@
     } else {
         dprintf(fd, "Focus listener registered\n");
     }
+    dprintf(fd, "AudioGainCallback %sregistered\n", (mAudioGainCallback == nullptr ? "NOT " : ""));
     return STATUS_OK;
 }
 
 binder_status_t AudioControl::cmdHelp(int fd) const {
     dprintf(fd, "Usage: \n\n");
-    dprintf(fd, "[no args]: dumps focus listener status\n");
+    dprintf(fd, "[no args]: dumps focus listener / gain callback registered status\n");
     dprintf(fd, "--help: shows this help\n");
     dprintf(fd,
             "--request <USAGE> <ZONE_ID> <FOCUS_GAIN>: requests audio focus for specified "
-            "usage (string), audio zone ID (int), and focus gain type (int)\n");
+            "usage (string), audio zone ID (int), and focus gain type (int)\n"
+            "Deprecated, use MetaData instead\n");
     dprintf(fd,
             "--abandon <USAGE> <ZONE_ID>: abandons audio focus for specified usage (string) and "
-            "audio zone ID (int)\n");
+            "audio zone ID (int)\n"
+            "Deprecated, use MetaData instead\n");
     dprintf(fd, "See audio_policy_configuration.xsd for valid AudioUsage values.\n");
+
+    dprintf(fd,
+            "--requestFocusWithMetaData <METADATA> <ZONE_ID> <FOCUS_GAIN>: "
+            "requests audio focus for specified metadata, audio zone ID (int), "
+            "and focus gain type (int)\n");
+    dprintf(fd,
+            "--abandonFocusWithMetaData <METADATA> <ZONE_ID>: "
+            "abandons audio focus for specified metadata and audio zone ID (int)\n");
+    dprintf(fd,
+            "--audioGainCallback <ZONE_ID> <REASON_1>[,<REASON_N> ...]"
+            "<DEVICE_ADDRESS_1> <GAIN_INDEX_1> [<DEVICE_ADDRESS_N> <GAIN_INDEX_N> ...]: fire audio "
+            "gain callback for audio zone ID (int), the given reasons (csv int) for given pairs "
+            "of device address (string) and gain index (int) \n");
+
+    dprintf(fd,
+            "Note on <METADATA>: <USAGE,CONTENT_TYPE[,TAGS]>  specified as where (int)usage, "
+            "(int)content type and tags (string)string)\n");
+    dprintf(fd,
+            "See android/media/audio/common/AudioUsageType.aidl for valid AudioUsage values.\n");
+    dprintf(fd,
+            "See android/media/audio/common/AudioContentType.aidl for valid AudioContentType "
+            "values.\n");
+    dprintf(fd,
+            "Tags are optional. If provided, it must follow the <key>=<value> pattern, where the "
+            "value is namespaced (for example com.google.strategy=VR).\n");
+
     return STATUS_OK;
 }
 
@@ -266,4 +344,174 @@
     return STATUS_OK;
 }
 
+binder_status_t AudioControl::parseMetaData(int fd, const std::string& metadataLiteral,
+                                            audiohalcommon::PlaybackTrackMetadata& trackMetadata) {
+    std::stringstream csvMetaData(metadataLiteral);
+    std::vector<std::string> splitMetaData;
+    std::string attribute;
+    while (getline(csvMetaData, attribute, ',')) {
+        splitMetaData.push_back(attribute);
+    }
+    if (splitMetaData.size() != 2 && splitMetaData.size() != 3) {
+        dprintf(fd,
+                "Invalid metadata: %s, please provide <METADATA> as <USAGE,CONTENT_TYPE[,TAGS]> "
+                "where (int)usage, (int)content type and tags (string)string)\n",
+                metadataLiteral.c_str());
+        return STATUS_BAD_VALUE;
+    }
+    int usage;
+    if (!safelyParseInt(splitMetaData[0], &usage)) {
+        dprintf(fd, "Non-integer usage provided with request: %s\n", splitMetaData[0].c_str());
+        return STATUS_BAD_VALUE;
+    }
+    int contentType;
+    if (!safelyParseInt(splitMetaData[1], &contentType)) {
+        dprintf(fd, "Non-integer content type provided with request: %s\n",
+                splitMetaData[1].c_str());
+        return STATUS_BAD_VALUE;
+    }
+    const std::string tags = (splitMetaData.size() == 3 ? splitMetaData[2] : "");
+
+    trackMetadata = {.usage = static_cast<audiomediacommon::AudioUsage>(usage),
+                     .contentType = static_cast<audiomediacommon::AudioContentType>(contentType),
+                     .tags = {tags}};
+    return STATUS_OK;
+}
+
+binder_status_t AudioControl::cmdRequestFocusWithMetaData(int fd, const char** args,
+                                                          uint32_t numArgs) {
+    if (!checkCallerHasWritePermissions(fd)) {
+        return STATUS_PERMISSION_DENIED;
+    }
+    if (numArgs != 4) {
+        dprintf(fd,
+                "Invalid number of arguments: please provide:\n"
+                "--requestFocusWithMetaData <METADATA> <ZONE_ID> <FOCUS_GAIN>: "
+                "requests audio focus for specified metadata, audio zone ID (int), "
+                "and focus gain type (int)\n");
+        return STATUS_BAD_VALUE;
+    }
+    std::string metadataLiteral = std::string(args[1]);
+    audiohalcommon::PlaybackTrackMetadata trackMetadata{};
+    auto status = parseMetaData(fd, metadataLiteral, trackMetadata);
+    if (status != STATUS_OK) {
+        return status;
+    }
+
+    int zoneId;
+    if (!safelyParseInt(std::string(args[2]), &zoneId)) {
+        dprintf(fd, "Non-integer zoneId provided with request: %s\n", std::string(args[2]).c_str());
+        return STATUS_BAD_VALUE;
+    }
+
+    int focusGainValue;
+    if (!safelyParseInt(std::string(args[3]), &focusGainValue)) {
+        dprintf(fd, "Non-integer focusGain provided with request: %s\n",
+                std::string(args[3]).c_str());
+        return STATUS_BAD_VALUE;
+    }
+    AudioFocusChange focusGain = AudioFocusChange(focusGainValue);
+
+    if (mFocusListener == nullptr) {
+        dprintf(fd, "Unable to request focus - no focus listener registered\n");
+        return STATUS_BAD_VALUE;
+    }
+    mFocusListener->requestAudioFocusWithMetaData(trackMetadata, zoneId, focusGain);
+    dprintf(fd, "Requested focus for metadata %s, zoneId %d, and focusGain %d\n",
+            trackMetadata.toString().c_str(), zoneId, focusGain);
+    return STATUS_OK;
+}
+
+binder_status_t AudioControl::cmdAbandonFocusWithMetaData(int fd, const char** args,
+                                                          uint32_t numArgs) {
+    if (!checkCallerHasWritePermissions(fd)) {
+        return STATUS_PERMISSION_DENIED;
+    }
+    if (numArgs != 3) {
+        dprintf(fd,
+                "Invalid number of arguments: please provide:\n"
+                "--abandonFocusWithMetaData <METADATA> <ZONE_ID>: "
+                "abandons audio focus for specified metadata and audio zone ID (int)\n");
+        return STATUS_BAD_VALUE;
+    }
+    std::string metadataLiteral = std::string(args[1]);
+    audiohalcommon::PlaybackTrackMetadata trackMetadata{};
+    auto status = parseMetaData(fd, metadataLiteral, trackMetadata);
+    if (status != STATUS_OK) {
+        return status;
+    }
+    int zoneId;
+    if (!safelyParseInt(std::string(args[2]), &zoneId)) {
+        dprintf(fd, "Non-integer zoneId provided with request: %s\n", std::string(args[2]).c_str());
+        return STATUS_BAD_VALUE;
+    }
+    if (mFocusListener == nullptr) {
+        dprintf(fd, "Unable to abandon focus - no focus listener registered\n");
+        return STATUS_BAD_VALUE;
+    }
+
+    mFocusListener->abandonAudioFocusWithMetaData(trackMetadata, zoneId);
+    dprintf(fd, "Abandoned focus for metadata %s and zoneId %d\n", trackMetadata.toString().c_str(),
+            zoneId);
+    return STATUS_OK;
+}
+
+binder_status_t AudioControl::cmdOnAudioDeviceGainsChanged(int fd, const char** args,
+                                                           uint32_t numArgs) {
+    if (!checkCallerHasWritePermissions(fd)) {
+        return STATUS_PERMISSION_DENIED;
+    }
+    if ((numArgs + 1) % 2 != 0) {
+        dprintf(fd,
+                "Invalid number of arguments: please provide\n"
+                "--audioGainCallback <ZONE_ID> <REASON_1>[,<REASON_N> ...]"
+                "<DEVICE_ADDRESS_1> <GAIN_INDEX_1> [<DEVICE_ADDRESS_N> <GAIN_INDEX_N> ...]: "
+                "fire audio gain callback for audio zone ID (int), "
+                "with the given reasons (csv int) for given pairs of device address (string) "
+                "and gain index (int) \n");
+        return STATUS_BAD_VALUE;
+    }
+    int zoneId;
+    if (!safelyParseInt(string(args[1]), &zoneId)) {
+        dprintf(fd, "Non-integer zoneId provided with request: %s\n", std::string(args[1]).c_str());
+        return STATUS_BAD_VALUE;
+    }
+    std::string reasonsLiteral = std::string(args[2]);
+    std::stringstream csvReasonsLiteral(reasonsLiteral);
+    std::vector<Reasons> reasons;
+    std::string reasonLiteral;
+    while (getline(csvReasonsLiteral, reasonLiteral, ',')) {
+        int reason;
+        if (!safelyParseInt(reasonLiteral, &reason)) {
+            dprintf(fd, "Invalid Reason(s) provided %s\n", reasonLiteral.c_str());
+            return STATUS_BAD_VALUE;
+        }
+        reasons.push_back(static_cast<Reasons>(reason));
+    }
+
+    std::vector<AudioGainConfigInfo> agcis{};
+    for (uint32_t i = 3; i < numArgs; i += 2) {
+        std::string deviceAddress = std::string(args[i]);
+        int32_t index;
+        if (!safelyParseInt(std::string(args[i + 1]), &index)) {
+            dprintf(fd, "Non-integer index provided with request: %s\n",
+                    std::string(args[i + 1]).c_str());
+            return STATUS_BAD_VALUE;
+        }
+        AudioGainConfigInfo agci{zoneId, deviceAddress, index};
+        agcis.push_back(agci);
+    }
+    if (mAudioGainCallback == nullptr) {
+        dprintf(fd,
+                "Unable to trig audio gain callback for reasons=%s and gains=%s\n"
+                " - no audio gain callback registered\n",
+                toEnumString(reasons).c_str(), toString(agcis).c_str());
+        return STATUS_BAD_VALUE;
+    }
+
+    mAudioGainCallback->onAudioDeviceGainsChanged(reasons, agcis);
+    dprintf(fd, "Fired audio gain callback for reasons=%s and gains=%s\n",
+            toEnumString(reasons).c_str(), toString(agcis).c_str());
+    return STATUS_OK;
+}
 }  // namespace aidl::android::hardware::automotive::audiocontrol
diff --git a/automotive/audiocontrol/aidl/default/AudioControl.h b/automotive/audiocontrol/aidl/default/AudioControl.h
index cca9c44..16b80e8 100644
--- a/automotive/audiocontrol/aidl/default/AudioControl.h
+++ b/automotive/audiocontrol/aidl/default/AudioControl.h
@@ -17,12 +17,20 @@
 #define ANDROID_HARDWARE_AUTOMOTIVE_AUDIOCONTROL_AUDIOCONTROL_H
 
 #include <aidl/android/hardware/automotive/audiocontrol/AudioFocusChange.h>
+#include <aidl/android/hardware/automotive/audiocontrol/AudioGainConfigInfo.h>
 #include <aidl/android/hardware/automotive/audiocontrol/BnAudioControl.h>
 #include <aidl/android/hardware/automotive/audiocontrol/DuckingInfo.h>
+#include <aidl/android/hardware/automotive/audiocontrol/IAudioGainCallback.h>
 #include <aidl/android/hardware/automotive/audiocontrol/MutingInfo.h>
+#include <aidl/android/hardware/automotive/audiocontrol/Reasons.h>
+
+#include <aidl/android/hardware/audio/common/PlaybackTrackMetadata.h>
 
 namespace aidl::android::hardware::automotive::audiocontrol {
 
+namespace audiohalcommon = ::aidl::android::hardware::audio::common;
+namespace audiomediacommon = ::aidl::android::media::audio::common;
+
 class AudioControl : public BnAudioControl {
   public:
     ndk::ScopedAStatus onAudioFocusChange(const std::string& in_usage, int32_t in_zoneId,
@@ -35,6 +43,15 @@
             const std::shared_ptr<IFocusListener>& in_listener) override;
     ndk::ScopedAStatus setBalanceTowardRight(float in_value) override;
     ndk::ScopedAStatus setFadeTowardFront(float in_value) override;
+    ndk::ScopedAStatus onAudioFocusChangeWithMetaData(
+            const audiohalcommon::PlaybackTrackMetadata& in_playbackMetaData, int32_t in_zoneId,
+            AudioFocusChange in_focusChange) override;
+    ndk::ScopedAStatus setAudioDeviceGainsChanged(
+            const std::vector<Reasons>& in_reasons,
+            const std::vector<AudioGainConfigInfo>& in_gains) override;
+    ndk::ScopedAStatus registerGainCallback(
+            const std::shared_ptr<IAudioGainCallback>& in_callback) override;
+
     binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
 
   private:
@@ -44,9 +61,22 @@
     // listener, then it should also include mutexes or make the listener atomic.
     std::shared_ptr<IFocusListener> mFocusListener;
 
+    /**
+     * @brief mAudioGainCallback will be used by this HAL instance to communicate e.g. with a single
+     * instance of CarAudioService to report unexpected gain changed.
+     */
+    std::shared_ptr<IAudioGainCallback> mAudioGainCallback = nullptr;
+
     binder_status_t cmdHelp(int fd) const;
     binder_status_t cmdRequestFocus(int fd, const char** args, uint32_t numArgs);
     binder_status_t cmdAbandonFocus(int fd, const char** args, uint32_t numArgs);
+    binder_status_t cmdRequestFocusWithMetaData(int fd, const char** args, uint32_t numArgs);
+    binder_status_t cmdAbandonFocusWithMetaData(int fd, const char** args, uint32_t numArgs);
+    binder_status_t cmdOnAudioDeviceGainsChanged(int fd, const char** args, uint32_t numArgs);
+
+    binder_status_t parseMetaData(int fd, const std::string& metadataLiteral,
+                                  audiohalcommon::PlaybackTrackMetadata& trackMetadata);
+
     binder_status_t dumpsys(int fd);
 };
 
diff --git a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
index f95d05f..e82f6fa 100644
--- a/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
+++ b/automotive/audiocontrol/aidl/default/audiocontrol-default.xml
@@ -1,4 +1,4 @@
-<manifest version="1.0" type="device">
+<manifest version="2.0" type="device">
     <hal format="aidl">
         <name>android.hardware.automotive.audiocontrol</name>
         <fqname>IAudioControl/default</fqname>
diff --git a/automotive/audiocontrol/aidl/vts/Android.bp b/automotive/audiocontrol/aidl/vts/Android.bp
index 6856b91..3d4be48 100644
--- a/automotive/audiocontrol/aidl/vts/Android.bp
+++ b/automotive/audiocontrol/aidl/vts/Android.bp
@@ -37,11 +37,16 @@
         "libxml2",
     ],
     static_libs: [
-        "android.hardware.automotive.audiocontrol-V1-cpp",
+        "android.hardware.automotive.audiocontrol-V2-cpp",
+        "android.hardware.audio.common-V1-cpp",
+        "android.media.audio.common.types-V1-cpp",
         "libgmock",
     ],
     test_suites: [
         "general-tests",
         "vts",
     ],
+    cflags: [
+        "-Wno-deprecated-declarations",
+    ],
 }
diff --git a/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp b/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp
index ae53c68..f4f5eef 100644
--- a/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp
+++ b/automotive/audiocontrol/aidl/vts/VtsHalAudioControlTargetTest.cpp
@@ -19,6 +19,7 @@
 #include <aidl/Vintf.h>
 #include <gmock/gmock.h>
 
+#include <android/hardware/automotive/audiocontrol/BnAudioGainCallback.h>
 #include <android/hardware/automotive/audiocontrol/BnFocusListener.h>
 #include <android/hardware/automotive/audiocontrol/IAudioControl.h>
 #include <android/log.h>
@@ -30,10 +31,13 @@
 using android::String16;
 using android::binder::Status;
 using android::hardware::automotive::audiocontrol::AudioFocusChange;
+using android::hardware::automotive::audiocontrol::AudioGainConfigInfo;
+using android::hardware::automotive::audiocontrol::BnAudioGainCallback;
 using android::hardware::automotive::audiocontrol::BnFocusListener;
 using android::hardware::automotive::audiocontrol::DuckingInfo;
 using android::hardware::automotive::audiocontrol::IAudioControl;
 using android::hardware::automotive::audiocontrol::MutingInfo;
+using android::hardware::automotive::audiocontrol::Reasons;
 
 #include "android_audio_policy_configuration_V7_0.h"
 
@@ -41,6 +45,9 @@
 using namespace android::audio::policy::configuration::V7_0;
 }
 
+namespace audiohalcommon = android::hardware::audio::common;
+namespace audiomediacommon = android::media::audio::common;
+
 class AudioControlAidl : public testing::TestWithParam<std::string> {
   public:
     virtual void SetUp() override {
@@ -103,6 +110,11 @@
     MOCK_METHOD(Status, requestAudioFocus,
                 (const String16& usage, int32_t zoneId, AudioFocusChange focusGain));
     MOCK_METHOD(Status, abandonAudioFocus, (const String16& usage, int32_t zoneId));
+    MOCK_METHOD(Status, requestAudioFocusWithMetaData,
+                (const audiohalcommon::PlaybackTrackMetadata& metaData, int32_t zoneId,
+                 AudioFocusChange focusGain));
+    MOCK_METHOD(Status, abandonAudioFocusWithMetaData,
+                (const audiohalcommon::PlaybackTrackMetadata& metaData, int32_t zoneId));
 };
 
 /*
@@ -159,6 +171,61 @@
     ASSERT_TRUE(audioControl->onDevicesToDuckChange(duckingInfos).isOk());
 }
 
+TEST_P(AudioControlAidl, FocusChangeWithMetaDataExercise) {
+    ALOGI("Focus Change test");
+
+    audiohalcommon::PlaybackTrackMetadata metadata;
+    metadata.usage = audiomediacommon::AudioUsage::MEDIA;
+    metadata.contentType = audiomediacommon::AudioContentType::MUSIC;
+    metadata.tags = {"com.google.android=VR"};
+    ASSERT_TRUE(
+            audioControl
+                    ->onAudioFocusChangeWithMetaData(metadata, 0, AudioFocusChange::GAIN_TRANSIENT)
+                    .isOk());
+};
+
+TEST_P(AudioControlAidl, SetAudioDeviceGainsChangedExercise) {
+    ALOGI("Set Audio Gains Changed test");
+
+    const std::vector<Reasons> reasons{Reasons::FORCED_MASTER_MUTE, Reasons::NAV_DUCKING};
+    AudioGainConfigInfo agci1;
+    agci1.zoneId = 0;
+    agci1.devicePortAddress = String16("address 1");
+    agci1.volumeIndex = 8;
+
+    AudioGainConfigInfo agci2;
+    agci1.zoneId = 0;
+    agci1.devicePortAddress = String16("address 2");
+    agci1.volumeIndex = 1;
+
+    std::vector<AudioGainConfigInfo> gains{agci1, agci2};
+    ASSERT_TRUE(audioControl->setAudioDeviceGainsChanged(reasons, gains).isOk());
+}
+
+/*
+ * Test Audio Gain Callback registration.
+ *
+ * Verifies that:
+ * - registerGainCallback succeeds;
+ * - registering a second callback succeeds in replacing the first;
+ * - closing handle does not crash;
+ */
+struct AudioGainCallbackMock : BnAudioGainCallback {
+    MOCK_METHOD(Status, onAudioDeviceGainsChanged,
+                (const std::vector<Reasons>& reasons,
+                 const std::vector<AudioGainConfigInfo>& gains));
+};
+
+TEST_P(AudioControlAidl, AudioGainCallbackRegistration) {
+    ALOGI("Focus listener test");
+
+    sp<AudioGainCallbackMock> gainCallback = new AudioGainCallbackMock();
+    ASSERT_TRUE(audioControl->registerGainCallback(gainCallback).isOk());
+
+    sp<AudioGainCallbackMock> gainCallback2 = new AudioGainCallbackMock();
+    ASSERT_TRUE(audioControl->registerGainCallback(gainCallback2).isOk());
+}
+
 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioControlAidl);
 INSTANTIATE_TEST_SUITE_P(
         Audiocontrol, AudioControlAidl,
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
index 0dd8148..2a88959 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.cpp
@@ -45,6 +45,7 @@
   latency_modes_ = latencyModes;
   audio_config_ = std::make_unique<AudioConfiguration>(audio_config);
   stack_iface_ = host_if;
+  is_binder_died = false;
 
   AIBinder_linkToDeath(stack_iface_->asBinder().get(), death_recipient_.get(),
                        this);
@@ -59,8 +60,10 @@
   if (stack_iface_ != nullptr) {
     BluetoothAudioSessionReport::OnSessionEnded(session_type_);
 
-    AIBinder_unlinkToDeath(stack_iface_->asBinder().get(),
-                           death_recipient_.get(), this);
+    if (!is_binder_died) {
+      AIBinder_unlinkToDeath(stack_iface_->asBinder().get(),
+                             death_recipient_.get(), this);
+    }
   } else {
     LOG(INFO) << __func__ << " - SessionType=" << toString(session_type_)
               << " has NO session";
@@ -147,6 +150,7 @@
     LOG(ERROR) << __func__ << ": Null AudioProvider HAL died";
     return;
   }
+  provider->is_binder_died = true;
   provider->endSession();
 }
 
diff --git a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
index a9f830a..dbfff7d 100644
--- a/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
+++ b/bluetooth/audio/aidl/default/BluetoothAudioProvider.h
@@ -62,6 +62,7 @@
   std::unique_ptr<AudioConfiguration> audio_config_ = nullptr;
   SessionType session_type_;
   std::vector<LatencyMode> latency_modes_;
+  bool is_binder_died = false;
 };
 
 }  // namespace audio
diff --git a/keymaster/4.0/support/fuzzer/Android.bp b/keymaster/4.0/support/fuzzer/Android.bp
index 3a3f4d5..8bc681a 100644
--- a/keymaster/4.0/support/fuzzer/Android.bp
+++ b/keymaster/4.0/support/fuzzer/Android.bp
@@ -30,12 +30,12 @@
         "libbase",
         "liblog",
         "libkeymaster4support",
-        "libutils",
     ],
     shared_libs: [
         "android.hardware.keymaster@4.0",
         "libcrypto",
         "libhidlbase",
+        "libutils",
     ],
     fuzz_config: {
         cc: [
diff --git a/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp b/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
index d9a6363..5fa13e7 100644
--- a/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
+++ b/media/omx/1.0/vts/functional/store/VtsHalMediaOmxV1_0TargetStoreTest.cpp
@@ -24,6 +24,7 @@
 #include <android-base/strings.h>
 #include <android/api-level.h>
 
+#include <VtsCoreUtil.h>
 #include <android/hardware/media/omx/1.0/IOmx.h>
 #include <android/hardware/media/omx/1.0/IOmxNode.h>
 #include <android/hardware/media/omx/1.0/IOmxObserver.h>
@@ -377,6 +378,10 @@
     return android::base::GetIntProperty("ro.product.first_api_level", __ANDROID_API_T__);
 }
 
+static bool isTV() {
+    return testing::deviceSupportsFeature("android.software.leanback");
+}
+
 // list components and roles.
 TEST_P(StoreHidlTest, OmxCodecAllowedTest) {
     hidl_vec<IOmx::ComponentInfo> componentInfos = getComponentInfoList(omx);
@@ -384,9 +389,16 @@
         for (std::string role : info.mRoles) {
             if (role.find("video_decoder") != std::string::npos ||
                 role.find("video_encoder") != std::string::npos) {
-                ASSERT_LT(getFirstApiLevel(), __ANDROID_API_S__)
-                        << " Component: " << info.mName.c_str() << " Role: " << role.c_str()
-                        << " not allowed for devices launching with Android S and above";
+                // Codec2 is not mandatory on Android TV devices that launched with Android S
+                if (isTV()) {
+                    ASSERT_LT(getFirstApiLevel(), __ANDROID_API_T__)
+                            << " Component: " << info.mName.c_str() << " Role: " << role.c_str()
+                            << " not allowed for devices launching with Android T and above";
+                } else {
+                    ASSERT_LT(getFirstApiLevel(), __ANDROID_API_S__)
+                            << " Component: " << info.mName.c_str() << " Role: " << role.c_str()
+                            << " not allowed for devices launching with Android S and above";
+                }
             }
             if (role.find("audio_decoder") != std::string::npos ||
                 role.find("audio_encoder") != std::string::npos) {
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index 2476430..c328879 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -10,6 +10,7 @@
 aidl_interface {
     name: "android.hardware.radio",
     vendor_available: true,
+    host_supported: true,
     srcs: ["android/hardware/radio/*.aidl"],
     stability: "vintf",
     backend: {
@@ -30,6 +31,7 @@
 aidl_interface {
     name: "android.hardware.radio.config",
     vendor_available: true,
+    host_supported: true,
     srcs: ["android/hardware/radio/config/*.aidl"],
     stability: "vintf",
     imports: ["android.hardware.radio"],
@@ -58,6 +60,7 @@
 aidl_interface {
     name: "android.hardware.radio.data",
     vendor_available: true,
+    host_supported: true,
     srcs: ["android/hardware/radio/data/*.aidl"],
     stability: "vintf",
     imports: ["android.hardware.radio"],
@@ -86,6 +89,7 @@
 aidl_interface {
     name: "android.hardware.radio.messaging",
     vendor_available: true,
+    host_supported: true,
     srcs: ["android/hardware/radio/messaging/*.aidl"],
     stability: "vintf",
     imports: ["android.hardware.radio"],
@@ -107,6 +111,7 @@
 aidl_interface {
     name: "android.hardware.radio.modem",
     vendor_available: true,
+    host_supported: true,
     srcs: ["android/hardware/radio/modem/*.aidl"],
     stability: "vintf",
     imports: ["android.hardware.radio"],
@@ -135,6 +140,7 @@
 aidl_interface {
     name: "android.hardware.radio.network",
     vendor_available: true,
+    host_supported: true,
     srcs: ["android/hardware/radio/network/*.aidl"],
     stability: "vintf",
     imports: ["android.hardware.radio"],
@@ -163,6 +169,7 @@
 aidl_interface {
     name: "android.hardware.radio.sim",
     vendor_available: true,
+    host_supported: true,
     srcs: ["android/hardware/radio/sim/*.aidl"],
     stability: "vintf",
     imports: [
@@ -197,6 +204,7 @@
 aidl_interface {
     name: "android.hardware.radio.voice",
     vendor_available: true,
+    host_supported: true,
     srcs: ["android/hardware/radio/voice/*.aidl"],
     stability: "vintf",
     imports: ["android.hardware.radio"],
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
index c99da41..07e3e3c 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.cpp
@@ -640,6 +640,48 @@
     testTimeFilter(timeFilterMap[timeFilter.timeFilterId]);
 }
 
+static bool isEventProducingFilter(const FilterConfig& filterConfig) {
+    switch (filterConfig.type.mainType) {
+        case DemuxFilterMainType::TS: {
+            auto tsFilterType =
+                    filterConfig.type.subType.get<DemuxFilterSubType::Tag::tsFilterType>();
+            return (tsFilterType == DemuxTsFilterType::SECTION ||
+                    tsFilterType == DemuxTsFilterType::PES ||
+                    tsFilterType == DemuxTsFilterType::AUDIO ||
+                    tsFilterType == DemuxTsFilterType::VIDEO ||
+                    tsFilterType == DemuxTsFilterType::RECORD ||
+                    tsFilterType == DemuxTsFilterType::TEMI);
+        }
+        case DemuxFilterMainType::MMTP: {
+            auto mmtpFilterType =
+                    filterConfig.type.subType.get<DemuxFilterSubType::Tag::mmtpFilterType>();
+            return (mmtpFilterType == DemuxMmtpFilterType::SECTION ||
+                    mmtpFilterType == DemuxMmtpFilterType::PES ||
+                    mmtpFilterType == DemuxMmtpFilterType::AUDIO ||
+                    mmtpFilterType == DemuxMmtpFilterType::VIDEO ||
+                    mmtpFilterType == DemuxMmtpFilterType::RECORD ||
+                    mmtpFilterType == DemuxMmtpFilterType::DOWNLOAD);
+        }
+        case DemuxFilterMainType::IP: {
+            auto ipFilterType =
+                    filterConfig.type.subType.get<DemuxFilterSubType::Tag::ipFilterType>();
+            return (ipFilterType == DemuxIpFilterType::SECTION);
+        }
+        case DemuxFilterMainType::TLV: {
+            auto tlvFilterType =
+                    filterConfig.type.subType.get<DemuxFilterSubType::Tag::tlvFilterType>();
+            return (tlvFilterType == DemuxTlvFilterType::SECTION);
+        }
+        case DemuxFilterMainType::ALP: {
+            auto alpFilterType =
+                    filterConfig.type.subType.get<DemuxFilterSubType::Tag::alpFilterType>();
+            return (alpFilterType == DemuxAlpFilterType::SECTION);
+        }
+        default:
+            return false;
+    }
+}
+
 static bool isMediaFilter(const FilterConfig& filterConfig) {
     switch (filterConfig.type.mainType) {
         case DemuxFilterMainType::TS: {
@@ -685,6 +727,12 @@
 
 // TODO: move boilerplate into text fixture
 void TunerFilterAidlTest::testDelayHint(const FilterConfig& filterConf) {
+    if (!filterConf.timeDelayInMs && !filterConf.dataDelayInBytes) {
+        return;
+    }
+    if (!isEventProducingFilter(filterConf)) {
+        return;
+    }
     int32_t feId;
     int32_t demuxId;
     std::shared_ptr<IDemux> demux;
@@ -707,11 +755,11 @@
     // startTime needs to be set before calling setDelayHint.
     auto startTime = std::chrono::steady_clock::now();
 
-    auto timeDelayInMs = std::chrono::milliseconds(filterConf.timeDelayInMs);
-    if (timeDelayInMs.count() > 0) {
+    int timeDelayInMs = filterConf.timeDelayInMs;
+    if (timeDelayInMs > 0) {
         FilterDelayHint delayHint;
         delayHint.hintType = FilterDelayHintType::TIME_DELAY_IN_MS;
-        delayHint.hintValue = timeDelayInMs.count();
+        delayHint.hintValue = timeDelayInMs;
 
         // setDelayHint should fail for media filters.
         ASSERT_EQ(filter->setDelayHint(delayHint).isOk(), !mediaFilter);
@@ -733,6 +781,10 @@
     auto cb = mFilterTests.getFilterCallbacks().at(filterId);
     auto future =
             cb->verifyFilterCallback([](const std::vector<DemuxFilterEvent>&) { return true; });
+
+    // The configure stage can also produce events, so we should set the delay
+    // hint beforehand.
+    ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
     mFilterTests.startFilter(filterId);
 
     auto timeout = std::chrono::seconds(30);
@@ -750,20 +802,16 @@
                     return true;
                 });
 
-        // The configure stage can also produce events, so we should set the delay
-        // hint beforehand.
-        ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
-
         ASSERT_TRUE(mFilterTests.startFilter(filterId));
 
         // block and wait for callback to be received.
         ASSERT_EQ(future.wait_for(timeout), std::future_status::ready);
-        auto duration = std::chrono::steady_clock::now() - startTime;
 
-        bool delayHintTest = duration >= timeDelayInMs;
+        auto duration = std::chrono::steady_clock::now() - startTime;
+        bool delayHintTest = duration >= std::chrono::milliseconds(timeDelayInMs);
         bool dataSizeTest = callbackSize >= dataDelayInBytes;
 
-        if (timeDelayInMs.count() > 0 && dataDelayInBytes > 0) {
+        if (timeDelayInMs > 0 && dataDelayInBytes > 0) {
             ASSERT_TRUE(delayHintTest || dataSizeTest);
         } else {
             // if only one of time delay / data delay is configured, one of them
@@ -781,7 +829,9 @@
 
 TEST_P(TunerFilterAidlTest, FilterDelayHintTest) {
     description("Test filter time delay hint.");
-
+    if (!live.hasFrontendConnection) {
+        return;
+    }
     for (const auto& obj : filterMap) {
         testDelayHint(obj.second);
     }
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
index 5a72ba4..5f1f9c5 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTestConfigurations.h
@@ -175,9 +175,14 @@
         ALOGW("[vts config] Record must support either a DVR source or a Frontend source.");
         return false;
     }
-    bool feIsValid = frontendMap.find(live.frontendId) != frontendMap.end() &&
-                     frontendMap.find(scan.frontendId) != frontendMap.end();
-    feIsValid &= record.support ? frontendMap.find(record.frontendId) != frontendMap.end() : true;
+    bool feIsValid = live.hasFrontendConnection
+                             ? frontendMap.find(live.frontendId) != frontendMap.end()
+                             : true;
+    feIsValid &= scan.hasFrontendConnection ? frontendMap.find(scan.frontendId) != frontendMap.end()
+                                            : true;
+    feIsValid &= record.support && record.hasFrontendConnection
+                         ? frontendMap.find(record.frontendId) != frontendMap.end()
+                         : true;
 
     if (!feIsValid) {
         ALOGW("[vts config] dynamic config fe connection is invalid.");
@@ -204,8 +209,10 @@
         return false;
     }
 
-    bool filterIsValid = filterMap.find(live.audioFilterId) != filterMap.end() &&
-                         filterMap.find(live.videoFilterId) != filterMap.end();
+    bool filterIsValid = (live.hasFrontendConnection)
+                             ? filterMap.find(live.audioFilterId) != filterMap.end() &&
+                               filterMap.find(live.videoFilterId) != filterMap.end()
+                             : true;
     filterIsValid &=
             record.support ? filterMap.find(record.recordFilterId) != filterMap.end() : true;
 
diff --git a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
index 3009c4a..189f5fd 100644
--- a/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
+++ b/tv/tuner/config/TunerTestingConfigAidlReaderV1_0.h
@@ -867,6 +867,8 @@
                         settings.set<DemuxFilterSettings::Tag::ip>(ip);
                         break;
                     case FilterSubTypeEnum::IP: {
+                        type.subType.set<DemuxFilterSubType::Tag::ipFilterType>(
+                                DemuxIpFilterType::IP);
                         ip.ipAddr = readIpAddress(filterConfig),
                         ip.filterSettings
                                 .set<DemuxIpFilterSettingsFilterSettings::Tag::bPassthrough>(
diff --git a/wifi/1.6/default/wifi_legacy_hal.cpp b/wifi/1.6/default/wifi_legacy_hal.cpp
index 8a75fd8..bb8cf59 100644
--- a/wifi/1.6/default/wifi_legacy_hal.cpp
+++ b/wifi/1.6/default/wifi_legacy_hal.cpp
@@ -1549,13 +1549,14 @@
 
 std::pair<wifi_error, wifi_radio_combination_matrix*>
 WifiLegacyHal::getSupportedRadioCombinationsMatrix() {
-    std::array<char, kMaxSupportedRadioCombinationsMatrixLength> buffer;
-    buffer.fill(0);
+    char* buffer = new char[kMaxSupportedRadioCombinationsMatrixLength];
+    std::fill(buffer, buffer + kMaxSupportedRadioCombinationsMatrixLength, 0);
     uint32_t size = 0;
     wifi_radio_combination_matrix* radio_combination_matrix_ptr =
-            reinterpret_cast<wifi_radio_combination_matrix*>(buffer.data());
+            reinterpret_cast<wifi_radio_combination_matrix*>(buffer);
     wifi_error status = global_func_table_.wifi_get_supported_radio_combinations_matrix(
-            global_handle_, buffer.size(), &size, radio_combination_matrix_ptr);
+            global_handle_, kMaxSupportedRadioCombinationsMatrixLength, &size,
+            radio_combination_matrix_ptr);
     CHECK(size >= 0 && size <= kMaxSupportedRadioCombinationsMatrixLength);
     return {status, radio_combination_matrix_ptr};
 }