1/*
2 * Copyright (c) 2023 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
16#include "setting_datashare.h"
17
18#include <thread>
19
20#include "datashare_predicates.h"
21#include "datashare_result_set.h"
22#include "datashare_values_bucket.h"
23#include "ipc_skeleton.h"
24#include "iservice_registry.h"
25#include "mmi_log.h"
26#include "rdb_errno.h"
27#include "result_set.h"
28#include "system_ability_definition.h"
29#include "uri.h"
30
31#undef MMI_LOG_DOMAIN
32#define MMI_LOG_DOMAIN MMI_LOG_HANDLER
33#undef MMI_LOG_TAG
34#define MMI_LOG_TAG "setting_DataShare"
35
36namespace OHOS {
37namespace MMI {
38std::shared_ptr<SettingDataShare> SettingDataShare::instance_ = nullptr;
39std::mutex SettingDataShare::mutex_;
40sptr<IRemoteObject> SettingDataShare::remoteObj_;
41namespace {
42const std::string SETTING_COLUMN_KEYWORD { "KEYWORD" };
43const std::string SETTING_COLUMN_VALUE { "VALUE" };
44const std::string SETTING_URI_PROXY { "datashare:///com.ohos.settingsdata/entry/settingsdata/SETTINGSDATA?Proxy=true" };
45const std::string SETTING_URI_USER_PROXY {
46    "datashare:///com.ohos.settingsdata/entry/settingsdata/USER_SETTINGSDATA_SECURE_100?Proxy=true" };
47const std::string SETTINGS_DATA_EXT_URI { "datashare:///com.ohos.settingsdata.DataAbility" };
48constexpr int32_t DECIMAL_BASE { 10 };
49constexpr const int32_t E_OK{ 0 };
50constexpr const int32_t E_DATA_SHARE_NOT_READY { 1055 };
51} // namespace
52
53SettingDataShare::~SettingDataShare() {}
54
55SettingDataShare& SettingDataShare::GetInstance(int32_t systemAbilityId)
56{
57    if (instance_ == nullptr) {
58        std::lock_guard<std::mutex> lock(mutex_);
59        if (instance_ == nullptr) {
60            instance_ = std::make_shared<SettingDataShare>();
61        }
62    }
63    return *instance_;
64}
65
66ErrCode SettingDataShare::GetIntValue(const std::string& key, int32_t& value, const std::string &strUri)
67{
68    int64_t valueLong;
69    ErrCode ret = GetLongValue(key, valueLong, strUri);
70    if (ret != ERR_OK) {
71        MMI_HILOGE("Get int value fail");
72        return ret;
73    }
74    value = static_cast<int32_t>(valueLong);
75    return ERR_OK;
76}
77
78ErrCode SettingDataShare::GetLongValue(const std::string& key, int64_t& value, const std::string &strUri)
79{
80    std::string valueStr;
81    ErrCode ret = GetStringValue(key, valueStr, strUri);
82    if (ret == ERR_NAME_NOT_FOUND) {
83        MMI_HILOGW("Not found this property");
84        return ERR_OK;
85    }
86    if (ret != ERR_OK) {
87        MMI_HILOGE("Get long value fail, ret:%{public}d", ret);
88        return ret;
89    }
90    value = static_cast<int64_t>(strtoll(valueStr.c_str(), nullptr, DECIMAL_BASE));
91    return ERR_OK;
92}
93
94ErrCode SettingDataShare::GetBoolValue(const std::string& key, bool& value, const std::string &strUri)
95{
96    std::string valueStr;
97    ErrCode ret = GetStringValue(key, valueStr, strUri);
98    if (ret == ERR_NAME_NOT_FOUND) {
99        MMI_HILOGW("Not found this property");
100        return ERR_OK;
101    }
102    if (ret != ERR_OK) {
103        MMI_HILOGE("Get bool value fail, ret:%{public}d", ret);
104        return ret;
105    }
106    value = ((valueStr == "true") || (valueStr == "1"));
107    return ERR_OK;
108}
109
110ErrCode SettingDataShare::PutIntValue(
111    const std::string& key, int32_t value, bool needNotify, const std::string &strUri)
112{
113    return PutStringValue(key, std::to_string(value), needNotify, strUri);
114}
115
116ErrCode SettingDataShare::PutLongValue(
117    const std::string& key, int64_t value, bool needNotify, const std::string &strUri)
118{
119    return PutStringValue(key, std::to_string(value), needNotify, strUri);
120}
121
122ErrCode SettingDataShare::PutBoolValue(
123    const std::string& key, bool value, bool needNotify, const std::string &strUri)
124{
125    std::string valueStr = value ? "true" : "false";
126    return PutStringValue(key, valueStr, needNotify, strUri);
127}
128
129bool SettingDataShare::IsValidKey(const std::string& key, const std::string &strUri)
130{
131    std::string value;
132    ErrCode ret = GetStringValue(key, value, strUri);
133    return (ret != ERR_NAME_NOT_FOUND) && (!value.empty());
134}
135
136sptr<SettingObserver> SettingDataShare::CreateObserver(const std::string& key, SettingObserver::UpdateFunc& func)
137{
138    sptr<SettingObserver> observer = new (std::nothrow) SettingObserver();
139    CHKPP(observer);
140    observer->SetKey(key);
141    observer->SetUpdateFunc(func);
142    return observer;
143}
144
145void SettingDataShare::ExecRegisterCb(const sptr<SettingObserver>& observer)
146{
147    CHKPV(observer);
148    observer->OnChange();
149}
150
151ErrCode SettingDataShare::RegisterObserver(const sptr<SettingObserver>& observer, const std::string &strUri)
152{
153    if (!isDataShareReady_) {
154        MMI_HILOGI("Data share not ready!");
155        return RET_ERR;
156    }
157    CHKPR(observer, RET_ERR);
158    std::string callingIdentity = IPCSkeleton::ResetCallingIdentity();
159    auto uri = AssembleUri(observer->GetKey(), strUri);
160    auto helper = CreateDataShareHelper(strUri);
161    if (helper == nullptr) {
162        IPCSkeleton::SetCallingIdentity(callingIdentity);
163        return ERR_NO_INIT;
164    }
165    helper->RegisterObserver(uri, observer);
166    helper->NotifyChange(uri);
167    std::thread execCb([this, observer] { this->ExecRegisterCb(observer); });
168    execCb.detach();
169    ReleaseDataShareHelper(helper);
170    IPCSkeleton::SetCallingIdentity(callingIdentity);
171    return ERR_OK;
172}
173
174ErrCode SettingDataShare::UnregisterObserver(const sptr<SettingObserver>& observer, const std::string &strUri)
175{
176    if (!isDataShareReady_) {
177        MMI_HILOGI("Data share not ready!");
178        return RET_ERR;
179    }
180    CHKPR(observer, RET_ERR);
181    std::string callingIdentity = IPCSkeleton::ResetCallingIdentity();
182    auto uri = AssembleUri(observer->GetKey(), strUri);
183    auto helper = CreateDataShareHelper(strUri);
184    if (helper == nullptr) {
185        IPCSkeleton::SetCallingIdentity(callingIdentity);
186        return ERR_NO_INIT;
187    }
188    helper->UnregisterObserver(uri, observer);
189    ReleaseDataShareHelper(helper);
190    IPCSkeleton::SetCallingIdentity(callingIdentity);
191    return ERR_OK;
192}
193
194ErrCode SettingDataShare::GetStringValue(const std::string& key, std::string& value, const std::string &strUri)
195{
196    if (!isDataShareReady_) {
197        MMI_HILOGI("Data share not ready!");
198        return RET_ERR;
199    }
200    std::string callingIdentity = IPCSkeleton::ResetCallingIdentity();
201    auto helper = CreateDataShareHelper(strUri);
202    if (helper == nullptr) {
203        IPCSkeleton::SetCallingIdentity(callingIdentity);
204        return ERR_NO_INIT;
205    }
206    std::vector<std::string> columns = {SETTING_COLUMN_VALUE};
207    DataShare::DataSharePredicates predicates;
208    predicates.EqualTo(SETTING_COLUMN_KEYWORD, key);
209    Uri uri(AssembleUri(key, strUri));
210    auto resultSet = helper->Query(uri, predicates, columns);
211    ReleaseDataShareHelper(helper);
212    if (resultSet == nullptr) {
213        IPCSkeleton::SetCallingIdentity(callingIdentity);
214        return ERR_INVALID_OPERATION;
215    }
216    int32_t count = 0;
217    resultSet->GetRowCount(count);
218    if (count == 0) {
219        IPCSkeleton::SetCallingIdentity(callingIdentity);
220        return ERR_NAME_NOT_FOUND;
221    }
222    const int32_t tmpRow = 0;
223    resultSet->GoToRow(tmpRow);
224    int32_t ret = resultSet->GetString(tmpRow, value);
225    if (ret != RET_OK) {
226        IPCSkeleton::SetCallingIdentity(callingIdentity);
227        return ERR_INVALID_VALUE;
228    }
229    resultSet->Close();
230    IPCSkeleton::SetCallingIdentity(callingIdentity);
231    return ERR_OK;
232}
233
234ErrCode SettingDataShare::PutStringValue(
235    const std::string& key, const std::string& value, bool needNotify, const std::string &strUri)
236{
237    if (!isDataShareReady_) {
238        MMI_HILOGI("Data share not ready!");
239        return RET_ERR;
240    }
241    std::string callingIdentity = IPCSkeleton::ResetCallingIdentity();
242    auto helper = CreateDataShareHelper(strUri);
243    if (helper == nullptr) {
244        IPCSkeleton::SetCallingIdentity(callingIdentity);
245        return ERR_NO_INIT;
246    }
247    DataShare::DataShareValueObject keyObj(key);
248    DataShare::DataShareValueObject valueObj(value);
249    DataShare::DataShareValuesBucket bucket;
250    bucket.Put(SETTING_COLUMN_KEYWORD, keyObj);
251    bucket.Put(SETTING_COLUMN_VALUE, valueObj);
252    DataShare::DataSharePredicates predicates;
253    predicates.EqualTo(SETTING_COLUMN_KEYWORD, key);
254    Uri uri(AssembleUri(key, strUri));
255    if (helper->Update(uri, predicates, bucket) <= 0) {
256        helper->Insert(uri, bucket);
257    }
258    if (needNotify) {
259        helper->NotifyChange(AssembleUri(key, strUri));
260    }
261    ReleaseDataShareHelper(helper);
262    IPCSkeleton::SetCallingIdentity(callingIdentity);
263    return ERR_OK;
264}
265
266std::shared_ptr<DataShare::DataShareHelper> SettingDataShare::CreateDataShareHelper(const std::string &strUri)
267{
268    if (remoteObj_ == nullptr) {
269        std::lock_guard<std::mutex> lock(mutex_);
270        if (remoteObj_ == nullptr) {
271            auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
272            CHKPP(sam);
273            remoteObj_ = sam->CheckSystemAbility(MULTIMODAL_INPUT_SERVICE_ID);
274        }
275    }
276    std::pair<int, std::shared_ptr<DataShare::DataShareHelper>> ret;
277    if (strUri.empty()) {
278        ret = DataShare::DataShareHelper::Create(remoteObj_, SETTING_URI_PROXY, SETTINGS_DATA_EXT_URI.c_str());
279    } else {
280        ret = DataShare::DataShareHelper::Create(remoteObj_, strUri, "");
281    }
282    return ret.second;
283}
284
285bool SettingDataShare::ReleaseDataShareHelper(std::shared_ptr<DataShare::DataShareHelper>& helper)
286{
287    if (!helper->Release()) {
288        return false;
289    }
290    return true;
291}
292
293Uri SettingDataShare::AssembleUri(const std::string& key, const std::string &strUri)
294{
295    if (strUri.empty()) {
296        if (key == "close_fingerprint_nav_event_key" || key == "close_fingerprint_event_key") {
297            return Uri(SETTING_URI_USER_PROXY + "&key=" + key);
298        }
299        return Uri(SETTING_URI_PROXY + "&key=" + key);
300    } else {
301        return Uri(strUri + "&key=" + key);
302    }
303}
304
305bool SettingDataShare::CheckIfSettingsDataReady()
306{
307    if (isDataShareReady_) {
308        return true;
309    }
310    if (remoteObj_ == nullptr) {
311        std::lock_guard<std::mutex> lock(mutex_);
312        if (remoteObj_ == nullptr) {
313            auto sam = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
314            CHKPF(sam);
315            remoteObj_ = sam->CheckSystemAbility(MULTIMODAL_INPUT_SERVICE_ID);
316        }
317    }
318    CHKPF(remoteObj_);
319    std::pair<int, std::shared_ptr<DataShare::DataShareHelper>> ret =
320            DataShare::DataShareHelper::Create(remoteObj_, SETTING_URI_PROXY, SETTINGS_DATA_EXT_URI);
321    MMI_HILOGD("Create data_share helper, ret=%{public}d", ret.first);
322    if (ret.first == E_OK) {
323        MMI_HILOGD("Create data_share helper success");
324        auto helper = ret.second;
325        if (helper != nullptr) {
326            bool releaseRet = helper->Release();
327            MMI_HILOGD("Release data_share helper, releaseRet=%{public}d", releaseRet);
328        }
329        isDataShareReady_ = true;
330        return true;
331    } else if (ret.first == E_DATA_SHARE_NOT_READY) {
332        MMI_HILOGE("Create data_share helper failed");
333        isDataShareReady_ = false;
334        return false;
335    }
336    MMI_HILOGE("data_share unknown");
337    return true;
338}
339}
340} // namespace OHOS