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