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