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