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