1 /*
2 * Copyright (c) 2023 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 "page_url_checker_ohos.h"
17
18 #include "ability_runtime/context/context.h"
19 #include "app_mgr_client.h"
20 #include "iremote_stub.h"
21 #include "iservice_registry.h"
22 #include "singleton.h"
23 #include "system_ability_definition.h"
24
25 namespace OHOS::Ace {
26 const char BUNDLE_TAG[] = "@bundle:";
27 constexpr size_t BUNDLE_START_POS = 8;
28 constexpr int32_t SILENT_INSTALL_SUCCESS = 0;
29
30 /**
31 * @class IAtomicServiceStatusCallback
32 * IAtomicServiceStatusCallback is used to notify caller ability that free install is complete.
33 */
34 class IAtomicServiceStatusCallback : public IRemoteBroker {
35 public:
36 DECLARE_INTERFACE_DESCRIPTOR(u"ohos.IAtomicServiceStatusCallback");
37
38 /**
39 * @brief OnActionEvent.
40 */
41 virtual int32_t OnActionEvent() = 0;
42 /**
43 * @brief OnError.
44 * @param code The code.
45 * @param msg The msg.
46 */
47 virtual int32_t OnError(int32_t code, const std::string& msg) = 0;
48 };
49
50 /**
51 * @class AtomicServiceStatusCallbackStub
52 * AtomicServiceStatusCallbackStub.
53 */
54 class AtomicServiceStatusCallbackStub : public IRemoteStub<IAtomicServiceStatusCallback> {
55 public:
AtomicServiceStatusCallbackStub()56 AtomicServiceStatusCallbackStub()
57 {
58 handleOnActionEventFunc_ = &AtomicServiceStatusCallbackStub::HandleOnActionEvent;
59 handleOnErrorFunc_ = &AtomicServiceStatusCallbackStub::HandleOnError;
60 }
61 ~AtomicServiceStatusCallbackStub() override
62 {
63 handleOnActionEventFunc_ = nullptr;
64 handleOnErrorFunc_ = nullptr;
65 }
66
67 int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override
68 {
69 TAG_LOGI(AceLogTag::ACE_ROUTER,
70 "AtomicServiceStatusCallbackStub::OnReceived,code = %{public}u, flags= %{public}d.", code,
71 option.GetFlags());
72 std::u16string descriptor = AtomicServiceStatusCallbackStub::GetDescriptor();
73 std::u16string remoteDescriptor = data.ReadInterfaceToken();
74 if (descriptor != remoteDescriptor) {
75 TAG_LOGE(AceLogTag::ACE_ROUTER, "%{public}s failed, local descriptor is not equal to remote", __func__);
76 return ERR_INVALID_VALUE;
77 }
78
79 auto resultCode = data.ReadInt32();
80 if (resultCode == SILENT_INSTALL_SUCCESS) {
81 if (handleOnActionEventFunc_ != nullptr) {
82 return (this->*handleOnActionEventFunc_)();
83 }
84 }
85
86 if (resultCode < SILENT_INSTALL_SUCCESS) {
87 if (handleOnErrorFunc_ != nullptr) {
88 return (this->*handleOnErrorFunc_)(data);
89 }
90 }
91
92 return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
93 }
94
95 private:
HandleOnActionEvent()96 int32_t HandleOnActionEvent()
97 {
98 return OnActionEvent();
99 }
HandleOnError(MessageParcel &data)100 int32_t HandleOnError(MessageParcel &data)
101 {
102 int32_t code = data.ReadInt32();
103 std::string msg = data.ReadString();
104 return OnError(code, msg);
105 }
106
107 using HandleOnActionEventFunc = int32_t (AtomicServiceStatusCallbackStub::*)();
108 HandleOnActionEventFunc handleOnActionEventFunc_;
109
110 using HandleOnErrorFunc = int32_t (AtomicServiceStatusCallbackStub::*)(MessageParcel &data);
111 HandleOnErrorFunc handleOnErrorFunc_;
112
113 DISALLOW_COPY_AND_MOVE(AtomicServiceStatusCallbackStub);
114 };
115
116 /**
117 * @class AtomicServiceStatusCallback
118 * AtomicServiceStatusCallback.
119 */
120 class AtomicServiceStatusCallback : public AtomicServiceStatusCallbackStub {
121 public:
122 AtomicServiceStatusCallback() = default;
123 ~AtomicServiceStatusCallback() override = default;
124
125 /**
126 * @brief OnActionEvent.
127 */
128 int32_t OnActionEvent() override
129 {
130 if (!actionEventHandler_) {
131 TAG_LOGE(AceLogTag::ACE_ROUTER, "actionEventHandler_ is null.");
132 return ERR_INVALID_VALUE;
133 }
134 actionEventHandler_();
135 return ERR_OK;
136 }
137 /**
138 * @brief OnError.
139 * @param code The code.
140 * @param msg The msg.
141 */
142 int32_t OnError(int32_t code, const std::string& msg) override
143 {
144 TAG_LOGW(AceLogTag::ACE_ROUTER, "silent install Error, code: %{public}d, msg: %{public}s", code, msg.c_str());
145 if (!errorEventHandler_) {
146 TAG_LOGW(AceLogTag::ACE_ROUTER, "errorEventHandler_ is null");
147 return ERR_INVALID_VALUE;
148 }
149
150 errorEventHandler_(code, msg);
151 return ERR_OK;
152 }
153
SetActionEventHandler(const std::function<void()>& listener)154 void SetActionEventHandler(const std::function<void()>& listener)
155 {
156 actionEventHandler_ = listener;
157 }
SetErrorEventHandler(const std::function<void(int32_t, const std::string&)>& listener)158 void SetErrorEventHandler(const std::function<void(int32_t, const std::string&)>& listener)
159 {
160 errorEventHandler_ = listener;
161 }
162
163 private:
164 std::function<void()> actionEventHandler_;
165 std::function<void(int32_t, const std::string&)> errorEventHandler_;
166 };
167
GetBundleManager()168 sptr<AppExecFwk::IBundleMgr> PageUrlCheckerOhos::GetBundleManager()
169 {
170 auto systemAbilityMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
171 if (systemAbilityMgr == nullptr) {
172 TAG_LOGE(AceLogTag::ACE_ROUTER, "Failed to get SystemAbilityManager.");
173 return nullptr;
174 }
175
176 auto bundleObj = systemAbilityMgr->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
177 if (bundleObj == nullptr) {
178 TAG_LOGE(AceLogTag::ACE_ROUTER, "Failed to get bundle manager service");
179 return nullptr;
180 }
181
182 return iface_cast<AppExecFwk::IBundleMgr>(bundleObj);
183 }
184
LoadPageUrl(const std::string& url, const std::function<void()>& callback, const std::function<void(int32_t, const std::string&)>& silentInstallErrorCallBack)185 void PageUrlCheckerOhos::LoadPageUrl(const std::string& url, const std::function<void()>& callback,
186 const std::function<void(int32_t, const std::string&)>& silentInstallErrorCallBack)
187 {
188 if (url.substr(0, strlen(BUNDLE_TAG)) != BUNDLE_TAG) {
189 return;
190 }
191
192 size_t bundleEndPos = url.find('/');
193 std::string bundleName = url.substr(BUNDLE_START_POS, bundleEndPos - BUNDLE_START_POS);
194 size_t moduleStartPos = bundleEndPos + 1;
195 size_t moduleEndPos = url.find('/', moduleStartPos);
196 std::string moduleName = url.substr(moduleStartPos, moduleEndPos - moduleStartPos);
197 size_t harStartPos = moduleName.find('@');
198 if (harStartPos != std::string::npos) {
199 moduleName = moduleName.substr(0, harStartPos);
200 }
201
202 auto appInfo = context_->GetApplicationInfo();
203 if (appInfo) {
204 std::vector<OHOS::AppExecFwk::ModuleInfo> moduleList = appInfo->moduleInfos;
205 auto res = std::any_of(moduleList.begin(), moduleList.end(), [moduleName](const auto &module) {
206 return module.moduleName == moduleName;
207 });
208 if (res) {
209 callback();
210 return;
211 }
212
213 auto bms = GetBundleManager();
214 CHECK_NULL_VOID(bms);
215 std::vector<AppExecFwk::BaseSharedBundleInfo> baseSharedBundleInfo;
216 if (bms->GetBaseSharedBundleInfos(bundleName, baseSharedBundleInfo) != 0 &&
217 baseSharedBundleInfo.size() != 0) {
218 callback();
219 return;
220 }
221
222 AppExecFwk::BundleInfo bundleInfo;
223 int32_t ret = bms->GetDependentBundleInfo(bundleName, bundleInfo,
224 AppExecFwk::GetDependentBundleInfoFlag::GET_APP_SERVICE_HSP_BUNDLE_INFO);
225 if (ret == ERR_OK && bundleInfo.hapModuleInfos.size() != 0) {
226 callback();
227 return;
228 }
229
230 AAFwk::Want want;
231 want.SetBundle(bundleName);
232 want.SetModuleName(moduleName);
233 sptr<AtomicServiceStatusCallback> routerCallback = new AtomicServiceStatusCallback();
234 routerCallback->SetActionEventHandler(callback);
235 routerCallback->SetErrorEventHandler(silentInstallErrorCallBack);
236 if (bms->SilentInstall(want, appInfo->uid / AppExecFwk::Constants::BASE_USER_RANGE, routerCallback)) {
237 TAG_LOGI(AceLogTag::ACE_ROUTER, "Begin to silent install");
238 }
239 }
240 }
241
CheckPreload(const std::string& url)242 void PageUrlCheckerOhos::CheckPreload(const std::string& url)
243 {
244 if (url.substr(0, strlen(BUNDLE_TAG)) != BUNDLE_TAG) {
245 return;
246 }
247
248 size_t bundleEndPos = url.find('/');
249 std::string bundleName = url.substr(BUNDLE_START_POS, bundleEndPos - BUNDLE_START_POS);
250 size_t moduleStartPos = bundleEndPos + 1;
251 size_t moduleEndPos = url.find('/', moduleStartPos);
252 std::string moduleName = url.substr(moduleStartPos, moduleEndPos - moduleStartPos);
253
254 auto appInfo = context_->GetApplicationInfo();
255 CHECK_NULL_VOID(appInfo);
256 if (appInfo->CheckNeedPreload(moduleName)) {
257 auto bms = GetBundleManager();
258 CHECK_NULL_VOID(bms);
259 AAFwk::Want want;
260 // only need to Transfer bundleName and moduleName
261 want.SetElementName("", bundleName, "", moduleName);
262 want.SetParam("uid", appInfo->uid);
263 bms->ProcessPreload(want);
264 }
265 }
266
NotifyPageShow(const std::string& pageName)267 void PageUrlCheckerOhos::NotifyPageShow(const std::string& pageName)
268 {
269 std::string targetBundleName;
270 std::string targetModuleName;
271 GetTargetPageInfo(pageName, targetBundleName, targetModuleName);
272 AppExecFwk::PageStateData pageStateData;
273 pageStateData.bundleName = abilityInfo_->bundleName;
274 pageStateData.moduleName = abilityInfo_->moduleName;
275 pageStateData.abilityName = abilityInfo_->name;
276 pageStateData.pageName = pageName;
277 pageStateData.targetBundleName = targetBundleName;
278 pageStateData.targetModuleName = targetModuleName;
279 DelayedSingleton<AppExecFwk::AppMgrClient>::GetInstance()->
280 NotifyPageShow(context_->GetToken(), pageStateData);
281 }
282
NotifyPageHide(const std::string& pageName)283 void PageUrlCheckerOhos::NotifyPageHide(const std::string& pageName)
284 {
285 std::string targetBundleName;
286 std::string targetModuleName;
287 GetTargetPageInfo(pageName, targetBundleName, targetModuleName);
288 AppExecFwk::PageStateData pageStateData;
289 pageStateData.bundleName = abilityInfo_->bundleName;
290 pageStateData.moduleName = abilityInfo_->moduleName;
291 pageStateData.abilityName = abilityInfo_->name;
292 pageStateData.pageName = pageName;
293 pageStateData.targetBundleName = targetBundleName;
294 pageStateData.targetModuleName = targetModuleName;
295 DelayedSingleton<AppExecFwk::AppMgrClient>::GetInstance()->
296 NotifyPageHide(context_->GetToken(), pageStateData);
297 }
298
GetTargetPageInfo(const std::string& pageName, std::string& targetBundleName, std::string& targetModuleName) const299 void PageUrlCheckerOhos::GetTargetPageInfo(const std::string& pageName, std::string& targetBundleName,
300 std::string& targetModuleName) const
301 {
302 if (pageName.substr(0, strlen(BUNDLE_TAG)) == BUNDLE_TAG) {
303 size_t bundleEndPos = pageName.find('/');
304 targetBundleName = pageName.substr(BUNDLE_START_POS, bundleEndPos - BUNDLE_START_POS);
305 size_t moduleStartPos = bundleEndPos + 1;
306 size_t moduleEndPos = pageName.find('/', moduleStartPos);
307 targetModuleName = pageName.substr(moduleStartPos, moduleEndPos - moduleStartPos);
308 } else {
309 targetBundleName = abilityInfo_->bundleName;
310 std::string moduleName = moduleNameCallback_(pageName);
311 if (moduleName == "") {
312 moduleName = abilityInfo_->moduleName;
313 }
314 targetModuleName = moduleName;
315 }
316 }
317
SetModuleNameCallback(std::function<std::string(const std::string&)>&& callback)318 void PageUrlCheckerOhos::SetModuleNameCallback(std::function<std::string(const std::string&)>&& callback)
319 {
320 moduleNameCallback_ = std::move(callback);
321 }
322 } // namespace OHOS::Ace