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::AudioPolicyEngine/PFWWrapper"
18 //#define LOG_NDEBUG 0
19
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
38 using std::string;
39 using std::map;
40 using std::vector;
41
42 /// PFW related definitions
43 // Logger
44 class ParameterMgrPlatformConnectorLogger : public CParameterMgrPlatformConnector::ILogger
45 {
46 public:
ParameterMgrPlatformConnectorLogger()47 ParameterMgrPlatformConnectorLogger() {}
48
info(const string & log)49 virtual void info(const string &log)
50 {
51 ALOGD("policy-parameter-manager: %s", log.c_str());
52 }
warning(const string & log)53 virtual void warning(const string &log)
54 {
55 ALOGW("policy-parameter-manager: %s", log.c_str());
56 }
57 };
58
59 namespace android
60 {
61
62 using utilities::convertTo;
63
64 namespace audio_policy
65 {
66 const char *const ParameterManagerWrapper::mPolicyPfwDefaultConfFileName =
67 "/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
68
69 template <>
70 struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionInterface> {};
71 template <>
72 struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionTypeInterface> {};
73
ParameterManagerWrapper()74 ParameterManagerWrapper::ParameterManagerWrapper()
75 : mPfwConnectorLogger(new ParameterMgrPlatformConnectorLogger)
76 {
77 // Connector
78 mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwDefaultConfFileName);
79
80 // Logger
81 mPfwConnector->setLogger(mPfwConnectorLogger);
82
83 // Load criteria file
84 if ((loadAudioPolicyCriteriaConfig(gAudioPolicyCriteriaVendorConfFilePath) != NO_ERROR) &&
85 (loadAudioPolicyCriteriaConfig(gAudioPolicyCriteriaConfFilePath) != NO_ERROR)) {
86 ALOGE("%s: Neither vendor conf file (%s) nor system conf file (%s) could be found",
87 __FUNCTION__, gAudioPolicyCriteriaVendorConfFilePath,
88 gAudioPolicyCriteriaConfFilePath);
89 }
90 }
91
~ParameterManagerWrapper()92 ParameterManagerWrapper::~ParameterManagerWrapper()
93 {
94 // Unset logger
95 mPfwConnector->setLogger(NULL);
96 // Remove logger
97 delete mPfwConnectorLogger;
98 // Remove connector
99 delete mPfwConnector;
100 }
101
start()102 status_t ParameterManagerWrapper::start()
103 {
104 ALOGD("%s: in", __FUNCTION__);
105 /// Start PFW
106 std::string error;
107 if (!mPfwConnector->start(error)) {
108 ALOGE("%s: Policy PFW start error: %s", __FUNCTION__, error.c_str());
109 return NO_INIT;
110 }
111 ALOGD("%s: Policy PFW successfully started!", __FUNCTION__);
112 return NO_ERROR;
113 }
114
115
addCriterionType(const string & typeName,bool isInclusive)116 void ParameterManagerWrapper::addCriterionType(const string &typeName, bool isInclusive)
117 {
118 ALOG_ASSERT(mPolicyCriterionTypes.find(typeName) == mPolicyCriterionTypes.end(),
119 "CriterionType %s already added", typeName.c_str());
120 ALOGD("%s: Adding new criterionType %s", __FUNCTION__, typeName.c_str());
121
122 mPolicyCriterionTypes[typeName] = mPfwConnector->createSelectionCriterionType(isInclusive);
123 }
124
addCriterionTypeValuePair(const string & typeName,uint32_t numericValue,const string & literalValue)125 void ParameterManagerWrapper::addCriterionTypeValuePair(
126 const string &typeName,
127 uint32_t numericValue,
128 const string &literalValue)
129 {
130 ALOG_ASSERT(mPolicyCriterionTypes.find(typeName) != mPolicyCriterionTypes.end(),
131 "CriterionType %s not found", typeName.c_str());
132 ALOGV("%s: Adding new value pair (%d,%s) for criterionType %s", __FUNCTION__,
133 numericValue, literalValue.c_str(), typeName.c_str());
134 ISelectionCriterionTypeInterface *criterionType = mPolicyCriterionTypes[typeName];
135 std::string error;
136 criterionType->addValuePair(numericValue, literalValue, error);
137 }
138
loadCriterionType(cnode * root,bool isInclusive)139 void ParameterManagerWrapper::loadCriterionType(cnode *root, bool isInclusive)
140 {
141 ALOG_ASSERT(root != NULL, "error in parsing file");
142 cnode *node;
143 for (node = root->first_child; node != NULL; node = node->next) {
144
145 ALOG_ASSERT(node != NULL, "error in parsing file");
146 const char *typeName = node->name;
147 char *valueNames = strndup(node->value, strlen(node->value));
148
149 addCriterionType(typeName, isInclusive);
150
151 uint32_t index = 0;
152 char *ctx;
153 char *valueName = strtok_r(valueNames, ",", &ctx);
154 while (valueName != NULL) {
155 if (strlen(valueName) != 0) {
156
157 // Conf file may use or not pair, if no pair, use incremental index, else
158 // use provided index.
159 if (strchr(valueName, ':') != NULL) {
160
161 char *first = strtok(valueName, ":");
162 char *second = strtok(NULL, ":");
163 ALOG_ASSERT((first != NULL) && (strlen(first) != 0) &&
164 (second != NULL) && (strlen(second) != 0),
165 "invalid value pair");
166
167 if (!convertTo<string, uint32_t>(first, index)) {
168 ALOGE("%s: Invalid index(%s) found", __FUNCTION__, first);
169 }
170 addCriterionTypeValuePair(typeName, index, second);
171 } else {
172
173 uint32_t pfwIndex = isInclusive ? 1 << index : index;
174 addCriterionTypeValuePair(typeName, pfwIndex, valueName);
175 index += 1;
176 }
177 }
178 valueName = strtok_r(NULL, ",", &ctx);
179 }
180 free(valueNames);
181 }
182 }
183
loadInclusiveCriterionType(cnode * root)184 void 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
loadExclusiveCriterionType(cnode * root)194 void 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
parseChildren(cnode * root,string & defaultValue,string & type)204 void 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
221 template <typename T>
getElement(const string & name,std::map<string,T * > & elementsMap)222 T *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 %s not found", name.c_str());
227 return it != elementsMap.end() ? it->second : NULL;
228 }
229
230 template <typename T>
getElement(const string & name,const std::map<string,T * > & elementsMap) const231 const 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 %s not found", name.c_str());
236 return it != elementsMap.end() ? it->second : NULL;
237 }
238
loadCriteria(cnode * root)239 void 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
addCriterion(const string & name,const string & typeName,const string & defaultLiteralValue)253 void ParameterManagerWrapper::addCriterion(const string &name, const string &typeName,
254 const string &defaultLiteralValue)
255 {
256 ALOG_ASSERT(mPolicyCriteria.find(name) == mPolicyCriteria.end(),
257 "Route Criterion %s already added", name.c_str());
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 (%s)", __FUNCTION__,
269 defaultLiteralValue.c_str());
270 }
271 criterion->setCriterionState(numericalValue);
272 }
273
loadCriterion(cnode * root)274 void 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 %s already added", criterionName);
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
loadConfig(cnode * root)292 void 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
loadAudioPolicyCriteriaConfig(const char * path)307 status_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
isStarted()330 bool ParameterManagerWrapper::isStarted()
331 {
332 return mPfwConnector && mPfwConnector->isStarted();
333 }
334
setPhoneState(audio_mode_t mode)335 status_t ParameterManagerWrapper::setPhoneState(audio_mode_t mode)
336 {
337 ISelectionCriterionInterface *criterion =
338 getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria);
339 if (criterion == NULL) {
340 ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionTag.c_str());
341 return BAD_VALUE;
342 }
343 if (!isValueValidForCriterion(criterion, static_cast<int>(mode))) {
344 return BAD_VALUE;
345 }
346 criterion->setCriterionState((int)(mode));
347 applyPlatformConfiguration();
348 return NO_ERROR;
349 }
350
getPhoneState() const351 audio_mode_t ParameterManagerWrapper::getPhoneState() const
352 {
353 const ISelectionCriterionInterface *criterion =
354 getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria);
355 if (criterion == NULL) {
356 ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionTag.c_str());
357 return AUDIO_MODE_NORMAL;
358 }
359 return static_cast<audio_mode_t>(criterion->getCriterionState());
360 }
361
setForceUse(audio_policy_force_use_t usage,audio_policy_forced_cfg_t config)362 status_t ParameterManagerWrapper::setForceUse(audio_policy_force_use_t usage,
363 audio_policy_forced_cfg_t config)
364 {
365 // @todo: return an error on a unsupported value
366 if (usage > AUDIO_POLICY_FORCE_USE_CNT) {
367 return BAD_VALUE;
368 }
369
370 ISelectionCriterionInterface *criterion =
371 getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
372 if (criterion == NULL) {
373 ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage].c_str());
374 return BAD_VALUE;
375 }
376 if (!isValueValidForCriterion(criterion, static_cast<int>(config))) {
377 return BAD_VALUE;
378 }
379 criterion->setCriterionState((int)config);
380 applyPlatformConfiguration();
381 return NO_ERROR;
382 }
383
getForceUse(audio_policy_force_use_t usage) const384 audio_policy_forced_cfg_t ParameterManagerWrapper::getForceUse(audio_policy_force_use_t usage) const
385 {
386 // @todo: return an error on a unsupported value
387 if (usage > AUDIO_POLICY_FORCE_USE_CNT) {
388 return AUDIO_POLICY_FORCE_NONE;
389 }
390 const ISelectionCriterionInterface *criterion =
391 getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
392 if (criterion == NULL) {
393 ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage].c_str());
394 return AUDIO_POLICY_FORCE_NONE;
395 }
396 return static_cast<audio_policy_forced_cfg_t>(criterion->getCriterionState());
397 }
398
isValueValidForCriterion(ISelectionCriterionInterface * criterion,int valueToCheck)399 bool ParameterManagerWrapper::isValueValidForCriterion(ISelectionCriterionInterface *criterion,
400 int valueToCheck)
401 {
402 const ISelectionCriterionTypeInterface *interface = criterion->getCriterionType();
403 string literalValue;
404 return interface->getLiteralValue(valueToCheck, literalValue);
405 }
406
setAvailableInputDevices(audio_devices_t inputDevices)407 status_t ParameterManagerWrapper::setAvailableInputDevices(audio_devices_t inputDevices)
408 {
409 ISelectionCriterionInterface *criterion =
410 getElement<ISelectionCriterionInterface>(gInputDeviceCriterionTag, mPolicyCriteria);
411 if (criterion == NULL) {
412 ALOGE("%s: no criterion found for %s", __FUNCTION__, gInputDeviceCriterionTag.c_str());
413 return DEAD_OBJECT;
414 }
415 criterion->setCriterionState(inputDevices & ~AUDIO_DEVICE_BIT_IN);
416 applyPlatformConfiguration();
417 return NO_ERROR;
418 }
419
setAvailableOutputDevices(audio_devices_t outputDevices)420 status_t ParameterManagerWrapper::setAvailableOutputDevices(audio_devices_t outputDevices)
421 {
422 ISelectionCriterionInterface *criterion =
423 getElement<ISelectionCriterionInterface>(gOutputDeviceCriterionTag, mPolicyCriteria);
424 if (criterion == NULL) {
425 ALOGE("%s: no criterion found for %s", __FUNCTION__, gOutputDeviceCriterionTag.c_str());
426 return DEAD_OBJECT;
427 }
428 criterion->setCriterionState(outputDevices);
429 applyPlatformConfiguration();
430 return NO_ERROR;
431 }
432
applyPlatformConfiguration()433 void ParameterManagerWrapper::applyPlatformConfiguration()
434 {
435 mPfwConnector->applyConfigurations();
436 }
437
438 } // namespace audio_policy
439 } // namespace android
440