1/*
2 * Copyright (c) 2022 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 "perform_reporter.h"
17
18#include <hisysevent.h>
19
20#include "window_manager_hilog.h"
21
22namespace OHOS {
23namespace Rosen {
24namespace {
25constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_DISPLAY, "PerformReporter"};
26}
27WM_IMPLEMENT_SINGLE_INSTANCE(WindowInfoReporter)
28
29constexpr char EVENT_KEY_BUNDLE_NAME[] = "BUNDLE_NAME";
30constexpr char EVENT_KEY_WINDOW_NAME[] = "WINDOW_NAME";
31constexpr char EVENT_KEY_MISSION_ID[] = "MISSION_ID";
32constexpr char EVENT_KEY_TIMESTAMP[] = "TIMESTAMP";
33
34/**
35 * @brief Construct a new Perform Reporter:: Perform Reporter object
36 *
37 * @param tag A tag that in report string
38 * @param timeSpiltsMs The time-interval that data statistic, details look up the comments in function body
39 * @param reportInterval Report data after reportInterval round start-end
40 */
41PerformReporter::PerformReporter(const std::string& tag,
42    const std::vector<int64_t>& timeSpiltsMs, uint32_t reportInterval)
43    : tag_(tag), reportInterval_(reportInterval)
44{
45    // re-organ data struct
46    // a, b, c, d -->
47    // (0, a] : cnt=0, (a, b] : cnt=0, (b, c] : cnt=0, (c, d] : cnt=0
48    for (auto split : timeSpiltsMs) {
49        timeSplitCount_[split] = 0;
50    }
51    // (d, +limit] : cnt=0
52    timeSplitCount_[BARRIER] = 0;
53    totalCount_ = 0;
54}
55
56void PerformReporter::start()
57{
58    startTime_ = std::chrono::steady_clock::now();
59}
60
61void PerformReporter::end()
62{
63    auto currentTime = std::chrono::steady_clock::now();
64    int64_t costTime = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - startTime_).count();
65
66    count(costTime);
67
68    bool repSucc = report();
69    if (repSucc) {
70        clear();
71    }
72}
73
74bool PerformReporter::report()
75{
76    if (totalCount_ < reportInterval_) {
77        return false;
78    }
79
80    std::ostringstream oss;
81    oss << tag_ << ": ";
82    auto maxSplit = 0;
83    for (const auto& iter: timeSplitCount_) {
84        if (iter.first != BARRIER) {
85            oss << "BELLOW" << iter.first << "(ms): " << iter.second << ", ";
86            maxSplit = iter.first;
87        }
88    }
89    oss << "ABOVE" << maxSplit << "(ms): " << timeSplitCount_[BARRIER];
90
91    int32_t ret = HiSysEventWrite(
92        OHOS::HiviewDFX::HiSysEvent::Domain::WINDOW_MANAGER, tag_,
93        OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, "MSG", oss.str());
94    WLOGI("Write HiSysEvent ret:%{public}d", ret);
95    return ret == 0;
96}
97
98void PerformReporter::count(int64_t costTime)
99{
100    totalCount_++;
101    for (auto& iter: timeSplitCount_) {
102        if (costTime <= iter.first) {
103            iter.second++;
104            break;
105        }
106    }
107
108    std::ostringstream oss;
109    oss << tag_ << " cost " << costTime << "ms, total count " << totalCount_;
110    WLOGI("%{public}s", oss.str().c_str());
111}
112
113void PerformReporter::clear()
114{
115    totalCount_ = 0;
116    for (auto& iter: timeSplitCount_) {
117        iter.second = 0;
118    }
119}
120
121std::string WindowInfoReporter::GetMsgString(const FullInfoMap& infoMap)
122{
123    if (infoMap.empty()) {
124        return "";
125    }
126    std::ostringstream oss;
127    oss << "{";
128    for (auto& bundleInfos : infoMap) {
129        if (bundleInfos.second.empty()) {
130            continue;
131        }
132        oss << "{";
133        for (auto& packageInfo : bundleInfos.second) {
134            oss << "BUNDLE_NAME:" << bundleInfos.first << ",";
135            oss << "ABILITY_NAME:" << packageInfo.first << ",";
136            oss << "COUNT:" << packageInfo.second;
137        }
138        oss << "},";
139    }
140    oss << "};";
141    return oss.str();
142}
143
144std::string WindowInfoReporter::GetMsgString(const BundleNameMap& infoMap)
145{
146    if (infoMap.empty()) {
147        return "";
148    }
149    std::ostringstream oss;
150    oss << "{";
151    for (auto& bundleInfo : infoMap) {
152        oss << "{";
153        oss << "BUNDLE_NAME:" << bundleInfo.first << ",";
154        oss << "COUNT:" << bundleInfo.second;
155        oss << "},";
156    }
157    oss << "};";
158    return oss.str();
159}
160
161void WindowInfoReporter::InsertCreateReportInfo(const std::string& bundleName)
162{
163    UpdateReportInfo(windowCreateReportInfos_, bundleName);
164}
165
166void WindowInfoReporter::InsertShowReportInfo(const std::string& bundleName)
167{
168    UpdateReportInfo(windowShowReportInfos_, bundleName);
169}
170
171void WindowInfoReporter::InsertHideReportInfo(const std::string& bundleName)
172{
173    UpdateReportInfo(windowHideReportInfos_, bundleName);
174}
175
176void WindowInfoReporter::InsertDestroyReportInfo(const std::string& bundleName)
177{
178    UpdateReportInfo(windowDestoryReportInfos_, bundleName);
179}
180
181void WindowInfoReporter::InsertNavigationBarReportInfo(const std::string& bundleName, const std::string& packageName)
182{
183    UpdateReportInfo(windowNavigationBarReportInfos_, bundleName, packageName);
184}
185
186void WindowInfoReporter::UpdateReportInfo(FullInfoMap& infoMap,
187    const std::string& bundleName, const std::string& packageName)
188{
189    if (bundleName.empty() || packageName.empty()) {
190        return;
191    }
192    std::lock_guard<std::mutex> lock(mtx_);
193    auto iter = infoMap.find(bundleName);
194    if (iter == infoMap.end()) {
195        std::map<std::string, uint32_t> infos;
196        infos.insert(std::make_pair(packageName, 1));
197        infoMap.insert(std::make_pair(bundleName, infos));
198        return;
199    }
200
201    auto countPairIter = iter->second.find(packageName);
202    if (countPairIter == iter->second.end()) {
203        iter->second.insert(std::make_pair(packageName, 1));
204        return;
205    }
206    infoMap[bundleName][packageName]++;
207}
208
209void WindowInfoReporter::UpdateReportInfo(BundleNameMap& infoMap, const std::string& bundleName)
210{
211    if (bundleName.empty()) {
212        return;
213    }
214    std::lock_guard<std::mutex> lock(mtx_);
215    auto iter = infoMap.find(bundleName);
216    if (iter == infoMap.end()) {
217        infoMap.insert(std::make_pair(bundleName, 1));
218        return;
219    }
220    infoMap[bundleName]++;
221}
222
223void WindowInfoReporter::ReportBackButtonInfoImmediately()
224{
225    Report("WM_REPORT_BACK_KEYEVENT", "Click Back Button");
226}
227
228void WindowInfoReporter::ReportZeroOpacityInfoImmediately(const std::string& bundleName, const std::string& packageName)
229{
230    if (bundleName.empty()) {
231        return;
232    }
233    std::ostringstream oss;
234    oss << "{ PROCESS_NAME:" << bundleName.c_str() << ", PACKAGE_NAME:" << "" << packageName.c_str() << " }";
235    Report("WM_REPORT_WINDOW_OPACITY_ZERO", oss.str());
236}
237
238void WindowInfoReporter::ReportStartWindow(const std::string& bundleName, const std::string& windowName)
239{
240    std::string eventName = "START_WINDOW";
241    int32_t ret = HiSysEventWrite(
242        OHOS::HiviewDFX::HiSysEvent::Domain::WINDOW_MANAGER, eventName,
243        OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
244        EVENT_KEY_BUNDLE_NAME, bundleName,
245        EVENT_KEY_WINDOW_NAME, windowName);
246    if (ret != 0) {
247        WLOGFE("Write HiSysEvent error, ret:%{public}d", ret);
248    }
249}
250
251void WindowInfoReporter::ReportRecordedInfos()
252{
253    std::lock_guard<std::mutex> lock(mtx_);
254    WLOGFD("----Report HiSysEvent write all-----");
255    Report("WM_REPORT_WINDOW_CREATE", GetMsgString(windowCreateReportInfos_));
256    Report("WM_REPORT_WINDOW_SHOW", GetMsgString(windowShowReportInfos_));
257    Report("WM_REPORT_WINDOW_HIDE", GetMsgString(windowHideReportInfos_));
258    Report("WM_REPORT_WINDOW_DESTORY", GetMsgString(windowDestoryReportInfos_));
259    Report("WM_REPORT_HIDE_NAVIGATIONBAR", GetMsgString(windowNavigationBarReportInfos_));
260    ClearRecordedInfos();
261}
262
263void WindowInfoReporter::ReportContainerStartBegin(int32_t missionId, const std::string& bundleName, int64_t timestamp)
264{
265    std::string eventName = "CONTAINER_START_BEGIN";
266    int32_t ret = HiSysEventWrite(
267        OHOS::HiviewDFX::HiSysEvent::Domain::WINDOW_MANAGER, eventName,
268        OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
269        EVENT_KEY_MISSION_ID, missionId,
270        EVENT_KEY_BUNDLE_NAME, bundleName,
271        EVENT_KEY_TIMESTAMP, timestamp);
272    if (ret != 0) {
273        WLOGFE("Write HiSysEvent error, ret:%{public}d", ret);
274    }
275}
276
277void WindowInfoReporter::Report(const std::string& reportTag, const std::string& msg)
278{
279    if (msg.empty()) {
280        return;
281    }
282    WLOGFD("Report Tag : [%{public}s], Msg: %{public}s", reportTag.c_str(), msg.c_str());
283    int32_t ret = HiSysEventWrite(
284        OHOS::HiviewDFX::HiSysEvent::Domain::WINDOW_MANAGER, reportTag,
285        OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, "MSG", msg);
286    if (ret != 0) {
287        WLOGFE("Write HiSysEvent error, ret:%{public}d", ret);
288    }
289}
290
291void WindowInfoReporter::ClearRecordedInfos()
292{
293    WLOGFD("Clear all hiSysEvent write information");
294    windowCreateReportInfos_.clear();
295    windowShowReportInfos_.clear();
296    windowHideReportInfos_.clear();
297    windowDestoryReportInfos_.clear();
298    windowNavigationBarReportInfos_.clear();
299}
300
301int32_t WindowInfoReporter::ReportWindowProfileInfo(const WindowProfileInfo& windowProfileInfo)
302{
303    std::string eventName = "WINDOW_PROFILE_INFORMATION";
304    int32_t ret = HiSysEventWrite(
305        OHOS::HiviewDFX::HiSysEvent::Domain::WINDOW_MANAGER, eventName,
306        OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC,
307        "BUNDLE_NAME", windowProfileInfo.bundleName,
308        "WINDOW_VISIBLE_STATE", windowProfileInfo.windowVisibleState,
309        "WINDOW_LOCATED_SCREEN", windowProfileInfo.windowLocatedScreen,
310        "WINDOW_SCENE_MODE", windowProfileInfo.windowSceneMode);
311    if (ret != 0) {
312        WLOGFE("Write HiSysEvent error, ret:%{public}d", ret);
313    }
314    return ret;
315}
316
317void WindowInfoReporter::ReportWindowException(int32_t detectionType, int32_t pid, const std::string& windowInfo)
318{
319    std::string eventName = "WINDOW_EXCEPTION_DETECTION";
320    int32_t ret = HiSysEventWrite(
321        OHOS::HiviewDFX::HiSysEvent::Domain::WINDOW_MANAGER, eventName,
322        OHOS::HiviewDFX::HiSysEvent::EventType::FAULT,
323        "DETECTION_TYPE", detectionType,
324        "PID", pid,
325        "MSG", windowInfo);
326    if (ret != 0) {
327        WLOGFE("Write HiSysEvent error, ret:%{public}d", ret);
328    }
329}
330}
331}