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