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