APM: update logic of populating profiles for dynamic mix port.

For AIDL HAL, use getAudioPort API to query the profiles for the dynamic
mix ports.

For HIDL HAL, if the HAL supports getAudioPort API, add the profiles of
the device port that contain attributes also reported by getParameters
API. The attributes reported by getParameters API but not in device port
will also be added to mix port.

The reason of using getAudioPort API instead of getParameters is that
getAudioPort API can return well structed audio profiles, which show the
correct relationship between audio format and sample rates, channel
masks.

Test: repo steps from the bug
Test: atest audiofoundation_containers_test
Test: atest audiopolicy_tests
Bug: 284033428
Change-Id: I6d3faf49470514c05fe57be755bb868d74d74dbb
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 4bd12b8..01edf72 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -898,6 +898,22 @@
     return NO_ERROR;
 }
 
+status_t AudioFlingerClientAdapter::getAudioMixPort(const struct audio_port_v7 *devicePort,
+                                                    struct audio_port_v7 *mixPort) const {
+    if (devicePort == nullptr || mixPort == nullptr) {
+        return BAD_VALUE;
+    }
+    media::AudioPortFw devicePortAidl = VALUE_OR_RETURN_STATUS(
+            legacy2aidl_audio_port_v7_AudioPortFw(*devicePort));
+    media::AudioPortFw mixPortAidl = VALUE_OR_RETURN_STATUS(
+            legacy2aidl_audio_port_v7_AudioPortFw(*mixPort));
+    media::AudioPortFw aidlRet;
+    RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+            mDelegate->getAudioMixPort(devicePortAidl, mixPortAidl, &aidlRet)));
+    *mixPort = VALUE_OR_RETURN_STATUS(aidl2legacy_AudioPortFw_audio_port_v7(aidlRet));
+    return OK;
+}
+
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 // AudioFlingerServerAdapter
 AudioFlingerServerAdapter::AudioFlingerServerAdapter(
@@ -1444,4 +1460,16 @@
     return Status::fromStatusT(mDelegate->getAudioPolicyConfig(_aidl_return));
 }
 
+Status AudioFlingerServerAdapter::getAudioMixPort(const media::AudioPortFw &devicePort,
+                                                  const media::AudioPortFw &mixPort,
+                                                  media::AudioPortFw *_aidl_return) {
+    audio_port_v7 devicePortLegacy = VALUE_OR_RETURN_BINDER(
+            aidl2legacy_AudioPortFw_audio_port_v7(devicePort));
+    audio_port_v7 mixPortLegacy = VALUE_OR_RETURN_BINDER(
+            aidl2legacy_AudioPortFw_audio_port_v7(mixPort));
+    RETURN_BINDER_IF_ERROR(mDelegate->getAudioMixPort(&devicePortLegacy, &mixPortLegacy));
+    *_aidl_return = VALUE_OR_RETURN_BINDER(legacy2aidl_audio_port_v7_AudioPortFw(mixPortLegacy));
+    return Status::ok();
+}
+
 } // namespace android
diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
index 6412810..31d3af5 100644
--- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
@@ -288,6 +288,11 @@
      */
     AudioPolicyConfig getAudioPolicyConfig();
 
+    /**
+     * Get the attributes of the mix port when connecting to the given device port.
+     */
+    AudioPortFw getAudioMixPort(in AudioPortFw devicePort, in AudioPortFw mixPort);
+
     // When adding a new method, please review and update
     // IAudioFlinger.h AudioFlingerServerAdapter::Delegate::TransactionCode
     // AudioFlinger.cpp AudioFlinger::onTransactWrapper()
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 3c96862..eb27e25 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -384,6 +384,9 @@
     virtual status_t supportsBluetoothVariableLatency(bool* support) const = 0;
 
     virtual status_t getAudioPolicyConfig(media::AudioPolicyConfig* output) = 0;
