• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 "events_emitter.h"
17 
18 #include <uv.h>
19 
20 #include "hilog/log.h"
21 
22 #define DEFINE_HILOG_LABEL(name) \
23 static constexpr OHOS::HiviewDFX::HiLogLabel LOG_LABEL = { LOG_CORE, LOG_DOMAIN, name }
24 
25 #define HILOGE(...) OHOS::HiviewDFX::HiLog::Error(LOG_LABEL, ##__VA_ARGS__)
26 #define HILOGW(...) OHOS::HiviewDFX::HiLog::Warn(LOG_LABEL, ##__VA_ARGS__)
27 #define HILOGI(...) OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, ##__VA_ARGS__)
28 #define HILOGD(...) OHOS::HiviewDFX::HiLog::Debug(LOG_LABEL, ##__VA_ARGS__)
29 
30 DEFINE_HILOG_LABEL("events_emitter");
31 using namespace std;
32 namespace OHOS {
33 namespace AppExecFwk {
34     static std::mutex emitterInsMutex;
35     static map<uint32_t, std::vector<AsyncCallbackInfo *>> emitterInstances;
36     std::shared_ptr<EventHandlerInstance> eventHandler;
EventHandlerInstance(const std::shared_ptr<EventRunner> & runner)37     EventHandlerInstance::EventHandlerInstance(const std::shared_ptr<EventRunner>& runner): EventHandler(runner)
38     {
39         HILOGI("EventHandlerInstance::EventHandlerInstance constructed");
40     }
~EventHandlerInstance()41     EventHandlerInstance::~EventHandlerInstance()
42     {
43         HILOGI("EventHandlerInstance::EventHandlerInstance de-constructed");
44     }
GetInstance()45     std::shared_ptr<EventHandlerInstance> EventHandlerInstance::GetInstance()
46     {
47         static auto runner = EventRunner::Create("events_emitter");
48         if (runner.get() == nullptr) {
49             HILOGE("failed to create EventRunner events_emitter");
50             return nullptr;
51         }
52         static auto instance = std::make_shared<EventHandlerInstance>(runner);
53         return instance;
54     }
55 
TransToEventData(napi_env env,EventData eventData,napi_value resultData)56     void TransToEventData(napi_env env, EventData eventData, napi_value resultData)
57     {
58         napi_value data = nullptr;
59         napi_create_object(env, &data);
60         for (map<string, Val>::iterator it = eventData.begin(); it != eventData.end(); ++it) {
61             string key = it->first;
62             Val val = it->second;
63             napi_value napiValue = nullptr;
64             switch (val.type) {
65                 case DataType::BOOL:
66                     HILOGD("ProcessEvent key:%{public}s value:%{public}d", key.c_str(), val.value.bValue);
67                     napi_get_boolean(env, val.value.bValue, &napiValue);
68                     break;
69                 case DataType::INT:
70                     HILOGD("ProcessEvent key:%{public}s value:%{public}d", key.c_str(), val.value.nValue);
71                     napi_create_int32(env, val.value.nValue, &napiValue);
72                     break;
73                 case DataType::STRING:
74                     HILOGD("ProcessEvent key:%{public}s value:%{public}s", key.c_str(), val.value.cValue);
75                     napi_create_string_utf8(env, val.value.cValue, NAPI_AUTO_LENGTH, &napiValue);
76                     break;
77                 default:
78                     HILOGE("ProcessEvent unsupport type data");
79                     break;
80             }
81             napi_set_named_property(env, data, key.c_str(), napiValue);
82         }
83         napi_set_named_property(env, resultData, "data", data);
84     }
85 
ProcessCallback(const EventDataWorker * eventDataInner)86     void ProcessCallback(const EventDataWorker* eventDataInner)
87     {
88         if (eventDataInner == nullptr) {
89             HILOGW("EventDataWorkder instance(uv_work_t) is nullptr");
90             return;
91         }
92         AsyncCallbackInfo* callbackInner = eventDataInner->callbackInfo;
93         if (callbackInner->isDeleted) {
94             HILOGI("ProcessEvent isDeleted");
95             std::lock_guard<std::mutex> lock(emitterInsMutex);
96             if (callbackInner->callback != nullptr) {
97                 napi_delete_reference(callbackInner->env, callbackInner->callback);
98                 callbackInner->callback = nullptr;
99             }
100         } else {
101             napi_value resultData = nullptr;
102             napi_create_object(callbackInner->env, &resultData);
103             TransToEventData(callbackInner->env, eventDataInner->data, resultData);
104 
105             napi_value callback = nullptr;
106             napi_value returnVal = nullptr;
107             napi_get_reference_value(callbackInner->env, callbackInner->callback, &callback);
108             napi_call_function(callbackInner->env, nullptr, callback, 1, &resultData, &returnVal);
109             if (callbackInner->once) {
110                 HILOGI("ProcessEvent delete once");
111                 std::lock_guard<std::mutex> lock(emitterInsMutex);
112                 callbackInner->isDeleted = true;
113                 napi_delete_reference(callbackInner->env, callbackInner->callback);
114                 callbackInner->callback = nullptr;
115             }
116         }
117     }
118 
ProcessEvent(const InnerEvent::Pointer & event)119     void EventHandlerInstance::ProcessEvent([[maybe_unused]] const InnerEvent::Pointer& event)
120     {
121         uint32_t eventId = event->GetInnerEventId();
122         HILOGI("ProcessEvent, eventId = %{public}d", eventId);
123         std::lock_guard<std::mutex> lock(emitterInsMutex);
124         auto subscribe = emitterInstances.find(eventId);
125         if (subscribe == emitterInstances.end()) {
126             HILOGW("ProcessEvent has no callback");
127             return;
128         }
129 
130         auto& callbackInfos = subscribe->second;
131         HILOGI("ProcessEvent, size = %{public}zu", callbackInfos.size());
132         EventData eventData = *(event->GetUniqueObject<EventData>());
133         for (auto iter = callbackInfos.begin(); iter != callbackInfos.end();) {
134             AsyncCallbackInfo* callbackInfo = *iter;
135             EventDataWorker* eventDataWorker = new (std::nothrow) EventDataWorker();
136             if (!eventDataWorker) {
137                 HILOGE("new object failed");
138                 continue;
139             }
140 
141             eventDataWorker->data = eventData;
142             eventDataWorker->callbackInfo = callbackInfo;
143 
144             uv_loop_s *loop = nullptr;
145             napi_get_uv_event_loop(callbackInfo->env, &loop);
146             uv_work_t *work = new (std::nothrow) uv_work_t;
147             if (work == nullptr) {
148                 HILOGI("uv_work_t instance is nullptr");
149                 delete eventDataWorker;
150                 eventDataWorker = nullptr;
151                 return;
152             }
153             work->data = reinterpret_cast<void *>(eventDataWorker);
154             uv_queue_work(loop, work, [](uv_work_t *work) {},
155                 [](uv_work_t *work, int status) {
156                 napi_handle_scope scope;
157                 EventDataWorker* eventDataInner = static_cast<EventDataWorker*>(work->data);
158                 napi_open_handle_scope(eventDataInner->callbackInfo->env, &scope);
159                 ProcessCallback(eventDataInner);
160                 napi_close_handle_scope(eventDataInner->callbackInfo->env, scope);
161                 delete eventDataInner;
162                 eventDataInner = nullptr;
163                 delete work;
164                 work = nullptr;
165             });
166             if (callbackInfo->once || callbackInfo->isDeleted) {
167                 HILOGI("ProcessEvent once callback or isDeleted callback");
168                 iter = callbackInfos.erase(iter);
169                 if (callbackInfos.begin() == callbackInfos.end()) {
170                     emitterInstances.erase(eventId);
171                     HILOGI("ProcessEvent delete the last callback");
172                     break;
173                 }
174             } else {
175                 ++iter;
176             }
177         }
178         HILOGI("ProcessEvent end");
179     }
180 
IsExistSameCallback(napi_env env,uint32_t eventIdValue,napi_value argv,bool once)181     bool IsExistSameCallback(napi_env env, uint32_t eventIdValue, napi_value argv, bool once)
182     {
183         auto subscribe = emitterInstances.find(eventIdValue);
184         if (subscribe == emitterInstances.end()) {
185             return false;
186         }
187         vector<AsyncCallbackInfo *> callbackInfo = subscribe->second;
188         size_t callbackSize = callbackInfo.size();
189         napi_value callback = nullptr;
190         for (size_t i = 0; i < callbackSize; i++) {
191             if (callbackInfo[i]->isDeleted) {
192                 continue;
193             }
194             if (callbackInfo[i]->env != env) {
195                 continue;
196             }
197             napi_get_reference_value(callbackInfo[i]->env, callbackInfo[i]->callback, &callback);
198             bool isEq = false;
199             napi_strict_equals(env, argv, callback, &isEq);
200             if (!isEq) {
201                 continue;
202             }
203             if (!once) {
204                 if (callbackInfo[i]->once) {
205                     HILOGI("JS_On change once to on");
206                     callbackInfo[i]->once = false;
207                 } else {
208                     HILOGI("JS_On already on");
209                 }
210             } else {
211                 if (callbackInfo[i]->once) {
212                     HILOGI("JS_Once already once");
213                 } else {
214                     HILOGI("JS_Once change on to once");
215                     callbackInfo[i]->once = true;
216                 }
217             }
218             return true;
219         }
220         return false;
221     }
222 
OnOrOnce(napi_env env,napi_callback_info cbinfo,bool once)223     napi_value OnOrOnce(napi_env env, napi_callback_info cbinfo, bool once)
224     {
225         size_t argc = ARGC_NUM;
226         napi_value argv[ARGC_NUM] = {0};
227         NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL));
228         NAPI_ASSERT(env, argc >= ARGC_NUM, "requires 2 parameter");
229 
230         napi_valuetype eventValueType;
231         napi_typeof(env, argv[0], &eventValueType);
232         NAPI_ASSERT(env, eventValueType == napi_object, "type mismatch for parameter 1");
233 
234         napi_valuetype eventHandleType;
235         napi_typeof(env, argv[1], &eventHandleType);
236         NAPI_ASSERT(env, eventHandleType == napi_function, "type mismatch for parameter 2");
237 
238         bool hasEventId = false;
239         napi_value eventId;
240         napi_has_named_property(env, argv[0], "eventId", &hasEventId);
241         NAPI_ASSERT(env, hasEventId, "Wrong argument 1");
242         napi_get_named_property(env, argv[0], "eventId", &eventId);
243         uint32_t eventIdValue;
244         napi_get_value_uint32(env, eventId, &eventIdValue);
245         HILOGI("OnOrOnce eventIdValue:%{public}d", eventIdValue);
246         std::lock_guard<std::mutex> lock(emitterInsMutex);
247         if (!IsExistSameCallback(env, eventIdValue, argv[1], once)) {
248             AsyncCallbackInfo* callbackInfo = new (std::nothrow) AsyncCallbackInfo();
249             if (!callbackInfo) {
250                 HILOGE("new object failed");
251                 return nullptr;
252             }
253             callbackInfo->env = env;
254             callbackInfo->once = once;
255             napi_create_reference(env, argv[1], 1, &callbackInfo->callback);
256             emitterInstances[eventIdValue].push_back(callbackInfo);
257         }
258         return nullptr;
259     }
260 
JS_On(napi_env env,napi_callback_info cbinfo)261     napi_value JS_On(napi_env env, napi_callback_info cbinfo)
262     {
263         HILOGI("JS_On start");
264         return OnOrOnce(env, cbinfo, false);
265     }
266 
JS_Once(napi_env env,napi_callback_info cbinfo)267     napi_value JS_Once(napi_env env, napi_callback_info cbinfo)
268     {
269         HILOGI("JS_Once start");
270         return OnOrOnce(env, cbinfo, true);
271     }
272 
JS_Off(napi_env env,napi_callback_info cbinfo)273     napi_value JS_Off(napi_env env, napi_callback_info cbinfo)
274     {
275         HILOGI("JS_Off start");
276         size_t argc = 1;
277         napi_value argv[1] = {0};
278         NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL));
279         NAPI_ASSERT(env, argc >= 1, "requires 1 parameter");
280 
281         napi_valuetype eventValueType;
282         napi_typeof(env, argv[0], &eventValueType);
283         NAPI_ASSERT(env, eventValueType == napi_number, "type mismatch for parameter 1");
284 
285         uint32_t eventId;
286         napi_get_value_uint32(env, argv[0], &eventId);
287         std::lock_guard<std::mutex> lock(emitterInsMutex);
288         auto subscribe = emitterInstances.find(eventId);
289         if (subscribe != emitterInstances.end()) {
290             for (auto callbackInfo : subscribe->second) {
291                 callbackInfo->isDeleted = true;
292             }
293         }
294         return nullptr;
295     }
296 
ParseEventData(napi_env env,napi_value key,napi_value data,Val * & val,char keyChars[NAPI_VALUE_STRING_LEN])297     bool ParseEventData(napi_env env, napi_value key, napi_value data, Val* &val, char keyChars[NAPI_VALUE_STRING_LEN])
298     {
299         napi_valuetype valueType;
300         napi_typeof(env, key, &valueType);
301         if (valueType != napi_valuetype::napi_string) {
302             HILOGI("param is discarded because the key type of the event params must be String.");
303             return false;
304         }
305 
306         size_t keyLength = 0;
307         napi_get_value_string_utf8(env, key, keyChars, NAPI_VALUE_STRING_LEN, &keyLength);
308         napi_value value = nullptr;
309         napi_get_named_property(env, data, keyChars, &value);
310         napi_typeof(env, value, &valueType);
311         if (valueType == napi_valuetype::napi_boolean) {
312             val->type = DataType::BOOL;
313             napi_get_value_bool(env, value, &(val->value.bValue));
314             HILOGD("key:%{public}s value=%{public}d.", keyChars, val->value.bValue);
315         } else if (valueType == napi_valuetype::napi_number) {
316             val->type = DataType::INT;
317             napi_get_value_int32(env, value, &(val->value.nValue));
318             HILOGD("key:%{public}s value=%{public}d.", keyChars, val->value.nValue);
319         } else if (valueType == napi_valuetype::napi_string) {
320             napi_get_value_string_utf8(env, value, val->value.cValue, NAPI_VALUE_STRING_LEN, &keyLength);
321             val->type = DataType::STRING;
322             HILOGD("key:%{public}s value=%{public}s.", keyChars, val->value.cValue);
323         } else {
324             HILOGI("param=%{public}s is discarded because the value type is invalid.", keyChars);
325             return false;
326         }
327         return true;
328     }
329 
EmitWithEventData(napi_env env,napi_value argv,uint32_t eventId,Priority priority)330     bool EmitWithEventData(napi_env env, napi_value argv, uint32_t eventId, Priority priority)
331     {
332         napi_valuetype dataType;
333         napi_typeof(env, argv, &dataType);
334         NAPI_ASSERT_BASE(env, dataType == napi_object, "type mismatch for parameter 2", false);
335 
336         bool hasData = false;
337         napi_has_named_property(env, argv, "data", &hasData);
338         if (hasData) {
339             napi_value data = nullptr;
340             napi_get_named_property(env, argv, "data", &data);
341 
342             napi_value keyArr = nullptr;
343             napi_status status = napi_get_property_names(env, data, &keyArr);
344             if (status != napi_ok) {
345                 HILOGI("can not get property names");
346                 return false;
347             }
348             uint32_t len = 0;
349             status = napi_get_array_length(env, keyArr, &len);
350             if (status != napi_ok) {
351                 HILOGI("can not get array length");
352                 return false;
353             }
354 
355             EventData eventData;
356             bool hasEventData = false;
357             for (uint32_t i = 0; i < len; i++) {
358                 napi_value key = nullptr;
359                 napi_get_element(env, keyArr, i, &key);
360                 char keyChars[NAPI_VALUE_STRING_LEN] = {0};
361                 Val* val = new (std::nothrow) Val();
362                 if (!val) {
363                     HILOGE("new object failed");
364                     return false;
365                 }
366 
367                 if (!ParseEventData(env, key, data, val, keyChars)) {
368                     delete val;
369                     val = nullptr;
370                     continue;
371                 }
372                 eventData.insert(make_pair(keyChars, *val));
373                 hasEventData = true;
374                 delete val;
375                 val = nullptr;
376             }
377 
378             if (hasEventData) {
379                 HILOGI("sendevent with eventData id:%{public}d", eventId);
380                 auto event = InnerEvent::Get(eventId, make_unique<EventData>(eventData));
381                 eventHandler->SendEvent(event, 0, priority);
382                 return true;
383             }
384         }
385         return false;
386     }
387 
IsExistValidCallback(napi_env env,uint32_t eventId)388     bool IsExistValidCallback(napi_env env, uint32_t eventId)
389     {
390         std::lock_guard<std::mutex> lock(emitterInsMutex);
391         auto subscribe = emitterInstances.find(eventId);
392         if (subscribe == emitterInstances.end()) {
393             HILOGW("JS_Emit has no callback");
394             return false;
395         }
396         vector<AsyncCallbackInfo *> callbackInfo = subscribe->second;
397         size_t callbackSize = callbackInfo.size();
398         for (size_t i = 0; i < callbackSize; i++) {
399             if (!callbackInfo[i]->isDeleted) {
400                 return true;
401             }
402         }
403         return false;
404     }
405 
JS_Emit(napi_env env,napi_callback_info cbinfo)406     napi_value JS_Emit(napi_env env, napi_callback_info cbinfo)
407     {
408         HILOGI("JS_Emit start");
409         size_t argc = ARGC_NUM;
410         napi_value argv[ARGC_NUM] = {0};
411         NAPI_CALL(env, napi_get_cb_info(env, cbinfo, &argc, argv, NULL, NULL));
412         NAPI_ASSERT(env, argc >= 1, "requires more than 1 parameter");
413         HILOGI("JS_Emit argc:%{public}zu", argc);
414 
415         napi_valuetype eventValueType;
416         napi_typeof(env, argv[0], &eventValueType);
417         NAPI_ASSERT(env, eventValueType == napi_object, "type mismatch for parameter 1");
418 
419         bool hasEventId = false;
420         napi_value value;
421         napi_has_named_property(env, argv[0], "eventId", &hasEventId);
422         NAPI_ASSERT(env, hasEventId == true, "Wrong argument 1");
423         napi_get_named_property(env, argv[0], "eventId", &value);
424         uint32_t eventId;
425         napi_get_value_uint32(env, value, &eventId);
426         HILOGI("JS_Emit eventIdValue:%{public}d", eventId);
427 
428         if (!IsExistValidCallback(env, eventId)) {
429             HILOGW("JS_Emit has no valid callback");
430             return nullptr;
431         }
432 
433         bool hasPriority = false;
434         napi_has_named_property(env, argv[0], "priority", &hasPriority);
435         Priority priority = Priority::LOW;
436         if (hasPriority) {
437             napi_get_named_property(env, argv[0], "priority", &value);
438             uint32_t priorityValue;
439             napi_get_value_uint32(env, value, &priorityValue);
440             HILOGI("JS_Emit priority:%{public}d", priorityValue);
441             priority = static_cast<Priority>(priorityValue);
442         }
443 
444         if (argc == ARGC_NUM && EmitWithEventData(env, argv[1], eventId, priority)) {
445             HILOGI("EmitWithEventData sucess");
446             return nullptr;
447         } else {
448             HILOGI("JS_Emit sendevent without id:%{public}d", eventId);
449             auto event = InnerEvent::Get(eventId, make_unique<EventData>());
450             eventHandler->SendEvent(event, 0, priority);
451             return nullptr;
452         }
453     }
454 
EnumEventClassConstructor(napi_env env,napi_callback_info info)455     napi_value EnumEventClassConstructor(napi_env env, napi_callback_info info)
456     {
457         napi_value thisArg = nullptr;
458         void *data = nullptr;
459 
460         napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data);
461 
462         napi_value global = nullptr;
463         napi_get_global(env, &global);
464 
465         return thisArg;
466     }
467 
CreateEnumEventPriority(napi_env env,napi_value exports)468     napi_value CreateEnumEventPriority(napi_env env, napi_value exports)
469     {
470         napi_value immediate = nullptr;
471         napi_value high = nullptr;
472         napi_value low = nullptr;
473         napi_value idle = nullptr;
474 
475         napi_create_uint32(env, (uint32_t)Priority::IMMEDIATE, &immediate);
476         napi_create_uint32(env, (uint32_t)Priority::HIGH, &high);
477         napi_create_uint32(env, (uint32_t)Priority::LOW, &low);
478         napi_create_uint32(env, (uint32_t)Priority::IDLE, &idle);
479 
480         napi_property_descriptor desc[] = {
481             DECLARE_NAPI_STATIC_PROPERTY("IMMEDIATE", immediate),
482             DECLARE_NAPI_STATIC_PROPERTY("HIGH", high),
483             DECLARE_NAPI_STATIC_PROPERTY("LOW", low),
484             DECLARE_NAPI_STATIC_PROPERTY("IDLE", idle),
485         };
486         napi_value result = nullptr;
487         napi_define_class(env, "EventPriority", NAPI_AUTO_LENGTH, EnumEventClassConstructor, nullptr,
488             sizeof(desc) / sizeof(*desc), desc, &result);
489 
490         napi_set_named_property(env, exports, "EventPriority", result);
491 
492         return exports;
493     }
494 
EmitterInit(napi_env env,napi_value exports)495     napi_value EmitterInit(napi_env env, napi_value exports)
496     {
497         HILOGE("enter");
498         napi_property_descriptor desc[] = {
499             DECLARE_NAPI_FUNCTION("on", JS_On),
500             DECLARE_NAPI_FUNCTION("once", JS_Once),
501             DECLARE_NAPI_FUNCTION("off", JS_Off),
502             DECLARE_NAPI_FUNCTION("emit", JS_Emit),
503         };
504         NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
505 
506         CreateEnumEventPriority(env, exports);
507 
508         eventHandler = EventHandlerInstance::GetInstance();
509         return exports;
510     }
511 }  // namespace AppExecFwk
512 }  // namespace OHOS
513