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 "napi_system_timer.h"
17
18 #include "securec.h"
19 #include "napi_utils.h"
20 #include "time_hilog.h"
21 #include "timer_type.h"
22
23 using namespace OHOS::MiscServices;
24
25 namespace OHOS {
26 namespace MiscServices {
27 namespace Time {
ITimerInfoInstance()28 ITimerInfoInstance::ITimerInfoInstance() : callbackInfo_{}
29 {
30 handler_ = std::make_shared<EventHandler>(EventRunner::GetMainEventRunner());
31 }
32
~ITimerInfoInstance()33 ITimerInfoInstance::~ITimerInfoInstance()
34 {
35 }
36
OnTrigger()37 void ITimerInfoInstance::OnTrigger()
38 {
39 if (callbackInfo_.ref == nullptr) {
40 return;
41 }
42 auto callbackInfo = callbackInfo_;
43 auto callback = [callbackInfo]() {
44 TIME_HILOGD(TIME_MODULE_JS_NAPI, "timerCallback success");
45 napi_value undefined = nullptr;
46 napi_get_undefined(callbackInfo.env, &undefined);
47 napi_value callback = nullptr;
48 napi_get_reference_value(callbackInfo.env, callbackInfo.ref, &callback);
49 napi_call_function(callbackInfo.env, undefined, callback, ARGC_ZERO, &undefined, &undefined);
50 };
51 if (handler_ == nullptr) {
52 TIME_HILOGE(TIME_MODULE_JS_NAPI, "handler is nullptr");
53 return;
54 }
55 handler_->PostImmediateTask(callback, "TimerCallbackHandler");
56 }
57
SetCallbackInfo(const napi_env & env,const napi_ref & ref)58 void ITimerInfoInstance::SetCallbackInfo(const napi_env &env, const napi_ref &ref)
59 {
60 callbackInfo_.env = env;
61 callbackInfo_.ref = ref;
62 }
63
SetType(const int & _type)64 void ITimerInfoInstance::SetType(const int &_type)
65 {
66 type = _type;
67 }
68
SetRepeat(bool _repeat)69 void ITimerInfoInstance::SetRepeat(bool _repeat)
70 {
71 repeat = _repeat;
72 }
SetInterval(const uint64_t & _interval)73 void ITimerInfoInstance::SetInterval(const uint64_t &_interval)
74 {
75 interval = _interval;
76 }
SetWantAgent(std::shared_ptr<OHOS::AbilityRuntime::WantAgent::WantAgent> _wantAgent)77 void ITimerInfoInstance::SetWantAgent(std::shared_ptr<OHOS::AbilityRuntime::WantAgent::WantAgent> _wantAgent)
78 {
79 wantAgent = _wantAgent;
80 }
81
SystemTimerInit(napi_env env,napi_value exports)82 napi_value NapiSystemTimer::SystemTimerInit(napi_env env, napi_value exports)
83 {
84 napi_property_descriptor descriptors[] = {
85 DECLARE_NAPI_STATIC_FUNCTION("createTimer", CreateTimer),
86 DECLARE_NAPI_STATIC_FUNCTION("startTimer", StartTimer),
87 DECLARE_NAPI_STATIC_FUNCTION("stopTimer", StopTimer),
88 DECLARE_NAPI_STATIC_FUNCTION("destroyTimer", DestroyTimer),
89 DECLARE_NAPI_PROPERTY("TIMER_TYPE_REALTIME", NapiUtils::CreateNapiNumber(env, 1 << TIMER_TYPE_REALTIME)),
90 DECLARE_NAPI_PROPERTY("TIMER_TYPE_WAKEUP", NapiUtils::CreateNapiNumber(env, 1 << TIMER_TYPE_WAKEUP)),
91 DECLARE_NAPI_PROPERTY("TIMER_TYPE_EXACT", NapiUtils::CreateNapiNumber(env, 1 << TIMER_TYPE_EXACT)),
92 DECLARE_NAPI_PROPERTY("TIMER_TYPE_IDLE", NapiUtils::CreateNapiNumber(env, 1 << TIMER_TYPE_IDLE)),
93 };
94
95 napi_status status =
96 napi_define_properties(env, exports, sizeof(descriptors) / sizeof(napi_property_descriptor), descriptors);
97 if (status != napi_ok) {
98 TIME_HILOGE(TIME_MODULE_JS_NAPI, "define manager properties failed");
99 return NapiUtils::GetUndefinedValue(env);
100 }
101 return exports;
102 }
103
104 std::map<std::string, napi_valuetype> TYPE_STRING_MAP = {
105 { "type", napi_number },
106 { "repeat", napi_boolean },
107 { "interval", napi_number },
108 { "wantAgent", napi_object },
109 { "callback", napi_function },
110 };
111
ParseTimerOptions(napi_env env,ContextBase * context,std::string paraType,const napi_value & value,std::shared_ptr<ITimerInfoInstance> & iTimerInfoInstance)112 void ParseTimerOptions(napi_env env, ContextBase *context, std::string paraType,
113 const napi_value &value, std::shared_ptr<ITimerInfoInstance> &iTimerInfoInstance)
114 {
115 napi_value result = nullptr;
116 OHOS::AbilityRuntime::WantAgent::WantAgent *wantAgent = nullptr;
117 napi_valuetype valueType = napi_undefined;
118 napi_get_named_property(env, value, paraType.c_str(), &result);
119 napi_typeof(env, result, &valueType);
120 CHECK_ARGS_RETURN_VOID(TIME_MODULE_JS_NAPI, context, valueType == TYPE_STRING_MAP[paraType],
121 "Parameter error. The type of type must be number.", JsErrorCode::PARAMETER_ERROR);
122 if (paraType == "type") {
123 int type = 0;
124 napi_get_value_int32(env, result, &type);
125 iTimerInfoInstance->SetType(type);
126 } else if (paraType == "repeat") {
127 bool repeat = false;
128 napi_get_value_bool(env, result, &repeat);
129 iTimerInfoInstance->SetRepeat(repeat);
130 } else if (paraType == "interval") {
131 int64_t interval = 0;
132 napi_get_value_int64(env, result, &interval);
133 CHECK_ARGS_RETURN_VOID(TIME_MODULE_JS_NAPI, context, interval >= 0,
134 "Wrong argument number. Positive number expected.", JsErrorCode::PARAMETER_ERROR);
135 iTimerInfoInstance->SetInterval((uint64_t)interval);
136 } else if (paraType == "wantAgent") {
137 napi_unwrap(env, result, (void **)&wantAgent);
138 CHECK_ARGS_RETURN_VOID(TIME_MODULE_JS_NAPI, context, wantAgent != nullptr, "wantAgent is nullptr.",
139 JsErrorCode::PARAMETER_ERROR);
140 std::shared_ptr<OHOS::AbilityRuntime::WantAgent::WantAgent> sWantAgent =
141 std::make_shared<OHOS::AbilityRuntime::WantAgent::WantAgent>(*wantAgent);
142 iTimerInfoInstance->SetWantAgent(sWantAgent);
143 } else if (paraType == "callback") {
144 napi_ref onTriggerCallback;
145 napi_create_reference(env, result, 1, &onTriggerCallback);
146 iTimerInfoInstance->SetCallbackInfo(env, onTriggerCallback);
147 }
148 }
149
GetTimerOptions(const napi_env & env,ContextBase * context,const napi_value & value,std::shared_ptr<ITimerInfoInstance> & iTimerInfoInstance)150 void NapiSystemTimer::GetTimerOptions(const napi_env &env, ContextBase *context,
151 const napi_value &value, std::shared_ptr<ITimerInfoInstance> &iTimerInfoInstance)
152 {
153 bool hasProperty = false;
154
155 // type: number
156 napi_has_named_property(env, value, "type", &hasProperty);
157 CHECK_ARGS_RETURN_VOID(TIME_MODULE_JS_NAPI, context, hasProperty, "type expected.", JsErrorCode::PARAMETER_ERROR);
158 ParseTimerOptions(env, context, "type", value, iTimerInfoInstance);
159 CHECK_STATUS_RETURN_VOID(TIME_MODULE_JS_NAPI, context, "type parameter error.", JsErrorCode::PARAMETER_ERROR);
160
161 // repeat: boolean
162 napi_has_named_property(env, value, "repeat", &hasProperty);
163 CHECK_ARGS_RETURN_VOID(TIME_MODULE_JS_NAPI, context, hasProperty, "repeat expected.", JsErrorCode::PARAMETER_ERROR);
164 ParseTimerOptions(env, context, "repeat", value, iTimerInfoInstance);
165 CHECK_STATUS_RETURN_VOID(TIME_MODULE_JS_NAPI, context, "repeat parameter error.", JsErrorCode::PARAMETER_ERROR);
166
167 // interval?: number
168 napi_has_named_property(env, value, "interval", &hasProperty);
169 if (hasProperty) {
170 ParseTimerOptions(env, context, "interval", value, iTimerInfoInstance);
171 CHECK_STATUS_RETURN_VOID(TIME_MODULE_JS_NAPI, context, "interval parameter error.",
172 JsErrorCode::PARAMETER_ERROR);
173 }
174
175 // wantAgent?: WantAgent
176 napi_has_named_property(env, value, "wantAgent", &hasProperty);
177 if (hasProperty) {
178 ParseTimerOptions(env, context, "wantAgent", value, iTimerInfoInstance);
179 CHECK_STATUS_RETURN_VOID(TIME_MODULE_JS_NAPI, context, "wantAgent parameter error.",
180 JsErrorCode::PARAMETER_ERROR);
181 }
182
183 // callback?: () => void
184 napi_has_named_property(env, value, "callback", &hasProperty);
185 if (hasProperty) {
186 ParseTimerOptions(env, context, "callback", value, iTimerInfoInstance);
187 CHECK_STATUS_RETURN_VOID(TIME_MODULE_JS_NAPI, context, "callback parameter error.",
188 JsErrorCode::PARAMETER_ERROR);
189 }
190 }
191
CreateTimer(napi_env env,napi_callback_info info)192 napi_value NapiSystemTimer::CreateTimer(napi_env env, napi_callback_info info)
193 {
194 struct CreateTimerContext : public ContextBase {
195 uint64_t timerId = 0;
196 std::shared_ptr<ITimerInfoInstance> iTimerInfoInstance = std::make_shared<ITimerInfoInstance>();
197 };
198 CreateTimerContext *createTimerContext = new CreateTimerContext();
199 auto inputParser = [env, createTimerContext](size_t argc, napi_value *argv) {
200 CHECK_ARGS_RETURN_VOID(TIME_MODULE_JS_NAPI, createTimerContext, argc >= ARGC_ONE, "invalid arguments",
201 JsErrorCode::PARAMETER_ERROR);
202 GetTimerOptions(env, createTimerContext, argv[ARGV_FIRST], createTimerContext->iTimerInfoInstance);
203 CHECK_ARGS_RETURN_VOID(TIME_MODULE_JS_NAPI, createTimerContext, createTimerContext->status == napi_ok,
204 "invalid timer parameter", JsErrorCode::PARAMETER_ERROR);
205 createTimerContext->status = napi_ok;
206 };
207 createTimerContext->GetCbInfo(env, info, inputParser);
208 auto executor = [createTimerContext]() {
209 auto innerCode = TimeServiceClient::GetInstance()->CreateTimerV9(createTimerContext->iTimerInfoInstance,
210 createTimerContext->timerId);
211 if (innerCode != JsErrorCode::ERROR_OK) {
212 createTimerContext->errCode = innerCode;
213 createTimerContext->status = napi_generic_failure;
214 }
215 };
216 auto complete = [createTimerContext](napi_value &output) {
217 uint64_t timerId = static_cast<uint64_t>(createTimerContext->timerId);
218 createTimerContext->status = napi_create_int64(createTimerContext->env, timerId, &output);
219 CHECK_STATUS_RETURN_VOID(TIME_MODULE_JS_NAPI, createTimerContext,
220 "convert native object to javascript object failed", ERROR);
221 };
222 return NapiWork::AsyncEnqueue(env, createTimerContext, "SetTime", executor, complete);
223 }
224
StartTimer(napi_env env,napi_callback_info info)225 napi_value NapiSystemTimer::StartTimer(napi_env env, napi_callback_info info)
226 {
227 struct StartTimerContext : public ContextBase {
228 uint64_t timerId = 0;
229 uint64_t triggerTime = 0;
230 };
231 StartTimerContext *startTimerContext = new StartTimerContext();
232 auto inputParser = [env, startTimerContext](size_t argc, napi_value *argv) {
233 CHECK_ARGS_RETURN_VOID(TIME_MODULE_JS_NAPI, startTimerContext, argc >= ARGC_TWO, "invalid arguments",
234 JsErrorCode::PARAMETER_ERROR);
235 int64_t timerId = 0;
236 startTimerContext->status = napi_get_value_int64(env, argv[ARGV_FIRST], &timerId);
237 CHECK_ARGS_RETURN_VOID(TIME_MODULE_JS_NAPI, startTimerContext, startTimerContext->status == napi_ok,
238 "invalid timerId", JsErrorCode::PARAMETER_ERROR);
239 startTimerContext->timerId = static_cast<uint64_t>(timerId);
240 int64_t triggerTime = 0;
241 startTimerContext->status = napi_get_value_int64(env, argv[ARGV_SECOND], &triggerTime);
242 CHECK_ARGS_RETURN_VOID(TIME_MODULE_JS_NAPI, startTimerContext, startTimerContext->status == napi_ok,
243 "invalid triggerTime", JsErrorCode::PARAMETER_ERROR);
244 startTimerContext->triggerTime = static_cast<uint64_t>(triggerTime);
245 startTimerContext->status = napi_ok;
246 };
247 startTimerContext->GetCbInfo(env, info, inputParser);
248 auto executor = [startTimerContext]() {
249 auto innerCode =
250 TimeServiceClient::GetInstance()->StartTimerV9(startTimerContext->timerId, startTimerContext->triggerTime);
251 if (innerCode != JsErrorCode::ERROR_OK) {
252 startTimerContext->errCode = innerCode;
253 startTimerContext->status = napi_generic_failure;
254 }
255 };
256 auto complete = [env](napi_value &output) { output = NapiUtils::GetUndefinedValue(env); };
257 return NapiWork::AsyncEnqueue(env, startTimerContext, "StartTimer", executor, complete);
258 }
259
StopTimer(napi_env env,napi_callback_info info)260 napi_value NapiSystemTimer::StopTimer(napi_env env, napi_callback_info info)
261 {
262 struct StopTimerContext : public ContextBase {
263 uint64_t timerId = 0;
264 };
265 StopTimerContext *stopTimerContext = new StopTimerContext();
266 auto inputParser = [env, stopTimerContext](size_t argc, napi_value *argv) {
267 CHECK_ARGS_RETURN_VOID(TIME_MODULE_JS_NAPI, stopTimerContext, argc >= ARGC_ONE, "invalid arguments",
268 JsErrorCode::PARAMETER_ERROR);
269 int64_t timerId = 0;
270 stopTimerContext->status = napi_get_value_int64(env, argv[ARGV_FIRST], &timerId);
271 stopTimerContext->timerId = static_cast<uint64_t>(timerId);
272 CHECK_ARGS_RETURN_VOID(TIME_MODULE_JS_NAPI, stopTimerContext, stopTimerContext->status == napi_ok,
273 "invalid timerId", JsErrorCode::PARAMETER_ERROR);
274 stopTimerContext->status = napi_ok;
275 };
276 stopTimerContext->GetCbInfo(env, info, inputParser);
277 auto executor = [stopTimerContext]() {
278 auto innerCode = TimeServiceClient::GetInstance()->StopTimerV9(stopTimerContext->timerId);
279 if (innerCode != JsErrorCode::ERROR_OK) {
280 stopTimerContext->errCode = innerCode;
281 stopTimerContext->status = napi_generic_failure;
282 }
283 };
284 auto complete = [env](napi_value &output) { output = NapiUtils::GetUndefinedValue(env); };
285 return NapiWork::AsyncEnqueue(env, stopTimerContext, "StopTimer", executor, complete);
286 }
287
DestroyTimer(napi_env env,napi_callback_info info)288 napi_value NapiSystemTimer::DestroyTimer(napi_env env, napi_callback_info info)
289 {
290 struct DestroyTimerContext : public ContextBase {
291 uint64_t timerId = 0;
292 };
293 DestroyTimerContext *destroyTimerContext = new DestroyTimerContext();
294 auto inputParser = [env, destroyTimerContext](size_t argc, napi_value *argv) {
295 CHECK_ARGS_RETURN_VOID(TIME_MODULE_JS_NAPI, destroyTimerContext, argc == ARGC_ONE, "invalid arguments",
296 JsErrorCode::PARAMETER_ERROR);
297 int64_t timerId = 0;
298 destroyTimerContext->status = napi_get_value_int64(env, argv[ARGV_FIRST], &timerId);
299 destroyTimerContext->timerId = static_cast<uint64_t>(timerId);
300 CHECK_ARGS_RETURN_VOID(TIME_MODULE_JS_NAPI, destroyTimerContext, destroyTimerContext->status == napi_ok,
301 "invalid timerId", JsErrorCode::PARAMETER_ERROR);
302 destroyTimerContext->status = napi_ok;
303 };
304 destroyTimerContext->GetCbInfo(env, info, inputParser);
305 auto executor = [destroyTimerContext]() {
306 auto innerCode = TimeServiceClient::GetInstance()->DestroyTimerV9(destroyTimerContext->timerId);
307 if (innerCode != ERROR_OK) {
308 destroyTimerContext->errCode = innerCode;
309 destroyTimerContext->status = napi_generic_failure;
310 }
311 };
312 auto complete = [env](napi_value &output) { output = NapiUtils::GetUndefinedValue(env); };
313
314 return NapiWork::AsyncEnqueue(env, destroyTimerContext, "DestroyTimer", executor, complete);
315 }
316 } // namespace Time
317 } // namespace MiscServices
318 } // namespace OHOS