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