• 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 "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