blob: cc4d4db69d28a3e96c49ffef618aef0f4e02340e [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>
25#include <convert.h>
26#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
49 virtual void log(bool isWarning, const string &log)
50 {
51 const static string format("policy-parameter-manager: ");
52
53 if (isWarning) {
54 ALOGW("%s %s", format.c_str(), log.c_str());
55 } else {
56 ALOGD("%s %s", format.c_str(), log.c_str());
57 }
58 }
59};
60
61namespace android
62{
63
64using utilities::convertTo;
65
66namespace audio_policy
67{
68const char *const ParameterManagerWrapper::mPolicyPfwDefaultConfFileName =
69 "/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
70
71template <>
72struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionInterface> {};
73template <>
74struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionTypeInterface> {};
75
76ParameterManagerWrapper::ParameterManagerWrapper()
77 : mPfwConnectorLogger(new ParameterMgrPlatformConnectorLogger)
78{
79 // Connector
80 mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwDefaultConfFileName);
81
82 // Logger
83 mPfwConnector->setLogger(mPfwConnectorLogger);
84
85 // Load criteria file
86 if ((loadAudioPolicyCriteriaConfig(gAudioPolicyCriteriaVendorConfFilePath) != NO_ERROR) &&
87 (loadAudioPolicyCriteriaConfig(gAudioPolicyCriteriaConfFilePath) != NO_ERROR)) {
88 ALOGE("%s: Neither vendor conf file (%s) nor system conf file (%s) could be found",
89 __FUNCTION__, gAudioPolicyCriteriaVendorConfFilePath,
90 gAudioPolicyCriteriaConfFilePath);
91 }
François Gaffie20f06f92015-03-24 09:01:14 +010092}
93
94ParameterManagerWrapper::~ParameterManagerWrapper()
95{
96 // Unset logger
97 mPfwConnector->setLogger(NULL);
98 // Remove logger
99 delete mPfwConnectorLogger;
100 // Remove connector
101 delete mPfwConnector;
102}
103
104status_t ParameterManagerWrapper::start()
105{
106 ALOGD("%s: in", __FUNCTION__);
107 /// Start PFW
108 std::string error;
109 if (!mPfwConnector->start(error)) {
110 ALOGE("%s: Policy PFW start error: %s", __FUNCTION__, error.c_str());
111 return NO_INIT;
112 }
113 ALOGD("%s: Policy PFW successfully started!", __FUNCTION__);
114 return NO_ERROR;
115}
116
117
118void ParameterManagerWrapper::addCriterionType(const string &typeName, bool isInclusive)
119{
120 ALOG_ASSERT(mPolicyCriterionTypes.find(typeName) == mPolicyCriterionTypes.end(),
François Gaffie814ce802016-01-18 11:23:47 +0100121 "CriterionType %s already added", typeName.c_str());
François Gaffie20f06f92015-03-24 09:01:14 +0100122 ALOGD("%s: Adding new criterionType %s", __FUNCTION__, typeName.c_str());
123
124 mPolicyCriterionTypes[typeName] = mPfwConnector->createSelectionCriterionType(isInclusive);
125}
126
127void ParameterManagerWrapper::addCriterionTypeValuePair(
128 const string &typeName,
129 uint32_t numericValue,
130 const string &literalValue)
131{
132 ALOG_ASSERT(mPolicyCriterionTypes.find(typeName) != mPolicyCriterionTypes.end(),
François Gaffie814ce802016-01-18 11:23:47 +0100133 "CriterionType %s not found", typeName.c_str());
François Gaffie20f06f92015-03-24 09:01:14 +0100134 ALOGV("%s: Adding new value pair (%d,%s) for criterionType %s", __FUNCTION__,
135 numericValue, literalValue.c_str(), typeName.c_str());
136 ISelectionCriterionTypeInterface *criterionType = mPolicyCriterionTypes[typeName];
137 criterionType->addValuePair(numericValue, literalValue.c_str());
138}
139
140void ParameterManagerWrapper::loadCriterionType(cnode *root, bool isInclusive)
141{
142 ALOG_ASSERT(root != NULL, "error in parsing file");
143 cnode *node;
144 for (node = root->first_child; node != NULL; node = node->next) {
145
146 ALOG_ASSERT(node != NULL, "error in parsing file");
147 const char *typeName = node->name;
François Gaffie0f17ab72015-05-13 18:13:00 +0200148 char *valueNames = strndup(node->value, strlen(node->value));
François Gaffie20f06f92015-03-24 09:01:14 +0100149
150 addCriterionType(typeName, isInclusive);
151
152 uint32_t index = 0;
153 char *ctx;
154 char *valueName = strtok_r(valueNames, ",", &ctx);
155 while (valueName != NULL) {
156 if (strlen(valueName) != 0) {
157
158 // Conf file may use or not pair, if no pair, use incremental index, else
159 // use provided index.
160 if (strchr(valueName, ':') != NULL) {
161
162 char *first = strtok(valueName, ":");
163 char *second = strtok(NULL, ":");
164 ALOG_ASSERT((first != NULL) && (strlen(first) != 0) &&
165 (second != NULL) && (strlen(second) != 0),
166 "invalid value pair");
167
168 if (!convertTo<string, uint32_t>(first, index)) {
169 ALOGE("%s: Invalid index(%s) found", __FUNCTION__, first);
170 }
171 addCriterionTypeValuePair(typeName, index, second);
172 } else {
173
174 uint32_t pfwIndex = isInclusive ? 1 << index : index;
175 addCriterionTypeValuePair(typeName, pfwIndex, valueName);
176 index += 1;
177 }
178 }
179 valueName = strtok_r(NULL, ",", &ctx);
180 }
François Gaffie0f17ab72015-05-13 18:13:00 +0200181 free(valueNames);
François Gaffie20f06f92015-03-24 09:01:14 +0100182 }
183}
184
185void ParameterManagerWrapper::loadInclusiveCriterionType(cnode *root)
186{
187 ALOG_ASSERT(root != NULL, "error in parsing file");
188 cnode *node = config_find(root, gInclusiveCriterionTypeTag.c_str());
189 if (node == NULL) {
190 return;
191 }
192 loadCriterionType(node, true);
193}
194
195void ParameterManagerWrapper::loadExclusiveCriterionType(cnode *root)
196{
197 ALOG_ASSERT(root != NULL, "error in parsing file");
198 cnode *node = config_find(root, gExclusiveCriterionTypeTag.c_str());
199 if (node == NULL) {
200 return;
201 }
202 loadCriterionType(node, false);
203}
204
205void ParameterManagerWrapper::parseChildren(cnode *root, string &defaultValue, string &type)
206{
207 ALOG_ASSERT(root != NULL, "error in parsing file");
208 cnode *node;
209 for (node = root->first_child; node != NULL; node = node->next) {
210 ALOG_ASSERT(node != NULL, "error in parsing file");
211
212 if (string(node->name) == gDefaultTag) {
213 defaultValue = node->value;
214 } else if (string(node->name) == gTypeTag) {
215 type = node->value;
216 } else {
217 ALOGE("%s: Unrecognized %s %s node", __FUNCTION__, node->name, node->value);
218 }
219 }
220}
221
222template <typename T>
223T *ParameterManagerWrapper::getElement(const string &name, std::map<string, T *> &elementsMap)
224{
225 parameterManagerElementSupported<T>();
226 typename std::map<string, T *>::iterator it = elementsMap.find(name);
François Gaffie814ce802016-01-18 11:23:47 +0100227 ALOG_ASSERT(it != elementsMap.end(), "Element %s not found", name.c_str());
228 return it != elementsMap.end() ? it->second : NULL;
François Gaffie20f06f92015-03-24 09:01:14 +0100229}
230
231template <typename T>
232const T *ParameterManagerWrapper::getElement(const string &name, const std::map<string, T *> &elementsMap) const
233{
234 parameterManagerElementSupported<T>();
235 typename std::map<string, T *>::const_iterator it = elementsMap.find(name);
François Gaffie814ce802016-01-18 11:23:47 +0100236 ALOG_ASSERT(it != elementsMap.end(), "Element %s not found", name.c_str());
237 return it != elementsMap.end() ? it->second : NULL;
François Gaffie20f06f92015-03-24 09:01:14 +0100238}
239
240void ParameterManagerWrapper::loadCriteria(cnode *root)
241{
242 ALOG_ASSERT(root != NULL, "error in parsing file");
243 cnode *node = config_find(root, gCriterionTag.c_str());
244
245 if (node == NULL) {
246 ALOGW("%s: no inclusive criteria found", __FUNCTION__);
247 return;
248 }
249 for (node = node->first_child; node != NULL; node = node->next) {
250 loadCriterion(node);
251 }
252}
253
254void ParameterManagerWrapper::addCriterion(const string &name, const string &typeName,
255 const string &defaultLiteralValue)
256{
François Gaffie814ce802016-01-18 11:23:47 +0100257 ALOG_ASSERT(mPolicyCriteria.find(name) == mPolicyCriteria.end(),
258 "Route Criterion %s already added", name.c_str());
François Gaffie20f06f92015-03-24 09:01:14 +0100259
260 ISelectionCriterionTypeInterface *criterionType =
261 getElement<ISelectionCriterionTypeInterface>(typeName, mPolicyCriterionTypes);
262
263 ISelectionCriterionInterface *criterion =
264 mPfwConnector->createSelectionCriterion(name, criterionType);
265
266 mPolicyCriteria[name] = criterion;
267 int numericalValue = 0;
268 if (!criterionType->getNumericalValue(defaultLiteralValue.c_str(), numericalValue)) {
269 ALOGE("%s; trying to apply invalid default literal value (%s)", __FUNCTION__,
270 defaultLiteralValue.c_str());
271 }
272 criterion->setCriterionState(numericalValue);
273}
274
275void ParameterManagerWrapper::loadCriterion(cnode *root)
276{
277 ALOG_ASSERT(root != NULL, "error in parsing file");
278 const char *criterionName = root->name;
279
280 ALOG_ASSERT(mPolicyCriteria.find(criterionName) == mPolicyCriteria.end(),
François Gaffie814ce802016-01-18 11:23:47 +0100281 "Criterion %s already added", criterionName);
François Gaffie20f06f92015-03-24 09:01:14 +0100282
283 string paramKeyName = "";
284 string path = "";
285 string typeName = "";
286 string defaultValue = "";
287
288 parseChildren(root, defaultValue, typeName);
289
290 addCriterion(criterionName, typeName, defaultValue);
291}
292
293void ParameterManagerWrapper::loadConfig(cnode *root)
294{
295 ALOG_ASSERT(root != NULL, "error in parsing file");
296 cnode *node = config_find(root, gPolicyConfTag.c_str());
297 if (node == NULL) {
298 ALOGW("%s: Could not find node for pfw", __FUNCTION__);
299 return;
300 }
301 ALOGD("%s: Loading conf for pfw", __FUNCTION__);
302 loadInclusiveCriterionType(node);
303 loadExclusiveCriterionType(node);
304 loadCriteria(node);
305}
306
307
308status_t ParameterManagerWrapper::loadAudioPolicyCriteriaConfig(const char *path)
309{
310 ALOG_ASSERT(path != NULL, "error in parsing file: empty path");
311 cnode *root;
312 char *data;
313 ALOGD("%s", __FUNCTION__);
314 data = (char *)load_file(path, NULL);
315 if (data == NULL) {
316 return -ENODEV;
317 }
318 root = config_node("", "");
319 ALOG_ASSERT(root != NULL, "Unable to allocate a configuration node");
320 config_load(root, data);
321
322 loadConfig(root);
323
324 config_free(root);
325 free(root);
326 free(data);
327 ALOGD("%s: loaded", __FUNCTION__);
328 return NO_ERROR;
329}
330
331bool ParameterManagerWrapper::isStarted()
332{
333 return mPfwConnector && mPfwConnector->isStarted();
334}
335
336status_t ParameterManagerWrapper::setPhoneState(audio_mode_t mode)
337{
François Gaffie814ce802016-01-18 11:23:47 +0100338 ISelectionCriterionInterface *criterion =
339 getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria);
340 if (criterion == NULL) {
341 ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionTag.c_str());
342 return BAD_VALUE;
343 }
François Gaffie20f06f92015-03-24 09:01:14 +0100344 if (!isValueValidForCriterion(criterion, static_cast<int>(mode))) {
345 return BAD_VALUE;
346 }
347 criterion->setCriterionState((int)(mode));
348 applyPlatformConfiguration();
349 return NO_ERROR;
350}
351
352audio_mode_t ParameterManagerWrapper::getPhoneState() const
353{
354 const ISelectionCriterionInterface *criterion =
355 getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria);
François Gaffie814ce802016-01-18 11:23:47 +0100356 if (criterion == NULL) {
357 ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionTag.c_str());
358 return AUDIO_MODE_NORMAL;
359 }
François Gaffie20f06f92015-03-24 09:01:14 +0100360 return static_cast<audio_mode_t>(criterion->getCriterionState());
361}
362
363status_t ParameterManagerWrapper::setForceUse(audio_policy_force_use_t usage,
364 audio_policy_forced_cfg_t config)
365{
366 // @todo: return an error on a unsupported value
367 if (usage > AUDIO_POLICY_FORCE_USE_CNT) {
368 return BAD_VALUE;
369 }
370
François Gaffie814ce802016-01-18 11:23:47 +0100371 ISelectionCriterionInterface *criterion =
372 getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
373 if (criterion == NULL) {
374 ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage].c_str());
375 return BAD_VALUE;
376 }
François Gaffie20f06f92015-03-24 09:01:14 +0100377 if (!isValueValidForCriterion(criterion, static_cast<int>(config))) {
378 return BAD_VALUE;
379 }
380 criterion->setCriterionState((int)config);
381 applyPlatformConfiguration();
382 return NO_ERROR;
383}
384
385audio_policy_forced_cfg_t ParameterManagerWrapper::getForceUse(audio_policy_force_use_t usage) const
386{
387 // @todo: return an error on a unsupported value
388 if (usage > AUDIO_POLICY_FORCE_USE_CNT) {
389 return AUDIO_POLICY_FORCE_NONE;
390 }
391 const ISelectionCriterionInterface *criterion =
392 getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
François Gaffie814ce802016-01-18 11:23:47 +0100393 if (criterion == NULL) {
394 ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage].c_str());
395 return AUDIO_POLICY_FORCE_NONE;
396 }
François Gaffie20f06f92015-03-24 09:01:14 +0100397 return static_cast<audio_policy_forced_cfg_t>(criterion->getCriterionState());
398}
399
400bool ParameterManagerWrapper::isValueValidForCriterion(ISelectionCriterionInterface *criterion,
401 int valueToCheck)
402{
403 const ISelectionCriterionTypeInterface *interface = criterion->getCriterionType();
404 string literalValue;
405 return interface->getLiteralValue(valueToCheck, literalValue);
406}
407
François Gaffiea3e696d2015-12-18 09:38:43 +0100408status_t ParameterManagerWrapper::setAvailableInputDevices(audio_devices_t inputDevices)
François Gaffie20f06f92015-03-24 09:01:14 +0100409{
François Gaffie814ce802016-01-18 11:23:47 +0100410 ISelectionCriterionInterface *criterion =
411 getElement<ISelectionCriterionInterface>(gInputDeviceCriterionTag, mPolicyCriteria);
François Gaffie20f06f92015-03-24 09:01:14 +0100412 if (criterion == NULL) {
François Gaffie814ce802016-01-18 11:23:47 +0100413 ALOGE("%s: no criterion found for %s", __FUNCTION__, gInputDeviceCriterionTag.c_str());
François Gaffie20f06f92015-03-24 09:01:14 +0100414 return DEAD_OBJECT;
415 }
François Gaffiea3e696d2015-12-18 09:38:43 +0100416 criterion->setCriterionState(inputDevices & ~AUDIO_DEVICE_BIT_IN);
417 applyPlatformConfiguration();
418 return NO_ERROR;
419}
François Gaffie20f06f92015-03-24 09:01:14 +0100420
François Gaffiea3e696d2015-12-18 09:38:43 +0100421status_t ParameterManagerWrapper::setAvailableOutputDevices(audio_devices_t outputDevices)
422{
François Gaffie814ce802016-01-18 11:23:47 +0100423 ISelectionCriterionInterface *criterion =
424 getElement<ISelectionCriterionInterface>(gOutputDeviceCriterionTag, mPolicyCriteria);
François Gaffiea3e696d2015-12-18 09:38:43 +0100425 if (criterion == NULL) {
François Gaffie814ce802016-01-18 11:23:47 +0100426 ALOGE("%s: no criterion found for %s", __FUNCTION__, gOutputDeviceCriterionTag.c_str());
François Gaffiea3e696d2015-12-18 09:38:43 +0100427 return DEAD_OBJECT;
François Gaffie20f06f92015-03-24 09:01:14 +0100428 }
François Gaffiea3e696d2015-12-18 09:38:43 +0100429 criterion->setCriterionState(outputDevices);
François Gaffie20f06f92015-03-24 09:01:14 +0100430 applyPlatformConfiguration();
431 return NO_ERROR;
432}
433
434void ParameterManagerWrapper::applyPlatformConfiguration()
435{
436 mPfwConnector->applyConfigurations();
437}
438
439} // namespace audio_policy
440} // namespace android