1 /*
2 * Copyright (c) 2024-2025 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 <file_ex.h>
17 #include <set>
18 #include <sstream>
19
20 #include "background_sensitive_task_overlapping_scene_recognizer.h"
21 #include "background_mode.h"
22 #include "res_sched_log.h"
23 #include "res_sched_mgr.h"
24 #include "res_type.h"
25 #include "string_ex.h"
26
27 namespace OHOS {
28 namespace ResourceSchedule {
29 namespace {
30 static const int32_t INVALID_VALUE = -1;
31 static const pid_t PID_MIN = -1;
32 static const pid_t PID_MAX = INT32_MAX;
33 static const char* PID_KEY = "pid";
34 static const char* TYPE_IDS_KEY = "typeIds";
35 static const std::set<uint32_t> PERCEIVABLE_MODES = {
36 BackgroundTaskMgr::BackgroundMode::Type::LOCATION,
37 BackgroundTaskMgr::BackgroundMode::Type::VOIP,
38 BackgroundTaskMgr::BackgroundMode::Type::AUDIO_PLAYBACK,
39 BackgroundTaskMgr::BackgroundMode::Type::MULTI_DEVICE_CONNECTION,
40 };
41 }
42
~BackgroundSensitiveTaskOverlappingSceneRecognizer()43 BackgroundSensitiveTaskOverlappingSceneRecognizer::~BackgroundSensitiveTaskOverlappingSceneRecognizer()
44 {
45 RESSCHED_LOGI("~BackgroundPerceivableSceneRecoginzer");
46 }
47
BackgroundSensitiveTaskOverlappingSceneRecognizer()48 BackgroundSensitiveTaskOverlappingSceneRecognizer::BackgroundSensitiveTaskOverlappingSceneRecognizer()
49 {
50 perceivableTasks_ = {};
51 AddAcceptResTypes({
52 ResType::RES_TYPE_APP_STATE_CHANGE,
53 ResType::RES_TYPE_CONTINUOUS_TASK,
54 ResType::RES_TYPE_REPORT_SCENE_BOARD,
55 });
56 }
57
OnDispatchResource(uint32_t resType,int64_t value,const nlohmann::json & payload)58 void BackgroundSensitiveTaskOverlappingSceneRecognizer::OnDispatchResource(uint32_t resType, int64_t value,
59 const nlohmann::json& payload)
60 {
61 if (!payload.contains(PID_KEY) || !payload[PID_KEY].is_string()) {
62 return;
63 }
64 int32_t invalidValue = INVALID_VALUE;
65 switch (resType) {
66 case ResType::RES_TYPE_APP_STATE_CHANGE:
67 HandleForeground(resType, value, payload);
68 break;
69 case ResType::RES_TYPE_CONTINUOUS_TASK:
70 HandleContinuousTask(resType, value, payload);
71 break;
72 case ResType::RES_TYPE_REPORT_SCENE_BOARD:
73 StrToInt(payload[PID_KEY].get<std::string>(), sceneboardPid_);
74 break;
75 default:
76 break;
77 }
78 }
79
HandleContinuousTask(uint32_t resType,int64_t value,const nlohmann::json & payload)80 void BackgroundSensitiveTaskOverlappingSceneRecognizer::HandleContinuousTask(uint32_t resType, int64_t value,
81 const nlohmann::json& payload)
82 {
83 pid_t pid = -1;
84 StrToInt(payload[PID_KEY].get<std::string>(), pid);
85 std::vector<uint32_t> typeIds;
86 if (payload.contains(TYPE_IDS_KEY) && payload[TYPE_IDS_KEY].is_array()) {
87 typeIds = payload[TYPE_IDS_KEY].get<std::vector<uint32_t>>();
88 }
89 std::stringstream typeIdsStr;
90 for (auto it = typeIds.begin(); it != typeIds.end();) {
91 if (!typeIdsStr.str().empty()) {
92 typeIdsStr << ", ";
93 }
94 typeIdsStr << *it;
95 if (PERCEIVABLE_MODES.find(*it) == PERCEIVABLE_MODES.end()) {
96 it = typeIds.erase(it);
97 } else {
98 it ++;
99 }
100 }
101 RESSCHED_LOGI("%{public}s, resType:%{public}d, value:%{public}lld, typeIds:{%{public}s}",
102 __func__, resType, (long long)value, typeIdsStr.str().c_str());
103 if (value == ResType::ContinuousTaskStatus::CONTINUOUS_TASK_START && !typeIds.empty()) {
104 HandleTaskStart(pid, typeIds);
105 } else if (value == ResType::ContinuousTaskStatus::CONTINUOUS_TASK_UPDATE) {
106 HandleTaskUpdate(pid, typeIds);
107 } else if (value == ResType::ContinuousTaskStatus::CONTINUOUS_TASK_END) {
108 HandleTaskStop(pid);
109 } else {
110 RESSCHED_LOGW("%{public}s, unknow ContinuousTaskStatus value", __func__);
111 }
112 }
113
114 /**
115 * @brief judge is enter scene.
116 * Rules for entering the BackgroundSensitiveTaskOverlapping scene:
117 * 1.Only one background sensitive continuous task,
118 * and the foreground app is NOT the app that start the continous task or scene board.
119 * 2.Two or more background sensitive continous tasks, and the foregound app is NOT scene board.
120 * @return True if enter scene, else false.
121 */
CheckEnterScene()122 bool BackgroundSensitiveTaskOverlappingSceneRecognizer::CheckEnterScene()
123 {
124 if (isInBackgroundPerceivableScene_ || foregroundPid_ == sceneboardPid_) {
125 RESSCHED_LOGD("already in background sensitive scene or foreground is sceneboard");
126 return false;
127 }
128
129 // more than one app has benn applied for sensitive task, there must be a task in background
130 if (perceivableTasks_.size() > 1) {
131 return true;
132 }
133 if (perceivableTasks_.size() > 0 && perceivableTasks_.find(foregroundPid_) == perceivableTasks_.end()) {
134 return true;
135 }
136 return false;
137 }
138
EnterScene()139 void BackgroundSensitiveTaskOverlappingSceneRecognizer::EnterScene()
140 {
141 nlohmann::json payload;
142 ResSchedMgr::GetInstance().ReportData(ResType::RES_TYPE_BACKGROUND_PERCEIVABLE_SCENE,
143 ResType::BackgroundPerceivableStatus::PERCEIVABLE_START, payload);
144 isInBackgroundPerceivableScene_ = true;
145 }
146
ExitScene()147 void BackgroundSensitiveTaskOverlappingSceneRecognizer::ExitScene()
148 {
149 nlohmann::json payload;
150 ResSchedMgr::GetInstance().ReportData(ResType::RES_TYPE_BACKGROUND_PERCEIVABLE_SCENE,
151 ResType::BackgroundPerceivableStatus::PERCEIVABLE_STOP, payload);
152 isInBackgroundPerceivableScene_ = false;
153 }
154
HandleTaskStart(pid_t pid,const std::vector<uint32_t> & filteredTypeIds)155 void BackgroundSensitiveTaskOverlappingSceneRecognizer::HandleTaskStart(pid_t pid,
156 const std::vector<uint32_t> &filteredTypeIds)
157 {
158 if (!IsValidPid(pid) || !IsValidFilteredTypeIds(filteredTypeIds)) {
159 return;
160 }
161 perceivableTasks_[pid] = filteredTypeIds;
162 if (CheckEnterScene()) {
163 RESSCHED_LOGI("perceivable task start enter scene");
164 EnterScene();
165 }
166 }
167
HandleTaskUpdate(pid_t pid,const std::vector<uint32_t> & filteredTypeIds)168 void BackgroundSensitiveTaskOverlappingSceneRecognizer::HandleTaskUpdate(pid_t pid,
169 const std::vector<uint32_t> &filteredTypeIds)
170 {
171 if (filteredTypeIds.empty()) {
172 if (perceivableTasks_.find(pid) != perceivableTasks_.end()) {
173 perceivableTasks_.erase(pid);
174 }
175 if (!CheckEnterScene()) {
176 RESSCHED_LOGI("after task update all perceivable task stop exit scene");
177 ExitScene();
178 }
179 } else {
180 perceivableTasks_[pid] = filteredTypeIds;
181 if (CheckEnterScene()) {
182 nlohmann::json payload;
183 RESSCHED_LOGI("after task update perceivable task update enter scene");
184 EnterScene();
185 }
186 }
187 }
188
HandleTaskStop(pid_t pid)189 void BackgroundSensitiveTaskOverlappingSceneRecognizer::HandleTaskStop(pid_t pid)
190 {
191 if (perceivableTasks_.find(pid) != perceivableTasks_.end()) {
192 perceivableTasks_.erase(pid);
193 if (!CheckEnterScene()) {
194 RESSCHED_LOGI("after task stop all perceivable task stop exit scene");
195 ExitScene();
196 }
197 }
198 }
199
HandleForeground(uint32_t resType,int64_t value,const nlohmann::json & payload)200 void BackgroundSensitiveTaskOverlappingSceneRecognizer::HandleForeground(uint32_t resType, int64_t value,
201 const nlohmann::json& payload)
202 {
203 if (value != ResType::ProcessStatus::PROCESS_FOREGROUND) {
204 return;
205 }
206 StrToInt(payload[PID_KEY].get<std::string>(), foregroundPid_);
207 if (foregroundPid_ == sceneboardPid_ && isInBackgroundPerceivableScene_) {
208 RESSCHED_LOGI("sceneboard foreground exit scene");
209 ExitScene();
210 } else if (CheckEnterScene()) {
211 RESSCHED_LOGI("sceneboard background and has perceivable task enter scene");
212 EnterScene();
213 }
214 }
215
IsValidPid(pid_t pid)216 bool BackgroundSensitiveTaskOverlappingSceneRecognizer::IsValidPid(pid_t pid)
217 {
218 return (pid >= PID_MIN && pid <= PID_MAX);
219 }
220
IsValidFilteredTypeIds(const std::vector<uint32_t> & filteredTypeIds)221 bool BackgroundSensitiveTaskOverlappingSceneRecognizer::IsValidFilteredTypeIds(
222 const std::vector<uint32_t> &filteredTypeIds)
223 {
224 for (auto fileteredTypeId : filteredTypeIds) {
225 if (fileteredTypeId < BackgroundTaskMgr::BackgroundMode::Type::DATA_TRANSFER ||
226 fileteredTypeId > BackgroundTaskMgr::BackgroundMode::Type::END) {
227 return false;
228 }
229 }
230 if (filteredTypeIds.size() > BackgroundTaskMgr::BackgroundMode::Type::END) {
231 return false;
232 }
233 return true;
234 }
235 } // namespace ResourceSchedule
236 } // namespace OHOS