blob: 9dda20c6ffb972724fd4d00f1f41d73a6a164299 [file] [log] [blame]
François Gaffie65c37812015-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"
18
19#include "ParameterManagerWrapper.h"
20#include "audio_policy_criteria_conf.h"
21#include <ParameterMgrPlatformConnector.h>
22#include <SelectionCriterionTypeInterface.h>
23#include <SelectionCriterionInterface.h>
24#include <convert.h>
25#include <algorithm>
26#include <cutils/config_utils.h>
27#include <cutils/misc.h>
28#include <fstream>
29#include <limits>
30#include <sstream>
31#include <string>
32#include <vector>
33#include <stdint.h>
34#include <cmath>
35#include <utils/Log.h>
36
37using std::string;
38using std::map;
39using std::vector;
40
41/// PFW related definitions
42// Logger
43class ParameterMgrPlatformConnectorLogger : public CParameterMgrPlatformConnector::ILogger
44{
45public:
46 ParameterMgrPlatformConnectorLogger() {}
47
48 virtual void log(bool isWarning, const string &log)
49 {
50 const static string format("policy-parameter-manager: ");
51
52 if (isWarning) {
53 ALOGW("%s %s", format.c_str(), log.c_str());
54 } else {
55 ALOGD("%s %s", format.c_str(), log.c_str());
56 }
57 }
58};
59
60namespace android
61{
62
63using utilities::convertTo;
64
65namespace audio_policy
66{
67const char *const ParameterManagerWrapper::mPolicyPfwDefaultConfFileName =
68 "/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
69
70template <>
71struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionInterface> {};
72template <>
73struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionTypeInterface> {};
74
75ParameterManagerWrapper::ParameterManagerWrapper()
76 : mPfwConnectorLogger(new ParameterMgrPlatformConnectorLogger)
77{
78 // Connector
79 mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwDefaultConfFileName);
80
81 // Logger
82 mPfwConnector->setLogger(mPfwConnectorLogger);
83
84 // Load criteria file
85 if ((loadAudioPolicyCriteriaConfig(gAudioPolicyCriteriaVendorConfFilePath) != NO_ERROR) &&
86 (loadAudioPolicyCriteriaConfig(gAudioPolicyCriteriaConfFilePath) != NO_ERROR)) {
87 ALOGE("%s: Neither vendor conf file (%s) nor system conf file (%s) could be found",
88 __FUNCTION__, gAudioPolicyCriteriaVendorConfFilePath,
89 gAudioPolicyCriteriaConfFilePath);
90 }
91 ALOGD("%s: ParameterManagerWrapper instantiated!", __FUNCTION__);
92}
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(),
121 "CriterionType " << typeName << " already added");
122 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(),
133 "CriterionType " << typeName.c_str() << "not found");
134 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;
148 char *valueNames = (char *)node->value;
149
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 }
181 }
182}
183
184void ParameterManagerWrapper::loadInclusiveCriterionType(cnode *root)
185{
186 ALOG_ASSERT(root != NULL, "error in parsing file");
187 cnode *node = config_find(root, gInclusiveCriterionTypeTag.c_str());
188 if (node == NULL) {
189 return;
190 }
191 loadCriterionType(node, true);
192}
193
194void ParameterManagerWrapper::loadExclusiveCriterionType(cnode *root)
195{
196 ALOG_ASSERT(root != NULL, "error in parsing file");
197 cnode *node = config_find(root, gExclusiveCriterionTypeTag.c_str());
198 if (node == NULL) {
199 return;
200 }
201 loadCriterionType(node, false);
202}
203
204void ParameterManagerWrapper::parseChildren(cnode *root, string &defaultValue, string &type)
205{
206 ALOG_ASSERT(root != NULL, "error in parsing file");
207 cnode *node;
208 for (node = root->first_child; node != NULL; node = node->next) {
209 ALOG_ASSERT(node != NULL, "error in parsing file");
210
211 if (string(node->name) == gDefaultTag) {
212 defaultValue = node->value;
213 } else if (string(node->name) == gTypeTag) {
214 type = node->value;
215 } else {
216 ALOGE("%s: Unrecognized %s %s node", __FUNCTION__, node->name, node->value);
217 }
218 }
219}
220
221template <typename T>
222T *ParameterManagerWrapper::getElement(const string &name, std::map<string, T *> &elementsMap)
223{
224 parameterManagerElementSupported<T>();
225 typename std::map<string, T *>::iterator it = elementsMap.find(name);
226 ALOG_ASSERT(it != elementsMap.end(), "Element " << name << " not found");
227 return it->second;
228}
229
230template <typename T>
231const T *ParameterManagerWrapper::getElement(const string &name, const std::map<string, T *> &elementsMap) const
232{
233 parameterManagerElementSupported<T>();
234 typename std::map<string, T *>::const_iterator it = elementsMap.find(name);
235 ALOG_ASSERT(it != elementsMap.end(), "Element " << name << " not found");
236 return it->second;
237}
238
239void ParameterManagerWrapper::loadCriteria(cnode *root)
240{
241 ALOG_ASSERT(root != NULL, "error in parsing file");
242 cnode *node = config_find(root, gCriterionTag.c_str());
243
244 if (node == NULL) {
245 ALOGW("%s: no inclusive criteria found", __FUNCTION__);
246 return;
247 }
248 for (node = node->first_child; node != NULL; node = node->next) {
249 loadCriterion(node);
250 }
251}
252
253void ParameterManagerWrapper::addCriterion(const string &name, const string &typeName,
254 const string &defaultLiteralValue)
255{
256 ALOG_ASSERT(mPolicyCriteria.find(criterionName) == mPolicyCriteria.end(),
257 "Route Criterion " << criterionName << " already added");
258
259 ISelectionCriterionTypeInterface *criterionType =
260 getElement<ISelectionCriterionTypeInterface>(typeName, mPolicyCriterionTypes);
261
262 ISelectionCriterionInterface *criterion =
263 mPfwConnector->createSelectionCriterion(name, criterionType);
264
265 mPolicyCriteria[name] = criterion;
266 int numericalValue = 0;
267 if (!criterionType->getNumericalValue(defaultLiteralValue.c_str(), numericalValue)) {
268 ALOGE("%s; trying to apply invalid default literal value", __FUNCTION__,
269 defaultLiteralValue.c_str());
270 }
271 criterion->setCriterionState(numericalValue);
272}
273
274void ParameterManagerWrapper::loadCriterion(cnode *root)
275{
276 ALOG_ASSERT(root != NULL, "error in parsing file");
277 const char *criterionName = root->name;
278
279 ALOG_ASSERT(mPolicyCriteria.find(criterionName) == mPolicyCriteria.end(),
280 "Criterion " << criterionName << " already added");
281
282 string paramKeyName = "";
283 string path = "";
284 string typeName = "";
285 string defaultValue = "";
286
287 parseChildren(root, defaultValue, typeName);
288
289 addCriterion(criterionName, typeName, defaultValue);
290}
291
292void ParameterManagerWrapper::loadConfig(cnode *root)
293{
294 ALOG_ASSERT(root != NULL, "error in parsing file");
295 cnode *node = config_find(root, gPolicyConfTag.c_str());
296 if (node == NULL) {
297 ALOGW("%s: Could not find node for pfw", __FUNCTION__);
298 return;
299 }
300 ALOGD("%s: Loading conf for pfw", __FUNCTION__);
301 loadInclusiveCriterionType(node);
302 loadExclusiveCriterionType(node);
303 loadCriteria(node);
304}
305
306
307status_t ParameterManagerWrapper::loadAudioPolicyCriteriaConfig(const char *path)
308{
309 ALOG_ASSERT(path != NULL, "error in parsing file: empty path");
310 cnode *root;
311 char *data;
312 ALOGD("%s", __FUNCTION__);
313 data = (char *)load_file(path, NULL);
314 if (data == NULL) {
315 return -ENODEV;
316 }
317 root = config_node("", "");
318 ALOG_ASSERT(root != NULL, "Unable to allocate a configuration node");
319 config_load(root, data);
320
321 loadConfig(root);
322
323 config_free(root);
324 free(root);
325 free(data);
326 ALOGD("%s: loaded", __FUNCTION__);
327 return NO_ERROR;
328}
329
330bool ParameterManagerWrapper::isStarted()
331{
332 return mPfwConnector && mPfwConnector->isStarted();
333}
334
335status_t ParameterManagerWrapper::setPhoneState(audio_mode_t mode)
336{
337 ISelectionCriterionInterface *criterion = mPolicyCriteria[gPhoneStateCriterionTag];
338 if (!isValueValidForCriterion(criterion, static_cast<int>(mode))) {
339 return BAD_VALUE;
340 }
341 criterion->setCriterionState((int)(mode));
342 applyPlatformConfiguration();
343 return NO_ERROR;
344}
345
346audio_mode_t ParameterManagerWrapper::getPhoneState() const
347{
348 const ISelectionCriterionInterface *criterion =
349 getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria);
350 return static_cast<audio_mode_t>(criterion->getCriterionState());
351}
352
353status_t ParameterManagerWrapper::setForceUse(audio_policy_force_use_t usage,
354 audio_policy_forced_cfg_t config)
355{
356 // @todo: return an error on a unsupported value
357 if (usage > AUDIO_POLICY_FORCE_USE_CNT) {
358 return BAD_VALUE;
359 }
360
361 ISelectionCriterionInterface *criterion = mPolicyCriteria[gForceUseCriterionTag[usage]];
362 if (!isValueValidForCriterion(criterion, static_cast<int>(config))) {
363 return BAD_VALUE;
364 }
365 criterion->setCriterionState((int)config);
366 applyPlatformConfiguration();
367 return NO_ERROR;
368}
369
370audio_policy_forced_cfg_t ParameterManagerWrapper::getForceUse(audio_policy_force_use_t usage) const
371{
372 // @todo: return an error on a unsupported value
373 if (usage > AUDIO_POLICY_FORCE_USE_CNT) {
374 return AUDIO_POLICY_FORCE_NONE;
375 }
376 const ISelectionCriterionInterface *criterion =
377 getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
378 return static_cast<audio_policy_forced_cfg_t>(criterion->getCriterionState());
379}
380
381bool ParameterManagerWrapper::isValueValidForCriterion(ISelectionCriterionInterface *criterion,
382 int valueToCheck)
383{
384 const ISelectionCriterionTypeInterface *interface = criterion->getCriterionType();
385 string literalValue;
386 return interface->getLiteralValue(valueToCheck, literalValue);
387}
388
389status_t ParameterManagerWrapper::setDeviceConnectionState(audio_devices_t devices,
390 audio_policy_dev_state_t state,
391 const char */*deviceAddres*/)
392{
393 ISelectionCriterionInterface *criterion = NULL;
394
395 if (audio_is_output_devices(devices)) {
396 criterion = mPolicyCriteria[gOutputDeviceCriterionTag];
397 } else if (devices & AUDIO_DEVICE_BIT_IN) {
398 criterion = mPolicyCriteria[gInputDeviceCriterionTag];
399 } else {
400 return BAD_TYPE;
401 }
402 if (criterion == NULL) {
403 ALOGE("%s: no criterion found for devices");
404 return DEAD_OBJECT;
405 }
406
407 int32_t previousDevices = criterion->getCriterionState();
408 switch (state)
409 {
410 case AUDIO_POLICY_DEVICE_STATE_AVAILABLE:
411 criterion->setCriterionState(previousDevices |= devices);
412 break;
413
414 case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE:
415 if (devices & AUDIO_DEVICE_BIT_IN) {
416 devices &= ~AUDIO_DEVICE_BIT_IN;
417 }
418 criterion->setCriterionState(previousDevices &= ~devices);
419 break;
420
421 default:
422 return BAD_VALUE;
423 }
424 applyPlatformConfiguration();
425 return NO_ERROR;
426}
427
428void ParameterManagerWrapper::applyPlatformConfiguration()
429{
430 mPfwConnector->applyConfigurations();
431}
432
433} // namespace audio_policy
434} // namespace android