blob: f8174f8c286f1b1302395e999b8ab2156fdbd052 [file] [log] [blame]
François Gaffie20f06f92015-03-24 09:01:14 +01001/*
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::AudioPolicyEngine/PFWWrapper"
François Gaffie814ce802016-01-18 11:23:47 +010018//#define LOG_NDEBUG 0
François Gaffie20f06f92015-03-24 09:01:14 +010019
20#include "ParameterManagerWrapper.h"
21#include "audio_policy_criteria_conf.h"
22#include <ParameterMgrPlatformConnector.h>
23#include <SelectionCriterionTypeInterface.h>
24#include <SelectionCriterionInterface.h>
Mikhail Naganov913d06c2016-11-01 12:49:22 -070025#include <media/convert.h>
François Gaffie20f06f92015-03-24 09:01:14 +010026#include <algorithm>
27#include <cutils/config_utils.h>
28#include <cutils/misc.h>
29#include <fstream>
30#include <limits>
31#include <sstream>
32#include <string>
33#include <vector>
34#include <stdint.h>
35#include <cmath>
36#include <utils/Log.h>
37
38using std::string;
39using std::map;
40using std::vector;
41
42/// PFW related definitions
43// Logger
44class ParameterMgrPlatformConnectorLogger : public CParameterMgrPlatformConnector::ILogger
45{
46public:
47 ParameterMgrPlatformConnectorLogger() {}
48
François Gaffiec1391f92015-12-10 09:43:48 +010049 virtual void info(const string &log)
François Gaffie20f06f92015-03-24 09:01:14 +010050 {
Liu Changcheng30cf41f2016-12-07 18:58:19 +080051 ALOGV("policy-parameter-manager: %s", log.c_str());
François Gaffiec1391f92015-12-10 09:43:48 +010052 }
53 virtual void warning(const string &log)
54 {
55 ALOGW("policy-parameter-manager: %s", log.c_str());
François Gaffie20f06f92015-03-24 09:01:14 +010056 }
57};
58
François Gaffief19cf792018-05-30 17:22:17 +020059namespace android {
François Gaffie20f06f92015-03-24 09:01:14 +010060
61using utilities::convertTo;
62
François Gaffief19cf792018-05-30 17:22:17 +020063namespace audio_policy {
64
François Gaffie20f06f92015-03-24 09:01:14 +010065const char *const ParameterManagerWrapper::mPolicyPfwDefaultConfFileName =
66 "/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
67
68template <>
69struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionInterface> {};
70template <>
71struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionTypeInterface> {};
72
73ParameterManagerWrapper::ParameterManagerWrapper()
74 : mPfwConnectorLogger(new ParameterMgrPlatformConnectorLogger)
75{
76 // Connector
77 mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwDefaultConfFileName);
78
79 // Logger
80 mPfwConnector->setLogger(mPfwConnectorLogger);
81
82 // Load criteria file
83 if ((loadAudioPolicyCriteriaConfig(gAudioPolicyCriteriaVendorConfFilePath) != NO_ERROR) &&
84 (loadAudioPolicyCriteriaConfig(gAudioPolicyCriteriaConfFilePath) != NO_ERROR)) {
85 ALOGE("%s: Neither vendor conf file (%s) nor system conf file (%s) could be found",
86 __FUNCTION__, gAudioPolicyCriteriaVendorConfFilePath,
87 gAudioPolicyCriteriaConfFilePath);
88 }
François Gaffie20f06f92015-03-24 09:01:14 +010089}
90
91ParameterManagerWrapper::~ParameterManagerWrapper()
92{
93 // Unset logger
94 mPfwConnector->setLogger(NULL);
95 // Remove logger
96 delete mPfwConnectorLogger;
97 // Remove connector
98 delete mPfwConnector;
99}
100
101status_t ParameterManagerWrapper::start()
102{
103 ALOGD("%s: in", __FUNCTION__);
104 /// Start PFW
105 std::string error;
106 if (!mPfwConnector->start(error)) {
107 ALOGE("%s: Policy PFW start error: %s", __FUNCTION__, error.c_str());
108 return NO_INIT;
109 }
110 ALOGD("%s: Policy PFW successfully started!", __FUNCTION__);
111 return NO_ERROR;
112}
113
114
115void ParameterManagerWrapper::addCriterionType(const string &typeName, bool isInclusive)
116{
117 ALOG_ASSERT(mPolicyCriterionTypes.find(typeName) == mPolicyCriterionTypes.end(),
François Gaffie814ce802016-01-18 11:23:47 +0100118 "CriterionType %s already added", typeName.c_str());
François Gaffie20f06f92015-03-24 09:01:14 +0100119 ALOGD("%s: Adding new criterionType %s", __FUNCTION__, typeName.c_str());
120
121 mPolicyCriterionTypes[typeName] = mPfwConnector->createSelectionCriterionType(isInclusive);
122}
123
124void ParameterManagerWrapper::addCriterionTypeValuePair(
125 const string &typeName,
126 uint32_t numericValue,
127 const string &literalValue)
128{
129 ALOG_ASSERT(mPolicyCriterionTypes.find(typeName) != mPolicyCriterionTypes.end(),
François Gaffie814ce802016-01-18 11:23:47 +0100130 "CriterionType %s not found", typeName.c_str());
François Gaffie20f06f92015-03-24 09:01:14 +0100131 ALOGV("%s: Adding new value pair (%d,%s) for criterionType %s", __FUNCTION__,
132 numericValue, literalValue.c_str(), typeName.c_str());
133 ISelectionCriterionTypeInterface *criterionType = mPolicyCriterionTypes[typeName];
François Gaffiec1391f92015-12-10 09:43:48 +0100134 std::string error;
135 criterionType->addValuePair(numericValue, literalValue, error);
François Gaffie20f06f92015-03-24 09:01:14 +0100136}
137
138void ParameterManagerWrapper::loadCriterionType(cnode *root, bool isInclusive)
139{
140 ALOG_ASSERT(root != NULL, "error in parsing file");
141 cnode *node;
142 for (node = root->first_child; node != NULL; node = node->next) {
143
144 ALOG_ASSERT(node != NULL, "error in parsing file");
145 const char *typeName = node->name;
François Gaffie0f17ab72015-05-13 18:13:00 +0200146 char *valueNames = strndup(node->value, strlen(node->value));
François Gaffie20f06f92015-03-24 09:01:14 +0100147
148 addCriterionType(typeName, isInclusive);
149
150 uint32_t index = 0;
151 char *ctx;
152 char *valueName = strtok_r(valueNames, ",", &ctx);
153 while (valueName != NULL) {
154 if (strlen(valueName) != 0) {
155
156 // Conf file may use or not pair, if no pair, use incremental index, else
157 // use provided index.
158 if (strchr(valueName, ':') != NULL) {
159
160 char *first = strtok(valueName, ":");
161 char *second = strtok(NULL, ":");
162 ALOG_ASSERT((first != NULL) && (strlen(first) != 0) &&
163 (second != NULL) && (strlen(second) != 0),
164 "invalid value pair");
165
166 if (!convertTo<string, uint32_t>(first, index)) {
167 ALOGE("%s: Invalid index(%s) found", __FUNCTION__, first);
168 }
169 addCriterionTypeValuePair(typeName, index, second);
170 } else {
171
172 uint32_t pfwIndex = isInclusive ? 1 << index : index;
173 addCriterionTypeValuePair(typeName, pfwIndex, valueName);
174 index += 1;
175 }
176 }
177 valueName = strtok_r(NULL, ",", &ctx);
178 }
François Gaffie0f17ab72015-05-13 18:13:00 +0200179 free(valueNames);
François Gaffie20f06f92015-03-24 09:01:14 +0100180 }
181}
182
183void ParameterManagerWrapper::loadInclusiveCriterionType(cnode *root)
184{
185 ALOG_ASSERT(root != NULL, "error in parsing file");
186 cnode *node = config_find(root, gInclusiveCriterionTypeTag.c_str());
187 if (node == NULL) {
188 return;
189 }
190 loadCriterionType(node, true);
191}
192
193void ParameterManagerWrapper::loadExclusiveCriterionType(cnode *root)
194{
195 ALOG_ASSERT(root != NULL, "error in parsing file");
196 cnode *node = config_find(root, gExclusiveCriterionTypeTag.c_str());
197 if (node == NULL) {
198 return;
199 }
200 loadCriterionType(node, false);
201}
202
203void ParameterManagerWrapper::parseChildren(cnode *root, string &defaultValue, string &type)
204{
205 ALOG_ASSERT(root != NULL, "error in parsing file");
206 cnode *node;
207 for (node = root->first_child; node != NULL; node = node->next) {
208 ALOG_ASSERT(node != NULL, "error in parsing file");
209
210 if (string(node->name) == gDefaultTag) {
211 defaultValue = node->value;
212 } else if (string(node->name) == gTypeTag) {
213 type = node->value;
214 } else {
215 ALOGE("%s: Unrecognized %s %s node", __FUNCTION__, node->name, node->value);
216 }
217 }
218}
219
220template <typename T>
221T *ParameterManagerWrapper::getElement(const string &name, std::map<string, T *> &elementsMap)
222{
223 parameterManagerElementSupported<T>();
224 typename std::map<string, T *>::iterator it = elementsMap.find(name);
François Gaffie814ce802016-01-18 11:23:47 +0100225 ALOG_ASSERT(it != elementsMap.end(), "Element %s not found", name.c_str());
226 return it != elementsMap.end() ? it->second : NULL;
François Gaffie20f06f92015-03-24 09:01:14 +0100227}
228
229template <typename T>
230const T *ParameterManagerWrapper::getElement(const string &name, const std::map<string, T *> &elementsMap) const
231{
232 parameterManagerElementSupported<T>();
233 typename std::map<string, T *>::const_iterator it = elementsMap.find(name);
François Gaffie814ce802016-01-18 11:23:47 +0100234 ALOG_ASSERT(it != elementsMap.end(), "Element %s not found", name.c_str());
235 return it != elementsMap.end() ? it->second : NULL;
François Gaffie20f06f92015-03-24 09:01:14 +0100236}
237
238void ParameterManagerWrapper::loadCriteria(cnode *root)
239{
240 ALOG_ASSERT(root != NULL, "error in parsing file");
241 cnode *node = config_find(root, gCriterionTag.c_str());
242
243 if (node == NULL) {
244 ALOGW("%s: no inclusive criteria found", __FUNCTION__);
245 return;
246 }
247 for (node = node->first_child; node != NULL; node = node->next) {
248 loadCriterion(node);
249 }
250}
251
252void ParameterManagerWrapper::addCriterion(const string &name, const string &typeName,
253 const string &defaultLiteralValue)
254{
François Gaffie814ce802016-01-18 11:23:47 +0100255 ALOG_ASSERT(mPolicyCriteria.find(name) == mPolicyCriteria.end(),
256 "Route Criterion %s already added", name.c_str());
François Gaffie20f06f92015-03-24 09:01:14 +0100257
258 ISelectionCriterionTypeInterface *criterionType =
259 getElement<ISelectionCriterionTypeInterface>(typeName, mPolicyCriterionTypes);
260
261 ISelectionCriterionInterface *criterion =
262 mPfwConnector->createSelectionCriterion(name, criterionType);
263
264 mPolicyCriteria[name] = criterion;
265 int numericalValue = 0;
266 if (!criterionType->getNumericalValue(defaultLiteralValue.c_str(), numericalValue)) {
267 ALOGE("%s; trying to apply invalid default literal value (%s)", __FUNCTION__,
268 defaultLiteralValue.c_str());
269 }
270 criterion->setCriterionState(numericalValue);
271}
272
273void ParameterManagerWrapper::loadCriterion(cnode *root)
274{
275 ALOG_ASSERT(root != NULL, "error in parsing file");
276 const char *criterionName = root->name;
277
278 ALOG_ASSERT(mPolicyCriteria.find(criterionName) == mPolicyCriteria.end(),
François Gaffie814ce802016-01-18 11:23:47 +0100279 "Criterion %s already added", criterionName);
François Gaffie20f06f92015-03-24 09:01:14 +0100280
281 string paramKeyName = "";
282 string path = "";
283 string typeName = "";
284 string defaultValue = "";
285
286 parseChildren(root, defaultValue, typeName);
287
288 addCriterion(criterionName, typeName, defaultValue);
289}
290
291void ParameterManagerWrapper::loadConfig(cnode *root)
292{
293 ALOG_ASSERT(root != NULL, "error in parsing file");
294 cnode *node = config_find(root, gPolicyConfTag.c_str());
295 if (node == NULL) {
296 ALOGW("%s: Could not find node for pfw", __FUNCTION__);
297 return;
298 }
299 ALOGD("%s: Loading conf for pfw", __FUNCTION__);
300 loadInclusiveCriterionType(node);
301 loadExclusiveCriterionType(node);
302 loadCriteria(node);
303}
304
305
306status_t ParameterManagerWrapper::loadAudioPolicyCriteriaConfig(const char *path)
307{
308 ALOG_ASSERT(path != NULL, "error in parsing file: empty path");
309 cnode *root;
310 char *data;
311 ALOGD("%s", __FUNCTION__);
312 data = (char *)load_file(path, NULL);
313 if (data == NULL) {
314 return -ENODEV;
315 }
316 root = config_node("", "");
317 ALOG_ASSERT(root != NULL, "Unable to allocate a configuration node");
318 config_load(root, data);
319
320 loadConfig(root);
321
322 config_free(root);
323 free(root);
324 free(data);
325 ALOGD("%s: loaded", __FUNCTION__);
326 return NO_ERROR;
327}
328
329bool ParameterManagerWrapper::isStarted()
330{
331 return mPfwConnector && mPfwConnector->isStarted();
332}
333
334status_t ParameterManagerWrapper::setPhoneState(audio_mode_t mode)
335{
François Gaffie814ce802016-01-18 11:23:47 +0100336 ISelectionCriterionInterface *criterion =
337 getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria);
338 if (criterion == NULL) {
339 ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionTag.c_str());
340 return BAD_VALUE;
341 }
François Gaffie20f06f92015-03-24 09:01:14 +0100342 if (!isValueValidForCriterion(criterion, static_cast<int>(mode))) {
343 return BAD_VALUE;
344 }
345 criterion->setCriterionState((int)(mode));
346 applyPlatformConfiguration();
347 return NO_ERROR;
348}
349
350audio_mode_t ParameterManagerWrapper::getPhoneState() const
351{
352 const ISelectionCriterionInterface *criterion =
353 getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria);
François Gaffie814ce802016-01-18 11:23:47 +0100354 if (criterion == NULL) {
355 ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionTag.c_str());
356 return AUDIO_MODE_NORMAL;
357 }
François Gaffie20f06f92015-03-24 09:01:14 +0100358 return static_cast<audio_mode_t>(criterion->getCriterionState());
359}
360
361status_t ParameterManagerWrapper::setForceUse(audio_policy_force_use_t usage,
362 audio_policy_forced_cfg_t config)
363{
364 // @todo: return an error on a unsupported value
365 if (usage > AUDIO_POLICY_FORCE_USE_CNT) {
366 return BAD_VALUE;
367 }
368
François Gaffie814ce802016-01-18 11:23:47 +0100369 ISelectionCriterionInterface *criterion =
370 getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
371 if (criterion == NULL) {
372 ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage].c_str());
373 return BAD_VALUE;
374 }
François Gaffie20f06f92015-03-24 09:01:14 +0100375 if (!isValueValidForCriterion(criterion, static_cast<int>(config))) {
376 return BAD_VALUE;
377 }
378 criterion->setCriterionState((int)config);
379 applyPlatformConfiguration();
380 return NO_ERROR;
381}
382
383audio_policy_forced_cfg_t ParameterManagerWrapper::getForceUse(audio_policy_force_use_t usage) const
384{
385 // @todo: return an error on a unsupported value
386 if (usage > AUDIO_POLICY_FORCE_USE_CNT) {
387 return AUDIO_POLICY_FORCE_NONE;
388 }
389 const ISelectionCriterionInterface *criterion =
390 getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
François Gaffie814ce802016-01-18 11:23:47 +0100391 if (criterion == NULL) {
392 ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage].c_str());
393 return AUDIO_POLICY_FORCE_NONE;
394 }
François Gaffie20f06f92015-03-24 09:01:14 +0100395 return static_cast<audio_policy_forced_cfg_t>(criterion->getCriterionState());
396}
397
398bool ParameterManagerWrapper::isValueValidForCriterion(ISelectionCriterionInterface *criterion,
399 int valueToCheck)
400{
401 const ISelectionCriterionTypeInterface *interface = criterion->getCriterionType();
402 string literalValue;
403 return interface->getLiteralValue(valueToCheck, literalValue);
404}
405
François Gaffiea3e696d2015-12-18 09:38:43 +0100406status_t ParameterManagerWrapper::setAvailableInputDevices(audio_devices_t inputDevices)
François Gaffie20f06f92015-03-24 09:01:14 +0100407{
François Gaffie814ce802016-01-18 11:23:47 +0100408 ISelectionCriterionInterface *criterion =
409 getElement<ISelectionCriterionInterface>(gInputDeviceCriterionTag, mPolicyCriteria);
François Gaffie20f06f92015-03-24 09:01:14 +0100410 if (criterion == NULL) {
François Gaffie814ce802016-01-18 11:23:47 +0100411 ALOGE("%s: no criterion found for %s", __FUNCTION__, gInputDeviceCriterionTag.c_str());
François Gaffie20f06f92015-03-24 09:01:14 +0100412 return DEAD_OBJECT;
413 }
François Gaffiea3e696d2015-12-18 09:38:43 +0100414 criterion->setCriterionState(inputDevices & ~AUDIO_DEVICE_BIT_IN);
415 applyPlatformConfiguration();
416 return NO_ERROR;
417}
François Gaffie20f06f92015-03-24 09:01:14 +0100418
François Gaffiea3e696d2015-12-18 09:38:43 +0100419status_t ParameterManagerWrapper::setAvailableOutputDevices(audio_devices_t outputDevices)
420{
François Gaffie814ce802016-01-18 11:23:47 +0100421 ISelectionCriterionInterface *criterion =
422 getElement<ISelectionCriterionInterface>(gOutputDeviceCriterionTag, mPolicyCriteria);
François Gaffiea3e696d2015-12-18 09:38:43 +0100423 if (criterion == NULL) {
François Gaffie814ce802016-01-18 11:23:47 +0100424 ALOGE("%s: no criterion found for %s", __FUNCTION__, gOutputDeviceCriterionTag.c_str());
François Gaffiea3e696d2015-12-18 09:38:43 +0100425 return DEAD_OBJECT;
François Gaffie20f06f92015-03-24 09:01:14 +0100426 }
François Gaffiea3e696d2015-12-18 09:38:43 +0100427 criterion->setCriterionState(outputDevices);
François Gaffie20f06f92015-03-24 09:01:14 +0100428 applyPlatformConfiguration();
429 return NO_ERROR;
430}
431
432void ParameterManagerWrapper::applyPlatformConfiguration()
433{
434 mPfwConnector->applyConfigurations();
435}
436
437} // namespace audio_policy
438} // namespace android