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