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 #ifndef OHOS_ROSEN_SCREEN_EVENT_TRACKER_H
17 #define OHOS_ROSEN_SCREEN_EVENT_TRACKER_H
18 
19 #include <iomanip>
20 #include <list>
21 #include <mutex>
22 #include <sstream>
23 #include <string>
24 #include <vector>
25 
26 #include "window_manager_hilog.h"
27 
28 namespace OHOS {
29 namespace Rosen {
30 const int32_t OUTPUT_FREQ = 1; // 1Hz
31 const int32_t MAX_CAPACITY = 6;
32 
33 struct TrackInfo {
34     std::string info;
35     std::chrono::system_clock::time_point timestamp;
36 };
37 
38 class EventTracker {
39 public:
40     void RecordEvent(std::string info = "")
41     {
42         std::lock_guard<std::mutex> lock(mutex_);
43         recordInfos_.push_back({info, std::chrono::system_clock::now()});
44     }
45 
46     void RecordBoundsEvent(std::string info = "")
47     {
48         std::lock_guard<std::mutex> lock(mutex_);
49         if (recordBoundsInfos_.size() >= MAX_CAPACITY) {
50             recordBoundsInfos_.pop_front();
51         }
52         recordBoundsInfos_.push_back({info, std::chrono::system_clock::now()});
53     }
54 
ClearAllRecordedEvents()55     void ClearAllRecordedEvents()
56     {
57         std::lock_guard<std::mutex> lock(mutex_);
58         recordInfos_.clear();
59         recordBoundsInfos_.clear();
60     }
61 
LogWarningAllInfos()62     void LogWarningAllInfos() const
63     {
64         auto now = std::chrono::system_clock::now();
65         if (std::chrono::duration_cast<std::chrono::seconds>(now - lastOutputTime_).count() < OUTPUT_FREQ) {
66             return ; // Output too frequent. Try again later.
67         }
68         lastOutputTime_ = now;
69 
70         std::lock_guard<std::mutex> lock(mutex_);
71         for (const auto& info : recordInfos_) {
72             TLOGW(WmsLogTag::DMS, "[%{public}s]: %{public}s",
73                 formatTimestamp(info.timestamp).c_str(), info.info.c_str());
74         }
75 
76         for (const auto& info : recordBoundsInfos_) {
77             TLOGW(WmsLogTag::DMS, "[%{public}s]: %{public}s",
78                 formatTimestamp(info.timestamp).c_str(), info.info.c_str());
79         }
80     }
81 
formatTimestamp(const std::chrono::system_clock::time_point & timePoint)82     std::string formatTimestamp(const std::chrono::system_clock::time_point& timePoint) const
83     {
84         const int32_t WIDTH_TIME = 2;
85         const int32_t WIDTH_TIME_MS = 3;
86         const int32_t TIME_CONVERT_MS = 1000;
87         const char DEFAULT_CHAR = '0';
88         auto time = std::chrono::system_clock::to_time_t(timePoint);
89         std::tm localTime;
90         localtime_r(&time, &localTime);
91         auto timeMs = std::chrono::duration_cast<std::chrono::milliseconds>(
92             timePoint.time_since_epoch()) % TIME_CONVERT_MS;
93 
94         std::ostringstream oss;
95         oss << std::setfill(DEFAULT_CHAR)
96             << std::setw(WIDTH_TIME) << (localTime.tm_mon + 1) << '-'
97             << std::setw(WIDTH_TIME) << localTime.tm_mday << ' '
98             << std::setw(WIDTH_TIME) << localTime.tm_hour << ':'
99             << std::setw(WIDTH_TIME) << localTime.tm_min << ':'
100             << std::setw(WIDTH_TIME) << localTime.tm_sec << '.'
101             << std::setw(WIDTH_TIME_MS) << timeMs.count();
102         return oss.str();
103     }
104 
GetRecordInfos()105     const std::vector<TrackInfo>& GetRecordInfos()
106     {
107         std::lock_guard<std::mutex> lock(mutex_);
108         allRecordInfos_ = recordInfos_;
109         for (auto info : recordBoundsInfos_) {
110             allRecordInfos_.emplace_back(info);
111         }
112         return allRecordInfos_;
113     }
114 
115 private:
116     mutable std::mutex mutex_;
117     mutable std::chrono::system_clock::time_point lastOutputTime_;
118     std::vector<TrackInfo> recordInfos_;
119     std::list<TrackInfo> recordBoundsInfos_;
120     std::vector<TrackInfo> allRecordInfos_;
121 };
122 
123 
124 } // Rosen
125 } // OHOS
126 #endif // OHOS_ROSEN_SCREEN_EVENT_TRACKER_H