1 /*
2 * Copyright (c) 2023 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 "nfc_napi_hce_adapter.h"
17 #include "loghelper.h"
18 #include "hce_service.h"
19 #include <uv.h>
20
21 namespace OHOS {
22 namespace NFC {
23 namespace KITS {
24 static const uint16_t DEFAULT_REF_COUNT = 1;
25 constexpr uint32_t INVALID_REF_COUNT = 0xFF;
26 static std::set<std::string> g_supportEventList = {
27 KITS::EVENT_HCE_CMD,
28 };
29
30 bool EventRegister::isEventRegistered = false;
31
32 static std::mutex g_regInfoMutex;
33 static std::map<std::string, RegObj> g_eventRegisterInfo;
34
35 class NapiEvent {
36 public:
37 napi_value CreateResult(const napi_env& env, const std::vector<uint8_t>& data);
38 bool CheckIsRegister(const std::string& type);
39 void EventNotify(AsyncEventData* asyncEvent);
40
41 template <typename T>
CheckAndNotify(const std::string& type, const T& obj)42 void CheckAndNotify(const std::string& type, const T& obj)
43 {
44 std::lock_guard<std::mutex> guard(g_regInfoMutex);
45 if (!CheckIsRegister(type)) {
46 return;
47 }
48
49 const RegObj& regObj = g_eventRegisterInfo[type];
50
51 auto result = [this, env = regObj.m_regEnv, obj]() -> napi_value { return CreateResult(env, obj); };
52 AsyncEventData* asyncEvent =
53 new (std::nothrow) AsyncEventData(regObj.m_regEnv, regObj.m_regHanderRef, result);
54 if (asyncEvent == nullptr) {
55 return;
56 }
57 EventNotify(asyncEvent);
58 }
59 };
60
61 class HceCmdListenerEvent : public IHceCmdCallback, public NapiEvent {
62 public:
HceCmdListenerEvent()63 HceCmdListenerEvent() {}
64
~HceCmdListenerEvent()65 virtual ~HceCmdListenerEvent() {}
66
67 public:
68 void OnCeApduData(const std::vector<uint8_t>& data) override
69 {
70 std::string dataStr(data.begin(), data.end());
71 InfoLog("OnNotify rcvd ce adpu data: Data Length = %{public}zu; Data "
72 "as String = %{public}s",
73 data.size(), dataStr.c_str());
74 CheckAndNotify(KITS::EVENT_HCE_CMD, data);
75 }
76
77 OHOS::sptr<OHOS::IRemoteObject> AsObject() override { return nullptr; }
78 };
79
80 sptr<HceCmdListenerEvent> hceCmdListenerEvent =
81 sptr<HceCmdListenerEvent>(new (std::nothrow) HceCmdListenerEvent());
82
Init(napi_env env, napi_value exports)83 napi_value NfcNapiHceAdapter::Init(napi_env env, napi_value exports)
84 {
85 napi_status status;
86 napi_property_descriptor properties[] = {
87 DECLARE_NAPI_FUNCTION("on", NfcNapiHceAdapter::OnHceCmd),
88 DECLARE_NAPI_FUNCTION("transmit", NfcNapiHceAdapter::Transmit),
89 DECLARE_NAPI_FUNCTION("stop", NfcNapiHceAdapter::StopHce),
90 DECLARE_NAPI_FUNCTION("stopHCE", NfcNapiHceAdapter::StopHCEDeprecated),
91 DECLARE_NAPI_FUNCTION("startHCE", NfcNapiHceAdapter::StartHCEDeprecated),
92 DECLARE_NAPI_FUNCTION("start", NfcNapiHceAdapter::StartHCE),
93 DECLARE_NAPI_FUNCTION("sendResponse", NfcNapiHceAdapter::SendResponse),
94 };
95
96 char hceClassName[] = "HceService";
97
98 napi_value cons;
99 status = napi_define_class(env, hceClassName, NAPI_AUTO_LENGTH, NfcNapiHceAdapter::Constructor, nullptr,
100 sizeof(properties) / sizeof(napi_property_descriptor), properties, &cons);
101 NAPI_ASSERT(env, status == napi_ok, "NfcNapiHceAdapter define class failed");
102
103 status = napi_set_named_property(env, exports, hceClassName, cons);
104 NAPI_ASSERT(env, status == napi_ok, "NfcNapiHceAdapter set name property failed");
105 return cons;
106 }
107
Constructor(napi_env env, napi_callback_info info)108 napi_value NfcNapiHceAdapter::Constructor(napi_env env, napi_callback_info info)
109 {
110 DebugLog("NfcNapiHceAdapter Constructor");
111 napi_status status;
112 napi_value jsHceService;
113 size_t argc = 1;
114 napi_value args[1];
115 status = napi_get_cb_info(env, info, &argc, args, &jsHceService, nullptr);
116 NAPI_ASSERT(env, status == napi_ok, "NfcNapiHceAdapter Constructor get_cb_info failed");
117 NfcNapiHceAdapter* hceService = new NfcNapiHceAdapter();
118 status = napi_wrap(env, jsHceService, hceService, NfcNapiHceAdapter::Destructor, nullptr, nullptr);
119 NAPI_ASSERT(env, status == napi_ok, "NfcNapiHceAdapter Constructor wrap failed");
120 return jsHceService;
121 }
122
Destructor(napi_env env, void* nativeObject, void* hint)123 void NfcNapiHceAdapter::Destructor(napi_env env, void* nativeObject, void* hint)
124 {
125 NfcNapiHceAdapter* nfcNapiHceAdapter = static_cast<NfcNapiHceAdapter*>(nativeObject);
126 nfcNapiHceAdapter->~NfcNapiHceAdapter();
127 delete nfcNapiHceAdapter;
128 }
129
OnHceCmd(napi_env env, napi_callback_info info)130 napi_value NfcNapiHceAdapter::OnHceCmd(napi_env env, napi_callback_info info)
131 {
132 // js method on("hce",callback)
133 size_t requireArgc = ARGV_NUM_2;
134 size_t argc = ARGV_NUM_2;
135 napi_value argv[2] = {0};
136 napi_value thisVar = 0;
137 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
138 NAPI_ASSERT(env, argc == requireArgc, "requires 2 parameter");
139
140 napi_valuetype eventName = napi_undefined;
141 napi_typeof(env, argv[0], &eventName);
142 NAPI_ASSERT(env, eventName == napi_string, "type mismatch for parameter 1");
143
144 napi_valuetype handler = napi_undefined;
145 napi_typeof(env, argv[1], &handler);
146 NAPI_ASSERT(env, handler == napi_function, "type mismatch for parameter 2");
147
148 char type[64] = {0};
149 size_t typeLen = 0;
150 napi_get_value_string_utf8(env, argv[0], type, sizeof(type), &typeLen);
151 EventRegister::GetInstance().Register(env, type, argv[1]);
152 napi_value result = nullptr;
153 napi_get_undefined(env, &result);
154 return result;
155 }
CheckTransmitParametersAndThrow(napi_env env, const napi_value parameters[], size_t parameterCount)156 static bool CheckTransmitParametersAndThrow(napi_env env, const napi_value parameters[],
157 size_t parameterCount)
158 {
159 if (parameterCount == ARGV_NUM_1) {
160 if (!CheckParametersAndThrow(env, parameters, {napi_object}, "data", "number[]")) {
161 return false;
162 }
163 return true;
164 } else if (parameterCount == ARGV_NUM_2) {
165 if (!CheckParametersAndThrow(env, parameters, {napi_object, napi_function}, "data & callback",
166 "number[] & function") ||
167 !CheckArrayNumberAndThrow(env, parameters[ARGV_NUM_0], "data", "number[]")) {
168 return false;
169 }
170 return true;
171 } else {
172 napi_throw(env, GenerateBusinessError(env, BUSI_ERR_PARAM,
173 BuildErrorMessage(BUSI_ERR_PARAM, "", "", "", "")));
174 return false;
175 }
176 }
177
GetInstance()178 EventRegister& EventRegister::GetInstance()
179 {
180 static EventRegister inst;
181 return inst;
182 }
183
IsEventSupport(const std::string& type)184 bool EventRegister::IsEventSupport(const std::string& type)
185 {
186 return g_supportEventList.find(type) != g_supportEventList.end();
187 }
188
Register(const napi_env& env, const std::string& type, napi_value handler)189 void EventRegister::Register(const napi_env& env, const std::string& type, napi_value handler)
190 {
191 InfoLog("Register eventType: %{public}s", type.c_str());
192 if (!IsEventSupport(type)) {
193 DebugLog("Register eventType error or not support!");
194 return;
195 }
196 std::lock_guard<std::mutex> guard(g_regInfoMutex);
197 if (!isEventRegistered) {
198 if (RegHceCmdCallbackEvents(env, type) != KITS::ERR_NONE) {
199 return;
200 }
201 isEventRegistered = true;
202 }
203 napi_ref handlerRef = nullptr;
204 napi_create_reference(env, handler, 1, &handlerRef);
205 RegObj regObj(env, handlerRef);
206 auto iter = g_eventRegisterInfo.find(type);
207 if (iter == g_eventRegisterInfo.end()) {
208 g_eventRegisterInfo[type] = regObj;
209 DebugLog("Register, add new type.");
210 return;
211 }
212
213 auto oldRegObj = iter->second;
214 if (env == oldRegObj.m_regEnv) {
215 DebugLog("handler env is same");
216 napi_value oldHandler = nullptr;
217 napi_get_reference_value(oldRegObj.m_regEnv, oldRegObj.m_regHanderRef, &oldHandler);
218 bool isEqual = false;
219 napi_strict_equals(oldRegObj.m_regEnv, oldHandler, handler, &isEqual);
220 if (isEqual) {
221 DebugLog("handler function is same");
222 } else {
223 iter->second = regObj;
224 }
225 } else {
226 DebugLog("handler env is different");
227 iter->second = regObj;
228 }
229 }
230
RegHceCmdCallbackEvents(const napi_env& env, const std::string& type)231 ErrorCode EventRegister::RegHceCmdCallbackEvents(const napi_env& env, const std::string& type)
232 {
233 HceService hceService = HceService::GetInstance();
234 ErrorCode ret = hceService.RegHceCmdCallback(hceCmdListenerEvent, type);
235 if (!CheckHceStatusCodeAndThrow(env, ret, "on")) {
236 ErrorLog("RegHceCmdCallback, statusCode = %{public}d", ret);
237 }
238 if (ret != KITS::ERR_NONE) {
239 DebugLog("RegHceCmdCallbackEvents failed!");
240 return ret;
241 }
242 return ret;
243 }
244
Unregister(const napi_env& env, ElementName& element)245 void EventRegister::Unregister(const napi_env& env, ElementName& element)
246 {
247 std::lock_guard<std::mutex> guard(g_regInfoMutex);
248 if (!g_eventRegisterInfo.empty()) {
249 if (UnregisterHceEvents(env, element) != KITS::ERR_NONE) {
250 ErrorLog("hce EventRegister::Unregister, unreg event failed.");
251 return;
252 }
253 }
254
255 DeleteHceCmdRegisterObj(env);
256
257 if (!g_eventRegisterInfo.empty()) {
258 g_eventRegisterInfo.erase(KITS::EVENT_HCE_CMD);
259 isEventRegistered = false;
260 }
261 InfoLog("hce EventRegister, isEvtRegistered = %{public}d", isEventRegistered);
262 }
263
DeleteHceCmdRegisterObj(const napi_env& env)264 void EventRegister::DeleteHceCmdRegisterObj(const napi_env& env)
265 {
266 auto iter = g_eventRegisterInfo.find(KITS::EVENT_HCE_CMD);
267 if (iter == g_eventRegisterInfo.end()) {
268 InfoLog("no hce cmd register info.");
269 return;
270 }
271
272 auto oldRegObj = iter->second;
273 if (env == oldRegObj.m_regEnv) {
274 DebugLog("env is same");
275 uint32_t refCount = INVALID_REF_COUNT;
276 napi_reference_unref(oldRegObj.m_regEnv, oldRegObj.m_regHanderRef, &refCount);
277 InfoLog(
278 "DeleteHceCmdRegisterObj, m_regEnv: %{private}p, m_regHanderRef: %{private}p, refCount: %{public}d",
279 oldRegObj.m_regEnv, oldRegObj.m_regHanderRef, refCount);
280 if (refCount == 0) {
281 InfoLog("DeleteHceCmdRegisterObj, ref count is zero");
282 napi_delete_reference(oldRegObj.m_regEnv, oldRegObj.m_regHanderRef);
283 }
284 } else {
285 InfoLog("DeleteHceCmdRegisterObj, env is different, env: %{private}p m_regEnv:: %{private}p", env,
286 oldRegObj.m_regEnv);
287 }
288 }
289
UnregisterHceEvents(const napi_env& env, ElementName& element)290 ErrorCode EventRegister::UnregisterHceEvents(const napi_env& env, ElementName& element)
291 {
292 HceService hceService = HceService::GetInstance();
293 ErrorCode ret = hceService.StopHce(element);
294 if (!CheckHceStatusCodeAndThrow(env, ret, "stop")) {
295 ErrorLog("StopHce, statusCode = %{public}d", ret);
296 }
297 if (ret != KITS::ERR_NONE) {
298 ErrorLog("UnregisterHceEvents failed!");
299 return ret;
300 }
301 return ret;
302 }
303
after_work_cb(uv_work_t* work, int status)304 static void after_work_cb(uv_work_t* work, int status)
305 {
306 AsyncEventData* asyncData = static_cast<AsyncEventData*>(work->data);
307 InfoLog("Napi event uv_queue_work, env: %{private}p, status: %{public}d", asyncData->env, status);
308 napi_handle_scope scope = nullptr;
309 uint32_t refCount = INVALID_REF_COUNT;
310 napi_open_handle_scope(asyncData->env, &scope);
311 napi_value handler = nullptr;
312 if (scope == nullptr) {
313 ErrorLog("after_work_cb: scope is nullptr");
314 goto EXIT;
315 }
316
317 napi_get_reference_value(asyncData->env, asyncData->callbackRef, &handler);
318 if (handler == nullptr) {
319 ErrorLog("after_work_cb: handler is nullptr");
320 goto EXIT;
321 }
322 napi_value resArgs[ARGV_INDEX_2];
323 napi_get_undefined(asyncData->env, &resArgs[ARGV_INDEX_0]);
324 resArgs[ARGV_INDEX_1] = asyncData->packResult();
325 napi_value returnVal;
326 napi_get_undefined(asyncData->env, &returnVal);
327 if (napi_call_function(asyncData->env, nullptr, handler, ARGV_INDEX_2, resArgs, &returnVal) != napi_ok) {
328 DebugLog("Report event to Js failed");
329 } else {
330 DebugLog("Report event to Js success");
331 }
332
333 EXIT:
334 napi_close_handle_scope(asyncData->env, scope);
335 napi_reference_unref(asyncData->env, asyncData->callbackRef, &refCount);
336 InfoLog("after_work_cb unref, env: %{private}p, callbackRef: %{private}p, "
337 "refCount: %{public}d",
338 asyncData->env, asyncData->callbackRef, refCount);
339 if (refCount == 0) {
340 napi_delete_reference(asyncData->env, asyncData->callbackRef);
341 }
342 delete asyncData;
343 delete work;
344 asyncData = nullptr;
345 work = nullptr;
346 }
347
EventNotify(AsyncEventData* asyncEvent)348 void NapiEvent::EventNotify(AsyncEventData* asyncEvent)
349 {
350 DebugLog("Enter hce cmd event notify");
351 if (asyncEvent == nullptr) {
352 DebugLog("hce asyncEvent is null.");
353 return;
354 }
355 uv_loop_s* loop = nullptr;
356 napi_get_uv_event_loop(asyncEvent->env, &loop);
357
358 uv_work_t* work = new uv_work_t;
359 if (work == nullptr) {
360 DebugLog("hce uv_work_t work is null.");
361 delete asyncEvent;
362 asyncEvent = nullptr;
363 return;
364 }
365
366 uint32_t refCount = INVALID_REF_COUNT;
367 napi_reference_ref(asyncEvent->env, asyncEvent->callbackRef, &refCount);
368 work->data = asyncEvent;
369 uv_after_work_cb tmp_after_work_cb = after_work_cb;
370 int ret = uv_queue_work(loop, work, [](uv_work_t* work) {}, tmp_after_work_cb);
371 if (ret != 0) {
372 ErrorLog("uv_queue_work failed!");
373 delete asyncEvent;
374 delete work;
375 }
376 }
377
CreateResult(const napi_env& env, const std::vector<uint8_t>& data)378 napi_value NapiEvent::CreateResult(const napi_env& env, const std::vector<uint8_t>& data)
379 {
380 napi_value result;
381 napi_create_array_with_length(env, data.size(), &result);
382 for (uint32_t i = 0; i < data.size(); i++) {
383 napi_value item;
384 napi_create_uint32(env, static_cast<uint32_t>(data[i]), &item);
385 napi_set_element(env, result, i, item);
386 }
387 return result;
388 }
389
CheckIsRegister(const std::string& type)390 bool NapiEvent::CheckIsRegister(const std::string& type)
391 {
392 return g_eventRegisterInfo.find(type) != g_eventRegisterInfo.end();
393 }
394
NativeTransmit(napi_env env, void* data)395 static void NativeTransmit(napi_env env, void* data)
396 {
397 auto context = static_cast<NfcHceSessionContext*>(data);
398 context->errorCode = BUSI_ERR_TAG_STATE_INVALID;
399 std::string hexRespData;
400 HceService hceService = HceService::GetInstance();
401 context->errorCode = hceService.SendRawFrame(context->dataBytes, true, hexRespData);
402 context->value = hexRespData;
403 context->resolved = true;
404 }
405
TransmitCallback(napi_env env, napi_status status, void* data)406 static void TransmitCallback(napi_env env, napi_status status, void* data)
407 {
408 auto context = static_cast<NfcHceSessionContext*>(data);
409 napi_value callbackValue = nullptr;
410 if (status == napi_ok && context->resolved && context->errorCode == ErrorCode::ERR_NONE) {
411 napi_get_undefined(env, &callbackValue);
412 DoAsyncCallbackOrPromise(env, context, callbackValue);
413 } else {
414 int errCode = BuildOutputErrorCodeHce(context->errorCode);
415 std::string errMessage = BuildErrorMessage(errCode, "transmit", CARD_EMULATION_PERM_DESC, "", "");
416 ThrowAsyncError(env, context, errCode, errMessage);
417 }
418 }
419
Transmit(napi_env env, napi_callback_info info)420 napi_value NfcNapiHceAdapter::Transmit(napi_env env, napi_callback_info info)
421 {
422 // JS API define1: Transmit(data: number[]): Promise<number[]>
423 // JS API define2: Transmit(data: number[], callback:
424 // AsyncCallback<number[]>): void
425 size_t paramsCount = ARGV_NUM_2;
426 napi_value params[ARGV_NUM_2] = {0};
427 void* data = nullptr;
428 napi_value thisVar = nullptr;
429 napi_get_cb_info(env, info, ¶msCount, params, &thisVar, &data);
430
431 if (!CheckTransmitParametersAndThrow(env, params, paramsCount)) {
432 return CreateUndefined(env);
433 }
434
435 auto context = std::make_unique<NfcHceSessionContext>().release();
436 if (!CheckContextAndThrow(env, context, BUSI_ERR_TAG_STATE_INVALID)) {
437 return CreateUndefined(env);
438 }
439
440 // parse the params
441 int32_t hexCmdData = 0;
442 napi_value hexCmdDataValue = nullptr;
443 uint32_t arrayLength = 0;
444 std::vector<unsigned char> dataBytes = {};
445 NAPI_CALL(env, napi_get_array_length(env, params[ARGV_INDEX_0], &arrayLength));
446 for (uint32_t i = 0; i < arrayLength; ++i) {
447 NAPI_CALL(env, napi_get_element(env, params[ARGV_INDEX_0], i, &hexCmdDataValue));
448 NAPI_CALL(env, napi_get_value_int32(env, hexCmdDataValue, &hexCmdData));
449 dataBytes.push_back(hexCmdData);
450 }
451 context->dataBytes =
452 NfcSdkCommon::BytesVecToHexString(static_cast<unsigned char*>(dataBytes.data()), dataBytes.size());
453 if (paramsCount == ARGV_NUM_2) {
454 napi_create_reference(env, params[ARGV_INDEX_1], DEFAULT_REF_COUNT, &context->callbackRef);
455 }
456
457 napi_value result = HandleAsyncWork(env, context, "Transmit", NativeTransmit, TransmitCallback);
458 return result;
459 }
460
StopHce(napi_env env, napi_callback_info cbinfo)461 napi_value NfcNapiHceAdapter::StopHce(napi_env env, napi_callback_info cbinfo)
462 {
463 size_t argc = ARGV_NUM_1;
464 napi_value argv[ARGV_NUM_1] = {0};
465 napi_value thisVar = 0;
466 napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
467 ElementName element;
468 if (!CheckArgCountAndThrow(env, argc, ARGV_NUM_1) ||
469 !ParseElementName(env, element, argv[ARGV_INDEX_0])) {
470 ErrorLog("Stop hce: parse args failed");
471 return CreateUndefined(env);
472 }
473
474 EventRegister::GetInstance().Unregister(env, element);
475 napi_value result = nullptr;
476 napi_get_undefined(env, &result);
477 return result;
478 }
StartHCEDeprecated(napi_env env, napi_callback_info cbinfo)479 napi_value NfcNapiHceAdapter::StartHCEDeprecated(napi_env env, napi_callback_info cbinfo)
480 {
481 return CreateUndefined(env);
482 }
StartHCE(napi_env env, napi_callback_info cbinfo)483 napi_value NfcNapiHceAdapter::StartHCE(napi_env env, napi_callback_info cbinfo)
484 {
485 size_t argc = ARGV_NUM_2;
486 napi_value argv[ARGV_NUM_2] = {0};
487 napi_value thisVar = 0;
488 napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
489 ElementName element;
490 std::vector<std::string> aidVec;
491 if (!CheckArgCountAndThrow(env, argc, ARGV_NUM_2) || !ParseElementName(env, element, argv[ARGV_INDEX_0]) ||
492 !ParseStringVector(env, aidVec, argv[ARGV_INDEX_1], MAX_AID_LIST_NUM_PER_APP)) {
493 ErrorLog("Start hce: parse args failed");
494 return CreateUndefined(env);
495 }
496
497 HceService hceService = HceService::GetInstance();
498 ErrorCode ret = hceService.StartHce(element, aidVec);
499 if (!CheckHceStatusCodeAndThrow(env, ret, "start")) {
500 ErrorLog("StartHce, statusCode = %{public}d", ret);
501 }
502 return CreateUndefined(env);
503 }
StopHCEDeprecated(napi_env env, napi_callback_info cbinfo)504 napi_value NfcNapiHceAdapter::StopHCEDeprecated(napi_env env, napi_callback_info cbinfo)
505 {
506 return CreateUndefined(env);
507 }
SendResponse(napi_env env, napi_callback_info cbinfo)508 napi_value NfcNapiHceAdapter::SendResponse(napi_env env, napi_callback_info cbinfo)
509 {
510 return CreateUndefined(env);
511 }
512 } // namespace KITS
513 } // namespace NFC
514 } // namespace OHOS