1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifndef LOG_TAG
16 #define LOG_TAG "AudioSettingProvider"
17 #endif
18
19 #include "audio_setting_provider.h"
20
21 #include "iservice_registry.h"
22 #include "audio_errors.h"
23 #include "system_ability_definition.h"
24 #include "audio_utils.h"
25
26 namespace OHOS {
27 namespace AudioStandard {
28 std::mutex AudioSettingProvider::mutex_;
29 std::atomic<bool> AudioSettingProvider::isDataShareReady_ = false;
30 sptr<IRemoteObject> AudioSettingProvider::remoteObj_;
31
32 const std::string SETTING_COLUMN_KEYWORD = "KEYWORD";
33 const std::string SETTING_COLUMN_VALUE = "VALUE";
34 const std::string SETTING_URI_PROXY = "datashare:///com.ohos.settingsdata/entry/settingsdata/SETTINGSDATA?Proxy=true";
35 const std::string SETTING_USER_URI_PROXY = "datashare:///com.ohos.settingsdata/entry/settingsdata/USER_SETTINGSDATA_";
36 const std::string SETTING_USER_SECURE_URI_PROXY =
37 "datashare:///com.ohos.settingsdata/entry/settingsdata/USER_SETTINGSDATA_SECURE_";
38 constexpr const char *SETTINGS_DATA_EXT_URI = "datashare:///com.ohos.settingsdata.DataAbility";
39 constexpr int32_t RETRY_TIMES = 5;
40 constexpr int64_t SLEEP_TIME = 1;
41
~AudioSettingProvider()42 AudioSettingProvider::~AudioSettingProvider()
43 {
44 remoteObj_ = nullptr;
45 }
46
OnChange()47 void AudioSettingObserver::OnChange()
48 {
49 if (update_) {
50 update_(key_);
51 }
52 }
53
SetKey(const std::string & key)54 void AudioSettingObserver::SetKey(const std::string &key)
55 {
56 key_ = key;
57 }
58
GetKey()59 const std::string& AudioSettingObserver::GetKey()
60 {
61 return key_;
62 }
63
SetUpdateFunc(UpdateFunc & func)64 void AudioSettingObserver::SetUpdateFunc(UpdateFunc &func)
65 {
66 update_ = func;
67 }
68
GetInstance(int32_t systemAbilityId)69 AudioSettingProvider& AudioSettingProvider::GetInstance(
70 int32_t systemAbilityId)
71 {
72 static AudioSettingProvider instance_;
73 std::lock_guard<std::mutex> lock(mutex_);
74 if (remoteObj_ == nullptr) {
75 Initialize(systemAbilityId);
76 }
77 return instance_;
78 }
79
GetIntValue(const std::string & key,int32_t & value,std::string tableType)80 ErrCode AudioSettingProvider::GetIntValue(const std::string &key, int32_t &value,
81 std::string tableType)
82 {
83 int64_t valueLong;
84 ErrCode ret = GetLongValue(key, valueLong, tableType);
85 if (ret != ERR_OK) {
86 return ret;
87 }
88 value = static_cast<int32_t>(valueLong);
89 return ERR_OK;
90 }
91
GetLongValue(const std::string & key,int64_t & value,std::string tableType)92 ErrCode AudioSettingProvider::GetLongValue(const std::string &key, int64_t &value,
93 std::string tableType)
94 {
95 std::string valueStr;
96 ErrCode ret = GetStringValue(key, valueStr, tableType);
97 if (ret != ERR_OK) {
98 return ret;
99 }
100 value = static_cast<int64_t>(strtoll(valueStr.c_str(), nullptr, MAX_STRING_LENGTH));
101 return ERR_OK;
102 }
103
GetFloatValue(const std::string & key,float & value,std::string tableType)104 ErrCode AudioSettingProvider::GetFloatValue(const std::string &key, float &value,
105 std::string tableType)
106 {
107 std::string valueStr;
108 ErrCode ret = GetStringValue(key, valueStr, tableType);
109 if (ret != ERR_OK) {
110 return ret;
111 }
112 CHECK_AND_RETURN_RET_LOG(StringConverterFloat(valueStr, value), ERR_INVALID_PARAM,
113 "GetFloatValue error! invalid valueStr = %{public}s", valueStr.c_str());
114 return ERR_OK;
115 }
116
GetBoolValue(const std::string & key,bool & value,std::string tableType,int32_t userId)117 ErrCode AudioSettingProvider::GetBoolValue(const std::string &key, bool &value,
118 std::string tableType, int32_t userId)
119 {
120 std::string valueStr;
121 ErrCode ret = GetStringValue(key, valueStr, tableType, userId);
122 if (ret != ERR_OK) {
123 return ret;
124 }
125 value = (valueStr == "true");
126 return ERR_OK;
127 }
128
GetMapValue(const std::string & key,std::vector<std::map<std::string,std::string>> & value,std::string tableType)129 ErrCode AudioSettingProvider::GetMapValue(const std::string &key,
130 std::vector<std::map<std::string, std::string>> &value, std::string tableType)
131 {
132 std::string valueStr;
133 ErrCode ret = GetStringValue(key, valueStr, tableType);
134 if (ret != ERR_OK) {
135 return ret;
136 }
137 value = ParseJsonArray(valueStr);
138 return ERR_OK;
139 }
140
ParseJsonArray(const std::string & input)141 std::vector<std::map<std::string, std::string>> AudioSettingProvider::ParseJsonArray(const std::string& input)
142 {
143 std::vector<std::map<std::string, std::string>> result;
144 size_t pos = 0;
145 const size_t len = input.length();
146 //skip the space value
147 auto skipWhitespace = [&]() {
148 while (pos < len && isspace(input[pos])) pos++;
149 };
150
151 skipWhitespace();
152 if (input[pos++] != '[') return {};
153 while (pos < len) {
154 skipWhitespace();
155 if (input[pos] == ']') break;
156 if (input[pos++]!= '{') return {};
157 std::map<std::string, std::string> obj;
158 while (pos < len) {
159 skipWhitespace();
160 if (input[pos] == '}') {
161 pos++;
162 break;
163 }
164 std::string key = ParseFirstOfKey(pos, len, input);
165 if (key != "uid" && input.find(',', pos) != std::string::npos) {
166 pos = input.find(',', pos);
167 pos++;
168 continue;
169 }
170 if (key != "uid") {
171 continue;
172 }
173 skipWhitespace();
174 if (input[pos++] != ':') return {};
175 std::string value = ParseSecondOfValue(pos, len, input);
176 if (!key.empty() || !value.empty()) {
177 obj[value] = "1";
178 }
179 skipWhitespace();
180 if (input[pos] == ',') pos++;
181 }
182 result.push_back(obj);
183 skipWhitespace();
184 if (input[pos] == ',') pos++;
185 }
186 return result;
187 }
188
ParseFirstOfKey(size_t & pos,size_t len,std::string input)189 std::string AudioSettingProvider::ParseFirstOfKey(size_t &pos, size_t len, std::string input)
190 {
191 // parse the key of input
192 while (pos < len && isspace(input[pos])) {
193 pos++;
194 }
195 if (pos >= len) {
196 return "";
197 }
198 size_t start = ++pos;
199 while (pos < len && input[pos] != '"') {
200 pos++;
201 }
202 std::string str = input.substr(start, pos - start);
203 if (pos < len) {
204 pos++;
205 }
206 return str;
207 }
208
ParseSecondOfValue(size_t & pos,size_t len,std::string input)209 std::string AudioSettingProvider::ParseSecondOfValue(size_t &pos, size_t len, std::string input)
210 {
211 // parse the value of input
212 while (pos < len && isspace(input[pos])) {
213 pos++;
214 }
215 if (pos >= len) {
216 return "";
217 }
218 size_t start = pos;
219 while (pos < len && input[pos] != ',') {
220 pos++;
221 }
222 std::string str = input.substr(start, pos - start);
223 if (pos < len) {
224 pos++;
225 }
226 return str;
227 }
228
PutIntValue(const std::string & key,int32_t value,std::string tableType,bool needNotify)229 ErrCode AudioSettingProvider::PutIntValue(const std::string &key, int32_t value,
230 std::string tableType, bool needNotify)
231 {
232 return PutStringValue(key, std::to_string(value), tableType, needNotify);
233 }
234
PutLongValue(const std::string & key,int64_t value,std::string tableType,bool needNotify)235 ErrCode AudioSettingProvider::PutLongValue(const std::string &key, int64_t value,
236 std::string tableType, bool needNotify)
237 {
238 return PutStringValue(key, std::to_string(value), tableType, needNotify);
239 }
240
PutBoolValue(const std::string & key,bool value,std::string tableType,bool needNotify,int32_t userId)241 ErrCode AudioSettingProvider::PutBoolValue(const std::string &key, bool value,
242 std::string tableType, bool needNotify, int32_t userId)
243 {
244 std::string valueStr = value ? "true" : "false";
245 return PutStringValue(key, valueStr, tableType, needNotify, userId);
246 }
247
IsValidKey(const std::string & key)248 bool AudioSettingProvider::IsValidKey(const std::string &key)
249 {
250 std::string value;
251 ErrCode ret = GetStringValue(key, value);
252 return (ret != ERR_NAME_NOT_FOUND) && (!value.empty());
253 }
254
CreateObserver(const std::string & key,AudioSettingObserver::UpdateFunc & func)255 sptr<AudioSettingObserver> AudioSettingProvider::CreateObserver(
256 const std::string &key, AudioSettingObserver::UpdateFunc &func)
257 {
258 sptr<AudioSettingObserver> observer = new AudioSettingObserver();
259 observer->SetKey(key);
260 observer->SetUpdateFunc(func);
261 return observer;
262 }
263
ExecRegisterCb(const sptr<AudioSettingObserver> & observer)264 void AudioSettingProvider::ExecRegisterCb(const sptr<AudioSettingObserver> &observer)
265 {
266 if (observer == nullptr) {
267 AUDIO_ERR_LOG("observer is nullptr");
268 return;
269 }
270 observer->OnChange();
271 }
272
RegisterObserver(const sptr<AudioSettingObserver> & observer,std::string tableType)273 ErrCode AudioSettingProvider::RegisterObserver(const sptr<AudioSettingObserver> &observer, std::string tableType)
274 {
275 std::string callingIdentity = IPCSkeleton::ResetCallingIdentity();
276 auto uri = AssembleUri(observer->GetKey(), tableType);
277 if (!isDataShareReady_) {
278 AUDIO_WARNING_LOG("DataShareHelper is not ready");
279 return ERR_NO_INIT;
280 }
281 auto helper = CreateDataShareHelper(tableType);
282 if (helper == nullptr) {
283 IPCSkeleton::SetCallingIdentity(callingIdentity);
284 return ERR_NO_INIT;
285 }
286 helper->RegisterObserver(uri, observer);
287 helper->NotifyChange(uri);
288 auto execFirCb = ([observer] { ExecRegisterCb(observer); });
289 std::thread execCb(execFirCb);
290 execCb.detach();
291 ReleaseDataShareHelper(helper);
292 IPCSkeleton::SetCallingIdentity(callingIdentity);
293 AUDIO_DEBUG_LOG("succeed to register observer of uri=%{public}s", uri.ToString().c_str());
294 return ERR_OK;
295 }
296
UnregisterObserver(const sptr<AudioSettingObserver> & observer,std::string tableType)297 ErrCode AudioSettingProvider::UnregisterObserver(const sptr<AudioSettingObserver> &observer, std::string tableType)
298 {
299 std::string callingIdentity = IPCSkeleton::ResetCallingIdentity();
300 auto uri = AssembleUri(observer->GetKey(), tableType);
301 auto helper = CreateDataShareHelper(tableType);
302 if (helper == nullptr) {
303 IPCSkeleton::SetCallingIdentity(callingIdentity);
304 return ERR_NO_INIT;
305 }
306 helper->UnregisterObserver(uri, observer);
307 ReleaseDataShareHelper(helper);
308 IPCSkeleton::SetCallingIdentity(callingIdentity);
309 AUDIO_DEBUG_LOG("succeed to unregister observer of uri=%{public}s", uri.ToString().c_str());
310 return ERR_OK;
311 }
312
Initialize(int32_t systemAbilityId)313 void AudioSettingProvider::Initialize(int32_t systemAbilityId)
314 {
315 auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
316 if (sam == nullptr) {
317 AUDIO_ERR_LOG("GetSystemAbilityManager return nullptr");
318 return;
319 }
320 auto remoteObj = sam->GetSystemAbility(systemAbilityId);
321 if (remoteObj == nullptr) {
322 AUDIO_ERR_LOG("GetSystemAbility return nullptr, systemAbilityId=%{public}d", systemAbilityId);
323 return;
324 }
325 remoteObj_ = remoteObj;
326 }
327
GetStringValue(const std::string & key,std::string & value,std::string tableType,int32_t userId)328 ErrCode AudioSettingProvider::GetStringValue(const std::string &key,
329 std::string &value, std::string tableType, int32_t userId)
330 {
331 std::string callingIdentity = IPCSkeleton::ResetCallingIdentity();
332 auto helper = CreateDataShareHelper(tableType, userId);
333 if (helper == nullptr) {
334 IPCSkeleton::SetCallingIdentity(callingIdentity);
335 return ERR_NO_INIT;
336 }
337 std::vector<std::string> columns = {SETTING_COLUMN_VALUE};
338 DataShare::DataSharePredicates predicates;
339 predicates.EqualTo(SETTING_COLUMN_KEYWORD, key);
340 Uri uri(AssembleUri(key, tableType, userId));
341 auto resultSet = helper->Query(uri, predicates, columns);
342 ReleaseDataShareHelper(helper);
343 if (resultSet == nullptr) {
344 AUDIO_ERR_LOG("helper->Query return nullptr");
345 IPCSkeleton::SetCallingIdentity(callingIdentity);
346 return ERR_INVALID_OPERATION;
347 }
348 int32_t count;
349 resultSet->GetRowCount(count);
350 if (count == 0) {
351 AUDIO_WARNING_LOG("not found value, key=%{public}s, uri=%{public}s, count=%{public}d", key.c_str(),
352 uri.ToString().c_str(), count);
353 IPCSkeleton::SetCallingIdentity(callingIdentity);
354 resultSet->Close();
355 return ERR_NAME_NOT_FOUND;
356 }
357 const int32_t INDEX = 0;
358 resultSet->GoToRow(INDEX);
359 int32_t ret = resultSet->GetString(INDEX, value);
360 if (ret != SUCCESS) {
361 AUDIO_WARNING_LOG("resultSet->GetString return not ok, ret=%{public}d", ret);
362 IPCSkeleton::SetCallingIdentity(callingIdentity);
363 resultSet->Close();
364 return ERR_INVALID_VALUE;
365 } else {
366 AUDIO_INFO_LOG("Read audio_info_database with key: %{public}s value: %{public}s in uri=%{public}s ",
367 key.c_str(), value.c_str(), uri.ToString().c_str());
368 }
369 resultSet->Close();
370 IPCSkeleton::SetCallingIdentity(callingIdentity);
371 return ERR_OK;
372 }
373
PutStringValue(const std::string & key,const std::string & value,std::string tableType,bool needNotify,int32_t userId)374 ErrCode AudioSettingProvider::PutStringValue(const std::string &key, const std::string &value,
375 std::string tableType, bool needNotify, int32_t userId)
376 {
377 AUDIO_INFO_LOG("Write audio_info_database with key: %{public}s value: %{public}s", key.c_str(), value.c_str());
378 std::string callingIdentity = IPCSkeleton::ResetCallingIdentity();
379 auto helper = CreateDataShareHelper(tableType, userId);
380 if (helper == nullptr) {
381 IPCSkeleton::SetCallingIdentity(callingIdentity);
382 return ERR_NO_INIT;
383 }
384 DataShare::DataShareValueObject keyObj(key);
385 DataShare::DataShareValueObject valueObj(value);
386 DataShare::DataShareValuesBucket bucket;
387 bucket.Put(SETTING_COLUMN_KEYWORD, keyObj);
388 bucket.Put(SETTING_COLUMN_VALUE, valueObj);
389 DataShare::DataSharePredicates predicates;
390 predicates.EqualTo(SETTING_COLUMN_KEYWORD, key);
391 Uri uri(AssembleUri(key, tableType, userId));
392 if (helper->Update(uri, predicates, bucket) <= 0) {
393 AUDIO_INFO_LOG("audio_info_database no data exist, insert one row");
394 helper->Insert(uri, bucket);
395 }
396 if (needNotify) {
397 helper->NotifyChange(AssembleUri(key, tableType, userId));
398 }
399 ReleaseDataShareHelper(helper);
400 IPCSkeleton::SetCallingIdentity(callingIdentity);
401 return ERR_OK;
402 }
403
GetCurrentUserId(int32_t specificUserId)404 int32_t AudioSettingProvider::GetCurrentUserId(int32_t specificUserId)
405 {
406 if (specificUserId != INVALID_ACCOUNT_ID && specificUserId >= MIN_USER_ACCOUNT) {
407 AUDIO_INFO_LOG("just use specific id: %{public}d", specificUserId);
408 return specificUserId;
409 }
410 std::vector<int> ids;
411 int32_t currentuserId = -1;
412 ErrCode result;
413 int32_t retry = RETRY_TIMES;
414 while (retry--) {
415 result = AccountSA::OsAccountManager::QueryActiveOsAccountIds(ids);
416 if (result == ERR_OK && !ids.empty()) {
417 currentuserId = ids[0];
418 AUDIO_DEBUG_LOG("current userId is :%{public}d", currentuserId);
419 break;
420 }
421 // sleep and wait for 1 second
422 sleep(SLEEP_TIME);
423 }
424 if (result != ERR_OK || ids.empty()) {
425 AUDIO_WARNING_LOG("current userId is empty");
426 }
427 return currentuserId;
428 }
429
CheckOsAccountReady()430 bool AudioSettingProvider::CheckOsAccountReady()
431 {
432 std::vector<int> ids;
433 ErrCode result = AccountSA::OsAccountManager::QueryActiveOsAccountIds(ids);
434 return (result == ERR_OK && !ids.empty());
435 }
436
SetDataShareReady(std::atomic<bool> isDataShareReady)437 void AudioSettingProvider::SetDataShareReady(std::atomic<bool> isDataShareReady)
438 {
439 AUDIO_INFO_LOG("Receive event DATA_SHARE_READY");
440 isDataShareReady_.store(isDataShareReady);
441 }
442
CreateDataShareHelper(std::string tableType,int32_t userId)443 std::shared_ptr<DataShare::DataShareHelper> AudioSettingProvider::CreateDataShareHelper(
444 std::string tableType, int32_t userId)
445 {
446 CHECK_AND_RETURN_RET_LOG(isDataShareReady_.load(), nullptr,
447 "DATA_SHARE_READY not received, create DataShareHelper failed");
448 {
449 std::lock_guard<std::mutex> lock(mutex_);
450 if (remoteObj_ == nullptr) {
451 AUDIO_WARNING_LOG("remoteObj_ is nullptr");
452 Initialize(AUDIO_POLICY_SERVICE_ID);
453 }
454 }
455 #ifdef SUPPORT_USER_ACCOUNT
456 int32_t currentuserId = GetCurrentUserId(userId);
457 if (currentuserId < MIN_USER_ACCOUNT) {
458 currentuserId = MIN_USER_ACCOUNT;
459 }
460 #else
461 int32_t currentuserId = -1;
462 #endif
463 std::shared_ptr<DataShare::DataShareHelper> helper = nullptr;
464 std::string SettingSystemUrlProxy = "";
465 // deal with multi useraccount table
466 if (currentuserId > 0 && tableType == "system") {
467 SettingSystemUrlProxy =
468 SETTING_USER_URI_PROXY + std::to_string(currentuserId) + "?Proxy=true";
469 helper = DataShare::DataShareHelper::Creator(remoteObj_, SettingSystemUrlProxy, SETTINGS_DATA_EXT_URI);
470 } else if (currentuserId > 0 && tableType == "secure") {
471 SettingSystemUrlProxy =
472 SETTING_USER_SECURE_URI_PROXY + std::to_string(currentuserId) + "?Proxy=true";
473 WatchTimeout guard("DataShare::DataShareHelper::Creator:CreateDataShareHelper.SettingSystemUrlProxy");
474 helper = DataShare::DataShareHelper::Creator(remoteObj_, SettingSystemUrlProxy, SETTINGS_DATA_EXT_URI);
475 guard.CheckCurrTimeout();
476 } else {
477 WatchTimeout guard("DataShare::DataShareHelper::Creator:CreateDataShareHelper.SETTING_URI_PROXY");
478 helper = DataShare::DataShareHelper::Creator(remoteObj_, SETTING_URI_PROXY, SETTINGS_DATA_EXT_URI);
479 guard.CheckCurrTimeout();
480 }
481 if (helper == nullptr) {
482 AUDIO_WARNING_LOG("helper is nullptr, uri=%{public}s", SettingSystemUrlProxy.c_str());
483 return nullptr;
484 }
485 return helper;
486 }
487
ReleaseDataShareHelper(std::shared_ptr<DataShare::DataShareHelper> & helper)488 bool AudioSettingProvider::ReleaseDataShareHelper(
489 std::shared_ptr<DataShare::DataShareHelper> &helper)
490 {
491 if (!helper->Release()) {
492 AUDIO_WARNING_LOG("release helper fail");
493 return false;
494 }
495 return true;
496 }
497
AssembleUri(const std::string & key,std::string tableType,int32_t userId)498 Uri AudioSettingProvider::AssembleUri(const std::string &key, std::string tableType, int32_t userId)
499 {
500 #ifdef SUPPORT_USER_ACCOUNT
501 int32_t currentuserId = GetCurrentUserId(userId);
502 if (currentuserId < MIN_USER_ACCOUNT) {
503 currentuserId = MIN_USER_ACCOUNT;
504 }
505 #else
506 int32_t currentuserId = -1;
507 #endif
508 std::string SettingSystemUrlProxy = "";
509
510 // deal with multi useraccount table
511 if (currentuserId > 0 && tableType == "system") {
512 SettingSystemUrlProxy = SETTING_USER_URI_PROXY + std::to_string(currentuserId) + "?Proxy=true";
513 Uri uri(SettingSystemUrlProxy + "&key=" + key);
514 return uri;
515 } else if (currentuserId > 0 && tableType == "secure") {
516 SettingSystemUrlProxy = SETTING_USER_SECURE_URI_PROXY + std::to_string(currentuserId) + "?Proxy=true";
517 Uri uri(SettingSystemUrlProxy + "&key=" + key);
518 return uri;
519 }
520 Uri uri(SETTING_URI_PROXY + "&key=" + key);
521 return uri;
522 }
523 } // namespace AudioStandard
524 } // namespace OHOS
525