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