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