/* * 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" #include "ParameterManagerWrapper.h" #include "audio_policy_criteria_conf.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using std::string; using std::map; using std::vector; /// PFW related definitions // Logger class ParameterMgrPlatformConnectorLogger : public CParameterMgrPlatformConnector::ILogger { public: ParameterMgrPlatformConnectorLogger() {} virtual void log(bool isWarning, const string &log) { const static string format("policy-parameter-manager: "); if (isWarning) { ALOGW("%s %s", format.c_str(), log.c_str()); } else { ALOGD("%s %s", format.c_str(), 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 {}; template <> struct ParameterManagerWrapper::parameterManagerElementSupported {}; 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); } ALOGD("%s: ParameterManagerWrapper instantiated!", __FUNCTION__); } 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 " << typeName << " already added"); 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 " << typeName.c_str() << "not found"); ALOGV("%s: Adding new value pair (%d,%s) for criterionType %s", __FUNCTION__, numericValue, literalValue.c_str(), typeName.c_str()); ISelectionCriterionTypeInterface *criterionType = mPolicyCriterionTypes[typeName]; criterionType->addValuePair(numericValue, literalValue.c_str()); } 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(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 T *ParameterManagerWrapper::getElement(const string &name, std::map &elementsMap) { parameterManagerElementSupported(); typename std::map::iterator it = elementsMap.find(name); ALOG_ASSERT(it != elementsMap.end(), "Element " << name << " not found"); return it->second; } template const T *ParameterManagerWrapper::getElement(const string &name, const std::map &elementsMap) const { parameterManagerElementSupported(); typename std::map::const_iterator it = elementsMap.find(name); ALOG_ASSERT(it != elementsMap.end(), "Element " << name << " not found"); return it->second; } 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(criterionName) == mPolicyCriteria.end(), "Route Criterion " << criterionName << " already added"); ISelectionCriterionTypeInterface *criterionType = getElement(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 " << criterionName << " already added"); 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 = mPolicyCriteria[gPhoneStateCriterionTag]; if (!isValueValidForCriterion(criterion, static_cast(mode))) { return BAD_VALUE; } criterion->setCriterionState((int)(mode)); applyPlatformConfiguration(); return NO_ERROR; } audio_mode_t ParameterManagerWrapper::getPhoneState() const { const ISelectionCriterionInterface *criterion = getElement(gPhoneStateCriterionTag, mPolicyCriteria); return static_cast(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 = mPolicyCriteria[gForceUseCriterionTag[usage]]; if (!isValueValidForCriterion(criterion, static_cast(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(gForceUseCriterionTag[usage], mPolicyCriteria); return static_cast(criterion->getCriterionState()); } bool ParameterManagerWrapper::isValueValidForCriterion(ISelectionCriterionInterface *criterion, int valueToCheck) { const ISelectionCriterionTypeInterface *interface = criterion->getCriterionType(); string literalValue; return interface->getLiteralValue(valueToCheck, literalValue); } status_t ParameterManagerWrapper::setDeviceConnectionState(audio_devices_t devices, audio_policy_dev_state_t state, const char */*deviceAddres*/) { ISelectionCriterionInterface *criterion = NULL; if (audio_is_output_devices(devices)) { criterion = mPolicyCriteria[gOutputDeviceCriterionTag]; } else if (devices & AUDIO_DEVICE_BIT_IN) { criterion = mPolicyCriteria[gInputDeviceCriterionTag]; } else { return BAD_TYPE; } if (criterion == NULL) { ALOGE("%s: no criterion found for devices", __FUNCTION__); return DEAD_OBJECT; } int32_t previousDevices = criterion->getCriterionState(); switch (state) { case AUDIO_POLICY_DEVICE_STATE_AVAILABLE: criterion->setCriterionState(previousDevices |= devices); break; case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE: if (devices & AUDIO_DEVICE_BIT_IN) { devices &= ~AUDIO_DEVICE_BIT_IN; } criterion->setCriterionState(previousDevices &= ~devices); break; default: return BAD_VALUE; } applyPlatformConfiguration(); return NO_ERROR; } void ParameterManagerWrapper::applyPlatformConfiguration() { mPfwConnector->applyConfigurations(); } } // namespace audio_policy } // namespace android