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 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 = 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 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); 227 ALOG_ASSERT(it != elementsMap.end(), "Element " << name << " not found"); 228 return it->second; 229} 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); 236 ALOG_ASSERT(it != elementsMap.end(), "Element " << name << " not found"); 237 return it->second; 238} 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{ 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 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(), 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 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{ 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 347audio_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 354status_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 371audio_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 382bool 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 390status_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 429void ParameterManagerWrapper::applyPlatformConfiguration() 430{ 431 mPfwConnector->applyConfigurations(); 432} 433 434} // namespace audio_policy 435} // namespace android 436