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_emitter.h"
17
18 #include <memory>
19 #include <string>
20 #include "event_logger.h"
21 #include "js_native_api_types.h"
22 #include "aync_callback_manager.h"
23 #include "napi_serialize.h"
24 #include "interops.h"
25 #include "napi_agent.h"
26 #include "napi/native_node_hybrid_api.h"
27
28 using namespace std;
29 namespace OHOS {
30 namespace AppExecFwk {
31 namespace {
32 DEFINE_EH_HILOG_LABEL("EventsEmitter");
33 constexpr static uint32_t ARGC_ONE = 1u;
34 static const int32_t ARGC_NUM = 2;
35 static const int32_t NAPI_VALUE_STRING_LEN = 10240;
StringToNapiValue(napi_env env,napi_value * napiValue,std::string strValue)36 bool StringToNapiValue(napi_env env, napi_value* napiValue, std::string strValue)
37 {
38 if (strValue.length() > 0) {
39 napi_value globalValue;
40 napi_get_global(env, &globalValue);
41 napi_value jsonValue;
42 napi_get_named_property(env, globalValue, "JSON", &jsonValue);
43 napi_value parseValue;
44 napi_get_named_property(env, jsonValue, "parse", &parseValue);
45 napi_value paramsNApi;
46 napi_create_string_utf8(env, strValue.c_str(), NAPI_AUTO_LENGTH, ¶msNApi);
47 napi_value funcArgv[1] = { paramsNApi };
48 auto status = napi_call_function(env, jsonValue, parseValue, 1, funcArgv, napiValue);
49 if (status != napi_ok) {
50 HILOGE("StringToNapiValue Stringify Failed");
51 return false;
52 }
53 }
54 return true;
55 }
56 }
57
GetEventIdWithNumberOrString(napi_env env,napi_value argv,napi_valuetype eventValueType,InnerEvent::EventId & eventId)58 bool GetEventIdWithNumberOrString(
59 napi_env env, napi_value argv, napi_valuetype eventValueType, InnerEvent::EventId &eventId)
60 {
61 if (eventValueType == napi_string) {
62 auto valueCStr = std::make_unique<char[]>(NAPI_VALUE_STRING_LEN + 1);
63 size_t valueStrLength = 0;
64 napi_get_value_string_utf8(env, argv, valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength);
65 std::string id(valueCStr.get(), valueStrLength);
66 if (id.empty()) {
67 return false;
68 }
69 eventId = id;
70 HILOGD("Event id value:%{public}s", id.c_str());
71 } else {
72 uint32_t id = 0u;
73 napi_get_value_uint32(env, argv, &id);
74 eventId = id;
75 HILOGD("Event id value:%{public}u", id);
76 }
77 return true;
78 }
79
JS_Off(napi_env env,napi_callback_info cbinfo)80 napi_value JS_Off(napi_env env, napi_callback_info cbinfo)
81 {
82 HILOGD("JS_Off enter");
83 size_t argc = ARGC_NUM;
84 napi_value argv[ARGC_NUM] = {0};
85 NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL));
86 if (argc < 1) {
87 HILOGE("requires at least 1 parameter");
88 return nullptr;
89 }
90
91 napi_valuetype eventValueType;
92 napi_typeof(env, argv[0], &eventValueType);
93 if (eventValueType != napi_number && eventValueType != napi_string) {
94 HILOGE("type mismatch for parameter 1");
95 return nullptr;
96 }
97
98 InnerEvent::EventId eventId = 0u;
99 bool ret = GetEventIdWithNumberOrString(env, argv[0], eventValueType, eventId);
100 if (!ret) {
101 HILOGE("Event id is empty for parameter 1.");
102 return nullptr;
103 }
104
105 if (argc == ARGC_NUM) {
106 napi_valuetype eventHandleType;
107 napi_typeof(env, argv[1], &eventHandleType);
108 if (eventHandleType != napi_function) {
109 HILOGE("type mismatch for parameter 2");
110 return nullptr;
111 }
112 AsyncCallbackManager::GetInstance().DeleteCallbackInfo(env, eventId, argv[1]);
113 return nullptr;
114 }
115 AsyncCallbackManager::GetInstance().DeleteCallbackInfoByEventId(eventId);
116 return nullptr;
117 }
118
EmitWithEventData(napi_env env,napi_value argv,const InnerEvent::EventId & eventId,Priority priority)119 bool EmitWithEventData(napi_env env, napi_value argv, const InnerEvent::EventId &eventId, Priority priority)
120 {
121 HILOGD("EmitWithEventData enter");
122 napi_valuetype dataType;
123 napi_typeof(env, argv, &dataType);
124 if (dataType != napi_object) {
125 HILOGE("type mismatch for parameter 2");
126 return false;
127 }
128
129 auto serializeDataPtr = new (std::nothrow) SerializeData();
130 if (serializeDataPtr == nullptr) {
131 HILOGE("memory allocation failed");
132 return false;
133 }
134 std::shared_ptr<SerializeData> serializeData(serializeDataPtr, [env](SerializeData* data) {
135 if (env != nullptr && std::get<napi_value>(data->peerData)) {
136 napi_delete_serialization_data(env, std::get<napi_value>(data->peerData));
137 }
138 delete data;
139 data = nullptr;
140 });
141 serializeData->envType = EnvType::NAPI;
142 if (!NapiSerialize::PeerSerialize(env, argv, serializeData)) {
143 return false;
144 }
145 if (AsyncCallbackManager::GetInstance().IsCrossRuntime(eventId, EnvType::NAPI)) {
146 serializeData->isCrossRuntime = true;
147 if (!NapiSerialize::CrossSerialize(env, argv, serializeData)) {
148 return false;
149 }
150 }
151 auto event = InnerEvent::Get(eventId, serializeData);
152 event->SetIsEnhanced(true);
153 EventHandlerInstance::GetInstance()->SendEvent(event, 0, priority);
154 return true;
155 }
156
EmitWithDefaultData(InnerEvent::EventId eventId,Priority priority)157 void EmitWithDefaultData(InnerEvent::EventId eventId, Priority priority)
158 {
159 auto serializeData = make_shared<SerializeData>();
160 serializeData->envType = EnvType::NAPI;
161 if (AsyncCallbackManager::GetInstance().IsCrossRuntime(eventId, EnvType::NAPI)) {
162 serializeData->isCrossRuntime = true;
163 }
164 auto event = InnerEvent::Get(eventId, serializeData);
165 event->SetIsEnhanced(true);
166 EventHandlerInstance::GetInstance()->SendEvent(event, 0, priority);
167 }
168
EmitWithEventIdUint32(napi_env env,size_t argc,napi_value argv[])169 napi_value EmitWithEventIdUint32(napi_env env, size_t argc, napi_value argv[])
170 {
171 InnerEvent::EventId eventId = 0u;
172 bool hasEventId = false;
173 napi_value value = nullptr;
174 napi_has_named_property(env, argv[0], "eventId", &hasEventId);
175 if (hasEventId == false) {
176 HILOGE("Wrong argument 1 does not have event id");
177 return nullptr;
178 }
179
180 napi_get_named_property(env, argv[0], "eventId", &value);
181 uint32_t id = 0u;
182 napi_get_value_uint32(env, value, &id);
183 eventId = id;
184 HILOGD("Event id value:%{public}u", id);
185
186 if (!AsyncCallbackManager::GetInstance().IsExistValidCallback(eventId)) {
187 EH_LOGE_LIMIT("Invalid callback");
188 return nullptr;
189 }
190
191 bool hasPriority = false;
192 napi_has_named_property(env, argv[0], "priority", &hasPriority);
193 Priority priority = Priority::LOW;
194 if (hasPriority) {
195 napi_get_named_property(env, argv[0], "priority", &value);
196 uint32_t priorityValue = 0u;
197 napi_get_value_uint32(env, value, &priorityValue);
198 HILOGD("Event priority:%{public}d", priorityValue);
199 priority = static_cast<Priority>(priorityValue);
200 }
201
202 if (argc == ARGC_NUM && EmitWithEventData(env, argv[1], eventId, priority)) {
203 return nullptr;
204 } else {
205 EmitWithDefaultData(eventId, priority);
206 }
207 return nullptr;
208 }
209
EmitWithEventIdString(napi_env env,size_t argc,napi_value argv[])210 napi_value EmitWithEventIdString(napi_env env, size_t argc, napi_value argv[])
211 {
212 InnerEvent::EventId eventId = 0u;
213 auto valueCStr = std::make_unique<char[]>(NAPI_VALUE_STRING_LEN + 1);
214 size_t valueStrLength = 0;
215 napi_get_value_string_utf8(env, argv[0], valueCStr.get(), NAPI_VALUE_STRING_LEN, &valueStrLength);
216 std::string id(valueCStr.get(), valueStrLength);
217 if (id.empty()) {
218 HILOGE("Invalid event id:%{public}s", id.c_str());
219 return nullptr;
220 }
221 eventId = id;
222 HILOGD("Event id value:%{public}s", id.c_str());
223
224 if (!AsyncCallbackManager::GetInstance().IsExistValidCallback(eventId)) {
225 EH_LOGE_LIMIT("Invalid callback");
226 return nullptr;
227 }
228 Priority priority = Priority::LOW;
229 if (argc < ARGC_NUM) {
230 EmitWithDefaultData(eventId, priority);
231 return nullptr;
232 }
233 bool hasPriority = false;
234 napi_value value = nullptr;
235 napi_has_named_property(env, argv[1], "priority", &hasPriority);
236 if (!hasPriority) {
237 if (!EmitWithEventData(env, argv[1], eventId, priority)) {
238 EmitWithDefaultData(eventId, priority);
239 }
240 return nullptr;
241 }
242
243 napi_get_named_property(env, argv[1], "priority", &value);
244 uint32_t priorityValue = 0u;
245 napi_get_value_uint32(env, value, &priorityValue);
246 HILOGD("Event priority:%{public}d", priorityValue);
247 priority = static_cast<Priority>(priorityValue);
248
249 if (argc > ARGC_NUM && EmitWithEventData(env, argv[ARGC_NUM], eventId, priority)) {
250 return nullptr;
251 } else {
252 EmitWithDefaultData(eventId, priority);
253 }
254 return nullptr;
255 }
256
JS_Emit(napi_env env,napi_callback_info cbinfo)257 napi_value JS_Emit(napi_env env, napi_callback_info cbinfo)
258 {
259 HILOGD("JS_Emit enter");
260 size_t argc = ARGC_NUM + ARGC_ONE;
261 napi_value argv[ARGC_NUM + ARGC_ONE] = {0};
262 NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL));
263 if (argc < ARGC_ONE) {
264 HILOGE("Requires more than 1 parameter");
265 return nullptr;
266 }
267 napi_valuetype eventValueType;
268 napi_typeof(env, argv[0], &eventValueType);
269 if (eventValueType != napi_object && eventValueType != napi_string) {
270 HILOGE("Type mismatch for parameter 1");
271 return nullptr;
272 }
273 if (eventValueType == napi_string) {
274 return EmitWithEventIdString(env, argc, argv);
275 }
276 return EmitWithEventIdUint32(env, argc, argv);
277 }
278
CreateJsUndefined(napi_env env)279 napi_value CreateJsUndefined(napi_env env)
280 {
281 napi_value result = nullptr;
282 napi_get_undefined(env, &result);
283 return result;
284 }
285
CreateJsNumber(napi_env env,uint32_t value)286 napi_value CreateJsNumber(napi_env env, uint32_t value)
287 {
288 napi_value result = nullptr;
289 napi_create_uint32(env, value, &result);
290 return result;
291 }
292
JS_GetListenerCount(napi_env env,napi_callback_info cbinfo)293 napi_value JS_GetListenerCount(napi_env env, napi_callback_info cbinfo)
294 {
295 HILOGD("JS_GetListenerCount enter");
296 size_t argc = ARGC_NUM;
297 napi_value argv[ARGC_NUM] = {0};
298 NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL));
299 if (argc < ARGC_ONE) {
300 HILOGE("Requires more than 1 parameter");
301 return CreateJsUndefined(env);
302 }
303
304 napi_valuetype eventValueType;
305 napi_typeof(env, argv[0], &eventValueType);
306 if (eventValueType != napi_number && eventValueType != napi_string) {
307 HILOGE("Type mismatch for parameter 1");
308 return CreateJsUndefined(env);
309 }
310
311 InnerEvent::EventId eventId = 0u;
312 bool ret = GetEventIdWithNumberOrString(env, argv[0], eventValueType, eventId);
313 if (!ret) {
314 HILOGE("Event id is empty for parameter 1");
315 return CreateJsUndefined(env);
316 }
317
318 uint32_t cnt = AsyncCallbackManager::GetInstance().GetListenerCountByEventId(eventId);
319 return CreateJsNumber(env, cnt);
320 }
321
EnumEventClassConstructor(napi_env env,napi_callback_info info)322 napi_value EnumEventClassConstructor(napi_env env, napi_callback_info info)
323 {
324 napi_value thisArg = nullptr;
325 void *data = nullptr;
326
327 napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data);
328
329 napi_value global = nullptr;
330 napi_get_global(env, &global);
331
332 return thisArg;
333 }
334
CreateEnumEventPriority(napi_env env,napi_value exports)335 napi_value CreateEnumEventPriority(napi_env env, napi_value exports)
336 {
337 napi_value immediate = nullptr;
338 napi_value high = nullptr;
339 napi_value low = nullptr;
340 napi_value idle = nullptr;
341
342 napi_create_uint32(env, static_cast<uint32_t>(Priority::IMMEDIATE), &immediate);
343 napi_create_uint32(env, static_cast<uint32_t>(Priority::HIGH), &high);
344 napi_create_uint32(env, static_cast<uint32_t>(Priority::LOW), &low);
345 napi_create_uint32(env, static_cast<uint32_t>(Priority::IDLE), &idle);
346
347 napi_property_descriptor desc[] = {
348 DECLARE_NAPI_STATIC_PROPERTY("IMMEDIATE", immediate),
349 DECLARE_NAPI_STATIC_PROPERTY("HIGH", high),
350 DECLARE_NAPI_STATIC_PROPERTY("LOW", low),
351 DECLARE_NAPI_STATIC_PROPERTY("IDLE", idle),
352 };
353 napi_value result = nullptr;
354 napi_define_class(env, "EventPriority", NAPI_AUTO_LENGTH, EnumEventClassConstructor, nullptr,
355 sizeof(desc) / sizeof(*desc), desc, &result);
356
357 napi_set_named_property(env, exports, "EventPriority", result);
358
359 return exports;
360 }
361
ProcessEvent(const InnerEvent::Pointer & event)362 void ProcessEvent(const InnerEvent::Pointer& event)
363 {
364 AsyncCallbackManager::GetInstance().DoCallback(event);
365 }
366
ProcessCallbackEnhanced(const EventDataWorker * eventDataInner)367 void ProcessCallbackEnhanced(const EventDataWorker* eventDataInner)
368 {
369 auto callbackInner = eventDataInner->callbackInfo;
370 napi_value resultData = nullptr;
371 if (eventDataInner->isCrossRuntime) {
372 char* serializeDataCharPtr = reinterpret_cast<char*>(eventDataInner->enhancedData);
373 std::string serializeData(serializeDataCharPtr);
374 bool ret = StringToNapiValue(callbackInner->env, &resultData, serializeData);
375 if (!ret) {
376 return;
377 }
378 } else {
379 if (eventDataInner->data != nullptr && *(eventDataInner->data) != nullptr) {
380 if (napi_deserialize_hybrid(callbackInner->env, *(eventDataInner->data), &resultData) != napi_ok ||
381 resultData == nullptr) {
382 HILOGE("Deserialize fail.");
383 return;
384 }
385 }
386 }
387 napi_value event = nullptr;
388 napi_create_object(callbackInner->env, &event);
389 napi_set_named_property(callbackInner->env, event, "data", resultData);
390 napi_value callback = nullptr;
391 napi_value returnVal = nullptr;
392 napi_get_reference_value(callbackInner->env, callbackInner->callback, &callback);
393 napi_call_function(callbackInner->env, nullptr, callback, 1, &event, &returnVal);
394 if (callbackInner->once) {
395 AsyncCallbackManager::GetInstance().DeleteCallbackInfo(callbackInner->env, callbackInner->eventId, callback);
396 }
397 }
398
AgentInit()399 void AgentInit()
400 {
401 EmitterEnhancedApi api = {
402 .JS_Off = &JS_Off,
403 .JS_Emit = &JS_Emit,
404 .JS_GetListenerCount = &JS_GetListenerCount,
405 .ProcessEvent = &ProcessEvent,
406 .ProcessCallbackEnhanced = &ProcessCallbackEnhanced
407 };
408
409 GetEmitterEnhancedApiRegister().Register(api);
410 }
411 } // namespace AppExecFwk
412 } // namespace OHOS