• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 <cstdint>
18 #include <istream>
19 #include <map>
20 #include <sstream>
21 #include <stdarg.h>
22 #include <string>
23 #include <string>
24 #include <vector>
25 #include <unordered_map>
26 
27 #define LOG_TAG "APM::AudioPolicyEngine/Config"
28 //#define LOG_NDEBUG 0
29 
30 #include "EngineConfig.h"
31 #include <TypeConverter.h>
32 #include <Volume.h>
33 #include <cutils/properties.h>
34 #include <libxml/parser.h>
35 #include <libxml/xinclude.h>
36 #include <media/AidlConversion.h>
37 #include <media/AidlConversionUtil.h>
38 #include <media/TypeConverter.h>
39 #include <media/convert.h>
40 #include <system/audio_config.h>
41 #include <utils/Log.h>
42 
43 namespace android {
44 
45 using utilities::convertTo;
46 
47 namespace engineConfig {
48 
49 static constexpr const char *gVersionAttribute = "version";
50 static const char *const gReferenceElementName = "reference";
51 static const char *const gReferenceAttributeName = "name";
52 
53 namespace {
54 
aidl2legacy_AudioHalProductStrategy_ProductStrategyType(int id)55 ConversionResult<std::string> aidl2legacy_AudioHalProductStrategy_ProductStrategyType(int id) {
56     using AudioProductStrategyType = media::audio::common::AudioProductStrategyType;
57 
58 #define STRATEGY_ENTRY(name) {static_cast<int>(AudioProductStrategyType::name), "STRATEGY_" #name}
59     static const std::unordered_map<int, std::string> productStrategyMap = {STRATEGY_ENTRY(MEDIA),
60                             STRATEGY_ENTRY(PHONE),
61                             STRATEGY_ENTRY(SONIFICATION),
62                             STRATEGY_ENTRY(SONIFICATION_RESPECTFUL),
63                             STRATEGY_ENTRY(DTMF),
64                             STRATEGY_ENTRY(ENFORCED_AUDIBLE),
65                             STRATEGY_ENTRY(TRANSMITTED_THROUGH_SPEAKER),
66                             STRATEGY_ENTRY(ACCESSIBILITY)};
67 #undef STRATEGY_ENTRY
68 
69     auto it = productStrategyMap.find(id);
70     if (it == productStrategyMap.end()) {
71         return base::unexpected(BAD_VALUE);
72     }
73     return it->second;
74 }
75 
aidl2legacy_AudioHalAttributeGroup_AttributesGroup(const media::audio::common::AudioHalAttributesGroup & aidl)76 ConversionResult<AttributesGroup> aidl2legacy_AudioHalAttributeGroup_AttributesGroup(
77         const media::audio::common::AudioHalAttributesGroup& aidl) {
78     AttributesGroup legacy;
79     legacy.stream = VALUE_OR_RETURN(
80             aidl2legacy_AudioStreamType_audio_stream_type_t(aidl.streamType));
81     legacy.volumeGroup = aidl.volumeGroupName;
82     legacy.attributesVect = VALUE_OR_RETURN(convertContainer<AttributesVector>(
83                     aidl.attributes, aidl2legacy_AudioAttributes_audio_attributes_t));
84     return legacy;
85 }
86 
aidl2legacy_AudioHalProductStrategy_ProductStrategy(const media::audio::common::AudioHalProductStrategy & aidl)87 ConversionResult<ProductStrategy> aidl2legacy_AudioHalProductStrategy_ProductStrategy(
88         const media::audio::common::AudioHalProductStrategy& aidl) {
89     ProductStrategy legacy;
90     legacy.name = VALUE_OR_RETURN(
91                     aidl2legacy_AudioHalProductStrategy_ProductStrategyType(aidl.id));
92     legacy.attributesGroups = VALUE_OR_RETURN(convertContainer<AttributesGroups>(
93                     aidl.attributesGroups,
94                     aidl2legacy_AudioHalAttributeGroup_AttributesGroup));
95     return legacy;
96 }
97 
legacy_device_category_to_string(device_category legacy)98 ConversionResult<std::string> legacy_device_category_to_string(device_category legacy) {
99     std::string s;
100     if (DeviceCategoryConverter::toString(legacy, s)) {
101         return s;
102     }
103     return base::unexpected(BAD_VALUE);
104 }
105 
aidl2legacy_DeviceCategory(const media::audio::common::AudioHalVolumeCurve::DeviceCategory aidl)106 ConversionResult<std::string> aidl2legacy_DeviceCategory(
107         const media::audio::common::AudioHalVolumeCurve::DeviceCategory aidl) {
108     using DeviceCategory = media::audio::common::AudioHalVolumeCurve::DeviceCategory;
109     switch (aidl) {
110         case DeviceCategory::HEADSET:
111             return legacy_device_category_to_string(DEVICE_CATEGORY_HEADSET);
112         case DeviceCategory::SPEAKER:
113             return legacy_device_category_to_string(DEVICE_CATEGORY_SPEAKER);
114         case DeviceCategory::EARPIECE:
115             return legacy_device_category_to_string(DEVICE_CATEGORY_EARPIECE);
116         case DeviceCategory::EXT_MEDIA:
117             return legacy_device_category_to_string(DEVICE_CATEGORY_EXT_MEDIA);
118         case DeviceCategory::HEARING_AID:
119             return legacy_device_category_to_string(DEVICE_CATEGORY_HEARING_AID);
120     }
121     return base::unexpected(BAD_VALUE);
122 }
123 
aidl2legacy_AudioHalCurvePoint_CurvePoint(const media::audio::common::AudioHalVolumeCurve::CurvePoint & aidl)124 ConversionResult<CurvePoint> aidl2legacy_AudioHalCurvePoint_CurvePoint(
125         const media::audio::common::AudioHalVolumeCurve::CurvePoint& aidl) {
126     CurvePoint legacy;
127     legacy.index = VALUE_OR_RETURN(convertIntegral<int>(aidl.index));
128     legacy.attenuationInMb = aidl.attenuationMb;
129     return legacy;
130 }
131 
aidl2legacy_AudioHalVolumeCurve_VolumeCurve(const media::audio::common::AudioHalVolumeCurve & aidl)132 ConversionResult<VolumeCurve> aidl2legacy_AudioHalVolumeCurve_VolumeCurve(
133         const media::audio::common::AudioHalVolumeCurve& aidl) {
134     VolumeCurve legacy;
135     legacy.deviceCategory = VALUE_OR_RETURN(aidl2legacy_DeviceCategory(aidl.deviceCategory));
136     legacy.curvePoints = VALUE_OR_RETURN(convertContainer<CurvePoints>(
137                     aidl.curvePoints, aidl2legacy_AudioHalCurvePoint_CurvePoint));
138     return legacy;
139 }
140 
aidl2legacy_AudioHalVolumeGroup_VolumeGroup(const media::audio::common::AudioHalVolumeGroup & aidl)141 ConversionResult<VolumeGroup> aidl2legacy_AudioHalVolumeGroup_VolumeGroup(
142         const media::audio::common::AudioHalVolumeGroup& aidl) {
143     VolumeGroup legacy;
144     legacy.name = aidl.name;
145     legacy.indexMin = aidl.minIndex;
146     legacy.indexMax = aidl.maxIndex;
147     legacy.volumeCurves = VALUE_OR_RETURN(convertContainer<VolumeCurves>(
148                     aidl.volumeCurves, aidl2legacy_AudioHalVolumeCurve_VolumeCurve));
149     return legacy;
150 }
151 
152 }  // namespace
153 
154 template<typename E, typename C>
155 struct BaseSerializerTraits {
156     typedef E Element;
157     typedef C Collection;
158     typedef void* PtrSerializingCtx;
159 };
160 
161 struct AttributesGroupTraits : public BaseSerializerTraits<AttributesGroup, AttributesGroups> {
162     static constexpr const char *tag = "AttributesGroup";
163     static constexpr const char *collectionTag = "AttributesGroups";
164 
165     struct Attributes {
166         static constexpr const char *streamType = "streamType";
167         static constexpr const char *volumeGroup = "volumeGroup";
168     };
169     static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root, Collection &ps);
170 };
171 
172 struct ProductStrategyTraits : public BaseSerializerTraits<ProductStrategy, ProductStrategies> {
173     static constexpr const char *tag = "ProductStrategy";
174     static constexpr const char *collectionTag = "ProductStrategies";
175 
176     struct Attributes {
177         static constexpr const char *name = "name";
178     };
179     static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root, Collection &ps);
180 };
181 struct ValueTraits : public BaseSerializerTraits<ValuePair, ValuePairs> {
182     static constexpr const char *tag = "value";
183     static constexpr const char *collectionTag = "values";
184 
185     struct Attributes {
186         static constexpr const char *literal = "literal";
187         static constexpr const char *numerical = "numerical";
188         static constexpr const char *androidType = "android_type";
189     };
190 
191     static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root,
192                                          Collection &collection);
193 };
194 struct CriterionTypeTraits : public BaseSerializerTraits<CriterionType, CriterionTypes> {
195     static constexpr const char *tag = "criterion_type";
196     static constexpr const char *collectionTag = "criterion_types";
197 
198     struct Attributes {
199         static constexpr const char *name = "name";
200         static constexpr const char *type = "type";
201     };
202 
203     static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root,
204                                          Collection &collection);
205 };
206 struct CriterionTraits : public BaseSerializerTraits<Criterion, Criteria> {
207     static constexpr const char *tag = "criterion";
208     static constexpr const char *collectionTag = "criteria";
209 
210     struct Attributes {
211         static constexpr const char *name = "name";
212         static constexpr const char *type = "type";
213         static constexpr const char *defaultVal = "default";
214     };
215 
216     static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root,
217                                          Collection &collection);
218 };
219 struct VolumeTraits : public BaseSerializerTraits<VolumeCurve, VolumeCurves> {
220     static constexpr const char *tag = "volume";
221     static constexpr const char *collectionTag = "volumes";
222     static constexpr const char *volumePointTag = "point";
223 
224     struct Attributes {
225         static constexpr const char *deviceCategory = "deviceCategory";
226         static constexpr const char *stream = "stream"; // For legacy volume curves
227         static constexpr const char *reference = "ref"; /**< For volume curves factorization. */
228     };
229 
230     static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root,
231                                          Collection &collection);
232 };
233 struct VolumeGroupTraits : public BaseSerializerTraits<VolumeGroup, VolumeGroups> {
234     static constexpr const char *tag = "volumeGroup";
235     static constexpr const char *collectionTag = "volumeGroups";
236 
237     struct Attributes {
238         static constexpr const char *name = "name";
239         static constexpr const char *stream = "stream"; // For legacy volume curves
240         static constexpr const char *indexMin = "indexMin";
241         static constexpr const char *indexMax = "indexMax";
242     };
243 
244     static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root,
245                                          Collection &collection);
246 };
247 
248 template <class T>
249 constexpr void (*xmlDeleter)(T* t);
250 template <>
251 constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
252 template <>
__anon370200eb0202(xmlChar *s) 253 constexpr auto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };
254 
255 /** @return a unique_ptr with the correct deleter for the libxml2 object. */
256 template <class T>
make_xmlUnique(T * t)257 constexpr auto make_xmlUnique(T *t) {
258     // Wrap deleter in lambda to enable empty base optimization
259     auto deleter = [](T *t) { xmlDeleter<T>(t); };
260     return std::unique_ptr<T, decltype(deleter)>{t, deleter};
261 }
262 
getXmlAttribute(const xmlNode * cur,const char * attribute)263 std::string getXmlAttribute(const xmlNode *cur, const char *attribute)
264 {
265     auto charPtr = make_xmlUnique(xmlGetProp(cur, reinterpret_cast<const xmlChar *>(attribute)));
266     if (charPtr == NULL) {
267         return "";
268     }
269     std::string value(reinterpret_cast<const char*>(charPtr.get()));
270     return value;
271 }
272 
getReference(const _xmlNode * root,const _xmlNode * & refNode,const std::string & refName,const char * collectionTag)273 static void getReference(const _xmlNode *root, const _xmlNode *&refNode, const std::string &refName,
274                          const char *collectionTag)
275 {
276     for (root = root->xmlChildrenNode; root != NULL; root = root->next) {
277         if (!xmlStrcmp(root->name, (const xmlChar *)collectionTag)) {
278             for (xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
279                 if ((!xmlStrcmp(cur->name, (const xmlChar *)gReferenceElementName))) {
280                     std::string name = getXmlAttribute(cur, gReferenceAttributeName);
281                     if (refName == name) {
282                         refNode = cur;
283                         return;
284                     }
285                 }
286             }
287         }
288     }
289     return;
290 }
291 
292 template <class Trait>
deserializeCollection(_xmlDoc * doc,const _xmlNode * cur,typename Trait::Collection & collection,size_t & nbSkippedElement)293 static status_t deserializeCollection(_xmlDoc *doc, const _xmlNode *cur,
294                                       typename Trait::Collection &collection,
295                                       size_t &nbSkippedElement)
296 {
297     for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
298         if (xmlStrcmp(cur->name, (const xmlChar *)Trait::collectionTag) &&
299             xmlStrcmp(cur->name, (const xmlChar *)Trait::tag)) {
300             continue;
301         }
302         const xmlNode *child = cur;
303         if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {
304             child = child->xmlChildrenNode;
305         }
306         for (; child != NULL; child = child->next) {
307             if (!xmlStrcmp(child->name, (const xmlChar *)Trait::tag)) {
308                 status_t status = Trait::deserialize(doc, child, collection);
309                 if (status != NO_ERROR) {
310                     nbSkippedElement += 1;
311                 }
312             }
313         }
314         if (!xmlStrcmp(cur->name, (const xmlChar *)Trait::tag)) {
315             return NO_ERROR;
316         }
317     }
318     return NO_ERROR;
319 }
320 
321 static constexpr const char *attributesAttributeRef = "attributesRef"; /**< for factorization. */
322 
parseAttributes(const _xmlNode * cur,audio_attributes_t & attributes)323 static status_t parseAttributes(const _xmlNode *cur, audio_attributes_t &attributes)
324 {
325     for (; cur != NULL; cur = cur->next) {
326         if (!xmlStrcmp(cur->name, (const xmlChar *)("ContentType"))) {
327             std::string contentTypeXml = getXmlAttribute(cur, "value");
328             audio_content_type_t contentType;
329             if (not AudioContentTypeConverter::fromString(contentTypeXml.c_str(), contentType)) {
330                 ALOGE("Invalid content type %s", contentTypeXml.c_str());
331                 return BAD_VALUE;
332             }
333             attributes.content_type = contentType;
334             ALOGV("%s content type %s",  __FUNCTION__, contentTypeXml.c_str());
335         }
336         if (!xmlStrcmp(cur->name, (const xmlChar *)("Usage"))) {
337             std::string usageXml = getXmlAttribute(cur, "value");
338             audio_usage_t usage;
339             if (not UsageTypeConverter::fromString(usageXml.c_str(), usage)) {
340                 ALOGE("Invalid usage %s", usageXml.c_str());
341                 return BAD_VALUE;
342             }
343             attributes.usage = usage;
344             ALOGV("%s usage %s",  __FUNCTION__, usageXml.c_str());
345         }
346         if (!xmlStrcmp(cur->name, (const xmlChar *)("Flags"))) {
347             std::string flags = getXmlAttribute(cur, "value");
348 
349             ALOGV("%s flags %s",  __FUNCTION__, flags.c_str());
350             attributes.flags = static_cast<audio_flags_mask_t>(
351                     AudioFlagConverter::maskFromString(flags, " "));
352         }
353         if (!xmlStrcmp(cur->name, (const xmlChar *)("Bundle"))) {
354             std::string bundleKey = getXmlAttribute(cur, "key");
355             std::string bundleValue = getXmlAttribute(cur, "value");
356 
357             ALOGV("%s Bundle %s %s",  __FUNCTION__, bundleKey.c_str(), bundleValue.c_str());
358 
359             std::string tags(bundleKey + "=" + bundleValue);
360             std::strncpy(attributes.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
361         }
362     }
363     return NO_ERROR;
364 }
365 
deserializeAttributes(_xmlDoc * doc,const _xmlNode * cur,audio_attributes_t & attributes)366 static status_t deserializeAttributes(_xmlDoc *doc, const _xmlNode *cur,
367                                       audio_attributes_t &attributes) {
368     // Retrieve content type, usage, flags, and bundle from xml
369     for (; cur != NULL; cur = cur->next) {
370         if (not xmlStrcmp(cur->name, (const xmlChar *)("Attributes"))) {
371             const xmlNode *attrNode = cur;
372             std::string attrRef = getXmlAttribute(cur, attributesAttributeRef);
373             if (!attrRef.empty()) {
374                 getReference(xmlDocGetRootElement(doc), attrNode, attrRef, attributesAttributeRef);
375                 if (attrNode == NULL) {
376                     ALOGE("%s: No reference found for %s", __FUNCTION__, attrRef.c_str());
377                     return BAD_VALUE;
378                 }
379                 return deserializeAttributes(doc, attrNode->xmlChildrenNode, attributes);
380             }
381             return parseAttributes(attrNode->xmlChildrenNode, attributes);
382         }
383         if (not xmlStrcmp(cur->name, (const xmlChar *)("ContentType")) ||
384                 not xmlStrcmp(cur->name, (const xmlChar *)("Usage")) ||
385                 not xmlStrcmp(cur->name, (const xmlChar *)("Flags")) ||
386                 not xmlStrcmp(cur->name, (const xmlChar *)("Bundle"))) {
387             return parseAttributes(cur, attributes);
388         }
389     }
390     return BAD_VALUE;
391 }
392 
deserializeAttributesCollection(_xmlDoc * doc,const _xmlNode * cur,AttributesVector & collection)393 static status_t deserializeAttributesCollection(_xmlDoc *doc, const _xmlNode *cur,
394                                                 AttributesVector &collection)
395 {
396     status_t ret = BAD_VALUE;
397     // Either we do provide only one attributes or a collection of supported attributes
398     for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
399         if (not xmlStrcmp(cur->name, (const xmlChar *)("Attributes")) ||
400                 not xmlStrcmp(cur->name, (const xmlChar *)("ContentType")) ||
401                 not xmlStrcmp(cur->name, (const xmlChar *)("Usage")) ||
402                 not xmlStrcmp(cur->name, (const xmlChar *)("Flags")) ||
403                 not xmlStrcmp(cur->name, (const xmlChar *)("Bundle"))) {
404             audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
405             ret = deserializeAttributes(doc, cur, attributes);
406             if (ret == NO_ERROR) {
407                 collection.push_back(attributes);
408                 // We are done if the "Attributes" balise is omitted, only one Attributes is allowed
409                 if (xmlStrcmp(cur->name, (const xmlChar *)("Attributes"))) {
410                     return ret;
411                 }
412             }
413         }
414     }
415     return ret;
416 }
417 
deserialize(_xmlDoc * doc,const _xmlNode * child,Collection & attributesGroup)418 status_t AttributesGroupTraits::deserialize(_xmlDoc *doc, const _xmlNode *child,
419                                             Collection &attributesGroup)
420 {
421     std::string volumeGroup = getXmlAttribute(child, Attributes::volumeGroup);
422     if (volumeGroup.empty()) {
423         ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::volumeGroup);
424     }
425     ALOGV("%s: %s = %s", __FUNCTION__, Attributes::volumeGroup, volumeGroup.c_str());
426 
427     audio_stream_type_t streamType = AUDIO_STREAM_DEFAULT;
428     std::string streamTypeXml = getXmlAttribute(child, Attributes::streamType);
429     if (streamTypeXml.empty()) {
430         ALOGV("%s: No attribute %s found", __FUNCTION__, Attributes::streamType);
431     } else {
432         ALOGV("%s: %s = %s", __FUNCTION__, Attributes::streamType, streamTypeXml.c_str());
433         if (not StreamTypeConverter::fromString(streamTypeXml.c_str(), streamType)) {
434             ALOGE("Invalid stream type %s", streamTypeXml.c_str());
435             return BAD_VALUE;
436         }
437     }
438     AttributesVector attributesVect;
439     deserializeAttributesCollection(doc, child, attributesVect);
440 
441     attributesGroup.push_back({streamType, volumeGroup, attributesVect});
442     return NO_ERROR;
443 }
444 
deserialize(_xmlDoc *,const _xmlNode * child,Collection & values)445 status_t ValueTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *child, Collection &values)
446 {
447     std::string literal = getXmlAttribute(child, Attributes::literal);
448     if (literal.empty()) {
449         ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::literal);
450         return BAD_VALUE;
451     }
452     uint32_t androidType = 0;
453     std::string androidTypeliteral = getXmlAttribute(child, Attributes::androidType);
454     if (!androidTypeliteral.empty()) {
455         ALOGV("%s: androidType %s", __FUNCTION__, androidTypeliteral.c_str());
456         if (!convertTo(androidTypeliteral, androidType)) {
457             ALOGE("%s: : Invalid typeset value(%s)", __FUNCTION__, androidTypeliteral.c_str());
458             return BAD_VALUE;
459         }
460     }
461     uint64_t numerical = 0;
462     std::string numericalTag = getXmlAttribute(child, Attributes::numerical);
463     if (numericalTag.empty()) {
464         ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::literal);
465         return BAD_VALUE;
466     }
467     if (!convertTo(numericalTag, numerical)) {
468         ALOGE("%s: : Invalid value(%s)", __FUNCTION__, numericalTag.c_str());
469         return BAD_VALUE;
470     }
471     values.push_back({numerical,  androidType, literal});
472     return NO_ERROR;
473 }
474 
deserialize(_xmlDoc * doc,const _xmlNode * child,Collection & criterionTypes)475 status_t CriterionTypeTraits::deserialize(_xmlDoc *doc, const _xmlNode *child,
476                                           Collection &criterionTypes)
477 {
478     std::string name = getXmlAttribute(child, Attributes::name);
479     if (name.empty()) {
480         ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::name);
481         return BAD_VALUE;
482     }
483     ALOGV("%s: %s %s = %s", __FUNCTION__, tag, Attributes::name, name.c_str());
484 
485     std::string type = getXmlAttribute(child, Attributes::type);
486     if (type.empty()) {
487         ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::type);
488         return BAD_VALUE;
489     }
490     ALOGV("%s: %s %s = %s", __FUNCTION__, tag, Attributes::type, type.c_str());
491     bool isInclusive(type == "inclusive");
492 
493     ValuePairs pairs;
494     size_t nbSkippedElements = 0;
495     deserializeCollection<ValueTraits>(doc, child, pairs, nbSkippedElements);
496     criterionTypes.push_back({name, isInclusive, pairs});
497     return NO_ERROR;
498 }
499 
deserialize(_xmlDoc *,const _xmlNode * child,Collection & criteria)500 status_t CriterionTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *child,
501                                       Collection &criteria)
502 {
503     std::string name = getXmlAttribute(child, Attributes::name);
504     if (name.empty()) {
505         ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::name);
506         return BAD_VALUE;
507     }
508     ALOGV("%s: %s = %s", __FUNCTION__, Attributes::name, name.c_str());
509 
510     std::string defaultValue = getXmlAttribute(child, Attributes::defaultVal);
511     if (defaultValue.empty()) {
512         // Not mandatory to provide a default value for a criterion, even it is recommanded...
513         ALOGV("%s: No attribute %s found (but recommanded)", __FUNCTION__, Attributes::defaultVal);
514     }
515     ALOGV("%s: %s = %s", __FUNCTION__, Attributes::defaultVal, defaultValue.c_str());
516 
517     std::string typeName = getXmlAttribute(child, Attributes::type);
518     if (typeName.empty()) {
519         ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::name);
520         return BAD_VALUE;
521     }
522     ALOGV("%s: %s = %s", __FUNCTION__, Attributes::type, typeName.c_str());
523 
524     criteria.push_back({name, typeName, defaultValue});
525     return NO_ERROR;
526 }
527 
deserialize(_xmlDoc * doc,const _xmlNode * child,Collection & strategies)528 status_t ProductStrategyTraits::deserialize(_xmlDoc *doc, const _xmlNode *child,
529                                             Collection &strategies)
530 {
531     std::string name = getXmlAttribute(child, Attributes::name);
532     if (name.empty()) {
533         ALOGE("ProductStrategyTraits No attribute %s found", Attributes::name);
534         return BAD_VALUE;
535     }
536     ALOGV("%s: %s = %s", __FUNCTION__, Attributes::name, name.c_str());
537 
538     size_t skipped = 0;
539     AttributesGroups attrGroups;
540     deserializeCollection<AttributesGroupTraits>(doc, child, attrGroups, skipped);
541 
542     strategies.push_back({name, attrGroups});
543     return NO_ERROR;
544 }
545 
deserialize(_xmlDoc * doc,const _xmlNode * root,Collection & volumes)546 status_t VolumeTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, Collection &volumes)
547 {
548     std::string deviceCategory = getXmlAttribute(root, Attributes::deviceCategory);
549     if (deviceCategory.empty()) {
550         ALOGW("%s: No %s found", __FUNCTION__, Attributes::deviceCategory);
551     }
552     std::string referenceName = getXmlAttribute(root, Attributes::reference);
553     const _xmlNode *ref = NULL;
554     if (!referenceName.empty()) {
555         getReference(xmlDocGetRootElement(doc), ref, referenceName, collectionTag);
556         if (ref == NULL) {
557             ALOGE("%s: No reference Ptr found for %s", __FUNCTION__, referenceName.c_str());
558             return BAD_VALUE;
559         }
560     }
561     // Retrieve curve point from reference element if found or directly from current curve
562     CurvePoints curvePoints;
563     for (const xmlNode *child = referenceName.empty() ?
564          root->xmlChildrenNode : ref->xmlChildrenNode; child != NULL; child = child->next) {
565         if (!xmlStrcmp(child->name, (const xmlChar *)volumePointTag)) {
566             auto pointXml = make_xmlUnique(xmlNodeListGetString(doc, child->xmlChildrenNode, 1));
567             if (pointXml == NULL) {
568                 return BAD_VALUE;
569             }
570             ALOGV("%s: %s=%s", __func__, tag, reinterpret_cast<const char*>(pointXml.get()));
571             std::vector<int> point;
572             collectionFromString<DefaultTraits<int>>(
573                         reinterpret_cast<const char*>(pointXml.get()), point, ",");
574             if (point.size() != 2) {
575                 ALOGE("%s: Invalid %s: %s", __func__, volumePointTag,
576                       reinterpret_cast<const char*>(pointXml.get()));
577                 return BAD_VALUE;
578             }
579             curvePoints.push_back({point[0], point[1]});
580         }
581     }
582     volumes.push_back({ deviceCategory, curvePoints });
583     return NO_ERROR;
584 }
585 
deserialize(_xmlDoc * doc,const _xmlNode * root,Collection & volumes)586 status_t VolumeGroupTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, Collection &volumes)
587 {
588     std::string name;
589     int indexMin = 0;
590     int indexMax = 0;
591     StreamVector streams = {};
592     AttributesVector attributesVect = {};
593 
594     for (const xmlNode *child = root->xmlChildrenNode; child != NULL; child = child->next) {
595         if (not xmlStrcmp(child->name, (const xmlChar *)Attributes::name)) {
596             auto nameXml = make_xmlUnique(xmlNodeListGetString(doc, child->xmlChildrenNode, 1));
597             if (nameXml == nullptr) {
598                 return BAD_VALUE;
599             }
600             name = reinterpret_cast<const char*>(nameXml.get());
601         }
602         if (not xmlStrcmp(child->name, (const xmlChar *)Attributes::indexMin)) {
603             auto indexMinXml = make_xmlUnique(xmlNodeListGetString(doc, child->xmlChildrenNode, 1));
604             if (indexMinXml == nullptr) {
605                 return BAD_VALUE;
606             }
607             std::string indexMinLiteral(reinterpret_cast<const char*>(indexMinXml.get()));
608             if (!convertTo(indexMinLiteral, indexMin)) {
609                 return BAD_VALUE;
610             }
611         }
612         if (not xmlStrcmp(child->name, (const xmlChar *)Attributes::indexMax)) {
613             auto indexMaxXml = make_xmlUnique(xmlNodeListGetString(doc, child->xmlChildrenNode, 1));
614             if (indexMaxXml == nullptr) {
615                 return BAD_VALUE;
616             }
617             std::string indexMaxLiteral(reinterpret_cast<const char*>(indexMaxXml.get()));
618             if (!convertTo(indexMaxLiteral, indexMax)) {
619                 return BAD_VALUE;
620             }
621         }
622     }
623     deserializeAttributesCollection(doc, root, attributesVect);
624 
625     std::string streamNames;
626     for (const auto &stream : streams) {
627         streamNames += android::toString(stream) + " ";
628     }
629     std::string attrmNames;
630     for (const auto &attr : attributesVect) {
631         attrmNames += android::toString(attr) + "\n";
632     }
633     ALOGV("%s: group=%s indexMin=%d, indexMax=%d streams=%s attributes=%s",
634           __func__, name.c_str(), indexMin, indexMax, streamNames.c_str(), attrmNames.c_str( ));
635 
636     VolumeCurves groupVolumeCurves;
637     size_t skipped = 0;
638     deserializeCollection<VolumeTraits>(doc, root, groupVolumeCurves, skipped);
639     volumes.push_back({ name, indexMin, indexMax, groupVolumeCurves });
640     return NO_ERROR;
641 }
642 
643 static constexpr const char *legacyVolumecollectionTag = "volumes";
644 static constexpr const char *legacyVolumeTag = "volume";
645 
deserializeLegacyVolume(_xmlDoc * doc,const _xmlNode * cur,std::map<std::string,VolumeCurves> & legacyVolumes)646 status_t deserializeLegacyVolume(_xmlDoc *doc, const _xmlNode *cur,
647                                  std::map<std::string, VolumeCurves> &legacyVolumes)
648 {
649     std::string streamTypeLiteral = getXmlAttribute(cur, "stream");
650     if (streamTypeLiteral.empty()) {
651         ALOGE("%s: No attribute stream found", __func__);
652         return BAD_VALUE;
653     }
654     std::string deviceCategoryLiteral = getXmlAttribute(cur, "deviceCategory");
655     if (deviceCategoryLiteral.empty()) {
656         ALOGE("%s: No attribute deviceCategory found", __func__);
657         return BAD_VALUE;
658     }
659     std::string referenceName = getXmlAttribute(cur, "ref");
660     const xmlNode *ref = NULL;
661     if (!referenceName.empty()) {
662         getReference(xmlDocGetRootElement(doc), ref, referenceName, legacyVolumecollectionTag);
663         if (ref == NULL) {
664             ALOGE("%s: No reference Ptr found for %s", __func__, referenceName.c_str());
665             return BAD_VALUE;
666         }
667         ALOGV("%s: reference found for %s", __func__, referenceName.c_str());
668     }
669     CurvePoints curvePoints;
670     for (const xmlNode *child = referenceName.empty() ?
671          cur->xmlChildrenNode : ref->xmlChildrenNode; child != NULL; child = child->next) {
672         if (!xmlStrcmp(child->name, (const xmlChar *)VolumeTraits::volumePointTag)) {
673             auto pointXml = make_xmlUnique(xmlNodeListGetString(doc, child->xmlChildrenNode, 1));
674             if (pointXml == NULL) {
675                 return BAD_VALUE;
676             }
677             ALOGV("%s: %s=%s", __func__, legacyVolumeTag,
678                   reinterpret_cast<const char*>(pointXml.get()));
679             std::vector<int> point;
680             collectionFromString<DefaultTraits<int>>(
681                         reinterpret_cast<const char*>(pointXml.get()), point, ",");
682             if (point.size() != 2) {
683                 ALOGE("%s: Invalid %s: %s", __func__, VolumeTraits::volumePointTag,
684                       reinterpret_cast<const char*>(pointXml.get()));
685                 return BAD_VALUE;
686             }
687             curvePoints.push_back({point[0], point[1]});
688         }
689     }
690     legacyVolumes[streamTypeLiteral].push_back({ deviceCategoryLiteral, curvePoints });
691     return NO_ERROR;
692 }
693 
deserializeLegacyVolumeCollection(_xmlDoc * doc,const _xmlNode * cur,VolumeGroups & volumeGroups,size_t & nbSkippedElement)694 static status_t deserializeLegacyVolumeCollection(_xmlDoc *doc, const _xmlNode *cur,
695                                                   VolumeGroups &volumeGroups,
696                                                   size_t &nbSkippedElement)
697 {
698     std::map<std::string, VolumeCurves> legacyVolumeMap;
699     for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
700         if (xmlStrcmp(cur->name, (const xmlChar *)legacyVolumecollectionTag)) {
701             continue;
702         }
703         const xmlNode *child = cur->xmlChildrenNode;
704         for (; child != NULL; child = child->next) {
705             if (!xmlStrcmp(child->name, (const xmlChar *)legacyVolumeTag)) {
706 
707                 status_t status = deserializeLegacyVolume(doc, child, legacyVolumeMap);
708                 if (status != NO_ERROR) {
709                     nbSkippedElement += 1;
710                 }
711             }
712         }
713     }
714     VolumeGroups tempVolumeGroups = volumeGroups;
715     for (const auto &volumeMapIter : legacyVolumeMap) {
716         // In order to let AudioService setting the min and max (compatibility), set Min and Max
717         // to -1 except for private streams
718         audio_stream_type_t streamType;
719         if (!StreamTypeConverter::fromString(volumeMapIter.first, streamType)) {
720             ALOGE("%s: Invalid stream %s", __func__, volumeMapIter.first.c_str());
721             return BAD_VALUE;
722         }
723         int indexMin = streamType >= AUDIO_STREAM_PUBLIC_CNT ? 0 : -1;
724         int indexMax = streamType >= AUDIO_STREAM_PUBLIC_CNT ? 100 : -1;
725         tempVolumeGroups.push_back(
726                 { volumeMapIter.first, indexMin, indexMax, volumeMapIter.second });
727     }
728     std::swap(tempVolumeGroups, volumeGroups);
729     return NO_ERROR;
730 }
731 
732 namespace {
733 
734 class XmlErrorHandler {
735 public:
XmlErrorHandler()736     XmlErrorHandler() {
737         xmlSetGenericErrorFunc(this, &xmlErrorHandler);
738     }
739     XmlErrorHandler(const XmlErrorHandler&) = delete;
740     XmlErrorHandler(XmlErrorHandler&&) = delete;
741     XmlErrorHandler& operator=(const XmlErrorHandler&) = delete;
742     XmlErrorHandler& operator=(XmlErrorHandler&&) = delete;
~XmlErrorHandler()743     ~XmlErrorHandler() {
744         xmlSetGenericErrorFunc(NULL, NULL);
745         if (!mErrorMessage.empty()) {
746             ALOG(LOG_ERROR, "libxml2", "%s", mErrorMessage.c_str());
747         }
748     }
xmlErrorHandler(void * ctx,const char * msg,...)749     static void xmlErrorHandler(void* ctx, const char* msg, ...) {
750         char buffer[256];
751         va_list args;
752         va_start(args, msg);
753         vsnprintf(buffer, sizeof(buffer), msg, args);
754         va_end(args);
755         static_cast<XmlErrorHandler*>(ctx)->mErrorMessage += buffer;
756     }
757 private:
758     std::string mErrorMessage;
759 };
760 
761 }  // namespace
762 
parse(const char * path)763 ParsingResult parse(const char* path) {
764     XmlErrorHandler errorHandler;
765     auto doc = make_xmlUnique(xmlParseFile(path));
766     if (doc == NULL) {
767         // It is OK not to find an engine config file at the default location
768         // as the caller will default to hardcoded default config
769         if (strncmp(path, DEFAULT_PATH, strlen(DEFAULT_PATH))) {
770             ALOGW("%s: Could not parse document %s", __FUNCTION__, path);
771         }
772         return {nullptr, 0};
773     }
774     xmlNodePtr cur = xmlDocGetRootElement(doc.get());
775     if (cur == NULL) {
776         ALOGE("%s: Could not parse: empty document %s", __FUNCTION__, path);
777         return {nullptr, 0};
778     }
779     if (xmlXIncludeProcess(doc.get()) < 0) {
780         ALOGE("%s: libxml failed to resolve XIncludes on document %s", __FUNCTION__, path);
781         return {nullptr, 0};
782     }
783     std::string version = getXmlAttribute(cur, gVersionAttribute);
784     if (version.empty()) {
785         ALOGE("%s: No version found", __func__);
786         return {nullptr, 0};
787     }
788     size_t nbSkippedElements = 0;
789     auto config = std::make_unique<Config>();
790     config->version = std::stof(version);
791     deserializeCollection<ProductStrategyTraits>(
792                 doc.get(), cur, config->productStrategies, nbSkippedElements);
793     deserializeCollection<CriterionTraits>(
794                 doc.get(), cur, config->criteria, nbSkippedElements);
795     deserializeCollection<CriterionTypeTraits>(
796                 doc.get(), cur, config->criterionTypes, nbSkippedElements);
797     deserializeCollection<VolumeGroupTraits>(
798                 doc.get(), cur, config->volumeGroups, nbSkippedElements);
799 
800     return {std::move(config), nbSkippedElements};
801 }
802 
parseLegacyVolumeFile(const char * path,VolumeGroups & volumeGroups)803 android::status_t parseLegacyVolumeFile(const char* path, VolumeGroups &volumeGroups) {
804     XmlErrorHandler errorHandler;
805     auto doc = make_xmlUnique(xmlParseFile(path));
806     if (doc == NULL) {
807         ALOGE("%s: Could not parse document %s", __FUNCTION__, path);
808         return BAD_VALUE;
809     }
810     xmlNodePtr cur = xmlDocGetRootElement(doc.get());
811     if (cur == NULL) {
812         ALOGE("%s: Could not parse: empty document %s", __FUNCTION__, path);
813         return BAD_VALUE;
814     }
815     if (xmlXIncludeProcess(doc.get()) < 0) {
816         ALOGE("%s: libxml failed to resolve XIncludes on document %s", __FUNCTION__, path);
817         return BAD_VALUE;
818     }
819     size_t nbSkippedElements = 0;
820     return deserializeLegacyVolumeCollection(doc.get(), cur, volumeGroups, nbSkippedElements);
821 }
822 
parseLegacyVolumes(VolumeGroups & volumeGroups)823 android::status_t parseLegacyVolumes(VolumeGroups &volumeGroups) {
824     if (std::string audioPolicyXmlConfigFile = audio_get_audio_policy_config_file();
825             !audioPolicyXmlConfigFile.empty()) {
826         return parseLegacyVolumeFile(audioPolicyXmlConfigFile.c_str(), volumeGroups);
827     } else {
828         ALOGE("No readable audio policy config file found");
829         return BAD_VALUE;
830     }
831 }
832 
convert(const::android::media::audio::common::AudioHalEngineConfig & aidlConfig)833 ParsingResult convert(const ::android::media::audio::common::AudioHalEngineConfig& aidlConfig) {
834     auto config = std::make_unique<engineConfig::Config>();
835     config->version = 1.0f;
836     if (auto conv = convertContainer<engineConfig::ProductStrategies>(
837                     aidlConfig.productStrategies,
838                     aidl2legacy_AudioHalProductStrategy_ProductStrategy); conv.ok()) {
839         config->productStrategies = std::move(conv.value());
840     } else {
841         return ParsingResult{};
842     }
843     if (auto conv = convertContainer<engineConfig::VolumeGroups>(
844                     aidlConfig.volumeGroups,
845                     aidl2legacy_AudioHalVolumeGroup_VolumeGroup); conv.ok()) {
846         config->volumeGroups = std::move(conv.value());
847     } else {
848         return ParsingResult{};
849     }
850     return {.parsedConfig=std::move(config), .nbSkippedElement=0};
851  }
852 
853 } // namespace engineConfig
854 } // namespace android
855