• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #include "napi_push_callback.h"
16 #include "common.h"
17 
18 #include "ans_log_wrapper.h"
19 #include "js_runtime.h"
20 #include "js_runtime_utils.h"
21 #include "nlohmann/json.hpp"
22 #include "notification_check_info.h"
23 #include "napi_common_want.h"
24 #include "napi_common_util.h"
25 #include "ans_log_wrapper.h"
26 
27 namespace OHOS {
28 namespace Notification {
29 namespace {
30 constexpr size_t ARGC_ONE = 1;
31 constexpr uint32_t ERR_INVOKE_PUSHCHECK_PROMISE = 1;
32 } // namespace
33 
JSPushCallBack(napi_env env)34 JSPushCallBack::JSPushCallBack(napi_env env) : env_(env) {}
35 
~JSPushCallBack()36 JSPushCallBack::~JSPushCallBack() {}
37 
SetJsPushCallBackObject(NotificationConstant::SlotType slotType,napi_value pushCallBackObject)38 void JSPushCallBack::SetJsPushCallBackObject(NotificationConstant::SlotType slotType, napi_value pushCallBackObject)
39 {
40     napi_ref pushCheckObject;
41     napi_create_reference(env_, pushCallBackObject, 1, &pushCheckObject);
42     pushCallBackObjects_.insert_or_assign(slotType, pushCheckObject);
43 }
44 
IsEqualPushCallBackObject(napi_value pushCallBackObject)45 bool JSPushCallBack::IsEqualPushCallBackObject(napi_value pushCallBackObject)
46 {
47     if (pushCallBackObject_ == nullptr) {
48         ANS_LOGE("null pushCallBackObject");
49         return false;
50     }
51     napi_value value = nullptr;
52     napi_get_reference_value(env_, pushCallBackObject_, &value);
53     if (value == nullptr) {
54         ANS_LOGE("null value");
55         return false;
56     }
57 
58     bool isEquals = false;
59     napi_strict_equals(env_, value, pushCallBackObject, &isEquals);
60     return isEquals;
61 }
62 
SetJsPropertyString(std::string key,std::string value,napi_value & jsResult)63 void JSPushCallBack::SetJsPropertyString(std::string key, std::string value, napi_value& jsResult)
64 {
65     napi_value keyNapiValue = nullptr;
66     napi_value valueNapiValue = nullptr;
67     napi_create_string_utf8(env_, key.c_str(), key.length(), &keyNapiValue);
68     napi_create_string_utf8(env_, value.c_str(), value.length(), &valueNapiValue);
69     napi_set_property(env_, jsResult, keyNapiValue, valueNapiValue);
70 }
71 
SetJsPropertyInt32(std::string key,int32_t value,napi_value & jsResult)72 void JSPushCallBack::SetJsPropertyInt32(std::string key, int32_t value, napi_value& jsResult)
73 {
74     napi_value keyNapiValue = nullptr;
75     napi_value valueNapiValue = nullptr;
76     napi_create_string_utf8(env_, key.c_str(), key.length(), &keyNapiValue);
77     napi_create_int32(env_, value, &valueNapiValue);
78     napi_set_property(env_, jsResult, keyNapiValue, valueNapiValue);
79 }
80 
SetJsPropertyWantParams(std::string key,std::shared_ptr<AAFwk::WantParams> wantParams,napi_value & jsResult)81 void JSPushCallBack::SetJsPropertyWantParams(
82     std::string key, std::shared_ptr<AAFwk::WantParams> wantParams, napi_value& jsResult)
83 {
84     napi_value keyNapiValue = nullptr;
85     napi_create_string_utf8(env_, key.c_str(), key.length(), &keyNapiValue);
86     if (wantParams) {
87         napi_value extraInfo = nullptr;
88         extraInfo = OHOS::AppExecFwk::WrapWantParams(env_, *wantParams);
89         napi_set_property(env_, jsResult, keyNapiValue, extraInfo);
90     }
91 }
92 
CallBackReturn(const int32_t ret,const std::weak_ptr<PushCallBackParam> pushCallBackParam)93 void CallBackReturn(const int32_t ret, const std::weak_ptr<PushCallBackParam> pushCallBackParam)
94 {
95     auto callBackParam = pushCallBackParam.lock();
96     if (callBackParam == nullptr) {
97         ANS_LOGI("null callBackParam");
98         return;
99     }
100 
101     std::unique_lock<ffrt::mutex> uniqueLock(callBackParam->callBackMutex);
102     callBackParam->result = ret;
103     callBackParam->ready = true;
104     callBackParam->callBackCondition.notify_all();
105 }
106 
CheckPromiseCallback(napi_env env,napi_callback_info info)107 napi_value JSPushCallBack::CheckPromiseCallback(napi_env env, napi_callback_info info)
108 {
109     ANS_LOGD("called");
110     if (info == nullptr) {
111         ANS_LOGE("null info");
112         return nullptr;
113     }
114 
115     size_t argc = ARGC_ONE;
116     napi_value argv[ARGC_ONE] = {nullptr};
117     void *data;
118 
119     napi_get_cb_info(env, info, &argc, &argv[0], nullptr, &data);
120     int32_t ret = ConvertFunctionResult(env, argv[0]);
121 
122     auto *callbackInfo = static_cast<PromiseCallbackInfo *>(data);
123     CallBackReturn(ret, callbackInfo->GetJsCallBackParam());
124 
125     PromiseCallbackInfo::Destroy(callbackInfo);
126     callbackInfo = nullptr;
127     return nullptr;
128 }
129 
OnCheckNotification(const std::string & notificationData,const std::shared_ptr<PushCallBackParam> & pushCallBackParam)130 int32_t JSPushCallBack::OnCheckNotification(
131     const std::string &notificationData, const std::shared_ptr<PushCallBackParam> &pushCallBackParam)
132 {
133     AbilityRuntime::HandleEscape handleEscape(env_);
134 
135     std::string pkgName;
136     auto checkInfo = std::make_shared<NotificationCheckInfo>();
137     checkInfo->ConvertJsonStringToValue(notificationData);
138 
139     NotificationConstant::SlotType outSlotType = static_cast<NotificationConstant::SlotType>(checkInfo->GetSlotType());
140     if (pushCallBackObjects_.find(outSlotType) == pushCallBackObjects_.end()) {
141         ANS_LOGE("null pushCallBackObjects");
142         return ERR_INVALID_STATE;
143     }
144 
145     napi_value checkFunc = nullptr;
146     napi_get_reference_value(env_, pushCallBackObjects_[outSlotType], &checkFunc);
147     if (checkFunc == nullptr) {
148         ANS_LOGE("null checkFunc");
149         return ERR_INVALID_STATE;
150     }
151     napi_value jsResult = nullptr;
152     napi_create_object(env_, &jsResult);
153 
154     NotificationNapi::SlotType slotType;
155     NotificationNapi::ContentType contentType;
156     NotificationNapi::AnsEnumUtil::ContentTypeCToJS(
157         static_cast<NotificationContent::Type>(checkInfo->GetContentType()), contentType);
158     NotificationNapi::AnsEnumUtil::SlotTypeCToJS(
159         static_cast<NotificationConstant::SlotType>(checkInfo->GetSlotType()), slotType);
160     SetJsPropertyString("bundleName", checkInfo->GetPkgName(), jsResult);
161     SetJsPropertyInt32("notificationId", checkInfo->GetNotifyId(), jsResult);
162     SetJsPropertyInt32("contentType", static_cast<int32_t>(contentType), jsResult);
163     SetJsPropertyInt32("creatorUserId", checkInfo->GetCreatorUserId(), jsResult);
164     SetJsPropertyInt32("slotType", static_cast<int32_t>(slotType), jsResult);
165     SetJsPropertyString("label", checkInfo->GetLabel(), jsResult);
166     SetJsPropertyWantParams("extraInfos", checkInfo->GetExtraInfo(), jsResult);
167 
168     napi_value funcResult;
169     napi_value argv[] = { jsResult };
170 
171     napi_value resultOut = nullptr;
172     napi_call_function(env_, nullptr, checkFunc, ARGC_ONE, &argv[0], &resultOut);
173     funcResult = handleEscape.Escape(resultOut);
174 
175     bool isPromise = false;
176     napi_is_promise(env_, funcResult, &isPromise);
177     if (!isPromise) {
178         ANS_LOGE("Notificaiton check function is not promise.");
179         return ERR_INVALID_STATE;
180     }
181 
182     HandleCheckPromise(funcResult, pushCallBackParam);
183     return ERR_OK;
184 }
185 
HandleCheckPromise(napi_value funcResult,const std::shared_ptr<PushCallBackParam> & pushCallBackParam)186 void JSPushCallBack::HandleCheckPromise(
187     napi_value funcResult, const std::shared_ptr<PushCallBackParam> &pushCallBackParam)
188 {
189     napi_value promiseThen = nullptr;
190     napi_value promiseCatch = nullptr;
191     napi_get_named_property(env_, funcResult, "then", &promiseThen);
192     napi_get_named_property(env_, funcResult, "catch", &promiseCatch);
193 
194     bool isCallable = false;
195     napi_is_callable(env_, promiseThen, &isCallable);
196     if (!isCallable) {
197         ANS_LOGE("HandleCheckPromise property then is not callable.");
198         return;
199     }
200     napi_is_callable(env_, promiseCatch, &isCallable);
201     if (!isCallable) {
202         ANS_LOGE("HandleCheckPromise property catch is not callable.");
203         return;
204     }
205 
206     napi_value checkPromiseCallback;
207     auto *callbackInfo = PromiseCallbackInfo::Create(pushCallBackParam);
208     napi_create_function(env_, "checkPromiseCallback", strlen("checkPromiseCallback"), CheckPromiseCallback,
209         callbackInfo, &checkPromiseCallback);
210 
211     napi_status status;
212     napi_value argvPromise[ARGC_ONE] = { checkPromiseCallback };
213 
214     status = napi_call_function(env_, funcResult, promiseThen, ARGC_ONE, argvPromise, nullptr);
215     if (status != napi_ok) {
216         ANS_LOGE("Invoke pushCheck promise then error.");
217         PromiseCallbackInfo::Destroy(callbackInfo);
218         return CallBackReturn(ERR_INVOKE_PUSHCHECK_PROMISE, pushCallBackParam);
219     }
220 
221     status = napi_call_function(env_, funcResult, promiseCatch, ARGC_ONE, argvPromise, nullptr);
222     if (status != napi_ok) {
223         ANS_LOGE("Invoke pushCheck promise catch error.");
224         PromiseCallbackInfo::Destroy(callbackInfo);
225         return CallBackReturn(ERR_INVOKE_PUSHCHECK_PROMISE, pushCallBackParam);
226     }
227 
228     return;
229 }
230 
ConvertFunctionResult(napi_env env,napi_value funcResult)231 int32_t JSPushCallBack::ConvertFunctionResult(napi_env env, napi_value funcResult)
232 {
233     if (funcResult == nullptr) {
234         ANS_LOGE("null funcResult");
235         return false;
236     }
237     napi_valuetype valueType = napi_undefined;
238     NAPI_CALL_BASE(env, napi_typeof(env, funcResult, &valueType), false);
239     if (valueType != napi_object) {
240         ANS_LOGE("The funcResult is not napi_object.");
241         return false;
242     }
243     if (AppExecFwk::IsExistsByPropertyName(env, funcResult, "code") == false) {
244         ANS_LOGE("GetProperty code failed.");
245         return false;
246     }
247 
248     napi_value codeValue = nullptr;
249     napi_valuetype codeType = napi_undefined;
250     napi_get_named_property(env, funcResult, "code", &codeValue);
251     NAPI_CALL_BASE(env, napi_typeof(env, codeValue, &codeType), false);
252 
253     if (codeType != napi_number) {
254         ANS_LOGE("GetProperty code failed. Number expected.");
255         return false;
256     }
257     int32_t code = -1;
258     if (!AbilityRuntime::ConvertFromJsValue(env, codeValue, code)) {
259         ANS_LOGE("Parse code failed.");
260         return false;
261     }
262 
263     bool hasMessageProperty = false;
264     NAPI_CALL_BASE(env, napi_has_named_property(env, funcResult, "message", &hasMessageProperty), false);
265     if (!hasMessageProperty) {
266         ANS_LOGE("Property message expected.");
267         return false;
268     }
269 
270     napi_value messageValue = nullptr;
271     napi_valuetype messageType = napi_undefined;
272     napi_get_named_property(env, funcResult, "message", &messageValue);
273     NAPI_CALL_BASE(env, napi_typeof(env, messageValue, &messageType), false);
274 
275     if (messageType != napi_string) {
276         ANS_LOGE("GetProperty message failed. String expected.");
277         return false;
278     }
279 
280     std::string message;
281     if (!AbilityRuntime::ConvertFromJsValue(env, messageValue, message)) {
282         ANS_LOGE("Parse message failed.");
283         return false;
284     }
285 
286     ANS_LOGI("code:%{public}d, message:%{public}s", code, message.c_str());
287     return code;
288 }
289 } // namespace Notification
290 } // namespace OHOS
291