xref: /aosp_15_r20/hardware/interfaces/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp (revision 4d7e907c777eeecc4c5bd7cf640a754fac206ff7)
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <set>
18 #include <string>
19 #include <unordered_map>
20 #include <unordered_set>
21 #include <vector>
22 
23 #define LOG_TAG "VtsHalAudioCore.Config"
24 
25 #include <Utils.h>
26 #include <aidl/Gtest.h>
27 #include <aidl/Vintf.h>
28 #include <aidl/android/hardware/audio/core/IConfig.h>
29 #include <aidl/android/media/audio/common/AudioFlag.h>
30 #include <aidl/android/media/audio/common/AudioProductStrategyType.h>
31 #include <android-base/logging.h>
32 
33 #include "AudioHalBinderServiceUtil.h"
34 #include "TestUtils.h"
35 
36 using namespace android;
37 using aidl::android::hardware::audio::common::isDefaultAudioFormat;
38 using aidl::android::hardware::audio::core::IConfig;
39 using aidl::android::hardware::audio::core::SurroundSoundConfig;
40 using aidl::android::media::audio::common::AudioAttributes;
41 using aidl::android::media::audio::common::AudioDeviceAddress;
42 using aidl::android::media::audio::common::AudioDeviceDescription;
43 using aidl::android::media::audio::common::AudioFlag;
44 using aidl::android::media::audio::common::AudioFormatDescription;
45 using aidl::android::media::audio::common::AudioFormatType;
46 using aidl::android::media::audio::common::AudioHalAttributesGroup;
47 using aidl::android::media::audio::common::AudioHalCapConfiguration;
48 using aidl::android::media::audio::common::AudioHalCapCriterionV2;
49 using aidl::android::media::audio::common::AudioHalCapDomain;
50 using aidl::android::media::audio::common::AudioHalCapParameter;
51 using aidl::android::media::audio::common::AudioHalCapRule;
52 using aidl::android::media::audio::common::AudioHalEngineConfig;
53 using aidl::android::media::audio::common::AudioHalProductStrategy;
54 using aidl::android::media::audio::common::AudioHalVolumeCurve;
55 using aidl::android::media::audio::common::AudioHalVolumeGroup;
56 using aidl::android::media::audio::common::AudioMode;
57 using aidl::android::media::audio::common::AudioPolicyForceUse;
58 using aidl::android::media::audio::common::AudioProductStrategyType;
59 using aidl::android::media::audio::common::AudioSource;
60 using aidl::android::media::audio::common::AudioStreamType;
61 using aidl::android::media::audio::common::AudioUsage;
62 using aidl::android::media::audio::common::PcmType;
63 
64 class AudioCoreConfig : public testing::TestWithParam<std::string> {
65   public:
SetUp()66     void SetUp() override { ASSERT_NO_FATAL_FAILURE(ConnectToService()); }
ConnectToService()67     void ConnectToService() {
68         mConfig = IConfig::fromBinder(mBinderUtil.connectToService(GetParam()));
69         ASSERT_NE(mConfig, nullptr);
70     }
71 
RestartService()72     void RestartService() {
73         ASSERT_NE(mConfig, nullptr);
74         mEngineConfig.reset();
75         mSurroundSoundConfig.reset();
76         mConfig = IConfig::fromBinder(mBinderUtil.restartService());
77         ASSERT_NE(mConfig, nullptr);
78     }
79 
SetUpEngineConfig()80     void SetUpEngineConfig() {
81         if (mEngineConfig == nullptr) {
82             auto tempConfig = std::make_unique<AudioHalEngineConfig>();
83             ASSERT_IS_OK(mConfig->getEngineConfig(tempConfig.get()));
84             mEngineConfig = std::move(tempConfig);
85         }
86     }
87 
SetUpSurroundSoundConfig()88     void SetUpSurroundSoundConfig() {
89         if (mSurroundSoundConfig == nullptr) {
90             auto tempConfig = std::make_unique<SurroundSoundConfig>();
91             ASSERT_IS_OK(mConfig->getSurroundSoundConfig(tempConfig.get()));
92             mSurroundSoundConfig = std::move(tempConfig);
93         }
94     }
95 
IsProductStrategyTypeReservedForSystemUse(const AudioProductStrategyType & pst)96     static bool IsProductStrategyTypeReservedForSystemUse(const AudioProductStrategyType& pst) {
97         switch (pst) {
98             case AudioProductStrategyType::SYS_RESERVED_NONE:
99             case AudioProductStrategyType::SYS_RESERVED_REROUTING:
100             case AudioProductStrategyType::SYS_RESERVED_CALL_ASSISTANT:
101                 return true;
102             default:
103                 return false;
104         }
105     }
106 
IsStreamTypeReservedForSystemUse(const AudioStreamType & streamType)107     static bool IsStreamTypeReservedForSystemUse(const AudioStreamType& streamType) {
108         switch (streamType) {
109             case AudioStreamType::SYS_RESERVED_DEFAULT:
110             case AudioStreamType::SYS_RESERVED_REROUTING:
111             case AudioStreamType::SYS_RESERVED_PATCH:
112             case AudioStreamType::CALL_ASSISTANT:
113                 return true;
114             default:
115                 return false;
116         }
117     }
118 
IsAudioUsageValid(const AudioUsage & usage)119     static bool IsAudioUsageValid(const AudioUsage& usage) {
120         switch (usage) {
121             case AudioUsage::INVALID:
122             case AudioUsage::SYS_RESERVED_NOTIFICATION_COMMUNICATION_REQUEST:
123             case AudioUsage::SYS_RESERVED_NOTIFICATION_COMMUNICATION_INSTANT:
124             case AudioUsage::SYS_RESERVED_NOTIFICATION_COMMUNICATION_DELAYED:
125                 return false;
126             default:
127                 return true;
128         }
129     }
130 
IsAudioSourceValid(const AudioSource & source)131     static bool IsAudioSourceValid(const AudioSource& source) {
132         return (source != AudioSource::SYS_RESERVED_INVALID);
133     }
134 
GetSupportedAudioProductStrategyTypes()135     static const std::unordered_set<int>& GetSupportedAudioProductStrategyTypes() {
136         static const std::unordered_set<int> supportedAudioProductStrategyTypes = []() {
137             std::unordered_set<int> supportedStrategyTypes;
138             for (const auto& audioProductStrategyType :
139                  ndk::enum_range<AudioProductStrategyType>()) {
140                 if (!IsProductStrategyTypeReservedForSystemUse(audioProductStrategyType)) {
141                     supportedStrategyTypes.insert(static_cast<int>(audioProductStrategyType));
142                 }
143             }
144             return supportedStrategyTypes;
145         }();
146         return supportedAudioProductStrategyTypes;
147     }
148 
GetSupportedAudioFlagsMask()149     static int GetSupportedAudioFlagsMask() {
150         static const int supportedAudioFlagsMask = []() {
151             int mask = 0;
152             for (const auto& audioFlag : ndk::enum_range<AudioFlag>()) {
153                 mask |= static_cast<int>(audioFlag);
154             }
155             return mask;
156         }();
157         return supportedAudioFlagsMask;
158     }
159 
160     /**
161      * Verify streamType is not INVALID if using default engine.
162      * Verify that streamType is a valid AudioStreamType if the associated
163      * volumeGroup minIndex/maxIndex is INDEX_DEFERRED_TO_AUDIO_SERVICE.
164      */
ValidateAudioStreamType(const AudioStreamType & streamType,const AudioHalVolumeGroup & associatedVolumeGroup)165     void ValidateAudioStreamType(const AudioStreamType& streamType,
166                                  const AudioHalVolumeGroup& associatedVolumeGroup) {
167         EXPECT_FALSE(IsStreamTypeReservedForSystemUse(streamType));
168         if (!mEngineConfig->capSpecificConfig ||
169             associatedVolumeGroup.minIndex ==
170                     AudioHalVolumeGroup::INDEX_DEFERRED_TO_AUDIO_SERVICE) {
171             EXPECT_NE(streamType, AudioStreamType::INVALID);
172         }
173     }
174 
175     /**
176      * Verify contained enum types are valid.
177      */
ValidateAudioAttributes(const AudioAttributes & attributes)178     void ValidateAudioAttributes(const AudioAttributes& attributes) {
179         // No need to check contentType; there are no INVALID or SYS_RESERVED values
180         EXPECT_TRUE(IsAudioUsageValid(attributes.usage));
181         EXPECT_TRUE(IsAudioSourceValid(attributes.source));
182         EXPECT_EQ(attributes.flags & ~GetSupportedAudioFlagsMask(), 0);
183     }
184 
185     /**
186      * Verify volumeGroupName corresponds to an AudioHalVolumeGroup.
187      * Validate contained types.
188      */
ValidateAudioHalAttributesGroup(const AudioHalAttributesGroup & attributesGroup,std::unordered_map<std::string,const AudioHalVolumeGroup &> & volumeGroupMap,std::unordered_set<std::string> & volumeGroupsUsedInStrategies)189     void ValidateAudioHalAttributesGroup(
190             const AudioHalAttributesGroup& attributesGroup,
191             std::unordered_map<std::string, const AudioHalVolumeGroup&>& volumeGroupMap,
192             std::unordered_set<std::string>& volumeGroupsUsedInStrategies) {
193         bool isVolumeGroupNameValid = volumeGroupMap.count(attributesGroup.volumeGroupName);
194         EXPECT_TRUE(isVolumeGroupNameValid);
195         EXPECT_NO_FATAL_FAILURE(ValidateAudioStreamType(
196                 attributesGroup.streamType, volumeGroupMap.at(attributesGroup.volumeGroupName)));
197         if (isVolumeGroupNameValid) {
198             volumeGroupsUsedInStrategies.insert(attributesGroup.volumeGroupName);
199         }
200         for (const AudioAttributes& attr : attributesGroup.attributes) {
201             EXPECT_NO_FATAL_FAILURE(ValidateAudioAttributes(attr));
202         }
203     }
204 
205     /**
206      * Default engine: verify productStrategy.id is valid AudioProductStrategyType.
207      * CAP engine: verify productStrategy.id is either valid AudioProductStrategyType
208      * or is >= VENDOR_STRATEGY_ID_START.
209      * Validate contained types.
210      */
ValidateAudioHalProductStrategy(const AudioHalProductStrategy & strategy,std::unordered_map<std::string,const AudioHalVolumeGroup &> & volumeGroupMap,std::unordered_set<std::string> & volumeGroupsUsedInStrategies)211     void ValidateAudioHalProductStrategy(
212             const AudioHalProductStrategy& strategy,
213             std::unordered_map<std::string, const AudioHalVolumeGroup&>& volumeGroupMap,
214             std::unordered_set<std::string>& volumeGroupsUsedInStrategies) {
215         if (!mEngineConfig->capSpecificConfig ||
216             (strategy.id < AudioHalProductStrategy::VENDOR_STRATEGY_ID_START)) {
217             EXPECT_NE(GetSupportedAudioProductStrategyTypes().find(strategy.id),
218                       GetSupportedAudioProductStrategyTypes().end());
219         }
220         for (const AudioHalAttributesGroup& attributesGroup : strategy.attributesGroups) {
221             EXPECT_NO_FATAL_FAILURE(ValidateAudioHalAttributesGroup(attributesGroup, volumeGroupMap,
222                                                                     volumeGroupsUsedInStrategies));
223         }
224     }
225 
226     /**
227      * Verify curve point index is in [CurvePoint::MIN_INDEX, CurvePoint::MAX_INDEX].
228      */
ValidateAudioHalVolumeCurve(const AudioHalVolumeCurve & volumeCurve)229     void ValidateAudioHalVolumeCurve(const AudioHalVolumeCurve& volumeCurve) {
230         for (const AudioHalVolumeCurve::CurvePoint& curvePoint : volumeCurve.curvePoints) {
231             EXPECT_TRUE(curvePoint.index >= AudioHalVolumeCurve::CurvePoint::MIN_INDEX);
232             EXPECT_TRUE(curvePoint.index <= AudioHalVolumeCurve::CurvePoint::MAX_INDEX);
233         }
234     }
235 
236     /**
237      * Verify minIndex, maxIndex are non-negative.
238      * Verify minIndex <= maxIndex.
239      * Verify no two volume curves use the same device category.
240      * Validate contained types.
241      */
ValidateAudioHalVolumeGroup(const AudioHalVolumeGroup & volumeGroup)242     void ValidateAudioHalVolumeGroup(const AudioHalVolumeGroup& volumeGroup) {
243         /**
244          * Legacy volume curves in audio_policy_configuration.xsd don't use
245          * minIndex or maxIndex. Use of audio_policy_configuration.xml still
246          * allows, and in some cases, relies on, AudioService to provide the min
247          * and max indices for a volumeGroup. From the VTS perspective, there is
248          * no way to differentiate between use of audio_policy_configuration.xml
249          * or audio_policy_engine_configuration.xml, as either one can be used
250          * for the default audio policy engine.
251          */
252         if (volumeGroup.minIndex != AudioHalVolumeGroup::INDEX_DEFERRED_TO_AUDIO_SERVICE ||
253             volumeGroup.maxIndex != AudioHalVolumeGroup::INDEX_DEFERRED_TO_AUDIO_SERVICE) {
254             EXPECT_TRUE(volumeGroup.minIndex >= 0);
255             EXPECT_TRUE(volumeGroup.maxIndex >= 0);
256         }
257         EXPECT_TRUE(volumeGroup.minIndex <= volumeGroup.maxIndex);
258         std::unordered_set<AudioHalVolumeCurve::DeviceCategory> deviceCategorySet;
259         for (const AudioHalVolumeCurve& volumeCurve : volumeGroup.volumeCurves) {
260             EXPECT_TRUE(deviceCategorySet.insert(volumeCurve.deviceCategory).second);
261             EXPECT_NO_FATAL_FAILURE(ValidateAudioHalVolumeCurve(volumeCurve));
262         }
263     }
264 
265     /**
266      * Verify criterion provides a non empty value list.
267      * Verify logic rule provided is the expected one.
268      */
ValidateAudioHalCapCriterion(const AudioHalCapCriterionV2 & criterionV2)269     void ValidateAudioHalCapCriterion(const AudioHalCapCriterionV2& criterionV2) {
270         switch (criterionV2.getTag()) {
271             case AudioHalCapCriterionV2::availableInputDevices: {
272                 auto criterion = criterionV2.get<AudioHalCapCriterionV2::availableInputDevices>();
273                 EXPECT_FALSE(criterion.values.empty());
274                 EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
275                 break;
276             }
277             case AudioHalCapCriterionV2::availableOutputDevices: {
278                 auto criterion = criterionV2.get<AudioHalCapCriterionV2::availableOutputDevices>();
279                 EXPECT_FALSE(criterion.values.empty());
280                 EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
281                 break;
282             }
283             case AudioHalCapCriterionV2::availableInputDevicesAddresses: {
284                 auto criterion =
285                         criterionV2.get<AudioHalCapCriterionV2::availableInputDevicesAddresses>();
286                 EXPECT_FALSE(criterion.values.empty());
287                 EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
288                 break;
289             }
290             case AudioHalCapCriterionV2::availableOutputDevicesAddresses: {
291                 auto criterion =
292                         criterionV2.get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>();
293                 EXPECT_FALSE(criterion.values.empty());
294                 EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
295                 break;
296             }
297             case AudioHalCapCriterionV2::telephonyMode: {
298                 auto criterion = criterionV2.get<AudioHalCapCriterionV2::telephonyMode>();
299                 EXPECT_FALSE(criterion.values.empty());
300                 EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::EXCLUSIVE);
301                 break;
302             }
303             case AudioHalCapCriterionV2::forceConfigForUse: {
304                 auto criterion = criterionV2.get<AudioHalCapCriterionV2::forceConfigForUse>();
305                 EXPECT_FALSE(criterion.values.empty());
306                 EXPECT_EQ(criterion.logic, AudioHalCapCriterionV2::LogicalDisjunction::EXCLUSIVE);
307                 break;
308             }
309             default:
310                 ADD_FAILURE() << "Invalid criterion tag " << toString(criterionV2.getTag());
311         }
312     }
313 
314     /**
315      * Verify the rule involve the right matching logic according to the criterion logic.
316      * @param matchingRule logic followed by the rule
317      * @param logicalDisjunction logic exposed by the criterion
318      */
ValidateAudioHalCapRuleMatchingRule(const AudioHalCapRule::MatchingRule matchingRule,const AudioHalCapCriterionV2::LogicalDisjunction logicalDisjunction)319     void ValidateAudioHalCapRuleMatchingRule(
320             const AudioHalCapRule::MatchingRule matchingRule,
321             const AudioHalCapCriterionV2::LogicalDisjunction logicalDisjunction) {
322         if (logicalDisjunction == AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE) {
323             EXPECT_TRUE(matchingRule == AudioHalCapRule::MatchingRule::EXCLUDES ||
324                         matchingRule == AudioHalCapRule::MatchingRule::INCLUDES);
325         } else if (logicalDisjunction == AudioHalCapCriterionV2::LogicalDisjunction::EXCLUSIVE) {
326             EXPECT_TRUE(matchingRule == AudioHalCapRule::MatchingRule::IS ||
327                         matchingRule == AudioHalCapRule::MatchingRule::IS_NOT);
328         } else {
329             ADD_FAILURE() << "Invalid criterion Logical rule";
330         }
331     }
332 
333     /**
334      * Verify that the value and the matching rule are supported by the given criterion
335      */
336     template <typename CriterionV2, typename Value>
validateAudioHalCapRule(CriterionV2 criterionV2,Value value,const AudioHalCapRule::MatchingRule matchingRule)337     void validateAudioHalCapRule(CriterionV2 criterionV2, Value value,
338                                  const AudioHalCapRule::MatchingRule matchingRule) {
339         ValidateAudioHalCapRuleMatchingRule(matchingRule, criterionV2.logic);
340         EXPECT_FALSE(criterionV2.values.empty());
341         auto values = criterionV2.values;
342         auto valueIt = find_if(values.begin(), values.end(),
343                                [&](const auto& typedValue) { return typedValue == value; });
344         EXPECT_NE(valueIt, values.end());
345     }
346 
347     /**
348      * Verify rule involves a supported criterion.
349      * Verify rule involves supported logic keyword according to logic rule exposed by the
350      * criterion.
351      * Verify rule involves a value supported by the associated criterion.
352      */
ValidateAudioHalConfigurationRule(const AudioHalCapRule & rule,const std::vector<std::optional<AudioHalCapCriterionV2>> & criteria)353     void ValidateAudioHalConfigurationRule(
354             const AudioHalCapRule& rule,
355             const std::vector<std::optional<AudioHalCapCriterionV2>>& criteria) {
356         const auto& compoundRule = rule.compoundRule;
357         if (rule.nestedRules.empty() && rule.criterionRules.empty()) {
358             EXPECT_EQ(compoundRule, AudioHalCapRule::CompoundRule::ALL);
359         }
360         EXPECT_TRUE(compoundRule == AudioHalCapRule::CompoundRule::ANY ||
361                     compoundRule == AudioHalCapRule::CompoundRule::ALL);
362         for (const auto& nestedRule : rule.nestedRules) {
363             ValidateAudioHalConfigurationRule(nestedRule, criteria);
364         }
365         for (const auto& criterionRule : rule.criterionRules) {
366             auto selectionCriterion = criterionRule.criterionAndValue;
367             auto criterionValue = criterionRule.criterionAndValue;
368             auto matchesWhen = criterionRule.matchingRule;
369             auto criteriaIt = find_if(criteria.begin(), criteria.end(), [&](const auto& criterion) {
370                 return criterion.has_value() &&
371                        criterion.value().getTag() == selectionCriterion.getTag();
372             });
373             EXPECT_NE(criteriaIt, criteria.end())
374                     << " Invalid rule criterion " << toString(selectionCriterion.getTag());
375             AudioHalCapCriterionV2 matchingCriterion = (*criteriaIt).value();
376             switch (selectionCriterion.getTag()) {
377                 case AudioHalCapCriterionV2::availableInputDevices: {
378                     const auto& values =
379                             criterionValue.get<AudioHalCapCriterionV2::availableInputDevices>()
380                                     .values;
381                     ASSERT_FALSE(values.empty());
382                     validateAudioHalCapRule(
383                             matchingCriterion.get<AudioHalCapCriterionV2::availableInputDevices>(),
384                             values[0], matchesWhen);
385                     break;
386                 }
387                 case AudioHalCapCriterionV2::availableOutputDevices: {
388                     const auto& values =
389                             criterionValue.get<AudioHalCapCriterionV2::availableOutputDevices>()
390                                     .values;
391                     ASSERT_FALSE(values.empty());
392                     validateAudioHalCapRule(
393                             matchingCriterion.get<AudioHalCapCriterionV2::availableOutputDevices>(),
394                             values[0], matchesWhen);
395                     break;
396                 }
397                 case AudioHalCapCriterionV2::availableInputDevicesAddresses: {
398                     const auto& values =
399                             criterionValue
400                                     .get<AudioHalCapCriterionV2::availableInputDevicesAddresses>()
401                                     .values;
402                     ASSERT_FALSE(values.empty());
403                     validateAudioHalCapRule(
404                             matchingCriterion
405                                     .get<AudioHalCapCriterionV2::availableInputDevicesAddresses>(),
406                             values[0], matchesWhen);
407                     break;
408                 }
409                 case AudioHalCapCriterionV2::availableOutputDevicesAddresses: {
410                     const auto& values =
411                             criterionValue
412                                     .get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>()
413                                     .values;
414                     ASSERT_FALSE(values.empty());
415                     validateAudioHalCapRule(
416                             matchingCriterion
417                                     .get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>(),
418                             values[0], matchesWhen);
419                     break;
420                 }
421                 case AudioHalCapCriterionV2::telephonyMode: {
422                     const auto& values =
423                             criterionValue.get<AudioHalCapCriterionV2::telephonyMode>().values;
424                     ASSERT_FALSE(values.empty());
425                     validateAudioHalCapRule(
426                             matchingCriterion.get<AudioHalCapCriterionV2::telephonyMode>(),
427                             values[0], matchesWhen);
428                     break;
429                 }
430                 case AudioHalCapCriterionV2::forceConfigForUse: {
431                     const auto& values =
432                             criterionValue.get<AudioHalCapCriterionV2::forceConfigForUse>().values;
433                     ASSERT_FALSE(values.empty());
434                     validateAudioHalCapRule(
435                             matchingCriterion.get<AudioHalCapCriterionV2::forceConfigForUse>(),
436                             values[0], matchesWhen);
437                     break;
438                 }
439                 default:
440                     break;
441             }
442         }
443     }
444 
445     /**
446      * Get the number of occurrence of a given parameter within a given vector of parameter.
447      * It just take into account the parameter, not its associated value.
448      * @param parameter to consider
449      * @param domainParameters to check against
450      * @return matching occurrence of the parameter within the provided vector.
451      */
countsParameter(const AudioHalCapParameter & parameter,const std::vector<AudioHalCapParameter> & domainParameters)452     size_t countsParameter(const AudioHalCapParameter& parameter,
453                            const std::vector<AudioHalCapParameter>& domainParameters) {
454         size_t count = 0;
455         for (const auto& domainParameter : domainParameters) {
456             if (domainParameter.getTag() != parameter.getTag()) {
457                 continue;
458             }
459             switch (domainParameter.getTag()) {
460                 case AudioHalCapParameter::selectedStrategyDevice: {
461                     auto typedDomainParam =
462                             domainParameter.get<AudioHalCapParameter::selectedStrategyDevice>();
463                     auto typedParam = parameter.get<AudioHalCapParameter::selectedStrategyDevice>();
464                     if (typedDomainParam.id == typedParam.id &&
465                         typedDomainParam.device == typedParam.device) {
466                         count += 1;
467                     }
468                     break;
469                 }
470                 case AudioHalCapParameter::strategyDeviceAddress: {
471                     auto typedDomainParam =
472                             domainParameter.get<AudioHalCapParameter::strategyDeviceAddress>();
473                     auto typedParam = parameter.get<AudioHalCapParameter::strategyDeviceAddress>();
474                     if (typedDomainParam.id == typedParam.id) {
475                         count += 1;
476                     }
477                     break;
478                 }
479                 case AudioHalCapParameter::selectedInputSourceDevice: {
480                     auto typedDomainParam =
481                             domainParameter.get<AudioHalCapParameter::selectedInputSourceDevice>();
482                     auto typedParam =
483                             parameter.get<AudioHalCapParameter::selectedInputSourceDevice>();
484                     if (typedDomainParam.inputSource == typedParam.inputSource &&
485                         typedDomainParam.device == typedParam.device) {
486                         count += 1;
487                     }
488                     break;
489                 }
490                 case AudioHalCapParameter::streamVolumeProfile: {
491                     auto typedDomainParam =
492                             domainParameter.get<AudioHalCapParameter::streamVolumeProfile>();
493                     auto typedParam = parameter.get<AudioHalCapParameter::streamVolumeProfile>();
494                     if (typedDomainParam.stream == typedParam.stream) {
495                         count += 1;
496                     }
497                     break;
498                 }
499                 default:
500                     break;
501             }
502         }
503         return count;
504     }
505 
506     /**
507      * Verify each configuration has unique name within a domain
508      * Verify no duplicate parameter within a domain.
509      * Verify that each configuration has no duplicated parameter.
510      * Verify that each configuration has an associated value for all parameter within a domain.
511      */
ValidateAudioHalCapDomain(const AudioHalCapDomain & domain,const std::vector<std::optional<AudioHalCapCriterionV2>> & criteria)512     void ValidateAudioHalCapDomain(
513             const AudioHalCapDomain& domain,
514             const std::vector<std::optional<AudioHalCapCriterionV2>>& criteria) {
515         std::unordered_set<std::string> configurationNames;
516         for (const AudioHalCapConfiguration& configuration : domain.configurations) {
517             EXPECT_TRUE(configurationNames.insert(configuration.name).second);
518             ValidateAudioHalConfigurationRule(configuration.rule, criteria);
519         }
520         auto domainParameters = domain.configurations[0].parameterSettings;
521         for (const auto& settingParameter : domainParameters) {
522             EXPECT_EQ(1ul, countsParameter(settingParameter, domainParameters))
523                     << "Duplicated parameter within domain " << domain.name << " configuration "
524                     << domain.configurations[0].name << " for parameter "
525                     << settingParameter.toString();
526         }
527         for (const auto& configuration : domain.configurations) {
528             auto configurationParameters = configuration.parameterSettings;
529             for (const auto& configurationParameter : configurationParameters) {
530                 EXPECT_EQ(1ul, countsParameter(configurationParameter, configurationParameters))
531                         << "Duplicated parameter within domain " << domain.name << " configuration "
532                         << configuration.name << " for parameter "
533                         << configurationParameter.toString();
534             }
535             EXPECT_EQ(domainParameters.size(), configurationParameters.size());
536             for (const auto& settingParameter : configuration.parameterSettings) {
537                 EXPECT_EQ(1ul, countsParameter(settingParameter, domainParameters))
538                         << "Confiugration " << configuration.name << " within domain "
539                         << domain.name << " exposes invalid parameter "
540                         << settingParameter.toString();
541                 ;
542             }
543         }
544     }
545 
546     /**
547      * Verify each domain has a unique name.
548      * Verify that a given parameter does not appear in more than one domain.
549      */
ValidateAudioHalCapDomains(const std::vector<std::optional<AudioHalCapDomain>> & domains,const std::vector<std::optional<AudioHalCapCriterionV2>> & criteria)550     void ValidateAudioHalCapDomains(
551             const std::vector<std::optional<AudioHalCapDomain>>& domains,
552             const std::vector<std::optional<AudioHalCapCriterionV2>>& criteria) {
553         std::unordered_map<std::string, AudioHalCapDomain> domainMap;
554         std::vector<AudioHalCapParameter> allDomainParameters;
555         for (const auto& domain : domains) {
556             EXPECT_TRUE(domain.has_value());
557             EXPECT_FALSE(domain.value().configurations.empty());
558             auto domainParameters = domain.value().configurations[0].parameterSettings;
559             for (const auto& domainParameter : domainParameters) {
560                 EXPECT_EQ(0ul, countsParameter(domainParameter, allDomainParameters))
561                         << "Duplicated parameter in domain " << domain.value().name
562                         << " for parameter " << domainParameter.toString();
563                 allDomainParameters.push_back(domainParameter);
564             }
565             EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapDomain(domain.value(), criteria));
566             EXPECT_TRUE(domainMap.insert({domain.value().name, domain.value()}).second);
567         }
568     }
569 
570     /**
571      * Verify unique criterion is provided for a given Tag, except for ForceUse
572      * Verify unique forceUse criterion are provided for usage
573      * Verify each criterion is validating.
574      * Verify domains.
575      */
ValidateCapSpecificConfig(const AudioHalEngineConfig::CapSpecificConfig & capCfg)576     void ValidateCapSpecificConfig(const AudioHalEngineConfig::CapSpecificConfig& capCfg) {
577         EXPECT_TRUE(capCfg.criteriaV2.has_value());
578         std::unordered_set<AudioHalCapCriterionV2::Tag> criterionTagSet;
579         std::unordered_set<AudioPolicyForceUse::Tag> forceUseCriterionUseSet;
580         for (const auto& criterion : capCfg.criteriaV2.value()) {
581             EXPECT_TRUE(criterion.has_value());
582             if (criterion.value().getTag() != AudioHalCapCriterionV2::forceConfigForUse) {
583                 EXPECT_TRUE(criterionTagSet.insert(criterion.value().getTag()).second);
584             } else {
585                 auto forceUseCriterion =
586                         criterion.value().get<AudioHalCapCriterionV2::forceConfigForUse>();
587                 ASSERT_FALSE(forceUseCriterion.values.empty());
588                 EXPECT_TRUE(forceUseCriterionUseSet.insert(forceUseCriterion.values[0].getTag())
589                                     .second);
590             }
591             EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapCriterion(criterion.value()));
592         }
593         ValidateAudioHalCapDomains(capCfg.domains.value(), capCfg.criteriaV2.value());
594     }
595 
596     /**
597      * Verify VolumeGroups are non-empty.
598      * Verify defaultProductStrategyId matches one of the provided productStrategies.
599      * Otherwise, must be left uninitialized.
600      * Verify each volumeGroup has a unique name.
601      * Verify each productStrategy has a unique id.
602      * Verify each volumeGroup is used in a product strategy.
603      * CAP engine: verify productStrategies are non-empty.
604      * Validate contained types.
605      */
ValidateAudioHalEngineConfig()606     void ValidateAudioHalEngineConfig() {
607         EXPECT_NE(mEngineConfig->volumeGroups.size(), 0UL);
608         std::unordered_map<std::string, const AudioHalVolumeGroup&> volumeGroupMap;
609         for (const AudioHalVolumeGroup& volumeGroup : mEngineConfig->volumeGroups) {
610             EXPECT_TRUE(volumeGroupMap.insert({volumeGroup.name, volumeGroup}).second);
611             EXPECT_NO_FATAL_FAILURE(ValidateAudioHalVolumeGroup(volumeGroup));
612         }
613         if (!mEngineConfig->productStrategies.empty()) {
614             std::unordered_set<int> productStrategyIdSet;
615             std::unordered_set<std::string> volumeGroupsUsedInStrategies;
616             for (const AudioHalProductStrategy& strategy : mEngineConfig->productStrategies) {
617                 EXPECT_TRUE(productStrategyIdSet.insert(strategy.id).second);
618                 EXPECT_NO_FATAL_FAILURE(ValidateAudioHalProductStrategy(
619                         strategy, volumeGroupMap, volumeGroupsUsedInStrategies));
620             }
621             EXPECT_TRUE(productStrategyIdSet.count(mEngineConfig->defaultProductStrategyId))
622                     << "defaultProductStrategyId doesn't match any of the provided "
623                        "productStrategies";
624             EXPECT_EQ(volumeGroupMap.size(), volumeGroupsUsedInStrategies.size());
625         } else {
626             EXPECT_EQ(mEngineConfig->defaultProductStrategyId,
627                       static_cast<int>(AudioProductStrategyType::SYS_RESERVED_NONE))
628                     << "defaultProductStrategyId defined, but no productStrategies were provided";
629         }
630         if (mEngineConfig->capSpecificConfig) {
631             EXPECT_NO_FATAL_FAILURE(
632                     ValidateCapSpecificConfig(mEngineConfig->capSpecificConfig.value()));
633             EXPECT_FALSE(mEngineConfig->productStrategies.empty());
634         }
635     }
636 
ValidateAudioFormatDescription(const AudioFormatDescription & format)637     void ValidateAudioFormatDescription(const AudioFormatDescription& format) {
638         EXPECT_NE(AudioFormatType::SYS_RESERVED_INVALID, format.type);
639         if (format.type == AudioFormatType::PCM) {
640             EXPECT_NE(PcmType::DEFAULT, format.pcm);
641             EXPECT_TRUE(format.encoding.empty()) << format.encoding;
642         } else {
643             EXPECT_FALSE(format.encoding.empty());
644         }
645     }
646 
647     /**
648      * Verify that the surround sound configuration is not empty.
649      * Verify each of the formatFamilies has a non-empty primaryFormat.
650      * Verify that each format only appears once.
651      */
ValidateSurroundSoundConfig()652     void ValidateSurroundSoundConfig() {
653         EXPECT_FALSE(mSurroundSoundConfig->formatFamilies.empty());
654         std::set<AudioFormatDescription> formatSet;
655         for (const SurroundSoundConfig::SurroundFormatFamily& family :
656              mSurroundSoundConfig->formatFamilies) {
657             EXPECT_NO_FATAL_FAILURE(ValidateAudioFormatDescription(family.primaryFormat));
658             EXPECT_FALSE(isDefaultAudioFormat(family.primaryFormat));
659             EXPECT_TRUE(formatSet.insert(family.primaryFormat).second);
660             for (const AudioFormatDescription& subformat : family.subFormats) {
661                 EXPECT_NO_FATAL_FAILURE(ValidateAudioFormatDescription(subformat));
662                 EXPECT_FALSE(isDefaultAudioFormat(subformat));
663                 EXPECT_TRUE(formatSet.insert(subformat).second);
664             }
665         }
666     }
667 
668   private:
669     std::shared_ptr<IConfig> mConfig;
670     std::unique_ptr<AudioHalEngineConfig> mEngineConfig;
671     std::unique_ptr<SurroundSoundConfig> mSurroundSoundConfig;
672     AudioHalBinderServiceUtil mBinderUtil;
673 };
674 
TEST_P(AudioCoreConfig,Published)675 TEST_P(AudioCoreConfig, Published) {
676     // SetUp must complete with no failures.
677 }
678 
TEST_P(AudioCoreConfig,CanBeRestarted)679 TEST_P(AudioCoreConfig, CanBeRestarted) {
680     ASSERT_NO_FATAL_FAILURE(RestartService());
681 }
682 
TEST_P(AudioCoreConfig,GetEngineConfigIsValid)683 TEST_P(AudioCoreConfig, GetEngineConfigIsValid) {
684     ASSERT_NO_FATAL_FAILURE(SetUpEngineConfig());
685     EXPECT_NO_FATAL_FAILURE(ValidateAudioHalEngineConfig());
686 }
687 
TEST_P(AudioCoreConfig,GetSurroundSoundConfigIsValid)688 TEST_P(AudioCoreConfig, GetSurroundSoundConfigIsValid) {
689     ASSERT_NO_FATAL_FAILURE(SetUpSurroundSoundConfig());
690     EXPECT_NO_FATAL_FAILURE(ValidateSurroundSoundConfig());
691 }
692 
693 INSTANTIATE_TEST_SUITE_P(AudioCoreConfigTest, AudioCoreConfig,
694                          testing::ValuesIn(android::getAidlHalInstanceNames(IConfig::descriptor)),
695                          android::PrintInstanceNameToString);
696 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreConfig);
697