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