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