+
+    virtual status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
+                                     struct audio_port_v7 *mixPort) const = 0;
 };
 
 /**
@@ -498,6 +501,8 @@
                                    sp<media::ISoundDose>* soundDose) const override;
     status_t invalidateTracks(const std::vector<audio_port_handle_t>& portIds) override;
     status_t getAudioPolicyConfig(media::AudioPolicyConfig* output) override;
+    status_t getAudioMixPort(const struct audio_port_v7 *devicePort,
+                             struct audio_port_v7 *mixPort) const override;
 
 private:
     const sp<media::IAudioFlingerService> mDelegate;
@@ -599,6 +604,7 @@
             INVALIDATE_TRACKS = media::BnAudioFlingerService::TRANSACTION_invalidateTracks,
             GET_AUDIO_POLICY_CONFIG =
                     media::BnAudioFlingerService::TRANSACTION_getAudioPolicyConfig,
+            GET_AUDIO_MIX_PORT = media::BnAudioFlingerService::TRANSACTION_getAudioMixPort,
         };
 
     protected:
@@ -732,6 +738,9 @@
                                  sp<media::ISoundDose>* _aidl_return) override;
     Status invalidateTracks(const std::vector<int32_t>& portIds) override;
     Status getAudioPolicyConfig(media::AudioPolicyConfig* _aidl_return) override;
+    Status getAudioMixPort(const media::AudioPortFw& devicePort,
+                           const media::AudioPortFw& mixPort,
+                           media::AudioPortFw* _aidl_return) override;
 private:
     const sp<AudioFlingerServerAdapter::Delegate> mDelegate;
 };
diff --git a/media/libaudiofoundation/AudioContainers.cpp b/media/libaudiofoundation/AudioContainers.cpp
index 3034b9a..e1265cf 100644
--- a/media/libaudiofoundation/AudioContainers.cpp
+++ b/media/libaudiofoundation/AudioContainers.cpp
@@ -130,4 +130,104 @@
     return ss.str();
 }
 
+AudioProfileAttributesMultimap createAudioProfilesAttrMap(audio_profile profiles[],
+                                                          uint32_t first,
+                                                          uint32_t last) {
+    AudioProfileAttributesMultimap result;
+    for (uint32_t i = first; i < last; ++i) {
+        SampleRateSet sampleRates(profiles[i].sample_rates,
+                                  profiles[i].sample_rates + profiles[i].num_sample_rates);
+        ChannelMaskSet channelMasks(profiles[i].channel_masks,
+                                    profiles[i].channel_masks + profiles[i].num_channel_masks);
+        result.emplace(profiles[i].format, std::make_pair(sampleRates, channelMasks));
+    }
+    return result;
+}
+
+namespace {
+
+void populateAudioProfile(audio_format_t format,
+                          const ChannelMaskSet& channelMasks,
+                          const SampleRateSet& samplingRates,
+                          audio_profile* profile) {
+    profile->format = format;
+    profile->num_channel_masks = 0;
+    for (auto it = channelMasks.begin();
+         it != channelMasks.end() && profile->num_channel_masks < AUDIO_PORT_MAX_CHANNEL_MASKS;
+         ++it) {
+        profile->channel_masks[profile->num_channel_masks++] = *it;
+    }
+    profile->num_sample_rates = 0;
+    for (auto it = samplingRates.begin();
+         it != samplingRates.end() && profile->num_sample_rates < AUDIO_PORT_MAX_SAMPLING_RATES;
+         ++it) {
+        profile->sample_rates[profile->num_sample_rates++] = *it;
+    }
+}
+
+} // namespace
+
+void populateAudioProfiles(const AudioProfileAttributesMultimap& profileAttrs,
+                           audio_format_t format,
+                           ChannelMaskSet allChannelMasks,
+                           SampleRateSet allSampleRates,
+                           audio_profile audioProfiles[],
+                           uint32_t* numAudioProfiles,
+                           uint32_t maxAudioProfiles) {
+    if (*numAudioProfiles >= maxAudioProfiles) {
+        return;
+    }
+
+    const auto lower= profileAttrs.lower_bound(format);
+    const auto upper = profileAttrs.upper_bound(format);
+    SampleRateSet sampleRatesPresent;
+    ChannelMaskSet channelMasksPresent;
+    for (auto it = lower; it != upper && *numAudioProfiles < maxAudioProfiles; ++it) {
+        SampleRateSet srs;
+        std::set_intersection(it->second.first.begin(), it->second.first.end(),
+                              allSampleRates.begin(), allSampleRates.end(),
+                              std::inserter(srs, srs.begin()));
+        if (srs.empty()) {
+            continue;
+        }
+        ChannelMaskSet cms;
+        std::set_intersection(it->second.second.begin(), it->second.second.end(),
+                              allChannelMasks.begin(), allChannelMasks.end(),
+                              std::inserter(cms, cms.begin()));
+        if (cms.empty()) {
+            continue;
+        }
+        sampleRatesPresent.insert(srs.begin(), srs.end());
+        channelMasksPresent.insert(cms.begin(), cms.end());
+        populateAudioProfile(it->first, cms, srs,
+                             &audioProfiles[(*numAudioProfiles)++]);
+    }
+    if (*numAudioProfiles >= maxAudioProfiles) {
+        ALOGW("%s, too many audio profiles", __func__);
+        return;
+    }
+
+    SampleRateSet srs;
+    std::set_difference(allSampleRates.begin(), allSampleRates.end(),
+                        sampleRatesPresent.begin(), sampleRatesPresent.end(),
+                        std::inserter(srs, srs.begin()));
+    if (!srs.empty()) {
+        populateAudioProfile(format, allChannelMasks, srs,
+                             &audioProfiles[(*numAudioProfiles)++]);
+    }
+    if (*numAudioProfiles >= maxAudioProfiles) {
+        ALOGW("%s, too many audio profiles", __func__);
+        return;
+    }
+    ChannelMaskSet cms;
+    std::set_difference(allChannelMasks.begin(), allChannelMasks.end(),
+                        channelMasksPresent.begin(), channelMasksPresent.end(),
+                        std::inserter(cms, cms.begin()));
+    if (!cms.empty()) {
+        populateAudioProfile(format, cms, allSampleRates,
+                             &audioProfiles[(*numAudioProfiles)++]);
+    }
+
+}
+
 } // namespace android
diff --git a/media/libaudiofoundation/AudioProfile.cpp b/media/libaudiofoundation/AudioProfile.cpp
index 999e263..4a5fb96 100644
--- a/media/libaudiofoundation/AudioProfile.cpp
+++ b/media/libaudiofoundation/AudioProfile.cpp
@@ -383,6 +383,16 @@
     }
 }
 
+ChannelMaskSet AudioProfileVector::getSupportedChannelMasks() const {
+    ChannelMaskSet channelMasks;
+    for (const auto& profile : *this) {
+        if (profile->isValid()) {
+            channelMasks.insert(profile->getChannels().begin(), profile->getChannels().end());
+        }
+    }
+    return channelMasks;
+}
+
 ConversionResult<AudioProfileVector>
 aidl2legacy_AudioProfileVector(const AudioProfileVector::Aidl& aidl, bool isInput) {
     return convertContainers<AudioProfileVector>(aidl.first, aidl.second,
diff --git a/media/libaudiofoundation/TEST_MAPPING b/media/libaudiofoundation/TEST_MAPPING
index a4e271e..f7e5b12 100644
--- a/media/libaudiofoundation/TEST_MAPPING
+++ b/media/libaudiofoundation/TEST_MAPPING
@@ -20,5 +20,10 @@
         }
       ]
     }
+  ],
+  "postsubmit": [
+    {
+      "name": "audiofoundation_containers_test"
+    }
   ]
 }
diff --git a/media/libaudiofoundation/include/media/AudioContainers.h b/media/libaudiofoundation/include/media/AudioContainers.h
index f22ee40..46fd620 100644
--- a/media/libaudiofoundation/include/media/AudioContainers.h
+++ b/media/libaudiofoundation/include/media/AudioContainers.h
@@ -19,6 +19,7 @@
 #include <algorithm>
 #include <functional>
 #include <iterator>
+#include <map>
 #include <set>
 #include <vector>
 
@@ -34,6 +35,8 @@
 using MixerBehaviorSet = std::set<audio_mixer_behavior_t>;
 
 using FormatVector = std::vector<audio_format_t>;
+using AudioProfileAttributesMultimap =
+        std::multimap<audio_format_t, std::pair<SampleRateSet, ChannelMaskSet>>;
 
 const DeviceTypeSet& getAudioDeviceOutAllSet();
 const DeviceTypeSet& getAudioDeviceOutAllA2dpSet();
@@ -135,5 +138,49 @@
     return deviceTypesToString(deviceTypes);
 }
 
+/**
+ * Create audio profile attributes map by given audio profile array from the range of [first, last).
+ *
+ * @param profiles the array of audio profiles.
+ * @param first the first index of the profile.
+ * @param last the last index of the profile.
+ * @return a multipmap of audio format to pair of corresponding sample rates and channel masks set.
+ */
+AudioProfileAttributesMultimap createAudioProfilesAttrMap(audio_profile profiles[],
+                                                          uint32_t first,
+                                                          uint32_t last);
+
+/**
+ * Populate audio profiles according to given profile attributes, format, channel masks and
+ * sample rates.
+ *
+ * The function will first go over all pairs of channel masks and sample rates that are present in
+ * the profile attributes of the given map. Note that the channel masks and the sample rates that
+ * are not present in the collections of all valid channel masks and all valid sample rates will be
+ * excluded. After that, if there are channel masks and sample rates that present in the all values
+ * collection but not in profile attributes, they will also be place in a new audio profile in the
+ * profile array.
+ *
+ * Note that if the resulting index of the audio profile exceeds the maximum, no new audio profiles
+ * will be placed in the array.
+ *
+ * @param profileAttrs a multimap that contains format and its corresponding channel masks and
+ *                     sample rates.
+ * @param format the targeted audio format.
+ * @param allChannelMasks all valid channel masks for the format.
+ * @param allSampleRates all valid sample rates for the format.
+ * @param audioProfiles the audio profile array.
+ * @param numAudioProfiles the start index to put audio profile in the array. The value will be
+ *                         updated if there is new audio profile placed.
+ * @param maxAudioProfiles the maximum number of audio profile.
+ */
+void populateAudioProfiles(const AudioProfileAttributesMultimap& profileAttrs,
+                           audio_format_t format,
+                           ChannelMaskSet allChannelMasks,
+                           SampleRateSet allSampleRates,
+                           audio_profile audioProfiles[],
+                           uint32_t* numAudioProfiles,
+                           uint32_t maxAudioProfiles = AUDIO_PORT_MAX_AUDIO_PROFILES);
+
 
 } // namespace android
