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