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