Files
ability_ability_runtime/frameworks/native/runtime/js_timer.cpp
T
shiyu_huang 971985f727 IssueNo:I5MAOI
Description:Fix setInterval bug while interval is zero
Sig: SIG_ApplicationFramework
Feature or Bugfix:Bugfix
Binary Source:No

Signed-off-by: shiyu_huang <huangshiyu1@huawei.com>
Change-Id: Ib975fb1314c31d44e64a9780e45556b0dbe223fa
2022-08-15 16:29:06 +08:00

193 lines
6.0 KiB
C++

/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "js_timer.h"
#include <atomic>
#include <string>
#include <vector>
#include "hilog_wrapper.h"
#include "js_runtime.h"
#include "js_runtime_utils.h"
#ifdef SUPPORT_GRAPHICS
#include "core/common/container_scope.h"
#endif
#ifdef ENABLE_HITRACE
#include "hitrace/trace.h"
#endif
#ifdef SUPPORT_GRAPHICS
using OHOS::Ace::ContainerScope;
#endif
namespace OHOS {
namespace AbilityRuntime {
namespace {
std::atomic<uint32_t> g_callbackId(1);
class TraceIdScope final {
public:
explicit TraceIdScope(const OHOS::HiviewDFX::HiTraceId& traceId) : valid_(traceId.IsValid())
{
if (valid_) {
OHOS::HiviewDFX::HiTrace::SetId(traceId);
}
}
~TraceIdScope()
{
if (valid_) {
OHOS::HiviewDFX::HiTrace::ClearId();
}
}
TraceIdScope(const TraceIdScope&) = delete;
TraceIdScope(TraceIdScope&&) = delete;
TraceIdScope& operator=(const TraceIdScope&) = delete;
TraceIdScope& operator=(TraceIdScope&&) = delete;
private:
bool valid_ = false;
};
class JsTimer final {
public:
JsTimer(JsRuntime& jsRuntime, const std::shared_ptr<NativeReference>& jsFunction, const std::string &name,
int64_t interval, bool isInterval)
: jsRuntime_(jsRuntime), jsFunction_(jsFunction), name_(name), interval_(interval), isInterval_(isInterval)
{}
~JsTimer() = default;
void operator()() const
{
if (isInterval_) {
jsRuntime_.PostTask(*this, name_, interval_);
}
#ifdef SUPPORT_GRAPHICS
// call js function
ContainerScope containerScope(containerScopeId_);
#endif
HandleScope handleScope(jsRuntime_);
std::vector<NativeValue*> args_;
args_.reserve(jsArgs_.size());
for (auto arg : jsArgs_) {
args_.emplace_back(arg->Get());
}
#ifdef ENABLE_HITRACE
TraceIdScope traceIdScope(traceId_);
#endif
NativeEngine& engine = jsRuntime_.GetNativeEngine();
engine.CallFunction(engine.CreateUndefined(), jsFunction_->Get(), args_.data(), args_.size());
}
void PushArgs(const std::shared_ptr<NativeReference>& ref)
{
jsArgs_.emplace_back(ref);
}
private:
JsRuntime& jsRuntime_;
std::shared_ptr<NativeReference> jsFunction_;
std::vector<std::shared_ptr<NativeReference>> jsArgs_;
std::string name_;
int64_t interval_ = 0;
bool isInterval_ = false;
#ifdef SUPPORT_GRAPHICS
int32_t containerScopeId_ = ContainerScope::CurrentId();
#endif
#ifdef ENABLE_HITRACE
OHOS::HiviewDFX::HiTraceId traceId_ = OHOS::HiviewDFX::HiTrace::GetId();
#endif
};
NativeValue* StartTimeoutOrInterval(NativeEngine* engine, NativeCallbackInfo* info, bool isInterval)
{
if (engine == nullptr || info == nullptr) {
HILOG_ERROR("Start timeout or interval failed with engine or callback info is nullptr.");
return nullptr;
}
// parameter check, must have at least 2 params
if (info->argc < 2 || info->argv[0]->TypeOf() != NATIVE_FUNCTION || info->argv[1]->TypeOf() != NATIVE_NUMBER) {
HILOG_ERROR("Set callback timer failed with invalid parameter.");
return engine->CreateUndefined();
}
// parse parameter
std::shared_ptr<NativeReference> jsFunction(engine->CreateReference(info->argv[0], 1));
int64_t delayTime = *ConvertNativeValueTo<NativeNumber>(info->argv[1]);
uint32_t callbackId = g_callbackId.fetch_add(1, std::memory_order_relaxed);
std::string name = "JsRuntimeTimer_";
name.append(std::to_string(callbackId));
// create timer task
JsRuntime& jsRuntime = *reinterpret_cast<JsRuntime*>(engine->GetJsEngine());
JsTimer task(jsRuntime, jsFunction, name, delayTime, isInterval);
for (size_t index = 2; index < info->argc; ++index) {
task.PushArgs(std::shared_ptr<NativeReference>(engine->CreateReference(info->argv[index], 1)));
}
jsRuntime.PostTask(task, name, delayTime);
return engine->CreateNumber(callbackId);
}
NativeValue* StartTimeout(NativeEngine* engine, NativeCallbackInfo* info)
{
return StartTimeoutOrInterval(engine, info, false);
}
NativeValue* StartInterval(NativeEngine* engine, NativeCallbackInfo* info)
{
return StartTimeoutOrInterval(engine, info, true);
}
NativeValue* StopTimeoutOrInterval(NativeEngine* engine, NativeCallbackInfo* info)
{
if (engine == nullptr || info == nullptr) {
HILOG_ERROR("Stop timeout or interval failed with engine or callback info is nullptr.");
return nullptr;
}
// parameter check, must have at least 1 param
if (info->argc < 1 || info->argv[0]->TypeOf() != NATIVE_NUMBER) {
HILOG_ERROR("Clear callback timer failed with invalid parameter.");
return engine->CreateUndefined();
}
uint32_t callbackId = *ConvertNativeValueTo<NativeNumber>(info->argv[0]);
std::string name = "JsRuntimeTimer_";
name.append(std::to_string(callbackId));
// event should be cancelable before executed
JsRuntime& jsRuntime = *reinterpret_cast<JsRuntime*>(engine->GetJsEngine());
jsRuntime.RemoveTask(name);
return engine->CreateUndefined();
}
}
void InitTimerModule(NativeEngine& engine, NativeObject& globalObject)
{
BindNativeFunction(engine, globalObject, "setTimeout", StartTimeout);
BindNativeFunction(engine, globalObject, "setInterval", StartInterval);
BindNativeFunction(engine, globalObject, "clearTimeout", StopTimeoutOrInterval);
BindNativeFunction(engine, globalObject, "clearInterval", StopTimeoutOrInterval);
}
} // namespace AbilityRuntime
} // namespace OHOS