1 /*
2 * Copyright (c) 2025 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_async_callback_manager.h"
17 #include <uv.h>
18 #include "event_logger.h"
19 #include "serialize.h"
20 namespace OHOS {
21 namespace AppExecFwk {
22 namespace {
23 DEFINE_EH_HILOG_LABEL("EventsEmitter");
24 }
25
NapiDeleteCallbackInfoByEventId(const InnerEvent::EventId & eventIdValue)26 void NapiAsyncCallbackManager::NapiDeleteCallbackInfoByEventId(const InnerEvent::EventId &eventIdValue)
27 {
28 std::lock_guard<std::mutex> lock(napiAsyncCallbackContainerMutex_);
29 auto iter = napiAsyncCallbackContainer_.find(eventIdValue);
30 if (iter != napiAsyncCallbackContainer_.end()) {
31 for (auto callbackInfo : iter->second) {
32 callbackInfo->isDeleted = true;
33 }
34 }
35 napiAsyncCallbackContainer_.erase(eventIdValue);
36 }
37
NapiGetListenerCountByEventId(const InnerEvent::EventId & eventId)38 uint32_t NapiAsyncCallbackManager::NapiGetListenerCountByEventId(const InnerEvent::EventId &eventId)
39 {
40 uint32_t cnt = 0u;
41 std::lock_guard<std::mutex> lock(napiAsyncCallbackContainerMutex_);
42 auto subscribe = napiAsyncCallbackContainer_.find(eventId);
43 if (subscribe != napiAsyncCallbackContainer_.end()) {
44 for (auto it = subscribe->second.begin(); it != subscribe->second.end();) {
45 if ((*it)->isDeleted == true || (*it)->env == nullptr) {
46 it = subscribe->second.erase(it);
47 continue;
48 }
49 ++it;
50 ++cnt;
51 }
52 }
53 return cnt;
54 }
55
NapiIsExistValidCallback(const InnerEvent::EventId & eventId)56 bool NapiAsyncCallbackManager::NapiIsExistValidCallback(const InnerEvent::EventId &eventId)
57 {
58 std::lock_guard<std::mutex> lock(napiAsyncCallbackContainerMutex_);
59 auto subscribe = napiAsyncCallbackContainer_.find(eventId);
60 if (subscribe == napiAsyncCallbackContainer_.end()) {
61 return false;
62 }
63 if (subscribe->second.size() != 0) {
64 return true;
65 }
66 return false;
67 }
68
NapiDeleteCallbackInfo(napi_env env,const InnerEvent::EventId & eventIdValue,napi_value argv)69 void NapiAsyncCallbackManager::NapiDeleteCallbackInfo(
70 napi_env env, const InnerEvent::EventId &eventIdValue, napi_value argv)
71 {
72 std::lock_guard<std::mutex> lock(napiAsyncCallbackContainerMutex_);
73 auto iter = napiAsyncCallbackContainer_.find(eventIdValue);
74 if (iter == napiAsyncCallbackContainer_.end()) {
75 return;
76 }
77 for (auto callbackInfo = iter->second.begin(); callbackInfo != iter->second.end();) {
78 napi_value callback = nullptr;
79 if ((*callbackInfo)->env != env) {
80 ++callbackInfo;
81 continue;
82 }
83 napi_get_reference_value((*callbackInfo)->env, (*callbackInfo)->callback, &callback);
84 bool isEq = false;
85 napi_strict_equals(env, argv, callback, &isEq);
86 if (!isEq) {
87 ++callbackInfo;
88 continue;
89 }
90 (*callbackInfo)->isDeleted = true;
91 callbackInfo = iter->second.erase(callbackInfo);
92 return;
93 }
94 return;
95 }
96
NapiGetAsyncCallbackInfo(const InnerEvent::EventId & eventId)97 std::unordered_set<std::shared_ptr<AsyncCallbackInfo>> NapiAsyncCallbackManager::NapiGetAsyncCallbackInfo(
98 const InnerEvent::EventId &eventId)
99 {
100 std::lock_guard<std::mutex> lock(napiAsyncCallbackContainerMutex_);
101 auto iter = napiAsyncCallbackContainer_.find(eventId);
102 if (iter == napiAsyncCallbackContainer_.end()) {
103 std::unordered_set<std::shared_ptr<AsyncCallbackInfo>> result;
104 return result;
105 }
106 for (auto it = iter->second.begin(); it != iter->second.end();) {
107 if ((*it)->isDeleted == true || (*it)->env == nullptr) {
108 it = iter->second.erase(it);
109 continue;
110 }
111 ++it;
112 }
113 return iter->second;
114 }
115
NapiDoCallback(const InnerEvent::Pointer & event)116 void NapiAsyncCallbackManager::NapiDoCallback(const InnerEvent::Pointer& event)
117 {
118 auto napiCallbackInfos = NapiGetAsyncCallbackInfo(event->GetInnerEventIdEx());
119 auto serializeData = event->GetSharedObject<SerializeData>();
120 auto deleter = [](napi_value* data) {
121 if (data != nullptr) {
122 delete data;
123 }
124 };
125 for (auto it = napiCallbackInfos.begin(); it != napiCallbackInfos.end(); ++it) {
126 if (*it == nullptr || (*it)->env == nullptr || (*it)->isDeleted) {
127 HILOGE("napiCallbackInfo is unavailable");
128 continue;
129 }
130 EventDataWorker* eventDataWorker = new (std::nothrow) EventDataWorker();
131 if (!eventDataWorker) {
132 HILOGE("new object failed");
133 return;
134 }
135 eventDataWorker->IsEnhanced = true;
136 eventDataWorker->serializePtr = serializeData;
137 eventDataWorker->callbackInfo = *it;
138 if (serializeData->envType == EnvType::NAPI) {
139 auto napiValue = std::get<napi_value>(serializeData->peerData);
140 auto* heapValue = new napi_value(napiValue);
141 eventDataWorker->data = std::shared_ptr<napi_value>(heapValue, deleter);
142 eventDataWorker->isCrossRuntime = false;
143 } else {
144 eventDataWorker->enhancedData =
145 reinterpret_cast<void*>(const_cast<char*>(serializeData->crossData.c_str()));
146 eventDataWorker->isCrossRuntime = true;
147 }
148 napi_acquire_threadsafe_function((*it)->tsfn);
149 napi_call_threadsafe_function((*it)->tsfn, eventDataWorker, napi_tsfn_nonblocking);
150 napi_release_threadsafe_function((*it)->tsfn, napi_tsfn_release);
151 }
152 }
153 } // namespace AppExecFwk
154 } // namespace OHOS