blob: bc6d046f31a5ab5f513cf26e25043c1c98798f4c [file] [log] [blame]
François Gaffiea56b5c22018-02-21 18:04:39 +01001/*
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/PFWWrapperConfig"
18#define LOG_NDEBUG 0
19
20#include "ParameterManagerWrapperConfig.h"
21
22#include <media/convert.h>
23#include <utils/Log.h>
24#include <libxml/parser.h>
25#include <libxml/xinclude.h>
26#include <string>
27#include <vector>
28#include <sstream>
29#include <istream>
30
31
32namespace android {
33
34using utilities::convertTo;
35
36namespace audio_policy {
37namespace wrapper_config {
38namespace detail {
39
40std::string getXmlAttribute(const xmlNode *cur, const char *attribute)
41{
42 xmlChar *xmlValue = xmlGetProp(cur, (const xmlChar *)attribute);
43 if (xmlValue == NULL) {
44 return "";
45 }
46 std::string value((const char *)xmlValue);
47 xmlFree(xmlValue);
48 return value;
49}
50
51template <class Trait>
52static status_t deserializeCollection(_xmlDoc *doc, const _xmlNode *cur,
53 typename Trait::Collection &collection,
54 size_t &nbSkippedElement)
55{
56 const xmlNode *root = cur->xmlChildrenNode;
57 while (root != NULL) {
58 if (xmlStrcmp(root->name, (const xmlChar *)Trait::collectionTag) &&
59 xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
60 root = root->next;
61 continue;
62 }
63 const xmlNode *child = root;
64 if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {
65 child = child->xmlChildrenNode;
66 }
67 while (child != NULL) {
68 if (!xmlStrcmp(child->name, (const xmlChar *)Trait::tag)) {
69 status_t status = Trait::deserialize(doc, child, collection);
70 if (status == NO_ERROR) {
71 nbSkippedElement += 1;
72 }
73 }
74 child = child->next;
75 }
76 if (!xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
77 return NO_ERROR;
78 }
79 root = root->next;
80 }
81 return NO_ERROR;
82}
83
84const char *const ValueTraits::tag = "value";
85const char *const ValueTraits::collectionTag = "values";
86
87const char ValueTraits::Attributes::literal[] = "literal";
88const char ValueTraits::Attributes::numerical[] = "numerical";
89
90status_t ValueTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *child, Collection &values)
91{
92 std::string literal = getXmlAttribute(child, Attributes::literal);
93 if (literal.empty()) {
94 ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::literal);
95 return BAD_VALUE;
96 }
97 uint32_t numerical = 0;
98 std::string numericalTag = getXmlAttribute(child, Attributes::numerical);
99 if (numericalTag.empty()) {
100 ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::literal);
101 return BAD_VALUE;
102 }
103 if (!convertTo(numericalTag, numerical)) {
104 ALOGE("%s: : Invalid value(%s)", __FUNCTION__, numericalTag.c_str());
105 return BAD_VALUE;
106 }
107 values.push_back({numerical, literal});
108 return NO_ERROR;
109}
110
111const char *const CriterionTypeTraits::tag = "criterion_type";
112const char *const CriterionTypeTraits::collectionTag = "criterion_types";
113
114const char CriterionTypeTraits::Attributes::name[] = "name";
115const char CriterionTypeTraits::Attributes::type[] = "type";
116
117status_t CriterionTypeTraits::deserialize(_xmlDoc *doc, const _xmlNode *child,
118 Collection &criterionTypes)
119{
120 std::string name = getXmlAttribute(child, Attributes::name);
121 if (name.empty()) {
122 ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::name);
123 return BAD_VALUE;
124 }
125 ALOGV("%s: %s %s = %s", __FUNCTION__, tag, Attributes::name, name.c_str());
126
127 std::string type = getXmlAttribute(child, Attributes::type);
128 if (type.empty()) {
129 ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::type);
130 return BAD_VALUE;
131 }
132 ALOGV("%s: %s %s = %s", __FUNCTION__, tag, Attributes::type, type.c_str());
133 bool isInclusive(type == "inclusive");
134
135 ValuePairs pairs;
136 size_t nbSkippedElements = 0;
137 detail::deserializeCollection<detail::ValueTraits>(doc, child, pairs, nbSkippedElements);
138
139 criterionTypes.push_back({name, isInclusive, pairs});
140 return NO_ERROR;
141}
142
143const char *const CriterionTraits::tag = "criterion";
144const char *const CriterionTraits::collectionTag = "criteria";
145
146const char CriterionTraits::Attributes::name[] = "name";
147const char CriterionTraits::Attributes::type[] = "type";
148const char CriterionTraits::Attributes::defaultVal[] = "default";
149
150status_t CriterionTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *child, Collection &criteria)
151{
152 std::string name = getXmlAttribute(child, Attributes::name);
153 if (name.empty()) {
154 ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::name);
155 return BAD_VALUE;
156 }
157 ALOGV("%s: %s = %s", __FUNCTION__, Attributes::name, name.c_str());
158
159 std::string defaultValue = getXmlAttribute(child, Attributes::defaultVal);
160 if (defaultValue.empty()) {
161 // Not mandatory to provide a default value for a criterion, even it is recommanded...
162 ALOGV("%s: No attribute %s found", __FUNCTION__, Attributes::defaultVal);
163 }
164 ALOGV("%s: %s = %s", __FUNCTION__, Attributes::defaultVal, defaultValue.c_str());
165
166 std::string typeName = getXmlAttribute(child, Attributes::type);
167 if (typeName.empty()) {
168 ALOGE("%s: No attribute %s found", __FUNCTION__, Attributes::name);
169 return BAD_VALUE;
170 }
171 ALOGV("%s: %s = %s", __FUNCTION__, Attributes::type, typeName.c_str());
172
173 criteria.push_back({name, typeName, defaultValue});
174 return NO_ERROR;
175}
176} // namespace detail
177
178ParsingResult parse(const char* path) {
179 xmlDocPtr doc;
180 doc = xmlParseFile(path);
181 if (doc == NULL) {
182 ALOGE("%s: Could not parse document %s", __FUNCTION__, path);
183 return {nullptr, 0};
184 }
185 xmlNodePtr cur = xmlDocGetRootElement(doc);
186 if (cur == NULL) {
187 ALOGE("%s: Could not parse: empty document %s", __FUNCTION__, path);
188 xmlFreeDoc(doc);
189 return {nullptr, 0};
190 }
191 if (xmlXIncludeProcess(doc) < 0) {
192 ALOGE("%s: libxml failed to resolve XIncludes on document %s", __FUNCTION__, path);
193 return {nullptr, 0};
194 }
195 size_t nbSkippedElements = 0;
196 auto config = std::make_unique<Config>();
197
198 detail::deserializeCollection<detail::CriterionTraits>(
199 doc, cur, config->criteria, nbSkippedElements);
200 detail::deserializeCollection<detail::CriterionTypeTraits>(
201 doc, cur, config->criterionTypes, nbSkippedElements);
202
203 return {std::move(config), nbSkippedElements};
204}
205
206} // namespace wrapper_config
207} // namespace audio_policy
208} // namespace android