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