blob: fc6c1e41734694fe1ffde43a1640a0cb67c8b628 [file] [log] [blame]
François Gaffie20f06f92015-03-24 09:01:14 +01001/*
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"
François Gaffie814ce802016-01-18 11:23:47 +010018//#define LOG_NDEBUG 0
François Gaffie20f06f92015-03-24 09:01:14 +010019
20#include "ParameterManagerWrapper.h"
François Gaffiea56b5c22018-02-21 18:04:39 +010021#include "ParameterManagerWrapperConfig.h"
François Gaffie20f06f92015-03-24 09:01:14 +010022#include <ParameterMgrPlatformConnector.h>
23#include <SelectionCriterionTypeInterface.h>
24#include <SelectionCriterionInterface.h>
Mikhail Naganov913d06c2016-11-01 12:49:22 -070025#include <media/convert.h>
François Gaffie20f06f92015-03-24 09:01:14 +010026#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
38using std::string;
39using std::map;
40using std::vector;
François Gaffiea56b5c22018-02-21 18:04:39 +010041using CriterionTypes = std::map<std::string, ISelectionCriterionTypeInterface *>;
François Gaffie20f06f92015-03-24 09:01:14 +010042
43/// PFW related definitions
44// Logger
45class ParameterMgrPlatformConnectorLogger : public CParameterMgrPlatformConnector::ILogger
46{
47public:
48 ParameterMgrPlatformConnectorLogger() {}
49
François Gaffiec1391f92015-12-10 09:43:48 +010050 virtual void info(const string &log)
François Gaffie20f06f92015-03-24 09:01:14 +010051 {
Liu Changcheng30cf41f2016-12-07 18:58:19 +080052 ALOGV("policy-parameter-manager: %s", log.c_str());
François Gaffiec1391f92015-12-10 09:43:48 +010053 }
54 virtual void warning(const string &log)
55 {
56 ALOGW("policy-parameter-manager: %s", log.c_str());
François Gaffie20f06f92015-03-24 09:01:14 +010057 }
58};
59
François Gaffief19cf792018-05-30 17:22:17 +020060namespace android {
François Gaffie20f06f92015-03-24 09:01:14 +010061
62using utilities::convertTo;
63
François Gaffief19cf792018-05-30 17:22:17 +020064namespace audio_policy {
65
François Gaffie20f06f92015-03-24 09:01:14 +010066const char *const ParameterManagerWrapper::mPolicyPfwDefaultConfFileName =
67 "/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
68
François Gaffiea56b5c22018-02-21 18:04:39 +010069static const char *const gInputDeviceCriterionName = "AvailableInputDevices";
70static const char *const gOutputDeviceCriterionName = "AvailableOutputDevices";
71static const char *const gPhoneStateCriterionName = "TelephonyMode";
72static const char *const gOutputDeviceAddressCriterionName = "AvailableOutputDevicesAddresses";
73static const char *const gInputDeviceAddressCriterionName = "AvailableInputDevicesAddresses";
74
75/**
76 * Order MUST be align with defintiion of audio_policy_force_use_t within audio_policy.h
77 */
78static const char *const gForceUseCriterionTag[AUDIO_POLICY_FORCE_USE_CNT] =
79{
80 [AUDIO_POLICY_FORCE_FOR_COMMUNICATION] = "ForceUseForCommunication",
81 [AUDIO_POLICY_FORCE_FOR_MEDIA] = "ForceUseForMedia",
82 [AUDIO_POLICY_FORCE_FOR_RECORD] = "ForceUseForRecord",
83 [AUDIO_POLICY_FORCE_FOR_DOCK] = "ForceUseForDock",
84 [AUDIO_POLICY_FORCE_FOR_SYSTEM] = "ForceUseForSystem",
85 [AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] = "ForceUseForHdmiSystemAudio",
86 [AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND] = "ForceUseForEncodedSurround",
87 [AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING] = "ForceUseForVibrateRinging"
88};
89
François Gaffie20f06f92015-03-24 09:01:14 +010090template <>
91struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionInterface> {};
92template <>
93struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionTypeInterface> {};
94
95ParameterManagerWrapper::ParameterManagerWrapper()
96 : mPfwConnectorLogger(new ParameterMgrPlatformConnectorLogger)
97{
98 // Connector
99 mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwDefaultConfFileName);
100
101 // Logger
102 mPfwConnector->setLogger(mPfwConnectorLogger);
103
François Gaffiea56b5c22018-02-21 18:04:39 +0100104 status_t loadResult = loadConfig();
105 if (loadResult < 0) {
106 ALOGE("Policy Wrapper configuration is partially invalid.");
François Gaffie20f06f92015-03-24 09:01:14 +0100107 }
François Gaffie20f06f92015-03-24 09:01:14 +0100108}
109
François Gaffiea56b5c22018-02-21 18:04:39 +0100110status_t ParameterManagerWrapper::loadConfig()
111{
112 auto result = wrapper_config::parse();
113 if (result.parsedConfig == nullptr) {
114 return -ENOENT;
115 }
116 ALOGE_IF(result.nbSkippedElement != 0, "skipped %zu elements", result.nbSkippedElement);
117
118 CriterionTypes criterionTypes;
119 for (auto criterionType : result.parsedConfig->criterionTypes) {
120 ALOG_ASSERT(criterionTypes.find(criterionType.name) == criterionTypes.end(),
121 "CriterionType %s already added", criterionType.name.c_str());
122 ALOGV("%s: Adding new criterionType %s", __FUNCTION__, criterionType.name.c_str());
123
124 auto criterionTypePfw =
125 mPfwConnector->createSelectionCriterionType(criterionType.isInclusive);
126
127 for (auto pair : criterionType.valuePairs) {
128 std::string error;
129 ALOGV("%s: Adding pair %d,%s for criterionType %s", __FUNCTION__, pair.first,
130 pair.second.c_str(), criterionType.name.c_str());
131 criterionTypePfw->addValuePair(pair.first, pair.second, error);
132 }
133 criterionTypes[criterionType.name] = criterionTypePfw;
134 }
135
136 for (auto criterion : result.parsedConfig->criteria) {
137 ALOG_ASSERT(mPolicyCriteria.find(criterion.name) == mPolicyCriteria.end(),
138 "%s: Criterion %s already added", __FUNCTION__, criterion.name.c_str());
139
140 auto criterionType =
141 getElement<ISelectionCriterionTypeInterface>(criterion.typeName, criterionTypes);
142 ALOG_ASSERT(criterionType != nullptr, "No %s Criterion type found for criterion %s",
143 criterion.typeName.c_str(), criterion.name.c_str());
144
145 auto criterionPfw = mPfwConnector->createSelectionCriterion(criterion.name, criterionType);
146 mPolicyCriteria[criterion.name] = criterionPfw;
147
148 if (not criterion.defaultLiteralValue.empty()) {
149 int numericalValue = 0;
150 if (not criterionType->getNumericalValue(criterion.defaultLiteralValue.c_str(),
151 numericalValue)) {
152 ALOGE("%s; trying to apply invalid default literal value (%s)", __FUNCTION__,
153 criterion.defaultLiteralValue.c_str());
154 continue;
155 }
156 criterionPfw->setCriterionState(numericalValue);
157 }
158 }
159 return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
160}
161
François Gaffie20f06f92015-03-24 09:01:14 +0100162ParameterManagerWrapper::~ParameterManagerWrapper()
163{
164 // Unset logger
165 mPfwConnector->setLogger(NULL);
166 // Remove logger
167 delete mPfwConnectorLogger;
168 // Remove connector
169 delete mPfwConnector;
170}
171
172status_t ParameterManagerWrapper::start()
173{
174 ALOGD("%s: in", __FUNCTION__);
175 /// Start PFW
176 std::string error;
177 if (!mPfwConnector->start(error)) {
178 ALOGE("%s: Policy PFW start error: %s", __FUNCTION__, error.c_str());
179 return NO_INIT;
180 }
181 ALOGD("%s: Policy PFW successfully started!", __FUNCTION__);
182 return NO_ERROR;
183}
184
François Gaffie20f06f92015-03-24 09:01:14 +0100185template <typename T>
186T *ParameterManagerWrapper::getElement(const string &name, std::map<string, T *> &elementsMap)
187{
188 parameterManagerElementSupported<T>();
189 typename std::map<string, T *>::iterator it = elementsMap.find(name);
François Gaffie814ce802016-01-18 11:23:47 +0100190 ALOG_ASSERT(it != elementsMap.end(), "Element %s not found", name.c_str());
191 return it != elementsMap.end() ? it->second : NULL;
François Gaffie20f06f92015-03-24 09:01:14 +0100192}
193
194template <typename T>
195const T *ParameterManagerWrapper::getElement(const string &name, const std::map<string, T *> &elementsMap) const
196{
197 parameterManagerElementSupported<T>();
198 typename std::map<string, T *>::const_iterator it = elementsMap.find(name);
François Gaffie814ce802016-01-18 11:23:47 +0100199 ALOG_ASSERT(it != elementsMap.end(), "Element %s not found", name.c_str());
200 return it != elementsMap.end() ? it->second : NULL;
François Gaffie20f06f92015-03-24 09:01:14 +0100201}
202
François Gaffie20f06f92015-03-24 09:01:14 +0100203bool ParameterManagerWrapper::isStarted()
204{
205 return mPfwConnector && mPfwConnector->isStarted();
206}
207
208status_t ParameterManagerWrapper::setPhoneState(audio_mode_t mode)
209{
François Gaffie814ce802016-01-18 11:23:47 +0100210 ISelectionCriterionInterface *criterion =
François Gaffiea56b5c22018-02-21 18:04:39 +0100211 getElement<ISelectionCriterionInterface>(gPhoneStateCriterionName, mPolicyCriteria);
François Gaffie814ce802016-01-18 11:23:47 +0100212 if (criterion == NULL) {
François Gaffiea56b5c22018-02-21 18:04:39 +0100213 ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionName);
François Gaffie814ce802016-01-18 11:23:47 +0100214 return BAD_VALUE;
215 }
François Gaffie20f06f92015-03-24 09:01:14 +0100216 if (!isValueValidForCriterion(criterion, static_cast<int>(mode))) {
217 return BAD_VALUE;
218 }
219 criterion->setCriterionState((int)(mode));
220 applyPlatformConfiguration();
221 return NO_ERROR;
222}
223
224audio_mode_t ParameterManagerWrapper::getPhoneState() const
225{
226 const ISelectionCriterionInterface *criterion =
François Gaffiea56b5c22018-02-21 18:04:39 +0100227 getElement<ISelectionCriterionInterface>(gPhoneStateCriterionName, mPolicyCriteria);
François Gaffie814ce802016-01-18 11:23:47 +0100228 if (criterion == NULL) {
François Gaffiea56b5c22018-02-21 18:04:39 +0100229 ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionName);
François Gaffie814ce802016-01-18 11:23:47 +0100230 return AUDIO_MODE_NORMAL;
231 }
François Gaffie20f06f92015-03-24 09:01:14 +0100232 return static_cast<audio_mode_t>(criterion->getCriterionState());
233}
234
235status_t ParameterManagerWrapper::setForceUse(audio_policy_force_use_t usage,
236 audio_policy_forced_cfg_t config)
237{
238 // @todo: return an error on a unsupported value
239 if (usage > AUDIO_POLICY_FORCE_USE_CNT) {
240 return BAD_VALUE;
241 }
242
François Gaffie814ce802016-01-18 11:23:47 +0100243 ISelectionCriterionInterface *criterion =
244 getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
245 if (criterion == NULL) {
François Gaffiea56b5c22018-02-21 18:04:39 +0100246 ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage]);
François Gaffie814ce802016-01-18 11:23:47 +0100247 return BAD_VALUE;
248 }
François Gaffie20f06f92015-03-24 09:01:14 +0100249 if (!isValueValidForCriterion(criterion, static_cast<int>(config))) {
250 return BAD_VALUE;
251 }
252 criterion->setCriterionState((int)config);
253 applyPlatformConfiguration();
254 return NO_ERROR;
255}
256
257audio_policy_forced_cfg_t ParameterManagerWrapper::getForceUse(audio_policy_force_use_t usage) const
258{
259 // @todo: return an error on a unsupported value
260 if (usage > AUDIO_POLICY_FORCE_USE_CNT) {
261 return AUDIO_POLICY_FORCE_NONE;
262 }
263 const ISelectionCriterionInterface *criterion =
264 getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
François Gaffie814ce802016-01-18 11:23:47 +0100265 if (criterion == NULL) {
François Gaffiea56b5c22018-02-21 18:04:39 +0100266 ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage]);
François Gaffie814ce802016-01-18 11:23:47 +0100267 return AUDIO_POLICY_FORCE_NONE;
268 }
François Gaffie20f06f92015-03-24 09:01:14 +0100269 return static_cast<audio_policy_forced_cfg_t>(criterion->getCriterionState());
270}
271
272bool ParameterManagerWrapper::isValueValidForCriterion(ISelectionCriterionInterface *criterion,
273 int valueToCheck)
274{
275 const ISelectionCriterionTypeInterface *interface = criterion->getCriterionType();
276 string literalValue;
277 return interface->getLiteralValue(valueToCheck, literalValue);
278}
279
François Gaffiea56b5c22018-02-21 18:04:39 +0100280status_t ParameterManagerWrapper::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
281 audio_policy_dev_state_t state)
282{
283 std::string criterionName = audio_is_output_device(devDesc->type()) ?
284 gOutputDeviceAddressCriterionName : gInputDeviceAddressCriterionName;
285
286 ALOGV("%s: device with address %s %s", __FUNCTION__, devDesc->mAddress.string(),
287 state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE? "disconnected" : "connected");
288 ISelectionCriterionInterface *criterion =
289 getElement<ISelectionCriterionInterface>(criterionName, mPolicyCriteria);
290
291 if (criterion == NULL) {
292 ALOGE("%s: no criterion found for %s", __FUNCTION__, criterionName.c_str());
293 return DEAD_OBJECT;
294 }
295
296 auto criterionType = criterion->getCriterionType();
297 int deviceAddressId;
298 if (not criterionType->getNumericalValue(devDesc->mAddress.string(), deviceAddressId)) {
299 ALOGE("%s: unknown device address reported (%s)", __FUNCTION__, devDesc->mAddress.c_str());
300 return BAD_TYPE;
301 }
302 int currentValueMask = criterion->getCriterionState();
303 if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
304 currentValueMask |= deviceAddressId;
305 }
306 else {
307 currentValueMask &= ~deviceAddressId;
308 }
309 criterion->setCriterionState(currentValueMask);
310 return NO_ERROR;
311}
312
François Gaffiea3e696d2015-12-18 09:38:43 +0100313status_t ParameterManagerWrapper::setAvailableInputDevices(audio_devices_t inputDevices)
François Gaffie20f06f92015-03-24 09:01:14 +0100314{
François Gaffie814ce802016-01-18 11:23:47 +0100315 ISelectionCriterionInterface *criterion =
François Gaffiea56b5c22018-02-21 18:04:39 +0100316 getElement<ISelectionCriterionInterface>(gInputDeviceCriterionName, mPolicyCriteria);
François Gaffie20f06f92015-03-24 09:01:14 +0100317 if (criterion == NULL) {
François Gaffiea56b5c22018-02-21 18:04:39 +0100318 ALOGE("%s: no criterion found for %s", __FUNCTION__, gInputDeviceCriterionName);
François Gaffie20f06f92015-03-24 09:01:14 +0100319 return DEAD_OBJECT;
320 }
François Gaffiea3e696d2015-12-18 09:38:43 +0100321 criterion->setCriterionState(inputDevices & ~AUDIO_DEVICE_BIT_IN);
322 applyPlatformConfiguration();
323 return NO_ERROR;
324}
François Gaffie20f06f92015-03-24 09:01:14 +0100325
François Gaffiea3e696d2015-12-18 09:38:43 +0100326status_t ParameterManagerWrapper::setAvailableOutputDevices(audio_devices_t outputDevices)
327{
François Gaffie814ce802016-01-18 11:23:47 +0100328 ISelectionCriterionInterface *criterion =
François Gaffiea56b5c22018-02-21 18:04:39 +0100329 getElement<ISelectionCriterionInterface>(gOutputDeviceCriterionName, mPolicyCriteria);
François Gaffiea3e696d2015-12-18 09:38:43 +0100330 if (criterion == NULL) {
François Gaffiea56b5c22018-02-21 18:04:39 +0100331 ALOGE("%s: no criterion found for %s", __FUNCTION__, gOutputDeviceCriterionName);
François Gaffiea3e696d2015-12-18 09:38:43 +0100332 return DEAD_OBJECT;
François Gaffie20f06f92015-03-24 09:01:14 +0100333 }
François Gaffiea3e696d2015-12-18 09:38:43 +0100334 criterion->setCriterionState(outputDevices);
François Gaffie20f06f92015-03-24 09:01:14 +0100335 applyPlatformConfiguration();
336 return NO_ERROR;
337}
338
339void ParameterManagerWrapper::applyPlatformConfiguration()
340{
341 mPfwConnector->applyConfigurations();
342}
343
344} // namespace audio_policy
345} // namespace android