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 bundleResourceProxy = bundleMgrProxy->GetBundleResourceProxy();
62 }
63
GetBundleIcon(const std::string bundleName,std::string & icon)64 bool BundleStatusAdapter::GetBundleIcon(const std::string bundleName, std::string& icon)
65 {
66 SLOGI("GetBundleIcon with bundleName:%{public}s", bundleName.c_str());
67
68 if (bundleMgrProxy == nullptr || bundleResourceProxy == nullptr) {
69 SLOGE("GetBundleIcon with bundleMgrProxy:%{public}d, bundleResourceProxy:%{public}d",
70 static_cast<int>(bundleMgrProxy != nullptr), static_cast<int>(bundleResourceProxy != nullptr));
71 return false;
72 }
73 AppExecFwk::BundleInfo bundleInfo;
74 if (!bundleMgrProxy->GetBundleInfo(bundleName, getBundleInfoWithHapModule, bundleInfo, startUserId)) {
75 SLOGE("GetBundleInfo of bundleName:%{public}s fail!", bundleName.c_str());
76 return false;
77 }
78 std::vector<AppExecFwk::LauncherAbilityResourceInfo> LauncherAbilityResourceInfoList;
79 ErrCode ret = bundleResourceProxy->GetLauncherAbilityResourceInfo(bundleName, 0, LauncherAbilityResourceInfoList);
80 if (ret != ERR_OK) {
81 SLOGE("GetLauncherAbilityResourceInfo of bundleName:%{public}s fail for errCode:%{public}d",
82 bundleName.c_str(), ret);
83 return false;
84 }
85
86 icon = LauncherAbilityResourceInfoList[0].icon;
87 return true;
88 }
89
SubscribeBundleStatusEvent(const std::string bundleName,const std::function<void (const std::string,const int32_t userId)> & callback,int32_t userId)90 bool BundleStatusAdapter::SubscribeBundleStatusEvent(const std::string bundleName,
91 const std::function<void(const std::string, const int32_t userId)>& callback, int32_t userId)
92 {
93 SLOGI("Bundle status adapter subscribe bundle status event, bundleName=%{public}s, userId=%{public}d",
94 bundleName.c_str(), userId);
95 auto bundleStatusListener = bundleStatusListeners_.find(std::make_pair(bundleName, userId));
96 if (bundleStatusListener != bundleStatusListeners_.end()) {
97 SLOGE("bundle status has already register");
98 return false;
99 }
100 auto bundleStatusCallback = [this](std::string bundleName, int32_t userId) {
101 NotifyBundleRemoved(bundleName, userId);
102 };
103 sptr<BundleStatusCallbackImpl> bundleStatusCallbackImpl =
104 new(std::nothrow) BundleStatusCallbackImpl(bundleStatusCallback, userId);
105 if (bundleStatusCallbackImpl == nullptr) {
106 SLOGE("no memory");
107 return false;
108 }
109 std::lock_guard bundleMgrProxyLockGuard(bundleMgrProxyLock_);
110 if (bundleMgrProxy == nullptr) {
111 SLOGE("SubscribeBundleStatusEvent with proxy null!");
112 Init();
113 if (bundleMgrProxy == nullptr) {
114 SLOGE("SubscribeBundleStatusEvent with proxy null after init!");
115 return false;
116 }
117 }
118 bundleStatusCallbackImpl->SetBundleName(bundleName);
119 bundleStatusCallbackImpl->SetUserId(userId);
120 if (bundleMgrProxy->RegisterBundleStatusCallback(bundleStatusCallbackImpl)) {
121 bundleStatusListeners_.insert(std::make_pair(std::make_pair(bundleName, userId), callback));
122 return true;
123 } else {
124 SLOGE("Register bundle status callback failed, bundleName=%{public}s", bundleName.c_str());
125 return false;
126 }
127 }
128
IsAudioPlayback(const std::string & bundleName,const std::string & abilityName)129 bool BundleStatusAdapter::IsAudioPlayback(const std::string& bundleName, const std::string& abilityName)
130 {
131 SLOGI("Estimate bundle audio playback status, bundleName=%{public}s", bundleName.c_str());
132 AppExecFwk::AbilityInfo abilityInfo;
133 bool flag = false;
134 if (bundleMgrProxy->GetAbilityInfo(bundleName, abilityName, abilityInfo)) {
135 flag = static_cast<int32_t>(abilityInfo.backgroundModes) == backgroundModeDemand ? true : false;
136 }
137 return flag;
138 }
139
NotifyBundleRemoved(const std::string bundleName,const int32_t userId)140 void BundleStatusAdapter::NotifyBundleRemoved(const std::string bundleName, const int32_t userId)
141 {
142 auto bundleStatusListener = bundleStatusListeners_.find(std::make_pair(bundleName, userId));
143 if (bundleStatusListener == bundleStatusListeners_.end()) {
144 return;
145 }
146 bundleStatusListener->second(bundleName, userId);
147 // BMS will keep callbackImpl for the bundleName & userId until avsession do ClearBundleStatusCallback
148 SLOGI("notify bundle status callback without erase, bundleName=%{public}s, userId=%{public}d",
149 bundleName.c_str(), userId);
150 }
151
GetBundleNameFromUid(const int32_t uid)152 std::string BundleStatusAdapter::GetBundleNameFromUid(const int32_t uid)
153 {
154 std::string bundleName {""};
155 if (bundleMgrProxy != nullptr) {
156 bundleMgrProxy->GetNameForUid(uid, bundleName);
157 }
158 return bundleName;
159 }
160
CheckBundleSupport(std::string & profile)161 bool BundleStatusAdapter::CheckBundleSupport(std::string& profile)
162 {
163 // check bundle support background mode & playmusiclist intent
164 nlohmann::json profileValues = nlohmann::json::parse(profile, nullptr, false);
165 CHECK_AND_RETURN_RET_LOG(!profileValues.is_discarded(), false, "json object is null");
166 CHECK_AND_RETURN_RET_LOG(profileValues.contains("insightIntents"), false, "json do not contains insightIntents");
167 for (const auto& value : profileValues["insightIntents"]) {
168 std::string insightName = value["intentName"];
169 CHECK_AND_RETURN_RET_LOG(value.contains("uiAbility"), false, "json do not contains uiAbility");
170 nlohmann::json abilityValue = value["uiAbility"];
171 if (insightName != PLAY_MUSICLIST && insightName != PLAY_AUDIO) {
172 continue;
173 }
174 if (abilityValue.is_discarded()) {
175 SLOGE("uiability discarded=%{public}d", abilityValue.is_discarded());
176 return false;
177 }
178 CHECK_AND_RETURN_RET_LOG(abilityValue.contains("executeMode"), false, "json do not contains executeMode");
179 auto modeValues = abilityValue["executeMode"];
180 if (modeValues.is_discarded()) {
181 SLOGE("executeMode discarded=%{public}d", modeValues.is_discarded());
182 return false;
183 }
184 auto mode = std::find(modeValues.begin(), modeValues.end(), "background");
185 return (mode != modeValues.end());
186 }
187 return false;
188 }
189
IsSupportPlayIntent(const std::string & bundleName,std::string & supportModule,std::string & profile)190 __attribute__((no_sanitize("cfi"))) bool BundleStatusAdapter::IsSupportPlayIntent(const std::string& bundleName,
191 std::string& supportModule, std::string& profile)
192 {
193 if (bundleMgrProxy == nullptr) {
194 return false;
195 }
196 AppExecFwk::BundleInfo bundleInfo;
197 if (!bundleMgrProxy->GetBundleInfo(bundleName, getBundleInfoWithHapModule, bundleInfo, startUserId)) {
198 SLOGE("GetBundleInfo=%{public}s fail", bundleName.c_str());
199 return false;
200 }
201 bool isSupportIntent = false;
202 for (std::string module : bundleInfo.moduleNames) {
203 auto ret = bundleMgrProxy->GetJsonProfile(AppExecFwk::ProfileType::INTENT_PROFILE, bundleName, module,
204 profile, startUserId);
205 if (ret == 0) {
206 SLOGI("GetJsonProfile success, profile=%{public}s", profile.c_str());
207 isSupportIntent = true;
208 supportModule = module;
209 break;
210 }
211 }
212 if (!isSupportIntent) {
213 SLOGE("Bundle=%{public}s does not support insight", bundleName.c_str());
214 return false;
215 }
216 return CheckBundleSupport(profile);
217 }
218
BundleStatusCallbackImpl(const std::function<void (const std::string,const int32_t userId)> & callback,int32_t userId)219 BundleStatusCallbackImpl::BundleStatusCallbackImpl(
220 const std::function<void(const std::string, const int32_t userId)>& callback, int32_t userId)
221 {
222 SLOGI("Create bundle status instance with userId %{public}d", userId);
223 callback_ = callback;
224 userId_ = userId;
225 }
226
~BundleStatusCallbackImpl()227 BundleStatusCallbackImpl::~BundleStatusCallbackImpl()
228 {
229 SLOGI("Destroy bundle status instance");
230 }
231
OnBundleStateChanged(const uint8_t installType,const int32_t resultCode,const std::string & resultMsg,const std::string & bundleName)232 void BundleStatusCallbackImpl::OnBundleStateChanged(const uint8_t installType, const int32_t resultCode,
233 const std::string &resultMsg, const std::string &bundleName)
234 {
235 if (installType == static_cast<uint8_t>(AppExecFwk::InstallType::UNINSTALL_CALLBACK)) {
236 callback_(bundleName, userId_);
237 }
238 }
239 }
240