* Copyright (c) 2024 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 "app_fwk_update_client.h"
#include <fcntl.h>
#include <string>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "app_fwk_update_load_callback.h"
#include "if_system_ability_manager.h"
#include "ipc_skeleton.h"
#include "iservice_registry.h"
#include "isystem_ability_load_callback.h"
#include "nweb_log.h"
#include "system_ability_definition.h"
#include "base/web/webview/sa/app_fwk_update/app_fwk_update_service_proxy.h"
#include "base/web/webview/sa/app_fwk_update/iapp_fwk_update_service.h"
namespace OHOS::NWeb {
namespace {
const int LOAD_SA_TIMEOUT_MS = 4 * 1000;
const int FOUNDATION_UID = 5523;
const std::set<std::string> ARK_WEB_DEFAULT_BUNDLE_NAME_SET = { "com.ohos.nweb", "com.ohos.arkwebcore" };
}
AppFwkUpdateClient::AppFwkUpdateClient()
{
appFwkUpdateDiedRecipient_ = new (std::nothrow) AppFwkUpdateDiedRecipient();
if (appFwkUpdateDiedRecipient_ == nullptr) {
WVLOG_I("create fwk update service died recipient failed");
}
}
AppFwkUpdateClient& AppFwkUpdateClient::GetInstance()
{
static AppFwkUpdateClient singleAppFwkUpdateClient;
return singleAppFwkUpdateClient;
}
void AppFwkUpdateClient::SetFwkUpdate(const sptr<IRemoteObject>& remoteObject)
{
std::lock_guard<std::mutex> lock(mutex_);
fwkUpdateProxy_ = iface_cast<IAppFwkUpdateService>(remoteObject);
if (fwkUpdateProxy_) {
WVLOG_I("SetFwkUpdate is not null");
}
}
sptr<IAppFwkUpdateService> AppFwkUpdateClient::GetFwkUpdate()
{
std::lock_guard<std::mutex> lock(mutex_);
return fwkUpdateProxy_;
}
sptr<IAppFwkUpdateService> AppFwkUpdateClient::GetFwkUpdateProxy()
{
auto fwkUpdateProxy = GetFwkUpdate();
if (fwkUpdateProxy != nullptr) {
return fwkUpdateProxy;
}
auto sam = OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (sam == nullptr) {
WVLOG_E("load fwk service sam is null");
return {};
}
auto remoteObj = sam->CheckSystemAbility(SUBSYS_WEBVIEW_SYS_UPDATE_SERVICE_ID);
if (remoteObj != nullptr) {
fwkUpdateProxy = iface_cast<IAppFwkUpdateService>(remoteObj);
return fwkUpdateProxy;
}
if (!LoadFwkService()) {
WVLOG_I("get fwk update service is null");
return nullptr;
}
fwkUpdateProxy = GetFwkUpdate();
if (fwkUpdateProxy == nullptr) {
WVLOG_I("get fwk update service proxy is null");
return nullptr;
}
WVLOG_I("load fwk service sa finished");
return fwkUpdateProxy;
}
int AppFwkUpdateClient::NotifyFWKAfterBmsStart()
{
WVLOG_I("NotifyFWKAfterBmsStart received message");
auto proxy = GetFwkUpdateProxy();
if (proxy == nullptr) {
WVLOG_E("NotifyFWKAfterBmsStart failed, proxy is null");
return -1;
}
return proxy->NotifyFWKAfterBmsStart();
}
void AppFwkUpdateClient::NotifyArkWebInstallSuccess()
{
auto proxy = GetFwkUpdateProxy();
if (proxy == nullptr) {
WVLOG_E("NotifyArkWebInstallSuccess failed, proxy is null");
return;
}
proxy->NotifyArkWebInstallSuccess();
}
int AppFwkUpdateClient::VerifyPackageInstall(const std::string& bundleName, const std::string& hapPath)
{
WVLOG_I("verify package install callingUid: %{public}d", IPCSkeleton::GetCallingUid());
if (IPCSkeleton::GetCallingUid() != FOUNDATION_UID) {
return -1;
}
if (!ARK_WEB_DEFAULT_BUNDLE_NAME_SET.count(bundleName)) {
WVLOG_I("bundle name is not nweb.");
return 0;
}
auto proxy = GetFwkUpdateProxy();
if (proxy == nullptr) {
WVLOG_E("verify package install failed, proxy is null");
return -1;
}
int32_t isSuccess = -1;
proxy->VerifyPackageInstall(bundleName, hapPath, isSuccess);
WVLOG_I("verify package install result: %{public}d", isSuccess);
return isSuccess;
}
bool AppFwkUpdateClient::LoadFwkService()
{
{
std::unique_lock<std::mutex> lock(loadSaMutex_);
loadSaFinished_ = false;
}
auto systemAbilityMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (systemAbilityMgr == nullptr) {
WVLOG_I("failed to get system ability manager");
return false;
}
sptr<AppFwkUpdateLoadCallback> loadCallback = new (std::nothrow) AppFwkUpdateLoadCallback();
if (loadCallback == nullptr) {
WVLOG_I("failed to create load callback");
return false;
}
auto ret = systemAbilityMgr->LoadSystemAbility(SUBSYS_WEBVIEW_SYS_UPDATE_SERVICE_ID, loadCallback);
if (ret != 0) {
WVLOG_W("load fwk update service failed.");
return false;
}
{
std::unique_lock<std::mutex> lock(loadSaMutex_);
auto waitStatus = loadSaCondition_.wait_for(
lock, std::chrono::milliseconds(LOAD_SA_TIMEOUT_MS), [this]() { return loadSaFinished_; });
if (!waitStatus) {
auto remoteObj = systemAbilityMgr->CheckSystemAbility(SUBSYS_WEBVIEW_SYS_UPDATE_SERVICE_ID);
if (remoteObj != nullptr) {
SetFwkUpdate(remoteObj);
return true;
}
WVLOG_I("load fwk service timeout.");
return false;
}
WVLOG_I("load fwk service success.");
return true;
}
}
void AppFwkUpdateClient::OnLoadSystemAbilitySuccess(const sptr<IRemoteObject>& remoteObject)
{
WVLOG_I("on load systemAbility success");
if (appFwkUpdateDiedRecipient_ == nullptr) {
WVLOG_E("register fwk update service died recipient failed");
return;
}
if (!remoteObject->AddDeathRecipient(appFwkUpdateDiedRecipient_)) {
WVLOG_E("add fwk update service died recipient failed");
return;
}
SetFwkUpdate(remoteObject);
std::unique_lock<std::mutex> lock(loadSaMutex_);
loadSaFinished_ = true;
loadSaCondition_.notify_one();
}
void AppFwkUpdateClient::OnLoadSystemAbilityFail()
{
SetFwkUpdate(nullptr);
std::unique_lock<std::mutex> lock(loadSaMutex_);
loadSaFinished_ = true;
loadSaCondition_.notify_one();
}
void AppFwkUpdateClient::AppFwkUpdateDiedRecipient::OnRemoteDied(const wptr<IRemoteObject>& remoteObject)
{
if (remoteObject == nullptr) {
WVLOG_E("remote object of fwk update service died recipient is nullptr");
return;
}
AppFwkUpdateClient::GetInstance().AppFwkUpdateOnRemoteDied(remoteObject);
}
void AppFwkUpdateClient::AppFwkUpdateOnRemoteDied(const wptr<IRemoteObject>& remoteObject)
{
WVLOG_I("remote object of fwk update service died recipient is died");
auto fwkUpdateProxy = GetFwkUpdate();
if (fwkUpdateProxy == nullptr) {
WVLOG_E("app fwk update proxy is nullptr");
return;
}
sptr<IRemoteObject> remotePromote = remoteObject.promote();
if (remotePromote == nullptr) {
WVLOG_E("remote object of fwk update service promote fail");
return;
}
if (fwkUpdateProxy->AsObject() != remotePromote) {
WVLOG_E("app fwk update died recipient not find remote object");
return;
}
remotePromote->RemoveDeathRecipient(appFwkUpdateDiedRecipient_);
SetFwkUpdate(nullptr);
}
}