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 "fold_event_cacher.h"
17 
18 #include "bundle_mgr_client.h"
19 #include "display_manager.h"
20 #include "hiview_logger.h"
21 #include "iremote_object.h"
22 #include "iservice_registry.h"
23 #include "system_ability_definition.h"
24 #include "time_util.h"
25 #include "usage_event_common.h"
26 
27 namespace OHOS {
28 namespace HiviewDFX {
29 DEFINE_LOG_TAG("FoldEventCacher");
30 namespace {
31 constexpr int MAX_FOREGROUND_APPS_SIZE = 10;
32 constexpr int UNKNOWN_FOLD_STATUS = -1;
33 constexpr int ONE_HOUR_INTERVAL = 3600;
34 constexpr int MILLISEC_TO_MICROSEC = 1000;
35 
GetAppManagerService()36 sptr<AppExecFwk::IAppMgr> GetAppManagerService()
37 {
38     auto systemAbilityManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
39     if (systemAbilityManager == nullptr) {
40         HIVIEW_LOGI("failed to get samgr");
41         return nullptr;
42     }
43     sptr<IRemoteObject> remoteObject = systemAbilityManager->GetSystemAbility(APP_MGR_SERVICE_ID);
44     if (remoteObject == nullptr) {
45         HIVIEW_LOGI("failed to get app manager service");
46         return nullptr;
47     }
48     return iface_cast<AppExecFwk::IAppMgr>(remoteObject);
49 }
50 
GetForegroundApplications()51 std::vector<AppExecFwk::AppStateData> GetForegroundApplications()
52 {
53     sptr<AppExecFwk::IAppMgr> appManager = GetAppManagerService();
54     std::vector<AppExecFwk::AppStateData> fgList;
55     if (appManager == nullptr) {
56         HIVIEW_LOGI("appManager iface_cast is nullptr");
57         return fgList;
58     }
59     int32_t errcode = appManager->GetForegroundApplications(fgList);
60     size_t fgListSize = fgList.size();
61     HIVIEW_LOGI("errcode=%{public}d,fgListSize=%{public}zu", errcode, fgListSize);
62     return fgList;
63 }
64 
GetAppVersion(const std::string & bundleName)65 std::string GetAppVersion(const std::string& bundleName)
66 {
67     AppExecFwk::BundleInfo info;
68     AppExecFwk::BundleMgrClient client;
69     if (!client.GetBundleInfo(bundleName, AppExecFwk::BundleFlag::GET_BUNDLE_DEFAULT, info,
70         AppExecFwk::Constants::ALL_USERID)) {
71         HIVIEW_LOGE("Failed to get the version of the bundle");
72         return "";
73     }
74     return info.versionName;
75 }
76 
GetCombineScreenStatus(int foldStatus,int vhMode)77 int GetCombineScreenStatus(int foldStatus, int vhMode)
78 {
79     if (foldStatus == 1 && vhMode == 1) { // foldStatus: 1-expand status
80         return ScreenFoldStatus::EXPAND_LANDSCAPE_STATUS;
81     }
82     if (foldStatus == 1 && vhMode == 0) {
83         return ScreenFoldStatus::EXPAND_PORTRAIT_STATUS;
84     }
85     if ((foldStatus == 2 || foldStatus == 3) && vhMode == 1) { // foldStatus: 2-fold status 3- half fold status
86         return ScreenFoldStatus::FOLD_LANDSCAPE_STATUS;
87     }
88     if ((foldStatus == 2 || foldStatus == 3) && vhMode == 0) { // foldStatus: 2-fold status 3- half fold status
89         return ScreenFoldStatus::FOLD_PORTRAIT_STATUS;
90     }
91     return UNKNOWN_FOLD_STATUS;
92 }
93 } // namespace
94 
FoldEventCacher(const std::string & workPath)95 FoldEventCacher::FoldEventCacher(const std::string& workPath)
96 {
97     timelyStart_ = TimeUtil::GetBootTimeMs();
98     dbHelper_ = std::make_unique<FoldAppUsageDbHelper>(workPath);
99 
100     foldStatus_ = static_cast<int>(OHOS::Rosen::DisplayManager::GetInstance().GetFoldStatus());
101     auto display = OHOS::Rosen::DisplayManager::GetInstance().GetDefaultDisplay();
102     if (display != nullptr) {
103         int orientation = static_cast<int>(display->GetRotation());
104         if (orientation == 0 || orientation == 2) { // 0-Portrait 2-portrait_inverted
105             vhMode_ = 0; // 0-Portrait
106         } else {
107             vhMode_ = 1; // 1-landscape
108         }
109     }
110     HIVIEW_LOGI("foldStatus=%{public}d,vhMode=%{public}d", foldStatus_, vhMode_);
111     auto fgList = GetForegroundApplications();
112     for (const auto& appData : fgList) {
113         if (FoldAppUsageEventSpace::SCENEBOARD_BUNDLE_NAME == appData.bundleName) {
114             continue;
115         }
116         foregroundApps_[appData.bundleName] = GetAppVersion(appData.bundleName);
117     }
118 }
119 
TimeOut()120 void FoldEventCacher::TimeOut()
121 {
122     uint64_t bootTime = TimeUtil::GetBootTimeMs();
123     uint64_t timeInterval = bootTime - timelyStart_;
124     if (timeInterval < static_cast<uint64_t>(ONE_HOUR_INTERVAL * TimeUtil::SEC_TO_MILLISEC)) {
125         return;
126     }
127     auto fgList = GetForegroundApplications();
128     for (const auto& appData : fgList) {
129         if (FoldAppUsageEventSpace::SCENEBOARD_BUNDLE_NAME == appData.bundleName) {
130             continue;
131         }
132         auto it = foregroundApps_.find(appData.bundleName);
133         if (it == foregroundApps_.end()) {
134             AppEventRecord appEventRecord;
135             appEventRecord.rawid = FoldEventId::EVENT_APP_START;
136             appEventRecord.ts = static_cast<int64_t>(TimeUtil::GetBootTimeMs());
137             appEventRecord.bundleName = appData.bundleName;
138             int combineScreenStatus = GetCombineScreenStatus(foldStatus_, vhMode_);
139             appEventRecord.preFoldStatus = combineScreenStatus;
140             appEventRecord.foldStatus = combineScreenStatus;
141             appEventRecord.versionName = GetAppVersion(appData.bundleName);
142             appEventRecord.happenTime = static_cast<int64_t>(TimeUtil::GenerateTimestamp()) / MILLISEC_TO_MICROSEC;
143             if (combineScreenStatus != UNKNOWN_FOLD_STATUS) {
144                 dbHelper_->AddAppEvent(appEventRecord);
145             }
146         }
147     }
148     timelyStart_ = bootTime;
149 }
150 
ProcessEvent(std::shared_ptr<SysEvent> event)151 void FoldEventCacher::ProcessEvent(std::shared_ptr<SysEvent> event)
152 {
153     if (dbHelper_ == nullptr) {
154         HIVIEW_LOGI("dbHelper is nulptr");
155         return;
156     }
157     std::string bundleName = event->GetEventValue(AppEventSpace::KEY_OF_BUNDLE_NAME);
158     if (FoldAppUsageEventSpace::SCENEBOARD_BUNDLE_NAME == bundleName) {
159         return;
160     }
161     AppEventRecord appEventRecord;
162     std::string eventName = event->eventName_;
163     if (eventName == AppEventSpace::FOREGROUND_EVENT_NAME) {
164         ProcessForegroundEvent(event, appEventRecord);
165     } else if (eventName == AppEventSpace::BACKGROUND_EVENT_NAME) {
166         ProcessBackgroundEvent(event, appEventRecord);
167         CountLifeCycleDuration(appEventRecord);
168     } else if (eventName == FoldStateChangeEventSpace::EVENT_NAME || eventName == VhModeChangeEventSpace::EVENT_NAME) {
169         ProcessSceenStatusChangedEvent(event);
170     } else {
171         HIVIEW_LOGI("event can not process");
172         return;
173     }
174 }
175 
ProcessForegroundEvent(std::shared_ptr<SysEvent> event,AppEventRecord & appEventRecord)176 void FoldEventCacher::ProcessForegroundEvent(std::shared_ptr<SysEvent> event, AppEventRecord& appEventRecord)
177 {
178     appEventRecord.rawid = FoldEventId::EVENT_APP_START;
179     appEventRecord.ts = static_cast<int64_t>(TimeUtil::GetBootTimeMs());
180     appEventRecord.bundleName = event->GetEventValue(AppEventSpace::KEY_OF_BUNDLE_NAME);
181     int combineScreenStatus = GetCombineScreenStatus(foldStatus_, vhMode_);
182     appEventRecord.preFoldStatus = combineScreenStatus;
183     appEventRecord.foldStatus = combineScreenStatus;
184     appEventRecord.versionName = event->GetEventValue(AppEventSpace::KEY_OF_VERSION_NAME);
185     appEventRecord.happenTime = static_cast<int64_t>(event->happenTime_);
186 
187     if (combineScreenStatus != UNKNOWN_FOLD_STATUS) {
188         dbHelper_->AddAppEvent(appEventRecord);
189     }
190     if (foregroundApps_.size() >= MAX_FOREGROUND_APPS_SIZE) {
191         foregroundApps_.clear();
192     }
193     foregroundApps_[appEventRecord.bundleName] = appEventRecord.versionName;
194 }
195 
ProcessBackgroundEvent(std::shared_ptr<SysEvent> event,AppEventRecord & appEventRecord)196 void FoldEventCacher::ProcessBackgroundEvent(std::shared_ptr<SysEvent> event, AppEventRecord& appEventRecord)
197 {
198     appEventRecord.rawid = FoldEventId::EVENT_APP_EXIT;
199     appEventRecord.ts = static_cast<int64_t>(TimeUtil::GetBootTimeMs());
200     appEventRecord.bundleName = event->GetEventValue(AppEventSpace::KEY_OF_BUNDLE_NAME);
201     int combineScreenStatus = GetCombineScreenStatus(foldStatus_, vhMode_);
202     appEventRecord.preFoldStatus = combineScreenStatus;
203     appEventRecord.foldStatus = combineScreenStatus;
204     appEventRecord.versionName = event->GetEventValue(AppEventSpace::KEY_OF_VERSION_NAME);
205     appEventRecord.happenTime = static_cast<int64_t>(event->happenTime_);
206 
207     if (combineScreenStatus != UNKNOWN_FOLD_STATUS) {
208         dbHelper_->AddAppEvent(appEventRecord);
209     }
210     auto it = foregroundApps_.find(appEventRecord.bundleName);
211     if (it != foregroundApps_.end()) {
212         foregroundApps_.erase(it);
213     }
214 }
215 
ProcessSceenStatusChangedEvent(std::shared_ptr<SysEvent> event)216 void FoldEventCacher::ProcessSceenStatusChangedEvent(std::shared_ptr<SysEvent> event)
217 {
218     int preFoldStatus = GetCombineScreenStatus(foldStatus_, vhMode_);
219     std::string eventName = event->eventName_;
220     if (eventName == FoldStateChangeEventSpace::EVENT_NAME) {
221         int nextFoldStatus = event->GetEventIntValue(FoldStateChangeEventSpace::KEY_OF_NEXT_STATUS);
222         UpdateFoldStatus(nextFoldStatus);
223     } else {
224         int nextMode = event->GetEventIntValue(VhModeChangeEventSpace::KEY_OF_MODE);
225         UpdateVhMode(nextMode);
226     }
227     for (auto it = foregroundApps_.begin(); it != foregroundApps_.end(); it++) {
228         AppEventRecord appEventRecord;
229         appEventRecord.rawid = FoldEventId::EVENT_SCREEN_STATUS_CHANGED;
230         appEventRecord.ts = static_cast<int64_t>(TimeUtil::GetBootTimeMs());
231         appEventRecord.bundleName = it->first;
232         appEventRecord.preFoldStatus = preFoldStatus;
233         appEventRecord.foldStatus = GetCombineScreenStatus(foldStatus_, vhMode_);
234         appEventRecord.versionName = it->second;
235         appEventRecord.happenTime = static_cast<int64_t>(event->happenTime_);
236         if ((appEventRecord.foldStatus != UNKNOWN_FOLD_STATUS)
237             && appEventRecord.preFoldStatus != appEventRecord.foldStatus) {
238             dbHelper_->AddAppEvent(appEventRecord);
239         }
240     }
241 }
242 
GetFoldStatusDuration(const int foldStatus,std::map<int,uint64_t> & durations)243 int64_t FoldEventCacher::GetFoldStatusDuration(const int foldStatus, std::map<int, uint64_t>& durations)
244 {
245     auto it = durations.find(foldStatus);
246     if (it == durations.end()) {
247         return 0;
248     }
249     return static_cast<int64_t>(it->second);
250 }
251 
ProcessCountDurationEvent(AppEventRecord & appEventRecord,std::map<int,uint64_t> & durations)252 void FoldEventCacher::ProcessCountDurationEvent(AppEventRecord& appEventRecord, std::map<int, uint64_t>& durations)
253 {
254     AppEventRecord newRecord;
255     newRecord.rawid = FoldEventId::EVENT_COUNT_DURATION;
256     newRecord.ts = static_cast<int64_t>(TimeUtil::GetBootTimeMs());
257     newRecord.bundleName = appEventRecord.bundleName;
258     newRecord.preFoldStatus = appEventRecord.preFoldStatus;
259     newRecord.foldStatus = appEventRecord.foldStatus;
260     newRecord.versionName = appEventRecord.versionName;
261     newRecord.happenTime = static_cast<int64_t>(TimeUtil::GenerateTimestamp()) / MILLISEC_TO_MICROSEC;
262     newRecord.foldPortraitTime = GetFoldStatusDuration(ScreenFoldStatus::FOLD_PORTRAIT_STATUS, durations);
263     newRecord.foldLandscapeTime = GetFoldStatusDuration(ScreenFoldStatus::FOLD_LANDSCAPE_STATUS, durations);
264     newRecord.expandPortraitTime = GetFoldStatusDuration(ScreenFoldStatus::EXPAND_PORTRAIT_STATUS, durations);
265     newRecord.expandLandscapeTime = GetFoldStatusDuration(ScreenFoldStatus::EXPAND_LANDSCAPE_STATUS, durations);
266     dbHelper_->AddAppEvent(newRecord);
267 }
268 
CountLifeCycleDuration(AppEventRecord & appEventRecord)269 void FoldEventCacher::CountLifeCycleDuration(AppEventRecord& appEventRecord)
270 {
271     std::string bundleName = appEventRecord.bundleName;
272     int startIndex = GetStartIndex(bundleName);
273     int64_t dayStartTime = TimeUtil::Get0ClockStampMs();
274     std::vector<AppEventRecord> records;
275     dbHelper_->QueryAppEventRecords(startIndex, dayStartTime, bundleName, records);
276     std::map<int, uint64_t> durations;
277     CalCulateDuration(dayStartTime, records, durations);
278     ProcessCountDurationEvent(appEventRecord, durations);
279 }
280 
CalCulateDuration(uint64_t dayStartTime,std::vector<AppEventRecord> & records,std::map<int,uint64_t> & durations)281 void FoldEventCacher::CalCulateDuration(uint64_t dayStartTime, std::vector<AppEventRecord>& records,
282     std::map<int, uint64_t>& durations)
283 {
284     if (records.empty()) {
285         return;
286     }
287     auto it = records.begin();
288     // app cross 0 clock
289     if (it->rawid == FoldEventId::EVENT_APP_EXIT || it->rawid == FoldEventId::EVENT_SCREEN_STATUS_CHANGED) {
290         int foldStatus = (it->rawid == FoldEventId::EVENT_APP_EXIT) ? it->foldStatus : it->preFoldStatus;
291         Accumulative(foldStatus, (it->happenTime - dayStartTime), durations);
292     }
293     auto preIt = it;
294     // app running from 0 clock to current time, calculate durations
295     it++;
296     for (; it != records.end(); it++) {
297         if (CanCalcDuration(preIt->rawid, it->rawid)) {
298             uint64_t duration = (it->ts > preIt->ts) ? static_cast<uint64_t>(it->ts - preIt->ts) : 0;
299             Accumulative(preIt->foldStatus, duration, durations);
300         }
301         preIt = it;
302     }
303 }
304 
CanCalcDuration(uint32_t preId,uint32_t id)305 bool FoldEventCacher::CanCalcDuration(uint32_t preId, uint32_t id)
306 {
307     if (id == FoldEventId::EVENT_APP_EXIT && preId == FoldEventId::EVENT_APP_START) {
308         return true;
309     }
310     if (id == FoldEventId::EVENT_SCREEN_STATUS_CHANGED && preId == FoldEventId::EVENT_APP_START) {
311         return true;
312     }
313     if (id == FoldEventId::EVENT_SCREEN_STATUS_CHANGED && preId == FoldEventId::EVENT_SCREEN_STATUS_CHANGED) {
314         return true;
315     }
316     if (id == FoldEventId::EVENT_APP_EXIT && preId == FoldEventId::EVENT_SCREEN_STATUS_CHANGED) {
317         return true;
318     }
319     return false;
320 }
321 
Accumulative(int foldStatus,uint64_t duration,std::map<int,uint64_t> & durations)322 void FoldEventCacher::Accumulative(int foldStatus, uint64_t duration, std::map<int, uint64_t>& durations)
323 {
324     if (durations.find(foldStatus) == durations.end()) {
325         durations[foldStatus] = duration;
326     } else {
327         durations[foldStatus] += duration;
328     }
329 }
330 
GetStartIndex(const std::string & bundleName)331 int FoldEventCacher::GetStartIndex(const std::string& bundleName)
332 {
333     return dbHelper_->QueryRawEventIndex(bundleName, FoldEventId::EVENT_APP_START);
334 }
335 
UpdateFoldStatus(int status)336 void FoldEventCacher::UpdateFoldStatus(int status)
337 {
338     foldStatus_ = status;
339 }
340 
UpdateVhMode(int mode)341 void FoldEventCacher::UpdateVhMode(int mode)
342 {
343     vhMode_ = mode;
344 }
345 
346 } // namespace HiviewDFX
347 } // namespace OHOS
348