• 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 "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