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 <string>
20 #include <vector>
21
22 #include "hilog_wrapper.h"
23 #include "js_runtime.h"
24 #include "js_runtime_utils.h"
25
26 #ifdef SUPPORT_GRAPHICS
27 #include "core/common/container_scope.h"
28 #endif
29 #ifdef ENABLE_HITRACE
30 #include "hitrace/trace.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 std::atomic<uint32_t> g_callbackId(1);
41
42 class TraceIdScope final {
43 public:
TraceIdScope(const OHOS::HiviewDFX::HiTraceId & traceId)44 explicit TraceIdScope(const OHOS::HiviewDFX::HiTraceId& traceId) : valid_(traceId.IsValid())
45 {
46 if (valid_) {
47 OHOS::HiviewDFX::HiTraceChain::SetId(traceId);
48 }
49 }
50
~TraceIdScope()51 ~TraceIdScope()
52 {
53 if (valid_) {
54 OHOS::HiviewDFX::HiTraceChain::ClearId();
55 }
56 }
57
58 TraceIdScope(const TraceIdScope&) = delete;
59 TraceIdScope(TraceIdScope&&) = delete;
60 TraceIdScope& operator=(const TraceIdScope&) = delete;
61 TraceIdScope& operator=(TraceIdScope&&) = delete;
62
63 private:
64 bool valid_ = false;
65 };
66
67 class JsTimer final {
68 public:
JsTimer(JsRuntime & jsRuntime,const std::shared_ptr<NativeReference> & jsFunction,const std::string & name,int64_t interval,bool isInterval)69 JsTimer(JsRuntime& jsRuntime, const std::shared_ptr<NativeReference>& jsFunction, const std::string &name,
70 int64_t interval, bool isInterval)
71 : jsRuntime_(jsRuntime), jsFunction_(jsFunction), name_(name), interval_(interval), isInterval_(isInterval)
72 {}
73
74 ~JsTimer() = default;
75
operator ()() const76 void operator()() const
77 {
78 if (isInterval_) {
79 jsRuntime_.PostTask(*this, name_, interval_);
80 }
81 #ifdef SUPPORT_GRAPHICS
82 // call js function
83 ContainerScope containerScope(containerScopeId_);
84 #endif
85 HandleScope handleScope(jsRuntime_);
86
87 std::vector<NativeValue*> args_;
88 args_.reserve(jsArgs_.size());
89 for (auto arg : jsArgs_) {
90 args_.emplace_back(arg->Get());
91 }
92
93 #ifdef ENABLE_HITRACE
94 TraceIdScope traceIdScope(traceId_);
95 #endif
96 NativeEngine& engine = jsRuntime_.GetNativeEngine();
97 engine.CallFunction(engine.CreateUndefined(), jsFunction_->Get(), args_.data(), args_.size());
98 }
99
PushArgs(const std::shared_ptr<NativeReference> & ref)100 void PushArgs(const std::shared_ptr<NativeReference>& ref)
101 {
102 jsArgs_.emplace_back(ref);
103 }
104
105 private:
106 JsRuntime& jsRuntime_;
107 std::shared_ptr<NativeReference> jsFunction_;
108 std::vector<std::shared_ptr<NativeReference>> jsArgs_;
109 std::string name_;
110 int64_t interval_ = 0;
111 bool isInterval_ = false;
112 #ifdef SUPPORT_GRAPHICS
113 int32_t containerScopeId_ = ContainerScope::CurrentId();
114 #endif
115 #ifdef ENABLE_HITRACE
116 OHOS::HiviewDFX::HiTraceId traceId_ = OHOS::HiviewDFX::HiTraceChain::GetId();
117 #endif
118 };
119
StartTimeoutOrInterval(NativeEngine * engine,NativeCallbackInfo * info,bool isInterval)120 NativeValue* StartTimeoutOrInterval(NativeEngine* engine, NativeCallbackInfo* info, bool isInterval)
121 {
122 if (engine == nullptr || info == nullptr) {
123 HILOG_ERROR("StartTimeoutOrInterval, engine or callback info is nullptr.");
124 return nullptr;
125 }
126
127 // parameter check, must have at least 2 params
128 if (info->argc < 2 || info->argv[0]->TypeOf() != NATIVE_FUNCTION || info->argv[1]->TypeOf() != NATIVE_NUMBER) {
129 HILOG_ERROR("Set callback timer failed with invalid parameter.");
130 return engine->CreateUndefined();
131 }
132
133 // parse parameter
134 std::shared_ptr<NativeReference> jsFunction(engine->CreateReference(info->argv[0], 1));
135 int64_t delayTime = *ConvertNativeValueTo<NativeNumber>(info->argv[1]);
136 uint32_t callbackId = g_callbackId.fetch_add(1, std::memory_order_relaxed);
137 std::string name = "JsRuntimeTimer_";
138 name.append(std::to_string(callbackId));
139
140 // create timer task
141 JsRuntime& jsRuntime = *reinterpret_cast<JsRuntime*>(engine->GetJsEngine());
142 JsTimer task(jsRuntime, jsFunction, name, delayTime, isInterval);
143 for (size_t index = 2; index < info->argc; ++index) {
144 task.PushArgs(std::shared_ptr<NativeReference>(engine->CreateReference(info->argv[index], 1)));
145 }
146
147 jsRuntime.PostTask(task, name, delayTime);
148 return engine->CreateNumber(callbackId);
149 }
150
StartTimeout(NativeEngine * engine,NativeCallbackInfo * info)151 NativeValue* StartTimeout(NativeEngine* engine, NativeCallbackInfo* info)
152 {
153 return StartTimeoutOrInterval(engine, info, false);
154 }
155
StartInterval(NativeEngine * engine,NativeCallbackInfo * info)156 NativeValue* StartInterval(NativeEngine* engine, NativeCallbackInfo* info)
157 {
158 return StartTimeoutOrInterval(engine, info, true);
159 }
160
StopTimeoutOrInterval(NativeEngine * engine,NativeCallbackInfo * info)161 NativeValue* StopTimeoutOrInterval(NativeEngine* engine, NativeCallbackInfo* info)
162 {
163 if (engine == nullptr || info == nullptr) {
164 HILOG_ERROR("Stop timeout or interval failed with engine or callback info is nullptr.");
165 return nullptr;
166 }
167
168 // parameter check, must have at least 1 param
169 if (info->argc < 1 || info->argv[0]->TypeOf() != NATIVE_NUMBER) {
170 HILOG_ERROR("Clear callback timer failed with invalid parameter.");
171 return engine->CreateUndefined();
172 }
173
174 uint32_t callbackId = *ConvertNativeValueTo<NativeNumber>(info->argv[0]);
175 std::string name = "JsRuntimeTimer_";
176 name.append(std::to_string(callbackId));
177
178 // event should be cancelable before executed
179 JsRuntime& jsRuntime = *reinterpret_cast<JsRuntime*>(engine->GetJsEngine());
180 jsRuntime.RemoveTask(name);
181 return engine->CreateUndefined();
182 }
183 }
184
InitTimerModule(NativeEngine & engine,NativeObject & globalObject)185 void InitTimerModule(NativeEngine& engine, NativeObject& globalObject)
186 {
187 HILOG_DEBUG("InitTimerModule begin.");
188 const char *moduleName = "JsTimer";
189 BindNativeFunction(engine, globalObject, "setTimeout", moduleName, StartTimeout);
190 BindNativeFunction(engine, globalObject, "setInterval", moduleName, StartInterval);
191 BindNativeFunction(engine, globalObject, "clearTimeout", moduleName, StopTimeoutOrInterval);
192 BindNativeFunction(engine, globalObject, "clearInterval", moduleName, StopTimeoutOrInterval);
193 }
194 } // namespace AbilityRuntime
195 } // namespace OHOS