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