Files
shiyu_huang d5982fa2d3 Fix problem that application will crash while using AsyncTask
Signed-off-by: shiyu_huang <huangshiyu1@huawei.com>
Change-Id: Id5263265c14f631af9fcfd5511989ed60e559b04
2022-03-08 11:01:58 +08:00

242 lines
8.0 KiB
C++

/*
* Copyright (c) 2021 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_runtime_utils.h"
#include "hilog_wrapper.h"
#include "js_runtime.h"
namespace OHOS {
namespace AbilityRuntime {
namespace {
std::unique_ptr<AsyncTask> CreateAsyncTaskWithLastParam(NativeEngine& engine, NativeValue* lastParam,
std::unique_ptr<AsyncTask::ExecuteCallback>&& execute, std::unique_ptr<AsyncTask::CompleteCallback>&& complete,
NativeValue** result)
{
if (lastParam == nullptr || lastParam->TypeOf() != NATIVE_FUNCTION) {
NativeDeferred* nativeDeferred = nullptr;
*result = engine.CreatePromise(&nativeDeferred);
return std::make_unique<AsyncTask>(nativeDeferred, std::move(execute), std::move(complete));
} else {
*result = engine.CreateUndefined();
NativeReference* callbackRef = engine.CreateReference(lastParam, 1);
return std::make_unique<AsyncTask>(callbackRef, std::move(execute), std::move(complete));
}
}
} // namespace
// Help Functions
NativeValue* CreateJsError(NativeEngine& engine, int32_t errCode, const std::string& message)
{
return engine.CreateError(CreateJsValue(engine, errCode), CreateJsValue(engine, message));
}
void BindNativeFunction(NativeEngine& engine, NativeObject& object, const char* name, NativeCallback func)
{
object.SetProperty(name, engine.CreateFunction(name, strlen(name), func, nullptr));
}
void BindNativeProperty(NativeObject& object, const char* name, NativeCallback getter)
{
NativePropertyDescriptor property;
property.utf8name = name;
property.name = nullptr;
property.method = nullptr;
property.getter = getter;
property.setter = nullptr;
property.value = nullptr;
property.attributes = napi_default;
property.data = nullptr;
object.DefineProperty(property);
}
void* GetNativePointerFromCallbackInfo(NativeEngine* engine, NativeCallbackInfo* info, const char* name)
{
if (engine == nullptr || info == nullptr) {
return nullptr;
}
NativeObject* object = ConvertNativeValueTo<NativeObject>(info->thisVar);
if (object != nullptr && name != nullptr) {
object = ConvertNativeValueTo<NativeObject>(object->GetProperty(name));
}
return (object != nullptr) ? object->GetNativePointer() : nullptr;
}
void SetNamedNativePointer(NativeEngine& engine, NativeObject& object, const char* name, void* ptr, NativeFinalize func)
{
NativeValue* value = engine.CreateObject();
NativeObject* newObject = ConvertNativeValueTo<NativeObject>(value);
if (newObject == nullptr) {
return;
}
newObject->SetNativePointer(ptr, func, nullptr);
object.SetProperty(name, value);
}
void* GetNamedNativePointer(NativeEngine& engine, NativeObject& object, const char* name)
{
NativeObject* namedObj = ConvertNativeValueTo<NativeObject>(object.GetProperty(name));
return (namedObj != nullptr) ? namedObj->GetNativePointer() : nullptr;
}
// Handle Scope
HandleScope::HandleScope(JsRuntime& jsRuntime)
{
scopeManager_ = jsRuntime.GetNativeEngine().GetScopeManager();
if (scopeManager_ != nullptr) {
nativeScope_ = scopeManager_->OpenEscape();
}
}
HandleScope::HandleScope(NativeEngine& engine)
{
scopeManager_ = engine.GetScopeManager();
if (scopeManager_ != nullptr) {
nativeScope_ = scopeManager_->OpenEscape();
}
}
HandleScope::~HandleScope()
{
if (nativeScope_ != nullptr) {
scopeManager_->CloseEscape(nativeScope_);
nativeScope_ = nullptr;
}
scopeManager_ = nullptr;
}
NativeValue* HandleScope::Escape(NativeValue* value)
{
if (nativeScope_ != nullptr) {
scopeManager_->Escape(nativeScope_, value);
}
return value;
}
// Async Task
AsyncTask::AsyncTask(NativeDeferred* deferred, std::unique_ptr<AsyncTask::ExecuteCallback>&& execute,
std::unique_ptr<AsyncTask::CompleteCallback>&& complete)
: deferred_(deferred), execute_(std::move(execute)), complete_(std::move(complete))
{}
AsyncTask::AsyncTask(NativeReference* callbackRef, std::unique_ptr<AsyncTask::ExecuteCallback>&& execute,
std::unique_ptr<AsyncTask::CompleteCallback>&& complete)
: callbackRef_(callbackRef), execute_(std::move(execute)), complete_(std::move(complete))
{}
AsyncTask::~AsyncTask() = default;
void AsyncTask::Schedule(NativeEngine& engine, std::unique_ptr<AsyncTask>&& task)
{
if (task && task->Start(engine)) {
task.release();
}
}
void AsyncTask::Resolve(NativeEngine& engine, NativeValue* value)
{
HILOG_INFO("AsyncTask::Resolve is called");
if (deferred_) {
deferred_->Resolve(value);
deferred_.reset();
}
if (callbackRef_) {
NativeValue* argv[] = {
CreateJsError(engine, 0),
value,
};
engine.CallFunction(engine.CreateUndefined(), callbackRef_->Get(), argv, ArraySize(argv));
callbackRef_.reset();
}
HILOG_INFO("AsyncTask::Resolve is called end.");
}
void AsyncTask::Reject(NativeEngine& engine, NativeValue* error)
{
if (deferred_) {
deferred_->Reject(error);
deferred_.reset();
}
if (callbackRef_) {
NativeValue* argv[] = {
error,
engine.CreateUndefined(),
};
engine.CallFunction(engine.CreateUndefined(), callbackRef_->Get(), argv, ArraySize(argv));
callbackRef_.reset();
}
}
void AsyncTask::Execute(NativeEngine* engine, void* data)
{
if (engine == nullptr || data == nullptr) {
return;
}
auto me = static_cast<AsyncTask*>(data);
if (me->execute_ && *(me->execute_)) {
(*me->execute_)();
}
}
void AsyncTask::Complete(NativeEngine* engine, int32_t status, void* data)
{
if (engine == nullptr || data == nullptr) {
return;
}
std::unique_ptr<AsyncTask> me(static_cast<AsyncTask*>(data));
if (me->complete_ && *(me->complete_)) {
HandleScope handleScope(*engine);
(*me->complete_)(*engine, *me, status);
}
}
bool AsyncTask::Start(NativeEngine& engine)
{
work_.reset(engine.CreateAsyncWork(Execute, Complete, this));
return work_->Queue();
}
std::unique_ptr<AsyncTask> CreateAsyncTaskWithLastParam(NativeEngine& engine, NativeValue* lastParam,
AsyncTask::ExecuteCallback&& execute, AsyncTask::CompleteCallback&& complete, NativeValue** result)
{
return CreateAsyncTaskWithLastParam(engine, lastParam,
std::make_unique<AsyncTask::ExecuteCallback>(std::move(execute)),
std::make_unique<AsyncTask::CompleteCallback>(std::move(complete)), result);
}
std::unique_ptr<AsyncTask> CreateAsyncTaskWithLastParam(NativeEngine& engine, NativeValue* lastParam,
AsyncTask::ExecuteCallback&& execute, nullptr_t, NativeValue** result)
{
return CreateAsyncTaskWithLastParam(
engine, lastParam, std::make_unique<AsyncTask::ExecuteCallback>(std::move(execute)), nullptr, result);
}
std::unique_ptr<AsyncTask> CreateAsyncTaskWithLastParam(NativeEngine& engine, NativeValue* lastParam,
nullptr_t, AsyncTask::CompleteCallback&& complete, NativeValue** result)
{
return CreateAsyncTaskWithLastParam(
engine, lastParam, nullptr, std::make_unique<AsyncTask::CompleteCallback>(std::move(complete)), result);
}
std::unique_ptr<AsyncTask> CreateAsyncTaskWithLastParam(NativeEngine& engine, NativeValue* lastParam,
nullptr_t, nullptr_t, NativeValue** result)
{
return CreateAsyncTaskWithLastParam(engine, lastParam, std::unique_ptr<AsyncTask::ExecuteCallback>(),
std::unique_ptr<AsyncTask::CompleteCallback>(), result);
}
} // namespace AbilityRuntime
} // namespace OHOS