diff --git a/media/libaudiofoundation/include/media/AudioProfile.h b/media/libaudiofoundation/include/media/AudioProfile.h
index a668afe..bcde1fe 100644
--- a/media/libaudiofoundation/include/media/AudioProfile.h
+++ b/media/libaudiofoundation/include/media/AudioProfile.h
@@ -149,6 +149,8 @@
     bool equals(const AudioProfileVector& other) const;
     void addAllValidProfiles(const AudioProfileVector& audioProfiles);
 
+    ChannelMaskSet getSupportedChannelMasks() const;
+
     using Aidl = std::pair<
             std::vector<media::audio::common::AudioProfile>,
             std::vector<media::AudioProfileSys>>;
diff --git a/media/libaudiofoundation/tests/Android.bp b/media/libaudiofoundation/tests/Android.bp
index 2f4aee0..82c7db7 100644
--- a/media/libaudiofoundation/tests/Android.bp
+++ b/media/libaudiofoundation/tests/Android.bp
@@ -43,3 +43,30 @@
 
     test_suites: ["device-tests"],
 }
+
+cc_test {
+    name: "audiofoundation_containers_test",
+
+    shared_libs: [
+        "liblog",
+    ],
+
+    static_libs: [
+        "libaudiofoundation",
+    ],
+
+    header_libs: [
+        "libaudio_system_headers",
+    ],
+
+    srcs: [
+        "audiofoundation_containers_test.cpp",
+    ],
+
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+
+    test_suites: ["device-tests"],
+}
diff --git a/media/libaudiofoundation/tests/audiofoundation_containers_test.cpp b/media/libaudiofoundation/tests/audiofoundation_containers_test.cpp
new file mode 100644
index 0000000..967e2ee
--- /dev/null
+++ b/media/libaudiofoundation/tests/audiofoundation_containers_test.cpp
@@ -0,0 +1,108 @@
+/*
+ * 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 <gtest/gtest.h>
+
+#include <media/AudioContainers.h>
+
+namespace android {
+
+const static AudioProfileAttributesMultimap AUDIO_PROFILE_ATTRIBUTES = {
+        {AUDIO_FORMAT_PCM_16_BIT, {{44100, 48000},
+                                   {AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1}}},
+        {AUDIO_FORMAT_PCM_16_BIT, {{96000},
+                                   {AUDIO_CHANNEL_OUT_STEREO}}},
+        {AUDIO_FORMAT_PCM_8_24_BIT, {{48000},
+                                     {AUDIO_CHANNEL_OUT_STEREO}}}
+};
+
+TEST(PopulateAudioProfilesTest, AllAttributesMatches) {
+    const AudioProfileAttributesMultimap expected = {
+            {AUDIO_FORMAT_PCM_16_BIT, {{44100, 48000},
+                                       {AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1}}},
+            {AUDIO_FORMAT_PCM_16_BIT, {{96000},
+                                       {AUDIO_CHANNEL_OUT_STEREO}}}
+    };
+    const audio_format_t format = AUDIO_FORMAT_PCM_16_BIT;
+    const SampleRateSet allSampleRates = {44100, 48000, 96000};
+    const ChannelMaskSet allChannelMasks = {AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1};
+
+    audio_profile profiles[AUDIO_PORT_MAX_AUDIO_PROFILES];
+    uint32_t numProfiles = 0;
+    populateAudioProfiles(AUDIO_PROFILE_ATTRIBUTES, format, allChannelMasks, allSampleRates,
+                          profiles, &numProfiles);
+    ASSERT_EQ(expected, createAudioProfilesAttrMap(profiles, 0, numProfiles));
+}
+
+TEST(PopulateAudioProfilesTest, AttributesNotInAllValues) {
+    const AudioProfileAttributesMultimap expected = {
+            {AUDIO_FORMAT_PCM_16_BIT, {{48000},
+                                       {AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1}}},
+            {AUDIO_FORMAT_PCM_16_BIT, {{96000},
+                                       {AUDIO_CHANNEL_OUT_STEREO}}}
+    };
+    const audio_format_t format = AUDIO_FORMAT_PCM_16_BIT;
+    const SampleRateSet allSampleRates = {48000, 96000};
+    const ChannelMaskSet allChannelMasks = {AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1};
+
+    audio_profile profiles[AUDIO_PORT_MAX_AUDIO_PROFILES];
+    uint32_t numProfiles = 0;
+    populateAudioProfiles(AUDIO_PROFILE_ATTRIBUTES, format, allChannelMasks, allSampleRates,
+            profiles, &numProfiles);
+    ASSERT_EQ(expected, createAudioProfilesAttrMap(profiles, 0, numProfiles));
+}
+
+TEST(PopulateAudioProfilesTest, AllValuesNotInAttributes) {
+    const AudioProfileAttributesMultimap expected = {
+            {AUDIO_FORMAT_PCM_16_BIT, {{48000},
+                                       {AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1}}},
+            {AUDIO_FORMAT_PCM_16_BIT, {{96000},
+                                       {AUDIO_CHANNEL_OUT_STEREO}}},
+            {AUDIO_FORMAT_PCM_16_BIT, {{88200},
+                                       {AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO,
+                                        AUDIO_CHANNEL_OUT_7POINT1}}},
+            {AUDIO_FORMAT_PCM_16_BIT, {{48000, 88200, 96000},
+                                       {AUDIO_CHANNEL_OUT_MONO}}}
+    };
+    const audio_format_t format = AUDIO_FORMAT_PCM_16_BIT;
+    const SampleRateSet allSampleRates = {48000, 88200, 96000};
+    const ChannelMaskSet allChannelMasks =
+            {AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1};
+
+    audio_profile profiles[AUDIO_PORT_MAX_AUDIO_PROFILES];
+    uint32_t numProfiles = 0;
+    populateAudioProfiles(AUDIO_PROFILE_ATTRIBUTES, format, allChannelMasks, allSampleRates,
+            profiles, &numProfiles);
+    ASSERT_EQ(expected, createAudioProfilesAttrMap(profiles, 0, numProfiles));
+}
+
+TEST(PopulateAudioProfilesTest, NoOverflow) {
+    const audio_format_t format = AUDIO_FORMAT_PCM_16_BIT;
+    const SampleRateSet allSampleRates = {48000, 88200, 96000};
+    const ChannelMaskSet allChannelMasks =
+            {AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_7POINT1};
+
+    audio_profile profiles[AUDIO_PORT_MAX_AUDIO_PROFILES];
+    const uint32_t expectedNumProfiles = 4;
+    for (uint32_t i = 0; i <= AUDIO_PORT_MAX_AUDIO_PROFILES; ++i) {
+        uint32_t numProfiles = 0;
+        populateAudioProfiles(AUDIO_PROFILE_ATTRIBUTES, format, allChannelMasks, allSampleRates,
+                              profiles, &numProfiles, i);
+        ASSERT_EQ(std::min(i, expectedNumProfiles), numProfiles);
+    }
+}
+
+} // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 72fe32b..b7af103 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -836,6 +836,33 @@
     return OK;
 }
 
+status_t DeviceHalAidl::getAudioMixPort(const struct audio_port_v7 *devicePort,
+                                        struct audio_port_v7 *mixPort) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+    if (devicePort->type != AUDIO_PORT_TYPE_DEVICE) {
+        return BAD_VALUE;
+    }
+    if (mixPort->type != AUDIO_PORT_TYPE_MIX) {
+        return BAD_VALUE;
+    }
+    const int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
+            ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(mixPort->ext.mix.handle));
+    auto it = findPortConfig(std::nullopt /*config*/, std::nullopt/*flags*/, aidlHandle);
+    if (it == mPortConfigs.end()) {
+        ALOGE("%s, cannot find mix port config for handle=%u", __func__, aidlHandle);
+        return BAD_VALUE;
+    }
+    AudioPort port;
+    if (status_t status = getAudioPort(it->second.portId, &port); status != NO_ERROR) {
+        return status;
+    }
+    const bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
+            mixPort->role, mixPort->type)) == ::aidl::android::AudioPortDirection::INPUT;
+    *mixPort = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
+            port, isInput));
+    return NO_ERROR;
+}
+
 status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
     ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
     TIME_CHECK();
