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