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