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