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 <unistd.h>
17 #include <cinttypes>
18 #include <cstdio>
19 #include <cstdlib>
20 #include <optional>
21 #include <string>
22 #include <map>
23 #include <vector>
24 #include <uv.h>
25 
26 #include "napi_remote_object.h"
27 #include "device_manager_middle.h"
28 
29 namespace OHOS {
30 namespace ExternalDeviceManager {
31 constexpr int32_t PARAM_COUNT_0 = 0;
32 constexpr int32_t PARAM_COUNT_1 = 1;
33 constexpr int32_t PARAM_COUNT_2 = 2;
34 constexpr int32_t PARAM_COUNT_3 = 3;
35 constexpr uint64_t MAX_JS_NUMBER = 9007199254740991;
36 
37 static const std::map<int32_t, std::string> ERROR_MESSAGES = {
38     {SERVICE_EXCEPTION,  "ExternalDeviceManager service exception."},
39     {PERMISSION_DENIED,  "Permission denied."},
40     {PERMISSION_NOT_SYSTEM_APP,  "Permission denied. A non-system application cannot call a system API."},
41     {PARAMETER_ERROR,  "The parameter check failed."},
42     {SERVICE_EXCEPTION_NEW, "ExternalDeviceManager service exception."}
43 };
44 
45 static std::mutex mapMutex;
46 static std::map<uint64_t, sptr<AsyncData>> g_callbackMap = {};
47 static DriverExtMgrClient &g_edmClient = DriverExtMgrClient::GetInstance();
48 static sptr<DeviceManagerCallback> g_edmCallback = new (std::nothrow) DeviceManagerCallback {};
49 
50 static napi_value ConvertToBusinessError(const napi_env &env, const ErrMsg &errMsg);
51 static napi_value ConvertToJsDeviceId(const napi_env &env, uint64_t deviceId);
52 static napi_value GetCallbackResult(const napi_env &env, uint64_t deviceId, const sptr<IRemoteObject> &drvExtObj);
53 
BindDeviceWorkCb(uv_work_t * work,int status)54 static void BindDeviceWorkCb(uv_work_t *work, int status)
55 {
56     if (work == nullptr) {
57         return;
58     }
59     sptr<AsyncData> data(reinterpret_cast<AsyncData *>(work->data));
60     data->DecStrongRef(nullptr);
61     delete work;
62 
63     napi_value result = GetCallbackResult(data->env, data->deviceId, data->drvExtObj);
64     napi_value err = ConvertToBusinessError(data->env, data->errMsg);
65     if (data->bindCallback != nullptr) {
66         napi_value callback;
67         napi_get_reference_value(data->env, data->bindCallback, &callback);
68         napi_value argv[PARAM_COUNT_2] = {err, result};
69         napi_value callResult;
70         napi_call_function(data->env, nullptr, callback, PARAM_COUNT_2, argv, &callResult);
71         EDM_LOGI(MODULE_DEV_MGR, "bind device callback finish.");
72     } else if (data->bindDeferred != nullptr) {
73         if (data->errMsg.IsOk()) {
74             napi_resolve_deferred(data->env, data->bindDeferred, result);
75         } else {
76             napi_reject_deferred(data->env, data->bindDeferred, err);
77         }
78         EDM_LOGI(MODULE_DEV_MGR, "bind device promise finish.");
79     }
80 }
81 
UvDeleteRef(uv_work_t * work,int status)82 void UvDeleteRef(uv_work_t *work, int status)
83 {
84     if (work == nullptr) {
85         return;
86     }
87     AsyncDataWorker *data = static_cast<AsyncDataWorker *>(work->data);
88     if (data == nullptr) {
89         delete work;
90         work = nullptr;
91         return;
92     }
93     if (data->bindCallback != nullptr) {
94         napi_delete_reference(data->env, data->bindCallback);
95     }
96     if (data->onDisconnect != nullptr) {
97         napi_delete_reference(data->env, data->onDisconnect);
98     }
99     if (data->unbindCallback != nullptr) {
100         napi_delete_reference(data->env, data->unbindCallback);
101     }
102     delete data;
103     data = nullptr;
104     delete work;
105 }
106 
DeleteNapiRef()107 void AsyncData::DeleteNapiRef()
108 {
109     if (env == nullptr) {
110         return;
111     }
112     uv_loop_t* loop = nullptr;
113     NAPI_CALL_RETURN_VOID(env, napi_get_uv_event_loop(env, &loop));
114     AsyncDataWorker *data = new (std::nothrow) AsyncDataWorker();
115     if (data == nullptr) {
116         EDM_LOGE(MODULE_DEV_MGR, "new AsyncDataWorker fail");
117         return;
118     }
119     data->env = env;
120     data->bindCallback = bindCallback;
121     data->onDisconnect = onDisconnect;
122     data->unbindCallback = unbindCallback;
123 
124     uv_work_t *work = new (std::nothrow) uv_work_t;
125     if (work == nullptr) {
126         EDM_LOGE(MODULE_DEV_MGR, "new work fail");
127         delete data;
128         data = nullptr;
129         return;
130     }
131     work->data = static_cast<void *>(data);
132     auto ret = uv_queue_work(
133         loop, work, [](uv_work_t *work) {}, UvDeleteRef);
134     if (ret != 0) {
135         delete data;
136         data = nullptr;
137         delete work;
138         work = nullptr;
139     }
140 }
141 
OnConnect(uint64_t deviceId,const sptr<IRemoteObject> & drvExtObj,const ErrMsg & errMsg)142 void DeviceManagerCallback::OnConnect(uint64_t deviceId, const sptr<IRemoteObject> &drvExtObj, const ErrMsg &errMsg)
143 {
144     EDM_LOGE(MODULE_DEV_MGR, "bind device callback: %{public}016" PRIX64, deviceId);
145     std::lock_guard<std::mutex> mapLock(mapMutex);
146     if (g_callbackMap.count(deviceId) == 0) {
147         EDM_LOGE(MODULE_DEV_MGR, "device OnConnect is null");
148         return;
149     }
150 
151     auto asyncData = g_callbackMap[deviceId];
152     if (!errMsg.IsOk()) {
153         g_callbackMap.erase(deviceId);
154     }
155     uv_loop_t* loop = nullptr;
156     NAPI_CALL_RETURN_VOID(asyncData->env, napi_get_uv_event_loop(asyncData->env, &loop));
157     uv_work_t* work = new (std::nothrow) uv_work_t;
158     if (work == nullptr) {
159         EDM_LOGE(MODULE_DEV_MGR, "new work fail");
160         return;
161     }
162     asyncData->drvExtObj = drvExtObj;
163     asyncData->errMsg = errMsg;
164     asyncData->IncStrongRef(nullptr);
165     work->data = asyncData.GetRefPtr();
166     auto ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, BindDeviceWorkCb);
167     if (ret != 0) {
168         delete work;
169         asyncData->DecStrongRef(nullptr);
170     }
171 }
172 
DisConnectWorkCb(uv_work_t * work,int status)173 static void DisConnectWorkCb(uv_work_t *work, int status)
174 {
175     if (work == nullptr) {
176             return;
177         }
178         sptr<AsyncData> data(reinterpret_cast<AsyncData*>(work->data));
179         data->DecStrongRef(nullptr);
180         delete work;
181 
182         napi_value disConnCallback;
183         napi_status napiSatus = napi_get_reference_value(data->env, data->onDisconnect, &disConnCallback);
184         if (napiSatus == napi_ok) {
185             napi_value err = ConvertToBusinessError(data->env, data->errMsg);
186             napi_value result = ConvertToJsDeviceId(data->env, data->deviceId);
187             napi_value argv[PARAM_COUNT_2] = {err, result};
188             napi_value callResult;
189             napi_call_function(data->env, nullptr, disConnCallback, PARAM_COUNT_2, argv, &callResult);
190             EDM_LOGI(MODULE_DEV_MGR, "onDisconnect callback finish.");
191         }
192 
193         napi_value err = ConvertToBusinessError(data->env, data->unBindErrMsg);
194         napi_value result = ConvertToJsDeviceId(data->env, data->deviceId);
195         if (data->unbindCallback != nullptr) {
196             napi_value callback;
197             NAPI_CALL_RETURN_VOID(data->env, napi_get_reference_value(data->env, data->unbindCallback, &callback));
198 
199             napi_value argv[PARAM_COUNT_2] = {err, result};
200             napi_value callResult;
201             napi_call_function(data->env, nullptr, callback, PARAM_COUNT_2, argv, &callResult);
202             EDM_LOGI(MODULE_DEV_MGR, "unbind device callback finish.");
203         } else if (data->unbindDeferred != nullptr) {
204             if (data->unBindErrMsg.IsOk()) {
205                 napi_resolve_deferred(data->env, data->unbindDeferred, result);
206             } else {
207                 napi_reject_deferred(data->env, data->unbindDeferred, err);
208             }
209             EDM_LOGI(MODULE_DEV_MGR, "unbind device promise finish.");
210         }
211 }
212 
OnDisconnect(uint64_t deviceId,const ErrMsg & errMsg)213 void DeviceManagerCallback::OnDisconnect(uint64_t deviceId, const ErrMsg &errMsg)
214 {
215     EDM_LOGE(MODULE_DEV_MGR, "device onDisconnect: %{public}016" PRIX64, deviceId);
216     std::lock_guard<std::mutex> mapLock(mapMutex);
217     if (g_callbackMap.count(deviceId) == 0) {
218         EDM_LOGE(MODULE_DEV_MGR, "device callback map is null");
219         return;
220     }
221 
222     auto asyncData = g_callbackMap[deviceId];
223     g_callbackMap.erase(deviceId);
224     if (asyncData == nullptr || (asyncData->onDisconnect == nullptr && asyncData->unbindCallback == nullptr
225         && asyncData->unbindDeferred == nullptr)) {
226         EDM_LOGE(MODULE_DEV_MGR, "device callback is null");
227         return;
228     }
229     uv_loop_t* loop = nullptr;
230     NAPI_CALL_RETURN_VOID(asyncData->env, napi_get_uv_event_loop(asyncData->env, &loop));
231     uv_work_t* work = new (std::nothrow) uv_work_t;
232     if (work == nullptr) {
233         EDM_LOGE(MODULE_DEV_MGR, "new work fail");
234         return;
235     }
236     asyncData->errMsg = errMsg;
237     asyncData->IncStrongRef(nullptr);
238     work->data = asyncData.GetRefPtr();
239     auto ret = uv_queue_work(loop, work, [] (uv_work_t *work) {}, DisConnectWorkCb);
240     if (ret != 0) {
241         delete work;
242         asyncData->DecStrongRef(nullptr);
243     }
244 }
245 
OnUnBind(uint64_t deviceId,const ErrMsg & errMsg)246 void DeviceManagerCallback::OnUnBind(uint64_t deviceId, const ErrMsg &errMsg)
247 {
248     EDM_LOGI(MODULE_DEV_MGR, "unbind device callback: %{public}016" PRIX64, deviceId);
249     std::lock_guard<std::mutex> mapLock(mapMutex);
250     if (g_callbackMap.count(deviceId) == 0) {
251         EDM_LOGE(MODULE_DEV_MGR, "device unbind map is null");
252         return;
253     }
254 
255     auto asyncData = g_callbackMap[deviceId];
256     if (asyncData == nullptr || (asyncData->unbindCallback == nullptr && asyncData->unbindDeferred == nullptr)) {
257         EDM_LOGE(MODULE_DEV_MGR, "device unbind is null");
258         return;
259     }
260     asyncData->unBindErrMsg = errMsg;
261 }
262 
IsMatchType(const napi_env & env,const napi_value & value,const napi_valuetype & type)263 static bool IsMatchType(const napi_env &env, const napi_value &value, const napi_valuetype &type)
264 {
265     napi_valuetype paramType = napi_undefined;
266     napi_typeof(env, value, &paramType);
267     return paramType == type;
268 }
269 
GetCallbackResult(const napi_env & env,uint64_t deviceId,const sptr<IRemoteObject> & drvExtObj)270 static napi_value GetCallbackResult(const napi_env &env, uint64_t deviceId, const sptr<IRemoteObject> &drvExtObj)
271 {
272     napi_value id = ConvertToJsDeviceId(env, deviceId);
273 
274     napi_value remoteObj;
275     if (drvExtObj == nullptr) {
276         napi_get_undefined(env, &remoteObj);
277         EDM_LOGE(MODULE_DEV_MGR, "Remote obj is null.");
278     } else {
279         EDM_LOGI(MODULE_DEV_MGR, "Remote obj create.");
280         remoteObj = NAPI_ohos_rpc_CreateJsRemoteObject(env, drvExtObj);
281     }
282 
283     napi_value result;
284     napi_create_object(env, &result);
285     napi_set_named_property(env, result, "deviceId", id);
286     napi_set_named_property(env, result, "remote", remoteObj);
287 
288     return result;
289 }
290 
GetNapiError(int32_t errorCode)291 static std::optional<std::string> GetNapiError(int32_t errorCode)
292 {
293     auto iter = ERROR_MESSAGES.find(errorCode);
294     if (iter != ERROR_MESSAGES.end()) {
295         return iter->second;
296     }
297     return std::nullopt;
298 }
299 
CreateBusinessError(const napi_env & env,const int32_t errCode,const std::string & errMessage)300 static napi_value CreateBusinessError(const napi_env &env, const int32_t errCode, const std::string &errMessage)
301 {
302     napi_value businessError = nullptr;
303     napi_value code = nullptr;
304     napi_value msg = nullptr;
305     NAPI_CALL(env, napi_create_int32(env, errCode, &code));
306     NAPI_CALL(env, napi_create_string_utf8(env, errMessage.c_str(), NAPI_AUTO_LENGTH, &msg));
307     napi_create_error(env, nullptr, msg, &businessError);
308     napi_set_named_property(env, businessError, "code", code);
309     napi_set_named_property(env, businessError, "message", msg);
310     return businessError;
311 }
312 
ConvertToBusinessError(const napi_env & env,const ErrMsg & errMsg)313 static napi_value ConvertToBusinessError(const napi_env &env, const ErrMsg &errMsg)
314 {
315     napi_value businessError = nullptr;
316     if (errMsg.IsOk()) {
317         napi_get_undefined(env, &businessError);
318         return businessError;
319     }
320 
321     auto msgString = GetNapiError(SERVICE_EXCEPTION);
322     if (!msgString) {
323         napi_get_undefined(env, &businessError);
324         return businessError;
325     }
326 
327     napi_value code = nullptr;
328     napi_value msg = nullptr;
329     NAPI_CALL(env, napi_create_int32(env, SERVICE_EXCEPTION, &code));
330     NAPI_CALL(env, napi_create_string_utf8(env, msgString.value().c_str(), NAPI_AUTO_LENGTH, &msg));
331     napi_create_error(env, nullptr, msg, &businessError);
332     napi_set_named_property(env, businessError, "code", code);
333     napi_set_named_property(env, businessError, "message", msg);
334     return businessError;
335 }
336 
ConvertToJsDeviceId(const napi_env & env,uint64_t deviceId)337 static napi_value ConvertToJsDeviceId(const napi_env &env, uint64_t deviceId)
338 {
339     napi_value result;
340     if (deviceId > MAX_JS_NUMBER) {
341         NAPI_CALL(env, napi_create_bigint_uint64(env, deviceId, &result));
342     } else {
343         NAPI_CALL(env, napi_create_int64(env, deviceId, &result));
344     }
345     return result;
346 }
347 
ThrowErr(const napi_env & env,const int32_t errCode,const std::string & printMsg)348 void ThrowErr(const napi_env &env, const int32_t errCode, const std::string &printMsg)
349 {
350     EDM_LOGE(MODULE_DEV_MGR, "message: %{public}s, code: %{public}d", printMsg.c_str(), errCode);
351     auto msg = GetNapiError(errCode);
352     if (!msg) {
353         EDM_LOGE(MODULE_DEV_MGR, "errCode: %{public}d is invalid", errCode);
354         return;
355     }
356     napi_handle_scope scope = nullptr;
357     napi_open_handle_scope(env, &scope);
358     napi_value error = CreateBusinessError(env, errCode, msg.value());
359     napi_throw(env, error);
360     napi_close_handle_scope(env, scope);
361 }
362 
ConvertDeviceToJsDevice(napi_env & env,std::shared_ptr<DeviceData> device)363 static napi_value ConvertDeviceToJsDevice(napi_env& env, std::shared_ptr<DeviceData> device)
364 {
365     napi_value object;
366     napi_value value;
367     NAPI_CALL(env, napi_create_object(env, &object));
368     NAPI_CALL(env, napi_create_int32(env, device->busType, &value));
369     NAPI_CALL(env, napi_set_named_property(env, object, "busType", value));
370     value = ConvertToJsDeviceId(env, device->deviceId);
371     NAPI_CALL(env, napi_set_named_property(env, object, "deviceId", value));
372     if (device->busType == BusType::BUS_TYPE_USB) {
373         std::shared_ptr<USBDevice> usb = std::static_pointer_cast<USBDevice>(device);
374         NAPI_CALL(env, napi_create_uint32(env, usb->vendorId, &value));
375         NAPI_CALL(env, napi_set_named_property(env, object, "vendorId", value));
376         NAPI_CALL(env, napi_create_uint32(env, usb->productId, &value));
377         NAPI_CALL(env, napi_set_named_property(env, object, "productId", value));
378     }
379 
380     return object;
381 }
382 
ConvertToJsUSBInterfaceDesc(napi_env & env,std::shared_ptr<USBInterfaceDesc> desc)383 static napi_value ConvertToJsUSBInterfaceDesc(napi_env& env, std::shared_ptr<USBInterfaceDesc> desc)
384 {
385     if (desc == nullptr) {
386         return nullptr;
387     }
388     napi_value object;
389     napi_value value;
390     NAPI_CALL(env, napi_create_object(env, &object));
391     NAPI_CALL(env, napi_create_uint32(env, desc->bInterfaceNumber, &value));
392     NAPI_CALL(env, napi_set_named_property(env, object, "bInterfaceNumber", value));
393     NAPI_CALL(env, napi_create_uint32(env, desc->bClass, &value));
394     NAPI_CALL(env, napi_set_named_property(env, object, "bClass", value));
395     NAPI_CALL(env, napi_create_uint32(env, desc->bSubClass, &value));
396     NAPI_CALL(env, napi_set_named_property(env, object, "bSubClass", value));
397     NAPI_CALL(env, napi_create_uint32(env, desc->bProtocol, &value));
398     NAPI_CALL(env, napi_set_named_property(env, object, "bProtocol", value));
399     return object;
400 }
401 
ConvertToJsDeviceInfo(napi_env & env,std::shared_ptr<DeviceInfoData> deviceInfo)402 static napi_value ConvertToJsDeviceInfo(napi_env& env, std::shared_ptr<DeviceInfoData> deviceInfo)
403 {
404     EDM_LOGD(MODULE_DEV_MGR, "ConvertToJsDeviceInfo start");
405     if (deviceInfo == nullptr) {
406         return nullptr;
407     }
408     napi_value object;
409     napi_value value;
410     NAPI_CALL(env, napi_create_object(env, &object));
411     value = ConvertToJsDeviceId(env, deviceInfo->deviceId);
412     NAPI_CALL(env, napi_set_named_property(env, object, "deviceId", value));
413     NAPI_CALL(env, napi_get_boolean(env, deviceInfo->isDriverMatched, &value));
414     NAPI_CALL(env, napi_set_named_property(env, object, "isDriverMatched", value));
415     if (deviceInfo->isDriverMatched) {
416         NAPI_CALL(env, napi_create_string_utf8(env, deviceInfo->driverUid.c_str(),
417             deviceInfo->driverUid.size(), &value));
418         NAPI_CALL(env, napi_set_named_property(env, object, "driverUid", value));
419     }
420     BusType busType = DeviceInfoData::GetBusTypeByDeviceId(deviceInfo->deviceId);
421     if (busType == BusType::BUS_TYPE_USB) {
422         std::shared_ptr<USBDeviceInfoData> usbDeviceInfo = std::static_pointer_cast<USBDeviceInfoData>(deviceInfo);
423         NAPI_CALL(env, napi_create_uint32(env, usbDeviceInfo->vendorId, &value));
424         NAPI_CALL(env, napi_set_named_property(env, object, "vendorId", value));
425         NAPI_CALL(env, napi_create_uint32(env, usbDeviceInfo->productId, &value));
426         NAPI_CALL(env, napi_set_named_property(env, object, "productId", value));
427 
428         napi_value interfaceDescList;
429         NAPI_CALL(env, napi_create_array(env, &interfaceDescList));
430         EDM_LOGD(MODULE_DEV_MGR, "interfaceDescList size = %{public}zu", usbDeviceInfo->interfaceDescList.size());
431         for (size_t i = 0; i < usbDeviceInfo->interfaceDescList.size(); i++) {
432             napi_value element = ConvertToJsUSBInterfaceDesc(env, usbDeviceInfo->interfaceDescList[i]);
433             NAPI_CALL(env, napi_set_element(env, interfaceDescList, i, element));
434         }
435         NAPI_CALL(env, napi_set_named_property(env, object, "interfaceDescList", interfaceDescList));
436     }
437     EDM_LOGD(MODULE_DEV_MGR, "ConvertToJsDeviceInfo end");
438     return object;
439 }
440 
ConvertToJsDriverInfo(napi_env & env,std::shared_ptr<DriverInfoData> driverInfo)441 static napi_value ConvertToJsDriverInfo(napi_env& env, std::shared_ptr<DriverInfoData> driverInfo)
442 {
443     if (driverInfo == nullptr) {
444         return nullptr;
445     }
446     napi_value object;
447     napi_value value;
448     NAPI_CALL(env, napi_create_object(env, &object));
449     NAPI_CALL(env, napi_create_int32(env, driverInfo->busType, &value));
450     NAPI_CALL(env, napi_set_named_property(env, object, "busType", value));
451     NAPI_CALL(env, napi_create_string_utf8(env, driverInfo->driverUid.c_str(), driverInfo->driverUid.size(), &value));
452     NAPI_CALL(env, napi_set_named_property(env, object, "driverUid", value));
453     NAPI_CALL(env, napi_create_string_utf8(env, driverInfo->driverName.c_str(), driverInfo->driverName.size(), &value));
454     NAPI_CALL(env, napi_set_named_property(env, object, "driverName", value));
455     NAPI_CALL(env, napi_create_string_utf8(env, driverInfo->bundleSize.c_str(), driverInfo->bundleSize.size(), &value));
456     NAPI_CALL(env, napi_set_named_property(env, object, "driverSize", value));
457     NAPI_CALL(env, napi_create_string_utf8(env, driverInfo->version.c_str(), driverInfo->version.size(), &value));
458     NAPI_CALL(env, napi_set_named_property(env, object, "driverVersion", value));
459     NAPI_CALL(env, napi_create_string_utf8(env, driverInfo->description.c_str(),
460         driverInfo->description.size(), &value));
461     NAPI_CALL(env, napi_set_named_property(env, object, "description", value));
462     if (driverInfo->busType == BusType::BUS_TYPE_USB) {
463         std::shared_ptr<USBDriverInfoData> usbDriverInfo = std::static_pointer_cast<USBDriverInfoData>(driverInfo);
464         napi_value pids;
465         NAPI_CALL(env, napi_create_array(env, &pids));
466         for (size_t i = 0; i < usbDriverInfo->pids.size(); i++) {
467             NAPI_CALL(env, napi_create_uint32(env, usbDriverInfo->pids[i], &value));
468             NAPI_CALL(env, napi_set_element(env, pids, i, value));
469         }
470         NAPI_CALL(env, napi_set_named_property(env, object, "productIdList", pids));
471         napi_value vids;
472         NAPI_CALL(env, napi_create_array(env, &vids));
473         for (size_t i = 0; i < usbDriverInfo->vids.size(); i++) {
474             NAPI_CALL(env, napi_create_uint32(env, usbDriverInfo->vids[i], &value));
475             NAPI_CALL(env, napi_set_element(env, vids, i, value));
476         }
477         NAPI_CALL(env, napi_set_named_property(env, object, "vendorIdList", vids));
478     }
479     return object;
480 }
481 
QueryDevices(napi_env env,napi_callback_info info)482 static napi_value QueryDevices(napi_env env, napi_callback_info info)
483 {
484     EDM_LOGI(MODULE_DEV_MGR, "queryDevices start");
485     size_t argc = PARAM_COUNT_1;
486     napi_value argv[PARAM_COUNT_1] = {nullptr};
487     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
488 
489     int32_t busType = BusType::BUS_TYPE_USB;
490     if (argc > 0 && IsMatchType(env, argv[0], napi_number)) {
491         NAPI_CALL(env, napi_get_value_int32(env, argv[0], &busType));
492         EDM_LOGI(MODULE_DEV_MGR, "bus type is %{public}d", busType);
493     }
494 
495     std::vector<std::shared_ptr<DeviceData>> devices;
496     UsbErrCode retCode = g_edmClient.QueryDevice(busType, devices);
497     if (retCode != UsbErrCode::EDM_OK) {
498         if (retCode == UsbErrCode::EDM_ERR_NO_PERM) {
499             ThrowErr(env, PERMISSION_DENIED, "queryDevice: no permission");
500         } else {
501             ThrowErr(env, SERVICE_EXCEPTION, "Query device service fail");
502         }
503         return nullptr;
504     }
505 
506     napi_value resultArray;
507     NAPI_CALL(env, napi_create_array(env, &resultArray));
508     for (size_t index = 0; index < devices.size(); index++) {
509         napi_value element = ConvertDeviceToJsDevice(env, devices[index]);
510         NAPI_CALL(env, napi_set_element(env, resultArray, index, element));
511     }
512     EDM_LOGI(MODULE_DEV_MGR, "query device finish");
513 
514     return resultArray;
515 }
516 
ParseDeviceId(const napi_env & env,const napi_value & value,uint64_t * deviceId)517 static bool ParseDeviceId(const napi_env& env, const napi_value& value, uint64_t* deviceId)
518 {
519     napi_valuetype type;
520     NAPI_CALL_BASE(env, napi_typeof(env, value, &type), false);
521     if (type == napi_bigint) {
522         bool lossless;
523         NAPI_CALL_BASE(env, napi_get_value_bigint_uint64(env, value, deviceId, &lossless), false);
524     } else if (type == napi_number) {
525         int64_t temp;
526         NAPI_CALL_BASE(env, napi_get_value_int64(env, value, &temp), false);
527         *deviceId = static_cast<uint64_t>(temp);
528     } else {
529         return false;
530     }
531     return true;
532 }
533 
BindDevice(napi_env env,napi_callback_info info)534 static napi_value BindDevice(napi_env env, napi_callback_info info)
535 {
536     size_t argc = PARAM_COUNT_3;
537     napi_value argv[PARAM_COUNT_3] = {nullptr};
538     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
539     if (argc < PARAM_COUNT_2) {
540         ThrowErr(env, PARAMETER_ERROR, "bindDevice parameter count not match");
541         return nullptr;
542     }
543 
544     uint64_t deviceId;
545     if (!ParseDeviceId(env, argv[0], &deviceId)) {
546         ThrowErr(env, PARAMETER_ERROR, "deviceid type error");
547         return nullptr;
548     }
549     EDM_LOGI(MODULE_DEV_MGR, "Enter bindDevice:%{public}016" PRIX64, deviceId);
550 
551     if (!IsMatchType(env, argv[1], napi_function)) {
552         ThrowErr(env, PARAMETER_ERROR, "onDisconnect param is error");
553         return nullptr;
554     }
555 
556     std::lock_guard<std::mutex> mapLock(mapMutex);
557     UsbErrCode retCode = g_edmClient.BindDevice(deviceId, g_edmCallback);
558     if (retCode != UsbErrCode::EDM_OK) {
559         if (retCode == UsbErrCode::EDM_ERR_NO_PERM) {
560             ThrowErr(env, PERMISSION_DENIED, "bindDevice: no permission");
561         } else {
562             ThrowErr(env, SERVICE_EXCEPTION, "bindDevice service failed");
563         }
564         return nullptr;
565     }
566 
567     sptr<AsyncData> data = new (std::nothrow) AsyncData {};
568     if (data == nullptr) {
569         ThrowErr(env, PARAMETER_ERROR, "malloc callback data fail");
570         return nullptr;
571     }
572     data->env = env;
573     data->deviceId = deviceId;
574     NAPI_CALL(env, napi_create_reference(env, argv[1], 1, &data->onDisconnect));
575     napi_value promise = nullptr;
576     if (argc > PARAM_COUNT_2 && IsMatchType(env, argv[PARAM_COUNT_2], napi_function)) {
577         NAPI_CALL(env, napi_create_reference(env, argv[PARAM_COUNT_2], 1, &data->bindCallback));
578     } else {
579         NAPI_CALL(env, napi_create_promise(env, &data->bindDeferred, &promise));
580     }
581     g_callbackMap[data->deviceId] = data;
582 
583     return promise;
584 }
585 
UnbindDevice(napi_env env,napi_callback_info info)586 static napi_value UnbindDevice(napi_env env, napi_callback_info info)
587 {
588     size_t argc = PARAM_COUNT_2;
589     napi_value argv[PARAM_COUNT_2] = {nullptr};
590     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
591     if (argc < PARAM_COUNT_1) {
592         ThrowErr(env, PARAMETER_ERROR, "Param count error");
593         return nullptr;
594     }
595 
596     uint64_t deviceId;
597     if (!ParseDeviceId(env, argv[0], &deviceId)) {
598         ThrowErr(env, PARAMETER_ERROR, "deviceid type error");
599         return nullptr;
600     }
601     EDM_LOGI(MODULE_DEV_MGR, "Enter unbindDevice:%{public}016" PRIX64, deviceId);
602 
603     UsbErrCode retCode = g_edmClient.UnBindDevice(deviceId);
604     if (retCode != UsbErrCode::EDM_OK) {
605         if (retCode == UsbErrCode::EDM_ERR_NO_PERM) {
606             ThrowErr(env, PERMISSION_DENIED, "unbindDevice: no permission");
607         } else {
608             ThrowErr(env, SERVICE_EXCEPTION, "unbindDevice service failed");
609         }
610         return nullptr;
611     }
612 
613     std::lock_guard<std::mutex> mapLock(mapMutex);
614     if (g_callbackMap.find(deviceId) == g_callbackMap.end()) {
615         ThrowErr(env, SERVICE_EXCEPTION, "Unbind callback does not exist");
616         return nullptr;
617     }
618     auto data = g_callbackMap[deviceId];
619     napi_value promise = nullptr;
620     if (argc > PARAM_COUNT_1 && IsMatchType(env, argv[1], napi_function)) {
621         NAPI_CALL(env, napi_create_reference(env, argv[1], 1, &data->unbindCallback));
622     } else {
623         NAPI_CALL(env, napi_create_promise(env, &data->unbindDeferred, &promise));
624     }
625 
626     return promise;
627 }
628 
QueryDeviceInfo(napi_env env,napi_callback_info info)629 static napi_value QueryDeviceInfo(napi_env env, napi_callback_info info)
630 {
631     size_t argc = PARAM_COUNT_1;
632     napi_value argv[PARAM_COUNT_1] = {nullptr};
633     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
634 
635     uint64_t deviceId = 0;
636     if (argc > PARAM_COUNT_0 && !ParseDeviceId(env, argv[0], &deviceId)) {
637         ThrowErr(env, PARAMETER_ERROR, "deviceId type error");
638         return nullptr;
639     }
640     std::vector<std::shared_ptr<DeviceInfoData>> deviceInfos;
641     int32_t ret;
642     if (argc > PARAM_COUNT_0) {
643         ret = g_edmClient.QueryDeviceInfo(deviceId, deviceInfos);
644     } else {
645         ret = g_edmClient.QueryDeviceInfo(deviceInfos);
646     }
647     if (ret != UsbErrCode::EDM_OK) {
648         if (ret == UsbErrCode::EDM_ERR_NOT_SYSTEM_APP) {
649             ThrowErr(env, PERMISSION_NOT_SYSTEM_APP, "queryDeviceInfo: none system app");
650         } else if (ret == UsbErrCode::EDM_ERR_NO_PERM) {
651             ThrowErr(env, PERMISSION_DENIED, "queryDeviceInfo: no permission");
652         } else {
653             ThrowErr(env, SERVICE_EXCEPTION_NEW, "Query device info service fail");
654         }
655         return nullptr;
656     }
657 
658     napi_value resultArray;
659     NAPI_CALL(env, napi_create_array(env, &resultArray));
660     for (size_t i = 0; i < deviceInfos.size(); i++) {
661         napi_value element = ConvertToJsDeviceInfo(env, deviceInfos[i]);
662         NAPI_CALL(env, napi_set_element(env, resultArray, i, element));
663     }
664 
665     return resultArray;
666 }
667 
QueryDriverInfo(napi_env env,napi_callback_info info)668 static napi_value QueryDriverInfo(napi_env env, napi_callback_info info)
669 {
670     size_t argc = PARAM_COUNT_1;
671     napi_value argv[PARAM_COUNT_1] = {nullptr};
672     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
673     if (argc > PARAM_COUNT_0 && !IsMatchType(env, argv[0], napi_string)) {
674         ThrowErr(env, PARAMETER_ERROR, "driverUid type is invalid");
675         return nullptr;
676     }
677 
678     std::vector<std::shared_ptr<DriverInfoData>> driverInfos;
679     int32_t ret;
680     if (argc > PARAM_COUNT_0) {
681         size_t len;
682         NAPI_CALL(env, napi_get_value_string_utf8(env, argv[0], nullptr, 0, &len));
683         std::string driverUid;
684         driverUid.resize(len);
685         NAPI_CALL(env, napi_get_value_string_utf8(env, argv[0], &driverUid[0], len + 1, &len));
686         ret = g_edmClient.QueryDriverInfo(driverUid, driverInfos);
687     } else {
688         ret = g_edmClient.QueryDriverInfo(driverInfos);
689     }
690 
691     if (ret != UsbErrCode::EDM_OK) {
692         if (ret == UsbErrCode::EDM_ERR_NOT_SYSTEM_APP) {
693             ThrowErr(env, PERMISSION_NOT_SYSTEM_APP, "queryDriverInfo: none system app");
694         } else if (ret == UsbErrCode::EDM_ERR_NO_PERM) {
695             ThrowErr(env, PERMISSION_DENIED, "queryDriverInfo: no permission");
696         } else {
697             ThrowErr(env, SERVICE_EXCEPTION_NEW, "Query driver info service fail");
698         }
699         return nullptr;
700     }
701 
702     napi_value resultArray;
703     NAPI_CALL(env, napi_create_array(env, &resultArray));
704     for (size_t index = 0; index < driverInfos.size(); index++) {
705         napi_value element = ConvertToJsDriverInfo(env, driverInfos[index]);
706         NAPI_CALL(env, napi_set_element(env, resultArray, index, element));
707     }
708 
709     return resultArray;
710 }
711 
EnumBusTypeConstructor(napi_env env,napi_callback_info info)712 static napi_value EnumBusTypeConstructor(napi_env env, napi_callback_info info)
713 {
714     napi_value thisArg = nullptr;
715     void* data = nullptr;
716 
717     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, &data));
718     return thisArg;
719 }
720 
CreateEnumBusType(napi_env env,napi_value exports)721 static void CreateEnumBusType(napi_env env, napi_value exports)
722 {
723     napi_value usb = nullptr;
724     napi_create_int32(env, 1, &usb);
725 
726     napi_property_descriptor desc[] = {
727         DECLARE_NAPI_STATIC_PROPERTY("USB", usb),
728     };
729 
730     napi_value result = nullptr;
731     napi_define_class(env, "BusType", NAPI_AUTO_LENGTH, EnumBusTypeConstructor, nullptr,
732         sizeof(desc) / sizeof(*desc), desc, &result);
733     napi_set_named_property(env, exports, "BusType", result);
734 }
735 
736 EXTERN_C_START
737 /*
738  * function for module exports
739  */
ExtDeviceManagerInit(napi_env env,napi_value exports)740 static napi_value ExtDeviceManagerInit(napi_env env, napi_value exports)
741 {
742     napi_property_descriptor desc[] = {
743         DECLARE_NAPI_FUNCTION("queryDevices", QueryDevices),
744         DECLARE_NAPI_FUNCTION("bindDevice", BindDevice),
745         DECLARE_NAPI_FUNCTION("bindDeviceDriver", BindDevice),
746         DECLARE_NAPI_FUNCTION("unbindDevice", UnbindDevice),
747         DECLARE_NAPI_FUNCTION("queryDeviceInfo", QueryDeviceInfo),
748         DECLARE_NAPI_FUNCTION("queryDriverInfo", QueryDriverInfo),
749     };
750     NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
751 
752     CreateEnumBusType(env, exports);
753 
754     return exports;
755 }
756 EXTERN_C_END
757 
758 /*
759  * Module definition
760  */
761 static napi_module g_moduleManager = {
762     .nm_version = 1,
763     .nm_flags = 0,
764     .nm_filename = nullptr,
765     .nm_register_func = ExtDeviceManagerInit,
766     .nm_modname = "driver.deviceManager",
767     .nm_priv = nullptr,
768     .reserved = {nullptr}
769 };
770 
771 /*
772  * Module registration
773  */
RegisterModule(void)774 extern "C" __attribute__((constructor)) void RegisterModule(void)
775 {
776     napi_module_register(&g_moduleManager);
777 }
778 }
779 }