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