• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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