1 /*
2 * Copyright (c) 2024 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 #include "preferences_helper.h"
16
17 #include <string>
18 #include <variant>
19 #include <vector>
20 #include <map>
21
22 #include "ffi_remote_data.h"
23 #include "securec.h"
24 #include "preferences.h"
25 #include "preferences_errno.h"
26 #include "preferences_impl.h"
27 #include "preferences_value.h"
28 #include "preferences_utils.h"
29 #include "preferences_errno.h"
30 #include "preferences_log.h"
31
32 using namespace OHOS::Preferences;
33 using namespace OHOS::FFI;
34 using namespace OHOS::NativePreferences;
35
36 namespace OHOS::Preferences {
GetInstancePath(OHOS::AbilityRuntime::Context * context,const std::string & name,const std::string & dataGroupId)37 std::tuple<int32_t, std::string> GetInstancePath(OHOS::AbilityRuntime::Context* context, const std::string &name,
38 const std::string &dataGroupId)
39 {
40 std::string path;
41 if (context == nullptr) {
42 LOGE("The context is nullptr.");
43 return {E_ERROR, path};
44 }
45 int32_t errcode = 0;
46 auto tempContext = std::make_shared<HelperAysncContext>();
47 tempContext->bundleName = context->GetBundleName();
48 tempContext->name = name;
49 std::string preferencesDir;
50 errcode = context->GetSystemPreferencesDir(dataGroupId, false, preferencesDir);
51 if (errcode != 0) {
52 return {errcode, path};
53 }
54 tempContext->path = preferencesDir.append("/").append(tempContext->name);
55 return {E_OK, tempContext->path};
56 }
57
PreferencesImpl(OHOS::AbilityRuntime::Context * context,const std::string & name,const std::string & dataGroupId,int32_t * errCode)58 PreferencesImpl::PreferencesImpl(OHOS::AbilityRuntime::Context* context,
59 const std::string& name, const std::string& dataGroupId, int32_t* errCode)
60 {
61 if (context == nullptr) {
62 LOGE("Failed to get native context instance");
63 *errCode = -1;
64 return;
65 }
66 auto [code, path] = GetInstancePath(context, name, dataGroupId);
67 if (code != E_OK) {
68 *errCode = code;
69 return;
70 }
71 NativePreferences::Options options(path, context->GetBundleName(), dataGroupId);
72 int err;
73 auto proxy = PreferencesHelper::GetPreferences(options, err);
74 *errCode = err;
75 if (err != E_OK) {
76 LOGE("Failed to get underlying preferences instance.");
77 return;
78 }
79 preferences = proxy;
80 if (preferences == nullptr) {
81 LOGE("The preferences is nullptr.");
82 return;
83 }
84 }
85
DeletePreferences(OHOS::AbilityRuntime::Context * context,const std::string & name,const std::string & dataGroupId)86 int32_t PreferencesImpl::DeletePreferences(OHOS::AbilityRuntime::Context* context, const std::string &name,
87 const std::string &dataGroupId)
88 {
89 auto [code, path] = GetInstancePath(context, name, dataGroupId);
90 if (code != E_OK) {
91 return code;
92 }
93 int errCode = PreferencesHelper::DeletePreferences(path);
94 if (errCode != E_OK) {
95 return errCode;
96 }
97 return 0;
98 }
99
RemovePreferencesFromCache(OHOS::AbilityRuntime::Context * context,const std::string & name,const std::string & dataGroupId)100 int32_t PreferencesImpl::RemovePreferencesFromCache(OHOS::AbilityRuntime::Context* context, const std::string &name,
101 const std::string &dataGroupId)
102 {
103 auto [code, path] = GetInstancePath(context, name, dataGroupId);
104 if (code != 0) {
105 return code;
106 }
107 int errCode = PreferencesHelper::RemovePreferencesFromCache(path);
108 if (errCode != E_OK) {
109 return errCode;
110 }
111 return E_OK;
112 }
113
Flush()114 void PreferencesImpl::Flush()
115 {
116 if (preferences == nullptr) {
117 LOGE("The preferences is nullptr.");
118 return;
119 }
120 preferences->FlushSync();
121 return;
122 }
123
Clear()124 void PreferencesImpl::Clear()
125 {
126 if (preferences == nullptr) {
127 LOGE("The preferences is nullptr.");
128 return;
129 }
130 preferences->Clear();
131 return;
132 }
133
Delete(const std::string & key)134 int32_t PreferencesImpl::Delete(const std::string &key)
135 {
136 if (preferences == nullptr) {
137 LOGE("The preferences is nullptr.");
138 return E_ERROR;
139 }
140 int errCode = preferences->Delete(key);
141 return errCode;
142 }
143
HasKey(const std::string & key)144 bool PreferencesImpl::HasKey(const std::string &key)
145 {
146 if (preferences == nullptr) {
147 LOGE("The preferences is nullptr.");
148 return false;
149 }
150 bool result = preferences->HasKey(key);
151 return result;
152 }
153
GetRuntimeType()154 OHOS::FFI::RuntimeType* PreferencesImpl::GetRuntimeType()
155 {
156 return GetClassType();
157 }
158
GetClassType()159 OHOS::FFI::RuntimeType* PreferencesImpl::GetClassType()
160 {
161 static OHOS::FFI::RuntimeType runtimeType =
162 OHOS::FFI::RuntimeType::Create<OHOS::FFI::FFIData>("PreferencesImpl");
163 return &runtimeType;
164 }
165
IsSameFunction(const std::function<void (std::string)> * f1,const std::function<void (std::string)> * f2)166 static bool IsSameFunction(const std::function<void(std::string)> *f1, const std::function<void(std::string)> *f2)
167 {
168 return f1 == f2;
169 }
170
ConvertToRegisterMode(const std::string & mode)171 RegisterMode PreferencesImpl::ConvertToRegisterMode(const std::string &mode)
172 {
173 return (mode == strChange) ? RegisterMode::LOCAL_CHANGE : RegisterMode::MULTI_PRECESS_CHANGE;
174 }
175
CValueTypeToNativeValue(const ValueType & value)176 static PreferencesValue CValueTypeToNativeValue(const ValueType &value)
177 {
178 NativePreferences::PreferencesValue preferencesValue = NativePreferences::PreferencesValue(-1);
179 switch (value.tag) {
180 case TYPE_INT: {
181 preferencesValue = NativePreferences::PreferencesValue(value.integer);
182 break;
183 }
184 case TYPE_DOU: {
185 preferencesValue = NativePreferences::PreferencesValue(value.float64);
186 break;
187 }
188 case TYPE_STR: {
189 preferencesValue = NativePreferences::PreferencesValue(std::string(value.string));
190 break;
191 }
192 case TYPE_BOOL: {
193 preferencesValue = NativePreferences::PreferencesValue(value.boolean);
194 break;
195 }
196 case TYPE_BOOLARR: {
197 std::vector<bool> bools = std::vector<bool>();
198 for (int64_t i = 0; i < value.boolArray.size; i++) {
199 bools.push_back(value.boolArray.head[i]);
200 }
201 preferencesValue = NativePreferences::PreferencesValue(bools);
202 break;
203 }
204 case TYPE_DOUARR: {
205 std::vector<double> doubles = std::vector<double>();
206 for (int64_t i = 0; i < value.doubleArray.size; i++) {
207 doubles.push_back(value.doubleArray.head[i]);
208 }
209 preferencesValue = NativePreferences::PreferencesValue(doubles);
210 break;
211 }
212 case TYPE_STRARR: {
213 std::vector<std::string> strings = std::vector<std::string>();
214 for (int64_t i = 0; i < value.stringArray.size; i++) {
215 strings.push_back(value.stringArray.head[i]);
216 }
217 preferencesValue = NativePreferences::PreferencesValue(strings);
218 break;
219 }
220 default:
221 preferencesValue = NativePreferences::PreferencesValue(-1);
222 break;
223 }
224 return preferencesValue;
225 }
226
FreeValueType(ValueType & v)227 static void FreeValueType(ValueType &v)
228 {
229 switch (v.tag) {
230 case TYPE_STR: {
231 free(v.string);
232 break;
233 }
234 case TYPE_BOOLARR: {
235 free(v.boolArray.head);
236 break;
237 }
238 case TYPE_DOUARR: {
239 free(v.doubleArray.head);
240 break;
241 }
242 case TYPE_STRARR: {
243 for (int64_t i = 0; i < v.stringArray.size; i++) {
244 free(v.stringArray.head[i]);
245 }
246 free(v.stringArray.head);
247 break;
248 }
249 default:
250 break;
251 }
252 }
253
FreeValueTypes(ValueType * v,int count)254 static void FreeValueTypes(ValueType *v, int count)
255 {
256 for (int i = 0; i < count; i++) {
257 FreeValueType(v[i]);
258 }
259 }
260
VectorToDoubleArray(const std::vector<double> & doubles,int32_t & code)261 static CArrDouble VectorToDoubleArray(const std::vector<double> &doubles, int32_t &code)
262 {
263 if (doubles.size() == 0) {
264 return CArrDouble{0};
265 }
266 double* head = static_cast<double*>(malloc(doubles.size() * sizeof(double)));
267 if (head == nullptr) {
268 code = E_ERROR;
269 return CArrDouble{0};
270 }
271 for (unsigned long i = 0; i < doubles.size(); i++) {
272 head[i] = doubles[i];
273 }
274 CArrDouble doubleArray = { head, doubles.size() };
275 return doubleArray;
276 }
277
VectorToBoolArray(std::vector<bool> & bools,int32_t & code)278 static CArrBool VectorToBoolArray(std::vector<bool> &bools, int32_t &code)
279 {
280 if (bools.size() == 0) {
281 return CArrBool{0};
282 }
283 bool* head = static_cast<bool*>(malloc(bools.size() * sizeof(bool)));
284 if (head == nullptr) {
285 code = E_ERROR;
286 return CArrBool{0};
287 }
288 for (unsigned long i = 0; i < bools.size(); i++) {
289 head[i] = bools[i];
290 }
291 CArrBool boolArray = { head, bools.size() };
292 return boolArray;
293 }
294
FreeCharPointer(char ** ptr,int count)295 static void FreeCharPointer(char** ptr, int count)
296 {
297 for (int i = 0; i < count; i++) {
298 free(ptr[i]);
299 }
300 }
301
VectorToCharPointer(std::vector<std::string> & vec,int32_t & code)302 static char** VectorToCharPointer(std::vector<std::string> &vec, int32_t &code)
303 {
304 if (vec.size() == 0) {
305 return nullptr;
306 }
307 char** result = static_cast<char**>(malloc(sizeof(char*) * vec.size()));
308 if (result == nullptr) {
309 code = E_ERROR;
310 return nullptr;
311 }
312 for (size_t i = 0; i < vec.size(); i++) {
313 result[i] = MallocCString(vec[i]);
314 if (result[i] == nullptr) {
315 FreeCharPointer(result, i);
316 free(result);
317 code = E_ERROR;
318 return nullptr;
319 }
320 }
321 return result;
322 }
323
VectorToStringArray(std::vector<std::string> & strings,int32_t & code)324 static CArrStr VectorToStringArray(std::vector<std::string> &strings, int32_t &code)
325 {
326 CArrStr strArray;
327 strArray.size = static_cast<int64_t>(strings.size());
328 strArray.head = VectorToCharPointer(strings, code);
329 if (code != E_OK) {
330 return CArrStr{0};
331 }
332 return strArray;
333 }
334
NativeValueToCValueType(const PreferencesValue & pValue,int32_t & code)335 static ValueType NativeValueToCValueType(const PreferencesValue &pValue, int32_t &code)
336 {
337 ValueType v = {0};
338 if (pValue.IsInt()) {
339 v.integer = (int64_t)std::get<int>(pValue.value_);
340 v.tag = TYPE_INT;
341 } else if (pValue.IsLong()) {
342 v.integer = std::get<int64_t>(pValue.value_);
343 v.tag = TYPE_INT;
344 } else if (pValue.IsFloat()) {
345 v.float64 = (double)std::get<float>(pValue.value_);
346 v.tag = TYPE_DOU;
347 } else if (pValue.IsDouble()) {
348 v.float64 = std::get<double>(pValue.value_);
349 v.tag = TYPE_DOU;
350 } else if (pValue.IsString()) {
351 auto pValueStr = std::get<std::string>(pValue.value_);
352 char* pValueChar = MallocCString(pValueStr);
353 v.string = pValueChar;
354 v.tag = TYPE_STR;
355 } else if (pValue.IsBool()) {
356 v.boolean = std::get<bool>(pValue.value_);
357 v.tag = TYPE_BOOL;
358 } else if (pValue.IsBoolArray()) {
359 auto boolVector = std::get<std::vector<bool>>(pValue.value_);
360 v.boolArray = VectorToBoolArray(boolVector, code);
361 v.tag = TYPE_BOOLARR;
362 } else if (pValue.IsDoubleArray()) {
363 auto doubleVector = std::get<std::vector<double>>(pValue.value_);
364 v.doubleArray = VectorToDoubleArray(doubleVector, code);
365 v.tag = TYPE_DOUARR;
366 } else if (pValue.IsStringArray()) {
367 auto stringVector = std::get<std::vector<std::string>>(pValue.value_);
368 v.stringArray = VectorToStringArray(stringVector, code);
369 v.tag = TYPE_STRARR;
370 } else {
371 v.tag = -1;
372 }
373 return v;
374 }
375
NativeValuesToCValueTypes(const std::map<std::string,PreferencesValue> & objects,int32_t & code)376 static ValueTypes NativeValuesToCValueTypes(const std::map<std::string, PreferencesValue> &objects, int32_t &code)
377 {
378 ValueTypes valueTypes = {0};
379 valueTypes.size = static_cast<int64_t>(objects.size());
380 valueTypes.key = static_cast<char**>(malloc(valueTypes.size * sizeof(char*)));
381 if (valueTypes.key == nullptr) {
382 code = E_ERROR;
383 return valueTypes;
384 }
385 valueTypes.head = static_cast<ValueType*>(malloc(valueTypes.size * sizeof(ValueType)));
386 if (valueTypes.head == nullptr) {
387 free(valueTypes.key);
388 code = E_ERROR;
389 return valueTypes;
390 }
391 int i = 0;
392 for (auto const& [key, value] : objects) {
393 valueTypes.key[i] = MallocCString(key);
394 if (valueTypes.key[i] == nullptr) {
395 FreeCharPointer(valueTypes.key, i);
396 FreeValueTypes(valueTypes.head, i);
397 free(valueTypes.key);
398 free(valueTypes.head);
399 code = E_ERROR;
400 return valueTypes;
401 }
402 valueTypes.head[i] = NativeValueToCValueType(value, code);
403 if (code != E_OK) {
404 free(valueTypes.key[i]);
405 FreeCharPointer(valueTypes.key, i);
406 FreeValueTypes(valueTypes.head, i);
407 free(valueTypes.key);
408 free(valueTypes.head);
409 code = E_ERROR;
410 return valueTypes;
411 }
412 i++;
413 }
414 return valueTypes;
415 }
416
Get(const std::string & key,const ValueType & defValue)417 ValueType PreferencesImpl::Get(const std::string &key, const ValueType &defValue)
418 {
419 if (preferences == nullptr) {
420 LOGE("The preferences is nullptr.");
421 return ValueType{0};
422 }
423 PreferencesValue p = CValueTypeToNativeValue(defValue);
424 int32_t err = E_OK;
425 ValueType v = NativeValueToCValueType(preferences->Get(key, p), err);
426 if (err != E_OK) {
427 return ValueType{0};
428 }
429 return v;
430 }
431
Put(const std::string & key,const ValueType & value)432 int32_t PreferencesImpl::Put(const std::string &key, const ValueType &value)
433 {
434 if (preferences == nullptr) {
435 LOGE("The preferences is nullptr.");
436 return E_ERROR;
437 }
438 return preferences->Put(key, CValueTypeToNativeValue(value));
439 }
440
GetAll()441 ValueTypes PreferencesImpl::GetAll()
442 {
443 if (preferences == nullptr) {
444 LOGE("The preferences is nullptr.");
445 return ValueTypes{0};
446 }
447 int32_t err = E_OK;
448 ValueTypes vs = NativeValuesToCValueTypes(preferences->GetAll(), err);
449 if (err != E_OK) {
450 return ValueTypes{0};
451 }
452 return vs;
453 }
454
RegisterObserver(const std::string & mode,std::function<void (std::string)> * callback,const std::function<void (std::string)> & callbackRef)455 int32_t PreferencesImpl::RegisterObserver(const std::string &mode, std::function<void(std::string)> *callback,
456 const std::function<void(std::string)>& callbackRef)
457 {
458 std::lock_guard<std::mutex> lck(listMutex_);
459 auto observer = std::make_shared<CJPreferencesObserver>(callback, callbackRef);
460 if (preferences == nullptr) {
461 LOGE("The preferences is nullptr.");
462 return E_ERROR;
463 }
464 int errCode = preferences->RegisterObserver(observer, ConvertToRegisterMode(mode));
465 if (errCode != E_OK) {
466 return errCode;
467 }
468 auto &observers = (ConvertToRegisterMode(mode) == RegisterMode::LOCAL_CHANGE) ?
469 localObservers_ : multiProcessObservers_;
470 observers.push_back(observer);
471 return E_OK;
472 }
473
UnRegisterObserver(const std::string & mode,std::function<void (std::string)> * callback)474 int32_t PreferencesImpl::UnRegisterObserver(const std::string &mode, std::function<void(std::string)> *callback)
475 {
476 std::lock_guard<std::mutex> lck(listMutex_);
477 auto &observers = (ConvertToRegisterMode(mode) == RegisterMode::LOCAL_CHANGE) ?
478 localObservers_ : multiProcessObservers_;
479 auto it = observers.begin();
480 if (preferences == nullptr) {
481 LOGE("The preferences is nullptr.");
482 return E_ERROR;
483 }
484 while (it != observers.end()) {
485 if (IsSameFunction(callback, (*it)->m_callback)) {
486 int errCode = preferences->UnRegisterObserver(*it, ConvertToRegisterMode(mode));
487 if (errCode != E_OK) {
488 return errCode;
489 }
490 it = observers.erase(it);
491 break; // specified observer is current iterator
492 }
493 ++it;
494 }
495 return E_OK;
496 }
497
UnRegisteredAllObservers(const std::string & mode)498 int32_t PreferencesImpl::UnRegisteredAllObservers(const std::string &mode)
499 {
500 std::lock_guard<std::mutex> lck(listMutex_);
501 auto &observers = (ConvertToRegisterMode(mode) == RegisterMode::LOCAL_CHANGE) ?
502 localObservers_ : multiProcessObservers_;
503 bool hasFailed = false;
504 int errCode;
505 if (preferences == nullptr) {
506 LOGE("The preferences is nullptr.");
507 return E_ERROR;
508 }
509 for (auto &observer : observers) {
510 errCode = preferences->UnRegisterObserver(observer, ConvertToRegisterMode(mode));
511 if (errCode != E_OK) {
512 hasFailed = true;
513 }
514 }
515 observers.clear();
516 return hasFailed ? E_ERROR : E_OK;
517 }
518
CJPreferencesObserver(std::function<void (std::string)> * callback,const std::function<void (std::string)> & callbackRef)519 CJPreferencesObserver::CJPreferencesObserver(std::function<void(std::string)> *callback,
520 const std::function<void(std::string)>& callbackRef)
521 {
522 if (callback == nullptr) {
523 LOGI("WARNING: nullptr");
524 }
525 m_callback = callback;
526 m_callbackRef = callbackRef;
527 }
528
OnChange(const std::string & key)529 void CJPreferencesObserver::OnChange(const std::string &key)
530 {
531 m_callbackRef(key);
532 }
533 }
534