Files
update_updateservice/client/update_session.cpp
T
2021-06-02 02:19:43 +08:00

233 lines
9.1 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 "update_session.h"
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <unistd.h>
#include <vector>
#include "node_api.h"
#include "update_client.h"
#include "update_helper.h"
#include "package/package.h"
#include "securec.h"
using namespace std;
using namespace OHOS::update_engine;
namespace updateClient {
const int32_t RESULT_ARGC = 2;
uint32_t g_sessionId = 0;
UpdateSession::UpdateSession(UpdateClient *client, int32_t type, size_t argc, size_t callbackNumber)
: sessionId(++g_sessionId), client_(client), type_(type), totalArgc_(argc), callbackNumber_(callbackNumber) {}
int32_t UpdateSession::CreateReference(napi_env env, napi_value arg, uint32_t refcount,
napi_ref &reference) const
{
napi_valuetype valuetype;
napi_status status = napi_typeof(env, arg, &valuetype);
CLIENT_CHECK(status == napi_ok, return status, "Failed to napi_typeof");
CLIENT_CHECK(valuetype == napi_function, return status, "Invalid callback type");
status = napi_create_reference(env, arg, refcount, &reference);
CLIENT_CHECK(status == napi_ok, return status, "Failed to create reference");
return status;
}
napi_value UpdateSession::CreateWorkerName(napi_env env) const
{
napi_value workName;
std::string name = "Async Work" + std::to_string(sessionId);
napi_status status = napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &workName);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to worker name");
return workName;
}
napi_value UpdateSession::StartWork(napi_env env,
size_t startIndex, const napi_value *args, UpdateClient::DoWorkFunction worker, void *context)
{
static std::string sessName[SESSION_MAX] = {
"check version", "download", "upgrade", "set policy", "get policy",
"get new version", "get upgrade status", "subscribe", "unsubscribe", "get update",
"apply new version", "reboot and clean", "verify package", "Cancel Upgrade"
};
CLIENT_LOGI("StartWork type: %s", sessName[type_].c_str());
doWorker_ = worker;
context_ = context;
return StartWork(env, startIndex, args);
}
void UpdateSession::ExecuteWork(napi_env env)
{
if (doWorker_ != nullptr) {
#ifndef UPDATER_UT
int32_t ret = doWorker_(type_, context_);
CLIENT_CHECK_NAPI_CALL(env, ret == 0, return, "execute work");
#else
doWorker_(type_, context_);
#endif
}
return;
}
napi_value UpdateAsyncession::StartWork(napi_env env, size_t startIndex, const napi_value *args)
{
CLIENT_LOGI("UpdateAsyncession::StartWork startIndex: %zu", startIndex);
CLIENT_LOGI("UpdateAsyncession::totalArgc_ %zu callbackNumber_: %zu", totalArgc_, callbackNumber_);
CLIENT_CHECK_NAPI_CALL(env, args != nullptr && totalArgc_ >= startIndex, return nullptr, "Invalid para");
napi_value workName = CreateWorkerName(env);
CLIENT_CHECK_NAPI_CALL(env, workName != nullptr, return nullptr, "Failed to worker name");
// Check whether a callback exists. Only one callback is allowed.
for (size_t i = 0; (i < (totalArgc_ - startIndex)) && (i < callbackNumber_); i++) {
CLIENT_LOGI("CreateReference index:%u", i + startIndex);
int32_t ret = CreateReference(env, args[i + startIndex], 1, callbackRef_[i]);
CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Failed to create reference");
}
// Create an asynchronous call.
napi_status status = napi_create_async_work(env, nullptr, workName, UpdateSession::ExecuteWork,
UpdateSession::CompleteWork, this, &(worker_));
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to create worker");
// Put the thread in the task execution queue.
status = napi_queue_async_work(env, worker_);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to queue worker");
napi_value result;
napi_create_int32(env, 0, &result);
return result;
}
void UpdateAsyncession::CompleteWork(napi_env env, napi_status status)
{
CLIENT_LOGI("UpdateAsyncession::CompleteWork callbackNumber_: %d", static_cast<int32_t>(callbackNumber_));
napi_value callback;
napi_value undefined;
napi_value callResult;
napi_get_undefined(env, &undefined);
napi_value retArgs[RESULT_ARGC] = { 0 };
UpdateResult result;
int32_t fail = 0;
client_->GetUpdateResult(type_, result, fail);
int ret = UpdateClient::BuildErrorResult(env, retArgs[0], fail);
ret |= result.buildJSObject(env, retArgs[1], result);
CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return, "Failed to build json");
status = napi_get_reference_value(env, callbackRef_[0], &callback);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return, "Failed to get reference");
const int callBackNumber = 2;
status = napi_call_function(env, undefined, callback, callBackNumber, retArgs, &callResult);
// Release resources.
for (size_t i = 0; i < callbackNumber_; i++) {
napi_delete_reference(env, callbackRef_[i]);
callbackRef_[i] = nullptr;
}
napi_delete_async_work(env, worker_);
worker_ = nullptr;
}
void UpdateAsyncessionNoCallback::CompleteWork(napi_env env, napi_status status)
{
CLIENT_LOGI("UpdateAsyncessionNoCallback::CompleteWork callbackNumber_: %d",
static_cast<int32_t>(callbackNumber_));
}
napi_value UpdatePromiseSession::StartWork(napi_env env, size_t startIndex, const napi_value *args)
{
CLIENT_LOGI("UpdatePromiseSession::StartWork");
CLIENT_CHECK_NAPI_CALL(env, args != nullptr, return nullptr, "Invalid para");
napi_value workName = CreateWorkerName(env);
CLIENT_CHECK_NAPI_CALL(env, workName != nullptr, return nullptr, "Failed to worker name");
napi_value promise;
napi_status status = napi_create_promise(env, &deferred_, &promise);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to napi_create_promise");
// Create an asynchronous call.
status = napi_create_async_work(env, nullptr, workName, UpdateSession::ExecuteWork,
UpdateSession::CompleteWork, this, &(worker_));
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to napi_create_async_work");
// Put the thread in the task execution queue.
status = napi_queue_async_work(env, worker_);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to napi_queue_async_work");
return promise;
}
void UpdatePromiseSession::CompleteWork(napi_env env, napi_status status)
{
CLIENT_LOGI("UpdatePromiseSession::CompleteWork status: %d", static_cast<int32_t>(status));
// Get the return result.
napi_value processResult;
UpdateResult result;
int32_t fail = 0;
client_->GetUpdateResult(type_, result, fail);
if (fail == 0) {
result.buildJSObject(env, processResult, result);
napi_resolve_deferred(env, deferred_, processResult);
} else {
UpdateClient::BuildErrorResult(env, processResult, fail);
napi_reject_deferred(env, deferred_, processResult);
}
napi_delete_async_work(env, worker_);
worker_ = nullptr;
}
napi_value UpdateListener::StartWork(napi_env env, size_t startIndex, const napi_value *args)
{
CLIENT_LOGI("UpdateListener::StartWork");
CLIENT_CHECK_NAPI_CALL(env, args != nullptr && totalArgc_ > startIndex, return nullptr, "Invalid para");
int ret = UpdateClient::GetStringValue(env, args[0], eventType_);
CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Failed to get event type");
// reference count is 1
ret = CreateReference(env, args[startIndex], 1, handlerRef_);
CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Failed to create reference");
napi_value result;
napi_create_int32(env, 0, &result);
return result;
}
void UpdateListener::NotifyJS(napi_env env, napi_value thisVar, int32_t retcode, const UpdateResult &result) const
{
CLIENT_LOGI("NotifyJS retcode:%d", retcode);
napi_value jsEvent;
result.buildJSObject(env, jsEvent, result);
napi_value handler = nullptr;
napi_value callResult;
napi_get_reference_value(env, handlerRef_, &handler);
napi_call_function(env, thisVar, handler, 1, &jsEvent, &callResult);
}
bool UpdateListener::CheckEqual(napi_env env, napi_value handler, const std::string &type) const
{
bool isEquals = false;
napi_value handlerTemp = nullptr;
napi_get_reference_value(env, handlerRef_, &handlerTemp);
napi_strict_equals(env, handler, handlerTemp, &isEquals);
return isEquals && (type.compare(eventType_) == 0);
}
} // namespace updateClient