@@ -1702,7 +1729,9 @@
 }
 
 DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
-            const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
+            const std::optional<AudioConfig>& config,
+            const std::optional<AudioIoFlags>& flags,
+            int32_t ioHandle) {
     using Tag = AudioPortExt::Tag;
     return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
             [&](const auto& pair) {
@@ -1713,7 +1742,8 @@
                         "%s: stored mix port config is not fully specified: %s",
                         __func__, p.toString().c_str());
                 return p.ext.getTag() == Tag::mix &&
-                        isConfigEqualToPortConfig(config, p) &&
+                        (!config.has_value() ||
+                                isConfigEqualToPortConfig(config.value(), p)) &&
                         (!flags.has_value() || p.flags.value() == flags.value()) &&
                         p.ext.template get<Tag::mix>().handle == ioHandle; });
 }
@@ -1840,6 +1870,25 @@
     return OK;
 }
 
+status_t DeviceHalAidl::getAudioPort(int32_t portId, AudioPort* port) {
+    ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+    TIME_CHECK();
+    if (!mModule) {
+        return NO_INIT;
+    }
+    const status_t status = statusTFromBinderStatus(mModule->getAudioPort(portId, port));
+    if (status == OK) {
+        auto portIt = mPorts.find(portId);
+        if (portIt != mPorts.end()) {
+            portIt->second = *port;
+        } else {
+            ALOGW("%s, port(%d) returned successfully from the HAL but not it is not cached",
+                  __func__, portId);
+        }
+    }
+    return status;
+}
+
 void DeviceHalAidl::clearCallbacks(void* cookie) {
     std::lock_guard l(mLock);
     mCallbacks.erase(cookie);
diff --git a/media/libaudiohal/impl/DeviceHalAidl.h b/media/libaudiohal/impl/DeviceHalAidl.h
index 6f45f1f..e1fe4d1 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.h
+++ b/media/libaudiohal/impl/DeviceHalAidl.h
@@ -176,6 +176,9 @@
 
     status_t setSimulateDeviceConnections(bool enabled) override;
 
+    status_t getAudioMixPort(const struct audio_port_v7* devicePort,
+                             struct audio_port_v7* mixPort) override;
+
     status_t dump(int __unused, const Vector<String16>& __unused) override;
 
   private:
@@ -260,7 +263,7 @@
     PortConfigs::iterator findPortConfig(
             const ::aidl::android::media::audio::common::AudioDevice& device);
     PortConfigs::iterator findPortConfig(
-            const ::aidl::android::media::audio::common::AudioConfig& config,
+            const std::optional<::aidl::android::media::audio::common::AudioConfig>& config,
             const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
             int32_t ioHandle);
     bool isPortHeldByAStream(int32_t portId);
@@ -280,6 +283,7 @@
     void resetUnusedPatchesAndPortConfigs();
     void resetUnusedPortConfigs();
     status_t updateRoutes();
+    status_t getAudioPort(int32_t portId, ::aidl::android::media::audio::common::AudioPort* port);
 
     // CallbackBroker implementation
     void clearCallbacks(void* cookie) override;
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index 0d71fd3..e8e1f46 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -304,7 +304,12 @@
                 }
                 HidlUtils::audioConfigToHal(suggestedConfig, config);
             });
