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