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