-    return processReturn("openOutputStream", ret, retval);
+    const status_t status = processReturn("openOutputStream", ret, retval);
+    cleanupStreams();
+    if (status == NO_ERROR) {
+        mStreams.insert({handle, *outStream});
+    }
+    return status;
 }
 
 status_t DeviceHalHidl::openInputStream(
@@ -377,7 +382,12 @@
                 }
                 HidlUtils::audioConfigToHal(suggestedConfig, config);
             });
-    return processReturn("openInputStream", ret, retval);
+    const status_t status = processReturn("openInputStream", ret, retval);
+    cleanupStreams();
+    if (status == NO_ERROR) {
+        mStreams.insert({handle, *inStream});
+    }
+    return status;
 }
 
 status_t DeviceHalHidl::supportsAudioPatches(bool *supportsPatches) {
@@ -706,4 +716,126 @@
     *supports = trueOrFalse == AudioParameter::valueTrue;
     return NO_ERROR;
 }
+
+namespace {
+
+status_t getParametersFromStream(
+        sp<StreamHalInterface> stream,
+        const char* parameters,
+        const char* extraParameters,
+        String8* reply) {
+    String8 request(parameters);
+    if (extraParameters != nullptr) {
+        request.append(";");
+        request.append(extraParameters);
+    }
+    status_t status = stream->getParameters(request, reply);
+    if (status != NO_ERROR) {
+        ALOGW("%s, failed to query %s, status=%d", __func__, parameters, status);
+        return status;
+    }
+    AudioParameter repliedParameters(*reply);
+    status = repliedParameters.get(String8(parameters), *reply);
+    if (status != NO_ERROR) {
+        ALOGW("%s: failed to retrieve %s, bailing out", __func__, parameters);
+    }
+    return status;
+}
+
+} // namespace
+
+status_t DeviceHalHidl::getAudioMixPort(const struct audio_port_v7 *devicePort,
+                                        struct audio_port_v7 *mixPort) {
+    // For HIDL HAL, querying mix port information is not supported. If the HAL supports
+    // `getAudioPort` API to query the device port attributes, use the structured audio profiles
+    // that have the same attributes reported by the `getParameters` API. Otherwise, only use
+    // the attributes reported by `getParameters` API.
+    struct audio_port_v7 temp = *devicePort;
+    AudioProfileAttributesMultimap attrsFromDevice;
+    status_t status = getAudioPort(&temp);
+    if (status == NO_ERROR) {
+        attrsFromDevice = createAudioProfilesAttrMap(temp.audio_profiles, 0 /*first*/,
+                                                     temp.num_audio_profiles);
+    }
+    auto streamIt = mStreams.find(mixPort->ext.mix.handle);
+    if (streamIt == mStreams.end()) {
+        return BAD_VALUE;
+    }
+    auto stream = streamIt->second.promote();
+    if (stream == nullptr) {
+        return BAD_VALUE;
+    }
+
+    String8 formatsStr;
+    status = getParametersFromStream(
+            stream, AudioParameter::keyStreamSupportedFormats, nullptr /*extraParameters*/,
+            &formatsStr);
+    if (status != NO_ERROR) {
+        return status;
+    }
+    FormatVector formats = formatsFromString(formatsStr.c_str());
+
+    mixPort->num_audio_profiles = 0;
+    for (audio_format_t format : formats) {
+        if (mixPort->num_audio_profiles >= AUDIO_PORT_MAX_AUDIO_PROFILES) {
+            ALOGW("%s, too many audio profiles", __func__);
+            break;
+        }
+        AudioParameter formatParameter;
+        formatParameter.addInt(String8(AudioParameter::keyFormat), format);
+
+        String8 samplingRatesStr;
+        status = getParametersFromStream(
+                stream, AudioParameter::keyStreamSupportedSamplingRates,
+                formatParameter.toString(), &samplingRatesStr);
+        if (status != NO_ERROR) {
+            // Failed to query supported sample rate for current format, may succeed with
+            // other formats.
+            ALOGW("Skip adding format=%#x, status=%d", format, status);
+            continue;
+        }
+        SampleRateSet sampleRatesFromStream = samplingRatesFromString(samplingRatesStr.c_str());
+        if (sampleRatesFromStream.empty()) {
+            ALOGW("Skip adding format=%#x as the returned sampling rates are empty", format);
+            continue;
+        }
+        String8 channelMasksStr;
+        status = getParametersFromStream(
+                stream, AudioParameter::keyStreamSupportedChannels,
+                formatParameter.toString(), &channelMasksStr);
+        if (status != NO_ERROR) {
+            // Failed to query supported channel masks for current format, may succeed with
+            // other formats.
+            ALOGW("Skip adding format=%#x, status=%d", format, status);
+            continue;
+        }
+        ChannelMaskSet channelMasksFromStream = channelMasksFromString(channelMasksStr.c_str());
+        if (channelMasksFromStream.empty()) {
+            ALOGW("Skip adding format=%#x as the returned channel masks are empty", format);
+            continue;
+        }
+
+        // For an audio format, all audio profiles from the device port with the same format will
+        // be added to mix port after filtering sample rates, channel masks according to the reply
+        // of getParameters API. If there is any sample rate or channel mask reported by
+        // getParameters API but not reported by the device, additional audio profiles will be
+        // added.
+        populateAudioProfiles(attrsFromDevice, format, channelMasksFromStream,
+                              sampleRatesFromStream, mixPort->audio_profiles,
+                              &mixPort->num_audio_profiles);
+    }
+
+    return NO_ERROR;
+}
+
+void DeviceHalHidl::cleanupStreams() {
+    for (auto it = mStreams.begin(); it != mStreams.end();) {
+        if (it->second.promote() == nullptr) {
+            it = mStreams.erase(it);
+        } else {
+            ++it;
+        }
+    }
+}
+
 } // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalHidl.h b/media/libaudiohal/impl/DeviceHalHidl.h
