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, &paramsCount, 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