• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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_impl.h"
17 
18 #include <cinttypes>
19 #include <climits>
20 #include <cstdint>
21 #include <cstdlib>
22 #include <functional>
23 #include <thread>
24 #include <chrono>
25 #include <cinttypes>
26 
27 #include "executor_pool.h"
28 #include "log_print.h"
29 #include "preferences_xml_utils.h"
30 #include "preferences_file_operation.h"
31 #include "preferences_anonymous.h"
32 #include "preferences_dfx_adapter.h"
33 #include "preferences_utils.h"
34 
35 namespace OHOS {
36 namespace NativePreferences {
37 
38 using namespace std::chrono;
39 
40 constexpr int32_t WAIT_TIME = 2;
41 constexpr int32_t TASK_EXEC_TIME = 100;
42 constexpr int32_t LOAD_XML_LOG_TIME = 1000;
PreferencesImpl(const Options & options)43 PreferencesImpl::PreferencesImpl(const Options &options) : PreferencesBase(options)
44 {
45     loaded_.store(false);
46     isNeverUnlock_ = false;
47     loadResult_= false;
48     queue_ = std::make_shared<SafeBlockQueue<uint64_t>>(1);
49     dataObsMgrClient_ = DataObsMgrClient::GetInstance();
50     isActive_.store(true);
51     isCleared_.store(false);
52 }
53 
~PreferencesImpl()54 PreferencesImpl::~PreferencesImpl()
55 {
56 }
57 
Init()58 int PreferencesImpl::Init()
59 {
60     if (!StartLoadFromDisk()) {
61         return E_ERROR;
62     }
63     return E_OK;
64 }
65 
StartLoadFromDisk()66 bool PreferencesImpl::StartLoadFromDisk()
67 {
68     std::lock_guard<std::mutex> lock(mutex_);
69     loaded_.store(false);
70     isNeverUnlock_ = false;
71     loadResult_ = false;
72 
73     ExecutorPool::Task task = [pref = shared_from_this()] { PreferencesImpl::LoadFromDisk(pref); };
74     return (executorPool_.Execute(std::move(task)) == ExecutorPool::INVALID_TASK_ID) ? false : true;
75 }
76 
77 /* static */
LoadFromDisk(std::shared_ptr<PreferencesImpl> pref)78 void PreferencesImpl::LoadFromDisk(std::shared_ptr<PreferencesImpl> pref)
79 {
80     if (pref->loaded_.load()) {
81         return;
82     }
83     std::lock_guard<std::mutex> lock(pref->mutex_);
84     if (!pref->loaded_.load()) {
85         std::string::size_type pos = pref->options_.filePath.find_last_of('/');
86         std::string filePath = pref->options_.filePath.substr(0, pos);
87         if (Access(filePath) != 0) {
88             pref->isNeverUnlock_ = true;
89         }
90         std::unordered_map<std::string, PreferencesValue> values;
91         bool loadResult = pref->ReadSettingXml(values);
92         if (!loadResult) {
93             LOG_WARN("The settingXml %{public}s load failed.", ExtractFileName(pref->options_.filePath).c_str());
94         } else {
95             std::unique_lock<decltype(pref->cacheMutex_)> lock(pref->cacheMutex_);
96             pref->valuesCache_ = std::move(values);
97             pref->loadResult_ = true;
98             pref->isNeverUnlock_ = false;
99         }
100         pref->loaded_.store(true);
101         pref->cond_.notify_all();
102     }
103 }
104 
ReloadFromDisk()105 bool PreferencesImpl::ReloadFromDisk()
106 {
107     if (loadResult_) {
108         return false;
109     }
110 
111     std::unique_lock<decltype(cacheMutex_)> lock(cacheMutex_);
112     std::unordered_map<std::string, PreferencesValue> values = valuesCache_;
113     bool loadResult = ReadSettingXml(values);
114     LOG_WARN("The settingXml %{public}s reload result is %{public}d",
115         ExtractFileName(options_.filePath).c_str(), loadResult);
116     if (loadResult) {
117         valuesCache_ = std::move(values);
118         isNeverUnlock_ = false;
119         loadResult_ = true;
120         return true;
121     }
122     return false;
123 }
124 
PreLoad()125 bool PreferencesImpl::PreLoad()
126 {
127     std::lock_guard<std::mutex> lock(mutex_);
128     if (!loaded_.load()) {
129         return true;
130     }
131     if (isNeverUnlock_ || (!isNeverUnlock_ && !loadResult_)) {
132         if (Access(options_.filePath) == 0) {
133             return ReloadFromDisk();
134         }
135     }
136     return true;
137 }
138 
AwaitLoadFile()139 void PreferencesImpl::AwaitLoadFile()
140 {
141     if (loaded_.load()) {
142         PreLoad();
143         return;
144     }
145     std::unique_lock<std::mutex> lock(mutex_);
146     if (!loaded_.load()) {
147         cond_.wait_for(lock, std::chrono::seconds(WAIT_TIME), [this] { return loaded_.load(); });
148     }
149 
150     if (!loaded_.load()) {
151         LOG_ERROR("The settingXml %{public}s load timeout.", ExtractFileName(options_.filePath).c_str());
152     }
153 }
154 
Get(const std::string & key,const PreferencesValue & defValue)155 PreferencesValue PreferencesImpl::Get(const std::string &key, const PreferencesValue &defValue)
156 {
157     if (PreferencesUtils::CheckKey(key) != E_OK) {
158         return defValue;
159     }
160 
161     AwaitLoadFile();
162     IsClose(std::string(__FUNCTION__));
163 
164     std::shared_lock<decltype(cacheMutex_)> lock(cacheMutex_);
165     if (!isCleared_.load()) {
166         auto iter = valuesCache_.find(key);
167         if (iter != valuesCache_.end()) {
168             return iter->second;
169         }
170     }
171     return defValue;
172 }
173 
GetAll()174 std::map<std::string, PreferencesValue> PreferencesImpl::GetAll()
175 {
176     AwaitLoadFile();
177     IsClose(std::string(__FUNCTION__));
178     std::map<std::string, PreferencesValue> allDatas;
179     std::shared_lock<decltype(cacheMutex_)> lock(cacheMutex_);
180     if (!isCleared_.load()) {
181         for (auto &it : valuesCache_) {
182             allDatas.insert_or_assign(it.first, it.second);
183         }
184     }
185     return allDatas;
186 }
187 
GetFileSize(const std::string & path)188 static int64_t GetFileSize(const std::string &path)
189 {
190     int64_t fileSize = -1;
191     struct stat buffer;
192     if (stat(path.c_str(), &buffer) == 0) {
193         fileSize = static_cast<int64_t>(buffer.st_size);
194     }
195     return fileSize;
196 }
197 
ReadSettingXml(std::unordered_map<std::string,PreferencesValue> & conMap)198 bool PreferencesImpl::ReadSettingXml(std::unordered_map<std::string, PreferencesValue> &conMap)
199 {
200     auto begin = static_cast<uint64_t>(duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count());
201     if (!PreferencesXmlUtils::ReadSettingXml(options_.filePath, options_.bundleName, conMap)) {
202         return false;
203     }
204     auto end = static_cast<uint64_t>(duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count());
205     if (end - begin > LOAD_XML_LOG_TIME) {
206         LOG_ERROR("The settingXml %{public}s load time exceed 1s, file size:%{public}" PRId64 ".",
207             ExtractFileName(options_.filePath).c_str(), GetFileSize(options_.filePath));
208     }
209     return true;
210 }
211 
Close()212 int PreferencesImpl::Close()
213 {
214     isActive_.store(false);
215     return E_OK;
216 }
217 
IsClose(const std::string & name)218 bool PreferencesImpl::IsClose(const std::string &name)
219 {
220     if (isActive_.load()) {
221         return false;
222     }
223 
224     LOG_WARN("%{public}s closed:%{public}s.", ExtractFileName(options_.filePath).c_str(), name.c_str());
225     std::string operationMsg = " use after close.";
226     ReportFaultParam reportParam = { "inactive object", options_.bundleName, NORMAL_DB,
227         ExtractFileName(options_.filePath), E_OBJECT_NOT_ACTIVE, name + operationMsg };
228     PreferencesDfxManager::ReportAbnormalOperation(reportParam, ReportedFaultBitMap::OBJECT_IS_NOT_ACTIVE);
229     return true;
230 }
231 
HasKey(const std::string & key)232 bool PreferencesImpl::HasKey(const std::string &key)
233 {
234     if (PreferencesUtils::CheckKey(key) != E_OK) {
235         return false;
236     }
237 
238     AwaitLoadFile();
239     IsClose(std::string(__FUNCTION__));
240     std::shared_lock<decltype(cacheMutex_)> lock(cacheMutex_);
241     if (isCleared_.load()) {
242         return false;
243     }
244     return valuesCache_.find(key) != valuesCache_.end();
245 }
246 
Put(const std::string & key,const PreferencesValue & value)247 int PreferencesImpl::Put(const std::string &key, const PreferencesValue &value)
248 {
249     int errCode = PreferencesUtils::CheckKey(key);
250     if (errCode != E_OK) {
251         return errCode;
252     }
253     errCode = PreferencesUtils::CheckValue(value);
254     if (errCode != E_OK) {
255         return errCode;
256     }
257     AwaitLoadFile();
258     IsClose(std::string(__FUNCTION__));
259     ReportObjectUsage(shared_from_this(), value);
260 
261     std::unique_lock<decltype(cacheMutex_)> lock(cacheMutex_);
262     if (isCleared_.load()) { // has cleared.
263         for (auto &it : valuesCache_) {
264             modifiedKeys_.emplace(it.first);
265         }
266         valuesCache_.clear();
267         valuesCache_.insert_or_assign(key, value);
268         modifiedKeys_.emplace(key);
269         isCleared_.store(false);
270     } else {
271         auto iter = valuesCache_.find(key);
272         if (iter != valuesCache_.end()) {
273             PreferencesValue &val = iter->second;
274             if (val == value) {
275                 return E_OK;
276             }
277         }
278         valuesCache_.insert_or_assign(key, value);
279         modifiedKeys_.emplace(key);
280     }
281     return E_OK;
282 }
283 
Delete(const std::string & key)284 int PreferencesImpl::Delete(const std::string &key)
285 {
286     int errCode = PreferencesUtils::CheckKey(key);
287     if (errCode != E_OK) {
288         return errCode;
289     }
290     AwaitLoadFile();
291     IsClose(std::string(__FUNCTION__));
292     std::unique_lock<decltype(cacheMutex_)> lock(cacheMutex_);
293     if (isCleared_.load()) {
294         return E_OK;
295     }
296     if (valuesCache_.find(key) != valuesCache_.end()) {
297         valuesCache_.erase(key);
298         modifiedKeys_.emplace(key);
299     }
300     return E_OK;
301 }
302 
Clear()303 int PreferencesImpl::Clear()
304 {
305     AwaitLoadFile();
306     IsClose(std::string(__FUNCTION__));
307     isCleared_.store(true);
308     return E_OK;
309 }
310 
WriteToDiskFile(std::shared_ptr<PreferencesImpl> pref)311 int PreferencesImpl::WriteToDiskFile(std::shared_ptr<PreferencesImpl> pref)
312 {
313     auto keysModified = std::make_shared<std::unordered_set<std::string>>();
314     auto writeToDiskMap = std::make_shared<std::unordered_map<std::string, PreferencesValue>>();
315     {
316         std::unique_lock<decltype(pref->cacheMutex_)> lock(pref->cacheMutex_);
317         if (pref->isCleared_.load()) {
318             for (auto &it : pref->valuesCache_) {
319                 pref->modifiedKeys_.emplace(it.first);
320             }
321             pref->valuesCache_.clear();
322             pref->isCleared_.store(false);
323         }
324         if (!pref->modifiedKeys_.empty()) {
325             *keysModified = std::move(pref->modifiedKeys_);
326             *writeToDiskMap = pref->valuesCache_;
327         } else {
328             // Cache has not changed, Not need to write persistent files.
329             return E_OK;
330         }
331     }
332     if (!PreferencesXmlUtils::WriteSettingXml(pref->options_.filePath, pref->options_.bundleName, *writeToDiskMap)) {
333         return E_ERROR;
334     }
335     if (pref->isNeverUnlock_) {
336         pref->isNeverUnlock_ = false;
337     }
338     if (!pref->loadResult_) {
339         pref->loadResult_ = true;
340     }
341 
342     NotifyPreferencesObserver(pref, keysModified, writeToDiskMap);
343     return E_OK;
344 }
345 
Flush()346 void PreferencesImpl::Flush()
347 {
348     IsClose(std::string(__FUNCTION__));
349     auto success = queue_->PushNoWait(1);
350     if (!success) {
351         return;
352     }
353     std::weak_ptr<SafeBlockQueue<uint64_t>> queue = queue_;
354     ExecutorPool::Task task = [queue, self = weak_from_this()] {
355         auto realQueue = queue.lock();
356         auto realThis = self.lock();
357         if (realQueue == nullptr || realThis == nullptr) {
358             return;
359         }
360         uint64_t value = 0;
361         if (!realThis->PreLoad()) {
362             return;
363         }
364         std::lock_guard<std::mutex> lock(realThis->mutex_);
365         auto has = realQueue->PopNotWait(value);
366         if (has && value == 1) {
367             PreferencesImpl::WriteToDiskFile(realThis);
368         }
369     };
370     executorPool_.Schedule(std::chrono::milliseconds(TASK_EXEC_TIME), std::move(task));
371 }
372 
FlushSync()373 int PreferencesImpl::FlushSync()
374 {
375     IsClose(std::string(__FUNCTION__));
376     auto success = queue_->PushNoWait(1);
377     if (success) {
378         if (queue_ == nullptr) {
379             return E_ERROR;
380         }
381         if (!PreLoad()) {
382             return E_OK;
383         }
384         uint64_t value = 0;
385         std::lock_guard<std::mutex> lock(mutex_);
386         auto has = queue_->PopNotWait(value);
387         if (has && value == 1) {
388             return PreferencesImpl::WriteToDiskFile(shared_from_this());
389         }
390     }
391     return E_OK;
392 }
393 
GetValue(const std::string & key,const PreferencesValue & defValue)394 std::pair<int, PreferencesValue> PreferencesImpl::GetValue(const std::string &key, const PreferencesValue &defValue)
395 {
396     int errCode = PreferencesUtils::CheckKey(key);
397     if (errCode != E_OK) {
398         return std::make_pair(errCode, defValue);
399     }
400 
401     AwaitLoadFile();
402     IsClose(std::string(__FUNCTION__));
403     std::shared_lock<decltype(cacheMutex_)> lock(cacheMutex_);
404     if (!isCleared_.load()) {
405         auto iter = valuesCache_.find(key);
406         if (iter != valuesCache_.end()) {
407             return std::make_pair(E_OK, iter->second);
408         }
409     }
410     return std::make_pair(E_NO_DATA, defValue);
411 }
412 
GetAllData()413 std::pair<int, std::map<std::string, PreferencesValue>> PreferencesImpl::GetAllData()
414 {
415     AwaitLoadFile();
416     IsClose(std::string(__FUNCTION__));
417     std::map<std::string, PreferencesValue> allDatas;
418     std::shared_lock<decltype(cacheMutex_)> lock(cacheMutex_);
419     if (!isCleared_.load()) {
420         for (auto &it : valuesCache_) {
421             allDatas.insert_or_assign(it.first, it.second);
422         }
423     }
424     return std::make_pair(E_OK, allDatas);
425 }
426 
GetAllDatas()427 std::unordered_map<std::string, PreferencesValue> PreferencesImpl::GetAllDatas()
428 {
429     AwaitLoadFile();
430     IsClose(std::string(__FUNCTION__));
431     std::shared_lock<decltype(cacheMutex_)> lock(cacheMutex_);
432     if (!isCleared_.load()) {
433         return valuesCache_;
434     }
435     return {};
436 }
437 
NotifyPreferencesObserver(std::shared_ptr<PreferencesImpl> pref,std::shared_ptr<std::unordered_set<std::string>> keysModified,std::shared_ptr<std::unordered_map<std::string,PreferencesValue>> writeToDisk)438 void PreferencesImpl::NotifyPreferencesObserver(std::shared_ptr<PreferencesImpl> pref,
439     std::shared_ptr<std::unordered_set<std::string>> keysModified,
440     std::shared_ptr<std::unordered_map<std::string, PreferencesValue>> writeToDisk)
441 {
442     if (keysModified->empty()) {
443         return;
444     }
445     std::shared_lock<std::shared_mutex> autoLock(pref->obseverMetux_);
446     for (const auto &[weakPrt, keys] : pref->dataObserversMap_) {
447         std::map<std::string, PreferencesValue> records;
448         for (auto &key : *keysModified) {
449             auto itKey = keys.find(key);
450             if (itKey == keys.end()) {
451                 continue;
452             }
453             PreferencesValue value;
454             auto dataIt = writeToDisk->find(key);
455             if (dataIt != writeToDisk->end()) {
456                 value = dataIt->second;
457             }
458             records.insert({key, value});
459         }
460         if (records.empty()) {
461             continue;
462         }
463         if (std::shared_ptr<PreferencesObserver> sharedPtr = weakPrt.lock()) {
464             sharedPtr->OnChange(records);
465         }
466     }
467 
468     for (auto &it : pref->localObservers_) {
469         for (auto &key : *keysModified) {
470             std::weak_ptr<PreferencesObserver> weakPreferencesObserver = it;
471             if (std::shared_ptr<PreferencesObserver> sharedPreferencesObserver = weakPreferencesObserver.lock()) {
472                 sharedPreferencesObserver->OnChange(key);
473             }
474         }
475     }
476 
477     ExecutorPool::Task task = [pref, keysModified] {
478         if (pref == nullptr || pref->dataObsMgrClient_ == nullptr) {
479             return;
480         }
481         for (auto &key : *keysModified) {
482             LOG_INFO("notify %{public}s", Anonymous::ToBeAnonymous(key).c_str());
483             pref->dataObsMgrClient_->NotifyChange(pref->MakeUri(key));
484         }
485     };
486     executorPool_.Execute(std::move(task));
487 }
488 } // End of namespace NativePreferences
489 } // End of namespace OHOS
490