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