/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "APM::AudioPolicyEngine/PFWWrapper" //#define LOG_NDEBUG 0 #include "ParameterManagerWrapper.h" #include "audio_policy_criteria_conf.h" #include <ParameterMgrPlatformConnector.h> #include <SelectionCriterionTypeInterface.h> #include <SelectionCriterionInterface.h> #include <media/convert.h> #include <algorithm> #include <cutils/config_utils.h> #include <cutils/misc.h> #include <fstream> #include <limits> #include <sstream> #include <string> #include <vector> #include <stdint.h> #include <cmath> #include <utils/Log.h> using std::string; using std::map; using std::vector; /// PFW related definitions // Logger class ParameterMgrPlatformConnectorLogger : public CParameterMgrPlatformConnector::ILogger { public: ParameterMgrPlatformConnectorLogger() {} virtual void info(const string &log) { ALOGV("policy-parameter-manager: %s", log.c_str()); } virtual void warning(const string &log) { ALOGW("policy-parameter-manager: %s", log.c_str()); } }; namespace android { using utilities::convertTo; namespace audio_policy { const char *const ParameterManagerWrapper::mPolicyPfwDefaultConfFileName = "/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml"; template <> struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionInterface> {}; template <> struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionTypeInterface> {}; ParameterManagerWrapper::ParameterManagerWrapper() : mPfwConnectorLogger(new ParameterMgrPlatformConnectorLogger) { // Connector mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwDefaultConfFileName); // Logger mPfwConnector->setLogger(mPfwConnectorLogger); // Load criteria file if ((loadAudioPolicyCriteriaConfig(gAudioPolicyCriteriaVendorConfFilePath) != NO_ERROR) && (loadAudioPolicyCriteriaConfig(gAudioPolicyCriteriaConfFilePath) != NO_ERROR)) { ALOGE("%s: Neither vendor conf file (%s) nor system conf file (%s) could be found", __FUNCTION__, gAudioPolicyCriteriaVendorConfFilePath, gAudioPolicyCriteriaConfFilePath); } } ParameterManagerWrapper::~ParameterManagerWrapper() { // Unset logger mPfwConnector->setLogger(NULL); // Remove logger delete mPfwConnectorLogger; // Remove connector delete mPfwConnector; } status_t ParameterManagerWrapper::start() { ALOGD("%s: in", __FUNCTION__); /// Start PFW std::string error; if (!mPfwConnector->start(error)) { ALOGE("%s: Policy PFW start error: %s", __FUNCTION__, error.c_str()); return NO_INIT; } ALOGD("%s: Policy PFW successfully started!", __FUNCTION__); return NO_ERROR; } void ParameterManagerWrapper::addCriterionType(const string &typeName, bool isInclusive) { ALOG_ASSERT(mPolicyCriterionTypes.find(typeName) == mPolicyCriterionTypes.end(), "CriterionType %s already added", typeName.c_str()); ALOGD("%s: Adding new criterionType %s", __FUNCTION__, typeName.c_str()); mPolicyCriterionTypes[typeName] = mPfwConnector->createSelectionCriterionType(isInclusive); } void ParameterManagerWrapper::addCriterionTypeValuePair( const string &typeName, uint32_t numericValue, const string &literalValue) { ALOG_ASSERT(mPolicyCriterionTypes.find(typeName) != mPolicyCriterionTypes.end(), "CriterionType %s not found", typeName.c_str()); ALOGV("%s: Adding new value pair (%d,%s) for criterionType %s", __FUNCTION__, numericValue, literalValue.c_str(), typeName.c_str()); ISelectionCriterionTypeInterface *criterionType = mPolicyCriterionTypes[typeName]; std::string error; criterionType->addValuePair(numericValue, literalValue, error); } void ParameterManagerWrapper::loadCriterionType(cnode *root, bool isInclusive) { ALOG_ASSERT(root != NULL, "error in parsing file"); cnode *node; for (node = root->first_child; node != NULL; node = node->next) { ALOG_ASSERT(node != NULL, "error in parsing file"); const char *typeName = node->name; char *valueNames = strndup(node->value, strlen(node->value)); addCriterionType(typeName, isInclusive); uint32_t index = 0; char *ctx; char *valueName = strtok_r(valueNames, ",", &ctx); while (valueName != NULL) { if (strlen(valueName) != 0) { // Conf file may use or not pair, if no pair, use incremental index, else // use provided index. if (strchr(valueName, ':') != NULL) { char *first = strtok(valueName, ":"); char *second = strtok(NULL, ":"); ALOG_ASSERT((first != NULL) && (strlen(first) != 0) && (second != NULL) && (strlen(second) != 0), "invalid value pair"); if (!convertTo<string, uint32_t>(first, index)) { ALOGE("%s: Invalid index(%s) found", __FUNCTION__, first); } addCriterionTypeValuePair(typeName, index, second); } else { uint32_t pfwIndex = isInclusive ? 1 << index : index; addCriterionTypeValuePair(typeName, pfwIndex, valueName); index += 1; } } valueName = strtok_r(NULL, ",", &ctx); } free(valueNames); } } void ParameterManagerWrapper::loadInclusiveCriterionType(cnode *root) { ALOG_ASSERT(root != NULL, "error in parsing file"); cnode *node = config_find(root, gInclusiveCriterionTypeTag.c_str()); if (node == NULL) { return; } loadCriterionType(node, true); } void ParameterManagerWrapper::loadExclusiveCriterionType(cnode *root) { ALOG_ASSERT(root != NULL, "error in parsing file"); cnode *node = config_find(root, gExclusiveCriterionTypeTag.c_str()); if (node == NULL) { return; } loadCriterionType(node, false); } void ParameterManagerWrapper::parseChildren(cnode *root, string &defaultValue, string &type) { ALOG_ASSERT(root != NULL, "error in parsing file"); cnode *node; for (node = root->first_child; node != NULL; node = node->next) { ALOG_ASSERT(node != NULL, "error in parsing file"); if (string(node->name) == gDefaultTag) { defaultValue = node->value; } else if (string(node->name) == gTypeTag) { type = node->value; } else { ALOGE("%s: Unrecognized %s %s node", __FUNCTION__, node->name, node->value); } } } template <typename T> T *ParameterManagerWrapper::getElement(const string &name, std::map<string, T *> &elementsMap) { parameterManagerElementSupported<T>(); typename std::map<string, T *>::iterator it = elementsMap.find(name); ALOG_ASSERT(it != elementsMap.end(), "Element %s not found", name.c_str()); return it != elementsMap.end() ? it->second : NULL; } template <typename T> const T *ParameterManagerWrapper::getElement(const string &name, const std::map<string, T *> &elementsMap) const { parameterManagerElementSupported<T>(); typename std::map<string, T *>::const_iterator it = elementsMap.find(name); ALOG_ASSERT(it != elementsMap.end(), "Element %s not found", name.c_str()); return it != elementsMap.end() ? it->second : NULL; } void ParameterManagerWrapper::loadCriteria(cnode *root) { ALOG_ASSERT(root != NULL, "error in parsing file"); cnode *node = config_find(root, gCriterionTag.c_str()); if (node == NULL) { ALOGW("%s: no inclusive criteria found", __FUNCTION__); return; } for (node = node->first_child; node != NULL; node = node->next) { loadCriterion(node); } } void ParameterManagerWrapper::addCriterion(const string &name, const string &typeName, const string &defaultLiteralValue) { ALOG_ASSERT(mPolicyCriteria.find(name) == mPolicyCriteria.end(), "Route Criterion %s already added", name.c_str()); ISelectionCriterionTypeInterface *criterionType = getElement<ISelectionCriterionTypeInterface>(typeName, mPolicyCriterionTypes); ISelectionCriterionInterface *criterion = mPfwConnector->createSelectionCriterion(name, criterionType); mPolicyCriteria[name] = criterion; int numericalValue = 0; if (!criterionType->getNumericalValue(defaultLiteralValue.c_str(), numericalValue)) { ALOGE("%s; trying to apply invalid default literal value (%s)", __FUNCTION__, defaultLiteralValue.c_str()); } criterion->setCriterionState(numericalValue); } void ParameterManagerWrapper::loadCriterion(cnode *root) { ALOG_ASSERT(root != NULL, "error in parsing file"); const char *criterionName = root->name; ALOG_ASSERT(mPolicyCriteria.find(criterionName) == mPolicyCriteria.end(), "Criterion %s already added", criterionName); string paramKeyName = ""; string path = ""; string typeName = ""; string defaultValue = ""; parseChildren(root, defaultValue, typeName); addCriterion(criterionName, typeName, defaultValue); } void ParameterManagerWrapper::loadConfig(cnode *root) { ALOG_ASSERT(root != NULL, "error in parsing file"); cnode *node = config_find(root, gPolicyConfTag.c_str()); if (node == NULL) { ALOGW("%s: Could not find node for pfw", __FUNCTION__); return; } ALOGD("%s: Loading conf for pfw", __FUNCTION__); loadInclusiveCriterionType(node); loadExclusiveCriterionType(node); loadCriteria(node); } status_t ParameterManagerWrapper::loadAudioPolicyCriteriaConfig(const char *path) { ALOG_ASSERT(path != NULL, "error in parsing file: empty path"); cnode *root; char *data; ALOGD("%s", __FUNCTION__); data = (char *)load_file(path, NULL); if (data == NULL) { return -ENODEV; } root = config_node("", ""); ALOG_ASSERT(root != NULL, "Unable to allocate a configuration node"); config_load(root, data); loadConfig(root); config_free(root); free(root); free(data); ALOGD("%s: loaded", __FUNCTION__); return NO_ERROR; } bool ParameterManagerWrapper::isStarted() { return mPfwConnector && mPfwConnector->isStarted(); } status_t ParameterManagerWrapper::setPhoneState(audio_mode_t mode) { ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria); if (criterion == NULL) { ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionTag.c_str()); return BAD_VALUE; } if (!isValueValidForCriterion(criterion, static_cast<int>(mode))) { return BAD_VALUE; } criterion->setCriterionState((int)(mode)); applyPlatformConfiguration(); return NO_ERROR; } audio_mode_t ParameterManagerWrapper::getPhoneState() const { const ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(gPhoneStateCriterionTag, mPolicyCriteria); if (criterion == NULL) { ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionTag.c_str()); return AUDIO_MODE_NORMAL; } return static_cast<audio_mode_t>(criterion->getCriterionState()); } status_t ParameterManagerWrapper::setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config) { // @todo: return an error on a unsupported value if (usage > AUDIO_POLICY_FORCE_USE_CNT) { return BAD_VALUE; } ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria); if (criterion == NULL) { ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage].c_str()); return BAD_VALUE; } if (!isValueValidForCriterion(criterion, static_cast<int>(config))) { return BAD_VALUE; } criterion->setCriterionState((int)config); applyPlatformConfiguration(); return NO_ERROR; } audio_policy_forced_cfg_t ParameterManagerWrapper::getForceUse(audio_policy_force_use_t usage) const { // @todo: return an error on a unsupported value if (usage > AUDIO_POLICY_FORCE_USE_CNT) { return AUDIO_POLICY_FORCE_NONE; } const ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria); if (criterion == NULL) { ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage].c_str()); return AUDIO_POLICY_FORCE_NONE; } return static_cast<audio_policy_forced_cfg_t>(criterion->getCriterionState()); } bool ParameterManagerWrapper::isValueValidForCriterion(ISelectionCriterionInterface *criterion, int valueToCheck) { const ISelectionCriterionTypeInterface *interface = criterion->getCriterionType(); string literalValue; return interface->getLiteralValue(valueToCheck, literalValue); } status_t ParameterManagerWrapper::setAvailableInputDevices(audio_devices_t inputDevices) { ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(gInputDeviceCriterionTag, mPolicyCriteria); if (criterion == NULL) { ALOGE("%s: no criterion found for %s", __FUNCTION__, gInputDeviceCriterionTag.c_str()); return DEAD_OBJECT; } criterion->setCriterionState(inputDevices & ~AUDIO_DEVICE_BIT_IN); applyPlatformConfiguration(); return NO_ERROR; } status_t ParameterManagerWrapper::setAvailableOutputDevices(audio_devices_t outputDevices) { ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(gOutputDeviceCriterionTag, mPolicyCriteria); if (criterion == NULL) { ALOGE("%s: no criterion found for %s", __FUNCTION__, gOutputDeviceCriterionTag.c_str()); return DEAD_OBJECT; } criterion->setCriterionState(outputDevices); applyPlatformConfiguration(); return NO_ERROR; } void ParameterManagerWrapper::applyPlatformConfiguration() { mPfwConnector->applyConfigurations(); } } // namespace audio_policy } // namespace android