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 "request_suspend_delay.h"
17
18 #include <uv.h>
19
20 #include "singleton.h"
21
22 #include "background_task_manager.h"
23 #include "transient_task_log.h"
24
25 namespace OHOS {
26 namespace BackgroundTaskMgr {
27 static const int32_t REQUEST_SUSPEND_DELAY_PARAMS = 2;
28
29 struct CallbackReceiveDataWorker {
30 napi_env env = nullptr;
31 napi_ref ref = nullptr;
32 };
33
CallbackInstance()34 CallbackInstance::CallbackInstance() {}
35
~CallbackInstance()36 CallbackInstance::~CallbackInstance()
37 {
38 if (expiredCallbackInfo_.ref != nullptr) {
39 napi_delete_reference(expiredCallbackInfo_.env, expiredCallbackInfo_.ref);
40 }
41 }
42
UvQueueWorkOnExpired(uv_work_t * work,int status)43 void UvQueueWorkOnExpired(uv_work_t *work, int status)
44 {
45 BGTASK_LOGI("OnExpired uv_work_t start");
46
47 if (work == nullptr) {
48 BGTASK_LOGE("work is null");
49 return;
50 }
51
52 CallbackReceiveDataWorker *dataWorkerData = (CallbackReceiveDataWorker *)work->data;
53 if (dataWorkerData == nullptr) {
54 BGTASK_LOGE("dataWorkerData is null");
55 delete work;
56 work = nullptr;
57 return;
58 }
59
60 Common::SetCallback(dataWorkerData->env, dataWorkerData->ref, Common::NapiGetNull(dataWorkerData->env));
61
62 delete dataWorkerData;
63 dataWorkerData = nullptr;
64 delete work;
65 work = nullptr;
66 }
67
OnExpired()68 void CallbackInstance::OnExpired()
69 {
70 BGTASK_LOGI("enter");
71
72 if (expiredCallbackInfo_.ref == nullptr) {
73 BGTASK_LOGE("expired callback unset");
74 return;
75 }
76
77 uv_loop_s *loop = nullptr;
78 napi_get_uv_event_loop(expiredCallbackInfo_.env, &loop);
79 if (loop == nullptr) {
80 BGTASK_LOGE("loop instance is nullptr");
81 return;
82 }
83
84 CallbackReceiveDataWorker *dataWorker = new (std::nothrow) CallbackReceiveDataWorker();
85 if (dataWorker == nullptr) {
86 BGTASK_LOGE("new dataWorker failed");
87 return;
88 }
89
90 dataWorker->env = expiredCallbackInfo_.env;
91 dataWorker->ref = expiredCallbackInfo_.ref;
92
93 uv_work_t *work = new (std::nothrow) uv_work_t;
94 if (work == nullptr) {
95 BGTASK_LOGE("new work failed");
96 delete dataWorker;
97 dataWorker = nullptr;
98 return;
99 }
100
101 work->data = (void *)dataWorker;
102
103 int ret = uv_queue_work(loop, work, [](uv_work_t *work) {}, UvQueueWorkOnExpired);
104 if (ret != 0) {
105 delete dataWorker;
106 dataWorker = nullptr;
107 delete work;
108 work = nullptr;
109 }
110 }
111
SetCallbackInfo(const napi_env & env,const napi_ref & ref)112 void CallbackInstance::SetCallbackInfo(const napi_env &env, const napi_ref &ref)
113 {
114 expiredCallbackInfo_.env = env;
115 expiredCallbackInfo_.ref = ref;
116 }
117
GetExpiredCallback(const napi_env & env,const napi_value & value,CallbackInstancesInfo & callbcakInfo)118 napi_value GetExpiredCallback(
119 const napi_env &env, const napi_value &value, CallbackInstancesInfo &callbcakInfo)
120 {
121 napi_ref result = nullptr;
122
123 callbcakInfo.callback = new (std::nothrow) CallbackInstance();
124 if (callbcakInfo.callback == nullptr) {
125 BGTASK_LOGE("callback is null");
126 return nullptr;
127 }
128
129 napi_create_reference(env, value, 1, &result);
130 callbcakInfo.callback->SetCallbackInfo(env, result);
131
132 return Common::NapiGetNull(env);
133 }
134
ParseParameters(const napi_env & env,const napi_callback_info & info,std::u16string & reason,CallbackInstance * & callback)135 napi_value ParseParameters(const napi_env &env, const napi_callback_info &info,
136 std::u16string &reason, CallbackInstance *&callback)
137 {
138 size_t argc = REQUEST_SUSPEND_DELAY_PARAMS;
139 napi_value argv[REQUEST_SUSPEND_DELAY_PARAMS] = {nullptr};
140 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
141 NAPI_ASSERT(env, argc == REQUEST_SUSPEND_DELAY_PARAMS, "Wrong number of arguments");
142
143 // argv[0] : reason
144 if (Common::GetU16StringValue(env, argv[0], reason) == nullptr) {
145 BGTASK_LOGE("ParseParameters failed, reason is nullptr ");
146 return nullptr;
147 }
148
149 // arg[1] : callback
150 napi_valuetype valuetype = napi_undefined;
151 NAPI_CALL(env, napi_typeof(env, argv[1], &valuetype));
152 NAPI_ASSERT(env, valuetype == napi_function, "Wrong argument type. Object expected.");
153
154 CallbackInstancesInfo callbackInstancesInfo;
155 if (GetExpiredCallback(env, argv[1], callbackInstancesInfo) == nullptr) {
156 BGTASK_LOGE("CallbackInstancesInfo parse failed");
157 return nullptr;
158 }
159 callback = callbackInstancesInfo.callback;
160 return Common::NapiGetNull(env);
161 }
162
RequestSuspendDelay(napi_env env,napi_callback_info info)163 napi_value RequestSuspendDelay(napi_env env, napi_callback_info info)
164 {
165 CallbackInstance *objectInfo = nullptr;
166 std::u16string reason;
167 if (ParseParameters(env, info, reason, objectInfo) == nullptr) {
168 if (objectInfo) {
169 delete objectInfo;
170 objectInfo = nullptr;
171 }
172 return Common::NapiGetNull(env);
173 }
174
175 std::shared_ptr<DelaySuspendInfo> delaySuspendInfo;
176 DelayedSingleton<BackgroundTaskManager>::GetInstance()->
177 RequestSuspendDelay(reason, *objectInfo, delaySuspendInfo);
178
179 napi_value result = nullptr;
180 napi_create_object(env, &result);
181 if (!Common::SetDelaySuspendInfo(env, delaySuspendInfo, result)) {
182 BGTASK_LOGW("Set DelaySuspendInfo object failed");
183 }
184 return result;
185 }
186 } // namespace BackgroundTaskMgr
187 } // namespace OHOS