• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 "js_continuation_manager.h"
17 
18 #include <memory>
19 
20 #include "device_connect_status.h"
21 #include "distributed_ability_manager_client.h"
22 #include "dtbschedmgr_log.h"
23 #include "js_runtime_utils.h"
24 #include "napi_common_util.h"
25 #include "napi_error_code.h"
26 
27 namespace OHOS {
28 namespace DistributedSchedule {
29 using namespace OHOS::AbilityRuntime;
30 using namespace OHOS::AppExecFwk;
31 namespace {
32 const std::string TAG = "JsContinuationManager";
33 const std::string CODE_KEY_NAME = "code";
34 constexpr int32_t ERR_NOT_OK = -1;
35 constexpr int32_t ARG_COUNT_ONE = 1;
36 constexpr int32_t ARG_COUNT_TWO = 2;
37 constexpr int32_t ARG_COUNT_THREE = 3;
38 constexpr uint32_t MAX_JSPROCOUNT = 1000000;
39 constexpr int32_t ARG_COUNT_FOUR = 4;
40 }
41 
Finalizer(NativeEngine * engine,void * data,void * hint)42 void JsContinuationManager::Finalizer(NativeEngine* engine, void* data, void* hint)
43 {
44     HILOGI("JsContinuationManager::Finalizer is called");
45     JsContinuationManager* jsContinuationManager = static_cast<JsContinuationManager*>(data);
46     if (jsContinuationManager != nullptr) {
47         delete jsContinuationManager;
48         jsContinuationManager = nullptr;
49     }
50 }
51 
Register(NativeEngine * engine,NativeCallbackInfo * info)52 NativeValue* JsContinuationManager::Register(NativeEngine* engine, NativeCallbackInfo* info)
53 {
54     JsContinuationManager* me = CheckParamsAndGetThis<JsContinuationManager>(engine, info);
55     return (me != nullptr) ? me->OnRegister(*engine, *info) : nullptr;
56 }
57 
Unregister(NativeEngine * engine,NativeCallbackInfo * info)58 NativeValue* JsContinuationManager::Unregister(NativeEngine* engine, NativeCallbackInfo* info)
59 {
60     JsContinuationManager* me = CheckParamsAndGetThis<JsContinuationManager>(engine, info);
61     return (me != nullptr) ? me->OnUnregister(*engine, *info) : nullptr;
62 }
63 
RegisterDeviceSelectionCallback(NativeEngine * engine,NativeCallbackInfo * info)64 NativeValue* JsContinuationManager::RegisterDeviceSelectionCallback(NativeEngine* engine, NativeCallbackInfo* info)
65 {
66     JsContinuationManager* me = CheckParamsAndGetThis<JsContinuationManager>(engine, info);
67     return (me != nullptr) ? me->OnRegisterDeviceSelectionCallback(*engine, *info) : nullptr;
68 }
69 
UnregisterDeviceSelectionCallback(NativeEngine * engine,NativeCallbackInfo * info)70 NativeValue* JsContinuationManager::UnregisterDeviceSelectionCallback(NativeEngine* engine, NativeCallbackInfo* info)
71 {
72     JsContinuationManager* me = CheckParamsAndGetThis<JsContinuationManager>(engine, info);
73     return (me != nullptr) ? me->OnUnregisterDeviceSelectionCallback(*engine, *info) : nullptr;
74 }
75 
UpdateConnectStatus(NativeEngine * engine,NativeCallbackInfo * info)76 NativeValue *JsContinuationManager::UpdateConnectStatus(NativeEngine *engine, NativeCallbackInfo *info)
77 {
78     JsContinuationManager *me = CheckParamsAndGetThis<JsContinuationManager>(engine, info);
79     return (me != nullptr) ? me->OnUpdateConnectStatus(*engine, *info) : nullptr;
80 }
81 
StartDeviceManager(NativeEngine * engine,NativeCallbackInfo * info)82 NativeValue *JsContinuationManager::StartDeviceManager(NativeEngine *engine, NativeCallbackInfo *info)
83 {
84     JsContinuationManager *me = CheckParamsAndGetThis<JsContinuationManager>(engine, info);
85     return (me != nullptr) ? me->OnStartDeviceManager(*engine, *info) : nullptr;
86 }
87 
InitDeviceConnectStateObject(NativeEngine * engine,NativeCallbackInfo * info)88 NativeValue *JsContinuationManager::InitDeviceConnectStateObject(NativeEngine *engine, NativeCallbackInfo *info)
89 {
90     JsContinuationManager *me = CheckParamsAndGetThis<JsContinuationManager>(engine, info);
91     return (me != nullptr) ? me->OnInitDeviceConnectStateObject(*engine, *info) : nullptr;
92 }
93 
InitContinuationModeObject(NativeEngine * engine,NativeCallbackInfo * info)94 NativeValue *JsContinuationManager::InitContinuationModeObject(NativeEngine *engine, NativeCallbackInfo *info)
95 {
96     JsContinuationManager *me = CheckParamsAndGetThis<JsContinuationManager>(engine, info);
97     return (me != nullptr) ? me->OnInitContinuationModeObject(*engine, *info) : nullptr;
98 }
99 
RegisterContinuation(NativeEngine * engine,NativeCallbackInfo * info)100 NativeValue* JsContinuationManager::RegisterContinuation(NativeEngine* engine, NativeCallbackInfo* info)
101 {
102     JsContinuationManager* me = CheckParamsAndGetThis<JsContinuationManager>(engine, info);
103     return (me != nullptr) ? me->OnRegisterContinuation(*engine, *info) : nullptr;
104 }
105 
UnregisterContinuation(NativeEngine * engine,NativeCallbackInfo * info)106 NativeValue* JsContinuationManager::UnregisterContinuation(NativeEngine* engine, NativeCallbackInfo* info)
107 {
108     JsContinuationManager* me = CheckParamsAndGetThis<JsContinuationManager>(engine, info);
109     return (me != nullptr) ? me->OnUnregisterContinuation(*engine, *info) : nullptr;
110 }
111 
UpdateContinuationState(NativeEngine * engine,NativeCallbackInfo * info)112 NativeValue* JsContinuationManager::UpdateContinuationState(NativeEngine* engine, NativeCallbackInfo *info)
113 {
114     JsContinuationManager *me = CheckParamsAndGetThis<JsContinuationManager>(engine, info);
115     return (me != nullptr) ? me->OnUpdateContinuationState(*engine, *info) : nullptr;
116 }
117 
StartContinuationDeviceManager(NativeEngine * engine,NativeCallbackInfo * info)118 NativeValue* JsContinuationManager::StartContinuationDeviceManager(NativeEngine* engine, NativeCallbackInfo *info)
119 {
120     JsContinuationManager *me = CheckParamsAndGetThis<JsContinuationManager>(engine, info);
121     return (me != nullptr) ? me->OnStartContinuationDeviceManager(*engine, *info) : nullptr;
122 }
123 
OnRegister(NativeEngine & engine,NativeCallbackInfo & info)124 NativeValue* JsContinuationManager::OnRegister(NativeEngine &engine, NativeCallbackInfo &info)
125 {
126     HILOGD("called.");
127     int32_t errCode = 0;
128     decltype(info.argc) unwrapArgc = 0;
129     std::shared_ptr<ContinuationExtraParams> continuationExtraParams = std::make_shared<ContinuationExtraParams>();
130     if (info.argc > 0 && info.argv[0]->TypeOf() == NATIVE_OBJECT) {
131         HILOGI("register options is used.");
132         if (!UnWrapContinuationExtraParams(reinterpret_cast<napi_env>(&engine),
133             reinterpret_cast<napi_value>(info.argv[0]), continuationExtraParams)) {
134             HILOGE("Parse continuationExtraParams failed");
135             errCode = ERR_NOT_OK;
136         }
137         unwrapArgc++;
138     }
139     AsyncTask::CompleteCallback complete =
140         [continuationExtraParams, unwrapArgc, errCode](NativeEngine &engine, AsyncTask &task, int32_t status) {
141         if (errCode != 0) {
142             task.Reject(engine, CreateJsError(engine, errCode, "Invalidate params."));
143             return;
144         }
145         int32_t token = -1;
146         int32_t ret = (unwrapArgc == 0) ? DistributedAbilityManagerClient::GetInstance().Register(nullptr, token) :
147             DistributedAbilityManagerClient::GetInstance().Register(continuationExtraParams, token);
148         if (ret == ERR_OK) {
149             task.Resolve(engine, engine.CreateNumber(token));
150         } else {
151             task.Reject(engine, CreateJsError(engine, ret, "Register failed."));
152         }
153     };
154 
155     NativeValue* lastParam = (info.argc <= unwrapArgc) ? nullptr : info.argv[unwrapArgc];
156     NativeValue* result = nullptr;
157     AsyncTask::Schedule("JsContinuationManager::OnRegister",
158         engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
159     return result;
160 }
161 
OnRegisterContinuation(NativeEngine & engine,NativeCallbackInfo & info)162 NativeValue* JsContinuationManager::OnRegisterContinuation(NativeEngine &engine, NativeCallbackInfo &info)
163 {
164     HILOGD("called.");
165     decltype(info.argc) unwrapArgc = 0;
166     std::shared_ptr<ContinuationExtraParams> continuationExtraParams;
167     std::string errInfo = [this, &engine, &info, &continuationExtraParams, &unwrapArgc]() -> std::string {
168         if (info.argc > ARG_COUNT_TWO) {
169             return "Parameter error. The type of \"number of parameters\" must be less than 3";
170         }
171         if (info.argc > 0 && info.argv[0]->TypeOf() == NATIVE_OBJECT) {
172             HILOGI("register options is used.");
173             continuationExtraParams = std::make_shared<ContinuationExtraParams>();
174             if (!UnWrapContinuationExtraParams(reinterpret_cast<napi_env>(&engine),
175                 reinterpret_cast<napi_value>(info.argv[0]), continuationExtraParams)) {
176                 return "Parameter error. The type of \"options\" must be ContinuationExtraParams";
177             }
178             unwrapArgc++;
179         }
180         return std::string();
181     } ();
182     if (!errInfo.empty()) {
183         HILOGE("%{public}s", errInfo.c_str());
184         napi_throw(reinterpret_cast<napi_env>(&engine),
185             GenerateBusinessError(reinterpret_cast<napi_env>(&engine), PARAMETER_CHECK_FAILED, errInfo));
186         return engine.CreateUndefined();
187     }
188     AsyncTask::CompleteCallback complete =
189         [this, continuationExtraParams, unwrapArgc](NativeEngine &engine, AsyncTask &task, int32_t status) {
190         int32_t token = -1;
191         int32_t errCode = (unwrapArgc == 0) ? DistributedAbilityManagerClient::GetInstance().Register(nullptr, token) :
192             DistributedAbilityManagerClient::GetInstance().Register(continuationExtraParams, token);
193         if (errCode == ERR_OK) {
194             task.Resolve(engine, engine.CreateNumber(token));
195         } else {
196             errCode = ErrorCodeReturn(errCode);
197             task.Reject(engine, CreateJsError(engine, errCode, ErrorMessageReturn(errCode)));
198         }
199     };
200 
201     NativeValue* lastParam = (info.argc <= unwrapArgc) ? nullptr : info.argv[unwrapArgc];
202     NativeValue* result = nullptr;
203     AsyncTask::Schedule("JsContinuationManager::OnRegisterContinuation",
204         engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
205     return result;
206 }
207 
OnUnregister(NativeEngine & engine,NativeCallbackInfo & info)208 NativeValue* JsContinuationManager::OnUnregister(NativeEngine &engine, NativeCallbackInfo &info)
209 {
210     HILOGD("called.");
211     int32_t errCode = 0;
212     if (info.argc == 0) {
213         HILOGE("Params not match");
214         errCode = ERR_NOT_OK;
215     }
216     int32_t token = -1;
217     if (!errCode && !ConvertFromJsValue(engine, info.argv[0], token)) {
218         HILOGE("Parse token failed");
219         errCode = ERR_NOT_OK;
220     }
221     AsyncTask::CompleteCallback complete =
222         [token, errCode](NativeEngine &engine, AsyncTask &task, int32_t status) {
223         if (errCode != 0) {
224             task.Reject(engine, CreateJsError(engine, errCode, "Invalidate params."));
225             return;
226         }
227         int32_t ret = DistributedAbilityManagerClient::GetInstance().Unregister(token);
228         if (ret == ERR_OK) {
229             task.Resolve(engine, engine.CreateUndefined());
230         } else {
231             task.Reject(engine, CreateJsError(engine, ret, "Unregister failed."));
232         }
233     };
234 
235     NativeValue* lastParam = (info.argc <= ARG_COUNT_ONE) ? nullptr : info.argv[ARG_COUNT_ONE];
236     NativeValue* result = nullptr;
237     AsyncTask::Schedule("JsContinuationManager::OnUnregister",
238         engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
239     return result;
240 }
241 
OnUnregisterContinuation(NativeEngine & engine,NativeCallbackInfo & info)242 NativeValue* JsContinuationManager::OnUnregisterContinuation(NativeEngine &engine, NativeCallbackInfo &info)
243 {
244     HILOGD("called.");
245     int32_t token = -1;
246     std::string errInfo = [this, &engine, &info, &token]() -> std::string {
247         if (info.argc == 0 || info.argc > ARG_COUNT_TWO) {
248             return "Parameter error. The type of \"number of parameters\" must be greater than 0 and less than 3";
249         }
250         if (!ConvertFromJsValue(engine, info.argv[0], token)) {
251             return "Parameter error. The type of \"token\" must be number";
252         }
253         return std::string();
254     } ();
255     if (!errInfo.empty()) {
256         HILOGE("%{public}s", errInfo.c_str());
257         napi_throw(reinterpret_cast<napi_env>(&engine),
258             GenerateBusinessError(reinterpret_cast<napi_env>(&engine), PARAMETER_CHECK_FAILED, errInfo));
259         return engine.CreateUndefined();
260     }
261     AsyncTask::CompleteCallback complete =
262         [this, token](NativeEngine &engine, AsyncTask &task, int32_t status) {
263         int32_t errCode = DistributedAbilityManagerClient::GetInstance().Unregister(token);
264         if (errCode == ERR_OK) {
265             task.Resolve(engine, engine.CreateNull());
266         } else {
267             errCode = ErrorCodeReturn(errCode);
268             task.Reject(engine, CreateJsError(engine, errCode, ErrorMessageReturn(errCode)));
269         }
270     };
271 
272     NativeValue* lastParam = (info.argc == ARG_COUNT_ONE) ? nullptr : info.argv[ARG_COUNT_ONE];
273     NativeValue* result = nullptr;
274     AsyncTask::Schedule("JsContinuationManager::OnUnregisterContinuation",
275         engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
276     return result;
277 }
278 
OnRegisterDeviceSelectionCallbackParameterCheck(NativeEngine & engine,NativeCallbackInfo & info,std::string & cbType,int32_t & token,NativeValue ** jsListenerObj)279 std::string JsContinuationManager::OnRegisterDeviceSelectionCallbackParameterCheck(NativeEngine &engine,
280     NativeCallbackInfo &info, std::string &cbType, int32_t &token, NativeValue** jsListenerObj)
281 {
282     if (info.argc != ARG_COUNT_THREE) {
283         return "Parameter error. The type of \"number of parameters\" must be 3";
284     }
285     if (!ConvertFromJsValue(engine, info.argv[0], cbType)) {
286         return "Parameter error. The type of \"type\" must be string";
287     }
288     if (cbType != EVENT_CONNECT && cbType != EVENT_DISCONNECT) {
289         return "Parameter error. The type of \"type\" must be " +
290             std::string(EVENT_CONNECT) + " or " + std::string(EVENT_DISCONNECT);
291     }
292     if (!ConvertFromJsValue(engine, info.argv[ARG_COUNT_ONE], token)) {
293         return "Parameter error. The type of \"token\" must be number";
294     }
295     *jsListenerObj = info.argv[ARG_COUNT_TWO];
296     if (!IsCallbackValid(*jsListenerObj)) {
297         return "Parameter error. The type of \"callback\" must be Callback<Array<ContinuationResult>>";
298     }
299     return std::string();
300 }
301 
OnRegisterDeviceSelectionCallback(NativeEngine & engine,NativeCallbackInfo & info)302 NativeValue* JsContinuationManager::OnRegisterDeviceSelectionCallback(NativeEngine &engine, NativeCallbackInfo &info)
303 {
304     HILOGD("called.");
305     std::string cbType;
306     int32_t token = -1;
307     int32_t errCode = PARAMETER_CHECK_FAILED;
308     NativeValue* jsListenerObj = nullptr;
309     std::string errInfo = OnRegisterDeviceSelectionCallbackParameterCheck(engine, info, cbType, token, &jsListenerObj);
310     if (errInfo.empty()) {
311         errInfo = [this, &engine, &info, &cbType, &token, &jsListenerObj, &errCode]() -> std::string {
312             std::lock_guard<std::mutex> jsCbMapLock(jsCbMapMutex_);
313             if (IsCallbackRegistered(token, cbType)) {
314                 errCode = REPEATED_REGISTRATION;
315                 return ErrorMessageReturn(errCode);
316             }
317             std::unique_ptr<NativeReference> callbackRef;
318             callbackRef.reset(engine.CreateReference(jsListenerObj, 1));
319             sptr<JsDeviceSelectionListener> deviceSelectionListener = new JsDeviceSelectionListener(&engine);
320             if (deviceSelectionListener == nullptr) {
321                 HILOGE("deviceSelectionListener is nullptr!");
322                 errCode = SYSTEM_WORK_ABNORMALLY;
323                 return ErrorMessageReturn(errCode);
324             }
325             errCode = DistributedAbilityManagerClient::GetInstance().RegisterDeviceSelectionCallback(
326                 token, cbType, deviceSelectionListener);
327             if (errCode == ERR_OK) {
328                 deviceSelectionListener->AddCallback(cbType, jsListenerObj);
329                 CallbackPair callbackPair = std::make_pair(std::move(callbackRef), deviceSelectionListener);
330                 jsCbMap_[token][cbType] = std::move(callbackPair); // move assignment
331                 HILOGI("RegisterDeviceSelectionListener success");
332             } else {
333                 deviceSelectionListener = nullptr;
334                 errCode = ErrorCodeReturn(errCode);
335                 return ErrorMessageReturn(errCode);
336             }
337             return std::string();
338         }();
339     }
340     if (!errInfo.empty()) {
341         HILOGE("%{public}s", errInfo.c_str());
342         napi_throw(reinterpret_cast<napi_env>(&engine),
343             GenerateBusinessError(reinterpret_cast<napi_env>(&engine), errCode, errInfo));
344     }
345     return engine.CreateUndefined();
346 }
347 
OnUnregisterDeviceSelectionCallback(NativeEngine & engine,NativeCallbackInfo & info)348 NativeValue* JsContinuationManager::OnUnregisterDeviceSelectionCallback(NativeEngine &engine, NativeCallbackInfo &info)
349 {
350     HILOGD("called.");
351     std::string cbType;
352     int32_t token = -1;
353     int32_t errCode = PARAMETER_CHECK_FAILED;
354     std::string errInfo = [this, &engine, &info, &cbType, &token, &errCode]() -> std::string {
355         if (info.argc != ARG_COUNT_TWO) {
356             return "Parameter error. The type of \"number of parameters\" must be 2";
357         }
358         if (!ConvertFromJsValue(engine, info.argv[0], cbType)) {
359             return "Parameter error. The type of \"type\" must be string";
360         }
361         if (cbType != EVENT_CONNECT && cbType != EVENT_DISCONNECT) {
362             return "Parameter error. The type of \"type\" must be " +
363                 std::string(EVENT_CONNECT) + " or " + std::string(EVENT_DISCONNECT);
364         }
365         if (!ConvertFromJsValue(engine, info.argv[ARG_COUNT_ONE], token)) {
366             return "Parameter error. The type of \"token\" must be number";
367         }
368         {
369             std::lock_guard<std::mutex> jsCbMapLock(jsCbMapMutex_);
370             if (!IsCallbackRegistered(token, cbType)) {
371                 errCode = CALLBACK_TOKEN_UNREGISTERED;
372                 return ErrorMessageReturn(errCode);
373             }
374             errCode = DistributedAbilityManagerClient::GetInstance().UnregisterDeviceSelectionCallback(token, cbType);
375             if (errCode == ERR_OK) {
376                 CallbackPair& callbackPair = jsCbMap_[token][cbType];
377                 callbackPair.second->RemoveCallback(cbType);
378                 jsCbMap_[token].erase(cbType);
379                 if (jsCbMap_[token].empty()) {
380                     jsCbMap_.erase(token);
381                 }
382                 HILOGI("UnregisterDeviceSelectionCallback success");
383             } else {
384                 errCode = ErrorCodeReturn(errCode);
385                 return ErrorMessageReturn(errCode);
386             }
387         }
388         return std::string();
389     } ();
390     if (!errInfo.empty()) {
391         HILOGE("%{public}s", errInfo.c_str());
392         napi_throw(reinterpret_cast<napi_env>(&engine),
393             GenerateBusinessError(reinterpret_cast<napi_env>(&engine), errCode, errInfo));
394     }
395     return engine.CreateUndefined();
396 }
397 
OnUpdateConnectStatus(NativeEngine & engine,NativeCallbackInfo & info)398 NativeValue *JsContinuationManager::OnUpdateConnectStatus(NativeEngine &engine, NativeCallbackInfo &info)
399 {
400     HILOGD("called.");
401     int32_t errCode = 0;
402     if (info.argc < ARG_COUNT_THREE) {
403         HILOGE("Params not match");
404         errCode = ERR_NOT_OK;
405     }
406     int32_t token = -1;
407     if (!errCode && !ConvertFromJsValue(engine, info.argv[0], token)) {
408         HILOGE("Parse token failed");
409         errCode = ERR_NOT_OK;
410     }
411     std::string deviceId;
412     if (!errCode && !ConvertFromJsValue(engine, info.argv[ARG_COUNT_ONE], deviceId)) {
413         HILOGE("Parse deviceId failed");
414         errCode = ERR_NOT_OK;
415     }
416     DeviceConnectStatus deviceConnectStatus = DeviceConnectStatus::IDLE;
417     if (!errCode && !ConvertFromJsValue(engine, info.argv[ARG_COUNT_TWO], deviceConnectStatus)) {
418         HILOGE("Parse device connect status failed");
419         errCode = ERR_NOT_OK;
420     }
421     AsyncTask::CompleteCallback complete =
422         [token, deviceId, deviceConnectStatus, errCode](NativeEngine &engine, AsyncTask &task, int32_t status) {
423         if (errCode != 0) {
424             task.Reject(engine, CreateJsError(engine, errCode, "Invalidate params."));
425             return;
426         }
427         int32_t ret = DistributedAbilityManagerClient::GetInstance().UpdateConnectStatus(
428             token, deviceId, deviceConnectStatus);
429         if (ret == ERR_OK) {
430             task.Resolve(engine, engine.CreateUndefined());
431         } else {
432             task.Reject(engine, CreateJsError(engine, ret, "UpdateConnectStatus failed."));
433         }
434     };
435 
436     NativeValue* lastParam = (info.argc <= ARG_COUNT_THREE) ? nullptr : info.argv[ARG_COUNT_THREE];
437     NativeValue* result = nullptr;
438     AsyncTask::Schedule("JsContinuationManager::OnUpdateConnectStatus",
439         engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
440     return result;
441 }
442 
OnUpdateContinuationState(NativeEngine & engine,NativeCallbackInfo & info)443 NativeValue* JsContinuationManager::OnUpdateContinuationState(NativeEngine &engine, NativeCallbackInfo &info)
444 {
445     HILOGD("called.");
446     int32_t token = -1;
447     std::string deviceId;
448     DeviceConnectStatus deviceConnectStatus;
449     std::string errInfo = [this, &engine, &info, &token, &deviceId, &deviceConnectStatus, &errInfo]() -> std::string {
450         if (info.argc != ARG_COUNT_THREE && info.argc != ARG_COUNT_FOUR) {
451             return "Parameter error. The type of \"number of parameters\" must be 3 or 4";
452         }
453         if (!ConvertFromJsValue(engine, info.argv[0], token)) {
454             return "Parameter error. The type of \"token\" must be number";
455         }
456         if (!ConvertFromJsValue(engine, info.argv[ARG_COUNT_ONE], deviceId) || deviceId.empty()) {
457             return "Parameter error. The type of \"deviceId\" must be string and not empty";
458         }
459         deviceConnectStatus = DeviceConnectStatus::IDLE;
460         if (!ConvertFromJsValue(engine, info.argv[ARG_COUNT_TWO], deviceConnectStatus)) {
461             return "Parameter error. The type of \"status\" must be DeviceConnectState";
462         }
463         if (static_cast<int32_t>(deviceConnectStatus) < static_cast<int32_t>(DeviceConnectStatus::IDLE) ||
464             static_cast<int32_t>(deviceConnectStatus) > static_cast<int32_t>(DeviceConnectStatus::DISCONNECTING)) {
465             HILOGE("deviceConnectStatus is invalid");
466             return "Parameter error. The type of \"status\" must be DeviceConnectState";
467         }
468         return std::string();
469     } ();
470     if (!errInfo.empty()) {
471         HILOGE("%{public}s", errInfo.c_str());
472         napi_throw(reinterpret_cast<napi_env>(&engine),
473             GenerateBusinessError(reinterpret_cast<napi_env>(&engine), PARAMETER_CHECK_FAILED, errInfo));
474         return engine.CreateUndefined();
475     }
476     AsyncTask::CompleteCallback complete =
477         [this, token, deviceId, deviceConnectStatus](NativeEngine &engine, AsyncTask &task, int32_t status) {
478         int32_t errCode = DistributedAbilityManagerClient::GetInstance().UpdateConnectStatus(
479             token, deviceId, deviceConnectStatus);
480         if (errCode == ERR_OK) {
481             task.Resolve(engine, engine.CreateNull());
482         } else {
483             errCode = ErrorCodeReturn(errCode);
484             task.Reject(engine, CreateJsError(engine, errCode, ErrorMessageReturn(errCode)));
485         }
486     };
487 
488     NativeValue* lastParam = (info.argc == ARG_COUNT_THREE) ? nullptr : info.argv[ARG_COUNT_THREE];
489     NativeValue* result = nullptr;
490     AsyncTask::Schedule("JsContinuationManager::OnUpdateContinuationState",
491         engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
492     return result;
493 }
494 
OnStartDeviceManager(NativeEngine & engine,NativeCallbackInfo & info)495 NativeValue *JsContinuationManager::OnStartDeviceManager(NativeEngine &engine, NativeCallbackInfo &info)
496 {
497     HILOGD("called.");
498     int32_t errCode = 0;
499     if (info.argc < ARG_COUNT_ONE) {
500         HILOGE("Params not match");
501         errCode = ERR_NOT_OK;
502     }
503     int32_t token = -1;
504     if (!errCode && !ConvertFromJsValue(engine, info.argv[0], token)) {
505         HILOGE("Parse token failed");
506         errCode = ERR_NOT_OK;
507     }
508     decltype(info.argc) unwrapArgc = ARG_COUNT_ONE;
509     std::shared_ptr<ContinuationExtraParams> continuationExtraParams = std::make_shared<ContinuationExtraParams>();
510     if (info.argc > ARG_COUNT_ONE && info.argv[ARG_COUNT_ONE]->TypeOf() == NATIVE_OBJECT) {
511         HILOGI("startDeviceManager options is used.");
512         if (!UnWrapContinuationExtraParams(reinterpret_cast<napi_env>(&engine),
513             reinterpret_cast<napi_value>(info.argv[ARG_COUNT_ONE]), continuationExtraParams)) {
514             HILOGE("Parse continuationExtraParams failed");
515             errCode = ERR_NOT_OK;
516         }
517         unwrapArgc++;
518     }
519     AsyncTask::CompleteCallback complete =
520         [token, continuationExtraParams, unwrapArgc, errCode](NativeEngine &engine, AsyncTask &task, int32_t status) {
521         if (errCode != 0) {
522             task.Reject(engine, CreateJsError(engine, errCode, "Invalidate params."));
523             return;
524         }
525         int32_t ret = (unwrapArgc == ARG_COUNT_ONE) ?
526             DistributedAbilityManagerClient::GetInstance().StartDeviceManager(token) :
527             DistributedAbilityManagerClient::GetInstance().StartDeviceManager(token, continuationExtraParams);
528         if (ret == ERR_OK) {
529             task.Resolve(engine, engine.CreateUndefined());
530         } else {
531             task.Reject(engine, CreateJsError(engine, ret, "StartDeviceManager failed."));
532         }
533     };
534 
535     NativeValue* lastParam = (info.argc <= unwrapArgc) ? nullptr : info.argv[unwrapArgc];
536     NativeValue* result = nullptr;
537     AsyncTask::Schedule("JsContinuationManager::OnStartDeviceManager",
538         engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
539     return result;
540 }
541 
OnStartContinuationDeviceManager(NativeEngine & engine,NativeCallbackInfo & info)542 NativeValue* JsContinuationManager::OnStartContinuationDeviceManager(NativeEngine &engine, NativeCallbackInfo &info)
543 {
544     HILOGD("called.");
545     int32_t token = -1;
546     decltype(info.argc) unwrapArgc = ARG_COUNT_ONE;
547     std::shared_ptr<ContinuationExtraParams> continuationExtraParams;
548     std::string errInfo = [this, &engine, &info, &token, & unwrapArgc, &continuationExtraParams]() -> std::string {
549         if (info.argc < ARG_COUNT_ONE || info.argc > ARG_COUNT_THREE) {
550             return "Parameter error. The type of \"number of parameters\" must be greater than 1 and less than 4";
551         }
552         if (!ConvertFromJsValue(engine, info.argv[0], token)) {
553             return "Parameter error. The type of \"token\" must be number";
554         }
555         continuationExtraParams = std::make_shared<ContinuationExtraParams>();
556         if (info.argc > ARG_COUNT_ONE && info.argv[ARG_COUNT_ONE]->TypeOf() == NATIVE_OBJECT) {
557             HILOGI("StartContinuationDeviceManager options is used.");
558             if (!UnWrapContinuationExtraParams(reinterpret_cast<napi_env>(&engine),
559                 reinterpret_cast<napi_value>(info.argv[ARG_COUNT_ONE]), continuationExtraParams)) {
560                 return "Parameter error. The type of \"options\" must be ContinuationExtraParams";
561             }
562             unwrapArgc++;
563         }
564         return std::string();
565     } ();
566     if (!errInfo.empty()) {
567         HILOGE("%{public}s", errInfo.c_str());
568         napi_throw(reinterpret_cast<napi_env>(&engine),
569             GenerateBusinessError(reinterpret_cast<napi_env>(&engine), PARAMETER_CHECK_FAILED, errInfo));
570         return engine.CreateUndefined();
571     }
572     AsyncTask::CompleteCallback complete =
573         [this, token, continuationExtraParams, unwrapArgc](NativeEngine &engine, AsyncTask &task, int32_t status) {
574         int32_t errCode = (unwrapArgc == ARG_COUNT_ONE) ?
575             DistributedAbilityManagerClient::GetInstance().StartDeviceManager(token) :
576             DistributedAbilityManagerClient::GetInstance().StartDeviceManager(token, continuationExtraParams);
577         if (errCode == ERR_OK) {
578             task.Resolve(engine, engine.CreateNull());
579         } else {
580             errCode = ErrorCodeReturn(errCode);
581             task.Reject(engine, CreateJsError(engine, errCode, ErrorMessageReturn(errCode)));
582         }
583     };
584 
585     NativeValue* lastParam = (info.argc <= unwrapArgc) ? nullptr : info.argv[unwrapArgc];
586     NativeValue* result = nullptr;
587     AsyncTask::Schedule("JsContinuationManager::OnStartContinuationDeviceManager",
588         engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
589     return result;
590 }
591 
OnInitDeviceConnectStateObject(NativeEngine & engine,NativeCallbackInfo & info)592 NativeValue *JsContinuationManager::OnInitDeviceConnectStateObject(NativeEngine &engine, NativeCallbackInfo &info)
593 {
594     napi_value object;
595     napi_env env = reinterpret_cast<napi_env>(&engine);
596     NAPI_CALL(env, napi_create_object(env, &object));
597 
598     NAPI_CALL(env, SetEnumItem(env, object, "IDLE",
599         static_cast<int32_t>(DeviceConnectStatus::IDLE)));
600     NAPI_CALL(env, SetEnumItem(env, object, "CONNECTING",
601         static_cast<int32_t>(DeviceConnectStatus::CONNECTING)));
602     NAPI_CALL(env, SetEnumItem(env, object, "CONNECTED",
603         static_cast<int32_t>(DeviceConnectStatus::CONNECTED)));
604     NAPI_CALL(env, SetEnumItem(env, object, "DISCONNECTING",
605         static_cast<int32_t>(DeviceConnectStatus::DISCONNECTING)));
606 
607     return reinterpret_cast<NativeValue*>(object);
608 }
609 
OnInitContinuationModeObject(NativeEngine & engine,NativeCallbackInfo & info)610 NativeValue *JsContinuationManager::OnInitContinuationModeObject(NativeEngine &engine, NativeCallbackInfo &info)
611 {
612     napi_value object;
613     napi_env env = reinterpret_cast<napi_env>(&engine);
614     NAPI_CALL(env, napi_create_object(env, &object));
615 
616     NAPI_CALL(env, SetEnumItem(env, object, "COLLABORATION_SINGLE",
617         static_cast<int32_t>(ContinuationMode::COLLABORATION_SINGLE)));
618     NAPI_CALL(env, SetEnumItem(env, object, "COLLABORATION_MULTIPLE",
619         static_cast<int32_t>(ContinuationMode::COLLABORATION_MUTIPLE)));
620 
621     return reinterpret_cast<NativeValue*>(object);
622 }
623 
SetEnumItem(const napi_env & env,napi_value object,const char * name,int32_t value)624 napi_status JsContinuationManager::SetEnumItem(const napi_env& env, napi_value object, const char* name, int32_t value)
625 {
626     napi_status status;
627     napi_value itemName;
628     napi_value itemValue;
629 
630     NAPI_CALL_BASE(env, status = napi_create_string_utf8(env, name, NAPI_AUTO_LENGTH, &itemName), status);
631     NAPI_CALL_BASE(env, status = napi_create_int32(env, value, &itemValue), status);
632     NAPI_CALL_BASE(env, status = napi_set_property(env, object, itemName, itemValue), status);
633     NAPI_CALL_BASE(env, status = napi_set_property(env, object, itemValue, itemName), status);
634 
635     return napi_ok;
636 }
637 
IsCallbackValid(NativeValue * listenerObj)638 bool JsContinuationManager::IsCallbackValid(NativeValue* listenerObj)
639 {
640     if (listenerObj == nullptr) {
641         HILOGE("listenerObj is nullptr");
642         return false;
643     }
644     if (!listenerObj->IsCallable()) {
645         HILOGE("listenerObj is not callable");
646         return false;
647     }
648     return true;
649 }
650 
IsCallbackRegistered(int32_t token,const std::string & cbType)651 bool JsContinuationManager::IsCallbackRegistered(int32_t token, const std::string& cbType)
652 {
653     if (jsCbMap_.empty() || jsCbMap_.find(token) == jsCbMap_.end()) {
654         HILOGE("token %{public}d not registered callback!", token);
655         return false;
656     }
657     if (jsCbMap_[token].empty() || jsCbMap_[token].find(cbType) == jsCbMap_[token].end()) {
658         HILOGE("cbType %{public}s not registered callback!", cbType.c_str());
659         return false;
660     }
661     HILOGI("callback already registered, token: %{public}d, cbType %{public}s", token, cbType.c_str());
662     return true;
663 }
664 
UnWrapContinuationExtraParams(const napi_env & env,const napi_value & options,std::shared_ptr<ContinuationExtraParams> & continuationExtraParams)665 bool JsContinuationManager::UnWrapContinuationExtraParams(const napi_env& env, const napi_value& options,
666     std::shared_ptr<ContinuationExtraParams>& continuationExtraParams)
667 {
668     HILOGD("called.");
669     if (!IsTypeForNapiValue(env, options, napi_object)) {
670         HILOGE("options is invalid.");
671         return false;
672     }
673     std::vector<std::string> deviceTypes;
674     if (UnwrapStringArrayByPropertyName(env, options, "deviceType", deviceTypes)) {
675         continuationExtraParams->SetDeviceType(deviceTypes);
676     }
677     std::string targetBundle("");
678     if (UnwrapStringByPropertyName(env, options, "targetBundle", targetBundle)) {
679         continuationExtraParams->SetTargetBundle(targetBundle);
680     }
681     std::string description("");
682     if (UnwrapStringByPropertyName(env, options, "description", description)) {
683         continuationExtraParams->SetDescription(description);
684     }
685     nlohmann::json filter;
686     if (!UnwrapJsonByPropertyName(env, options, "filter", filter)) {
687         return false;
688     }
689     continuationExtraParams->SetFilter(filter.dump());
690     int32_t continuationMode = 0;
691     if (UnwrapInt32ByPropertyName(env, options, "continuationMode", continuationMode)) {
692         continuationExtraParams->SetContinuationMode(static_cast<ContinuationMode>(continuationMode));
693     }
694     nlohmann::json authInfo;
695     if (UnwrapJsonByPropertyName(env, options, "authInfo", authInfo)) {
696         continuationExtraParams->SetAuthInfo(authInfo.dump());
697     }
698     return true;
699 }
700 
UnwrapJsonByPropertyName(const napi_env & env,const napi_value & param,const std::string & field,nlohmann::json & jsonObj)701 bool JsContinuationManager::UnwrapJsonByPropertyName(const napi_env& env, const napi_value& param,
702     const std::string& field, nlohmann::json& jsonObj)
703 {
704     HILOGD("called.");
705     if (!IsTypeForNapiValue(env, param, napi_object)) {
706         HILOGE("param is invalid.");
707         return false;
708     }
709     napi_value jsonField = nullptr;
710     napi_get_named_property(env, param, field.c_str(), &jsonField);
711     napi_valuetype jsonFieldType = napi_undefined;
712     napi_typeof(env, jsonField, &jsonFieldType);
713     if (jsonFieldType != napi_object && jsonFieldType != napi_undefined) {
714         HILOGE("field: %{public}s is invalid json.", field.c_str());
715         return false;
716     }
717     napi_value jsProNameList = nullptr;
718     uint32_t jsProCount = 0;
719     napi_get_property_names(env, jsonField, &jsProNameList);
720     napi_get_array_length(env, jsProNameList, &jsProCount);
721     if (!PraseJson(env, jsonField, jsProNameList, jsProCount, jsonObj)) {
722         HILOGE("PraseJson failed.");
723         return false;
724     }
725     return true;
726 }
727 
PraseJson(const napi_env & env,const napi_value & jsonField,const napi_value & jsProNameList,uint32_t jsProCount,nlohmann::json & jsonObj)728 bool JsContinuationManager::PraseJson(const napi_env& env, const napi_value& jsonField,
729     const napi_value& jsProNameList, uint32_t jsProCount, nlohmann::json& jsonObj)
730 {
731     napi_value jsProName = nullptr;
732     napi_value jsProValue = nullptr;
733     napi_valuetype jsValueType = napi_undefined;
734     if (jsProCount > MAX_JSPROCOUNT) {
735         HILOGE("value of jsProCount is larger than MAX_JSPROCOUNT");
736         return false;
737     }
738     for (uint32_t index = 0; index < jsProCount; index++) {
739         napi_get_element(env, jsProNameList, index, &jsProName);
740         std::string strProName = UnwrapStringFromJS(env, jsProName);
741         napi_get_named_property(env, jsonField, strProName.c_str(), &jsProValue);
742         napi_typeof(env, jsProValue, &jsValueType);
743         switch (jsValueType) {
744             case napi_string: {
745                 std::string elementValue = UnwrapStringFromJS(env, jsProValue);
746                 HILOGI("Property name=%{public}s, string, value=%{public}s", strProName.c_str(), elementValue.c_str());
747                 jsonObj[strProName] = elementValue;
748                 break;
749             }
750             case napi_boolean: {
751                 bool elementValue = false;
752                 napi_get_value_bool(env, jsProValue, &elementValue);
753                 HILOGI("Property name=%{public}s, boolean, value=%{public}d.", strProName.c_str(), elementValue);
754                 jsonObj[strProName] = elementValue;
755                 break;
756             }
757             case napi_number: {
758                 int32_t elementValue = 0;
759                 if (napi_get_value_int32(env, jsProValue, &elementValue) != napi_ok) {
760                     HILOGE("Property name=%{public}s, Property int32_t parse error", strProName.c_str());
761                 } else {
762                     HILOGI("Property name=%{public}s, number, value=%{public}d.", strProName.c_str(), elementValue);
763                     jsonObj[strProName] = elementValue;
764                 }
765                 break;
766             }
767             default: {
768                 HILOGE("Property name=%{public}s, value type not support.", strProName.c_str());
769                 break;
770             }
771         }
772     }
773     return true;
774 }
775 
ErrorCodeReturn(int32_t code)776 int32_t JsContinuationManager::ErrorCodeReturn(int32_t code)
777 {
778     switch (code) {
779         case DMS_PERMISSION_DENIED:
780             return PERMISSION_DENIED;
781         case ERR_NULL_OBJECT:
782             return SYSTEM_WORK_ABNORMALLY;
783         case ERR_FLATTEN_OBJECT:
784             return SYSTEM_WORK_ABNORMALLY;
785         case CONNECT_ABILITY_FAILED:
786             return SYSTEM_WORK_ABNORMALLY;
787         case INVALID_CONTINUATION_MODE:
788             return PARAMETER_CHECK_FAILED;
789         case UNKNOWN_CALLBACK_TYPE:
790             return PARAMETER_CHECK_FAILED;
791         case INVALID_CONNECT_STATUS:
792             return PARAMETER_CHECK_FAILED;
793         case CALLBACK_HAS_NOT_REGISTERED:
794             return CALLBACK_TOKEN_UNREGISTERED;
795         case TOKEN_HAS_NOT_REGISTERED:
796             return CALLBACK_TOKEN_UNREGISTERED;
797         case REGISTER_EXCEED_MAX_TIMES:
798             return OVER_MAX_REGISTERED_TIMES;
799         case CALLBACK_HAS_REGISTERED:
800             return REPEATED_REGISTRATION;
801         default:
802             return SYSTEM_WORK_ABNORMALLY;
803     };
804 }
805 
ErrorMessageReturn(int32_t code)806 std::string JsContinuationManager::ErrorMessageReturn(int32_t code)
807 {
808     switch (code) {
809         case PARAMETER_CHECK_FAILED:
810             return "The parameter check failed.";
811         case SYSTEM_WORK_ABNORMALLY:
812             return "The system ability works abnormally.";
813         case CALLBACK_TOKEN_UNREGISTERED:
814             return "The specified token or callback is not registered.";
815         case OVER_MAX_REGISTERED_TIMES:
816             return "The number of token registration times has reached the upper limit.";
817         case REPEATED_REGISTRATION:
818             return "The specified callback has been registered.";
819         default:
820             return "The system ability works abnormally.";
821     };
822 }
823 
GenerateBusinessError(const napi_env & env,int32_t errCode,const std::string & errMsg)824 napi_value JsContinuationManager::GenerateBusinessError(const napi_env &env, int32_t errCode, const std::string &errMsg)
825 {
826     napi_value code = nullptr;
827     napi_create_int32(env, errCode, &code);
828     napi_value msg = nullptr;
829     napi_create_string_utf8(env, errMsg.c_str(), NAPI_AUTO_LENGTH, &msg);
830     napi_value businessError = nullptr;
831     napi_create_error(env, nullptr, msg, &businessError);
832     napi_set_named_property(env, businessError, CODE_KEY_NAME.c_str(), code);
833     return businessError;
834 }
835 
JsContinuationManagerInit(NativeEngine * engine,NativeValue * exportObj)836 NativeValue* JsContinuationManagerInit(NativeEngine* engine, NativeValue* exportObj)
837 {
838     HILOGD("called.");
839     if (engine == nullptr || exportObj == nullptr) {
840         HILOGE("Invalid input parameters");
841         return nullptr;
842     }
843 
844     NativeObject* object = ConvertNativeValueTo<NativeObject>(exportObj);
845     if (object == nullptr) {
846         HILOGE("convertNativeValueTo result is nullptr.");
847         return nullptr;
848     }
849 
850     JsContinuationManager* jsContinuationManager = new JsContinuationManager();
851     object->SetNativePointer(jsContinuationManager, JsContinuationManager::Finalizer, nullptr);
852 
853     const char *moduleName = "JsContinuationManager";
854     BindNativeFunction(*engine, *object, "register", moduleName, JsContinuationManager::Register);
855     BindNativeFunction(*engine, *object, "unregister", moduleName, JsContinuationManager::Unregister);
856     BindNativeFunction(*engine, *object, "on", moduleName, JsContinuationManager::RegisterDeviceSelectionCallback);
857     BindNativeFunction(*engine, *object, "off", moduleName, JsContinuationManager::UnregisterDeviceSelectionCallback);
858     BindNativeFunction(*engine, *object, "updateConnectStatus", moduleName, JsContinuationManager::UpdateConnectStatus);
859     BindNativeFunction(*engine, *object, "startDeviceManager", moduleName, JsContinuationManager::StartDeviceManager);
860     BindNativeProperty(*object, "DeviceConnectState", JsContinuationManager::InitDeviceConnectStateObject);
861     BindNativeProperty(*object, "ContinuationMode", JsContinuationManager::InitContinuationModeObject);
862     BindNativeFunction(*engine, *object, "registerContinuation", moduleName,
863         JsContinuationManager::RegisterContinuation);
864     BindNativeFunction(*engine, *object, "unregisterContinuation", moduleName,
865         JsContinuationManager::UnregisterContinuation);
866     BindNativeFunction(*engine, *object, "updateContinuationState", moduleName,
867         JsContinuationManager::UpdateContinuationState);
868     BindNativeFunction(*engine, *object, "startContinuationDeviceManager", moduleName,
869         JsContinuationManager::StartContinuationDeviceManager);
870 
871     return engine->CreateUndefined();
872 }
873 }  // namespace DistributedSchedule
874 }  // namespace OHOS