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

911 lines
37 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* 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_client.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <memory>
#include <mutex>
#include <string>
#include <sys/reboot.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <vector>
#include "iupdate_service.h"
#include "misc_info/misc_info.h"
#include "node_api.h"
#include "node_api_types.h"
#include "package/package.h"
#include "securec.h"
#include "update_helper.h"
#include "update_service_kits.h"
#include "update_session.h"
using namespace std;
using namespace OHOS::update_engine;
namespace updateClient {
const int32_t MAX_ARGC = 3;
const int32_t DEVICE_ID_INDEX = 1;
const int32_t MID_ARGC = 2;
const int32_t CLIENT_STRING_MAX_LENGTH = 200;
constexpr int PROGRESS_DOWNLOAD_FINISH = 100;
const std::string MISC_FILE = "/dev/block/platform/soc/10100000.himci.eMMC/by-name/misc";
const std::string UPDATER_PKG_NAME = "/data/updater/updater.zip";
UpdateClient::UpdateClient(napi_env env, napi_value thisVar)
{
thisReference_ = nullptr;
env_ = env;
napi_create_reference(env, thisVar, 1, &thisReference_);
context_.type = "OTA";
context_.upgradeDevId = "local";
context_.controlDevId = "local";
context_.upgradeApp = "updateclient";
context_.upgradeFile = UPDATER_PKG_NAME;
}
UpdateClient::~UpdateClient()
{
sessions_.clear();
if (thisReference_ != nullptr) {
napi_delete_reference(env_, thisReference_);
}
}
UpdateSession *UpdateClient::RemoveSession(uint32_t sessionId)
{
CLIENT_LOGI("RemoveSession sess");
std::lock_guard<std::mutex> guard(sessionMutex_);
UpdateSession *sess = nullptr;
auto iter = sessions_.find(sessionId);
if (iter != sessions_.end()) {
sess = iter->second.get();
sessions_.erase(iter);
}
return sess;
}
void UpdateClient::AddSession(std::shared_ptr<UpdateSession> session)
{
CLIENT_CHECK(session != nullptr, return, "Invalid param");
std::lock_guard<std::mutex> guard(sessionMutex_);
sessions_.insert(make_pair(session->GetSessionId(), session));
}
napi_value UpdateClient::GetUpdaterForOther(napi_env env, napi_callback_info info)
{
size_t argc = MAX_ARGC;
napi_value args[MAX_ARGC] = {0};
napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info");
CLIENT_CHECK_NAPI_CALL(env, argc >= MID_ARGC, return nullptr, "Invalid param");
// Get the devid.
int ret = GetStringValue(env, args[1], context_.upgradeDevId);
CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Error get type");
return GetUpdater(env, info, DEVICE_ID_INDEX + 1);
}
napi_value UpdateClient::GetUpdaterFromOther(napi_env env, napi_callback_info info)
{
size_t argc = MAX_ARGC;
napi_value args[MAX_ARGC] = {0};
napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info");
CLIENT_CHECK_NAPI_CALL(env, argc >= MID_ARGC, return nullptr, "Invalid param");
// Get the devid.
int ret = GetStringValue(env, args[1], context_.controlDevId);
CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Error get type");
return GetUpdater(env, info, DEVICE_ID_INDEX + 1);
}
bool UpdateClient::CheckUpgradeType(const std::string &type)
{
std::vector<std::string> upgradeTypes = {
"ota", "patch"
};
std::string upgradeType = type;
upgradeType.erase(0, upgradeType.find_first_not_of(" "));
upgradeType.erase(upgradeType.find_last_not_of(" ") + 1);
std::transform(upgradeType.begin(), upgradeType.end(), upgradeType.begin(), ::tolower);
for (auto inter = upgradeTypes.cbegin(); inter != upgradeTypes.cend(); inter++) {
if ((*inter).compare(upgradeType) == 0) {
return true;
}
}
return false;
}
bool UpdateClient::CheckUpgradeFile(const std::string &upgradeFile)
{
if (upgradeFile.empty()) {
return false;
}
std::string file = upgradeFile;
file.erase(0, file.find_first_not_of(" "));
file.erase(file.find_last_not_of(" ") + 1);
int32_t pos = file.find_first_of('/');
if (pos != 0) {
return false;
}
pos = file.find_last_of('.');
if (pos < 0) {
return false;
}
std::string postfix = file.substr(pos + 1, -1);
std::transform(postfix.begin(), postfix.end(), postfix.begin(), ::tolower);
if (postfix.compare("bin") == 0) {
return true;
} else if (postfix.compare("zip") == 0) {
return true;
} else if (postfix.compare("lz4") == 0) {
return true;
} else if (postfix.compare("gz") == 0) {
return true;
}
return false;
}
napi_value UpdateClient::GetUpdater(napi_env env, napi_callback_info info, int32_t typeIndex)
{
napi_value result;
napi_create_int32(env, 0, &result);
size_t argc = MAX_ARGC;
napi_value args[MAX_ARGC] = {0};
napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info");
CLIENT_CHECK_NAPI_CALL(env, argc >= 1, return nullptr, "Invalid param");
CLIENT_CHECK_NAPI_CALL(env, !isInit, return nullptr, "Has beed init");
int ret = GetStringValue(env, args[0], context_.upgradeFile);
CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok && CheckUpgradeFile(context_.upgradeFile),
return nullptr, "Invalid upgradeFile");
ret = GetStringValue(env, args[typeIndex], context_.type);
if (ret == napi_ok) {
CLIENT_CHECK_NAPI_CALL(env, CheckUpgradeType(context_.type), return nullptr, "Error get upgradeType");
} else {
context_.type = "OTA";
}
CLIENT_LOGE("GetUpdater argc %s", context_.type.c_str());
UpdateCallbackInfo callback {
[&](const VersionInfo &info) {
this->NotifyCheckVersionDone(info);
},
[&](const Progress &info) {
this->NotifyDownloadProgress(info);
},
[&](const Progress &info) {
this->NotifyUpgradeProgresss(info);
},
};
UpdateServiceKits::GetInstance().RegisterUpdateCallback(context_, callback);
isInit = true;
return nullptr;
}
napi_value UpdateClient::StartSession(napi_env env,
napi_callback_info info, int32_t type, size_t callbackStartIndex, DoWorkFunction function)
{
size_t argc = MAX_ARGC;
napi_value args[MAX_ARGC] = {0};
napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info");
CLIENT_LOGE("StartSession type %d argc %zu callbackStartIndex %d", type, argc, callbackStartIndex);
std::shared_ptr<UpdateSession> sess = nullptr;
if (argc > callbackStartIndex) {
sess = std::make_shared<UpdateAsyncession>(this, type, argc, 1);
} else {
sess = std::make_shared<UpdatePromiseSession>(this, type, argc, 0);
}
CLIENT_CHECK_NAPI_CALL(env, sess != nullptr, return nullptr, "Failed to create update session");
AddSession(sess);
napi_value retValue = sess->StartWork(env, callbackStartIndex, args, function, nullptr);
CLIENT_CHECK(retValue != nullptr, RemoveSession(sess->GetSessionId()); return nullptr, "Failed to start worker.");
return retValue;
}
napi_value UpdateClient::CheckNewVersion(napi_env env, napi_callback_info info)
{
versionInfo_.status = SYSTEM_ERROR;
napi_value ret = StartSession(env, info, SESSION_CHECK_VERSION, 0,
[&](int32_t type, void *context) -> int {
return UpdateServiceKits::GetInstance().CheckNewVersion();
});
CLIENT_CHECK(ret != nullptr, return nullptr, "Failed to start worker.");
return ret;
}
napi_value UpdateClient::CancelUpgrade(napi_env env, napi_callback_info info)
{
size_t argc = MAX_ARGC;
napi_value args[MAX_ARGC] = {0};
napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info");
CLIENT_LOGE("CancelUpgrade");
std::shared_ptr<UpdateSession> sess = nullptr;
sess = std::make_shared<UpdateAsyncessionNoCallback>(this, SESSION_CANCEL_UPGRADE, argc, 0);
CLIENT_CHECK_NAPI_CALL(env, sess != nullptr, return nullptr, "Failed to create update session");
AddSession(sess);
napi_value retValue = sess->StartWork(env, 0, args,
[&](int32_t type, void *context) -> int {
return UpdateServiceKits::GetInstance().Cancel(IUpdateService::DOWNLOAD);
}, nullptr);
CLIENT_CHECK(retValue != nullptr, RemoveSession(sess->GetSessionId()); return nullptr, "Failed to start worker.");
return retValue;
}
napi_value UpdateClient::DownloadVersion(napi_env env, napi_callback_info info)
{
size_t argc = MAX_ARGC;
napi_value args[MAX_ARGC] = {0};
napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info");
CLIENT_LOGE("DownloadVersion");
std::shared_ptr<UpdateSession> sess = nullptr;
sess = std::make_shared<UpdateAsyncessionNoCallback>(this, SESSION_DOWNLOAD, argc, 0);
CLIENT_CHECK_NAPI_CALL(env, sess != nullptr, return nullptr, "Failed to create update session");
AddSession(sess);
napi_value retValue = sess->StartWork(env, 0, args,
[&](int32_t type, void *context) -> int {
return UpdateServiceKits::GetInstance().DownloadVersion();
}, nullptr);
CLIENT_CHECK(retValue != nullptr, RemoveSession(sess->GetSessionId()); return nullptr, "Failed to start worker.");
return retValue;
}
napi_value UpdateClient::UpgradeVersion(napi_env env, napi_callback_info info)
{
size_t argc = MAX_ARGC;
napi_value args[MAX_ARGC] = {0};
napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info");
std::shared_ptr<UpdateSession> sess = nullptr;
sess = std::make_shared<UpdateAsyncessionNoCallback>(this, SESSION_UPGRADE, argc, 0);
CLIENT_CHECK_NAPI_CALL(env, sess != nullptr, return nullptr, "Failed to create update session");
AddSession(sess);
napi_value retValue = sess->StartWork(env, 0, args,
[&](int32_t type, void *context) -> int {
#ifndef UPDATER_API_TEST
return UpdateServiceKits::GetInstance().DoUpdate();
#else
return 0;
#endif
}, nullptr);
CLIENT_CHECK(retValue != nullptr, RemoveSession(sess->GetSessionId()); return nullptr, "Failed to start worker.");
return retValue;
}
napi_value UpdateClient::SetUpdatePolicy(napi_env env, napi_callback_info info)
{
size_t argc = MAX_ARGC;
napi_value args[MAX_ARGC] = {0};
napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info");
int ret = GetUpdatePolicyFromArg(env, args[0], updatePolicy_);
CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Failed to get policy para");
std::shared_ptr<UpdateSession> sess = nullptr;
if (argc >= MID_ARGC) {
sess = std::make_shared<UpdateAsyncession>(this, SESSION_SET_POLICY, argc, 1);
} else {
sess = std::make_shared<UpdatePromiseSession>(this, SESSION_SET_POLICY, argc, 0);
}
CLIENT_CHECK_NAPI_CALL(env, sess != nullptr, return nullptr, "Failed to create update session");
AddSession(sess);
napi_value retValue = sess->StartWork(env, 1, args,
[&](int32_t type, void *context) -> int {
result_ = UpdateServiceKits::GetInstance().SetUpdatePolicy(updatePolicy_);
return result_;
}, nullptr);
CLIENT_CHECK(retValue != nullptr, RemoveSession(sess->GetSessionId());
return nullptr, "Failed to SetUpdatePolicy.");
return retValue;
}
napi_value UpdateClient::GetUpdatePolicy(napi_env env, napi_callback_info info)
{
napi_value retValue = StartSession(env, info, SESSION_GET_POLICY, 0,
[&](int32_t type, void *context) -> int {
return UpdateServiceKits::GetInstance().GetUpdatePolicy(updatePolicy_);
});
CLIENT_CHECK(retValue != nullptr, return nullptr, "Failed to UpgradeVersion.");
return retValue;
}
napi_value UpdateClient::GetNewVersionInfo(napi_env env, napi_callback_info info)
{
napi_value retValue = StartSession(env, info, SESSION_GET_NEW_VERSION, 0,
[&](int32_t type, void *context) -> int {
return UpdateServiceKits::GetInstance().GetNewVersion(versionInfo_);
});
CLIENT_CHECK(retValue != nullptr, return nullptr, "Failed to GetNewVersionInfo.");
return retValue;
}
napi_value UpdateClient::GetUpgradeStatus(napi_env env, napi_callback_info info)
{
napi_value retValue = StartSession(env, info, SESSION_GET_STATUS, 0,
[&](int32_t type, void *context) -> int {
return UpdateServiceKits::GetInstance().GetUpgradeStatus(upgradeInfo_);
});
CLIENT_CHECK(retValue != nullptr, return nullptr, "Failed to GetUpgradeStatus.");
return retValue;
}
napi_value UpdateClient::ApplyNewVersion(napi_env env, napi_callback_info info)
{
napi_value retValue = StartSession(env, info, SESSION_APPLY_NEW_VERSION, 0,
[&](int32_t type, void *context) -> int {
result_ = UpdateServiceKits::GetInstance().RebootAndInstall(MISC_FILE, UPDATER_PKG_NAME);
return result_;
});
CLIENT_CHECK(retValue != nullptr, return nullptr, "Failed to GetNewVersionInfo.");
return retValue;
}
napi_value UpdateClient::RebootAndClean(napi_env env, napi_callback_info info)
{
napi_value retValue = StartSession(env, info, SESSION_REBOOT_AND_CLEAN, 0,
[&](int32_t type, void *context) -> int {
result_ = UpdateServiceKits::GetInstance().RebootAndClean(MISC_FILE, UPDATER_PKG_NAME);
return result_;
});
CLIENT_CHECK(retValue != nullptr, return nullptr, "Failed to GetNewVersionInfo.");
return retValue;
}
napi_value UpdateClient::VerifyUpdatePackage(napi_env env, napi_callback_info info)
{
size_t argc = MAX_ARGC;
napi_value args[MAX_ARGC] = {0};
napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info");
CLIENT_CHECK_NAPI_CALL(env, argc >= MID_ARGC, return nullptr, "Error get cb info");
int ret = GetStringValue(env, args[0], upgradeFile_);
CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Error get upgradeType");
ret = GetStringValue(env, args[1], certsFile_);
CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Error get certsFile");
CLIENT_LOGE("VerifyUpdatePackage");
std::shared_ptr<UpdateSession> sess = nullptr;
sess = std::make_shared<UpdateAsyncessionNoCallback>(this, SESSION_VERIFY_PACKAGE, argc, 0);
CLIENT_CHECK_NAPI_CALL(env, sess != nullptr, return nullptr, "Fail to create update session");
AddSession(sess);
size_t startIndex = 2;
napi_value retValue = sess->StartWork(env, startIndex, args,
[&](int32_t type, void *context) -> int {
CLIENT_LOGE("StartWork VerifyUpdatePackage");
result_ = VerifyPackageWithCallback(upgradeFile_, certsFile_,
[&](int32_t result, uint32_t percent) { NotifyVerifyProgresss(result, percent); });
return result_;
},
nullptr);
CLIENT_CHECK(retValue != nullptr, RemoveSession(sess->GetSessionId()); return nullptr, "Failed to start worker.");
return retValue;
}
napi_value UpdateClient::SubscribeEvent(napi_env env, napi_callback_info info)
{
size_t argc = MAX_ARGC;
napi_value args[MAX_ARGC] = {0};
napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info");
// Two arguments are required: type + callback.
CLIENT_CHECK_NAPI_CALL(env, argc >= MID_ARGC, return nullptr, "Invalid param");
std::string eventType;
int ret = UpdateClient::GetStringValue(env, args[0], eventType);
CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Failed to get event type");
CLIENT_CHECK(FindSessionByHandle(env, eventType, args[1]) == nullptr, return nullptr, "Handle has been sub");
std::shared_ptr<UpdateSession> sess = std::make_shared<UpdateListener>(this, SESSION_SUBSCRIBE, argc, 1, false);
CLIENT_CHECK_NAPI_CALL(env, sess != nullptr, return nullptr, "Failed to create listener");
AddSession(sess);
napi_value retValue = sess->StartWork(env, 1, args,
[&](int32_t type, void *context) -> int {
return 0;
}, nullptr);
CLIENT_CHECK(retValue != nullptr, RemoveSession(sess->GetSessionId()); return nullptr, "Failed to SubscribeEvent.");
return retValue;
}
napi_value UpdateClient::UnsubscribeEvent(napi_env env, napi_callback_info info)
{
size_t argc = MAX_ARGC;
napi_value args[MAX_ARGC] = {0};
napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info");
std::string eventType;
int ret = UpdateClient::GetStringValue(env, args[0], eventType);
CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Failed to get event type");
CLIENT_LOGI("UnsubscribeEvent %s argc %d", eventType.c_str(), argc);
if (argc >= MID_ARGC) {
napi_valuetype valuetype;
napi_status status = napi_typeof(env, args[1], &valuetype);
CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to napi_typeof");
CLIENT_CHECK_NAPI_CALL(env, valuetype == napi_function, return nullptr, "Invalid callback type");
}
ret = ProcessUnsubscribe(eventType, argc, args[1]);
napi_value result;
napi_create_int32(env, ret, &result);
return result;
}
int32_t UpdateClient::ProcessUnsubscribe(const std::string &eventType, size_t argc, napi_value arg)
{
napi_handle_scope scope;
napi_status status = napi_open_handle_scope(env_, &scope);
CLIENT_CHECK(status == napi_ok, return -1, "Error open handle");
uint32_t nextSessId = 0;
bool hasNext = GetFirstSessionId(nextSessId);
while (hasNext) {
uint32_t currSessId = nextSessId;
auto iter = sessions_.find(currSessId);
if (iter == sessions_.end()) {
break;
}
hasNext = GetNextSessionId(nextSessId);
UpdateListener *listener = static_cast<UpdateListener *>(iter->second.get());
if (listener->GetType() != SESSION_SUBSCRIBE
|| eventType.compare(listener->GetEventType()) != 0) {
continue;
}
CLIENT_LOGI("ProcessUnsubscribe remove session");
if (argc == 1) {
listener->RemoveHandlerRef(env_);
RemoveSession(currSessId);
} else if (listener->CheckEqual(env_, arg, eventType)) {
listener->RemoveHandlerRef(env_);
RemoveSession(currSessId);
break;
}
}
napi_close_handle_scope(env_, scope);
return 0;
}
UpdateSession *UpdateClient::FindSessionByHandle(napi_env env, const std::string &eventType, napi_value arg)
{
uint32_t nextSessId = 0;
bool hasNext = GetFirstSessionId(nextSessId);
while (hasNext) {
uint32_t currSessId = nextSessId;
auto iter = sessions_.find(currSessId);
if (iter == sessions_.end()) {
break;
}
hasNext = GetNextSessionId(nextSessId);
UpdateListener *listener = static_cast<UpdateListener *>(iter->second.get());
if (listener->GetType() != SESSION_SUBSCRIBE) {
continue;
}
if ((eventType.compare(listener->GetEventType()) == 0) && listener->CheckEqual(env_, arg, eventType)) {
return listener;
}
}
return nullptr;
}
bool UpdateClient::GetNextSessionId(uint32_t &sessionId)
{
std::lock_guard<std::mutex> guard(sessionMutex_);
{
auto iter = sessions_.find(sessionId);
if (iter == sessions_.end()) {
return false;
}
iter++;
if (iter == sessions_.end()) {
return false;
}
sessionId = iter->second->GetSessionId();
}
return true;
}
bool UpdateClient::GetFirstSessionId(uint32_t &sessionId)
{
std::lock_guard<std::mutex> guard(sessionMutex_);
{
if (sessions_.empty()) {
return false;
}
sessionId = sessions_.begin()->second->GetSessionId();
return true;
}
}
void UpdateClient::Emit(const std::string &type, int32_t retcode, const UpdateResult &result)
{
napi_handle_scope scope;
napi_status status = napi_open_handle_scope(env_, &scope);
CLIENT_CHECK_NAPI_CALL(env_, status == napi_ok, return, "Error open_handle_scope");
napi_value thisVar = nullptr;
status = napi_get_reference_value(env_, thisReference_, &thisVar);
CLIENT_CHECK_NAPI_CALL(env_, status == napi_ok, return, "Error get_reference");
uint32_t nextSessId = 0;
bool hasNext = GetFirstSessionId(nextSessId);
while (hasNext) {
uint32_t currSessId = nextSessId;
auto iter = sessions_.find(currSessId);
if (iter == sessions_.end()) {
break;
}
hasNext = GetNextSessionId(nextSessId);
UpdateListener *listener = static_cast<UpdateListener *>((iter->second).get());
if ((listener->GetType() != SESSION_SUBSCRIBE) || (type.compare(listener->GetEventType()) != 0)) {
continue;
}
listener->NotifyJS(env_, thisVar, retcode, result);
iter = sessions_.find(currSessId);
if (iter == sessions_.end()) {
continue;
}
listener = static_cast<UpdateListener *>((iter->second).get());
if (listener->IsOnce()) {
listener->RemoveHandlerRef(env_);
RemoveSession(currSessId);
}
}
napi_close_handle_scope(env_, scope);
}
void UpdateClient::NotifyDownloadProgress(const Progress &progress)
{
CLIENT_LOGI("NotifyDownloadProgress status %d %d", progress.status, progress.percent);
if (progress.percent == PROGRESS_DOWNLOAD_FINISH && progress.status == UPDATE_STATE_DOWNLOAD_ON) {
return;
}
progress_.percent = progress.percent;
progress_.status = progress.status;
progress_.endReason = progress.endReason;
UpdateResult result;
result.type = SESSION_DOWNLOAD;
result.result.progress = &progress_;
result.buildJSObject = BuildProgress;
int32_t fail = (progress_.status == UPDATE_STATE_DOWNLOAD_FAIL || progress_.status == UPDATE_STATE_VERIFY_FAIL) ?
progress_.status : 0;
Emit("downloadProgress", fail, result);
}
void UpdateClient::NotifyUpgradeProgresss(const Progress &progress)
{
CLIENT_LOGI("NotifyUpgradeProgresss status %d %d", progress.status, progress.percent);
progress_.percent = progress.percent;
progress_.status = progress.status;
UpdateResult result;
result.type = SESSION_UPGRADE;
result.result.progress = &progress_;
result.buildJSObject = BuildProgress;
int32_t fail = (progress_.status == UPDATE_STATE_DOWNLOAD_FAIL) ? progress_.status : 0;
Emit("upgradeProgress", fail, result);
}
void UpdateClient::NotifyVerifyProgresss(int32_t retCode, uint32_t percent)
{
verifyProgress_.status = (retCode == 0) ? UPDATE_STATE_VERIFY_SUCCESS : UPDATE_STATE_VERIFY_FAIL;
verifyProgress_.percent = percent;
UpdateResult result;
result.type = SESSION_VERIFY_PACKAGE;
result.result.progress = &verifyProgress_;
result.buildJSObject = BuildProgress;
Emit("verifyProgress", retCode, result);
}
void UpdateClient::NotifyCheckVersionDone(const VersionInfo &info)
{
CLIENT_LOGE("NotifyCheckVersionDone status %d", info.status);
CLIENT_LOGE("NotifyCheckVersionDone errMsg %s", info.errMsg.c_str());
CLIENT_LOGE("NotifyCheckVersionDone versionName : %s", info.result[0].versionName.c_str());
CLIENT_LOGE("NotifyCheckVersionDone versionCode : %s", info.result[0].versionCode.c_str());
CLIENT_LOGE("NotifyCheckVersionDone verifyInfo : %s", info.result[0].verifyInfo.c_str());
CLIENT_LOGE("NotifyCheckVersionDone size : %zu", info.result[0].size);
CLIENT_LOGE("NotifyCheckVersionDone content : %s", info.descriptInfo[0].content.c_str());
UpdateHelper::CopyVersionInfo(info, versionInfo_);
}
int32_t UpdateClient::GetInt32(napi_env env, napi_value arg, const std::string &attrName, int32_t &intValue)
{
bool result = false;
napi_status status = napi_has_named_property(env, arg, attrName.c_str(), &result);
if (result && (status == napi_ok)) {
napi_value value;
napi_get_named_property(env, arg, attrName.c_str(), &value);
napi_get_value_int32(env, value, &intValue);
}
return CLIENT_SUCCESS;
}
int32_t UpdateClient::GetBool(napi_env env, napi_value arg, const std::string &attrName, bool &value)
{
bool result = false;
napi_status status = napi_has_named_property(env, arg, attrName.c_str(), &result);
if (result && (status == napi_ok)) {
napi_value obj;
napi_get_named_property(env, arg, attrName.c_str(), &obj);
napi_get_value_bool(env, obj, &value);
}
return CLIENT_SUCCESS;
}
int32_t UpdateClient::GetStringValue(napi_env env, napi_value arg, std::string &strValue)
{
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_string, return CLIENT_INVALID_TYPE, "Invalid type");
std::vector<char> buff(CLIENT_STRING_MAX_LENGTH);
size_t copied;
status = napi_get_value_string_utf8(env, arg, (char*)buff.data(), CLIENT_STRING_MAX_LENGTH, &copied);
CLIENT_CHECK(status == napi_ok, return CLIENT_INVALID_TYPE, "Error get string");
strValue.assign(buff.data(), copied);
return napi_ok;
}
int32_t UpdateClient::SetString(napi_env env, napi_value arg, const std::string &attrName, const std::string &string)
{
napi_value value;
napi_create_string_utf8(env, string.c_str(), string.length(), &value);
napi_set_named_property(env, arg, attrName.c_str(), value);
return CLIENT_SUCCESS;
}
int32_t UpdateClient::SetInt32(napi_env env, napi_value arg, const std::string &attrName, int32_t intValue)
{
napi_value infoStatus;
napi_create_int32(env, intValue, &infoStatus);
napi_set_named_property(env, arg, attrName.c_str(), infoStatus);
return CLIENT_SUCCESS;
}
int32_t UpdateClient::SetBool(napi_env env, napi_value arg, const std::string &attrName, bool value)
{
napi_value infoStatus;
napi_create_int32(env, value, &infoStatus);
napi_set_named_property(env, arg, attrName.c_str(), infoStatus);
return CLIENT_SUCCESS;
}
int32_t UpdateClient::SetInt64(napi_env env, napi_value arg, const std::string &attrName, int64_t intValue)
{
napi_value infoStatus;
napi_create_int64(env, intValue, &infoStatus);
napi_set_named_property(env, arg, attrName.c_str(), infoStatus);
return CLIENT_SUCCESS;
}
int32_t UpdateClient::GetUpdatePolicyFromArg(napi_env env,
const napi_value arg, UpdatePolicy &updatePolicy) const
{
napi_valuetype type = napi_undefined;
napi_status status = napi_typeof(env, arg, &type);
CLIENT_CHECK(status == napi_ok, return CLIENT_INVALID_TYPE, "Invlid argc %d", static_cast<int32_t>(status));
CLIENT_CHECK(type == napi_object, return CLIENT_INVALID_TYPE, "Invlid argc %d", static_cast<int32_t>(type));
// updatePolicy
int32_t tmpValue = 0;
int32_t ret = GetBool(env, arg, "autoDownload", updatePolicy.autoDownload);
ret |= GetBool(env, arg, "autoDownloadNet", updatePolicy.autoDownloadNet);
ret |= GetInt32(env, arg, "mode", tmpValue);
updatePolicy.mode = static_cast<InstallMode>(tmpValue);
CLIENT_CHECK(ret == 0, return CLIENT_INVALID_TYPE, "Failed to get attr ");
// Get the array.
bool result = false;
status = napi_has_named_property(env, arg, "autoUpgradeInterval", &result);
if (result && (status == napi_ok)) {
napi_value value;
status = napi_get_named_property(env, arg, "autoUpgradeInterval", &value);
CLIENT_CHECK(status == napi_ok, return CLIENT_FAIL, "Failed to get attr autoUpgradeInterval");
status = napi_is_array(env, value, &result);
CLIENT_CHECK(status == napi_ok, return CLIENT_FAIL, "napi_is_array failed");
uint32_t count = 0;
status = napi_get_array_length(env, value, &count);
CLIENT_CHECK(status == napi_ok, return CLIENT_FAIL, "napi_get_array_length failed");
uint32_t i = 0;
do {
napi_value element;
ret = napi_get_element(env, value, i, &element);
ret = napi_get_value_uint32(env, element, &updatePolicy.autoUpgradeInterval[i]);
CLIENT_LOGI("updatePolicy autoUpgradeInterval%u ", updatePolicy.autoUpgradeInterval[i]);
if (i >= sizeof(updatePolicy.autoUpgradeInterval) / sizeof(updatePolicy.autoUpgradeInterval[0])) {
break;
}
i++;
} while (i < count);
}
ret |= GetInt32(env, arg, "autoUpgradeCondition", tmpValue);
CLIENT_CHECK(ret == 0, return CLIENT_INVALID_TYPE, "Failed to get attr autoUpgradeCondition");
updatePolicy.autoUpgradeCondition = static_cast<AutoUpgradeCondition>(tmpValue);
CLIENT_LOGI("updatePolicy autoDownload%d autoDownloadNet:%d mode:%d autoUpgradeCondition:%d",
static_cast<int32_t>(updatePolicy.autoDownload),
static_cast<int32_t>(updatePolicy.autoDownloadNet),
static_cast<int32_t>(updatePolicy.mode),
static_cast<int32_t>(updatePolicy.autoUpgradeCondition));
return CLIENT_SUCCESS;
}
int32_t UpdateClient::BuildCheckVersionResult(napi_env env, napi_value &obj, const UpdateResult &result)
{
CLIENT_CHECK(result.type == SESSION_CHECK_VERSION || result.type == SESSION_GET_NEW_VERSION,
return CLIENT_INVALID_TYPE, "invalid type %d", result.type);
napi_status status = napi_create_object(env, &obj);
CLIENT_CHECK(status == napi_ok, return CLIENT_INVALID_TYPE,
"Failed to create napi_create_object %d", static_cast<int32_t>(status));
VersionInfo *info = result.result.versionInfo;
// Add the result.
int32_t ret = SetInt32(env, obj, "status", info->status);
if (info->status == SERVER_BUSY || info->status == SYSTEM_ERROR) {
ret = SetString(env, obj, "errMsg", info->errMsg);
return ret;
}
napi_value checkResults;
napi_create_array_with_length(env, sizeof(info->result) / sizeof(info->result[0]), &checkResults);
for (size_t i = 0; i < sizeof(info->result) / sizeof(info->result[0]); i++) {
napi_value result;
status = napi_create_object(env, &result);
ret |= SetString(env, result, "versionName", info->result[i].versionName);
ret |= SetString(env, result, "versionCode", info->result[i].versionCode);
ret |= SetString(env, result, "verifyInfo", info->result[i].verifyInfo);
ret |= SetString(env, result, "descriptionId", info->result[i].descriptPackageId);
ret |= SetInt64(env, result, "size", info->result[i].size);
ret |= SetInt32(env, result, "packageType", info->result[i].packageType);
napi_set_element(env, checkResults, i, result);
}
napi_set_named_property(env, obj, "checkResults", checkResults);
napi_value descriptInfos;
napi_create_array_with_length(env, sizeof(info->descriptInfo) / sizeof(info->descriptInfo[0]), &descriptInfos);
for (size_t i = 0; i < sizeof(info->descriptInfo) / sizeof(info->descriptInfo[0]); i++) {
napi_value descriptInfo;
status = napi_create_object(env, &descriptInfo);
ret |= SetString(env, descriptInfo, "descriptionId", info->descriptInfo[i].descriptPackageId);
ret |= SetString(env, descriptInfo, "content", info->descriptInfo[i].content);
napi_set_element(env, descriptInfos, i, descriptInfo);
}
napi_set_named_property(env, obj, "descriptionInfo", descriptInfos);
return CLIENT_SUCCESS;
}
int32_t UpdateClient::BuildProgress(napi_env env, napi_value &obj, const UpdateResult &result)
{
napi_status status = napi_create_object(env, &obj);
CLIENT_CHECK(status == napi_ok, return CLIENT_INVALID_TYPE,
"Failed to create napi_create_object %d", static_cast<int32_t>(status));
int32_t ret = SetInt32(env, obj, "status", result.result.progress->status);
ret |= SetInt32(env, obj, "percent", result.result.progress->percent);
ret |= SetString(env, obj, "endReason", result.result.progress->endReason);
return CLIENT_SUCCESS;
}
int32_t UpdateClient::BuildErrorResult(napi_env env, napi_value &obj, int32_t result)
{
napi_status status = napi_create_object(env, &obj);
CLIENT_CHECK(status == napi_ok, return CLIENT_INVALID_TYPE,
"Failed to create napi_create_object %d", static_cast<int32_t>(status));
return SetInt32(env, obj, "code", result);
}
int32_t UpdateClient::BuildInt32Status(napi_env env, napi_value &obj, const UpdateResult &result)
{
return napi_create_int32(env, result.result.status, &obj);
}
int32_t UpdateClient::BuildUpdatePolicy(napi_env env, napi_value &obj, const UpdateResult &result)
{
CLIENT_CHECK(result.type == SESSION_GET_POLICY || result.type == SESSION_SET_POLICY,
return CLIENT_INVALID_TYPE, "invalid type %d", result.type);
napi_status status = napi_create_object(env, &obj);
CLIENT_CHECK(status == napi_ok, return status, "Failed to create napi_create_object %d", status);
UpdatePolicy &updatePolicy = *result.result.updatePolicy;
// Add the result.
int32_t ret = SetBool(env, obj, "autoDownload", updatePolicy.autoDownload);
ret |= SetBool(env, obj, "autoDownloadNet", updatePolicy.autoDownloadNet);
ret |= SetInt32(env, obj, "mode", static_cast<int32_t>(updatePolicy.mode));
CLIENT_CHECK(ret == napi_ok, return ret, "Failed to add value %d", ret);
napi_value autoUpgradeInterval;
size_t count = sizeof(updatePolicy.autoUpgradeInterval) / sizeof(updatePolicy.autoUpgradeInterval[0]);
status = napi_create_array_with_length(env, count, &autoUpgradeInterval);
CLIENT_CHECK(status == napi_ok, return status, "Failed to create array for interval %d", status);
for (size_t i = 0; i < count; i++) {
napi_value interval;
status = napi_create_uint32(env, updatePolicy.autoUpgradeInterval[i], &interval);
status = napi_set_element(env, autoUpgradeInterval, i, interval);
CLIENT_CHECK(status == napi_ok, return status, "Failed to add interval to array %d", status);
}
status = napi_set_named_property(env, obj, "autoUpgradeInterval", autoUpgradeInterval);
CLIENT_CHECK(status == napi_ok, return status, "Failed to add autoUpgradeInterval %d", status);
ret |= SetInt32(env, obj, "autoUpgradeCondition", static_cast<int32_t>(updatePolicy.autoUpgradeCondition));
CLIENT_CHECK(ret == napi_ok, return ret, "Failed to add autoUpgradeCondition %d", ret);
return napi_ok;
}
int32_t UpdateClient::GetUpdateResult(int type, UpdateResult &result, int32_t &fail)
{
fail = 0;
result.type = type;
switch (type) {
case SESSION_CHECK_VERSION:
case SESSION_GET_NEW_VERSION: {
fail = (versionInfo_.status == SYSTEM_ERROR) ? versionInfo_.status : 0;
result.result.versionInfo = &versionInfo_;
result.buildJSObject = BuildCheckVersionResult;
break;
}
case SESSION_DOWNLOAD: {
fail = (progress_.status == UPDATE_STATE_DOWNLOAD_FAIL || progress_.status == UPDATE_STATE_VERIFY_FAIL) ?
progress_.status : 0;
result.result.progress = &progress_;
result.buildJSObject = BuildProgress;
break;
}
case SESSION_UPGRADE: {
fail = (progress_.status == UPDATE_STATE_DOWNLOAD_FAIL) ? progress_.status : 0;
result.result.progress = &progress_;
result.buildJSObject = BuildProgress;
break;
}
case SESSION_VERIFY_PACKAGE: {
fail = (verifyProgress_.status == UPDATE_STATE_VERIFY_FAIL) ? verifyProgress_.status : 0;
result.result.progress = &verifyProgress_;
result.buildJSObject = BuildProgress;
break;
}
case SESSION_GET_POLICY: {
result.result.updatePolicy = &updatePolicy_;
result.buildJSObject = BuildUpdatePolicy;
break;
}
case SESSION_GET_STATUS: {
result.result.status = upgradeInfo_.status;
result.buildJSObject = BuildInt32Status;
break;
}
default:{
fail = result_;
result.result.status = result_;
result.buildJSObject = BuildInt32Status;
break;
}
}
return napi_ok;
}
} // namespace updateClient