* Copyright (c) 2022 Huawei Device Co., Ltd.
* 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.
*/
#include "setting_provider.h"
#include <thread>
#include <regex>
#include "datashare_predicates.h"
#include "datashare_result_set.h"
#include "datashare_values_bucket.h"
#include "ipc_skeleton.h"
#include "iservice_registry.h"
#include "os_account_manager.h"
#include "power_log.h"
#include "rdb_errno.h"
#include "result_set.h"
#include "uri.h"
#include "ffrt.h"
namespace OHOS {
namespace PowerMgr {
static ffrt::mutex g_settingMutex;
namespace {
const std::string SETTING_COLUMN_KEYWORD = "KEYWORD";
const std::string SETTING_COLUMN_VALUE = "VALUE";
const std::string SETTING_URI_PROXY = "datashare:///com.ohos.settingsdata/entry/settingsdata/SETTINGSDATA?Proxy=true";
const std::string SETTING_URI_PROXY_USER = "datashare:///com.ohos.settingsdata/entry/settingsdata/";
constexpr const char *USERID_REPLACE = "##USERID##";
constexpr const char *SETTINGS_DATA_EXT_URI = "datashare:///com.ohos.settingsdata.DataAbility";
}
SettingProvider::~SettingProvider()
{
instance_ = nullptr;
remoteObj_ = nullptr;
}
SettingProvider& SettingProvider::GetInstance(int32_t systemAbilityId)
{
SettingProvider* tmp = instance_.load(std::memory_order_acquire);
if (tmp == nullptr) {
std::lock_guard<ffrt::mutex> lock(g_settingMutex);
tmp = instance_.load(std::memory_order_relaxed);
if (tmp == nullptr) {
Initialize(systemAbilityId);
tmp = new SettingProvider();
instance_.store(tmp, std::memory_order_release);
}
}
return *instance_;
}
void SettingProvider::CopyDataForUpdateScene()
{
if (IsNeedDataMigrationCopy()) {
DataMigrationCopy();
}
}
ErrCode SettingProvider::GetIntValue(const std::string& key, int32_t& value)
{
int64_t valueLong;
ErrCode ret = GetLongValue(key, valueLong);
if (ret != ERR_OK) {
return ret;
}
value = static_cast<int32_t>(valueLong);
return ERR_OK;
}
ErrCode SettingProvider::GetLongValue(const std::string& key, int64_t& value)
{
std::string valueStr;
ErrCode ret = GetStringValue(key, valueStr);
if (ret != ERR_OK) {
return ret;
}
char* endptr = nullptr;
int64_t result = static_cast<int64_t>(strtoll(valueStr.c_str(), &endptr, 10));
if (endptr == nullptr || *endptr != '\0') {
POWER_HILOGE(COMP_UTILS, "GetLongValue error! key:%{public}s, value:%{public}s",
key.c_str(), valueStr.c_str());
return ERR_INVALID_VALUE;
}
value = result;
return ERR_OK;
}
ErrCode SettingProvider::GetBoolValue(const std::string& key, bool& value)
{
std::string valueStr;
ErrCode ret = GetStringValue(key, valueStr);
if (ret != ERR_OK) {
return ret;
}
value = (valueStr == "true");
return ERR_OK;
}
ErrCode SettingProvider::PutIntValue(const std::string& key, int32_t value, bool needNotify)
{
return PutStringValue(key, std::to_string(value), needNotify);
}
ErrCode SettingProvider::PutLongValue(const std::string& key, int64_t value, bool needNotify)
{
return PutStringValue(key, std::to_string(value), needNotify);
}
ErrCode SettingProvider::PutBoolValue(const std::string& key, bool value, bool needNotify)
{
std::string valueStr = value ? "true" : "false";
return PutStringValue(key, valueStr, needNotify);
}
bool SettingProvider::IsValidKey(const std::string& key)
{
std::string value;
ErrCode ret = GetStringValue(key, value);
if (!value.empty()) {
POWER_HILOGI(COMP_UTILS, "the getValue is:%{public}s", value.c_str());
}
POWER_HILOGI(COMP_UTILS, "the getRet is:%{public}u", ret);
return (ret != ERR_NAME_NOT_FOUND) && (!value.empty());
}
bool SettingProvider::IsValidKeyGlobal(const std::string& key)
{
std::string value;
ErrCode ret = GetStringValueGlobal(key, value);
if (!value.empty()) {
POWER_HILOGI(COMP_UTILS, "the getValueGlobal is:%{public}s", value.c_str());
}
POWER_HILOGI(COMP_UTILS, "the getRetGlobal is:%{public}u", ret);
return (ret != ERR_NAME_NOT_FOUND) && (!value.empty());
}
sptr<SettingObserver> SettingProvider::CreateObserver(const std::string& key, const SettingObserver::UpdateFunc& func)
{
sptr<SettingObserver> observer = new SettingObserver();
observer->SetKey(key);
observer->SetUpdateFunc(func);
return observer;
}
void SettingProvider::ExecRegisterCb(const sptr<SettingObserver>& observer)
{
if (observer == nullptr) {
POWER_HILOGE(COMP_UTILS, "observer is nullptr");
return;
}
observer->OnChange();
}
ErrCode SettingProvider::RegisterObserver(const sptr<SettingObserver>& observer)
{
if (observer == nullptr) {
POWER_HILOGE(COMP_UTILS, "observer is nullptr");
return ERR_INVALID_VALUE;
}
std::string callingIdentity = IPCSkeleton::ResetCallingIdentity();
auto uri = AssembleUri(observer->GetKey());
auto helper = CreateDataShareHelper(observer->GetKey());
if (helper == nullptr) {
IPCSkeleton::SetCallingIdentity(callingIdentity);
return ERR_NO_INIT;
}
helper->RegisterObserver(uri, observer);
helper->NotifyChange(uri);
std::thread execCb([this, observer] { this->ExecRegisterCb(observer); });
execCb.detach();
ReleaseDataShareHelper(helper);
IPCSkeleton::SetCallingIdentity(callingIdentity);
POWER_HILOGD(COMP_UTILS, "succeed to register observer of uri=%{public}s", uri.ToString().c_str());
return ERR_OK;
}
ErrCode SettingProvider::UnregisterObserver(const sptr<SettingObserver>& observer)
{
if (observer == nullptr) {
POWER_HILOGE(COMP_UTILS, "observer is nullptr");
return ERR_INVALID_VALUE;
}
std::string callingIdentity = IPCSkeleton::ResetCallingIdentity();
auto uri = AssembleUri(observer->GetKey());
auto helper = CreateDataShareHelper(observer->GetKey());
if (helper == nullptr) {
IPCSkeleton::SetCallingIdentity(callingIdentity);
return ERR_NO_INIT;
}
helper->UnregisterObserver(uri, observer);
ReleaseDataShareHelper(helper);
IPCSkeleton::SetCallingIdentity(callingIdentity);
POWER_HILOGD(COMP_UTILS, "succeed to unregister observer of uri=%{public}s", uri.ToString().c_str());
return ERR_OK;
}
void SettingProvider::Initialize(int32_t systemAbilityId)
{
auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (sam == nullptr) {
POWER_HILOGE(COMP_UTILS, "GetSystemAbilityManager return nullptr");
return;
}
auto remoteObj = sam->GetSystemAbility(systemAbilityId);
if (remoteObj == nullptr) {
POWER_HILOGE(COMP_UTILS, "GetSystemAbility return nullptr, systemAbilityId=%{public}d", systemAbilityId);
remoteObj = sptr<IPCObjectStub>::MakeSptr(u"ohos.powermgr.utils.setting_provider");
}
remoteObj_ = std::move(remoteObj);
}
ErrCode SettingProvider::GetStringValue(const std::string& key, std::string& value)
{
std::string callingIdentity = IPCSkeleton::ResetCallingIdentity();
auto helper = CreateDataShareHelper(key);
if (helper == nullptr) {
IPCSkeleton::SetCallingIdentity(callingIdentity);
return ERR_NO_INIT;
}
std::vector<std::string> columns = {SETTING_COLUMN_VALUE};
DataShare::DataSharePredicates predicates;
predicates.EqualTo(SETTING_COLUMN_KEYWORD, key);
Uri uri(AssembleUri(key));
auto resultSet = helper->Query(uri, predicates, columns);
ReleaseDataShareHelper(helper);
if (resultSet == nullptr) {
POWER_HILOGE(COMP_UTILS, "helper->Query return nullptr");
IPCSkeleton::SetCallingIdentity(callingIdentity);
return ERR_INVALID_OPERATION;
}
int32_t count;
resultSet->GetRowCount(count);
if (count == 0) {
POWER_HILOGW(COMP_UTILS, "not found value, key=%{public}s, count=%{public}d", key.c_str(), count);
IPCSkeleton::SetCallingIdentity(callingIdentity);
resultSet->Close();
return ERR_NAME_NOT_FOUND;
}
const int32_t INDEX = 0;
resultSet->GoToRow(INDEX);
int32_t ret = resultSet->GetString(INDEX, value);
if (ret != NativeRdb::E_OK) {
POWER_HILOGW(COMP_UTILS, "resultSet->GetString return not ok, ret=%{public}d", ret);
IPCSkeleton::SetCallingIdentity(callingIdentity);
resultSet->Close();
return ERR_INVALID_VALUE;
}
resultSet->Close();
IPCSkeleton::SetCallingIdentity(callingIdentity);
return ERR_OK;
}
ErrCode SettingProvider::PutStringValue(const std::string& key, const std::string& value, bool needNotify)
{
std::string callingIdentity = IPCSkeleton::ResetCallingIdentity();
auto helper = CreateDataShareHelper(key);
if (helper == nullptr) {
IPCSkeleton::SetCallingIdentity(callingIdentity);
return ERR_NO_INIT;
}
DataShare::DataShareValueObject keyObj(key);
DataShare::DataShareValueObject valueObj(value);
DataShare::DataShareValuesBucket bucket;
bucket.Put(SETTING_COLUMN_KEYWORD, keyObj);
bucket.Put(SETTING_COLUMN_VALUE, valueObj);
DataShare::DataSharePredicates predicates;
predicates.EqualTo(SETTING_COLUMN_KEYWORD, key);
Uri uri(AssembleUri(key));
if (helper->Update(uri, predicates, bucket) <= 0) {
POWER_HILOGD(COMP_UTILS, "no data exist, insert one row");
helper->Insert(uri, bucket);
}
if (needNotify) {
helper->NotifyChange(AssembleUri(key));
}
ReleaseDataShareHelper(helper);
IPCSkeleton::SetCallingIdentity(callingIdentity);
return ERR_OK;
}
std::shared_ptr<DataShare::DataShareHelper> SettingProvider::CreateDataShareHelper(const std::string& key)
{
std::lock_guard<ffrt::mutex> lock(g_settingMutex);
std::string uriProxyStr;
if (IsNeedMultiUser(key)) {
uriProxyStr = SETTING_URI_PROXY_USER + "USER_SETTINGSDATA_SECURE_" +
std::to_string(currentUserId_) + "?Proxy=true";
POWER_HILOGI(COMP_UTILS, "the uriProxyStr is %{public}s", uriProxyStr.c_str());
} else {
uriProxyStr = SETTING_URI_PROXY;
}
auto helper = DataShare::DataShareHelper::Creator(remoteObj_, uriProxyStr, SETTINGS_DATA_EXT_URI);
if (helper == nullptr) {
POWER_HILOGW(COMP_UTILS, "helper is nullptr, uri=%{public}s", uriProxyStr.c_str());
return nullptr;
}
return helper;
}
bool SettingProvider::ReleaseDataShareHelper(std::shared_ptr<DataShare::DataShareHelper>& helper)
{
if (!helper->Release()) {
POWER_HILOGW(COMP_UTILS, "release helper fail");
return false;
}
return true;
}
std::string SettingProvider::GetUriPrefix(int32_t userId, const std::string& key)
{
if (IsNeedMultiUser(key)) {
static const std::regex pattern(USERID_REPLACE);
auto specialUri = std::regex_replace(needMultiUserStrMap[key], pattern, std::to_string(userId));
POWER_HILOGI(COMP_UTILS, "the non-global uri is %{public}s&key=%{public}s", specialUri.c_str(), key.c_str());
return specialUri;
} else {
return SETTING_URI_NORMAL;
}
}
Uri SettingProvider::AssembleUri(const std::string& key)
{
std::lock_guard<ffrt::mutex> lock(g_settingMutex);
auto userSetting = GetUriPrefix(currentUserId_, key);
std::string specialUri = SETTING_URI_PROXY_USER + userSetting + "&key=" + key;
Uri uri(specialUri);
return uri;
}
bool SettingProvider::IsNeedDataMigrationCopy()
{
bool isNeedMigrationCopy = false;
do {
if (!(IsValidKeyGlobal(SETTING_POWER_WAKEUP_PICKUP_KEY) && !IsValidKey(SETTING_POWER_WAKEUP_PICKUP_KEY))) {
break;
}
if (!(IsValidKeyGlobal(SETTING_POWER_WAKEUP_DOUBLE_KEY) && !IsValidKey(SETTING_POWER_WAKEUP_DOUBLE_KEY))) {
break;
}
if (!(IsValidKeyGlobal(SETTING_POWER_WAKEUP_SOURCES_KEY) && !IsValidKey(SETTING_POWER_WAKEUP_SOURCES_KEY))) {
break;
}
isNeedMigrationCopy = true;
} while (0);
POWER_HILOGI(COMP_UTILS, "IsNeedDataMigrationCopy:(%{public}d)", isNeedMigrationCopy);
return isNeedMigrationCopy;
}
void SettingProvider::DataMigrationCopy()
{
std::string value;
if (GetStringValueGlobal(SETTING_POWER_WAKEUP_DOUBLE_KEY, value) == ERR_OK) {
PutStringValue(SETTING_POWER_WAKEUP_DOUBLE_KEY, value);
}
if (GetStringValueGlobal(SETTING_POWER_WAKEUP_PICKUP_KEY, value) == ERR_OK) {
PutStringValue(SETTING_POWER_WAKEUP_PICKUP_KEY, value);
}
if (GetStringValueGlobal(SETTING_POWER_WAKEUP_SOURCES_KEY, value) == ERR_OK) {
PutStringValue(SETTING_POWER_WAKEUP_SOURCES_KEY, value);
}
}
ErrCode SettingProvider::GetStringValueGlobal(const std::string& key, std::string& value)
{
std::string callingIdentity = IPCSkeleton::ResetCallingIdentity();
auto helper = DataShare::DataShareHelper::Creator(remoteObj_, SETTING_URI_PROXY, SETTINGS_DATA_EXT_URI);
if (helper == nullptr) {
IPCSkeleton::SetCallingIdentity(callingIdentity);
return ERR_NO_INIT;
}
std::vector<std::string> columns = {SETTING_COLUMN_VALUE};
DataShare::DataSharePredicates predicates;
predicates.EqualTo(SETTING_COLUMN_KEYWORD, key);
Uri uri(SETTING_URI_PROXY + "&key=" + key);
auto resultSet = helper->Query(uri, predicates, columns);
ReleaseDataShareHelper(helper);
if (resultSet == nullptr) {
POWER_HILOGE(COMP_UTILS, "helper->Query return nullptr");
IPCSkeleton::SetCallingIdentity(callingIdentity);
return ERR_INVALID_OPERATION;
}
int32_t count;
resultSet->GetRowCount(count);
if (count == 0) {
POWER_HILOGW(COMP_UTILS, "not found value, key=%{public}s, count=%{public}d", key.c_str(), count);
IPCSkeleton::SetCallingIdentity(callingIdentity);
resultSet->Close();
return ERR_NAME_NOT_FOUND;
}
const int32_t INDEX = 0;
resultSet->GoToRow(INDEX);
int32_t ret = resultSet->GetString(INDEX, value);
if (ret != NativeRdb::E_OK) {
POWER_HILOGW(COMP_UTILS, "resultSet->GetString return not ok, ret=%{public}d", ret);
IPCSkeleton::SetCallingIdentity(callingIdentity);
resultSet->Close();
return ERR_INVALID_VALUE;
}
resultSet->Close();
IPCSkeleton::SetCallingIdentity(callingIdentity);
return ERR_OK;
}
bool SettingProvider::IsNeedMultiUser(const std::string& key)
{
auto it = needMultiUserStrMap.find(key);
return it != needMultiUserStrMap.end();
}
bool SettingProvider::AddMultiUserKey(const std::string& key, const std::string& value)
{
std::lock_guard<ffrt::mutex> lock(g_settingMutex);
if (IsNeedMultiUser(key)) {
return true;
}
if (needMultiUserStrMap.size() >= MULTI_USER_STR_VEC_SIZE_MAX) {
POWER_HILOGW(COMP_UTILS, "capacity limit reached: size=%{public}zu", needMultiUserStrMap.size());
return false;
}
needMultiUserStrMap.emplace(key, value);
return true;
}
void SettingProvider::UpdateCurrentUserId()
{
std::lock_guard<ffrt::mutex> lock(g_settingMutex);
std::vector<int> activedIds;
int ret = AccountSA::OsAccountManager::QueryActiveOsAccountIds(activedIds);
if (ret != 0) {
POWER_HILOGE(COMP_UTILS, "QueryActivedOsAccountIds failed, ret is %{public}d", ret);
return;
}
if (activedIds.empty()) {
POWER_HILOGE(COMP_UTILS, "QueryActivedOsAccountIds is empty");
return;
}
currentUserId_ = activedIds[0];
POWER_HILOGI(COMP_UTILS, "currentUserId_ is %{public}d", currentUserId_);
}
}
}