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 ¬ificationData, 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