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 "fold_event_cacher.h"
17
18 #include "display_info.h"
19 #include "display_manager.h"
20 #include "fold_common_utils.h"
21 #include "hiview_logger.h"
22 #include "string_util.h"
23 #include "time_util.h"
24 #include "usage_event_common.h"
25
26 using namespace OHOS::HiviewDFX::FoldState;
27 using namespace OHOS::HiviewDFX::MultiWindowMode;
28
29 namespace OHOS {
30 namespace HiviewDFX {
31 DEFINE_LOG_TAG("FoldEventCacher");
32 namespace {
33 constexpr int8_t UNKNOWN_STATUS = -1;
34 constexpr uint32_t MILLISEC_TO_MICROSEC = 1000;
35 constexpr int8_t EXPAND = 1;
36 constexpr int8_t FOLD = 2;
37 constexpr int8_t G = 3;
38 constexpr int8_t LANDSCAPE = 1;
39 constexpr int8_t PORTRAIT = 2;
40 constexpr int8_t FULL = 0;
41 constexpr int8_t SPLIT = 1;
42 constexpr int8_t FLOATING = 2;
43 constexpr int8_t MIDSCENE = 3;
44 constexpr int8_t THE_TENS_DIGIT = 10;
45
ConvertFoldStatus(int32_t foldStatus)46 int8_t ConvertFoldStatus(int32_t foldStatus)
47 {
48 switch (foldStatus) {
49 case FOLD_STATE_EXPAND:
50 case FOLD_STATE_HALF_FOLDED:
51 return EXPAND;
52 case FOLD_STATE_FOLDED:
53 case FOLD_STATE_FOLDED_WITH_SECOND_HALF_FOLDED:
54 return FOLD;
55 case FOLD_STATE_EXPAND_WITH_SECOND_EXPAND:
56 case FOLD_STATE_EXPAND_WITH_SECOND_HALF_FOLDED:
57 case FOLD_STATE_HALF_FOLDED_WITH_SECOND_EXPAND:
58 case FOLD_STATE_HALF_FOLDED_WITH_SECOND_HALF_FOLDED:
59 return G;
60 default:
61 return UNKNOWN_STATUS;
62 }
63 }
64
ConvertVhMode(int32_t vhMode)65 int8_t ConvertVhMode(int32_t vhMode)
66 {
67 switch (vhMode) {
68 case 0: // 0-Portrait
69 return PORTRAIT;
70 case 1: // 1-landscape
71 return LANDSCAPE;
72 default:
73 return UNKNOWN_STATUS;
74 }
75 }
76
ConvertWindowMode(int32_t windowMode)77 int8_t ConvertWindowMode(int32_t windowMode)
78 {
79 switch (windowMode) {
80 case WINDOW_MODE_FULL:
81 return FULL;
82 case WINDOW_MODE_FLOATING:
83 return FLOATING;
84 case WINDOW_MODE_SPLIT_PRIMARY:
85 case WINDOW_MODE_SPLIT_SECONDARY:
86 return SPLIT;
87 case WINDOW_MODE_MIDSCENE:
88 return MIDSCENE;
89 default:
90 return UNKNOWN_STATUS;
91 }
92 }
93
GetScreenFoldStatus(int32_t foldStatus,int32_t vhMode,int32_t windowMode)94 int GetScreenFoldStatus(int32_t foldStatus, int32_t vhMode, int32_t windowMode)
95 {
96 int8_t combineFoldStatus = ConvertFoldStatus(foldStatus);
97 int8_t combineVhMode = ConvertVhMode(vhMode);
98 int8_t combineWindowMode = ConvertWindowMode(windowMode);
99 if (combineFoldStatus == UNKNOWN_STATUS || combineVhMode == UNKNOWN_STATUS || combineWindowMode == UNKNOWN_STATUS) {
100 return UNKNOWN_STATUS;
101 }
102 // for example ScreenFoldStatus = 110 means foldStatus = 1, vhMode = 1 and windowMode = 0
103 return ((combineFoldStatus * THE_TENS_DIGIT) + combineVhMode) * THE_TENS_DIGIT + combineWindowMode;
104 }
105 } // namespace
106
FoldEventCacher(const std::string & workPath)107 FoldEventCacher::FoldEventCacher(const std::string& workPath)
108 {
109 timelyStart_ = TimeUtil::GetBootTimeMs();
110 dbHelper_ = std::make_unique<FoldAppUsageDbHelper>(workPath);
111
112 foldStatus_ = static_cast<int32_t>(OHOS::Rosen::DisplayManager::GetInstance().GetFoldStatus());
113 auto display = OHOS::Rosen::DisplayManager::GetInstance().GetDefaultDisplay();
114 if (display != nullptr) {
115 auto displayInfo = display->GetDisplayInfo();
116 if (displayInfo != nullptr) {
117 auto orientation = displayInfo->GetDisplayOrientation();
118 if (orientation == OHOS::Rosen::DisplayOrientation::PORTRAIT ||
119 orientation == OHOS::Rosen::DisplayOrientation::PORTRAIT_INVERTED) {
120 vhMode_ = 0; // 0-Portrait
121 } else {
122 vhMode_ = 1; // 1-landscape
123 }
124 }
125 }
126 FoldCommonUtils::GetFocusedAppAndWindowInfos(focusedAppPair_, multiWindowInfos_);
127 HIVIEW_LOGI("foldStatus=%{public}d, vhMode=%{public}d", foldStatus_, vhMode_);
128 }
129
ProcessEvent(std::shared_ptr<SysEvent> event)130 void FoldEventCacher::ProcessEvent(std::shared_ptr<SysEvent> event)
131 {
132 if (dbHelper_ == nullptr) {
133 HIVIEW_LOGI("dbHelper is nulptr");
134 return;
135 }
136 std::string eventName = event->eventName_;
137 if (eventName == AppEventSpace::FOCUS_WINDOW) {
138 ProcessFocusWindowEvent(event);
139 }
140 if ((eventName == FoldStateChangeEventSpace::EVENT_NAME) || (eventName == VhModeChangeEventSpace::EVENT_NAME) ||
141 (eventName == MultiWindowChangeEventSpace::EVENT_NAME)) {
142 ProcessSceenStatusChangedEvent(event);
143 }
144 }
145
ProcessFocusWindowEvent(std::shared_ptr<SysEvent> event)146 void FoldEventCacher::ProcessFocusWindowEvent(std::shared_ptr<SysEvent> event)
147 {
148 if (focusedAppPair_.second) {
149 ProcessBackgroundEvent(event);
150 }
151 bool shouldCount = (event->GetEventIntValue(AppEventSpace::KEY_OF_WINDOW_TYPE)
152 < FoldCommonUtils::SYSTEM_WINDOW_BASE);
153 std::string bundleName = event->GetEventValue(AppEventSpace::KEY_OF_BUNDLE_NAME);
154 focusedAppPair_ = std::make_pair(bundleName, shouldCount);
155 if (shouldCount) {
156 ProcessForegroundEvent(event);
157 }
158 }
159
ProcessForegroundEvent(std::shared_ptr<SysEvent> event)160 void FoldEventCacher::ProcessForegroundEvent(std::shared_ptr<SysEvent> event)
161 {
162 AppEventRecord appEventRecord;
163 appEventRecord.rawid = FoldEventId::EVENT_APP_START;
164 appEventRecord.ts = static_cast<int64_t>(TimeUtil::GetBootTimeMs());
165 appEventRecord.bundleName = focusedAppPair_.first;
166 int combineScreenStatus = GetScreenFoldStatus(foldStatus_, vhMode_, GetWindowModeOfFocusedApp());
167 appEventRecord.preFoldStatus = combineScreenStatus;
168 appEventRecord.foldStatus = combineScreenStatus;
169 appEventRecord.happenTime = static_cast<int64_t>(event->happenTime_);
170
171 if (combineScreenStatus != UNKNOWN_STATUS) {
172 dbHelper_->AddAppEvent(appEventRecord);
173 }
174 }
175
ProcessBackgroundEvent(std::shared_ptr<SysEvent> event)176 void FoldEventCacher::ProcessBackgroundEvent(std::shared_ptr<SysEvent> event)
177 {
178 AppEventRecord appEventRecord;
179 appEventRecord.rawid = FoldEventId::EVENT_APP_EXIT;
180 appEventRecord.ts = static_cast<int64_t>(TimeUtil::GetBootTimeMs());
181 appEventRecord.bundleName = focusedAppPair_.first;
182 int combineScreenStatus = GetScreenFoldStatus(foldStatus_, vhMode_, GetWindowModeOfFocusedApp());
183 appEventRecord.preFoldStatus = combineScreenStatus;
184 appEventRecord.foldStatus = combineScreenStatus;
185 appEventRecord.happenTime = static_cast<int64_t>(event->happenTime_);
186
187 if (combineScreenStatus != UNKNOWN_STATUS) {
188 dbHelper_->AddAppEvent(appEventRecord);
189 CountLifeCycleDuration(appEventRecord);
190 }
191 }
192
ProcessSceenStatusChangedEvent(std::shared_ptr<SysEvent> event)193 void FoldEventCacher::ProcessSceenStatusChangedEvent(std::shared_ptr<SysEvent> event)
194 {
195 int preFoldStatus = GetScreenFoldStatus(foldStatus_, vhMode_, GetWindowModeOfFocusedApp());
196 std::string eventName = event->eventName_;
197 if (eventName == FoldStateChangeEventSpace::EVENT_NAME) {
198 UpdateFoldStatus(static_cast<int32_t>(event->GetEventIntValue(FoldStateChangeEventSpace::KEY_OF_NEXT_STATUS)));
199 } else if (eventName == VhModeChangeEventSpace::EVENT_NAME) {
200 UpdateVhMode(static_cast<int32_t>(event->GetEventIntValue(VhModeChangeEventSpace::KEY_OF_MODE)));
201 } else {
202 UpdateMultiWindowInfos(
203 static_cast<uint8_t>(event->GetEventIntValue(MultiWindowChangeEventSpace::KEY_OF_MULTI_NUM)),
204 event->GetEventValue(MultiWindowChangeEventSpace::KEY_OF_MULTI_WINDOW));
205 }
206 if (!focusedAppPair_.second) {
207 return;
208 }
209 AppEventRecord appEventRecord;
210 appEventRecord.rawid = FoldEventId::EVENT_SCREEN_STATUS_CHANGED;
211 appEventRecord.ts = static_cast<int64_t>(TimeUtil::GetBootTimeMs());
212 appEventRecord.bundleName = focusedAppPair_.first;
213 appEventRecord.preFoldStatus = preFoldStatus;
214 appEventRecord.foldStatus = GetScreenFoldStatus(foldStatus_, vhMode_, GetWindowModeOfFocusedApp());
215 appEventRecord.happenTime = static_cast<int64_t>(event->happenTime_);
216 if ((appEventRecord.foldStatus != UNKNOWN_STATUS)
217 && appEventRecord.preFoldStatus != appEventRecord.foldStatus) {
218 dbHelper_->AddAppEvent(appEventRecord);
219 }
220 }
221
ProcessCountDurationEvent(AppEventRecord & appEventRecord,std::map<int,uint64_t> & durations)222 void FoldEventCacher::ProcessCountDurationEvent(AppEventRecord& appEventRecord, std::map<int, uint64_t>& durations)
223 {
224 AppEventRecord newRecord;
225 newRecord.rawid = FoldEventId::EVENT_COUNT_DURATION;
226 newRecord.ts = static_cast<int64_t>(TimeUtil::GetBootTimeMs());
227 newRecord.bundleName = appEventRecord.bundleName;
228 newRecord.preFoldStatus = appEventRecord.preFoldStatus;
229 newRecord.foldStatus = appEventRecord.foldStatus;
230 newRecord.happenTime = static_cast<int64_t>(TimeUtil::GenerateTimestamp()) / MILLISEC_TO_MICROSEC;
231 dbHelper_->AddAppEvent(newRecord, durations);
232 }
233
CountLifeCycleDuration(AppEventRecord & appEventRecord)234 void FoldEventCacher::CountLifeCycleDuration(AppEventRecord& appEventRecord)
235 {
236 std::string bundleName = appEventRecord.bundleName;
237 int startIndex = GetStartIndex(bundleName);
238 int64_t dayStartTime = TimeUtil::Get0ClockStampMs();
239 std::vector<AppEventRecord> records;
240 dbHelper_->QueryAppEventRecords(startIndex, dayStartTime, bundleName, records);
241 std::map<int, uint64_t> durations;
242 CalCulateDuration(dayStartTime, records, durations);
243 ProcessCountDurationEvent(appEventRecord, durations);
244 }
245
CalCulateDuration(uint64_t dayStartTime,std::vector<AppEventRecord> & records,std::map<int,uint64_t> & durations)246 void FoldEventCacher::CalCulateDuration(uint64_t dayStartTime, std::vector<AppEventRecord>& records,
247 std::map<int, uint64_t>& durations)
248 {
249 if (records.empty()) {
250 return;
251 }
252 auto it = records.begin();
253 // app cross 0 clock
254 if (it->rawid == FoldEventId::EVENT_APP_EXIT || it->rawid == FoldEventId::EVENT_SCREEN_STATUS_CHANGED) {
255 int foldStatus = (it->rawid == FoldEventId::EVENT_APP_EXIT) ? it->foldStatus : it->preFoldStatus;
256 Accumulative(foldStatus, (it->happenTime - dayStartTime), durations);
257 }
258 auto preIt = it;
259 // app running from 0 clock to current time, calculate durations
260 it++;
261 for (; it != records.end(); it++) {
262 if (CanCalcDuration(preIt->rawid, it->rawid)) {
263 uint64_t duration = (it->ts > preIt->ts) ? static_cast<uint64_t>(it->ts - preIt->ts) : 0;
264 Accumulative(preIt->foldStatus, duration, durations);
265 }
266 preIt = it;
267 }
268 }
269
CanCalcDuration(uint32_t preId,uint32_t id)270 bool FoldEventCacher::CanCalcDuration(uint32_t preId, uint32_t id)
271 {
272 if (id == FoldEventId::EVENT_APP_EXIT && preId == FoldEventId::EVENT_APP_START) {
273 return true;
274 }
275 if (id == FoldEventId::EVENT_SCREEN_STATUS_CHANGED && preId == FoldEventId::EVENT_APP_START) {
276 return true;
277 }
278 if (id == FoldEventId::EVENT_SCREEN_STATUS_CHANGED && preId == FoldEventId::EVENT_SCREEN_STATUS_CHANGED) {
279 return true;
280 }
281 if (id == FoldEventId::EVENT_APP_EXIT && preId == FoldEventId::EVENT_SCREEN_STATUS_CHANGED) {
282 return true;
283 }
284 return false;
285 }
286
Accumulative(int foldStatus,uint64_t duration,std::map<int,uint64_t> & durations)287 void FoldEventCacher::Accumulative(int foldStatus, uint64_t duration, std::map<int, uint64_t>& durations)
288 {
289 if (durations.find(foldStatus) == durations.end()) {
290 durations[foldStatus] = duration;
291 } else {
292 durations[foldStatus] += duration;
293 }
294 }
295
GetStartIndex(const std::string & bundleName)296 int FoldEventCacher::GetStartIndex(const std::string& bundleName)
297 {
298 return dbHelper_->QueryRawEventIndex(bundleName, FoldEventId::EVENT_APP_START);
299 }
300
UpdateFoldStatus(int32_t status)301 void FoldEventCacher::UpdateFoldStatus(int32_t status)
302 {
303 foldStatus_ = status;
304 }
305
UpdateVhMode(int32_t mode)306 void FoldEventCacher::UpdateVhMode(int32_t mode)
307 {
308 vhMode_ = mode;
309 }
310
UpdateMultiWindowInfos(uint8_t multiNum,const std::string & multiWindow)311 void FoldEventCacher::UpdateMultiWindowInfos(uint8_t multiNum, const std::string& multiWindow)
312 {
313 std::vector<std::string> infos;
314 // for example multiWindow = "PKG: test_bundle, MODE: 1; PKG: test_bundle1, MODE: 2"
315 StringUtil::SplitStr(multiWindow, ";", infos);
316 if (infos.size() != multiNum) {
317 HIVIEW_LOGE("invalid multiWindowInfo multiNum=%{public}u, size=%{public}zu", multiNum, infos.size());
318 return;
319 }
320 multiWindowInfos_.clear();
321 for (const auto& info : infos) {
322 std::string bundleName = StringUtil::TrimStr(StringUtil::GetMidSubstr(info, "PKG:", ","));
323 std::string modeStr = StringUtil::TrimStr(StringUtil::GetRightSubstr(info, "MODE:"));
324 int32_t mode = 0;
325 StringUtil::ConvertStringTo<int32_t>(modeStr, mode);
326 if (!bundleName.empty() && mode > 0) {
327 multiWindowInfos_[bundleName] = mode;
328 } else {
329 HIVIEW_LOGE("invalid windowInfo mode=%{public}d", mode);
330 }
331 }
332 }
333
GetWindowModeOfFocusedApp()334 int32_t FoldEventCacher::GetWindowModeOfFocusedApp()
335 {
336 std::string bundleName = focusedAppPair_.first;
337 if (multiWindowInfos_.find(bundleName) != multiWindowInfos_.end()) {
338 return multiWindowInfos_[bundleName];
339 }
340 // if not in the multiple window informations, return full screen.
341 return WINDOW_MODE_FULL;
342 }
343 } // namespace HiviewDFX
344 } // namespace OHOS
345