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