• 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 <cstdlib>
21 #include <functional>
22 #include <sstream>
23 #include <thread>
24 
25 #include "base64_helper.h"
26 #include "executor_pool.h"
27 #include "log_print.h"
28 #include "preferences_errno.h"
29 #include "preferences_observer_stub.h"
30 #include "preferences_xml_utils.h"
31 #include "securec.h"
32 
33 namespace OHOS {
34 namespace NativePreferences {
GetTypeName()35 template<typename T> std::string GetTypeName()
36 {
37     return "unknown";
38 }
39 
GetTypeName()40 template<> std::string GetTypeName<int>()
41 {
42     return "int";
43 }
44 
GetTypeName()45 template<> std::string GetTypeName<bool>()
46 {
47     return "bool";
48 }
49 
GetTypeName()50 template<> std::string GetTypeName<int64_t>()
51 {
52     return "long";
53 }
54 
GetTypeName()55 template<> std::string GetTypeName<float>()
56 {
57     return "float";
58 }
59 
GetTypeName()60 template<> std::string GetTypeName<double>()
61 {
62     return "double";
63 }
64 
GetTypeName()65 template<> std::string GetTypeName<std::string>()
66 {
67     return "string";
68 }
69 
GetTypeName()70 template<> std::string GetTypeName<std::vector<std::string>>()
71 {
72     return "stringArray";
73 }
74 
GetTypeName()75 template<> std::string GetTypeName<std::vector<double>>()
76 {
77     return "doubleArray";
78 }
79 
GetTypeName()80 template<> std::string GetTypeName<std::vector<bool>>()
81 {
82     return "boolArray";
83 }
84 
GetTypeName()85 template<> std::string GetTypeName<std::vector<uint8_t>>()
86 {
87     return "uint8Array";
88 }
89 
90 ExecutorPool PreferencesImpl::executorPool_ = ExecutorPool(1, 0);
91 
PreferencesImpl(const Options & options)92 PreferencesImpl::PreferencesImpl(const Options &options) : loaded_(false), options_(options)
93 {
94     currentMemoryStateGeneration_ = 0;
95     diskStateGeneration_ = 0;
96 }
97 
MakeFilePath(const std::string & prefPath,const std::string & suffix)98 std::string PreferencesImpl::MakeFilePath(const std::string &prefPath, const std::string &suffix)
99 {
100     std::string filePath = prefPath;
101     filePath += suffix;
102     return filePath;
103 }
104 
~PreferencesImpl()105 PreferencesImpl::~PreferencesImpl()
106 {
107 }
108 
Init()109 int PreferencesImpl::Init()
110 {
111     if (!StartLoadFromDisk()) {
112         return E_ERROR;
113     }
114     return E_OK;
115 }
116 
StartLoadFromDisk()117 bool PreferencesImpl::StartLoadFromDisk()
118 {
119     {
120         std::lock_guard<std::mutex> lock(mutex_);
121         loaded_ = false;
122     }
123 
124     ExecutorPool::Task task = std::bind(PreferencesImpl::LoadFromDisk, shared_from_this());
125     return (executorPool_.Execute(std::move(task)) == ExecutorPool::INVALID_TASK_ID) ? false : true;
126 }
127 
CheckKey(const std::string & key)128 int PreferencesImpl::CheckKey(const std::string &key)
129 {
130     if (key.empty()) {
131         LOG_ERROR("The key string is null or empty.");
132         return E_KEY_EMPTY;
133     }
134     if (Preferences::MAX_KEY_LENGTH < key.length()) {
135         LOG_ERROR("The key string length should shorter than 80.");
136         return E_KEY_EXCEED_MAX_LENGTH;
137     }
138     return E_OK;
139 }
140 
141 /* static */
LoadFromDisk(std::shared_ptr<PreferencesImpl> pref)142 void PreferencesImpl::LoadFromDisk(std::shared_ptr<PreferencesImpl> pref)
143 {
144     std::lock_guard<std::mutex> lock(pref->mutex_);
145     if (pref->loaded_) {
146         return;
147     }
148     pref->ReadSettingXml(pref);
149     pref->loaded_ = true;
150     pref->cond_.notify_all();
151 }
152 
AwaitLoadFile()153 void PreferencesImpl::AwaitLoadFile()
154 {
155     std::unique_lock<std::mutex> lock(mutex_);
156     if (!loaded_) {
157         cond_.wait(lock, [this] { return loaded_; });
158     }
159 }
160 
WriteToDiskFile(std::shared_ptr<PreferencesImpl> pref,std::shared_ptr<MemoryToDiskRequest> mcr)161 void PreferencesImpl::WriteToDiskFile(std::shared_ptr<PreferencesImpl> pref, std::shared_ptr<MemoryToDiskRequest> mcr)
162 {
163     std::unique_lock<std::mutex> lock(pref->mutex_);
164     if (!pref->CheckRequestValidForStateGeneration(mcr)) {
165         mcr->SetDiskWriteResult(true, E_OK);
166         return;
167     }
168 
169     if (pref->WriteSettingXml(pref, mcr->writeToDiskMap_)) {
170         pref->diskStateGeneration_ = mcr->memoryStateGeneration_;
171         mcr->SetDiskWriteResult(true, E_OK);
172     } else {
173         mcr->SetDiskWriteResult(false, E_ERROR);
174     }
175 }
176 
CheckRequestValidForStateGeneration(std::shared_ptr<MemoryToDiskRequest> mcr)177 bool PreferencesImpl::CheckRequestValidForStateGeneration(std::shared_ptr<MemoryToDiskRequest> mcr)
178 {
179     if (diskStateGeneration_ >= mcr->memoryStateGeneration_) {
180         LOG_DEBUG("DiskStateGeneration should be less than memoryStateGeneration.");
181         return false;
182     }
183 
184     if (mcr->isSyncRequest_ || currentMemoryStateGeneration_ == mcr->memoryStateGeneration_) {
185         return true;
186     }
187     return false;
188 }
189 
Get(const std::string & key,const PreferencesValue & defValue)190 PreferencesValue PreferencesImpl::Get(const std::string &key, const PreferencesValue &defValue)
191 {
192     if (CheckKey(key) != E_OK) {
193         return defValue;
194     }
195 
196     AwaitLoadFile();
197     std::lock_guard<std::mutex> lock(mutex_);
198     auto iter = map_.find(key);
199     if (iter != map_.end()) {
200         return iter->second;
201     }
202     return defValue;
203 }
204 
GetAll()205 std::map<std::string, PreferencesValue> PreferencesImpl::GetAll()
206 {
207     AwaitLoadFile();
208     return map_;
209 }
210 
Convert2PrefValue(const Element & element,T & value)211 template<typename T> static void Convert2PrefValue(const Element &element, T &value)
212 {
213     if constexpr (std::is_same<T, bool>::value) {
214         value = (element.value_.compare("true") == 0) ? true : false;
215     } else if constexpr (std::is_same<T, std::string>::value) {
216         value = element.value_;
217     } else {
218         std::stringstream ss;
219         ss << element.value_;
220         ss >> value;
221     }
222 }
223 
Convert2PrefValue(const Element & element,std::vector<T> & values)224 template<typename T> static void Convert2PrefValue(const Element &element, std::vector<T> &values)
225 {
226     for (const auto &child : element.children_) {
227         T value;
228         Convert2PrefValue(child, value);
229         values.push_back(value);
230     }
231 }
232 
GetPrefValue(const Element & element,T & value)233 template<typename T> bool GetPrefValue(const Element &element, T &value)
234 {
235     LOG_WARN("unknown element type. the key is %{public}s", element.key_.c_str());
236     return false;
237 }
238 
Convert2PrefValue(const Element & element,std::vector<uint8_t> & value)239 static void Convert2PrefValue(const Element &element, std::vector<uint8_t> &value)
240 {
241     if (!Base64Helper::Decode(element.value_, value)) {
242         value.clear();
243     }
244 }
245 
GetPrefValue(const Element & element,T & value)246 template<typename T, typename First, typename... Types> bool GetPrefValue(const Element &element, T &value)
247 {
248     if (element.tag_ == GetTypeName<First>()) {
249         First val;
250         Convert2PrefValue(element, val);
251         value = val;
252         return true;
253     }
254     return GetPrefValue<T, Types...>(element, value);
255 }
256 
Convert2PrefValue(const Element & element,std::variant<Types...> & value)257 template<typename... Types> bool Convert2PrefValue(const Element &element, std::variant<Types...> &value)
258 {
259     return GetPrefValue<decltype(value), Types...>(element, value);
260 }
261 
ReadXmlElement(const Element & element,std::map<std::string,PreferencesValue> & prefMap)262 void ReadXmlElement(const Element &element, std::map<std::string, PreferencesValue> &prefMap)
263 {
264     PreferencesValue value(static_cast<int64_t>(0));
265     if (Convert2PrefValue(element, value.value_)) {
266         prefMap.insert(std::make_pair(element.key_, value));
267     }
268 }
269 
ReadSettingXml(std::shared_ptr<PreferencesImpl> pref)270 bool PreferencesImpl::ReadSettingXml(std::shared_ptr<PreferencesImpl> pref)
271 {
272     std::vector<Element> settings;
273     if (!PreferencesXmlUtils::ReadSettingXml(pref->options_.filePath, pref->options_.dataGroupId, settings)) {
274         return false;
275     }
276 
277     for (const auto &element : settings) {
278         ReadXmlElement(element, pref->map_);
279     }
280     return true;
281 }
282 
Convert2Element(Element & elem,const T & value)283 template<typename T> void Convert2Element(Element &elem, const T &value)
284 {
285     elem.tag_ = GetTypeName<T>();
286     if constexpr (std::is_same<T, bool>::value) {
287         elem.value_ = ((bool)value) ? "true" : "false";
288     } else if constexpr (std::is_same<T, std::string>::value) {
289         elem.value_ = value;
290     } else {
291         elem.value_ = std::to_string(value);
292     }
293 }
294 
Convert2Element(Element & elem,const std::vector<T> & value)295 template<typename T> void Convert2Element(Element &elem, const std::vector<T> &value)
296 {
297     elem.tag_ = GetTypeName<std::vector<T>>();
298     for (const T &val : value) {
299         Element element;
300         Convert2Element(element, val);
301         elem.children_.push_back(element);
302     }
303 }
304 
Convert2Element(Element & elem,const std::vector<uint8_t> & value)305 void Convert2Element(Element &elem, const std::vector<uint8_t> &value)
306 {
307     elem.tag_ = GetTypeName<std::vector<uint8_t>>();
308     elem.value_ = Base64Helper::Encode(value);
309 }
310 
GetElement(Element & elem,const T & value)311 template<typename T> void GetElement(Element &elem, const T &value)
312 {
313     LOG_WARN("unknown element type. the key is %{public}s", elem.key_.c_str());
314 }
315 
GetElement(Element & elem,const T & value)316 template<typename T, typename First, typename... Types> void GetElement(Element &elem, const T &value)
317 {
318     auto *val = std::get_if<First>(&value);
319     if (val != nullptr) {
320         return Convert2Element(elem, *val);
321     }
322     return GetElement<T, Types...>(elem, value);
323 }
324 
Convert2Element(Element & elem,const std::variant<Types...> & value)325 template<typename... Types> void Convert2Element(Element &elem, const std::variant<Types...> &value)
326 {
327     return GetElement<decltype(value), Types...>(elem, value);
328 }
329 
WriteXmlElement(Element & elem,const PreferencesValue & value)330 void WriteXmlElement(Element &elem, const PreferencesValue &value)
331 {
332     Convert2Element(elem, value.value_);
333 }
334 
WriteSettingXml(std::shared_ptr<PreferencesImpl> pref,const std::map<std::string,PreferencesValue> & prefMap)335 bool PreferencesImpl::WriteSettingXml(
336     std::shared_ptr<PreferencesImpl> pref, const std::map<std::string, PreferencesValue> &prefMap)
337 {
338     std::vector<Element> settings;
339     for (auto it = prefMap.begin(); it != prefMap.end(); it++) {
340         Element elem;
341         elem.key_ = it->first;
342         PreferencesValue value = it->second;
343         WriteXmlElement(elem, value);
344         settings.push_back(elem);
345     }
346 
347     return PreferencesXmlUtils::WriteSettingXml(pref->options_.filePath, pref->options_.dataGroupId, settings);
348 }
349 
HasKey(const std::string & key)350 bool PreferencesImpl::HasKey(const std::string &key)
351 {
352     if (CheckKey(key) != E_OK) {
353         return false;
354     }
355 
356     AwaitLoadFile();
357 
358     std::lock_guard<std::mutex> lock(mutex_);
359     return (map_.find(key) != map_.end());
360 }
361 
RegisterObserver(std::shared_ptr<PreferencesObserver> preferencesObserver,RegisterMode mode)362 int PreferencesImpl::RegisterObserver(std::shared_ptr<PreferencesObserver> preferencesObserver, RegisterMode mode)
363 {
364     std::lock_guard<std::mutex> lock(mutex_);
365     if (mode == RegisterMode::LOCAL_CHANGE) {
366         std::weak_ptr<PreferencesObserver> weakPreferencesObserver = preferencesObserver;
367         localObservers_.push_back(weakPreferencesObserver);
368     } else {
369         auto dataObsMgrClient = DataObsMgrClient::GetInstance();
370         if (dataObsMgrClient == nullptr) {
371             return E_GET_DATAOBSMGRCLIENT_FAIL;
372         }
373         sptr<DataPreferencesObserverStub> observer(new (std::nothrow) DataPreferencesObserverStub(preferencesObserver));
374         int errcode = dataObsMgrClient->RegisterObserver(MakeUri(), observer);
375         if (errcode != 0) {
376             LOG_ERROR("RegisterObserver multiProcessChange failed, errCode %{public}d", errcode);
377             return errcode;
378         }
379         multiProcessObservers_.push_back(observer);
380     }
381     return E_OK;
382 }
383 
UnRegisterObserver(std::shared_ptr<PreferencesObserver> preferencesObserver,RegisterMode mode)384 int PreferencesImpl::UnRegisterObserver(std::shared_ptr<PreferencesObserver> preferencesObserver, RegisterMode mode)
385 {
386     std::lock_guard<std::mutex> lock(mutex_);
387     if (mode == RegisterMode::LOCAL_CHANGE) {
388         for (auto it = localObservers_.begin(); it != localObservers_.end(); ++it) {
389             std::weak_ptr<PreferencesObserver> weakPreferencesObserver = *it;
390             std::shared_ptr<PreferencesObserver> sharedObserver = weakPreferencesObserver.lock();
391             if (!sharedObserver || sharedObserver == preferencesObserver) {
392                 localObservers_.erase(it);
393                 break;
394             }
395         }
396         return E_OK;
397     }
398     for (auto it = multiProcessObservers_.begin(); it != multiProcessObservers_.end(); ++it) {
399         std::shared_ptr<PreferencesObserver> sharedObserver = (*it)->preferencesObserver_.lock();
400         if (!sharedObserver || sharedObserver == preferencesObserver) {
401             auto dataObsMgrClient = DataObsMgrClient::GetInstance();
402             if (dataObsMgrClient == nullptr) {
403                 return E_GET_DATAOBSMGRCLIENT_FAIL;
404             }
405             int errcode = dataObsMgrClient->UnregisterObserver(MakeUri(), *it);
406             if (errcode != 0) {
407                 LOG_ERROR("RegisterObserver multiProcessChange failed, errCode %{public}d", errcode);
408                 return errcode;
409             }
410             multiProcessObservers_.erase(it);
411             break;
412         }
413     }
414     return E_OK;
415 }
416 
Put(const std::string & key,const PreferencesValue & value)417 int PreferencesImpl::Put(const std::string &key, const PreferencesValue &value)
418 {
419     int errCode = CheckKey(key);
420     if (errCode != E_OK) {
421         return errCode;
422     }
423     if (value.IsString()) {
424         errCode = CheckStringValue(value);
425         if (errCode != E_OK) {
426             LOG_ERROR("PreferencesImpl::Put string value length should shorter than 8*1024");
427             return errCode;
428         }
429     }
430     AwaitLoadFile();
431 
432     std::lock_guard<std::mutex> lock(mutex_);
433 
434     auto iter = map_.find(key);
435     if (iter != map_.end()) {
436         PreferencesValue &val = iter->second;
437         if (val == value) {
438             return E_OK;
439         }
440     }
441     map_.insert_or_assign(key, value);
442     modifiedKeys_.push_back(key);
443     return E_OK;
444 }
445 
CheckStringValue(const std::string & value)446 int PreferencesImpl::CheckStringValue(const std::string &value)
447 {
448     if (Preferences::MAX_VALUE_LENGTH < value.length()) {
449         LOG_ERROR("The value string length should shorter than 8 * 1024.");
450         return E_VALUE_EXCEED_MAX_LENGTH;
451     }
452     return E_OK;
453 }
454 
MakeUri(const std::string & key)455 Uri PreferencesImpl::MakeUri(const std::string &key)
456 {
457     std::string uriStr;
458     if (options_.dataGroupId.empty()) {
459         uriStr = STR_SCHEME + options_.bundleName + STR_SLASH + options_.filePath;
460     } else {
461         uriStr = STR_SCHEME + options_.dataGroupId + STR_SLASH + options_.filePath;
462     }
463 
464     if (!key.empty()) {
465         uriStr = uriStr + STR_QUERY + key;
466     }
467     return Uri(uriStr);
468 }
469 
Delete(const std::string & key)470 int PreferencesImpl::Delete(const std::string &key)
471 {
472     int errCode = CheckKey(key);
473     if (errCode != E_OK) {
474         return errCode;
475     }
476 
477     std::lock_guard<std::mutex> lock(mutex_);
478 
479     auto pos = map_.find(key);
480     if (pos != map_.end()) {
481         map_.erase(pos);
482         modifiedKeys_.push_back(key);
483     }
484 
485     return E_OK;
486 }
487 
Clear()488 int PreferencesImpl::Clear()
489 {
490     std::lock_guard<std::mutex> lock(mutex_);
491 
492     if (!map_.empty()) {
493         for (auto &kv : map_) {
494             modifiedKeys_.push_back(kv.first);
495         }
496         map_.clear();
497     }
498     return E_OK;
499 }
500 
Flush()501 void PreferencesImpl::Flush()
502 {
503     std::shared_ptr<PreferencesImpl::MemoryToDiskRequest> request = commitToMemory();
504     request->isSyncRequest_ = false;
505     ExecutorPool::Task task = std::bind(PreferencesImpl::WriteToDiskFile, shared_from_this(), request);
506     executorPool_.Execute(std::move(task));
507 
508     notifyPreferencesObserver(*request);
509 }
510 
FlushSync()511 int PreferencesImpl::FlushSync()
512 {
513     std::shared_ptr<PreferencesImpl::MemoryToDiskRequest> request = commitToMemory();
514     request->isSyncRequest_ = true;
515     PreferencesImpl::WriteToDiskFile(shared_from_this(), request);
516     if (request->wasWritten_) {
517         LOG_DEBUG("Successfully written to disk file, memory state generation is %{public}" PRId64 "",
518             request->memoryStateGeneration_);
519     }
520     notifyPreferencesObserver(*request);
521     return request->writeToDiskResult_;
522 }
523 
commitToMemory()524 std::shared_ptr<PreferencesImpl::MemoryToDiskRequest> PreferencesImpl::commitToMemory()
525 {
526     std::lock_guard<std::mutex> lock(mutex_);
527     int64_t memoryStateGeneration = -1;
528     std::list<std::string> keysModified;
529     std::vector<std::weak_ptr<PreferencesObserver>> preferencesObservers;
530     std::map<std::string, PreferencesValue> writeToDiskMap;
531     writeToDiskMap = map_;
532     if (!modifiedKeys_.empty()) {
533         currentMemoryStateGeneration_++;
534         keysModified = modifiedKeys_;
535         modifiedKeys_.clear();
536     }
537     memoryStateGeneration = currentMemoryStateGeneration_;
538     preferencesObservers = localObservers_;
539     return std::make_shared<MemoryToDiskRequest>(
540         writeToDiskMap, keysModified, preferencesObservers, memoryStateGeneration);
541 }
542 
notifyPreferencesObserver(const PreferencesImpl::MemoryToDiskRequest & request)543 void PreferencesImpl::notifyPreferencesObserver(const PreferencesImpl::MemoryToDiskRequest &request)
544 {
545     if (request.keysModified_.empty()) {
546         return;
547     }
548 
549     auto dataObsMgrClient = DataObsMgrClient::GetInstance();
550     for (auto key = request.keysModified_.begin(); key != request.keysModified_.end(); ++key) {
551         for (auto it = request.localObservers_.begin(); it != request.localObservers_.end(); ++it) {
552             std::weak_ptr<PreferencesObserver> weakPreferencesObserver = *it;
553             if (std::shared_ptr<PreferencesObserver> sharedPreferencesObserver = weakPreferencesObserver.lock()) {
554                 sharedPreferencesObserver->OnChange(*key);
555             }
556         }
557 
558         if (dataObsMgrClient == nullptr) {
559             continue;
560         }
561         dataObsMgrClient->NotifyChange(MakeUri(*key));
562     }
563 }
564 
MemoryToDiskRequest(const std::map<std::string,PreferencesValue> & writeToDiskMap,const std::list<std::string> & keysModified,const std::vector<std::weak_ptr<PreferencesObserver>> preferencesObservers,int64_t memStataGeneration)565 PreferencesImpl::MemoryToDiskRequest::MemoryToDiskRequest(
566     const std::map<std::string, PreferencesValue> &writeToDiskMap, const std::list<std::string> &keysModified,
567     const std::vector<std::weak_ptr<PreferencesObserver>> preferencesObservers, int64_t memStataGeneration)
568 {
569     writeToDiskMap_ = writeToDiskMap;
570     keysModified_ = keysModified;
571     localObservers_ = preferencesObservers;
572     memoryStateGeneration_ = memStataGeneration;
573     isSyncRequest_ = false;
574     wasWritten_ = false;
575     writeToDiskResult_ = E_ERROR;
576 }
577 
SetDiskWriteResult(bool wasWritten,int result)578 void PreferencesImpl::MemoryToDiskRequest::SetDiskWriteResult(bool wasWritten, int result)
579 {
580     writeToDiskResult_ = result;
581     wasWritten_ = wasWritten;
582     reqCond_.notify_one();
583 }
584 } // End of namespace NativePreferences
585 } // End of namespace OHOS
586