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 "bundle_status_adapter.h"
17 
18 #include "avsession_log.h"
19 #include "iservice_registry.h"
20 #include "system_ability_definition.h"
21 #include "nlohmann/json.hpp"
22 #include "want.h"
23 #include "want_params_wrapper.h"
24 #include "string_wrapper.h"
25 #include "array_wrapper.h"
26 
27 namespace OHOS::AVSession {
BundleStatusAdapter()28 BundleStatusAdapter::BundleStatusAdapter()
29 {
30     SLOGI("construct");
31 }
32 
~BundleStatusAdapter()33 BundleStatusAdapter::~BundleStatusAdapter()
34 {
35     SLOGI("destroy");
36 }
37 
GetInstance()38 BundleStatusAdapter& BundleStatusAdapter::GetInstance()
39 {
40     static BundleStatusAdapter bundleStatusAdapter;
41     return bundleStatusAdapter;
42 }
43 
Init()44 void BundleStatusAdapter::Init()
45 {
46     auto systemAbilityManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
47     if (!systemAbilityManager) {
48         SLOGI("fail to get system ability mgr");
49         return;
50     }
51 
52     auto remoteObject = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
53     if (!remoteObject) {
54         SLOGI("fail to get bundle manager proxy");
55         return;
56     }
57 
58     std::lock_guard bundleMgrProxyLockGuard(bundleMgrProxyLock_);
59     SLOGI("get bundle manager proxy success");
60     bundleMgrProxy = iface_cast<AppExecFwk::BundleMgrProxy>(remoteObject);
61 }
62 
SubscribeBundleStatusEvent(const std::string bundleName,const std::function<void (const std::string,const int32_t userId)> & callback,int32_t userId)63 bool BundleStatusAdapter::SubscribeBundleStatusEvent(const std::string bundleName,
64     const std::function<void(const std::string, const int32_t userId)>& callback, int32_t userId)
65 {
66     SLOGI("Bundle status adapter subscribe bundle status event, bundleName=%{public}s, userId=%{public}d",
67         bundleName.c_str(), userId);
68     auto bundleStatusListener = bundleStatusListeners_.find(std::make_pair(bundleName, userId));
69     if (bundleStatusListener != bundleStatusListeners_.end()) {
70         SLOGE("bundle status has already register");
71         return false;
72     }
73     auto bundleStatusCallback = [this](std::string bundleName, int32_t userId) {
74         NotifyBundleRemoved(bundleName, userId);
75     };
76     sptr<BundleStatusCallbackImpl> bundleStatusCallbackImpl =
77             new(std::nothrow) BundleStatusCallbackImpl(bundleStatusCallback, userId);
78     if (bundleStatusCallbackImpl == nullptr) {
79         SLOGE("no memory");
80         return false;
81     }
82     std::lock_guard bundleMgrProxyLockGuard(bundleMgrProxyLock_);
83     if (bundleMgrProxy == nullptr) {
84         SLOGE("SubscribeBundleStatusEvent with proxy null!");
85         Init();
86         if (bundleMgrProxy == nullptr) {
87             SLOGE("SubscribeBundleStatusEvent with proxy null after init!");
88             return false;
89         }
90     }
91     bundleStatusCallbackImpl->SetBundleName(bundleName);
92     bundleStatusCallbackImpl->SetUserId(userId);
93     if (bundleMgrProxy->RegisterBundleStatusCallback(bundleStatusCallbackImpl)) {
94         bundleStatusListeners_.insert(std::make_pair(std::make_pair(bundleName, userId), callback));
95         return true;
96     } else {
97         SLOGE("Register bundle status callback failed, bundleName=%{public}s", bundleName.c_str());
98         return false;
99     }
100 }
101 
IsAudioPlayback(const std::string & bundleName,const std::string & abilityName)102 bool BundleStatusAdapter::IsAudioPlayback(const std::string& bundleName, const std::string& abilityName)
103 {
104     SLOGI("Estimate bundle audio playback status, bundleName=%{public}s", bundleName.c_str());
105     AppExecFwk::AbilityInfo abilityInfo;
106     bool flag = false;
107     if (bundleMgrProxy->GetAbilityInfo(bundleName, abilityName, abilityInfo)) {
108         flag = static_cast<int32_t>(abilityInfo.backgroundModes) == backgroundModeDemand ? true : false;
109     }
110     return flag;
111 }
112 
NotifyBundleRemoved(const std::string bundleName,const int32_t userId)113 void BundleStatusAdapter::NotifyBundleRemoved(const std::string bundleName, const int32_t userId)
114 {
115     auto bundleStatusListener = bundleStatusListeners_.find(std::make_pair(bundleName, userId));
116     if (bundleStatusListener == bundleStatusListeners_.end()) {
117         return;
118     }
119     bundleStatusListener->second(bundleName, userId);
120     // BMS will keep callbackImpl for the bundleName & userId until avsession do ClearBundleStatusCallback
121     SLOGI("notify bundle status callback without erase, bundleName=%{public}s, userId=%{public}d",
122         bundleName.c_str(), userId);
123 }
124 
GetBundleNameFromUid(const int32_t uid)125 std::string BundleStatusAdapter::GetBundleNameFromUid(const int32_t uid)
126 {
127     std::string bundleName {""};
128     if (bundleMgrProxy != nullptr) {
129         bundleMgrProxy->GetNameForUid(uid, bundleName);
130     }
131     return bundleName;
132 }
133 
CheckBundleSupport(std::string & profile)134 bool BundleStatusAdapter::CheckBundleSupport(std::string& profile)
135 {
136     // check bundle support background mode & playmusiclist intent
137     nlohmann::json profileValues = nlohmann::json::parse(profile, nullptr, false);
138     CHECK_AND_RETURN_RET_LOG(!profileValues.is_discarded(), false, "json object is null");
139     CHECK_AND_RETURN_RET_LOG(profileValues.contains("insightIntents"), false, "json do not contains insightIntents");
140     for (const auto& value : profileValues["insightIntents"]) {
141         std::string insightName = value["intentName"];
142         CHECK_AND_RETURN_RET_LOG(value.contains("uiAbility"), false, "json do not contains uiAbility");
143         nlohmann::json abilityValue = value["uiAbility"];
144         if (insightName != PLAY_MUSICLIST && insightName != PLAY_AUDIO) {
145             continue;
146         }
147         if (abilityValue.is_discarded()) {
148             SLOGE("uiability discarded=%{public}d", abilityValue.is_discarded());
149             return false;
150         }
151         CHECK_AND_RETURN_RET_LOG(abilityValue.contains("executeMode"), false, "json do not contains executeMode");
152         auto modeValues = abilityValue["executeMode"];
153         if (modeValues.is_discarded()) {
154             SLOGE("executeMode discarded=%{public}d", modeValues.is_discarded());
155             return false;
156         }
157         auto mode = std::find(modeValues.begin(), modeValues.end(), "background");
158         return (mode != modeValues.end());
159     }
160     return false;
161 }
162 
IsSupportPlayIntent(const std::string & bundleName,std::string & supportModule,std::string & profile)163 __attribute__((no_sanitize("cfi"))) bool BundleStatusAdapter::IsSupportPlayIntent(const std::string& bundleName,
164     std::string& supportModule, std::string& profile)
165 {
166     if (bundleMgrProxy == nullptr) {
167         return false;
168     }
169     AppExecFwk::BundleInfo bundleInfo;
170     if (!bundleMgrProxy->GetBundleInfo(bundleName, getBundleInfoWithHapModule, bundleInfo, startUserId)) {
171         SLOGE("GetBundleInfo=%{public}s fail", bundleName.c_str());
172         return false;
173     }
174     bool isSupportIntent = false;
175     for (std::string module : bundleInfo.moduleNames) {
176         auto ret = bundleMgrProxy->GetJsonProfile(AppExecFwk::ProfileType::INTENT_PROFILE, bundleName, module,
177             profile, startUserId);
178         if (ret == 0) {
179             SLOGI("GetJsonProfile success, profile=%{public}s", profile.c_str());
180             isSupportIntent = true;
181             supportModule = module;
182             break;
183         }
184     }
185     if (!isSupportIntent) {
186         SLOGE("Bundle=%{public}s does not support insight", bundleName.c_str());
187         return false;
188     }
189     return CheckBundleSupport(profile);
190 }
191 
BundleStatusCallbackImpl(const std::function<void (const std::string,const int32_t userId)> & callback,int32_t userId)192 BundleStatusCallbackImpl::BundleStatusCallbackImpl(
193     const std::function<void(const std::string, const int32_t userId)>& callback, int32_t userId)
194 {
195     SLOGI("Create bundle status instance with userId %{public}d", userId);
196     callback_ = callback;
197     userId_ = userId;
198 }
199 
~BundleStatusCallbackImpl()200 BundleStatusCallbackImpl::~BundleStatusCallbackImpl()
201 {
202     SLOGI("Destroy bundle status instance");
203 }
204 
OnBundleStateChanged(const uint8_t installType,const int32_t resultCode,const std::string & resultMsg,const std::string & bundleName)205 void BundleStatusCallbackImpl::OnBundleStateChanged(const uint8_t installType, const int32_t resultCode,
206     const std::string &resultMsg, const std::string &bundleName)
207 {
208     if (installType == static_cast<uint8_t>(AppExecFwk::InstallType::UNINSTALL_CALLBACK)) {
209         callback_(bundleName, userId_);
210     }
211 }
212 }
213