index 1a1db33..7a712df 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.h
+++ b/media/libaudiohal/impl/DeviceHalHidl.h
@@ -21,6 +21,7 @@
 #include PATH(android/hardware/audio/FILE_VERSION/IPrimaryDevice.h)
 #include <media/audiohal/DeviceHalInterface.h>
 #include <media/audiohal/EffectHalInterface.h>
+#include <media/audiohal/StreamHalInterface.h>
 
 #include "CoreConversionHelperHidl.h"
 
@@ -145,6 +146,9 @@
 
     status_t prepareToDisconnectExternalDevice(const struct audio_port_v7* port) override;
 
+    status_t getAudioMixPort(const struct audio_port_v7* devicePort,
+                             struct audio_port_v7* mixPort) override;
+
   private:
     friend class DevicesFactoryHalHidl;
     sp<::android::hardware::audio::CPP_VERSION::IDevice> mDevice;
@@ -154,12 +158,15 @@
     class SoundDoseWrapper;
     const std::unique_ptr<SoundDoseWrapper> mSoundDoseWrapper;
     std::set<audio_port_handle_t> mDeviceDisconnectionNotified;
+    std::map<audio_io_handle_t, wp<StreamHalInterface>> mStreams;
 
     // Can not be constructed directly by clients.
     explicit DeviceHalHidl(const sp<::android::hardware::audio::CPP_VERSION::IDevice>& device);
     explicit DeviceHalHidl(
             const sp<::android::hardware::audio::CPP_VERSION::IPrimaryDevice>& device);
 
+    void cleanupStreams();
+
     // The destructor automatically closes the device.
     virtual ~DeviceHalHidl();
 
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index dd14135..bb5f851 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -160,6 +160,9 @@
 
     virtual status_t prepareToDisconnectExternalDevice(const struct audio_port_v7* port) = 0;
 
+    virtual status_t getAudioMixPort(const struct audio_port_v7* devicePort,
+                                     struct audio_port_v7* mixPort) = 0;
+
   protected:
     // Subclasses can not be constructed directly by clients.
     DeviceHalInterface() {}