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 <ParameterMgrPlatformConnector.h>
22 #include <SelectionCriterionTypeInterface.h>
23 #include <SelectionCriterionInterface.h>
24 #include <media/convert.h>
25 #include <algorithm>
26 #include <cutils/bitops.h>
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 <cinttypes>
36 #include <cmath>
37 #include <utils/Log.h>
38
39 using std::string;
40 using std::map;
41 using std::vector;
42
43 /// PFW related definitions
44 // Logger
45 class ParameterMgrPlatformConnectorLogger : public CParameterMgrPlatformConnector::ILogger
46 {
47 public:
ParameterMgrPlatformConnectorLogger()48 ParameterMgrPlatformConnectorLogger() {}
49
info(const string & log)50 virtual void info(const string &log)
51 {
52 ALOGV("policy-parameter-manager: %s", log.c_str());
53 }
warning(const string & log)54 virtual void warning(const string &log)
55 {
56 ALOGW("policy-parameter-manager: %s", log.c_str());
57 }
58 };
59
60 namespace android {
61
62 using utilities::convertTo;
63
64 namespace audio_policy {
65
66 const char *const ParameterManagerWrapper::mPolicyPfwDefaultConfFileName =
67 "/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
68 const char *const ParameterManagerWrapper::mPolicyPfwVendorConfFileName =
69 "/vendor/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
70
71 static const char *const gInputDeviceCriterionName = "AvailableInputDevices";
72 static const char *const gOutputDeviceCriterionName = "AvailableOutputDevices";
73 static const char *const gPhoneStateCriterionName = "TelephonyMode";
74 static const char *const gOutputDeviceAddressCriterionName = "AvailableOutputDevicesAddresses";
75 static const char *const gInputDeviceAddressCriterionName = "AvailableInputDevicesAddresses";
76
77 /**
78 * Order MUST be align with defintiion of audio_policy_force_use_t within audio_policy.h
79 */
80 static const char *const gForceUseCriterionTag[AUDIO_POLICY_FORCE_USE_CNT] =
81 {
82 [AUDIO_POLICY_FORCE_FOR_COMMUNICATION] = "ForceUseForCommunication",
83 [AUDIO_POLICY_FORCE_FOR_MEDIA] = "ForceUseForMedia",
84 [AUDIO_POLICY_FORCE_FOR_RECORD] = "ForceUseForRecord",
85 [AUDIO_POLICY_FORCE_FOR_DOCK] = "ForceUseForDock",
86 [AUDIO_POLICY_FORCE_FOR_SYSTEM] = "ForceUseForSystem",
87 [AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] = "ForceUseForHdmiSystemAudio",
88 [AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND] = "ForceUseForEncodedSurround",
89 [AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING] = "ForceUseForVibrateRinging"
90 };
91
92 template <>
93 struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionInterface> {};
94 template <>
95 struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionTypeInterface> {};
96
ParameterManagerWrapper(bool enableSchemaVerification,const std::string & schemaUri)97 ParameterManagerWrapper::ParameterManagerWrapper(bool enableSchemaVerification,
98 const std::string &schemaUri)
99 : mPfwConnectorLogger(new ParameterMgrPlatformConnectorLogger)
100 {
101 // Connector
102 if (access(mPolicyPfwVendorConfFileName, R_OK) == 0) {
103 mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwVendorConfFileName);
104 } else {
105 mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwDefaultConfFileName);
106 }
107
108 // Logger
109 mPfwConnector->setLogger(mPfwConnectorLogger);
110
111 // Schema validation
112 std::string error;
113 bool ret = mPfwConnector->setValidateSchemasOnStart(enableSchemaVerification, error);
114 ALOGE_IF(!ret, "Failed to activate schema validation: %s", error.c_str());
115 if (enableSchemaVerification && ret && !schemaUri.empty()) {
116 ALOGE("Schema verification activated with schema URI: %s", schemaUri.c_str());
117 mPfwConnector->setSchemaUri(schemaUri);
118 }
119 }
120
addCriterion(const std::string & name,bool isInclusive,ValuePairs pairs,const std::string & defaultValue)121 status_t ParameterManagerWrapper::addCriterion(const std::string &name, bool isInclusive,
122 ValuePairs pairs, const std::string &defaultValue)
123 {
124 ALOG_ASSERT(not isStarted(), "Cannot add a criterion if PFW is already started");
125 auto criterionType = mPfwConnector->createSelectionCriterionType(isInclusive);
126
127 for (auto pair : pairs) {
128 std::string error;
129 ALOGV("%s: Adding pair %" PRIu64", %s for criterionType %s", __func__, std::get<0>(pair),
130 std::get<2>(pair).c_str(), name.c_str());
131 criterionType->addValuePair(std::get<0>(pair), std::get<2>(pair), error);
132
133 if (name == gOutputDeviceCriterionName) {
134 ALOGV("%s: Adding mOutputDeviceToCriterionTypeMap %d %" PRIu64" for criterionType %s",
135 __func__, std::get<1>(pair), std::get<0>(pair), name.c_str());
136 audio_devices_t androidType = static_cast<audio_devices_t>(std::get<1>(pair));
137 mOutputDeviceToCriterionTypeMap[androidType] = std::get<0>(pair);
138 }
139 if (name == gInputDeviceCriterionName) {
140 ALOGV("%s: Adding mInputDeviceToCriterionTypeMap %d %" PRIu64" for criterionType %s",
141 __func__, std::get<1>(pair), std::get<0>(pair), name.c_str());
142 audio_devices_t androidType = static_cast<audio_devices_t>(std::get<1>(pair));
143 mInputDeviceToCriterionTypeMap[androidType] = std::get<0>(pair);
144 }
145 }
146 ALOG_ASSERT(mPolicyCriteria.find(name) == mPolicyCriteria.end(),
147 "%s: Criterion %s already added", __FUNCTION__, name.c_str());
148
149 auto criterion = mPfwConnector->createSelectionCriterion(name, criterionType);
150 mPolicyCriteria[name] = criterion;
151
152 if (not defaultValue.empty()) {
153 uint64_t numericalValue = 0;
154 if (not criterionType->getNumericalValue(defaultValue.c_str(), numericalValue)) {
155 ALOGE("%s; trying to apply invalid default literal value (%s)", __FUNCTION__,
156 defaultValue.c_str());
157 }
158 criterion->setCriterionState(numericalValue);
159 }
160 return NO_ERROR;
161 }
162
~ParameterManagerWrapper()163 ParameterManagerWrapper::~ParameterManagerWrapper()
164 {
165 // Unset logger
166 mPfwConnector->setLogger(NULL);
167 // Remove logger
168 delete mPfwConnectorLogger;
169 // Remove connector
170 delete mPfwConnector;
171 }
172
start(std::string & error)173 status_t ParameterManagerWrapper::start(std::string &error)
174 {
175 ALOGD("%s: in", __FUNCTION__);
176 /// Start PFW
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
185 template <typename T>
getElement(const string & name,std::map<string,T * > & elementsMap)186 T *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);
190 ALOG_ASSERT(it != elementsMap.end(), "Element %s not found", name.c_str());
191 return it != elementsMap.end() ? it->second : NULL;
192 }
193
194 template <typename T>
getElement(const string & name,const std::map<string,T * > & elementsMap) const195 const 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);
199 ALOG_ASSERT(it != elementsMap.end(), "Element %s not found", name.c_str());
200 return it != elementsMap.end() ? it->second : NULL;
201 }
202
isStarted()203 bool ParameterManagerWrapper::isStarted()
204 {
205 return mPfwConnector && mPfwConnector->isStarted();
206 }
207
setPhoneState(audio_mode_t mode)208 status_t ParameterManagerWrapper::setPhoneState(audio_mode_t mode)
209 {
210 ISelectionCriterionInterface *criterion =
211 getElement<ISelectionCriterionInterface>(gPhoneStateCriterionName, mPolicyCriteria);
212 if (criterion == NULL) {
213 ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionName);
214 return BAD_VALUE;
215 }
216 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
getPhoneState() const224 audio_mode_t ParameterManagerWrapper::getPhoneState() const
225 {
226 const ISelectionCriterionInterface *criterion =
227 getElement<ISelectionCriterionInterface>(gPhoneStateCriterionName, mPolicyCriteria);
228 if (criterion == NULL) {
229 ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionName);
230 return AUDIO_MODE_NORMAL;
231 }
232 return static_cast<audio_mode_t>(criterion->getCriterionState());
233 }
234
setForceUse(audio_policy_force_use_t usage,audio_policy_forced_cfg_t config)235 status_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
243 ISelectionCriterionInterface *criterion =
244 getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
245 if (criterion == NULL) {
246 ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage]);
247 return BAD_VALUE;
248 }
249 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
getForceUse(audio_policy_force_use_t usage) const257 audio_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);
265 if (criterion == NULL) {
266 ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage]);
267 return AUDIO_POLICY_FORCE_NONE;
268 }
269 return static_cast<audio_policy_forced_cfg_t>(criterion->getCriterionState());
270 }
271
isValueValidForCriterion(ISelectionCriterionInterface * criterion,int valueToCheck)272 bool 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
setDeviceConnectionState(audio_devices_t type,const std::string & address,audio_policy_dev_state_t state)280 status_t ParameterManagerWrapper::setDeviceConnectionState(
281 audio_devices_t type, const std::string &address, audio_policy_dev_state_t state)
282 {
283 std::string criterionName = audio_is_output_device(type) ?
284 gOutputDeviceAddressCriterionName : gInputDeviceAddressCriterionName;
285
286 ALOGV("%s: device with address %s %s", __FUNCTION__, address.c_str(),
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 uint64_t deviceAddressId;
298 if (not criterionType->getNumericalValue(address.c_str(), deviceAddressId)) {
299 ALOGW("%s: unknown device address reported (%s) for criterion %s", __FUNCTION__,
300 address.c_str(), criterionName.c_str());
301 return BAD_TYPE;
302 }
303 int currentValueMask = criterion->getCriterionState();
304 if (state == AUDIO_POLICY_DEVICE_STATE_AVAILABLE) {
305 currentValueMask |= deviceAddressId;
306 }
307 else {
308 currentValueMask &= ~deviceAddressId;
309 }
310 criterion->setCriterionState(currentValueMask);
311 return NO_ERROR;
312 }
313
setAvailableInputDevices(const DeviceTypeSet & types)314 status_t ParameterManagerWrapper::setAvailableInputDevices(const DeviceTypeSet &types)
315 {
316 ISelectionCriterionInterface *criterion =
317 getElement<ISelectionCriterionInterface>(gInputDeviceCriterionName, mPolicyCriteria);
318 if (criterion == NULL) {
319 ALOGE("%s: no criterion found for %s", __func__, gInputDeviceCriterionName);
320 return DEAD_OBJECT;
321 }
322 criterion->setCriterionState(convertDeviceTypesToCriterionValue(types));
323 applyPlatformConfiguration();
324 return NO_ERROR;
325 }
326
setAvailableOutputDevices(const DeviceTypeSet & types)327 status_t ParameterManagerWrapper::setAvailableOutputDevices(const DeviceTypeSet &types)
328 {
329 ISelectionCriterionInterface *criterion =
330 getElement<ISelectionCriterionInterface>(gOutputDeviceCriterionName, mPolicyCriteria);
331 if (criterion == NULL) {
332 ALOGE("%s: no criterion found for %s", __func__, gOutputDeviceCriterionName);
333 return DEAD_OBJECT;
334 }
335 criterion->setCriterionState(convertDeviceTypesToCriterionValue(types));
336 applyPlatformConfiguration();
337 return NO_ERROR;
338 }
339
applyPlatformConfiguration()340 void ParameterManagerWrapper::applyPlatformConfiguration()
341 {
342 mPfwConnector->applyConfigurations();
343 }
344
convertDeviceTypeToCriterionValue(audio_devices_t type) const345 uint64_t ParameterManagerWrapper::convertDeviceTypeToCriterionValue(audio_devices_t type) const {
346 bool isOut = audio_is_output_devices(type);
347 uint32_t typeMask = isOut ? type : (type & ~AUDIO_DEVICE_BIT_IN);
348
349 const auto &adapters = isOut ? mOutputDeviceToCriterionTypeMap : mInputDeviceToCriterionTypeMap;
350 // Only multibit devices need adaptation.
351 if (popcount(typeMask) > 1) {
352 const auto &adapter = adapters.find(type);
353 if (adapter != adapters.end()) {
354 ALOGV("%s: multibit device %d converted to criterion %" PRIu64, __func__, type,
355 adapter->second);
356 return adapter->second;
357 }
358 ALOGE("%s: failed to find map for multibit device %d", __func__, type);
359 return 0;
360 }
361 return typeMask;
362 }
363
convertDeviceTypesToCriterionValue(const DeviceTypeSet & types) const364 uint64_t ParameterManagerWrapper::convertDeviceTypesToCriterionValue(
365 const DeviceTypeSet &types) const {
366 uint64_t criterionValue = 0;
367 for (const auto &type : types) {
368 criterionValue += convertDeviceTypeToCriterionValue(type);
369 }
370 return criterionValue;
371 }
372
convertDeviceCriterionValueToDeviceTypes(uint64_t criterionValue,bool isOut) const373 DeviceTypeSet ParameterManagerWrapper::convertDeviceCriterionValueToDeviceTypes(
374 uint64_t criterionValue, bool isOut) const {
375 DeviceTypeSet deviceTypes;
376 const auto &adapters = isOut ? mOutputDeviceToCriterionTypeMap : mInputDeviceToCriterionTypeMap;
377 for (const auto &adapter : adapters) {
378 if ((adapter.second & criterionValue) == adapter.second) {
379 deviceTypes.insert(adapter.first);
380 }
381 }
382 return deviceTypes;
383 }
384
385 } // namespace audio_policy
386 } // namespace android
387