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