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
16 #include "preferences_enhance_impl.h"
17
18 #include <cinttypes>
19 #include <climits>
20 #include <cstdint>
21 #include <cstdlib>
22 #include <functional>
23 #include <sstream>
24 #include <thread>
25
26 #include "executor_pool.h"
27 #include "preferences_file_operation.h"
28 #include "log_print.h"
29 #include "preferences_observer_stub.h"
30 #include "preferences_value.h"
31 #include "preferences_value_parcel.h"
32
33 namespace OHOS {
34 namespace NativePreferences {
35
PreferencesEnhanceImpl(const Options & options)36 PreferencesEnhanceImpl::PreferencesEnhanceImpl(const Options &options): PreferencesBase(options)
37 {
38 }
39
~PreferencesEnhanceImpl()40 PreferencesEnhanceImpl::~PreferencesEnhanceImpl()
41 {
42 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
43 db_ = nullptr;
44 }
45
Init()46 int PreferencesEnhanceImpl::Init()
47 {
48 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
49 db_ = std::make_shared<PreferencesDb>();
50 int errCode = db_->Init(options_.filePath, options_.bundleName);
51 if (errCode != E_OK) {
52 db_ = nullptr;
53 }
54 return errCode;
55 }
56
Get(const std::string & key,const PreferencesValue & defValue)57 PreferencesValue PreferencesEnhanceImpl::Get(const std::string &key, const PreferencesValue &defValue)
58 {
59 if (CheckKey(key) != E_OK) {
60 return defValue;
61 }
62 // write lock here, get not support concurrence
63 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
64 if (db_ == nullptr) {
65 LOG_ERROR("PreferencesEnhanceImpl:Get failed, db has been closed.");
66 return defValue;
67 }
68
69 std::vector<uint8_t> oriKey(key.begin(), key.end());
70 std::vector<uint8_t> oriValue;
71 int errCode = db_->Get(oriKey, oriValue);
72 if (errCode != E_OK) {
73 LOG_ERROR("get key failed, errCode=%{public}d", errCode);
74 return defValue;
75 }
76 auto item = PreferencesValueParcel::UnmarshallingPreferenceValue(oriValue);
77 if (item.first != E_OK) {
78 LOG_ERROR("get key failed, errCode=%{public}d", errCode);
79 return defValue;
80 }
81 return item.second;
82 }
83
HasKey(const std::string & key)84 bool PreferencesEnhanceImpl::HasKey(const std::string &key)
85 {
86 if (CheckKey(key) != E_OK) {
87 return false;
88 }
89 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
90 if (db_ == nullptr) {
91 LOG_ERROR("PreferencesEnhanceImpl:HasKey failed, db has been closed.");
92 return false;
93 }
94
95 std::vector<uint8_t> oriKey(key.begin(), key.end());
96 std::vector<uint8_t> oriValue;
97 int errCode = db_->Get(oriKey, oriValue);
98 if (errCode != E_OK) {
99 LOG_ERROR("get key failed, errCode=%{public}d", errCode);
100 return false;
101 }
102 return true;
103 }
104
Put(const std::string & key,const PreferencesValue & value)105 int PreferencesEnhanceImpl::Put(const std::string &key, const PreferencesValue &value)
106 {
107 int errCode = CheckKey(key);
108 if (errCode != E_OK) {
109 return errCode;
110 }
111 errCode = CheckValue(value);
112 if (errCode != E_OK) {
113 return errCode;
114 }
115 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
116 if (db_ == nullptr) {
117 LOG_ERROR("PreferencesEnhanceImpl:Put failed, db has been closed.");
118 return E_ERROR;
119 }
120
121 std::vector<uint8_t> oriValue;
122 uint32_t oriValueLen = PreferencesValueParcel::CalSize(value);
123 oriValue.resize(oriValueLen);
124 errCode = PreferencesValueParcel::MarshallingPreferenceValue(value, oriValue);
125 if (errCode != E_OK) {
126 LOG_ERROR("marshalling value failed, errCode=%{public}d", errCode);
127 return errCode;
128 }
129 std::vector<uint8_t> oriKey(key.begin(), key.end());
130 errCode = db_->Put(oriKey, oriValue);
131 if (errCode != E_OK) {
132 LOG_ERROR("put data failed, errCode=%{public}d", errCode);
133 return errCode;
134 }
135
136 ExecutorPool::Task task = [pref = shared_from_this(), key, value] {
137 PreferencesEnhanceImpl::NotifyPreferencesObserver(pref, key, value);
138 };
139 executorPool_.Execute(std::move(task));
140 return E_OK;
141 }
142
Delete(const std::string & key)143 int PreferencesEnhanceImpl::Delete(const std::string &key)
144 {
145 int errCode = CheckKey(key);
146 if (errCode != E_OK) {
147 return errCode;
148 }
149 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
150 if (db_ == nullptr) {
151 LOG_ERROR("PreferencesEnhanceImpl:Delete failed, db has been closed.");
152 return E_ERROR;
153 }
154
155 std::vector<uint8_t> oriKey(key.begin(), key.end());
156 errCode = db_->Delete(oriKey);
157 if (errCode != E_OK) {
158 LOG_ERROR("delete data failed, errCode=%{public}d", errCode);
159 return errCode;
160 }
161
162 PreferencesValue value;
163 ExecutorPool::Task task = [pref = shared_from_this(), key, value] {
164 PreferencesEnhanceImpl::NotifyPreferencesObserver(pref, key, value);
165 };
166 executorPool_.Execute(std::move(task));
167 return E_OK;
168 }
169
GetAllInner()170 std::pair<int, std::map<std::string, PreferencesValue>> PreferencesEnhanceImpl::GetAllInner()
171 {
172 std::map<std::string, PreferencesValue> map;
173 if (db_ == nullptr) {
174 LOG_ERROR("PreferencesEnhanceImpl:GetAll failed, db has been closed.");
175 return std::make_pair(E_ALREADY_CLOSED, map);
176 }
177
178 std::map<std::string, PreferencesValue> result;
179 std::list<std::pair<std::vector<uint8_t>, std::vector<uint8_t>>> data;
180 int errCode = db_->GetAll(data);
181 if (errCode != E_OK) {
182 LOG_ERROR("get all failed, errCode=%{public}d", errCode);
183 return std::make_pair(errCode, map);
184 }
185 for (auto it = data.begin(); it != data.end(); it++) {
186 std::string key(it->first.begin(), it->first.end());
187 auto item = PreferencesValueParcel::UnmarshallingPreferenceValue(it->second);
188 result.insert({key, item.second});
189 if (item.first != E_OK) {
190 LOG_ERROR("get key failed, errCode=%{public}d", errCode);
191 return std::make_pair(item.first, map);
192 }
193 }
194 return std::make_pair(E_OK, result);
195 }
196
GetAll()197 std::map<std::string, PreferencesValue> PreferencesEnhanceImpl::GetAll()
198 {
199 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
200 std::pair<int, std::map<std::string, PreferencesValue>> res = GetAllInner();
201 return res.second;
202 }
203
NotifyPreferencesObserver(std::shared_ptr<PreferencesEnhanceImpl> pref,const std::string & key,const PreferencesValue & value)204 void PreferencesEnhanceImpl::NotifyPreferencesObserver(std::shared_ptr<PreferencesEnhanceImpl> pref,
205 const std::string &key, const PreferencesValue &value)
206 {
207 std::shared_lock<std::shared_mutex> readLock(pref->mapSharedMutex_);
208 LOG_DEBUG("notify observer size:%{public}zu", pref->dataObserversMap_.size());
209 for (const auto &[weakPrt, keys] : pref->dataObserversMap_) {
210 auto itKey = keys.find(key);
211 if (itKey == keys.end()) {
212 continue;
213 }
214 std::map<std::string, PreferencesValue> records = {{key, value}};
215 if (std::shared_ptr<PreferencesObserver> sharedPtr = weakPrt.lock()) {
216 LOG_DEBUG("dataChange observer call, resultSize:%{public}zu", records.size());
217 sharedPtr->OnChange(records);
218 }
219 }
220 auto dataObsMgrClient = DataObsMgrClient::GetInstance();
221 for (auto it = pref->localObservers_.begin(); it != pref->localObservers_.end(); ++it) {
222 std::weak_ptr<PreferencesObserver> weakPreferencesObserver = *it;
223 if (std::shared_ptr<PreferencesObserver> sharedPreferencesObserver = weakPreferencesObserver.lock()) {
224 sharedPreferencesObserver->OnChange(key);
225 }
226 }
227 if (dataObsMgrClient != nullptr) {
228 dataObsMgrClient->NotifyChange(pref->MakeUri(key));
229 }
230 }
231
NotifyPreferencesObserverBatchKeys(std::shared_ptr<PreferencesEnhanceImpl> pref,const std::map<std::string,PreferencesValue> & data)232 void PreferencesEnhanceImpl::NotifyPreferencesObserverBatchKeys(std::shared_ptr<PreferencesEnhanceImpl> pref,
233 const std::map<std::string, PreferencesValue> &data)
234 {
235 for (const auto &[key, value] : data) {
236 NotifyPreferencesObserver(pref, key, value);
237 }
238 }
239
Clear()240 int PreferencesEnhanceImpl::Clear()
241 {
242 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
243 LOG_INFO("Clear called, file: %{public}s", ExtractFileName(options_.filePath).c_str());
244 if (db_ == nullptr) {
245 LOG_ERROR("PreferencesEnhanceImpl:Clear failed, db has been closed.");
246 return E_ERROR;
247 }
248
249 std::pair<int, std::map<std::string, PreferencesValue>> res = GetAllInner();
250 if (res.first != E_OK) {
251 LOG_ERROR("get all failed when clear, errCode=%{public}d", res.first);
252 return res.first;
253 }
254
255 std::map<std::string, PreferencesValue> allData = res.second;
256
257 int errCode = db_->DropCollection();
258 if (errCode != E_OK) {
259 LOG_ERROR("drop collection failed when clear, errCode=%{public}d", errCode);
260 return errCode;
261 }
262
263 if (!allData.empty()) {
264 ExecutorPool::Task task = [pref = shared_from_this(), allData] {
265 PreferencesEnhanceImpl::NotifyPreferencesObserverBatchKeys(pref, allData);
266 };
267 executorPool_.Execute(std::move(task));
268 }
269
270 errCode = db_->CreateCollection();
271 if (errCode != E_OK) {
272 LOG_ERROR("create collection failed when clear, errCode=%{public}d", errCode);
273 }
274 return errCode;
275 }
276
CloseDb()277 int PreferencesEnhanceImpl::CloseDb()
278 {
279 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
280 if (db_ == nullptr) {
281 LOG_WARN("PreferencesEnhanceImpl:CloseDb failed, db has been closed, no need to close again.");
282 return E_OK;
283 }
284 int errCode = db_->CloseDb();
285 if (errCode != E_OK) {
286 LOG_ERROR("PreferencesEnhanceImpl:CloseDb failed.");
287 return errCode;
288 }
289 db_ = nullptr;
290 return E_OK;
291 }
292
GetValue(const std::string & key,const PreferencesValue & defValue)293 std::pair<int, PreferencesValue> PreferencesEnhanceImpl::GetValue(const std::string &key,
294 const PreferencesValue &defValue)
295 {
296 int errCode = CheckKey(key);
297 if (errCode != E_OK) {
298 return std::make_pair(errCode, defValue);
299 }
300 // write lock here, get not support concurrence
301 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
302 if (db_ == nullptr) {
303 LOG_ERROR("PreferencesEnhanceImpl:Get failed, db has been closed.");
304 return std::make_pair(E_ALREADY_CLOSED, defValue);
305 }
306
307 std::vector<uint8_t> oriKey(key.begin(), key.end());
308 std::vector<uint8_t> oriValue;
309 errCode = db_->Get(oriKey, oriValue);
310 if (errCode != E_OK) {
311 LOG_ERROR("get key failed, errCode=%{public}d", errCode);
312 return std::make_pair(errCode, defValue);
313 }
314 auto item = PreferencesValueParcel::UnmarshallingPreferenceValue(oriValue);
315 if (item.first != E_OK) {
316 LOG_ERROR("get key failed, errCode=%{public}d", item.first);
317 return std::make_pair(item.first, defValue);
318 }
319
320 return std::make_pair(E_OK, item.second);
321 }
322
GetAllData()323 std::pair<int, std::map<std::string, PreferencesValue>> PreferencesEnhanceImpl::GetAllData()
324 {
325 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
326 return GetAllInner();
327 }
328 } // End of namespace NativePreferences
329 } // End of namespace OHOS
330