From c5445e3cbd982cf128110982cc7c0535e51e07e9 Mon Sep 17 00:00:00 2001 From: yuanyulu Date: Sat, 7 Oct 2023 14:47:14 +0800 Subject: [PATCH] Fix multithreading safety crash issue Signed-off-by:yuanyulu@huawei.com Signed-off-by: yuanyulu --- .../extension/include/js_print_callback.h | 1 + .../extension/include/js_print_extension.h | 16 ++ .../kits/extension/src/js_print_callback.cpp | 17 ++ .../kits/extension/src/js_print_extension.cpp | 237 ++++++++++++------ 4 files changed, 189 insertions(+), 82 deletions(-) diff --git a/frameworks/kits/extension/include/js_print_callback.h b/frameworks/kits/extension/include/js_print_callback.h index 5ab10d20..7771fb68 100644 --- a/frameworks/kits/extension/include/js_print_callback.h +++ b/frameworks/kits/extension/include/js_print_callback.h @@ -30,6 +30,7 @@ class JsPrintCallback : public std::enable_shared_from_this { public: explicit JsPrintCallback(JsRuntime &jsRutime); ~JsPrintCallback() = default; + static bool Call(napi_env env, void *data, uv_after_work_cb afterCallback); napi_value Exec(napi_value jsObj, const std::string &name, napi_value const *argv = nullptr, size_t argc = 0, bool isSync = true); diff --git a/frameworks/kits/extension/include/js_print_extension.h b/frameworks/kits/extension/include/js_print_extension.h index 128f8548..9cb524ae 100644 --- a/frameworks/kits/extension/include/js_print_extension.h +++ b/frameworks/kits/extension/include/js_print_extension.h @@ -16,6 +16,8 @@ #ifndef JS_PRINT_EXTENSION_H #define JS_PRINT_EXTENSION_H +#include + #include "napi/native_api.h" #include "print_extension.h" #include "print_job.h" @@ -26,6 +28,16 @@ namespace OHOS { namespace AbilityRuntime { class PrintExtension; class JsRuntime; + +struct WorkParam { + napi_env env; + std::string funcName; + std::string printerId; + Print::PrintJob job; + WorkParam(napi_env env, std::string funcName) : env(env), funcName(funcName) + {} +}; + /** * @brief Basic Print components. */ @@ -108,6 +120,9 @@ private: napi_value CallObjectMethod(const char *name, napi_value const *argv = nullptr, size_t argc = 0); bool InitExtensionObj(JsRuntime &jsRuntime); bool InitContextObj(JsRuntime &jsRuntime, napi_value &extObj, std::string &extensionId); + bool Callback(const std::string funcName); + bool Callback(const std::string funcName, const std::string &printerId); + bool Callback(const std::string funcName, const Print::PrintJob &job); void RegisterDiscoveryCb(); void RegisterConnectionCb(); void RegisterPrintJobCb(); @@ -121,6 +136,7 @@ private: JsRuntime &jsRuntime_; std::unique_ptr jsObj_; static JsPrintExtension *jsExtension_; + static std::mutex mtx; std::string extensionId_; bool hasDestroyed_; }; diff --git a/frameworks/kits/extension/src/js_print_callback.cpp b/frameworks/kits/extension/src/js_print_callback.cpp index 327d5c29..c777fbd3 100644 --- a/frameworks/kits/extension/src/js_print_callback.cpp +++ b/frameworks/kits/extension/src/js_print_callback.cpp @@ -46,6 +46,23 @@ uv_loop_s* JsPrintCallback::GetJsLoop(JsRuntime &jsRuntime) return loop; } +bool JsPrintCallback::Call(napi_env env, void *data, uv_after_work_cb afterCallback) +{ + uv_loop_s *loop = nullptr; + napi_get_uv_event_loop(env, &loop); + if (loop == nullptr) { + return false; + } + uv_work_t *work = new (std::nothrow) uv_work_t; + if (work == nullptr) { + return false; + } + work->data = data; + uv_queue_work_with_qos( + loop, work, [](uv_work_t *work) {}, afterCallback, uv_qos_user_initiated); + return true; +} + bool JsPrintCallback::BuildJsWorker(napi_value jsObj, const std::string &name, napi_value const *argv, size_t argc, bool isSync) { diff --git a/frameworks/kits/extension/src/js_print_extension.cpp b/frameworks/kits/extension/src/js_print_extension.cpp index b3e3ee43..e60d9a66 100644 --- a/frameworks/kits/extension/src/js_print_extension.cpp +++ b/frameworks/kits/extension/src/js_print_extension.cpp @@ -36,6 +36,7 @@ namespace OHOS { namespace AbilityRuntime { JsPrintExtension *JsPrintExtension::jsExtension_ = nullptr; +std::mutex JsPrintExtension::mtx; using namespace OHOS::AppExecFwk; using namespace OHOS::Print; @@ -302,26 +303,140 @@ void JsPrintExtension::GetSrcPath(std::string &srcPath) } } +bool JsPrintExtension::Callback(std::string funcName) +{ + PRINT_HILOGD("call %{public}s", funcName.c_str()); + std::lock_guard lock(mtx); + if (JsPrintExtension::jsExtension_ == nullptr) { + return false; + } + napi_env env = (JsPrintExtension::jsExtension_->jsRuntime_).GetNapiEnv(); + WorkParam *workParam = new (std::nothrow) WorkParam(env, funcName); + if (workParam == nullptr) { + return false; + } + uv_after_work_cb afterCallback = [](uv_work_t *work, int32_t status) { + WorkParam *param = reinterpret_cast(work->data); + if (param == nullptr) { + delete work; + return; + } + napi_handle_scope scope = nullptr; + napi_open_handle_scope(param->env, &scope); + if (scope == nullptr) { + delete param; + delete work; + return; + } + napi_value arg[] = { 0 }; + std::lock_guard lock(mtx); + if (JsPrintExtension::jsExtension_ != nullptr) { + JsPrintExtension::jsExtension_->CallObjectMethod(param->funcName.c_str(), arg, NapiPrintUtils::ARGC_ZERO); + } + napi_close_handle_scope(param->env, scope); + delete param; + delete work; + }; + JsPrintCallback::Call(env, workParam, afterCallback); + return true; +} + +bool JsPrintExtension::Callback(const std::string funcName, const std::string &printerId) +{ + PRINT_HILOGD("call %{public}s", funcName.c_str()); + std::lock_guard lock(mtx); + if (JsPrintExtension::jsExtension_ == nullptr) { + return false; + } + napi_env env = (JsPrintExtension::jsExtension_->jsRuntime_).GetNapiEnv(); + WorkParam *workParam = new (std::nothrow) WorkParam(env, funcName); + if (workParam == nullptr) { + return false; + } + workParam->printerId = printerId; + uv_after_work_cb afterCallback = [](uv_work_t *work, int32_t status) { + WorkParam *param = reinterpret_cast(work->data); + if (param == nullptr) { + delete work; + return; + } + napi_handle_scope scope = nullptr; + napi_open_handle_scope(param->env, &scope); + if (scope == nullptr) { + delete param; + delete work; + return; + } + napi_value id = OHOS::AppExecFwk::WrapStringToJS(param->env, param->printerId); + napi_value arg[] = { id }; + std::lock_guard lock(mtx); + if (JsPrintExtension::jsExtension_ != nullptr) { + JsPrintExtension::jsExtension_->CallObjectMethod(param->funcName.c_str(), arg, NapiPrintUtils::ARGC_ONE); + } + napi_close_handle_scope(param->env, scope); + delete param; + delete work; + }; + JsPrintCallback::Call(env, workParam, afterCallback); + return true; +} + +bool JsPrintExtension::Callback(const std::string funcName, const Print::PrintJob &job) +{ + PRINT_HILOGD("call %{public}s", funcName.c_str()); + std::lock_guard lock(mtx); + if (JsPrintExtension::jsExtension_ == nullptr) { + return false; + } + napi_env env = (JsPrintExtension::jsExtension_->jsRuntime_).GetNapiEnv(); + WorkParam *workParam = new (std::nothrow) WorkParam(env, funcName); + if (workParam == nullptr) { + return false; + } + workParam->job = job; + uv_after_work_cb afterCallback = [](uv_work_t *work, int32_t status) { + WorkParam *param = reinterpret_cast(work->data); + if (param == nullptr) { + delete work; + return; + } + napi_handle_scope scope = nullptr; + napi_open_handle_scope(param->env, &scope); + if (scope == nullptr) { + delete param; + delete work; + return; + } + napi_value jobObject = PrintJobHelper::MakeJsObject(param->env, param->job); + napi_value arg[] = { jobObject }; + std::lock_guard lock(mtx); + if (JsPrintExtension::jsExtension_ != nullptr) { + JsPrintExtension::jsExtension_->CallObjectMethod(param->funcName.c_str(), arg, NapiPrintUtils::ARGC_ONE); + } + napi_close_handle_scope(param->env, scope); + delete param; + delete work; + }; + JsPrintCallback::Call(env, workParam, afterCallback); + return true; +} + void JsPrintExtension::RegisterDiscoveryCb() { PRINT_HILOGD("Register Print Extension Callback"); PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_START_DISCOVERY, []() -> bool { - PRINT_HILOGD("Start Print Discovery"); - HandleScope handleScope(jsExtension_->jsRuntime_); - auto callback = std::make_shared(jsExtension_->jsRuntime_); - napi_value value = jsExtension_->jsObj_->GetNapiValue(); - callback->Exec(value, "onStartDiscoverPrinter"); - return true; + if (JsPrintExtension::jsExtension_ == nullptr) { + return false; + } + return JsPrintExtension::jsExtension_->Callback("onStartDiscoverPrinter"); }); PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_STOP_DISCOVERY, []() -> bool { - PRINT_HILOGD("Stop Print Discovery"); - HandleScope handleScope(jsExtension_->jsRuntime_); - auto callback = std::make_shared(jsExtension_->jsRuntime_); - napi_value value = jsExtension_->jsObj_->GetNapiValue(); - callback->Exec(value, "onStopDiscoverPrinter"); - return true; + if (JsPrintExtension::jsExtension_ == nullptr) { + return false; + } + return JsPrintExtension::jsExtension_->Callback("onStopDiscoverPrinter"); }); } @@ -329,31 +444,19 @@ void JsPrintExtension::RegisterConnectionCb() { PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_CONNECT_PRINTER, [](const std::string &printId) -> bool { - PRINT_HILOGD("Connect Printer"); + if (JsPrintExtension::jsExtension_ == nullptr) { + return false; + } std::string realPrinterId = PrintUtils::GetLocalId(printId, jsExtension_->extensionId_); - HandleScope handleScope(jsExtension_->jsRuntime_); - napi_env nativeEng = (jsExtension_->jsRuntime_).GetNapiEnv(); - napi_value nativePrintId = - OHOS::AppExecFwk::WrapStringToJS(nativeEng, realPrinterId); - napi_value arg[] = { nativePrintId }; - auto callback = std::make_shared(jsExtension_->jsRuntime_); - napi_value value = jsExtension_->jsObj_->GetNapiValue(); - callback->Exec(value, "onConnectPrinter", arg, NapiPrintUtils::ARGC_ONE); - return true; + return JsPrintExtension::jsExtension_->Callback("onConnectPrinter", realPrinterId); }); PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_DISCONNECT_PRINTER, [](const std::string &printId) -> bool { - PRINT_HILOGD("Disconnect Printer"); + if (JsPrintExtension::jsExtension_ == nullptr) { + return false; + } std::string realPrinterId = PrintUtils::GetLocalId(printId, jsExtension_->extensionId_); - HandleScope handleScope(jsExtension_->jsRuntime_); - napi_env nativeEng = (jsExtension_->jsRuntime_).GetNapiEnv(); - napi_value nativePrintId = - OHOS::AppExecFwk::WrapStringToJS(nativeEng, realPrinterId); - napi_value arg[] = { nativePrintId }; - auto callback = std::make_shared(jsExtension_->jsRuntime_); - napi_value value = jsExtension_->jsObj_->GetNapiValue(); - callback->Exec(value, "onDisconnectPrinter", arg, NapiPrintUtils::ARGC_ONE); - return true; + return JsPrintExtension::jsExtension_->Callback("onDisconnectPrinter", realPrinterId); }); } @@ -361,29 +464,17 @@ void JsPrintExtension::RegisterPrintJobCb() { PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_START_PRINT, [](const PrintJob &job) -> bool { - PRINT_HILOGD("Start Print Job"); - HandleScope handleScope(jsExtension_->jsRuntime_); - napi_env nativeEng = (jsExtension_->jsRuntime_).GetNapiEnv(); - napi_value nativeJob = PrintJobHelper::MakeJsObject(nativeEng, job); - napi_value arg[] = { nativeJob }; - - auto callback = std::make_shared(jsExtension_->jsRuntime_); - napi_value value = jsExtension_->jsObj_->GetNapiValue(); - callback->Exec(value, "onStartPrintJob", arg, NapiPrintUtils::ARGC_ONE); - return true; + if (JsPrintExtension::jsExtension_ == nullptr) { + return false; + } + return JsPrintExtension::jsExtension_->Callback("onStartPrintJob", job); }); PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_CANCEL_PRINT, [](const PrintJob &job) -> bool { - PRINT_HILOGD("Cancel Print Job"); - HandleScope handleScope(jsExtension_->jsRuntime_); - napi_env nativeEng = (jsExtension_->jsRuntime_).GetNapiEnv(); - napi_value nativeJob = PrintJobHelper::MakeJsObject(nativeEng, job); - napi_value arg[] = { nativeJob }; - - auto callback = std::make_shared(jsExtension_->jsRuntime_); - napi_value value = jsExtension_->jsObj_->GetNapiValue(); - callback->Exec(value, "onCancelPrintJob", arg, NapiPrintUtils::ARGC_ONE); - return true; + if (JsPrintExtension::jsExtension_ == nullptr) { + return false; + } + return JsPrintExtension::jsExtension_->Callback("onCancelPrintJob", job); }); } @@ -391,16 +482,10 @@ void JsPrintExtension::RegisterPreviewCb() { PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_REQUEST_PREVIEW, [](const PrintJob &job) -> bool { - PRINT_HILOGD("Requet preview"); - HandleScope handleScope(jsExtension_->jsRuntime_); - napi_env nativeEng = (jsExtension_->jsRuntime_).GetNapiEnv(); - napi_value nativeJob = PrintJobHelper::MakeJsObject(nativeEng, job); - napi_value arg[] = { nativeJob }; - - auto callback = std::make_shared(jsExtension_->jsRuntime_); - napi_value value = jsExtension_->jsObj_->GetNapiValue(); - callback->Exec(value, "onRequestPreview", arg, NapiPrintUtils::ARGC_ONE); - return true; + if (JsPrintExtension::jsExtension_ == nullptr) { + return false; + } + return JsPrintExtension::jsExtension_->Callback("onRequestPreview", job); }); } @@ -408,18 +493,11 @@ void JsPrintExtension::RegisterQueryCapCb() { PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_REQUEST_CAP, [](const std::string &printId) -> bool { - PRINT_HILOGD("Request Capability"); + if (JsPrintExtension::jsExtension_ == nullptr) { + return false; + } std::string realPrinterId = PrintUtils::GetLocalId(printId, jsExtension_->extensionId_); - HandleScope handleScope(jsExtension_->jsRuntime_); - napi_env nativeEng = (jsExtension_->jsRuntime_).GetNapiEnv(); - napi_value nativePrintId = - OHOS::AppExecFwk::WrapStringToJS(nativeEng, realPrinterId); - napi_value arg[] = { nativePrintId }; - auto callback = std::make_shared(jsExtension_->jsRuntime_); - napi_value value = jsExtension_->jsObj_->GetNapiValue(); - callback->Exec(value, "onRequestPrinterCapability", arg, NapiPrintUtils::ARGC_ONE); - PRINT_HILOGD("Request Capability Success"); - return true; + return JsPrintExtension::jsExtension_->Callback("onRequestPrinterCapability", realPrinterId); }); } @@ -427,15 +505,10 @@ void JsPrintExtension::RegisterExtensionCb() { PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_DESTROY_EXTENSION, []() -> bool { - PRINT_HILOGD("Stop Extension"); - HandleScope handleScope(jsExtension_->jsRuntime_); - napi_value arg[] = { }; - auto callback = std::make_shared(jsExtension_->jsRuntime_); - napi_value value = jsExtension_->jsObj_->GetNapiValue(); - callback->Exec(value, "onDestroy", arg, NapiPrintUtils::ARGC_ZERO); - jsExtension_->hasDestroyed_ = true; - PRINT_HILOGD("Destroy Extension Success"); - return true; + if (JsPrintExtension::jsExtension_ == nullptr) { + return false; + } + return JsPrintExtension::jsExtension_->Callback("onDestroy"); }); } } // namespace AbilityRuntime -- Gitee