1 /*
2 * Copyright (C) 2015 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::Serializer"
18 //#define LOG_NDEBUG 0
19
20 #include <memory>
21 #include <string>
22 #include <utility>
23 #include <variant>
24
25 #include <libxml/parser.h>
26 #include <libxml/xinclude.h>
27 #include <media/convert.h>
28 #include <utils/Log.h>
29 #include <utils/StrongPointer.h>
30 #include <utils/Errors.h>
31 #include <utils/RefBase.h>
32 #include "Serializer.h"
33 #include "TypeConverter.h"
34
35 namespace android {
36
37 namespace {
38
39 using utilities::convertTo;
40
maybeVendorExtension(const std::string & s)41 static inline bool maybeVendorExtension(const std::string& s) {
42 // Only checks whether the string starts with the "vendor prefix".
43 static const std::string vendorPrefix = "VX_";
44 return s.size() > vendorPrefix.size() && s.substr(0, vendorPrefix.size()) == vendorPrefix;
45 }
46
47 template<typename E, typename C>
48 struct AndroidCollectionTraits {
49 typedef sp<E> Element;
50 typedef C Collection;
51 typedef void* PtrSerializingCtx;
52
addElementToCollectionandroid::__anonf09962200111::AndroidCollectionTraits53 static status_t addElementToCollection(const Element &element, Collection *collection) {
54 return collection->add(element) >= 0 ? NO_ERROR : BAD_VALUE;
55 }
56 };
57
58 template<typename C>
59 struct StdCollectionTraits {
60 typedef C Collection;
61 typedef typename C::value_type Element;
62 typedef void* PtrSerializingCtx;
63
addElementToCollectionandroid::__anonf09962200111::StdCollectionTraits64 static status_t addElementToCollection(const Element &element, Collection *collection) {
65 auto pair = collection->insert(element);
66 return pair.second ? NO_ERROR : BAD_VALUE;
67 }
68 };
69
70 struct AudioGainTraits : public AndroidCollectionTraits<AudioGain, AudioGains>
71 {
72 static constexpr const char *tag = "gain";
73 static constexpr const char *collectionTag = "gains";
74
75 struct Attributes
76 {
77 /** gain modes supported, e.g. AUDIO_GAIN_MODE_CHANNELS. */
78 static constexpr const char *mode = "mode";
79 /** controlled channels, needed if mode AUDIO_GAIN_MODE_CHANNELS. */
80 static constexpr const char *channelMask = "channel_mask";
81 static constexpr const char *minValueMB = "minValueMB"; /**< min value in millibel. */
82 static constexpr const char *maxValueMB = "maxValueMB"; /**< max value in millibel. */
83 /** default value in millibel. */
84 static constexpr const char *defaultValueMB = "defaultValueMB";
85 static constexpr const char *stepValueMB = "stepValueMB"; /**< step value in millibel. */
86 /** needed if mode AUDIO_GAIN_MODE_RAMP. */
87 static constexpr const char *minRampMs = "minRampMs";
88 /** needed if mode AUDIO_GAIN_MODE_RAMP. */
89 static constexpr const char *maxRampMs = "maxRampMs";
90 /** needed to allow use setPortGain instead of setStreamVolume. */
91 static constexpr const char *useForVolume = "useForVolume";
92
93 };
94
95 // No children
96 };
97
98 // A profile section contains a name, one audio format and the list of supported sampling rates
99 // and channel masks for this format
100 struct AudioProfileTraits : public AndroidCollectionTraits<AudioProfile, AudioProfileVector>
101 {
102 static constexpr const char *tag = "profile";
103 static constexpr const char *collectionTag = "profiles";
104
105 struct Attributes
106 {
107 static constexpr const char *samplingRates = "samplingRates";
108 static constexpr const char *format = "format";
109 static constexpr const char *channelMasks = "channelMasks";
110 };
111 };
112
113 struct MixPortTraits : public AndroidCollectionTraits<IOProfile, IOProfileCollection>
114 {
115 static constexpr const char *tag = "mixPort";
116 static constexpr const char *collectionTag = "mixPorts";
117
118 struct Attributes
119 {
120 static constexpr const char *name = "name";
121 static constexpr const char *role = "role";
122 static constexpr const char *roleSource = "source"; /**< <attribute role source value>. */
123 static constexpr const char *flags = "flags";
124 static constexpr const char *maxOpenCount = "maxOpenCount";
125 static constexpr const char *maxActiveCount = "maxActiveCount";
126 };
127
128 // Children: GainTraits
129 };
130
131 struct DevicePortTraits : public AndroidCollectionTraits<DeviceDescriptor, DeviceVector>
132 {
133 static constexpr const char *tag = "devicePort";
134 static constexpr const char *collectionTag = "devicePorts";
135
136 struct Attributes
137 {
138 /** <device tag name>: any string without space. */
139 static constexpr const char *tagName = "tagName";
140 static constexpr const char *type = "type"; /**< <device type>. */
141 static constexpr const char *role = "role"; /**< <device role: sink or source>. */
142 static constexpr const char *roleSource = "source"; /**< <attribute role source value>. */
143 /** optional: device address, char string less than 64. */
144 static constexpr const char *address = "address";
145 /** optional: the list of encoded audio formats that are known to be supported. */
146 static constexpr const char *encodedFormats = "encodedFormats";
147 };
148
149 // Children: GainTraits (optional)
150 };
151
152 struct RouteTraits : public AndroidCollectionTraits<AudioRoute, AudioRouteVector>
153 {
154 static constexpr const char *tag = "route";
155 static constexpr const char *collectionTag = "routes";
156
157 struct Attributes
158 {
159 static constexpr const char *type = "type"; /**< <route type>: mix or mux. */
160 static constexpr const char *typeMix = "mix"; /**< type attribute mix value. */
161 static constexpr const char *sink = "sink"; /**< <sink: involved in this route>. */
162 /** sources: all source that can be involved in this route. */
163 static constexpr const char *sources = "sources";
164 };
165
166 typedef HwModule *PtrSerializingCtx;
167 };
168
169 struct ModuleTraits : public AndroidCollectionTraits<HwModule, HwModuleCollection>
170 {
171 static constexpr const char *tag = "module";
172 static constexpr const char *collectionTag = "modules";
173
174 static constexpr const char *childAttachedDevicesTag = "attachedDevices";
175 static constexpr const char *childAttachedDeviceTag = "item";
176 static constexpr const char *childDefaultOutputDeviceTag = "defaultOutputDevice";
177
178 struct Attributes
179 {
180 static constexpr const char *name = "name";
181 static constexpr const char *version = "halVersion";
182 };
183
184 typedef AudioPolicyConfig *PtrSerializingCtx;
185
186 // Children: mixPortTraits, devicePortTraits, and routeTraits
187 // Need to call deserialize on each child
188 };
189
190 struct GlobalConfigTraits
191 {
192 typedef std::monostate Element;
193
194 static constexpr const char *tag = "globalConfiguration";
195
196 struct Attributes
197 {
198 static constexpr const char *speakerDrcEnabled = "speaker_drc_enabled";
199 static constexpr const char *callScreenModeSupported= "call_screen_mode_supported";
200 static constexpr const char *engineLibrarySuffix = "engine_library";
201 };
202
203 typedef AudioPolicyConfig *PtrSerializingCtx;
204 };
205
206 struct SurroundSoundTraits
207 {
208 typedef std::monostate Element;
209
210 static constexpr const char *tag = "surroundSound";
211
212 typedef AudioPolicyConfig *PtrSerializingCtx;
213 // Children: SurroundSoundFormatTraits
214 };
215
216 struct SurroundSoundFormatTraits : public StdCollectionTraits<AudioPolicyConfig::SurroundFormats>
217 {
218 static constexpr const char *tag = "format";
219 static constexpr const char *collectionTag = "formats";
220
221 struct Attributes
222 {
223 static constexpr const char *name = "name";
224 static constexpr const char *subformats = "subformats";
225 };
226 };
227
228 class PolicySerializer
229 {
230 public:
231 status_t deserialize(const char *configFile, AudioPolicyConfig *config,
232 bool ignoreVendorExtensions = false);
233
234 template <class Trait>
235 status_t deserializeCollection(const xmlNode *cur,
236 typename Trait::Collection *collection,
237 typename Trait::PtrSerializingCtx serializingContext);
238 template <class Trait>
239 std::variant<status_t, typename Trait::Element> deserialize(const xmlNode *cur,
240 typename Trait::PtrSerializingCtx serializingContext);
241
242 private:
243 static constexpr const char *rootName = "audioPolicyConfiguration";
244 static constexpr const char *versionAttribute = "version";
245
246 typedef AudioPolicyConfig Element;
247
248 bool mIgnoreVendorExtensions = false;
249 std::string mChannelMasksSeparator = ",";
250 std::string mSamplingRatesSeparator = ",";
251 std::string mFlagsSeparator = "|";
252
253 // Children: ModulesTraits, VolumeTraits, SurroundSoundTraits (optional)
254 };
255
256 // Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
257 struct FreeDelete {
258 // NOTE: Deleting a const object is valid but free() takes a non-const pointer.
operator ()android::__anonf09962200111::FreeDelete259 void operator()(const void* ptr) const {
260 free(const_cast<void*>(ptr));
261 }
262 };
263
264 // Alias for std::unique_ptr<> that uses the C function free() to delete objects.
265 template <typename T>
266 using UniqueCPtr = std::unique_ptr<T, FreeDelete>;
267
268 template <class T>
269 constexpr void (*xmlDeleter)(T* t);
270 template <>
271 constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
272 template <>
__anonf09962200202(xmlChar *s) 273 constexpr auto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };
274
275 /** @return a unique_ptr with the correct deleter for the libxml2 object. */
276 template <class T>
make_xmlUnique(T * t)277 constexpr auto make_xmlUnique(T *t) {
278 // Wrap deleter in lambda to enable empty base optimization
279 auto deleter = [](T *t) { xmlDeleter<T>(t); };
280 return std::unique_ptr<T, decltype(deleter)>{t, deleter};
281 }
282
getXmlAttribute(const xmlNode * cur,const char * attribute)283 std::string getXmlAttribute(const xmlNode *cur, const char *attribute)
284 {
285 auto xmlValue = make_xmlUnique(xmlGetProp(cur, reinterpret_cast<const xmlChar*>(attribute)));
286 if (xmlValue == nullptr) {
287 return "";
288 }
289 std::string value(reinterpret_cast<const char*>(xmlValue.get()));
290 return value;
291 }
292
293 template <class Trait>
getReference(const xmlNode * cur,const std::string & refName)294 const xmlNode* getReference(const xmlNode *cur, const std::string &refName)
295 {
296 for (; cur != NULL; cur = cur->next) {
297 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag))) {
298 for (const xmlNode *child = cur->children; child != NULL; child = child->next) {
299 if ((!xmlStrcmp(child->name,
300 reinterpret_cast<const xmlChar*>(Trait::referenceTag)))) {
301 std::string name = getXmlAttribute(child, Trait::Attributes::referenceName);
302 if (refName == name) {
303 return child;
304 }
305 }
306 }
307 }
308 }
309 return NULL;
310 }
311
312 template <class Trait>
deserializeCollection(const xmlNode * cur,typename Trait::Collection * collection,typename Trait::PtrSerializingCtx serializingContext)313 status_t PolicySerializer::deserializeCollection(const xmlNode *cur,
314 typename Trait::Collection *collection,
315 typename Trait::PtrSerializingCtx serializingContext)
316 {
317 for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
318 const xmlNode *child = NULL;
319 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag))) {
320 child = cur->xmlChildrenNode;
321 } else if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
322 child = cur;
323 }
324 for (; child != NULL; child = child->next) {
325 if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
326 auto maybeElement = deserialize<Trait>(child, serializingContext);
327 if (maybeElement.index() == 1) {
328 status_t status = Trait::addElementToCollection(
329 std::get<1>(maybeElement), collection);
330 if (status != NO_ERROR) {
331 ALOGE("%s: could not add element to %s collection", __func__,
332 Trait::collectionTag);
333 return status;
334 }
335 } else if (mIgnoreVendorExtensions && std::get<status_t>(maybeElement) == NO_INIT) {
336 // Skip a vendor extension element.
337 } else {
338 return BAD_VALUE;
339 }
340 }
341 }
342 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
343 return NO_ERROR;
344 }
345 }
346 return NO_ERROR;
347 }
348
349 template<>
deserialize(const xmlNode * cur,AudioGainTraits::PtrSerializingCtx)350 std::variant<status_t, AudioGainTraits::Element> PolicySerializer::deserialize<AudioGainTraits>(
351 const xmlNode *cur, AudioGainTraits::PtrSerializingCtx /*serializingContext*/)
352 {
353 using Attributes = AudioGainTraits::Attributes;
354
355 static uint32_t index = 0;
356 AudioGainTraits::Element gain = new AudioGain(index++, true);
357
358 std::string mode = getXmlAttribute(cur, Attributes::mode);
359 if (!mode.empty()) {
360 gain->setMode(GainModeConverter::maskFromString(mode, " "));
361 }
362
363 std::string channelsLiteral = getXmlAttribute(cur, Attributes::channelMask);
364 if (!channelsLiteral.empty()) {
365 gain->setChannelMask(channelMaskFromString(channelsLiteral));
366 }
367
368 std::string minValueMBLiteral = getXmlAttribute(cur, Attributes::minValueMB);
369 int32_t minValueMB;
370 if (!minValueMBLiteral.empty() && convertTo(minValueMBLiteral, minValueMB)) {
371 gain->setMinValueInMb(minValueMB);
372 }
373
374 std::string maxValueMBLiteral = getXmlAttribute(cur, Attributes::maxValueMB);
375 int32_t maxValueMB;
376 if (!maxValueMBLiteral.empty() && convertTo(maxValueMBLiteral, maxValueMB)) {
377 gain->setMaxValueInMb(maxValueMB);
378 }
379
380 std::string defaultValueMBLiteral = getXmlAttribute(cur, Attributes::defaultValueMB);
381 int32_t defaultValueMB;
382 if (!defaultValueMBLiteral.empty() && convertTo(defaultValueMBLiteral, defaultValueMB)) {
383 gain->setDefaultValueInMb(defaultValueMB);
384 }
385
386 std::string stepValueMBLiteral = getXmlAttribute(cur, Attributes::stepValueMB);
387 uint32_t stepValueMB;
388 if (!stepValueMBLiteral.empty() && convertTo(stepValueMBLiteral, stepValueMB)) {
389 gain->setStepValueInMb(stepValueMB);
390 }
391
392 std::string minRampMsLiteral = getXmlAttribute(cur, Attributes::minRampMs);
393 uint32_t minRampMs;
394 if (!minRampMsLiteral.empty() && convertTo(minRampMsLiteral, minRampMs)) {
395 gain->setMinRampInMs(minRampMs);
396 }
397
398 std::string maxRampMsLiteral = getXmlAttribute(cur, Attributes::maxRampMs);
399 uint32_t maxRampMs;
400 if (!maxRampMsLiteral.empty() && convertTo(maxRampMsLiteral, maxRampMs)) {
401 gain->setMaxRampInMs(maxRampMs);
402 }
403 std::string useForVolumeLiteral = getXmlAttribute(cur, Attributes::useForVolume);
404 bool useForVolume = false;
405 if (!useForVolumeLiteral.empty() && convertTo(useForVolumeLiteral, useForVolume)) {
406 gain->setUseForVolume(useForVolume);
407 }
408 ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d UseForVolume: %d",
409 __func__, gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
410 gain->getMaxValueInMb(), useForVolume);
411
412 if (gain->getMode() != 0) {
413 return gain;
414 } else {
415 return BAD_VALUE;
416 }
417 }
418
419 template<>
420 std::variant<status_t, AudioProfileTraits::Element>
deserialize(const xmlNode * cur,AudioProfileTraits::PtrSerializingCtx)421 PolicySerializer::deserialize<AudioProfileTraits>(
422 const xmlNode *cur, AudioProfileTraits::PtrSerializingCtx /*serializingContext*/)
423 {
424 using Attributes = AudioProfileTraits::Attributes;
425
426 std::string samplingRates = getXmlAttribute(cur, Attributes::samplingRates);
427 std::string format = getXmlAttribute(cur, Attributes::format);
428 std::string channels = getXmlAttribute(cur, Attributes::channelMasks);
429
430 if (mIgnoreVendorExtensions && maybeVendorExtension(format)) {
431 ALOGI("%s: vendor extension format \"%s\" skipped", __func__, format.c_str());
432 return NO_INIT;
433 }
434 AudioProfileTraits::Element profile = new AudioProfile(formatFromString(format, gDynamicFormat),
435 channelMasksFromString(channels, mChannelMasksSeparator.c_str()),
436 samplingRatesFromString(samplingRates, mSamplingRatesSeparator.c_str()));
437
438 profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
439 profile->setDynamicChannels(profile->getChannels().empty());
440 profile->setDynamicRate(profile->getSampleRates().empty());
441
442 return profile;
443 }
444
445 template<>
deserialize(const xmlNode * child,MixPortTraits::PtrSerializingCtx)446 std::variant<status_t, MixPortTraits::Element> PolicySerializer::deserialize<MixPortTraits>(
447 const xmlNode *child, MixPortTraits::PtrSerializingCtx /*serializingContext*/)
448 {
449 using Attributes = MixPortTraits::Attributes;
450
451 std::string name = getXmlAttribute(child, Attributes::name);
452 if (name.empty()) {
453 ALOGE("%s: No %s found", __func__, Attributes::name);
454 return BAD_VALUE;
455 }
456 ALOGV("%s: %s %s=%s", __func__, MixPortTraits::tag, Attributes::name, name.c_str());
457 std::string role = getXmlAttribute(child, Attributes::role);
458 if (role.empty()) {
459 ALOGE("%s: No %s found", __func__, Attributes::role);
460 return BAD_VALUE;
461 }
462 ALOGV("%s: Role=%s", __func__, role.c_str());
463 audio_port_role_t portRole = (role == Attributes::roleSource) ?
464 AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
465
466 MixPortTraits::Element mixPort = new IOProfile(name, portRole);
467
468 AudioProfileTraits::Collection profiles;
469 status_t status = deserializeCollection<AudioProfileTraits>(child, &profiles, NULL);
470 if (status != NO_ERROR) {
471 return status;
472 }
473 if (profiles.empty()) {
474 profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
475 }
476 // The audio profiles are in order of listed in audio policy configuration file.
477 // Sort audio profiles accroding to the format.
478 sortAudioProfiles(profiles);
479 mixPort->setAudioProfiles(profiles);
480
481 std::string flags = getXmlAttribute(child, Attributes::flags);
482 if (!flags.empty()) {
483 // Source role
484 if (portRole == AUDIO_PORT_ROLE_SOURCE) {
485 mixPort->setFlags(OutputFlagConverter::maskFromString(flags, mFlagsSeparator.c_str()));
486 } else {
487 // Sink role
488 mixPort->setFlags(InputFlagConverter::maskFromString(flags, mFlagsSeparator.c_str()));
489 }
490 }
491 std::string maxOpenCount = getXmlAttribute(child, Attributes::maxOpenCount);
492 if (!maxOpenCount.empty()) {
493 convertTo(maxOpenCount, mixPort->maxOpenCount);
494 }
495 std::string maxActiveCount = getXmlAttribute(child, Attributes::maxActiveCount);
496 if (!maxActiveCount.empty()) {
497 convertTo(maxActiveCount, mixPort->maxActiveCount);
498 }
499 // Deserialize children
500 AudioGainTraits::Collection gains;
501 status = deserializeCollection<AudioGainTraits>(child, &gains, NULL);
502 if (status != NO_ERROR) {
503 return status;
504 }
505 mixPort->setGains(gains);
506
507 return mixPort;
508 }
509
510 template<>
deserialize(const xmlNode * cur,DevicePortTraits::PtrSerializingCtx)511 std::variant<status_t, DevicePortTraits::Element> PolicySerializer::deserialize<DevicePortTraits>(
512 const xmlNode *cur, DevicePortTraits::PtrSerializingCtx /*serializingContext*/)
513 {
514 using Attributes = DevicePortTraits::Attributes;
515 auto& tag = DevicePortTraits::tag;
516
517 std::string name = getXmlAttribute(cur, Attributes::tagName);
518 if (name.empty()) {
519 ALOGE("%s: No %s found", __func__, Attributes::tagName);
520 return BAD_VALUE;
521 }
522 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::tagName, name.c_str());
523 std::string typeName = getXmlAttribute(cur, Attributes::type);
524 if (typeName.empty()) {
525 ALOGE("%s: no type for %s", __func__, name.c_str());
526 return BAD_VALUE;
527 }
528 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::type, typeName.c_str());
529 std::string role = getXmlAttribute(cur, Attributes::role);
530 if (role.empty()) {
531 ALOGE("%s: No %s found", __func__, Attributes::role);
532 return BAD_VALUE;
533 }
534 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::role, role.c_str());
535 audio_port_role_t portRole = (role == Attributes::roleSource) ?
536 AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
537
538 if (mIgnoreVendorExtensions && maybeVendorExtension(typeName)) {
539 ALOGI("%s: vendor extension device type \"%s\" skipped", __func__, typeName.c_str());
540 return NO_INIT;
541 }
542 audio_devices_t type = AUDIO_DEVICE_NONE;
543 if (!DeviceConverter::fromString(typeName, type) ||
544 (!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
545 (!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
546 ALOGW("%s: bad type %08x", __func__, type);
547 return BAD_VALUE;
548 }
549 std::string encodedFormatsLiteral = getXmlAttribute(cur, Attributes::encodedFormats);
550 ALOGV("%s: %s %s=%s", __func__, tag, Attributes::encodedFormats, encodedFormatsLiteral.c_str());
551 FormatVector encodedFormats;
552 if (!encodedFormatsLiteral.empty()) {
553 encodedFormats = formatsFromString(encodedFormatsLiteral, " ");
554 }
555 std::string address = getXmlAttribute(cur, Attributes::address);
556 DevicePortTraits::Element deviceDesc =
557 new DeviceDescriptor(type, name, address, encodedFormats);
558
559 AudioProfileTraits::Collection profiles;
560 status_t status = deserializeCollection<AudioProfileTraits>(cur, &profiles, NULL);
561 if (status != NO_ERROR) {
562 return status;
563 }
564 if (profiles.empty()) {
565 profiles.add(AudioProfile::createFullDynamic(gDynamicFormat));
566 }
567 // The audio profiles are in order of listed in audio policy configuration file.
568 // Sort audio profiles accroding to the format.
569 sortAudioProfiles(profiles);
570 deviceDesc->setAudioProfiles(profiles);
571
572 // Deserialize AudioGain children
573 status = deserializeCollection<AudioGainTraits>(cur, &deviceDesc->mGains, NULL);
574 if (status != NO_ERROR) {
575 return status;
576 }
577 ALOGV("%s: adding device tag %s type %08x address %s", __func__,
578 deviceDesc->getName().c_str(), type, deviceDesc->address().c_str());
579 return deviceDesc;
580 }
581
582 template<>
deserialize(const xmlNode * cur,RouteTraits::PtrSerializingCtx ctx)583 std::variant<status_t, RouteTraits::Element> PolicySerializer::deserialize<RouteTraits>(
584 const xmlNode *cur, RouteTraits::PtrSerializingCtx ctx)
585 {
586 using Attributes = RouteTraits::Attributes;
587
588 std::string type = getXmlAttribute(cur, Attributes::type);
589 if (type.empty()) {
590 ALOGE("%s: No %s found", __func__, Attributes::type);
591 return BAD_VALUE;
592 }
593 audio_route_type_t routeType = (type == Attributes::typeMix) ?
594 AUDIO_ROUTE_MIX : AUDIO_ROUTE_MUX;
595
596 ALOGV("%s: %s %s=%s", __func__, RouteTraits::tag, Attributes::type, type.c_str());
597 RouteTraits::Element route = new AudioRoute(routeType);
598
599 std::string sinkAttr = getXmlAttribute(cur, Attributes::sink);
600 if (sinkAttr.empty()) {
601 ALOGE("%s: No %s found", __func__, Attributes::sink);
602 return BAD_VALUE;
603 }
604 // Convert Sink name to port pointer
605 sp<PolicyAudioPort> sink = ctx->findPortByTagName(sinkAttr);
606 if (sink == NULL && !mIgnoreVendorExtensions) {
607 ALOGE("%s: no sink found with name=%s", __func__, sinkAttr.c_str());
608 return BAD_VALUE;
609 } else if (sink == NULL) {
610 ALOGW("Skipping route to sink \"%s\" as it likely has vendor extension type",
611 sinkAttr.c_str());
612 return NO_INIT;
613 }
614 route->setSink(sink);
615
616 std::string sourcesAttr = getXmlAttribute(cur, Attributes::sources);
617 if (sourcesAttr.empty()) {
618 ALOGE("%s: No %s found", __func__, Attributes::sources);
619 return BAD_VALUE;
620 }
621 // Tokenize and Convert Sources name to port pointer
622 PolicyAudioPortVector sources;
623 UniqueCPtr<char> sourcesLiteral{strndup(
624 sourcesAttr.c_str(), strlen(sourcesAttr.c_str()))};
625 char *devTag = strtok(sourcesLiteral.get(), ",");
626 while (devTag != NULL) {
627 if (strlen(devTag) != 0) {
628 sp<PolicyAudioPort> source = ctx->findPortByTagName(devTag);
629 if (source == NULL && !mIgnoreVendorExtensions) {
630 ALOGE("%s: no source found with name=%s", __func__, devTag);
631 return BAD_VALUE;
632 } else if (source == NULL) {
633 ALOGW("Skipping route source \"%s\" as it likely has vendor extension type",
634 devTag);
635 } else {
636 sources.add(source);
637 }
638 }
639 devTag = strtok(NULL, ",");
640 }
641
642 sink->addRoute(route);
643 for (size_t i = 0; i < sources.size(); i++) {
644 sp<PolicyAudioPort> source = sources.itemAt(i);
645 source->addRoute(route);
646 }
647 route->setSources(sources);
648 return route;
649 }
650
651 template<>
deserialize(const xmlNode * cur,ModuleTraits::PtrSerializingCtx ctx)652 std::variant<status_t, ModuleTraits::Element> PolicySerializer::deserialize<ModuleTraits>(
653 const xmlNode *cur, ModuleTraits::PtrSerializingCtx ctx)
654 {
655 using Attributes = ModuleTraits::Attributes;
656 auto& tag = ModuleTraits::tag;
657 auto& childAttachedDevicesTag = ModuleTraits::childAttachedDevicesTag;
658 auto& childAttachedDeviceTag = ModuleTraits::childAttachedDeviceTag;
659 auto& childDefaultOutputDeviceTag = ModuleTraits::childDefaultOutputDeviceTag;
660
661 std::string name = getXmlAttribute(cur, Attributes::name);
662 if (name.empty()) {
663 ALOGE("%s: No %s found", __func__, Attributes::name);
664 return BAD_VALUE;
665 }
666 uint32_t versionMajor = 0, versionMinor = 0;
667 std::string versionLiteral = getXmlAttribute(cur, Attributes::version);
668 if (!versionLiteral.empty()) {
669 sscanf(versionLiteral.c_str(), "%u.%u", &versionMajor, &versionMinor);
670 ALOGV("%s: mHalVersion = major %u minor %u", __func__,
671 versionMajor, versionMajor);
672 }
673
674 ALOGV("%s: %s %s=%s", __func__, ModuleTraits::tag, Attributes::name, name.c_str());
675
676 ModuleTraits::Element module = new HwModule(name.c_str(), versionMajor, versionMinor);
677
678 // Deserialize children: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
679 MixPortTraits::Collection mixPorts;
680 status_t status = deserializeCollection<MixPortTraits>(cur, &mixPorts, NULL);
681 if (status != NO_ERROR) {
682 return status;
683 }
684 module->setProfiles(mixPorts);
685
686 DevicePortTraits::Collection devicePorts;
687 status = deserializeCollection<DevicePortTraits>(cur, &devicePorts, NULL);
688 if (status != NO_ERROR) {
689 return status;
690 }
691 module->setDeclaredDevices(devicePorts);
692
693 RouteTraits::Collection routes;
694 status = deserializeCollection<RouteTraits>(cur, &routes, module.get());
695 if (status != NO_ERROR) {
696 return status;
697 }
698 module->setRoutes(routes);
699
700 for (const xmlNode *children = cur->xmlChildrenNode; children != NULL;
701 children = children->next) {
702 if (!xmlStrcmp(children->name, reinterpret_cast<const xmlChar*>(childAttachedDevicesTag))) {
703 ALOGV("%s: %s %s found", __func__, tag, childAttachedDevicesTag);
704 for (const xmlNode *child = children->xmlChildrenNode; child != NULL;
705 child = child->next) {
706 if (!xmlStrcmp(child->name,
707 reinterpret_cast<const xmlChar*>(childAttachedDeviceTag))) {
708 auto attachedDevice = make_xmlUnique(xmlNodeListGetString(
709 child->doc, child->xmlChildrenNode, 1));
710 if (attachedDevice != nullptr) {
711 ALOGV("%s: %s %s=%s", __func__, tag, childAttachedDeviceTag,
712 reinterpret_cast<const char*>(attachedDevice.get()));
713 sp<DeviceDescriptor> device = module->getDeclaredDevices().
714 getDeviceFromTagName(std::string(reinterpret_cast<const char*>(
715 attachedDevice.get())));
716 if (device == nullptr && mIgnoreVendorExtensions) {
717 ALOGW("Skipped attached device \"%s\" because it likely uses a vendor"
718 "extension type",
719 reinterpret_cast<const char*>(attachedDevice.get()));
720 continue;
721 }
722 ctx->addDevice(device);
723 }
724 }
725 }
726 }
727 if (!xmlStrcmp(children->name,
728 reinterpret_cast<const xmlChar*>(childDefaultOutputDeviceTag))) {
729 auto defaultOutputDevice = make_xmlUnique(xmlNodeListGetString(
730 children->doc, children->xmlChildrenNode, 1));
731 if (defaultOutputDevice != nullptr) {
732 ALOGV("%s: %s %s=%s", __func__, tag, childDefaultOutputDeviceTag,
733 reinterpret_cast<const char*>(defaultOutputDevice.get()));
734 sp<DeviceDescriptor> device = module->getDeclaredDevices().getDeviceFromTagName(
735 std::string(reinterpret_cast<const char*>(defaultOutputDevice.get())));
736 if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
737 ctx->setDefaultOutputDevice(device);
738 ALOGV("%s: default is %08x",
739 __func__, ctx->getDefaultOutputDevice()->type());
740 }
741 }
742 }
743 }
744 return module;
745 }
746
747 template<>
748 std::variant<status_t, GlobalConfigTraits::Element>
deserialize(const xmlNode * root,GlobalConfigTraits::PtrSerializingCtx config)749 PolicySerializer::deserialize<GlobalConfigTraits>(
750 const xmlNode *root, GlobalConfigTraits::PtrSerializingCtx config)
751 {
752 using Attributes = GlobalConfigTraits::Attributes;
753
754 for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
755 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(GlobalConfigTraits::tag))) {
756 bool value;
757 std::string attr = getXmlAttribute(cur, Attributes::speakerDrcEnabled);
758 if (!attr.empty() &&
759 convertTo<std::string, bool>(attr, value)) {
760 config->setSpeakerDrcEnabled(value);
761 }
762 attr = getXmlAttribute(cur, Attributes::callScreenModeSupported);
763 if (!attr.empty() &&
764 convertTo<std::string, bool>(attr, value)) {
765 config->setCallScreenModeSupported(value);
766 }
767 std::string engineLibrarySuffix = getXmlAttribute(cur, Attributes::engineLibrarySuffix);
768 if (!engineLibrarySuffix.empty()) {
769 config->setEngineLibraryNameSuffix(engineLibrarySuffix);
770 }
771 return NO_ERROR;
772 }
773 }
774 return NO_ERROR;
775 }
776
777 template<>
778 std::variant<status_t, SurroundSoundTraits::Element>
deserialize(const xmlNode * root,SurroundSoundTraits::PtrSerializingCtx config)779 PolicySerializer::deserialize<SurroundSoundTraits>(
780 const xmlNode *root, SurroundSoundTraits::PtrSerializingCtx config)
781 {
782 config->setDefaultSurroundFormats();
783
784 for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
785 if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(SurroundSoundTraits::tag))) {
786 AudioPolicyConfig::SurroundFormats formats;
787 status_t status = deserializeCollection<SurroundSoundFormatTraits>(
788 cur, &formats, nullptr);
789 if (status == NO_ERROR) {
790 config->setSurroundFormats(formats);
791 }
792 return NO_ERROR;
793 }
794 }
795 return NO_ERROR;
796 }
797
798 template<>
799 std::variant<status_t, SurroundSoundFormatTraits::Element>
deserialize(const xmlNode * cur,SurroundSoundFormatTraits::PtrSerializingCtx)800 PolicySerializer::deserialize<SurroundSoundFormatTraits>(
801 const xmlNode *cur, SurroundSoundFormatTraits::PtrSerializingCtx /*serializingContext*/)
802 {
803 using Attributes = SurroundSoundFormatTraits::Attributes;
804
805 std::string formatLiteral = getXmlAttribute(cur, Attributes::name);
806 if (formatLiteral.empty()) {
807 ALOGE("%s: No %s found for a surround format", __func__, Attributes::name);
808 return BAD_VALUE;
809 }
810 if (mIgnoreVendorExtensions && maybeVendorExtension(formatLiteral)) {
811 ALOGI("%s: vendor extension format \"%s\" skipped", __func__, formatLiteral.c_str());
812 return NO_INIT;
813 }
814 audio_format_t format = formatFromString(formatLiteral);
815 if (format == AUDIO_FORMAT_DEFAULT) {
816 ALOGE("%s: Unrecognized format %s", __func__, formatLiteral.c_str());
817 return BAD_VALUE;
818 }
819 SurroundSoundFormatTraits::Element pair = std::make_pair(
820 format, SurroundSoundFormatTraits::Collection::mapped_type{});
821
822 std::string subformatsLiteral = getXmlAttribute(cur, Attributes::subformats);
823 if (subformatsLiteral.empty()) return pair;
824 FormatVector subformats = formatsFromString(subformatsLiteral, " ");
825 for (const auto& subformat : subformats) {
826 auto result = pair.second.insert(subformat);
827 if (!result.second) {
828 ALOGE("%s: could not add subformat %x to collection", __func__, subformat);
829 return BAD_VALUE;
830 }
831 }
832 return pair;
833 }
834
deserialize(const char * configFile,AudioPolicyConfig * config,bool ignoreVendorExtensions)835 status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config,
836 bool ignoreVendorExtensions)
837 {
838 mIgnoreVendorExtensions = ignoreVendorExtensions;
839 auto doc = make_xmlUnique(xmlParseFile(configFile));
840 if (doc == nullptr) {
841 ALOGE("%s: Could not parse %s document.", __func__, configFile);
842 return BAD_VALUE;
843 }
844 xmlNodePtr root = xmlDocGetRootElement(doc.get());
845 if (root == NULL) {
846 ALOGE("%s: Could not parse %s document: empty.", __func__, configFile);
847 return BAD_VALUE;
848 }
849 if (xmlXIncludeProcess(doc.get()) < 0) {
850 ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __func__, configFile);
851 }
852
853 if (xmlStrcmp(root->name, reinterpret_cast<const xmlChar*>(rootName))) {
854 ALOGE("%s: No %s root element found in xml data %s.", __func__, rootName,
855 reinterpret_cast<const char*>(root->name));
856 return BAD_VALUE;
857 }
858
859 std::string version = getXmlAttribute(root, versionAttribute);
860 if (version.empty()) {
861 ALOGE("%s: No version found in root node %s", __func__, rootName);
862 return BAD_VALUE;
863 }
864 if (version == "7.0") {
865 mChannelMasksSeparator = mSamplingRatesSeparator = mFlagsSeparator = " ";
866 } else if (version != "1.0") {
867 ALOGE("%s: Version does not match; expected \"1.0\" or \"7.0\" got \"%s\"",
868 __func__, version.c_str());
869 return BAD_VALUE;
870 }
871 // Let's deserialize children
872 // Modules
873 ModuleTraits::Collection modules;
874 status_t status = deserializeCollection<ModuleTraits>(root, &modules, config);
875 if (status != NO_ERROR) {
876 return status;
877 }
878 config->setHwModules(modules);
879
880 // Global Configuration
881 deserialize<GlobalConfigTraits>(root, config);
882
883 // Surround configuration
884 deserialize<SurroundSoundTraits>(root, config);
885
886 return android::OK;
887 }
888
889 } // namespace
890
deserializeAudioPolicyFile(const char * fileName,AudioPolicyConfig * config)891 status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config)
892 {
893 PolicySerializer serializer;
894 status_t status = serializer.deserialize(fileName, config);
895 if (status != OK) config->clear();
896 return status;
897 }
898
deserializeAudioPolicyFileForVts(const char * fileName,AudioPolicyConfig * config)899 status_t deserializeAudioPolicyFileForVts(const char *fileName, AudioPolicyConfig *config)
900 {
901 PolicySerializer serializer;
902 status_t status = serializer.deserialize(fileName, config, true /*ignoreVendorExtensions*/);
903 if (status != OK) config->clear();
904 return status;
905 }
906
907 } // namespace android
908