• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &paramsNApi);
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