• 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 "js_timer.h"
17 
18 #include <atomic>
19 #include <memory>
20 #include <mutex>
21 #include <string>
22 #include <vector>
23 #include <unordered_map>
24 
25 #include "hilog_wrapper.h"
26 #include "js_runtime.h"
27 #include "js_runtime_utils.h"
28 
29 #ifdef SUPPORT_GRAPHICS
30 #include "core/common/container_scope.h"
31 #endif
32 
33 #ifdef SUPPORT_GRAPHICS
34 using OHOS::Ace::ContainerScope;
35 #endif
36 
37 namespace OHOS {
38 namespace AbilityRuntime {
39 namespace {
40 class JsTimer;
41 
42 std::atomic<uint32_t> g_callbackId(1);
43 std::mutex g_mutex;
44 std::unordered_map<uint32_t, std::shared_ptr<JsTimer>> g_timerTable;
45 
46 class JsTimer final {
47 public:
JsTimer(NativeEngine & nativeEngine,const std::shared_ptr<NativeReference> & jsFunction,uint32_t id)48     JsTimer(NativeEngine& nativeEngine, const std::shared_ptr<NativeReference>& jsFunction, uint32_t id)
49         : nativeEngine_(nativeEngine), jsFunction_(jsFunction), id_(id)
50     {
51         uv_timer_init(nativeEngine.GetUVLoop(), &timerReq_);
52         timerReq_.data = this;
53     }
54 
~JsTimer()55     ~JsTimer()
56     {
57         uv_timer_stop(&timerReq_);
58     }
59 
Start(int64_t timeout,int64_t repeat)60     void Start(int64_t timeout, int64_t repeat)
61     {
62         uv_timer_start(&timerReq_, [](uv_timer_t* timerReq) {
63             auto me = static_cast<JsTimer*>(timerReq->data);
64             me->OnTimeout();
65         }, timeout, repeat);
66     }
67 
OnTimeout()68     void OnTimeout()
69     {
70 #ifdef SUPPORT_GRAPHICS
71         // call js function
72         ContainerScope containerScope(containerScopeId_);
73 #endif
74         HandleScope handleScope(nativeEngine_);
75 
76         std::vector<NativeValue*> args;
77         args.reserve(jsArgs_.size());
78         for (auto arg : jsArgs_) {
79             args.emplace_back(arg->Get());
80         }
81         nativeEngine_.CallFunction(nativeEngine_.CreateUndefined(), jsFunction_->Get(), args.data(), args.size());
82 
83         if (uv_timer_get_repeat(&timerReq_) == 0) {
84             std::lock_guard<std::mutex> lock(g_mutex);
85             g_timerTable.erase(id_);
86         }
87     }
88 
PushArgs(const std::shared_ptr<NativeReference> & ref)89     void PushArgs(const std::shared_ptr<NativeReference>& ref)
90     {
91         jsArgs_.emplace_back(ref);
92     }
93 
94 private:
95     NativeEngine& nativeEngine_;
96     std::shared_ptr<NativeReference> jsFunction_;
97     std::vector<std::shared_ptr<NativeReference>> jsArgs_;
98     uv_timer_t timerReq_;
99     uint32_t id_ = 0;
100 #ifdef SUPPORT_GRAPHICS
101     int32_t containerScopeId_ = ContainerScope::CurrentId();
102 #endif
103 };
104 
StartTimeoutOrInterval(NativeEngine * engine,NativeCallbackInfo * info,bool isInterval)105 NativeValue* StartTimeoutOrInterval(NativeEngine* engine, NativeCallbackInfo* info, bool isInterval)
106 {
107     if (engine == nullptr || info == nullptr) {
108         HILOG_ERROR("Start timeout or interval failed with engine or callback info is nullptr.");
109         return nullptr;
110     }
111 
112     // parameter check, must have at least 2 params
113     if (info->argc < 2 || info->argv[0]->TypeOf() != NATIVE_FUNCTION || info->argv[1]->TypeOf() != NATIVE_NUMBER) {
114         HILOG_ERROR("Set callback timer failed with invalid parameter.");
115         return engine->CreateUndefined();
116     }
117 
118     // parse parameter
119     std::shared_ptr<NativeReference> jsFunction(engine->CreateReference(info->argv[0], 1));
120     int64_t delayTime = *ConvertNativeValueTo<NativeNumber>(info->argv[1]);
121     uint32_t callbackId = g_callbackId.fetch_add(1, std::memory_order_relaxed);
122 
123     auto task = std::make_shared<JsTimer>(*engine, jsFunction, callbackId);
124     for (size_t index = 2; index < info->argc; ++index) {
125         task->PushArgs(std::shared_ptr<NativeReference>(engine->CreateReference(info->argv[index], 1)));
126     }
127 
128     // if setInterval is called, interval must not be zero for repeat, so set to 1ms
129     int64_t interval = 0;
130     if (isInterval) {
131         interval = delayTime > 0 ? delayTime : 1;
132     }
133     task->Start(delayTime, interval);
134 
135     {
136         std::lock_guard<std::mutex> lock(g_mutex);
137         g_timerTable.emplace(callbackId, task);
138     }
139 
140     return engine->CreateNumber(callbackId);
141 }
142 
StartTimeout(NativeEngine * engine,NativeCallbackInfo * info)143 NativeValue* StartTimeout(NativeEngine* engine, NativeCallbackInfo* info)
144 {
145     return StartTimeoutOrInterval(engine, info, false);
146 }
147 
StartInterval(NativeEngine * engine,NativeCallbackInfo * info)148 NativeValue* StartInterval(NativeEngine* engine, NativeCallbackInfo* info)
149 {
150     return StartTimeoutOrInterval(engine, info, true);
151 }
152 
StopTimeoutOrInterval(NativeEngine * engine,NativeCallbackInfo * info)153 NativeValue* StopTimeoutOrInterval(NativeEngine* engine, NativeCallbackInfo* info)
154 {
155     if (engine == nullptr || info == nullptr) {
156         HILOG_ERROR("Stop timeout or interval failed with engine or callback info is nullptr.");
157         return nullptr;
158     }
159 
160     // parameter check, must have at least 1 param
161     if (info->argc < 1 || info->argv[0]->TypeOf() != NATIVE_NUMBER) {
162         HILOG_ERROR("Clear callback timer failed with invalid parameter.");
163         return engine->CreateUndefined();
164     }
165 
166     uint32_t callbackId = *ConvertNativeValueTo<NativeNumber>(info->argv[0]);
167     {
168         std::lock_guard<std::mutex> lock(g_mutex);
169         g_timerTable.erase(callbackId);
170     }
171     return engine->CreateUndefined();
172 }
173 }
174 
InitTimerModule(NativeEngine & engine,NativeObject & globalObject)175 void InitTimerModule(NativeEngine& engine, NativeObject& globalObject)
176 {
177     const char *moduleName = "AsJsTimer";
178     BindNativeFunction(engine, globalObject, "setTimeout", moduleName, StartTimeout);
179     BindNativeFunction(engine, globalObject, "setInterval", moduleName, StartInterval);
180     BindNativeFunction(engine, globalObject, "clearTimeout", moduleName, StopTimeoutOrInterval);
181     BindNativeFunction(engine, globalObject, "clearInterval", moduleName, StopTimeoutOrInterval);
182 }
183 } // namespace AbilityRuntime
184 } // namespace OHOS