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