1 /*
2 * Copyright (c) 2020-2021 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 "feature_ability_module.h"
17 #if (FEATURE_FEATURE_ABILITY_MODULE == 1)
18 #include "ace_event_error_code.h"
19 #include "ace_log.h"
20 #include "fatal_handler.h"
21 #include "js_app_context.h"
22 #include "js_async_work.h"
23 #include "js_fwk_common.h"
24 #include "securec.h"
25
26 namespace OHOS {
27 namespace ACELite {
28 constexpr char FUNC_SUBSCRIBE[] = "subscribeMsg";
29 constexpr char FUNC_UNSUBSCRIBE[] = "unsubscribeMsg";
30 constexpr char FUNC_SEND_MSG[] = "sendMsg";
31 constexpr char FUNC_DETECT[] = "detect";
32 constexpr char ATTR_DEVICE_ID[] = "deviceId";
33 constexpr char ATTR_BUNDLE_NAME[] = "bundleName";
34 constexpr char ATTR_ABILITY_NAME[] = "abilityName";
35 constexpr char ATTR_MESSAGE[] = "message";
36 constexpr char ERR_MESSAGE[] = "Invalid parameter";
37 constexpr char ERR_SEND_FAIL[] = "Send message fail";
38 constexpr uint8_t ARG_LENGTH_SUCCESS = 1;
39 constexpr uint8_t ARG_LENGTH_FAIL = 2;
40 constexpr uint16_t ERR_CODE_INVALID_PARAMETER = 202;
41 constexpr uint16_t ERR_CODE_SEND_MSG_FAILED = 2060;
42 jerry_value_t FeatureAbilityModule::callbackContext_;
43 jerry_value_t FeatureAbilityModule::successCallback_;
44 jerry_value_t FeatureAbilityModule::failCallback_;
45 bool FeatureAbilityModule::registed = false;
46 jerry_value_t FeatureAbilityModule::sendMsgCallbackContext_;
47 jerry_value_t FeatureAbilityModule::sendMsgSuccessCallback_;
48 jerry_value_t FeatureAbilityModule::sendMsgFailCallback_;
49 jerry_value_t FeatureAbilityModule::detectCallbackContext_;
50 jerry_value_t FeatureAbilityModule::detectSuccessCallback_;
51 jerry_value_t FeatureAbilityModule::detectFailCallback_;
52
Init()53 void FeatureAbilityModule::Init()
54 {
55 callbackContext_ = UNDEFINED;
56 successCallback_ = UNDEFINED;
57 failCallback_ = UNDEFINED;
58 sendMsgCallbackContext_ = UNDEFINED;
59 sendMsgSuccessCallback_ = UNDEFINED;
60 sendMsgFailCallback_ = UNDEFINED;
61 detectCallbackContext_ = UNDEFINED;
62 detectSuccessCallback_ = UNDEFINED;
63 detectFailCallback_ = UNDEFINED;
64 CreateNamedFunction(FUNC_SUBSCRIBE, SubscribeMessage);
65 CreateNamedFunction(FUNC_UNSUBSCRIBE, UnsubscribeMessage);
66 CreateNamedFunction(FUNC_SEND_MSG, SendMsgToPeer);
67 CreateNamedFunction(FUNC_DETECT, Detect);
68 }
69
Release()70 void FeatureAbilityModule::Release()
71 {
72 ReleaseJsValues();
73 if (registed) {
74 char *bundleName = const_cast<char *>(JsAppContext::GetInstance()->GetCurrentBundleName());
75 AbilityKit::UnregisterReceiver(bundleName);
76 registed = false;
77 }
78 ReleaseDetectJsValue();
79 ReleaseSendMsgJsValue();
80 }
81
SyncFailCallback(jerry_value_t & failCb,const jerry_value_t & context,const char * const data,uint16_t errorCode)82 void FeatureAbilityModule::SyncFailCallback(jerry_value_t &failCb,
83 const jerry_value_t &context,
84 const char * const data,
85 uint16_t errorCode)
86 {
87 const char * const emptyStr = "";
88 jerry_value_t args[ARG_LENGTH_FAIL];
89 jerry_value_t cbContext = jerry_acquire_value(context);
90 if (data == nullptr) {
91 args[0] = jerry_create_string(reinterpret_cast<const jerry_char_t *>(emptyStr));
92 } else {
93 args[0] = jerry_create_string(reinterpret_cast<const jerry_char_t *>(data));
94 }
95 args[1] = jerry_create_number(errorCode);
96 CallJSFunctionAutoRelease(failCb, callbackContext_, args, ARG_LENGTH_FAIL);
97 ReleaseJerryValue(args[0], args[1], cbContext, VA_ARG_END_FLAG);
98 }
SyncSendMsgCallback(const jerry_value_t & arg,const jerry_value_t & context,const char * errMsg,const uint16_t errCode,bool success)99 void FeatureAbilityModule::SyncSendMsgCallback(const jerry_value_t &arg,
100 const jerry_value_t &context,
101 const char *errMsg,
102 const uint16_t errCode,
103 bool success)
104 {
105 if (!success) {
106 jerry_value_t failCbValue = jerryx_get_property_str(arg, ATTR_FAIL);
107 if (jerry_value_is_function(failCbValue)) {
108 SyncFailCallback(failCbValue, context, errMsg, errCode);
109 }
110 jerry_release_value(failCbValue);
111 }
112
113 jerry_value_t cmpltCbValue = jerryx_get_property_str(arg, ATTR_COMPLETE);
114 if (jerry_value_is_function(cmpltCbValue)) {
115 CallJSFunctionAutoRelease(cmpltCbValue, context, nullptr, 0);
116 }
117 jerry_release_value(cmpltCbValue);
118 }
119
Detect(const jerry_value_t func,const jerry_value_t context,const jerry_value_t args[],const jerry_length_t length)120 jerry_value_t FeatureAbilityModule::Detect(const jerry_value_t func,
121 const jerry_value_t context,
122 const jerry_value_t args[],
123 const jerry_length_t length)
124 {
125 if (length <= 0) {
126 return UNDEFINED;
127 }
128
129 ReleaseDetectJsValue();
130
131 detectCallbackContext_ = jerry_acquire_value(context);
132
133 jerry_value_t options = args[0];
134 jerry_value_t successCallback = jerryx_get_property_str(options, ATTR_SUCCESS);
135 if (!jerry_value_is_undefined(successCallback)) {
136 if (!jerry_value_is_function(successCallback)) {
137 HILOG_ERROR(HILOG_MODULE_ACE, "the success callback for detect should be a function.");
138 } else {
139 detectSuccessCallback_ = jerry_acquire_value(successCallback);
140 }
141 }
142 jerry_release_value(successCallback);
143
144 jerry_value_t failCallback = jerryx_get_property_str(options, ATTR_FAIL);
145 if (!jerry_value_is_undefined(failCallback)) {
146 if (!jerry_value_is_function(failCallback)) {
147 HILOG_ERROR(HILOG_MODULE_ACE, "the fail callback for detect should be a function.");
148 } else {
149 detectFailCallback_ = jerry_acquire_value(failCallback);
150 }
151 }
152 jerry_release_value(failCallback);
153
154 jerry_value_t nameValue = jerryx_get_property_str(args[0], ATTR_BUNDLE_NAME);
155 char *dstAbilityName = MallocStringOf(nameValue);
156 if (dstAbilityName == nullptr) {
157 SyncFailCallback(detectFailCallback_, context, ERR_MESSAGE, ERR_CODE_INVALID_PARAMETER);
158 ReleaseJerryValue(nameValue, VA_ARG_END_FLAG);
159 return UNDEFINED;
160 }
161
162 char *bundleName = const_cast<char *>(JsAppContext::GetInstance()->GetCurrentBundleName());
163 int32_t ret = AbilityKit::DetectPhoneApp(bundleName, dstAbilityName, detectSuccessCallback_, detectFailCallback_,
164 detectCallbackContext_);
165 if (ret != 0) {
166 SyncFailCallback(detectFailCallback_, context, ERR_SEND_FAIL, ERR_CODE_SEND_MSG_FAILED);
167 }
168
169 ReleaseJerryValue(nameValue, VA_ARG_END_FLAG);
170 ace_free(dstAbilityName);
171 return UNDEFINED;
172 }
173
SendMsgToPeer(const jerry_value_t func,const jerry_value_t context,const jerry_value_t args[],const jerry_length_t length)174 jerry_value_t FeatureAbilityModule::SendMsgToPeer(const jerry_value_t func,
175 const jerry_value_t context,
176 const jerry_value_t args[],
177 const jerry_length_t length)
178 {
179 if (length <= 0) {
180 return UNDEFINED;
181 }
182 ReleaseSendMsgJsValue();
183
184 sendMsgCallbackContext_ = jerry_acquire_value(context);
185 jerry_value_t options = args[0];
186 jerry_value_t successCallback = jerryx_get_property_str(options, ATTR_SUCCESS);
187 if ((!jerry_value_is_undefined(successCallback)) && (!jerry_value_is_function(successCallback))) {
188 sendMsgSuccessCallback_ = jerry_acquire_value(successCallback);
189 } else {
190 HILOG_ERROR(HILOG_MODULE_ACE, "the success callback for sendMsg should be a function.");
191 }
192 jerry_release_value(successCallback);
193 jerry_value_t failCallback = jerryx_get_property_str(options, ATTR_FAIL);
194 if ((!jerry_value_is_undefined(failCallback)) && (!jerry_value_is_function(failCallback))) {
195 sendMsgFailCallback_ = jerry_acquire_value(failCallback);
196 } else {
197 HILOG_ERROR(HILOG_MODULE_ACE, "the fail callback for sendMsg should be a function.");
198 }
199 jerry_release_value(failCallback);
200
201 uint16_t nameLength = 0;
202 jerry_value_t nameValue = jerryx_get_property_str(args[0], ATTR_BUNDLE_NAME);
203 char *dstBundleName = MallocStringOf(nameValue, &nameLength);
204 uint16_t msgLength = 0;
205 jerry_value_t msgValue = jerryx_get_property_str(args[0], ATTR_MESSAGE);
206 char *message = MallocStringOf(msgValue, &msgLength);
207 uint16_t idLength = 0;
208 jerry_value_t devIdValue = jerryx_get_property_str(args[0], ATTR_DEVICE_ID);
209 char *deviceId = MallocStringOf(devIdValue, &idLength);
210 if ((dstBundleName == nullptr) || (nameLength == 0) || (message == nullptr) || (msgLength == 0) ||
211 (deviceId == nullptr)) {
212 SyncSendMsgCallback(args[0], context, ERR_MESSAGE, ERR_CODE_INVALID_PARAMETER, false);
213 } else {
214 char *bundleName = const_cast<char *>(JsAppContext::GetInstance()->GetCurrentBundleName());
215 int32_t ret = AbilityKit::SendMsgToPeerApp(
216 (idLength == 0), bundleName, dstBundleName, (reinterpret_cast<const uint8_t *>(message)), strlen(message),
217 sendMsgSuccessCallback_, sendMsgFailCallback_, sendMsgCallbackContext_);
218 // if the message is sent out successfully, do not invoke user's callback until the peer result back
219 if (ret != 0) {
220 SyncSendMsgCallback(args[0], context, ERR_SEND_FAIL, ERR_CODE_SEND_MSG_FAILED, false);
221 }
222 }
223 ReleaseJerryValue(nameValue, msgValue, devIdValue, VA_ARG_END_FLAG);
224 ACE_FREE(dstBundleName);
225 ACE_FREE(message);
226 ACE_FREE(deviceId);
227 return UNDEFINED;
228 }
229
SubscribeMessage(const jerry_value_t func,const jerry_value_t context,const jerry_value_t args[],const jerry_length_t length)230 jerry_value_t FeatureAbilityModule::SubscribeMessage(const jerry_value_t func,
231 const jerry_value_t context,
232 const jerry_value_t args[],
233 const jerry_length_t length)
234 {
235 if (length <= 0) {
236 return UNDEFINED;
237 }
238
239 ReleaseJsValues();
240
241 callbackContext_ = jerry_acquire_value(context);
242 jerry_value_t options = args[0];
243 jerry_value_t successCallback = jerryx_get_property_str(options, ATTR_SUCCESS);
244 if (!IS_UNDEFINED(successCallback)) {
245 if (!jerry_value_is_function(successCallback)) {
246 HILOG_ERROR(HILOG_MODULE_ACE, "the success callback should be a function.");
247 } else {
248 successCallback_ = jerry_acquire_value(successCallback);
249 }
250 }
251 jerry_release_value(successCallback);
252 jerry_value_t failCallback = jerryx_get_property_str(options, ATTR_FAIL);
253 if (!IS_UNDEFINED(failCallback)) {
254 if (!jerry_value_is_function(failCallback)) {
255 HILOG_ERROR(HILOG_MODULE_ACE, "the fail callback should be a function.");
256 } else {
257 failCallback_ = jerry_acquire_value(failCallback);
258 }
259 }
260 jerry_release_value(failCallback);
261
262 if (!registed) {
263 char *bundleName = const_cast<char *>(JsAppContext::GetInstance()->GetCurrentBundleName());
264 AbilityKit::RegisterReceiver(bundleName, MessageSuccessCallback, MessageFailCallback, successCallback_,
265 failCallback_, callbackContext_);
266 registed = true;
267 }
268
269 return UNDEFINED;
270 }
271
UnsubscribeMessage(const jerry_value_t func,const jerry_value_t context,const jerry_value_t args[],const jerry_length_t length)272 jerry_value_t FeatureAbilityModule::UnsubscribeMessage(const jerry_value_t func,
273 const jerry_value_t context,
274 const jerry_value_t args[],
275 const jerry_length_t length)
276 {
277 Release();
278 ACE_FEATURE_EVENT_PRINT(MT_ACE_FEATUREABILITY, MT_ACE_FEATUREABILITY_UNSUBSCRIBEMSG, 0);
279 return UNDEFINED;
280 }
281
MessageSuccessCallback(const void * data)282 int32_t FeatureAbilityModule::MessageSuccessCallback(const void *data)
283 {
284 if (FatalHandler::GetInstance().IsFatalErrorHitted()) {
285 HILOG_ERROR(HILOG_MODULE_ACE, "drop message as handling fatal error");
286 return -1;
287 }
288 if (data == nullptr) {
289 HILOG_ERROR(HILOG_MODULE_ACE, "message error");
290 return -1;
291 }
292 ACE_FEATURE_EVENT_PRINT(MT_ACE_FEATUREABILITY, MT_ACE_FEATUREABILITY_SUBSCRIBEMSG, 0);
293 const FeatureAbilityDataInfo *origin = static_cast<const FeatureAbilityDataInfo *>(data);
294 FeatureAbilityDataInfo *target = static_cast<FeatureAbilityDataInfo *>(ace_malloc(sizeof(FeatureAbilityDataInfo)));
295 if (target == nullptr) {
296 HILOG_ERROR(HILOG_MODULE_ACE, "Failed to ace_malloc data");
297 return -1;
298 }
299
300 if (memset_s(target, sizeof(FeatureAbilityDataInfo), 0, sizeof(FeatureAbilityDataInfo)) != 0) {
301 HILOG_ERROR(HILOG_MODULE_ACE, "MessageSuccessCallback memset_s failed");
302 ACE_FREE(target);
303 return -1;
304 }
305
306 CopySuccessMessage(origin, target);
307 if (!JsAsyncWork::DispatchAsyncWork(AsyncSuccessCallback, target)) {
308 ACE_FREE(target->deviceID);
309 ACE_FREE(target->bundleName);
310 ACE_FREE(target->abilityName);
311 ACE_FREE(target->message);
312 ACE_FREE(target);
313 }
314
315 return 0;
316 }
CopySuccessMessage(const FeatureAbilityDataInfo * origin,FeatureAbilityDataInfo * & target)317 void FeatureAbilityModule::CopySuccessMessage(const FeatureAbilityDataInfo *origin, FeatureAbilityDataInfo *&target)
318 {
319 size_t bufSize = 0;
320 if (origin->deviceID != nullptr) {
321 bufSize = strlen(origin->deviceID);
322 if (bufSize < DEVICE_ID_LENGTH_MAX) {
323 target->deviceID = static_cast<char *>(ace_malloc(sizeof(char) * (bufSize + 1)));
324 if (target->deviceID != nullptr && memcpy_s(target->deviceID, bufSize, origin->deviceID, bufSize) == 0) {
325 target->deviceID[bufSize] = '\0';
326 } else {
327 ACE_FREE(target->deviceID);
328 }
329 }
330 }
331
332 if (origin->bundleName != nullptr) {
333 bufSize = strlen(origin->bundleName);
334 if (bufSize < NAME_LENGTH_MAX) {
335 target->bundleName = static_cast<char *>(ace_malloc(sizeof(char) * (bufSize + 1)));
336 if (target->bundleName != nullptr &&
337 memcpy_s(target->bundleName, bufSize, origin->bundleName, bufSize) == 0) {
338 target->bundleName[bufSize] = '\0';
339 } else {
340 ACE_FREE(target->bundleName);
341 }
342 }
343 }
344
345 if (origin->abilityName != nullptr) {
346 bufSize = strlen(origin->abilityName);
347 if (bufSize < NAME_LENGTH_MAX) {
348 target->abilityName = static_cast<char *>(ace_malloc(sizeof(char) * (bufSize + 1)));
349 if (target->abilityName != nullptr &&
350 memcpy_s(target->abilityName, bufSize, origin->abilityName, bufSize) == 0) {
351 target->abilityName[bufSize] = '\0';
352 } else {
353 ACE_FREE(target->abilityName);
354 }
355 }
356 }
357
358 if ((origin->message != nullptr) && (origin->messageLength > 0) && (origin->messageLength < UINT16_MAX)) {
359 bufSize = origin->messageLength;
360 char *buffer = static_cast<char *>(ace_malloc(sizeof(char) * (bufSize + 1)));
361 if (buffer != nullptr && memcpy_s(buffer, bufSize, static_cast<const char *>(origin->message), bufSize) == 0) {
362 buffer[bufSize] = '\0';
363 target->messageLength = bufSize;
364 target->message = buffer;
365 } else {
366 ACE_FREE(buffer);
367 target->messageLength = 0;
368 target->message = nullptr;
369 }
370 }
371 }
MessageFailCallback(const void * data,uint16_t dataLength,uint16_t errorCode)372 int32_t FeatureAbilityModule::MessageFailCallback(const void *data, uint16_t dataLength, uint16_t errorCode)
373 {
374 if (FatalHandler::GetInstance().IsFatalErrorHitted()) {
375 HILOG_ERROR(HILOG_MODULE_ACE, "drop message as handling fatal error");
376 return -1;
377 }
378 FailCallbackParams *params = new FailCallbackParams();
379 if (params == nullptr) {
380 return -1;
381 }
382 if ((data != nullptr) && (dataLength > 0)) {
383 char *buffer = static_cast<char *>(ace_malloc(sizeof(char) * (dataLength + 1)));
384 if (buffer != nullptr && memcpy_s(buffer, dataLength, static_cast<const char *>(data), dataLength) == 0) {
385 buffer[dataLength] = '\0';
386 params->dataLength = dataLength;
387 params->data = buffer;
388 } else {
389 ACE_FREE(buffer);
390 params->dataLength = 0;
391 params->data = nullptr;
392 }
393 }
394 params->errorCode = errorCode;
395
396 if (!JsAsyncWork::DispatchAsyncWork(AsyncFailCallback, static_cast<void *>(params))) {
397 ACE_FREE(params->data);
398 delete params;
399 params = nullptr;
400 }
401 return 0;
402 }
403
AsyncSuccessCallback(void * data)404 void FeatureAbilityModule::AsyncSuccessCallback(void *data)
405 {
406 if (data == nullptr) {
407 CallJSFunctionAutoRelease(successCallback_, callbackContext_, nullptr, 0);
408 return;
409 }
410
411 FeatureAbilityDataInfo *nativeData = static_cast<FeatureAbilityDataInfo *>(data);
412 jerry_value_t object = jerry_create_object();
413 if (nativeData->deviceID != nullptr) {
414 JerrySetStringProperty(object, ATTR_DEVICE_ID, nativeData->deviceID);
415 ace_free(nativeData->deviceID);
416 nativeData->deviceID = nullptr;
417 }
418 if (nativeData->bundleName != nullptr) {
419 JerrySetStringProperty(object, ATTR_BUNDLE_NAME, nativeData->bundleName);
420 ace_free(nativeData->bundleName);
421 nativeData->bundleName = nullptr;
422 }
423 if (nativeData->abilityName != nullptr) {
424 JerrySetStringProperty(object, ATTR_ABILITY_NAME, nativeData->abilityName);
425 ace_free(nativeData->abilityName);
426 nativeData->abilityName = nullptr;
427 }
428 if ((nativeData->message != nullptr) && (nativeData->messageLength > 0)) {
429 JerrySetStringProperty(object, ATTR_MESSAGE, static_cast<const char *>(nativeData->message),
430 nativeData->messageLength);
431 ace_free(nativeData->message);
432 nativeData->message = nullptr;
433 }
434
435 jerry_value_t args[ARG_LENGTH_SUCCESS] = {object};
436 CallJSFunctionAutoRelease(successCallback_, callbackContext_, args, ARG_LENGTH_SUCCESS);
437 jerry_release_value(object);
438 ace_free(nativeData);
439 nativeData = nullptr;
440 }
AsyncFailCallback(void * data)441 void FeatureAbilityModule::AsyncFailCallback(void *data)
442 {
443 if (data == nullptr) {
444 return;
445 }
446
447 FailCallbackParams *params = static_cast<FailCallbackParams *>(data);
448 jerry_value_t args[ARG_LENGTH_FAIL];
449 if (params->data == nullptr || params->dataLength == 0) {
450 args[0] = jerry_create_string(reinterpret_cast<const jerry_char_t *>(""));
451 } else {
452 args[0] = jerry_create_string_sz_from_utf8(static_cast<const jerry_char_t *>(params->data), params->dataLength);
453 ace_free(params->data);
454 params->data = nullptr;
455 }
456
457 args[1] = jerry_create_number(params->errorCode);
458 CallJSFunctionAutoRelease(failCallback_, callbackContext_, args, ARG_LENGTH_FAIL);
459 ReleaseJerryValue(args[0], args[1], VA_ARG_END_FLAG);
460 delete (params);
461 params = nullptr;
462 }
463
ReleaseJsValues()464 void FeatureAbilityModule::ReleaseJsValues()
465 {
466 ReleaseJsValue(callbackContext_);
467 ReleaseJsValue(successCallback_);
468 ReleaseJsValue(failCallback_);
469 }
470
ReleaseJsValue(jerry_value_t & value)471 void FeatureAbilityModule::ReleaseJsValue(jerry_value_t &value)
472 {
473 if (!IS_UNDEFINED(value)) {
474 jerry_release_value(value);
475 value = UNDEFINED;
476 }
477 }
478
ReleaseDetectJsValue()479 void FeatureAbilityModule::ReleaseDetectJsValue()
480 {
481 ReleaseJsValue(detectCallbackContext_);
482 ReleaseJsValue(detectSuccessCallback_);
483 ReleaseJsValue(detectFailCallback_);
484
485 AbilityKit::DetectResourceRelease();
486 }
487
ReleaseSendMsgJsValue()488 void FeatureAbilityModule::ReleaseSendMsgJsValue()
489 {
490 ReleaseJsValue(sendMsgCallbackContext_);
491 ReleaseJsValue(sendMsgSuccessCallback_);
492 ReleaseJsValue(sendMsgFailCallback_);
493
494 AbilityKit::SendMsgResourceRelease();
495 }
496 } // namespace ACELite
497 } // namespace OHOS
498 #endif
499