1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "app_fwk_update_client.h"
17
18#include <fcntl.h>
19#include <string>
20#include <sys/ioctl.h>
21#include <sys/stat.h>
22#include <sys/types.h>
23#include <unistd.h>
24
25#include "app_fwk_update_load_callback.h"
26#include "if_system_ability_manager.h"
27#include "ipc_skeleton.h"
28#include "iservice_registry.h"
29#include "isystem_ability_load_callback.h"
30#include "nweb_log.h"
31#include "system_ability_definition.h"
32
33#include "base/web/webview/sa/app_fwk_update_service_proxy.h"
34#include "base/web/webview/sa/iapp_fwk_update_service.h"
35
36namespace OHOS::NWeb {
37namespace {
38const int LOAD_SA_TIMEOUT_MS = 2 * 1000;
39const int FOUNDATION_UID = 5523;
40const std::set<std::string> ARK_WEB_DEFAULT_BUNDLE_NAME_SET = { "com.ohos.nweb", "com.ohos.arkwebcore" };
41} // namespace
42
43AppFwkUpdateClient::AppFwkUpdateClient()
44{
45    appFwkUpdateDiedRecipient_ = new (std::nothrow) AppFwkUpdateDiedRecipient();
46    if (appFwkUpdateDiedRecipient_ == nullptr) {
47        WVLOG_I("create fwk update service died recipient failed");
48    }
49}
50
51AppFwkUpdateClient& AppFwkUpdateClient::GetInstance()
52{
53    static AppFwkUpdateClient singleAppFwkUpdateClient;
54    return singleAppFwkUpdateClient;
55}
56void AppFwkUpdateClient::SetFwkUpdate(const sptr<IRemoteObject>& remoteObject)
57{
58    std::lock_guard<std::mutex> lock(mutex_);
59    fwkUpdateProxy_ = iface_cast<IAppFwkUpdateService>(remoteObject);
60    if (fwkUpdateProxy_) {
61        WVLOG_I("SetFwkUpdate is not null");
62    }
63}
64
65sptr<IAppFwkUpdateService> AppFwkUpdateClient::GetFwkUpdate()
66{
67    std::lock_guard<std::mutex> lock(mutex_);
68    return fwkUpdateProxy_;
69}
70
71sptr<IAppFwkUpdateService> AppFwkUpdateClient::GetFwkUpdateProxy()
72{
73    auto fwkUpdateProxy = GetFwkUpdate();
74    if (fwkUpdateProxy != nullptr) {
75        return fwkUpdateProxy;
76    }
77    auto sam = OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
78    if (sam == nullptr) {
79        WVLOG_E("load fwk service sam is null");
80        return {};
81    }
82
83    auto remoteObj = sam->CheckSystemAbility(SUBSYS_WEBVIEW_SYS_UPDATE_SERVICE_ID);
84    if (remoteObj != nullptr) {
85        fwkUpdateProxy = iface_cast<IAppFwkUpdateService>(remoteObj);
86        return fwkUpdateProxy;
87    }
88    if (!LoadFwkService()) {
89        WVLOG_I("get fwk update service is null");
90        return nullptr;
91    }
92    fwkUpdateProxy = GetFwkUpdate();
93    if (fwkUpdateProxy == nullptr) {
94        WVLOG_I("get fwk update service proxy is null");
95        return nullptr;
96    }
97    WVLOG_I("load fwk service sa finished");
98    return fwkUpdateProxy;
99}
100
101int AppFwkUpdateClient::VerifyPackageInstall(const std::string& bundleName, const std::string& hapPath)
102{
103    WVLOG_I("verify package install callingUid: %{public}d", IPCSkeleton::GetCallingUid());
104    if (IPCSkeleton::GetCallingUid() != FOUNDATION_UID) {
105        return -1;
106    }
107    if (!ARK_WEB_DEFAULT_BUNDLE_NAME_SET.count(bundleName)) {
108        WVLOG_I("bundle name is not nweb.");
109        return 0;
110    }
111
112    auto proxy = GetFwkUpdateProxy();
113    if (proxy == nullptr) {
114        WVLOG_E("verify package install failed, proxy is null");
115        return -1;
116    }
117    int32_t isSuccess = -1;
118    proxy->VerifyPackageInstall(bundleName, hapPath, isSuccess);
119    WVLOG_I("verify package install result: %{public}d", isSuccess);
120    return isSuccess;
121}
122
123bool AppFwkUpdateClient::LoadFwkService()
124{
125    {
126        std::unique_lock<std::mutex> lock(loadSaMutex_);
127        loadSaFinished_ = false;
128    }
129    auto systemAbilityMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
130    if (systemAbilityMgr == nullptr) {
131        WVLOG_I("failed to get system ability manager");
132        return false;
133    }
134    sptr<AppFwkUpdateLoadCallback> loadCallback = new (std::nothrow) AppFwkUpdateLoadCallback();
135    if (loadCallback == nullptr) {
136        WVLOG_I("failed to create load callback");
137        return false;
138    }
139    auto ret = systemAbilityMgr->LoadSystemAbility(SUBSYS_WEBVIEW_SYS_UPDATE_SERVICE_ID, loadCallback);
140    if (ret != 0) {
141        WVLOG_W("load fwk update service failed.");
142        return false;
143    }
144    {
145        std::unique_lock<std::mutex> lock(loadSaMutex_);
146        auto waitStatus = loadSaCondition_.wait_for(
147            lock, std::chrono::milliseconds(LOAD_SA_TIMEOUT_MS), [this]() { return loadSaFinished_; });
148        if (!waitStatus) {
149            WVLOG_I("load fwk service timeout.");
150            return false;
151        }
152        WVLOG_I("load fwk service success.");
153        return true;
154    }
155}
156
157void AppFwkUpdateClient::OnLoadSystemAbilitySuccess(const sptr<IRemoteObject>& remoteObject)
158{
159    WVLOG_I("on load systemAbility success");
160    if (appFwkUpdateDiedRecipient_ == nullptr) {
161        WVLOG_E("register fwk update service died recipient failed");
162        return;
163    }
164    if (!remoteObject->AddDeathRecipient(appFwkUpdateDiedRecipient_)) {
165        WVLOG_E("add fwk update service died recipient failed");
166        return;
167    }
168    SetFwkUpdate(remoteObject);
169    std::unique_lock<std::mutex> lock(loadSaMutex_);
170    loadSaFinished_ = true;
171    loadSaCondition_.notify_one();
172}
173
174void AppFwkUpdateClient::OnLoadSystemAbilityFail()
175{
176    SetFwkUpdate(nullptr);
177    std::unique_lock<std::mutex> lock(loadSaMutex_);
178    loadSaFinished_ = true;
179    loadSaCondition_.notify_one();
180}
181
182void AppFwkUpdateClient::AppFwkUpdateDiedRecipient::OnRemoteDied(const wptr<IRemoteObject>& remoteObject)
183{
184    if (remoteObject == nullptr) {
185        WVLOG_E("remote object of fwk update service died recipient is nullptr");
186        return;
187    }
188    AppFwkUpdateClient::GetInstance().AppFwkUpdateOnRemoteDied(remoteObject);
189}
190
191void AppFwkUpdateClient::AppFwkUpdateOnRemoteDied(const wptr<IRemoteObject>& remoteObject)
192{
193    WVLOG_I("remote object of fwk update service died recipient is died");
194    auto fwkUpdateProxy = GetFwkUpdate();
195    if (fwkUpdateProxy == nullptr) {
196        WVLOG_E("app fwk update proxy is nullptr");
197        return;
198    }
199    sptr<IRemoteObject> remotePromote = remoteObject.promote();
200    if (remotePromote == nullptr) {
201        WVLOG_E("remote object of fwk update service promote fail");
202        return;
203    }
204    if (fwkUpdateProxy->AsObject() != remotePromote) {
205        WVLOG_E("app fwk update died recipient not find remote object");
206        return;
207    }
208    remotePromote->RemoveDeathRecipient(appFwkUpdateDiedRecipient_);
209    SetFwkUpdate(nullptr);
210}
211} // namespace OHOS::NWeb
212