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 <sstream>
24 #include <thread>
25 #include <chrono>
26 #include <cinttypes>
27 
28 #include "base64_helper.h"
29 #include "executor_pool.h"
30 #include "log_print.h"
31 #include "preferences_observer_stub.h"
32 #include "preferences_xml_utils.h"
33 #include "preferences_file_operation.h"
34 #include "preferences_anonymous.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 
44 template<typename T>
GetTypeName()45 std::string GetTypeName()
46 {
47     return "unknown";
48 }
49 
50 template<>
GetTypeName()51 std::string GetTypeName<int>()
52 {
53     return "int";
54 }
55 
56 template<>
GetTypeName()57 std::string GetTypeName<bool>()
58 {
59     return "bool";
60 }
61 
62 template<>
GetTypeName()63 std::string GetTypeName<int64_t>()
64 {
65     return "long";
66 }
67 
68 template<>
GetTypeName()69 std::string GetTypeName<uint64_t>()
70 {
71     return "uint64_t";
72 }
73 
74 template<>
GetTypeName()75 std::string GetTypeName<float>()
76 {
77     return "float";
78 }
79 
80 template<>
GetTypeName()81 std::string GetTypeName<double>()
82 {
83     return "double";
84 }
85 
86 template<>
GetTypeName()87 std::string GetTypeName<std::string>()
88 {
89     return "string";
90 }
91 
92 template<>
GetTypeName()93 std::string GetTypeName<std::vector<std::string>>()
94 {
95     return "stringArray";
96 }
97 
98 template<>
GetTypeName()99 std::string GetTypeName<std::vector<double>>()
100 {
101     return "doubleArray";
102 }
103 
104 template<>
GetTypeName()105 std::string GetTypeName<std::vector<bool>>()
106 {
107     return "boolArray";
108 }
109 
110 template<>
GetTypeName()111 std::string GetTypeName<std::vector<uint8_t>>()
112 {
113     return "uint8Array";
114 }
115 
116 template<>
GetTypeName()117 std::string GetTypeName<Object>()
118 {
119     return "object";
120 }
121 
122 template<>
GetTypeName()123 std::string GetTypeName<BigInt>()
124 {
125     return "BigInt";
126 }
127 
PreferencesImpl(const Options & options)128 PreferencesImpl::PreferencesImpl(const Options &options) : PreferencesBase(options)
129 {
130     loaded_.store(false);
131     currentMemoryStateGeneration_ = 0;
132     diskStateGeneration_ = 0;
133     queue_ = std::make_shared<SafeBlockQueue<uint64_t>>(1);
134 }
135 
~PreferencesImpl()136 PreferencesImpl::~PreferencesImpl()
137 {
138 }
139 
Init()140 int PreferencesImpl::Init()
141 {
142     if (!StartLoadFromDisk()) {
143         return E_ERROR;
144     }
145     return E_OK;
146 }
147 
StartLoadFromDisk()148 bool PreferencesImpl::StartLoadFromDisk()
149 {
150     loaded_.store(false);
151 
152     ExecutorPool::Task task = [pref = shared_from_this()] { PreferencesImpl::LoadFromDisk(pref); };
153     return (executorPool_.Execute(std::move(task)) == ExecutorPool::INVALID_TASK_ID) ? false : true;
154 }
155 
156 /* static */
LoadFromDisk(std::shared_ptr<PreferencesImpl> pref)157 void PreferencesImpl::LoadFromDisk(std::shared_ptr<PreferencesImpl> pref)
158 {
159     if (pref->loaded_.load()) {
160         return;
161     }
162     std::lock_guard<std::mutex> lock(pref->mutex_);
163     if (!pref->loaded_.load()) {
164         bool loadResult = PreferencesImpl::ReadSettingXml(pref);
165         if (!loadResult) {
166             LOG_WARN("The settingXml %{public}s load failed.", ExtractFileName(pref->options_.filePath).c_str());
167         }
168         pref->loaded_.store(true);
169         pref->cond_.notify_all();
170     }
171 }
172 
AwaitLoadFile()173 void PreferencesImpl::AwaitLoadFile()
174 {
175     if (loaded_.load()) {
176         return;
177     }
178     std::unique_lock<std::mutex> lock(mutex_);
179     if (!loaded_.load()) {
180         cond_.wait_for(lock, std::chrono::seconds(WAIT_TIME), [this] { return loaded_.load(); });
181     }
182 
183     if (!loaded_.load()) {
184         LOG_ERROR("The settingXml %{public}s load timeout.", ExtractFileName(options_.filePath).c_str());
185     }
186 }
187 
Get(const std::string & key,const PreferencesValue & defValue)188 PreferencesValue PreferencesImpl::Get(const std::string &key, const PreferencesValue &defValue)
189 {
190     if (CheckKey(key) != E_OK) {
191         return defValue;
192     }
193 
194     AwaitLoadFile();
195 
196     auto it = valuesCache_.Find(key);
197     if (it.first) {
198         return it.second;
199     }
200     return defValue;
201 }
202 
GetAll()203 std::map<std::string, PreferencesValue> PreferencesImpl::GetAll()
204 {
205     AwaitLoadFile();
206     return valuesCache_.Clone();
207 }
208 
209 template<typename T>
Convert2PrefValue(const Element & element,T & value)210 static void Convert2PrefValue(const Element &element, T &value)
211 {
212     if constexpr (std::is_same<T, bool>::value) {
213         value = (element.value_.compare("true") == 0) ? true : false;
214     } else if constexpr (std::is_same<T, std::string>::value) {
215         value = element.value_;
216     } else if constexpr (std::is_same<T, std::monostate>::value) {
217         value = std::monostate();
218     } else {
219         std::stringstream ss;
220         ss << element.value_;
221         ss >> value;
222     }
223 }
224 
225 template<typename T>
Convert2PrefValue(const Element & element,std::vector<T> & values)226 static void Convert2PrefValue(const Element &element, std::vector<T> &values)
227 {
228     for (const auto &child : element.children_) {
229         T value;
230         Convert2PrefValue(child, value);
231         values.push_back(value);
232     }
233 }
234 
Convert2PrefValue(const Element & element,BigInt & value)235 static void Convert2PrefValue(const Element &element, BigInt &value)
236 {
237     for (const auto &child : element.children_) {
238         uint64_t val;
239         Convert2PrefValue(child, val);
240         value.words_.push_back(val);
241     }
242     value.sign_ = 0;
243     if (!value.words_.empty()) {
244         value.sign_ = static_cast<int>(value.words_[value.words_.size() - 1]);
245         value.words_.pop_back();
246     }
247 }
248 
249 template<typename T>
GetPrefValue(const Element & element,T & value)250 bool GetPrefValue(const Element &element, T &value)
251 {
252     LOG_WARN("unknown element type. the key is %{public}s", Anonymous::ToBeAnonymous(element.key_).c_str());
253     return false;
254 }
255 
Convert2PrefValue(const Element & element,std::vector<uint8_t> & value)256 static void Convert2PrefValue(const Element &element, std::vector<uint8_t> &value)
257 {
258     if (!Base64Helper::Decode(element.value_, value)) {
259         value.clear();
260     }
261 }
262 
Convert2PrefValue(const Element & element,Object & value)263 static void Convert2PrefValue(const Element &element, Object &value)
264 {
265     value.valueStr = element.value_;
266 }
267 
268 template<typename T, typename First, typename... Types>
GetPrefValue(const Element & element,T & value)269 bool GetPrefValue(const Element &element, T &value)
270 {
271     if (element.tag_ == GetTypeName<First>()) {
272         First val;
273         Convert2PrefValue(element, val);
274         value = val;
275         return true;
276     }
277     return GetPrefValue<T, Types...>(element, value);
278 }
279 
280 template<typename... Types>
Convert2PrefValue(const Element & element,std::variant<Types...> & value)281 bool Convert2PrefValue(const Element &element, std::variant<Types...> &value)
282 {
283     return GetPrefValue<decltype(value), Types...>(element, value);
284 }
285 
ReadXmlElement(const Element & element,std::map<std::string,PreferencesValue> & prefMap)286 void ReadXmlElement(const Element &element, std::map<std::string, PreferencesValue> &prefMap)
287 {
288     PreferencesValue value(static_cast<int64_t>(0));
289     if (Convert2PrefValue(element, value.value_)) {
290         prefMap.insert(std::make_pair(element.key_, value));
291     }
292 }
293 
ReadSettingXml(std::shared_ptr<PreferencesImpl> pref)294 bool PreferencesImpl::ReadSettingXml(std::shared_ptr<PreferencesImpl> pref)
295 {
296     std::vector<Element> settings;
297     if (!PreferencesXmlUtils::ReadSettingXml(pref->options_.filePath, pref->options_.bundleName,
298         pref->options_.dataGroupId, settings)) {
299         return false;
300     }
301 
302     std::map<std::string, PreferencesValue> values;
303     for (const auto &element : settings) {
304         ReadXmlElement(element, values);
305     }
306     pref->valuesCache_ = std::move(values);
307     return true;
308 }
309 
310 template<typename T>
Convert2Element(Element & elem,const T & value)311 void Convert2Element(Element &elem, const T &value)
312 {
313     elem.tag_ = GetTypeName<T>();
314     if constexpr (std::is_same<T, bool>::value) {
315         elem.value_ = ((bool)value) ? "true" : "false";
316     } else if constexpr (std::is_same<T, std::string>::value) {
317         elem.value_ = value;
318     } else if constexpr (std::is_same<T, std::monostate>::value) {
319         elem.value_ = {};
320     } else {
321         elem.value_ = std::to_string(value);
322     }
323 }
324 
325 template<typename T>
Convert2Element(Element & elem,const std::vector<T> & value)326 void Convert2Element(Element &elem, const std::vector<T> &value)
327 {
328     elem.tag_ = GetTypeName<std::vector<T>>();
329     for (const T &val : value) {
330         Element element;
331         Convert2Element(element, val);
332         elem.children_.push_back(element);
333     }
334 }
335 
Convert2Element(Element & elem,const std::vector<uint8_t> & value)336 void Convert2Element(Element &elem, const std::vector<uint8_t> &value)
337 {
338     elem.tag_ = GetTypeName<std::vector<uint8_t>>();
339     elem.value_ = Base64Helper::Encode(value);
340 }
341 
Convert2Element(Element & elem,const Object & value)342 void Convert2Element(Element &elem, const Object &value)
343 {
344     elem.tag_ = GetTypeName<Object>();
345     elem.value_ = value.valueStr;
346 }
347 
Convert2Element(Element & elem,const BigInt & value)348 void Convert2Element(Element &elem, const BigInt &value)
349 {
350     elem.tag_ = GetTypeName<BigInt>();
351     for (const auto &val : value.words_) {
352         Element element;
353         Convert2Element(element, val);
354         elem.children_.push_back(element);
355     }
356     // place symbol at the end
357     Element symbolElement;
358     Convert2Element(symbolElement, static_cast<uint64_t>(value.sign_));
359     elem.children_.push_back(symbolElement);
360 }
361 
GetElement(Element & elem,const T & value)362 template<typename T> void GetElement(Element &elem, const T &value)
363 {
364     LOG_WARN("unknown element type. the key is %{public}s", Anonymous::ToBeAnonymous(elem.key_).c_str());
365 }
366 
GetElement(Element & elem,const T & value)367 template<typename T, typename First, typename... Types> void GetElement(Element &elem, const T &value)
368 {
369     auto *val = std::get_if<First>(&value);
370     if (val != nullptr) {
371         return Convert2Element(elem, *val);
372     }
373     return GetElement<T, Types...>(elem, value);
374 }
375 
Convert2Element(Element & elem,const std::variant<Types...> & value)376 template<typename... Types> void Convert2Element(Element &elem, const std::variant<Types...> &value)
377 {
378     return GetElement<decltype(value), Types...>(elem, value);
379 }
380 
WriteXmlElement(Element & elem,const PreferencesValue & value)381 void WriteXmlElement(Element &elem, const PreferencesValue &value)
382 {
383     Convert2Element(elem, value.value_);
384 }
385 
WriteSettingXml(const Options & options,const std::map<std::string,PreferencesValue> & writeToDiskMap)386 bool PreferencesImpl::WriteSettingXml(
387     const Options &options, const std::map<std::string, PreferencesValue> &writeToDiskMap)
388 {
389     std::vector<Element> settings;
390     for (auto it = writeToDiskMap.begin(); it != writeToDiskMap.end(); it++) {
391         Element elem;
392         elem.key_ = it->first;
393         PreferencesValue value = it->second;
394         WriteXmlElement(elem, value);
395         settings.push_back(elem);
396     }
397 
398     return PreferencesXmlUtils::WriteSettingXml(options.filePath, options.bundleName, options.dataGroupId, settings);
399 }
400 
401 
HasKey(const std::string & key)402 bool PreferencesImpl::HasKey(const std::string &key)
403 {
404     if (CheckKey(key) != E_OK) {
405         return false;
406     }
407 
408     AwaitLoadFile();
409     return valuesCache_.Contains(key);
410 }
411 
Put(const std::string & key,const PreferencesValue & value)412 int PreferencesImpl::Put(const std::string &key, const PreferencesValue &value)
413 {
414     int errCode = CheckKey(key);
415     if (errCode != E_OK) {
416         return errCode;
417     }
418     errCode = CheckValue(value);
419     if (errCode != E_OK) {
420         return errCode;
421     }
422     AwaitLoadFile();
423 
424     valuesCache_.Compute(key, [this, &value](auto &key, PreferencesValue &val) {
425         if (val == value) {
426             return true;
427         }
428         val = value;
429         modifiedKeys_.push_back(key);
430         return true;
431     });
432     return E_OK;
433 }
434 
Delete(const std::string & key)435 int PreferencesImpl::Delete(const std::string &key)
436 {
437     int errCode = CheckKey(key);
438     if (errCode != E_OK) {
439         return errCode;
440     }
441     AwaitLoadFile();
442     valuesCache_.EraseIf(key, [this](auto &key, PreferencesValue &val) {
443         modifiedKeys_.push_back(key);
444         return true;
445     });
446     return E_OK;
447 }
448 
Clear()449 int PreferencesImpl::Clear()
450 {
451     AwaitLoadFile();
452     valuesCache_.EraseIf([this](auto &key, PreferencesValue &val) {
453         modifiedKeys_.push_back(key);
454         return true;
455     });
456     return E_OK;
457 }
458 
WriteToDiskFile(std::shared_ptr<PreferencesImpl> pref)459 int PreferencesImpl::WriteToDiskFile(std::shared_ptr<PreferencesImpl> pref)
460 {
461     std::list<std::string> keysModified;
462     std::map<std::string, PreferencesValue> writeToDiskMap;
463     pref->valuesCache_.DoActionWhenClone(
464         [pref, &writeToDiskMap, &keysModified](const std::map<std::string, PreferencesValue> &map) {
465         if (!pref->modifiedKeys_.empty()) {
466             keysModified = std::move(pref->modifiedKeys_);
467         }
468         writeToDiskMap = std::move(map);
469     });
470 
471     // Cache has not changed, Not need to write persistent files.
472     if (keysModified.empty()) {
473         LOG_INFO("No data to update persistent file");
474         return E_OK;
475     }
476     if (!pref->WriteSettingXml(pref->options_, writeToDiskMap)) {
477         return E_ERROR;
478     }
479     pref->NotifyPreferencesObserver(keysModified, writeToDiskMap);
480     return E_OK;
481 }
482 
Flush()483 void PreferencesImpl::Flush()
484 {
485     auto success = queue_->PushNoWait(1);
486     if (success) {
487         std::weak_ptr<SafeBlockQueue<uint64_t>> queue = queue_;
488         ExecutorPool::Task task = [queue, self = weak_from_this()] {
489             auto realQueue = queue.lock();
490             auto realThis = self.lock();
491             if (realQueue == nullptr || realThis == nullptr) {
492                 return ;
493             }
494             uint64_t value = 0;
495             std::lock_guard<std::mutex> lock(realThis->mutex_);
496             auto has = realQueue->PopNotWait(value);
497             if (has && value == 1) {
498                 PreferencesImpl::WriteToDiskFile(realThis);
499             }
500         };
501         executorPool_.Schedule(std::chrono::milliseconds(TASK_EXEC_TIME), std::move(task));
502     }
503 }
504 
FlushSync()505 int PreferencesImpl::FlushSync()
506 {
507     auto success = queue_->PushNoWait(1);
508     if (success) {
509         if (queue_ == nullptr) {
510             return E_ERROR;
511         }
512         uint64_t value = 0;
513         std::lock_guard<std::mutex> lock(mutex_);
514         auto has = queue_->PopNotWait(value);
515         if (has && value == 1) {
516             return PreferencesImpl::WriteToDiskFile(shared_from_this());
517         }
518     }
519     return E_OK;
520 }
521 
GetValue(const std::string & key,const PreferencesValue & defValue)522 std::pair<int, PreferencesValue> PreferencesImpl::GetValue(const std::string &key, const PreferencesValue &defValue)
523 {
524     int errCode = CheckKey(key);
525     if (errCode != E_OK) {
526         return std::make_pair(errCode, defValue);
527     }
528 
529     AwaitLoadFile();
530     auto iter = valuesCache_.Find(key);
531     if (iter.first) {
532         return std::make_pair(E_OK, iter.second);
533     }
534     return std::make_pair(E_NO_DATA, defValue);
535 }
536 
GetAllData()537 std::pair<int, std::map<std::string, PreferencesValue>> PreferencesImpl::GetAllData()
538 {
539     AwaitLoadFile();
540     return std::make_pair(E_OK, valuesCache_.Clone());
541 }
542 
NotifyPreferencesObserver(const std::list<std::string> & keysModified,const std::map<std::string,PreferencesValue> & writeToDiskMap)543 void PreferencesImpl::NotifyPreferencesObserver(const std::list<std::string> &keysModified,
544     const std::map<std::string, PreferencesValue> &writeToDiskMap)
545 {
546     if (keysModified.empty()) {
547         return;
548     }
549     LOG_DEBUG("notify observer size:%{public}zu", dataObserversMap_.size());
550     std::shared_lock<std::shared_mutex> autoLock(obseverMetux_);
551     for (const auto &[weakPrt, keys] : dataObserversMap_) {
552         std::map<std::string, PreferencesValue> records;
553         for (auto key = keysModified.begin(); key != keysModified.end(); ++key) {
554             auto itKey = keys.find(*key);
555             if (itKey == keys.end()) {
556                 continue;
557             }
558             PreferencesValue value;
559             auto dataIt = writeToDiskMap.find(*key);
560             if (dataIt != writeToDiskMap.end()) {
561                 value = dataIt->second;
562             }
563             records.insert({*key, value});
564         }
565         if (records.empty()) {
566             continue;
567         }
568         if (std::shared_ptr<PreferencesObserver> sharedPtr = weakPrt.lock()) {
569             LOG_DEBUG("dataChange observer call, resultSize:%{public}zu", records.size());
570             sharedPtr->OnChange(records);
571         }
572     }
573 
574     auto dataObsMgrClient = DataObsMgrClient::GetInstance();
575     for (auto key = keysModified.begin(); key != keysModified.end(); ++key) {
576         for (auto it = localObservers_.begin(); it != localObservers_.end(); ++it) {
577             std::weak_ptr<PreferencesObserver> weakPreferencesObserver = *it;
578             if (std::shared_ptr<PreferencesObserver> sharedPreferencesObserver = weakPreferencesObserver.lock()) {
579                 sharedPreferencesObserver->OnChange(*key);
580             }
581         }
582 
583         if (dataObsMgrClient == nullptr) {
584             continue;
585         }
586         LOG_INFO("The %{public}s is changed, the observer needs to be triggered.",
587             Anonymous::ToBeAnonymous(*key).c_str());
588         dataObsMgrClient->NotifyChange(MakeUri(*key));
589     }
590 }
591 } // End of namespace NativePreferences
592 } // End of namespace OHOS
593