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_utils.h"
31 #include "preferences_value.h"
32 #include "preferences_value_parcel.h"
33
34 namespace OHOS {
35 namespace NativePreferences {
36
37 constexpr int32_t CACHED_THRESHOLDS = 512 * 1024; // we will cached big obj(len >= 512k)
38
PreferencesEnhanceImpl(const Options & options)39 PreferencesEnhanceImpl::PreferencesEnhanceImpl(const Options &options): PreferencesBase(options)
40 {
41 }
42
~PreferencesEnhanceImpl()43 PreferencesEnhanceImpl::~PreferencesEnhanceImpl()
44 {
45 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
46 db_ = nullptr;
47 }
48
Init()49 int PreferencesEnhanceImpl::Init()
50 {
51 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
52 PreferenceDbAdapter::ApiInit();
53 if (!PreferenceDbAdapter::IsEnhandceDbEnable()) {
54 LOG_ERROR("enhance api load failed.");
55 return E_ERROR;
56 }
57 db_ = std::make_shared<PreferencesDb>();
58 cachedDataVersion_ = 0;
59 int errCode = db_->Init(options_.filePath, options_.bundleName);
60 if (errCode != E_OK) {
61 db_ = nullptr;
62 }
63 return errCode;
64 }
65
Get(const std::string & key,const PreferencesValue & defValue)66 PreferencesValue PreferencesEnhanceImpl::Get(const std::string &key, const PreferencesValue &defValue)
67 {
68 if (CheckKey(key) != E_OK) {
69 return defValue;
70 }
71 // write lock here, get not support concurrence
72 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
73 if (db_ == nullptr) {
74 LOG_ERROR("PreferencesEnhanceImpl:Get failed, db has been closed.");
75 return defValue;
76 }
77
78 int64_t kernelDataVersion = 0;
79 if (db_->GetKernelDataVersion(kernelDataVersion) != E_OK) {
80 LOG_ERROR("PreferencesEnhanceImpl:Get failed, get kernel data version failed.");
81 return defValue;
82 }
83 if (kernelDataVersion == cachedDataVersion_) {
84 auto it = largeCachedData_.find(key);
85 if (it != largeCachedData_.end()) {
86 return it->second;
87 }
88 }
89
90 std::vector<uint8_t> oriKey(key.begin(), key.end());
91 std::vector<uint8_t> oriValue;
92 int errCode = db_->Get(oriKey, oriValue);
93 if (errCode == E_NO_DATA) {
94 return defValue;
95 }
96 if (errCode != E_OK) {
97 LOG_ERROR("get key failed, errCode=%{public}d", errCode);
98 return defValue;
99 }
100 auto item = PreferencesValueParcel::UnmarshallingPreferenceValue(oriValue);
101 if (item.first != E_OK) {
102 LOG_ERROR("get key failed, errCode=%{public}d", item.first);
103 return defValue;
104 }
105 if (oriValue.size() >= CACHED_THRESHOLDS) {
106 largeCachedData_.insert_or_assign(key, item.second);
107 cachedDataVersion_ = kernelDataVersion;
108 }
109 return item.second;
110 }
111
HasKey(const std::string & key)112 bool PreferencesEnhanceImpl::HasKey(const std::string &key)
113 {
114 if (CheckKey(key) != E_OK) {
115 return false;
116 }
117 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
118 if (db_ == nullptr) {
119 LOG_ERROR("PreferencesEnhanceImpl:HasKey failed, db has been closed.");
120 return false;
121 }
122
123 int64_t kernelDataVersion = 0;
124 if (db_->GetKernelDataVersion(kernelDataVersion) != E_OK) {
125 LOG_ERROR("PreferencesEnhanceImpl:HasKey failed, get kernel data version failed.");
126 return false;
127 }
128 if (kernelDataVersion == cachedDataVersion_) {
129 auto it = largeCachedData_.find(key);
130 if (it != largeCachedData_.end()) {
131 return true;
132 }
133 }
134
135 std::vector<uint8_t> oriKey(key.begin(), key.end());
136 std::vector<uint8_t> oriValue;
137 int errCode = db_->Get(oriKey, oriValue);
138 if (errCode == E_NO_DATA) {
139 return false;
140 }
141 if (errCode != E_OK) {
142 LOG_ERROR("get key failed, errCode=%{public}d", errCode);
143 return false;
144 }
145 if (oriValue.size() >= CACHED_THRESHOLDS) {
146 auto item = PreferencesValueParcel::UnmarshallingPreferenceValue(oriValue);
147 if (item.first != E_OK) {
148 LOG_WARN("haskey unmarshall failed, haskey return true, errCode=%{public}d", item.first);
149 return true;
150 }
151 largeCachedData_.insert_or_assign(key, item.second);
152 cachedDataVersion_ = kernelDataVersion;
153 }
154 return true;
155 }
156
Put(const std::string & key,const PreferencesValue & value)157 int PreferencesEnhanceImpl::Put(const std::string &key, const PreferencesValue &value)
158 {
159 int errCode = CheckKey(key);
160 if (errCode != E_OK) {
161 return errCode;
162 }
163 errCode = CheckValue(value);
164 if (errCode != E_OK) {
165 return errCode;
166 }
167 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
168 if (db_ == nullptr) {
169 LOG_ERROR("PreferencesEnhanceImpl:Put failed, db has been closed.");
170 return E_ERROR;
171 }
172
173 std::vector<uint8_t> oriValue;
174 uint32_t oriValueLen = PreferencesValueParcel::CalSize(value);
175 oriValue.resize(oriValueLen);
176 errCode = PreferencesValueParcel::MarshallingPreferenceValue(value, oriValue);
177 if (errCode != E_OK) {
178 LOG_ERROR("marshalling value failed, errCode=%{public}d", errCode);
179 return errCode;
180 }
181 std::vector<uint8_t> oriKey(key.begin(), key.end());
182 errCode = db_->Put(oriKey, oriValue);
183 if (errCode != E_OK) {
184 LOG_ERROR("put data failed, errCode=%{public}d", errCode);
185 return errCode;
186 }
187
188 // update cached and version
189 if (oriValueLen >= CACHED_THRESHOLDS) {
190 largeCachedData_.insert_or_assign(key, value);
191 cachedDataVersion_ = cachedDataVersion_ == INT64_MAX ? 0 : cachedDataVersion_ + 1;
192 } else {
193 auto pos = largeCachedData_.find(key);
194 if (pos != largeCachedData_.end()) {
195 largeCachedData_.erase(pos);
196 }
197 }
198
199 ExecutorPool::Task task = [pref = shared_from_this(), key, value] {
200 PreferencesEnhanceImpl::NotifyPreferencesObserver(pref, key, value);
201 };
202 executorPool_.Execute(std::move(task));
203 return E_OK;
204 }
205
Delete(const std::string & key)206 int PreferencesEnhanceImpl::Delete(const std::string &key)
207 {
208 int errCode = CheckKey(key);
209 if (errCode != E_OK) {
210 return errCode;
211 }
212 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
213 if (db_ == nullptr) {
214 LOG_ERROR("PreferencesEnhanceImpl:Delete failed, db has been closed.");
215 return E_ERROR;
216 }
217
218 std::vector<uint8_t> oriKey(key.begin(), key.end());
219 errCode = db_->Delete(oriKey);
220 if (errCode != E_OK) {
221 LOG_ERROR("delete data failed, errCode=%{public}d", errCode);
222 return errCode;
223 }
224
225 // update cached and version
226 auto it = largeCachedData_.find(key);
227 if (it != largeCachedData_.end()) {
228 largeCachedData_.erase(it);
229 cachedDataVersion_ = cachedDataVersion_ == INT64_MAX ? 0 : cachedDataVersion_ + 1;
230 }
231
232 PreferencesValue value;
233 ExecutorPool::Task task = [pref = shared_from_this(), key, value] {
234 PreferencesEnhanceImpl::NotifyPreferencesObserver(pref, key, value);
235 };
236 executorPool_.Execute(std::move(task));
237 return E_OK;
238 }
239
GetAllInner()240 std::pair<int, std::unordered_map<std::string, PreferencesValue>> PreferencesEnhanceImpl::GetAllInner()
241 {
242 std::unordered_map<std::string, PreferencesValue> map;
243 if (db_ == nullptr) {
244 LOG_ERROR("PreferencesEnhanceImpl:GetAll failed, db has been closed.");
245 return std::make_pair(E_ALREADY_CLOSED, map);
246 }
247
248 int64_t kernelDataVersion = 0;
249 if (db_->GetKernelDataVersion(kernelDataVersion) != E_OK) {
250 LOG_ERROR("PreferencesEnhanceImpl:GetAll failed, get kernel data version failed.");
251 return std::make_pair(E_ERROR, map);
252 }
253
254 std::unordered_map<std::string, PreferencesValue> result;
255 std::list<std::pair<std::vector<uint8_t>, std::vector<uint8_t>>> data;
256 int errCode = db_->GetAll(data);
257 if (errCode != E_OK) {
258 LOG_ERROR("get all failed, errCode=%{public}d", errCode);
259 return std::make_pair(errCode, map);
260 }
261 for (auto it = data.begin(); it != data.end(); it++) {
262 std::string key(it->first.begin(), it->first.end());
263 auto item = PreferencesValueParcel::UnmarshallingPreferenceValue(it->second);
264 result.insert({key, item.second});
265 if (item.first != E_OK) {
266 LOG_ERROR("get key failed, errCode=%{public}d", errCode);
267 return std::make_pair(item.first, map);
268 }
269 if (it->second.size() >= CACHED_THRESHOLDS) {
270 largeCachedData_.insert_or_assign(key, item.second);
271 }
272 }
273 cachedDataVersion_ = kernelDataVersion;
274 return std::make_pair(E_OK, result);
275 }
276
GetAll()277 std::map<std::string, PreferencesValue> PreferencesEnhanceImpl::GetAll()
278 {
279 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
280 std::pair<int, std::unordered_map<std::string, PreferencesValue>> res = GetAllInner();
281 std::map<std::string, PreferencesValue> allDatas;
282 for (auto &it : res.second) {
283 allDatas.insert_or_assign(it.first, it.second);
284 }
285 return allDatas;
286 }
287
NotifyPreferencesObserver(std::shared_ptr<PreferencesEnhanceImpl> pref,const std::string & key,const PreferencesValue & value)288 void PreferencesEnhanceImpl::NotifyPreferencesObserver(std::shared_ptr<PreferencesEnhanceImpl> pref,
289 const std::string &key, const PreferencesValue &value)
290 {
291 std::shared_lock<std::shared_mutex> readLock(pref->obseverMetux_);
292 LOG_DEBUG("notify observer size:%{public}zu", pref->dataObserversMap_.size());
293 for (const auto &[weakPrt, keys] : pref->dataObserversMap_) {
294 auto itKey = keys.find(key);
295 if (itKey == keys.end()) {
296 continue;
297 }
298 std::map<std::string, PreferencesValue> records = {{key, value}};
299 if (std::shared_ptr<PreferencesObserver> sharedPtr = weakPrt.lock()) {
300 LOG_DEBUG("dataChange observer call, resultSize:%{public}zu", records.size());
301 sharedPtr->OnChange(records);
302 }
303 }
304 auto dataObsMgrClient = DataObsMgrClient::GetInstance();
305 for (auto it = pref->localObservers_.begin(); it != pref->localObservers_.end(); ++it) {
306 std::weak_ptr<PreferencesObserver> weakPreferencesObserver = *it;
307 if (std::shared_ptr<PreferencesObserver> sharedPreferencesObserver = weakPreferencesObserver.lock()) {
308 sharedPreferencesObserver->OnChange(key);
309 }
310 }
311 if (dataObsMgrClient != nullptr) {
312 dataObsMgrClient->NotifyChange(pref->MakeUri(key));
313 }
314 }
315
NotifyPreferencesObserverBatchKeys(std::shared_ptr<PreferencesEnhanceImpl> pref,const std::unordered_map<std::string,PreferencesValue> & data)316 void PreferencesEnhanceImpl::NotifyPreferencesObserverBatchKeys(std::shared_ptr<PreferencesEnhanceImpl> pref,
317 const std::unordered_map<std::string, PreferencesValue> &data)
318 {
319 for (const auto &[key, value] : data) {
320 NotifyPreferencesObserver(pref, key, value);
321 }
322 }
323
Clear()324 int PreferencesEnhanceImpl::Clear()
325 {
326 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
327 LOG_INFO("Clear called, file: %{public}s", ExtractFileName(options_.filePath).c_str());
328 if (db_ == nullptr) {
329 LOG_ERROR("PreferencesEnhanceImpl:Clear failed, db has been closed.");
330 return E_ERROR;
331 }
332
333 std::pair<int, std::unordered_map<std::string, PreferencesValue>> res = GetAllInner();
334 if (res.first != E_OK) {
335 LOG_ERROR("get all failed when clear, errCode=%{public}d", res.first);
336 return res.first;
337 }
338
339 std::unordered_map<std::string, PreferencesValue> allData = res.second;
340
341 int errCode = db_->DropCollection();
342 if (errCode != E_OK) {
343 LOG_ERROR("drop collection failed when clear, errCode=%{public}d", errCode);
344 return errCode;
345 }
346
347 if (!allData.empty()) {
348 ExecutorPool::Task task = [pref = shared_from_this(), allData] {
349 PreferencesEnhanceImpl::NotifyPreferencesObserverBatchKeys(pref, allData);
350 };
351 executorPool_.Execute(std::move(task));
352 }
353
354 errCode = db_->CreateCollection();
355 if (errCode != E_OK) {
356 LOG_ERROR("create collection failed when clear, errCode=%{public}d", errCode);
357 return errCode;
358 }
359 largeCachedData_.clear();
360 cachedDataVersion_ = cachedDataVersion_ == INT64_MAX ? 0 : cachedDataVersion_ + 1;
361 return E_OK;
362 }
363
CloseDb()364 int PreferencesEnhanceImpl::CloseDb()
365 {
366 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
367 if (db_ == nullptr) {
368 LOG_WARN("PreferencesEnhanceImpl:CloseDb failed, db has been closed, no need to close again.");
369 return E_OK;
370 }
371 int errCode = db_->CloseDb();
372 if (errCode != E_OK) {
373 LOG_ERROR("PreferencesEnhanceImpl:CloseDb failed.");
374 return errCode;
375 }
376 largeCachedData_.clear();
377 db_ = nullptr;
378 return E_OK;
379 }
380
GetValue(const std::string & key,const PreferencesValue & defValue)381 std::pair<int, PreferencesValue> PreferencesEnhanceImpl::GetValue(const std::string &key,
382 const PreferencesValue &defValue)
383 {
384 int errCode = CheckKey(key);
385 if (errCode != E_OK) {
386 return std::make_pair(errCode, defValue);
387 }
388 // write lock here, get not support concurrence
389 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
390 if (db_ == nullptr) {
391 LOG_ERROR("PreferencesEnhanceImpl:Get failed, db has been closed.");
392 return std::make_pair(E_ALREADY_CLOSED, defValue);
393 }
394
395 int64_t kernelDataVersion = 0;
396 if (db_->GetKernelDataVersion(kernelDataVersion) != E_OK) {
397 LOG_ERROR("PreferencesEnhanceImpl:Get failed, get kernel data version failed.");
398 return std::make_pair(E_ERROR, defValue);
399 }
400 if (kernelDataVersion == cachedDataVersion_) {
401 auto it = largeCachedData_.find(key);
402 if (it != largeCachedData_.end()) {
403 return std::make_pair(E_OK, it->second);
404 }
405 }
406
407 std::vector<uint8_t> oriKey(key.begin(), key.end());
408 std::vector<uint8_t> oriValue;
409 errCode = db_->Get(oriKey, oriValue);
410 if (errCode == E_NO_DATA) {
411 return std::make_pair(errCode, defValue);
412 }
413 if (errCode != E_OK) {
414 LOG_ERROR("get key failed, errCode=%{public}d", errCode);
415 return std::make_pair(errCode, defValue);
416 }
417 auto item = PreferencesValueParcel::UnmarshallingPreferenceValue(oriValue);
418 if (item.first != E_OK) {
419 LOG_ERROR("get key failed, errCode=%{public}d", item.first);
420 return std::make_pair(item.first, defValue);
421 }
422 if (oriValue.size() >= CACHED_THRESHOLDS) {
423 largeCachedData_.insert_or_assign(key, item.second);
424 cachedDataVersion_ = kernelDataVersion;
425 }
426 return std::make_pair(E_OK, item.second);
427 }
428
GetAllData()429 std::pair<int, std::map<std::string, PreferencesValue>> PreferencesEnhanceImpl::GetAllData()
430 {
431 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
432 std::pair<int, std::unordered_map<std::string, PreferencesValue>> res = GetAllInner();
433 std::map<std::string, PreferencesValue> allDatas;
434 for (auto &it : res.second) {
435 allDatas.insert_or_assign(it.first, it.second);
436 }
437 return {res.first, allDatas};
438 }
439
GetAllDatas()440 std::unordered_map<std::string, PreferencesValue> PreferencesEnhanceImpl::GetAllDatas()
441 {
442 std::unique_lock<std::shared_mutex> writeLock(dbMutex_);
443 return GetAllInner().second;
444 }
445 } // End of namespace NativePreferences
446 } // End of namespace OHOS
447