• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 
37 using std::string;
38 using std::map;
39 using std::vector;
40 
41 /// PFW related definitions
42 // Logger
43 class ParameterMgrPlatformConnectorLogger : public CParameterMgrPlatformConnector::ILogger
44 {
45 public:
ParameterMgrPlatformConnectorLogger()46     ParameterMgrPlatformConnectorLogger() {}
47 
log(bool isWarning,const string & log)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 
60 namespace android
61 {
62 
63 using utilities::convertTo;
64 
65 namespace audio_policy
66 {
67 const char *const ParameterManagerWrapper::mPolicyPfwDefaultConfFileName =
68     "/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
69 
70 template <>
71 struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionInterface> {};
72 template <>
73 struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionTypeInterface> {};
74 
ParameterManagerWrapper()75 ParameterManagerWrapper::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 
~ParameterManagerWrapper()94 ParameterManagerWrapper::~ParameterManagerWrapper()
95 {
96     // Unset logger
97     mPfwConnector->setLogger(NULL);
98     // Remove logger
99     delete mPfwConnectorLogger;
100     // Remove connector
101     delete mPfwConnector;
102 }
103 
start()104 status_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 
addCriterionType(const string & typeName,bool isInclusive)118 void 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 
addCriterionTypeValuePair(const string & typeName,uint32_t numericValue,const string & literalValue)127 void 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 
loadCriterionType(cnode * root,bool isInclusive)140 void 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 = strndup(node->value, strlen(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         free(valueNames);
182     }
183 }
184 
loadInclusiveCriterionType(cnode * root)185 void 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 
loadExclusiveCriterionType(cnode * root)195 void 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 
parseChildren(cnode * root,string & defaultValue,string & type)205 void 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 
222 template <typename T>
getElement(const string & name,std::map<string,T * > & elementsMap)223 T *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);
227     ALOG_ASSERT(it != elementsMap.end(), "Element " << name << " not found");
228     return it->second;
229 }
230 
231 template <typename T>
getElement(const string & name,const std::map<string,T * > & elementsMap) const232 const 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);
236     ALOG_ASSERT(it != elementsMap.end(), "Element " << name << " not found");
237     return it->second;
238 }
239 
loadCriteria(cnode * root)240 void 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 
addCriterion(const string & name,const string & typeName,const string & defaultLiteralValue)254 void ParameterManagerWrapper::addCriterion(const string &name, const string &typeName,
255                               const string &defaultLiteralValue)
256 {
257     ALOG_ASSERT(mPolicyCriteria.find(criterionName) == mPolicyCriteria.end(),
258                 "Route Criterion " << criterionName << " already added");
259 
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 
loadCriterion(cnode * root)275 void 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(),
281                       "Criterion " << criterionName << " already added");
282 
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 
loadConfig(cnode * root)293 void 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 
loadAudioPolicyCriteriaConfig(const char * path)308 status_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 
isStarted()331 bool ParameterManagerWrapper::isStarted()
332 {
333     return mPfwConnector && mPfwConnector->isStarted();
334 }
335 
setPhoneState(audio_mode_t mode)336 status_t ParameterManagerWrapper::setPhoneState(audio_mode_t mode)
337 {
338     ISelectionCriterionInterface *criterion = mPolicyCriteria[gPhoneStateCriterionTag];
339     if (!isValueValidForCriterion(criterion, static_cast<int>(mode))) {
340         return BAD_VALUE;
341     }
342     criterion->setCriterionState((int)(mode));
343     applyPlatformConfiguration();
344     return NO_ERROR;
345 }
346 
getPhoneState() const347 audio_mode_t ParameterManagerWrapper::getPhoneState() const
348 {
349     const ISelectionCriterionInterface *criterion =
350             getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria);
351     return static_cast<audio_mode_t>(criterion->getCriterionState());
352 }
353 
setForceUse(audio_policy_force_use_t usage,audio_policy_forced_cfg_t config)354 status_t ParameterManagerWrapper::setForceUse(audio_policy_force_use_t usage,
355                                               audio_policy_forced_cfg_t config)
356 {
357     // @todo: return an error on a unsupported value
358     if (usage > AUDIO_POLICY_FORCE_USE_CNT) {
359         return BAD_VALUE;
360     }
361 
362     ISelectionCriterionInterface *criterion = mPolicyCriteria[gForceUseCriterionTag[usage]];
363     if (!isValueValidForCriterion(criterion, static_cast<int>(config))) {
364         return BAD_VALUE;
365     }
366     criterion->setCriterionState((int)config);
367     applyPlatformConfiguration();
368     return NO_ERROR;
369 }
370 
getForceUse(audio_policy_force_use_t usage) const371 audio_policy_forced_cfg_t ParameterManagerWrapper::getForceUse(audio_policy_force_use_t usage) const
372 {
373     // @todo: return an error on a unsupported value
374     if (usage > AUDIO_POLICY_FORCE_USE_CNT) {
375         return AUDIO_POLICY_FORCE_NONE;
376     }
377     const ISelectionCriterionInterface *criterion =
378             getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
379     return static_cast<audio_policy_forced_cfg_t>(criterion->getCriterionState());
380 }
381 
isValueValidForCriterion(ISelectionCriterionInterface * criterion,int valueToCheck)382 bool ParameterManagerWrapper::isValueValidForCriterion(ISelectionCriterionInterface *criterion,
383                                                        int valueToCheck)
384 {
385     const ISelectionCriterionTypeInterface *interface = criterion->getCriterionType();
386     string literalValue;
387     return interface->getLiteralValue(valueToCheck, literalValue);
388 }
389 
setDeviceConnectionState(audio_devices_t devices,audio_policy_dev_state_t state,const char *)390 status_t ParameterManagerWrapper::setDeviceConnectionState(audio_devices_t devices,
391                                                            audio_policy_dev_state_t state,
392                                                            const char */*deviceAddres*/)
393 {
394     ISelectionCriterionInterface *criterion = NULL;
395 
396     if (audio_is_output_devices(devices)) {
397         criterion = mPolicyCriteria[gOutputDeviceCriterionTag];
398     } else if (devices & AUDIO_DEVICE_BIT_IN) {
399         criterion = mPolicyCriteria[gInputDeviceCriterionTag];
400     } else {
401         return BAD_TYPE;
402     }
403     if (criterion == NULL) {
404         ALOGE("%s: no criterion found for devices", __FUNCTION__);
405         return DEAD_OBJECT;
406     }
407 
408     int32_t previousDevices = criterion->getCriterionState();
409     switch (state)
410     {
411     case AUDIO_POLICY_DEVICE_STATE_AVAILABLE:
412         criterion->setCriterionState(previousDevices |= devices);
413         break;
414 
415     case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE:
416         if (devices & AUDIO_DEVICE_BIT_IN) {
417             devices &= ~AUDIO_DEVICE_BIT_IN;
418         }
419         criterion->setCriterionState(previousDevices &= ~devices);
420         break;
421 
422     default:
423         return BAD_VALUE;
424     }
425     applyPlatformConfiguration();
426     return NO_ERROR;
427 }
428 
applyPlatformConfiguration()429 void ParameterManagerWrapper::applyPlatformConfiguration()
430 {
431     mPfwConnector->applyConfigurations();
432 }
433 
434 } // namespace audio_policy
435 } // namespace android
436