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