From c41ef0fd936b0353d9db53c6cd84675a8c13ac5f Mon Sep 17 00:00:00 2001 From: wangkun Date: Mon, 27 Sep 2021 13:05:53 +0800 Subject: [PATCH] Fix Js Interface Callback crash. Signed-off-by: wangkun --- .../distributeddata/include/single_kv_store.h | 14 +++ .../distributeddata/src/single_kv_store.cpp | 89 +++++++++++++------ interfaces/jskits/distributeddata/BUILD.gn | 12 ++- 3 files changed, 82 insertions(+), 33 deletions(-) diff --git a/frameworks/jskitsimpl/distributeddata/include/single_kv_store.h b/frameworks/jskitsimpl/distributeddata/include/single_kv_store.h index 47c0b990d..dd9942fdf 100644 --- a/frameworks/jskitsimpl/distributeddata/include/single_kv_store.h +++ b/frameworks/jskitsimpl/distributeddata/include/single_kv_store.h @@ -88,8 +88,17 @@ public: std::unique_ptr snapshot) override; void OnChange(const DistributedKv::ChangeNotification ¬ification) override; private: + struct EventDataWorker { + const DataObserver *observer = nullptr; + const DistributedKv::ChangeNotification data; + EventDataWorker(const DataObserver * const & observerIn, const DistributedKv::ChangeNotification &dataIn) + : observer(observerIn), + data(dataIn.GetInsertEntries(), dataIn.GetUpdateEntries(), + dataIn.GetDeleteEntries(), dataIn.GetDeviceId(), false) {} + }; napi_ref callback_ = nullptr; napi_env env_; + uv_loop_s *loop_ = nullptr; }; class SyncObserver : public DistributedKv::KvStoreSyncCallback { @@ -98,8 +107,13 @@ public: virtual ~SyncObserver(); void SyncCompleted(const std::map &results) override; private: + struct EventDataWorker { + const SyncObserver *observer = nullptr; + std::map data; + }; napi_ref callback_ = nullptr; napi_env env_; + uv_loop_s *loop_ = nullptr; }; } #endif // OHOS_SINGLE_KV_STORE_H diff --git a/frameworks/jskitsimpl/distributeddata/src/single_kv_store.cpp b/frameworks/jskitsimpl/distributeddata/src/single_kv_store.cpp index 0150561fa..c91d54153 100644 --- a/frameworks/jskitsimpl/distributeddata/src/single_kv_store.cpp +++ b/frameworks/jskitsimpl/distributeddata/src/single_kv_store.cpp @@ -15,10 +15,13 @@ #define LOG_TAG "SingleKVStore" #include "single_kv_store.h" -#include "js_util.h" -#include "single_kvstore.h" + +#include + #include "async_call.h" +#include "js_util.h" #include "log_print.h" +#include "single_kvstore.h" using namespace OHOS::DistributedKv; namespace OHOS::DistributedData { @@ -72,6 +75,7 @@ napi_value SingleKVStore::Put(napi_env env, napi_callback_info info) { auto context = std::make_shared(); auto input = [context](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status { + // 2 is the max number of parameters NAPI_ASSERT_BASE(env, argc >= 2, " should 2 or more parameters!", napi_invalid_arg); context->key = JSUtil::Convert2String(env, argv[0]); context->value = JSUtil::Convert2Vector(env, argv[1]); @@ -84,6 +88,7 @@ napi_value SingleKVStore::Put(napi_env env, napi_callback_info info) context->status = (status != Status::SUCCESS) ? napi_generic_failure : napi_ok; }; context->SetAction(std::move(input)); + // 2 is the callback position AsyncCall asyncCall(env, info, std::dynamic_pointer_cast(context), 2); return asyncCall.Call(env, exec); } @@ -160,6 +165,7 @@ napi_value SingleKVStore::Sync(napi_env env, napi_callback_info info) size_t argc = JSUtil::MAX_ARGC; napi_value argv[JSUtil::MAX_ARGC] = {nullptr}; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr)); + // the number of parameters is greater than 2 is error NAPI_ASSERT_BASE(env, argc >= 2, "args is out of range", nullptr); NAPI_ASSERT_BASE(env, self != nullptr, "self is nullptr", nullptr); SingleKVStore *proxy = nullptr; @@ -170,8 +176,9 @@ napi_value SingleKVStore::Sync(napi_env env, napi_callback_info info) int32_t mode = int32_t(SyncMode::PUSH_PULL); napi_get_value_int32(env, argv[1], &mode); uint32_t delay = 0; + // 3 is the max number of parameters if (argc >= 3) { - napi_get_value_uint32(env, argv[2], &delay); + napi_get_value_uint32(env, argv[2], &delay); // argv[2] is the third parameter } ZLOGD("sync data %{public}d, mode:%{public}d, devices:%{public}zu", static_cast(argc), mode, devices.size()); @@ -270,6 +277,7 @@ DataObserver::DataObserver(napi_env env, napi_value callback) : env_(env) { napi_create_reference(env, callback, 1, &callback_); + napi_get_uv_event_loop(env, &loop_); } DataObserver::~DataObserver() @@ -290,23 +298,38 @@ void DataObserver::OnChange(const ChangeNotification ¬ification) notification.GetInsertEntries().size(), notification.GetUpdateEntries().size(), notification.GetDeleteEntries().size()); KvStoreObserver::OnChange(notification); - napi_value jsNotification = JSUtil::Convert2JSNotification(env_, notification); - napi_value callback = nullptr; - napi_value args[1] = {jsNotification}; - napi_get_reference_value(env_, callback_, &callback); - napi_value global = nullptr; - napi_get_global(env_, &global); - napi_value result; - napi_status status = napi_call_function(env_, global, callback, 1, args, &result); - if (status != napi_ok) { - ZLOGE("notify data change failed status:%{public}d callback:%{public}p", status, callback); - } + EventDataWorker *eventDataWorker = new EventDataWorker(this, notification); + uv_work_t *work = new uv_work_t; + work->data = eventDataWorker; + uv_queue_work(loop_, work, + [](uv_work_t *work) {}, + [](uv_work_t *work, int status) { + EventDataWorker *eventDataInner = reinterpret_cast(work->data); + napi_value jsNotification = JSUtil::Convert2JSNotification(eventDataInner->observer->env_, + eventDataInner->data); + napi_value callback = nullptr; + napi_value args[1] = {jsNotification}; + napi_get_reference_value(eventDataInner->observer->env_, eventDataInner->observer->callback_, &callback); + napi_value global = nullptr; + napi_get_global(eventDataInner->observer->env_, &global); + napi_value result; + napi_status callStatus = napi_call_function(eventDataInner->observer->env_, global, callback, + 1, args, &result); + if (callStatus != napi_ok) { + ZLOGE("notify data change failed callStatus:%{public}d callback:%{public}p", callStatus, callback); + } + delete eventDataInner; + eventDataInner = nullptr; + delete work; + work = nullptr; + }); } SyncObserver::SyncObserver(napi_env env, napi_value callback) : env_(env) { napi_create_reference(env, callback, 1, &callback_); + napi_get_uv_event_loop(env, &loop_); } SyncObserver::~SyncObserver() @@ -316,17 +339,31 @@ SyncObserver::~SyncObserver() void SyncObserver::SyncCompleted(const std::map &results) { - std::map dataMap; - for (const auto &[key, value] : results) { - dataMap.emplace(key, int32_t(value)); - } - napi_value notification = JSUtil::Convert2JSTupleArray(env_, dataMap); - napi_value callback = nullptr; - napi_value args[1] = {notification}; - napi_get_reference_value(env_, callback_, &callback); - napi_value global = nullptr; - napi_value result = nullptr; - napi_get_global(env_, &global); - napi_call_function(env_, global, callback, 1, args, &result); + EventDataWorker *eventDataWorker = new EventDataWorker(); + eventDataWorker->observer = this; + eventDataWorker->data = results; + uv_work_t *work = new uv_work_t; + work->data = eventDataWorker; + uv_queue_work(loop_, work, + [](uv_work_t *work) {}, + [](uv_work_t *work, int status) { + EventDataWorker *eventDataInner = reinterpret_cast(work->data); + std::map dataMap; + for (const auto &[key, value] : eventDataInner->data) { + dataMap.emplace(key, int32_t(value)); + } + napi_value notification = JSUtil::Convert2JSTupleArray(eventDataInner->observer->env_, dataMap); + napi_value callback = nullptr; + napi_value args[1] = {notification}; + napi_get_reference_value(eventDataInner->observer->env_, eventDataInner->observer->callback_, &callback); + napi_value global = nullptr; + napi_value result = nullptr; + napi_get_global(eventDataInner->observer->env_, &global); + napi_call_function(eventDataInner->observer->env_, global, callback, 1, args, &result); + delete eventDataInner; + eventDataInner = nullptr; + delete work; + work = nullptr; + }); } } diff --git a/interfaces/jskits/distributeddata/BUILD.gn b/interfaces/jskits/distributeddata/BUILD.gn index c57565e14..bc86872e9 100644 --- a/interfaces/jskits/distributeddata/BUILD.gn +++ b/interfaces/jskits/distributeddata/BUILD.gn @@ -19,9 +19,7 @@ group("build_module") { } ohos_copy("distributeddatamgr_declaration") { - sources = [ - "./api" - ] + sources = [ "./api" ] outputs = [ target_out_dir + "/$target_name/" ] module_source_dir = target_out_dir + "/$target_name" module_install_name = "" @@ -30,6 +28,7 @@ ohos_copy("distributeddatamgr_declaration") { ohos_shared_library("distributeddata") { include_dirs = [ "//third_party/node/src", + "//third_party/libuv/include", "//utils/native/base/include", "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata/include", "//foundation/distributeddatamgr/distributeddatamgr/frameworks/jskitsimpl/distributeddata/include", @@ -48,12 +47,11 @@ ohos_shared_library("distributeddata") { deps = [ "//foundation/ace/napi:ace_napi", "//foundation/distributeddatamgr/distributeddatamgr/interfaces/innerkits/distributeddata:distributeddata_inner", - "//utils/native/base:utils" + "//third_party/libuv:uv_static", + "//utils/native/base:utils", ] - external_deps = [ - "hiviewdfx_hilog_native:libhilog" - ] + external_deps = [ "hiviewdfx_hilog_native:libhilog" ] subsystem_name = "distributeddatamgr" relative_install_dir = "module/data" -- Gitee