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 <media/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: 47 ParameterMgrPlatformConnectorLogger() {} 48 49 virtual void info(const string &log) 50 { 51 ALOGV("policy-parameter-manager: %s", log.c_str()); 52 } 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 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 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 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 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 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 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 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 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 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> 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> 231 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 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 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 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 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 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 330 bool ParameterManagerWrapper::isStarted() 331 { 332 return mPfwConnector && mPfwConnector->isStarted(); 333 } 334 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 351 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 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 384 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 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 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 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 433 void ParameterManagerWrapper::applyPlatformConfiguration() 434 { 435 mPfwConnector->applyConfigurations(); 436 } 437 438 } // namespace audio_policy 439 } // namespace android 440