• 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 "napi_preferences.h"
17 
18 #include <cerrno>
19 #include <climits>
20 #include <cmath>
21 #include <list>
22 
23 #include "napi_async_call.h"
24 #include "napi_preferences_error.h"
25 #include "preferences.h"
26 #include "preferences_errno.h"
27 #include "preferences_value.h"
28 #include "securec.h"
29 
30 using namespace OHOS::NativePreferences;
31 
32 namespace OHOS {
33 namespace PreferencesJsKit {
34 #define MAX_KEY_LENGTH Preferences::MAX_KEY_LENGTH
35 #define MAX_VALUE_LENGTH Preferences::MAX_VALUE_LENGTH
36 
37 struct PreferencesAysncContext : public BaseContext {
38     std::string key;
39     PreferencesValue defValue = PreferencesValue(static_cast<int64_t>(0));
40     napi_ref inputValueRef = nullptr;
41     std::map<std::string, PreferencesValue> allElements;
42     bool hasKey = false;
43     std::list<std::string> keysModified;
44     std::vector<std::weak_ptr<PreferencesObserver>> preferencesObservers;
45 
PreferencesAysncContextOHOS::PreferencesJsKit::PreferencesAysncContext46     PreferencesAysncContext()
47     {
48     }
~PreferencesAysncContextOHOS::PreferencesJsKit::PreferencesAysncContext49     virtual ~PreferencesAysncContext(){};
50 };
51 
52 static __thread napi_ref constructor_;
53 
PreferencesProxy()54 PreferencesProxy::PreferencesProxy()
55     : value_(nullptr), env_(nullptr), uvQueue_(nullptr)
56 {
57 }
58 
~PreferencesProxy()59 PreferencesProxy::~PreferencesProxy()
60 {
61     UnRegisteredAllObservers(RegisterMode::LOCAL_CHANGE);
62     UnRegisteredAllObservers(RegisterMode::MULTI_PRECESS_CHANGE);
63 }
64 
Destructor(napi_env env,void * nativeObject,void * finalize_hint)65 void PreferencesProxy::Destructor(napi_env env, void *nativeObject, void *finalize_hint)
66 {
67     PreferencesProxy *obj = static_cast<PreferencesProxy *>(nativeObject);
68     delete obj;
69 }
70 
Init(napi_env env,napi_value exports)71 void PreferencesProxy::Init(napi_env env, napi_value exports)
72 {
73     napi_property_descriptor descriptors[] = {
74         DECLARE_NAPI_FUNCTION_WITH_DATA("put", SetValue, ASYNC),
75         DECLARE_NAPI_FUNCTION_WITH_DATA("putSync", SetValue, SYNC),
76         DECLARE_NAPI_FUNCTION_WITH_DATA("get", GetValue, ASYNC),
77         DECLARE_NAPI_FUNCTION_WITH_DATA("getSync", GetValue, SYNC),
78         DECLARE_NAPI_FUNCTION_WITH_DATA("getAll", GetAll, ASYNC),
79         DECLARE_NAPI_FUNCTION_WITH_DATA("getAllSync", GetAll, SYNC),
80         DECLARE_NAPI_FUNCTION_WITH_DATA("delete", Delete, ASYNC),
81         DECLARE_NAPI_FUNCTION_WITH_DATA("deleteSync", Delete, SYNC),
82         DECLARE_NAPI_FUNCTION_WITH_DATA("clear", Clear, ASYNC),
83         DECLARE_NAPI_FUNCTION_WITH_DATA("clearSync", Clear, SYNC),
84         DECLARE_NAPI_FUNCTION_WITH_DATA("has", HasKey, ASYNC),
85         DECLARE_NAPI_FUNCTION_WITH_DATA("hasSync", HasKey, SYNC),
86         DECLARE_NAPI_FUNCTION_WITH_DATA("flush", Flush, ASYNC),
87         DECLARE_NAPI_FUNCTION_WITH_DATA("flushSync", Flush, SYNC),
88         DECLARE_NAPI_FUNCTION("on", RegisterObserver),
89         DECLARE_NAPI_FUNCTION("off", UnRegisterObserver),
90     };
91 
92     napi_value cons = nullptr;
93     napi_define_class(env, "Preferences", NAPI_AUTO_LENGTH, New, nullptr,
94         sizeof(descriptors) / sizeof(napi_property_descriptor), descriptors, &cons);
95 
96     napi_create_reference(env, cons, 1, &constructor_);
97 }
98 
NewInstance(napi_env env,std::shared_ptr<OHOS::NativePreferences::Preferences> value,napi_value * instance)99 napi_status PreferencesProxy::NewInstance(
100     napi_env env, std::shared_ptr<OHOS::NativePreferences::Preferences> value, napi_value *instance)
101 {
102     if (value == nullptr) {
103         LOG_ERROR("PreferencesProxy::NewInstance get native preferences is null");
104         return napi_invalid_arg;
105     }
106     napi_value cons;
107     napi_status status = napi_get_reference_value(env, constructor_, &cons);
108     if (status != napi_ok) {
109         return status;
110     }
111 
112     status = napi_new_instance(env, cons, 0, nullptr, instance);
113     if (status != napi_ok) {
114         return status;
115     }
116 
117     PreferencesProxy *obj = new (std::nothrow) PreferencesProxy();
118     if (obj == nullptr) {
119         LOG_ERROR("PreferencesProxy::New new failed, obj is nullptr");
120         return napi_invalid_arg;
121     }
122     obj->value_ = value;
123     obj->env_ = env;
124     obj->uvQueue_ = std::make_shared<UvQueue>(env);
125     status = napi_wrap(env, *instance, obj, PreferencesProxy::Destructor, nullptr, nullptr);
126     if (status != napi_ok) {
127         delete obj;
128         return status;
129     }
130 
131     return napi_ok;
132 }
133 
New(napi_env env,napi_callback_info info)134 napi_value PreferencesProxy::New(napi_env env, napi_callback_info info)
135 {
136     napi_value thiz = nullptr;
137     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thiz, nullptr));
138     if (thiz == nullptr) {
139         LOG_WARN("get this failed");
140         return nullptr;
141     }
142     return thiz;
143 }
144 
ParseKey(napi_env env,const napi_value arg,std::shared_ptr<PreferencesAysncContext> context)145 int ParseKey(napi_env env, const napi_value arg, std::shared_ptr<PreferencesAysncContext> context)
146 {
147     int32_t rc = JSUtils::Convert2NativeValue(env, arg, context->key);
148     PRE_CHECK_RETURN_ERR_SET(rc == napi_ok, std::make_shared<ParamTypeError>("value", "string."));
149     PRE_CHECK_RETURN_ERR_SET(context->key.length() <= MAX_KEY_LENGTH,
150         std::make_shared<ParamTypeError>("key", "less than 80 bytes."));
151     return OK;
152 }
153 
ParseDefValue(const napi_env env,const napi_value jsVal,std::shared_ptr<PreferencesAysncContext> context)154 int ParseDefValue(const napi_env env, const napi_value jsVal, std::shared_ptr<PreferencesAysncContext> context)
155 {
156     int32_t rc = JSUtils::Convert2NativeValue(env, jsVal, context->defValue.value_);
157     PRE_CHECK_RETURN_ERR_SET(rc == napi_ok, std::make_shared<ParamTypeError>("value", "ValueType."));
158     return OK;
159 }
160 
GetAllExecute(napi_env env,std::shared_ptr<PreferencesAysncContext> context,napi_value & result)161 int GetAllExecute(napi_env env, std::shared_ptr<PreferencesAysncContext> context, napi_value &result)
162 {
163     napi_create_object(env, &result);
164     for (const auto &[key, value] : context->allElements) {
165         napi_set_named_property(env, result, key.c_str(), JSUtils::Convert2JSValue(env, value.value_));
166     }
167     return OK;
168 }
169 
GetAll(napi_env env,napi_callback_info info)170 napi_value PreferencesProxy::GetAll(napi_env env, napi_callback_info info)
171 {
172     LOG_DEBUG("GetAll start");
173     auto context = std::make_shared<PreferencesAysncContext>();
174     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
175         PRE_CHECK_RETURN_VOID_SET(argc == 0, std::make_shared<ParamNumError>("0 or 1"));
176         napi_unwrap(env, self, &context->boundObj);
177         PRE_CHECK_RETURN_VOID_SET(context->boundObj != nullptr,
178             std::make_shared<InnerError>("Failed to unwrap when getting all."));
179     };
180     auto exec = [context]() -> int {
181         PreferencesProxy *obj = reinterpret_cast<PreferencesProxy *>(context->boundObj);
182         context->allElements = obj->value_->GetAll();
183         return OK;
184     };
185     auto output = [context](napi_env env, napi_value &result) {
186         GetAllExecute(env, context, result);
187     };
188     context->SetAction(env, info, input, exec, output);
189 
190     PRE_CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
191     return AsyncCall::Call(env, context, "GetAll");
192 }
193 
GetValue(napi_env env,napi_callback_info info)194 napi_value PreferencesProxy::GetValue(napi_env env, napi_callback_info info)
195 {
196     LOG_DEBUG("GetValue start");
197     auto context = std::make_shared<PreferencesAysncContext>();
198     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
199         PRE_CHECK_RETURN_VOID_SET(argc == 2, std::make_shared<ParamNumError>("2 or 3"));
200         PRE_CHECK_RETURN_VOID(ParseKey(env, argv[0], context) == OK);
201         napi_create_reference(env, argv[1], 1, &context->inputValueRef);
202         napi_unwrap(env, self, &context->boundObj);
203         PRE_CHECK_RETURN_VOID_SET(context->boundObj != nullptr,
204             std::make_shared<InnerError>("Failed to unwrap when getting value."));
205     };
206     auto exec = [context]() -> int {
207         PreferencesProxy *obj = reinterpret_cast<PreferencesProxy *>(context->boundObj);
208         context->defValue = obj->value_->Get(context->key, context->defValue);
209         return OK;
210     };
211     auto output = [context](napi_env env, napi_value &result) {
212         if (context->defValue.IsLong()) {
213             LOG_DEBUG("GetValue get default value.");
214             napi_get_reference_value(env, context->inputValueRef, &result);
215         } else {
216             result = JSUtils::Convert2JSValue(env, context->defValue.value_);
217         }
218         napi_delete_reference(env, context->inputValueRef);
219         PRE_CHECK_RETURN_VOID_SET(result != nullptr,
220             std::make_shared<InnerError>("Failed to delete reference when getting value."));
221     };
222     context->SetAction(env, info, input, exec, output);
223 
224     PRE_CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
225     return AsyncCall::Call(env, context, "GetValue");
226 }
227 
SetValue(napi_env env,napi_callback_info info)228 napi_value PreferencesProxy::SetValue(napi_env env, napi_callback_info info)
229 {
230     LOG_DEBUG("SetValue start");
231     auto context = std::make_shared<PreferencesAysncContext>();
232     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
233         PRE_CHECK_RETURN_VOID_SET(argc == 2, std::make_shared<ParamNumError>("2 or 3"));
234         PRE_CHECK_RETURN_VOID(ParseKey(env, argv[0], context) == OK);
235         PRE_CHECK_RETURN_VOID(ParseDefValue(env, argv[1], context) == OK);
236         napi_unwrap(env, self, &context->boundObj);
237         PRE_CHECK_RETURN_VOID_SET(context->boundObj != nullptr,
238             std::make_shared<InnerError>("Failed to unwrap when setting value."));
239     };
240     auto exec = [context]() -> int {
241         PreferencesProxy *obj = reinterpret_cast<PreferencesProxy *>(context->boundObj);
242         return obj->value_->Put(context->key, context->defValue);
243     };
244     auto output = [context](napi_env env, napi_value &result) {
245         napi_status status = napi_get_undefined(env, &result);
246         PRE_CHECK_RETURN_VOID_SET(status == napi_ok,
247             std::make_shared<InnerError>("Failed to get undefined when setting value."));
248         LOG_DEBUG("SetValue end.");
249     };
250     context->SetAction(env, info, input, exec, output);
251 
252     PRE_CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
253     return AsyncCall::Call(env, context, "SetValue");
254 }
255 
Delete(napi_env env,napi_callback_info info)256 napi_value PreferencesProxy::Delete(napi_env env, napi_callback_info info)
257 {
258     LOG_DEBUG("Delete start");
259     auto context = std::make_shared<PreferencesAysncContext>();
260     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
261         PRE_CHECK_RETURN_VOID_SET(argc == 1, std::make_shared<ParamNumError>("1 or 2"));
262         PRE_CHECK_RETURN_VOID(ParseKey(env, argv[0], context) == OK);
263         napi_unwrap(env, self, &context->boundObj);
264         PRE_CHECK_RETURN_VOID_SET(context->boundObj != nullptr,
265             std::make_shared<InnerError>("Failed to unwrap when deleting value."));
266     };
267     auto exec = [context]() -> int {
268         PreferencesProxy *obj = reinterpret_cast<PreferencesProxy *>(context->boundObj);
269         return obj->value_->Delete(context->key);
270     };
271     auto output = [context](napi_env env, napi_value &result) {
272         napi_status status = napi_get_undefined(env, &result);
273         PRE_CHECK_RETURN_VOID_SET(status == napi_ok,
274             std::make_shared<InnerError>("Failed to get undefined when deleting value."));
275         LOG_DEBUG("Delete end.");
276     };
277     context->SetAction(env, info, input, exec, output);
278 
279     PRE_CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
280     return AsyncCall::Call(env, context, "Delete");
281 }
282 
HasKey(napi_env env,napi_callback_info info)283 napi_value PreferencesProxy::HasKey(napi_env env, napi_callback_info info)
284 {
285     LOG_DEBUG("HasKey start");
286     auto context = std::make_shared<PreferencesAysncContext>();
287     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
288         PRE_CHECK_RETURN_VOID_SET(argc == 1, std::make_shared<ParamNumError>("1 or 2"));
289         PRE_CHECK_RETURN_VOID(ParseKey(env, argv[0], context) == OK);
290         napi_unwrap(env, self, &context->boundObj);
291         PRE_CHECK_RETURN_VOID_SET(context->boundObj != nullptr,
292             std::make_shared<InnerError>("Failed to unwrap when having key."));
293     };
294     auto exec = [context]() -> int {
295         PreferencesProxy *obj = reinterpret_cast<PreferencesProxy *>(context->boundObj);
296         context->hasKey = obj->value_->HasKey(context->key);
297         return OK;
298     };
299     auto output = [context](napi_env env, napi_value &result) {
300         napi_status status = napi_get_boolean(env, context->hasKey, &result);
301         PRE_CHECK_RETURN_VOID_SET(status == napi_ok,
302             std::make_shared<InnerError>("Failed to get boolean when having key."));
303         LOG_DEBUG("HasKey end.");
304     };
305     context->SetAction(env, info, input, exec, output);
306 
307     PRE_CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
308     return AsyncCall::Call(env, context, "HasKey");
309 }
310 
Flush(napi_env env,napi_callback_info info)311 napi_value PreferencesProxy::Flush(napi_env env, napi_callback_info info)
312 {
313     LOG_DEBUG("Flush start");
314     auto context = std::make_shared<PreferencesAysncContext>();
315     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
316         PRE_CHECK_RETURN_VOID_SET(argc == 0, std::make_shared<ParamNumError>("0 or 1"));
317         napi_unwrap(env, self, &context->boundObj);
318         PRE_CHECK_RETURN_VOID_SET(context->boundObj != nullptr,
319             std::make_shared<InnerError>("Failed to unwrap when flushing."));
320     };
321     auto exec = [context]() -> int {
322         PreferencesProxy *obj = reinterpret_cast<PreferencesProxy *>(context->boundObj);
323         return obj->value_->FlushSync();
324     };
325     auto output = [context](napi_env env, napi_value &result) {
326         napi_status status = napi_get_undefined(env, &result);
327         PRE_CHECK_RETURN_VOID_SET(status == napi_ok,
328             std::make_shared<InnerError>("Failed to get undefined when flushing."));
329         LOG_DEBUG("Flush end.");
330     };
331     context->SetAction(env, info, input, exec, output);
332 
333     PRE_CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
334     return AsyncCall::Call(env, context, "Flush");
335 }
336 
Clear(napi_env env,napi_callback_info info)337 napi_value PreferencesProxy::Clear(napi_env env, napi_callback_info info)
338 {
339     LOG_DEBUG("Clear start");
340     auto context = std::make_shared<PreferencesAysncContext>();
341     auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) {
342         PRE_CHECK_RETURN_VOID_SET(argc == 0, std::make_shared<ParamNumError>("0 or 1"));
343         napi_unwrap(env, self, &context->boundObj);
344         PRE_CHECK_RETURN_VOID_SET(context->boundObj != nullptr,
345             std::make_shared<InnerError>("Failed to unwrap unwrap when clearing."));
346     };
347     auto exec = [context]() -> int {
348         PreferencesProxy *obj = reinterpret_cast<PreferencesProxy *>(context->boundObj);
349         return obj->value_->Clear();
350     };
351     auto output = [context](napi_env env, napi_value &result) {
352         napi_status status = napi_get_undefined(env, &result);
353         PRE_CHECK_RETURN_VOID_SET(status == napi_ok,
354             std::make_shared<InnerError>("Failed to get undefined when clearing."));
355         LOG_DEBUG("Clear end.");
356     };
357     context->SetAction(env, info, input, exec, output);
358 
359     PRE_CHECK_RETURN_NULL(context->error == nullptr || context->error->GetCode() == OK);
360     return AsyncCall::Call(env, context, "Clear");
361 }
362 
RegisterObserver(napi_env env,napi_callback_info info)363 napi_value PreferencesProxy::RegisterObserver(napi_env env, napi_callback_info info)
364 {
365     napi_value thiz = nullptr;
366     const size_t requireArgc = 2;
367     size_t argc = 2;
368     napi_value args[2] = { 0 };
369 
370     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thiz, nullptr));
371     PRE_NAPI_ASSERT(env, argc == requireArgc, std::make_shared<ParamNumError>("2"));
372     napi_valuetype type;
373     NAPI_CALL(env, napi_typeof(env, args[0], &type));
374     PRE_NAPI_ASSERT(env, type == napi_string,
375         std::make_shared<ParamTypeError>("registerMode", "string 'change or multiProcessChange'."));
376     std::string registerMode;
377     JSUtils::Convert2NativeValue(env, args[0], registerMode);
378     PRE_NAPI_ASSERT(env, registerMode == STR_CHANGE || registerMode == STR_MULTI_PRECESS_CHANGE,
379         std::make_shared<ParamTypeError>("registerMode", "string 'change or multiProcessChange'."));
380 
381     NAPI_CALL(env, napi_typeof(env, args[1], &type));
382     PRE_NAPI_ASSERT(env, type == napi_function, std::make_shared<ParamTypeError>("callback", "function type."));
383 
384     PreferencesProxy *obj = nullptr;
385     NAPI_CALL(env, napi_unwrap(env, thiz, reinterpret_cast<void **>(&obj)));
386     int errCode = obj->RegisteredObserver(args[1], ConvertToRegisterMode(registerMode));
387     PRE_NAPI_ASSERT(env, errCode == OK, std::make_shared<InnerError>(errCode));
388 
389     return nullptr;
390 }
391 
UnRegisterObserver(napi_env env,napi_callback_info info)392 napi_value PreferencesProxy::UnRegisterObserver(napi_env env, napi_callback_info info)
393 {
394     napi_value thiz = nullptr;
395     const size_t requireArgc = 2;
396     size_t argc = 2;
397     napi_value args[2] = { 0 };
398 
399     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thiz, nullptr));
400     PRE_NAPI_ASSERT(env, argc > 0 && argc <= requireArgc, std::make_shared<ParamNumError>("1 or 2"));
401 
402     napi_valuetype type;
403     NAPI_CALL(env, napi_typeof(env, args[0], &type));
404     PRE_NAPI_ASSERT(env, type == napi_string,
405         std::make_shared<ParamTypeError>("registerMode", "string change or multiProcessChange."));
406 
407     std::string registerMode;
408     JSUtils::Convert2NativeValue(env, args[0], registerMode);
409     PRE_NAPI_ASSERT(env, registerMode == STR_CHANGE || registerMode == STR_MULTI_PRECESS_CHANGE,
410         std::make_shared<ParamTypeError>("registerMode", "string change or multiProcessChange."));
411 
412     if (argc == requireArgc) {
413         NAPI_CALL(env, napi_typeof(env, args[1], &type));
414         PRE_NAPI_ASSERT(env, type == napi_function || type == napi_undefined || type == napi_null,
415             std::make_shared<ParamTypeError>("callback", "function type."));
416     }
417 
418     PreferencesProxy *obj = nullptr;
419     NAPI_CALL(env, napi_unwrap(env, thiz, reinterpret_cast<void **>(&obj)));
420     int errCode;
421     if (type == napi_function) {
422         errCode = obj->UnRegisteredObserver(args[1], ConvertToRegisterMode(registerMode));
423     } else {
424         errCode = obj->UnRegisteredAllObservers(ConvertToRegisterMode(registerMode));
425     }
426     PRE_NAPI_ASSERT(env, errCode == OK, std::make_shared<InnerError>(errCode));
427     return nullptr;
428 }
429 
HasRegisteredObserver(napi_value callback,RegisterMode mode)430 bool PreferencesProxy::HasRegisteredObserver(napi_value callback, RegisterMode mode)
431 {
432     auto &observers = (mode == RegisterMode::LOCAL_CHANGE) ? localObservers_ : multiProcessObservers_;
433     for (auto &it : observers) {
434         if (JSUtils::Equals(env_, callback, it->GetCallback())) {
435             LOG_INFO("The observer has already subscribed.");
436             return true;
437         }
438     }
439     return false;
440 }
441 
ConvertToRegisterMode(const std::string & mode)442 RegisterMode PreferencesProxy::ConvertToRegisterMode(const std::string &mode)
443 {
444     return (mode == STR_CHANGE) ? RegisterMode::LOCAL_CHANGE : RegisterMode::MULTI_PRECESS_CHANGE;
445 }
446 
RegisteredObserver(napi_value callback,RegisterMode mode)447 int PreferencesProxy::RegisteredObserver(napi_value callback, RegisterMode mode)
448 {
449     std::lock_guard<std::mutex> lck(listMutex_);
450     auto &observers = (mode == RegisterMode::LOCAL_CHANGE) ? localObservers_ : multiProcessObservers_;
451     if (!HasRegisteredObserver(callback, mode)) {
452         auto observer = std::make_shared<JSPreferencesObserver>(uvQueue_, callback);
453         int errCode = value_->RegisterObserver(observer, mode);
454         if (errCode != E_OK) {
455             return errCode;
456         }
457         observers.push_back(observer);
458     }
459     LOG_INFO("The observer subscribed success.");
460     return E_OK;
461 }
462 
UnRegisteredObserver(napi_value callback,RegisterMode mode)463 int PreferencesProxy::UnRegisteredObserver(napi_value callback, RegisterMode mode)
464 {
465     std::lock_guard<std::mutex> lck(listMutex_);
466     auto &observers = (mode == RegisterMode::LOCAL_CHANGE) ? localObservers_ : multiProcessObservers_;
467     auto it = observers.begin();
468     while (it != observers.end()) {
469         if (JSUtils::Equals(env_, callback, (*it)->GetCallback())) {
470             int errCode = value_->UnRegisterObserver(*it, mode);
471             if (errCode != E_OK) {
472                 return errCode;
473             }
474             (*it)->ClearCallback();
475             it = observers.erase(it);
476             LOG_INFO("The observer unsubscribed success.");
477             break; // specified observer is current iterator
478         }
479         ++it;
480     }
481     return E_OK;
482 }
483 
UnRegisteredAllObservers(RegisterMode mode)484 int PreferencesProxy::UnRegisteredAllObservers(RegisterMode mode)
485 {
486     std::lock_guard<std::mutex> lck(listMutex_);
487     auto &observers = (mode == RegisterMode::LOCAL_CHANGE) ? localObservers_ : multiProcessObservers_;
488     bool hasFailed = false;
489     int errCode = E_OK;
490     for (auto &observer : observers) {
491         errCode = value_->UnRegisterObserver(observer, mode);
492         if (errCode != E_OK) {
493             hasFailed = true;
494             LOG_ERROR("The observer unsubscribed has failed, errCode %{public}d.", errCode);
495         }
496         observer->ClearCallback();
497     }
498     observers.clear();
499     LOG_DEBUG("All observers unsubscribed success.");
500     return hasFailed ? E_ERROR : E_OK;
501 }
502 } // namespace PreferencesJsKit
503 } // namespace OHOS
504