• 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_observer_stub.h"
30 #include "preferences_xml_utils.h"
31 #include "preferences_file_operation.h"
32 #include "preferences_anonymous.h"
33 #include "preferences_dfx_adapter.h"
34 #include "preferences_utils.h"
35 
36 namespace OHOS {
37 namespace NativePreferences {
38 
39 using namespace std::chrono;
40 
41 constexpr int32_t WAIT_TIME = 2;
42 constexpr int32_t TASK_EXEC_TIME = 100;
43 constexpr int32_t LOAD_XML_LOG_TIME = 1000;
PreferencesImpl(const Options & options)44 PreferencesImpl::PreferencesImpl(const Options &options) : PreferencesBase(options)
45 {
46     loaded_.store(false);
47     isNeverUnlock_ = false;
48     loadResult_= false;
49     queue_ = std::make_shared<SafeBlockQueue<uint64_t>>(1);
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 (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("file %{public}s is inactive.", ExtractFileName(options_.filePath).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 (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 = CheckKey(key);
250     if (errCode != E_OK) {
251         return errCode;
252     }
253     errCode = CheckValue(value);
254     if (errCode != E_OK) {
255         return errCode;
256     }
257     AwaitLoadFile();
258     IsClose(std::string(__FUNCTION__));
259 
260     std::unique_lock<decltype(cacheMutex_)> lock(cacheMutex_);
261     if (isCleared_.load()) { // has cleared.
262         for (auto &it : valuesCache_) {
263             modifiedKeys_.emplace(it.first);
264         }
265         valuesCache_.clear();
266         valuesCache_.insert_or_assign(key, value);
267         modifiedKeys_.emplace(key);
268         isCleared_.store(false);
269     } else {
270         auto iter = valuesCache_.find(key);
271         if (iter != valuesCache_.end()) {
272             PreferencesValue &val = iter->second;
273             if (val == value) {
274                 return E_OK;
275             }
276         }
277         valuesCache_.insert_or_assign(key, value);
278         modifiedKeys_.emplace(key);
279     }
280     return E_OK;
281 }
282 
Delete(const std::string & key)283 int PreferencesImpl::Delete(const std::string &key)
284 {
285     int errCode = CheckKey(key);
286     if (errCode != E_OK) {
287         return errCode;
288     }
289     AwaitLoadFile();
290     IsClose(std::string(__FUNCTION__));
291     std::unique_lock<decltype(cacheMutex_)> lock(cacheMutex_);
292     if (isCleared_.load()) {
293         return E_OK;
294     }
295     if (valuesCache_.find(key) != valuesCache_.end()) {
296         valuesCache_.erase(key);
297         modifiedKeys_.emplace(key);
298     }
299     return E_OK;
300 }
301 
Clear()302 int PreferencesImpl::Clear()
303 {
304     AwaitLoadFile();
305     IsClose(std::string(__FUNCTION__));
306     isCleared_.store(true);
307     return E_OK;
308 }
309 
WriteToDiskFile(std::shared_ptr<PreferencesImpl> pref)310 int PreferencesImpl::WriteToDiskFile(std::shared_ptr<PreferencesImpl> pref)
311 {
312     auto keysModified = std::make_shared<std::unordered_set<std::string>>();
313     auto writeToDiskMap = std::make_shared<std::unordered_map<std::string, PreferencesValue>>();
314     {
315         std::unique_lock<decltype(pref->cacheMutex_)> lock(pref->cacheMutex_);
316         if (pref->isCleared_.load()) {
317             for (auto &it : pref->valuesCache_) {
318                 pref->modifiedKeys_.emplace(it.first);
319             }
320             pref->valuesCache_.clear();
321             pref->isCleared_.store(false);
322         }
323         if (!pref->modifiedKeys_.empty()) {
324             *keysModified = std::move(pref->modifiedKeys_);
325             *writeToDiskMap = pref->valuesCache_;
326         } else {
327             // Cache has not changed, Not need to write persistent files.
328             LOG_INFO("No data to update persistent file");
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 = 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         auto dataObsMgrClient = DataObsMgrClient::GetInstance();
479         if (dataObsMgrClient == nullptr) {
480             return;
481         }
482         for (auto &key : *keysModified) {
483             LOG_INFO("The %{public}s is changed, the observer needs to be triggered.",
484                 Anonymous::ToBeAnonymous(key).c_str());
485             dataObsMgrClient->NotifyChange(pref->MakeUri(key));
486         }
487     };
488     executorPool_.Execute(std::move(task));
489 }
490 } // End of namespace NativePreferences
491 } // End of namespace OHOS
492