1/*
2 * Copyright (c) 2022 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 "background_audio_controller.h"
17#include "avsession_log.h"
18#include "avsession_service.h"
19#include "avsession_item.h"
20#include "permission_checker.h"
21
22namespace OHOS::AVSession {
23using AudioStandard::RendererState;
24
25BackgroundAudioController::BackgroundAudioController() : ptr_(nullptr)
26{
27    SLOGI("construct");
28}
29
30BackgroundAudioController::~BackgroundAudioController()
31{
32    SLOGI("destroy");
33}
34
35void BackgroundAudioController::Init(AVSessionService *ptr)
36{
37    ptr_ = ptr;
38    AudioAdapter::GetInstance().AddStreamRendererStateListener([this](const auto& infos) {
39        HandleAudioStreamRendererStateChange(infos);
40    });
41    AppManagerAdapter::GetInstance().SetAppStateChangeObserver([this](int32_t uid, int32_t pid, bool isBackground) {
42        SLOGI("set background observe for uid=%{public}d, pid=%{public}d, isBackground=%{public}d",
43            uid, pid, isBackground);
44        HandleAppMuteState(uid, pid, isBackground);
45    });
46}
47
48void BackgroundAudioController::OnSessionCreate(const AVSessionDescriptor& descriptor)
49{
50    std::lock_guard lockGuard(lock_);
51    sessionUIDs_.insert(descriptor.uid_);
52    SLOGI("OnSessionCreate remove observe for uid %{public}d", descriptor.uid_);
53    AppManagerAdapter::GetInstance().RemoveObservedApp(descriptor.uid_);
54}
55
56void BackgroundAudioController::OnSessionRelease(const AVSessionDescriptor& descriptor)
57{
58    {
59        std::lock_guard lockGuard(lock_);
60        sessionUIDs_.erase(descriptor.uid_);
61    }
62
63    if (descriptor.isThirdPartyApp_) {
64        SLOGI("OnSessionRelease add observe for uid %{public}d", descriptor.uid_);
65        AppManagerAdapter::GetInstance().AddObservedApp(descriptor.uid_);
66        int32_t uid = descriptor.uid_;
67        bool isRunning = AudioAdapter::GetInstance().GetRendererRunning(uid);
68        if (!isRunning) {
69            SLOGI("renderer state is not running when session release");
70            return;
71        }
72        if (AppManagerAdapter::GetInstance().IsAppBackground(descriptor.uid_, descriptor.pid_)) {
73            AudioAdapter::GetInstance().MuteAudioStream(descriptor.uid_);
74            if (ptr_ != nullptr) {
75                ptr_->NotifyAudioSessionCheckTrigger(descriptor.uid_);
76            }
77        }
78    }
79}
80
81// LCOV_EXCL_START
82void BackgroundAudioController::HandleAudioStreamRendererStateChange(const AudioRendererChangeInfos& infos)
83{
84    for (const auto& info : infos) {
85        if (info->rendererState != AudioStandard::RENDERER_RUNNING) {
86            continue;
87        }
88        if (PermissionChecker::GetInstance().CheckSystemPermissionByUid(info->clientUID)) {
89            SLOGD("uid=%{public}d is system app", info->clientUID);
90            continue;
91        }
92        SLOGI("AudioStreamRendererStateChange add observe for uid %{public}d", info->clientUID);
93        AppManagerAdapter::GetInstance().AddObservedApp(info->clientUID);
94
95        if (HasAVSession(info->clientUID)) {
96            continue;
97        }
98
99        if (AppManagerAdapter::GetInstance().IsAppBackground(info->clientUID, info->clientPid)) {
100            AudioAdapter::GetInstance().MuteAudioStream(info->clientUID);
101            if (ptr_ != nullptr) {
102                ptr_->NotifyAudioSessionCheckTrigger(info->clientUID);
103            }
104        } else {
105            AudioAdapter::GetInstance().UnMuteAudioStream(info->clientUID);
106        }
107    }
108}
109
110void BackgroundAudioController::HandleAppMuteState(int32_t uid, int32_t pid, bool isBackground)
111{
112    if (PermissionChecker::GetInstance().CheckSystemPermissionByUid(uid)) {
113        SLOGD("uid=%{public}d is system app", uid);
114        return;
115    }
116    if (HasAVSession(uid)) {
117        return;
118    }
119
120    if (isBackground) {
121        std::vector<std::shared_ptr<AudioStandard::AudioRendererChangeInfo>> infos;
122        auto ret = AudioStandard::AudioStreamManager::GetInstance()->GetCurrentRendererChangeInfos(infos);
123        if (ret != 0) {
124            SLOGE("get renderer state failed");
125            return;
126        }
127        bool isRunning = false;
128        for (const auto& info : infos) {
129            if (info->rendererState == AudioStandard::RENDERER_RUNNING &&
130                (info->clientUID == uid and info->clientPid == pid)) {
131                isRunning = true;
132                break;
133            }
134        }
135        if (!isRunning) {
136            SLOGI("find uid=%{public}d pid=%{public}d isn't running, return", uid, pid);
137            return;
138        }
139        SLOGI("mute uid=%{public}d", uid);
140        AudioAdapter::GetInstance().MuteAudioStream(uid);
141        if (ptr_ != nullptr) {
142            ptr_->NotifyAudioSessionCheckTrigger(uid);
143        }
144    } else {
145        SLOGI("unmute uid=%{public}d", uid);
146        AudioAdapter::GetInstance().UnMuteAudioStream(uid);
147    }
148}
149// LCOV_EXCL_STOP
150
151bool BackgroundAudioController::IsBackgroundMode(int32_t creatorUid, BackgroundMode backgroundMode) const
152{
153    // LCOV_EXCL_START
154    std::vector<std::shared_ptr<ContinuousTaskCallbackInfo>> continuousTaskList;
155    ErrCode code = BackgroundTaskMgr::BackgroundTaskMgrHelper::GetContinuousTaskApps(continuousTaskList);
156    if (code != OHOS::ERR_OK) {
157        SLOGE("uid=%{public}d no continuous task list, code=%{public}d", creatorUid, code);
158        return false;
159    }
160    // LCOV_EXCL_STOP
161
162    for (const auto &task : continuousTaskList) {
163        SLOGD("uid=%{public}d taskCreatorUid=%{public}d", creatorUid, task->GetCreatorUid());
164        if (task->GetCreatorUid() != creatorUid) {
165            continue;
166        }
167
168        std::vector<uint32_t> bgModeIds = task->GetTypeIds();
169        auto it = std::find_if(bgModeIds.begin(), bgModeIds.end(), [ = ](auto mode) {
170            uint32_t uMode = static_cast<uint32_t>(backgroundMode);
171            return (mode == uMode);
172        });
173        if (it != bgModeIds.end()) {
174            SLOGD("uid=%{public}d is audio playback", creatorUid);
175            return true;
176        }
177    }
178    SLOGD("uid=%{public}d isn't audio playback", creatorUid);
179    return false;
180}
181
182bool BackgroundAudioController::HasAVSession(int32_t uid)
183{
184    std::lock_guard lockGuard(lock_);
185    bool hasSession = false;
186    auto it = sessionUIDs_.find(uid);
187    if (it != sessionUIDs_.end()) {
188        SLOGD("uid=%{public}d has av_session, no need to handle mute or unmute strategy.", uid);
189        hasSession = true;
190    }
191    return hasSession;
192}
193}
194