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 "event_statistic.h"
17#include "mmi_log.h"
18#include "util_ex.h"
19
20#undef MMI_LOG_DOMAIN
21#define MMI_LOG_DOMAIN MMI_LOG_HANDLER
22#undef MMI_LOG_TAG
23#define MMI_LOG_TAG "EventStatistic"
24
25namespace OHOS {
26namespace MMI {
27namespace {
28const std::string EVENT_FILE_NAME = "/data/service/el1/public/multimodalinput/multimodal_event.dmp";
29const std::string EVENT_FILE_NAME_HISTORY = "/data/service/el1/public/multimodalinput/multimodal_event_history.dmp";
30constexpr int32_t FILE_MAX_SIZE = 100 * 1024 * 1024;
31constexpr int32_t EVENT_OUT_SIZE = 30;
32constexpr int32_t FUNC_EXE_OK = 0;
33constexpr int32_t STRING_WIDTH = 3;
34}
35
36std::queue<std::string> EventStatistic::eventQueue_;
37std::list<std::string> EventStatistic::dumperEventList_;
38std::mutex EventStatistic::queueMutex_;
39std::condition_variable EventStatistic::queueCondition_;
40bool EventStatistic::writeFileEnabled_ = false;
41
42std::string EventStatistic::ConvertEventToStr(const std::shared_ptr<InputEvent> eventPtr)
43{
44    auto nowTime = std::chrono::system_clock::now();
45    std::time_t timeT = std::chrono::system_clock::to_time_t(nowTime);
46    auto milsecsCount = std::chrono::duration_cast<std::chrono::milliseconds>(nowTime.time_since_epoch()).count();
47    std::string handleTime = ConvertTimeToStr(static_cast<int64_t>(timeT));
48    int32_t milsec = milsecsCount % 1000;
49    std::stringstream strStream;
50    strStream << std::left << std::setw(STRING_WIDTH) << milsec;
51    std::string milsecStr(strStream.str());
52    handleTime += "." + milsecStr;
53    std::string eventStr = "{" + handleTime + "," + eventPtr->ToString() + "}";
54    return eventStr;
55}
56
57std::string EventStatistic::ConvertTimeToStr(int64_t timestamp)
58{
59    std::string timeStr = std::to_string(timestamp);
60    std::time_t timeT = timestamp;
61    std::tm tmInfo;
62    localtime_r(&timeT, &tmInfo);
63    char buffer[32] = {0};
64    if (std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tmInfo) > 0) {
65        timeStr = buffer;
66    }
67    return timeStr;
68}
69
70void EventStatistic::PushPointerEvent(std::shared_ptr<PointerEvent> eventPtr)
71{
72    CHKPV(eventPtr);
73    int32_t pointerAction = eventPtr->GetPointerAction();
74    if (pointerAction == PointerEvent::POINTER_ACTION_MOVE ||
75        eventPtr->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
76        MMI_HILOGD("PointEvent is filtered");
77        return;
78    }
79    PushEvent(eventPtr);
80}
81
82void EventStatistic::PushEvent(std::shared_ptr<InputEvent> eventPtr)
83{
84    std::lock_guard<std::mutex> lock(queueMutex_);
85    CHKPV(eventPtr);
86    std::string eventStr = ConvertEventToStr(eventPtr);
87    dumperEventList_.push_back(eventStr);
88    if (dumperEventList_.size() > EVENT_OUT_SIZE) {
89        dumperEventList_.pop_front();
90    }
91    if (writeFileEnabled_) {
92        eventQueue_.push(eventStr);
93        queueCondition_.notify_all();
94    }
95}
96
97std::string EventStatistic::PopEvent()
98{
99    std::unique_lock<std::mutex> lock(queueMutex_);
100    if (eventQueue_.empty()) {
101        queueCondition_.wait(lock, []() { return !eventQueue_.empty(); });
102    }
103    std::string eventStr = eventQueue_.front();
104    eventQueue_.pop();
105    return eventStr;
106}
107
108void EventStatistic::WriteEventFile()
109{
110    while (writeFileEnabled_) {
111        std::string eventStr = PopEvent();
112        struct stat statbuf;
113        int32_t fileSize = 0;
114        if (stat(EVENT_FILE_NAME.c_str(), &statbuf) == FUNC_EXE_OK) {
115            fileSize = static_cast<int32_t>(statbuf.st_size);
116        }
117        if (fileSize >= FILE_MAX_SIZE) {
118            if (access(EVENT_FILE_NAME_HISTORY.c_str(), F_OK) == FUNC_EXE_OK &&
119                remove(EVENT_FILE_NAME_HISTORY.c_str()) != FUNC_EXE_OK) {
120                MMI_HILOGE("Remove history file failed");
121            }
122            if (rename(EVENT_FILE_NAME.c_str(), EVENT_FILE_NAME_HISTORY.c_str()) != FUNC_EXE_OK) {
123                MMI_HILOGE("Rename file failed");
124            }
125        }
126        std::ofstream file(EVENT_FILE_NAME, std::ios::app);
127        if (file.is_open()) {
128            file << eventStr << std::endl;
129            file.close();
130        } else {
131            MMI_HILOGE("Open file failed");
132        }
133    }
134}
135
136void EventStatistic::Dump(int32_t fd, const std::vector<std::string> &args)
137{
138    std::lock_guard<std::mutex> lock(queueMutex_);
139    for (auto it = dumperEventList_.begin(); it != dumperEventList_.end(); ++it) {
140        mprintf(fd, (*it).c_str());
141    }
142}
143} // namespace MMI
144} // namespace OHOS