• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "util_ex.h"
18 
19 #undef MMI_LOG_DOMAIN
20 #define MMI_LOG_DOMAIN MMI_LOG_HANDLER
21 #undef MMI_LOG_TAG
22 #define MMI_LOG_TAG "EventStatistic"
23 
24 namespace OHOS {
25 namespace MMI {
26 namespace {
27 const char* EVENT_FILE_NAME = "/data/service/el1/public/multimodalinput/multimodal_event.dmp";
28 const char* EVENT_FILE_NAME_HISTORY = "/data/service/el1/public/multimodalinput/multimodal_event_history.dmp";
29 constexpr int32_t FILE_MAX_SIZE = 100 * 1024 * 1024;
30 constexpr int32_t EVENT_OUT_SIZE = 30;
31 constexpr int32_t FUNC_EXE_OK = 0;
32 constexpr int32_t STRING_WIDTH = 3;
33 constexpr int32_t POINTER_RECORD_MAX_SIZE = 100;
34 }
35 
36 std::queue<std::string> EventStatistic::eventQueue_;
37 std::list<std::string> EventStatistic::dumperEventList_;
38 std::mutex EventStatistic::queueMutex_;
39 std::condition_variable EventStatistic::queueCondition_;
40 std::deque<EventStatistic::PointerEventRecord> EventStatistic::pointerRecordDeque_;
41 bool EventStatistic::writeFileEnabled_ = false;
42 static const std::unordered_map<int32_t, std::string> pointerActionMap = {
43     { PointerEvent::POINTER_ACTION_CANCEL, "cancel" },
44     { PointerEvent::POINTER_ACTION_DOWN, "down" },
45     { PointerEvent::POINTER_ACTION_MOVE, "move" },
46     { PointerEvent::POINTER_ACTION_UP, "up" },
47     { PointerEvent::POINTER_ACTION_AXIS_BEGIN, "axis-begin" },
48     { PointerEvent::POINTER_ACTION_AXIS_UPDATE, "axis-update" },
49     { PointerEvent::POINTER_ACTION_AXIS_END, "axis-end" },
50     { PointerEvent::POINTER_ACTION_BUTTON_DOWN, "button-down" },
51     { PointerEvent::POINTER_ACTION_BUTTON_UP, "button-up" },
52     { PointerEvent::POINTER_ACTION_ENTER_WINDOW, "enter-window" },
53     { PointerEvent::POINTER_ACTION_LEAVE_WINDOW, "leave-window" },
54     { PointerEvent::POINTER_ACTION_PULL_DOWN, "pull-down" },
55     { PointerEvent::POINTER_ACTION_PULL_MOVE, "pull-move" },
56     { PointerEvent::POINTER_ACTION_PULL_UP, "pull-up" },
57     { PointerEvent::POINTER_ACTION_PULL_IN_WINDOW, "pull-in-window" },
58     { PointerEvent::POINTER_ACTION_PULL_OUT_WINDOW, "pull-out-window" },
59     { PointerEvent::POINTER_ACTION_SWIPE_BEGIN, "swipe-begin" },
60     { PointerEvent::POINTER_ACTION_SWIPE_UPDATE, "swipe-update" },
61     { PointerEvent::POINTER_ACTION_SWIPE_END, "swipe-end" },
62     { PointerEvent::POINTER_ACTION_ROTATE_BEGIN, "rotate-begin" },
63     { PointerEvent::POINTER_ACTION_ROTATE_UPDATE, "rotate-update" },
64     { PointerEvent::POINTER_ACTION_ROTATE_END, "rotate-end" },
65     { PointerEvent::POINTER_ACTION_TRIPTAP, "touchpad-triptap" },
66     { PointerEvent::POINTER_ACTION_QUADTAP, "quadtap" },
67     { PointerEvent::POINTER_ACTION_HOVER_MOVE, "hover-move" },
68     { PointerEvent::POINTER_ACTION_HOVER_ENTER, "hover-enter" },
69     { PointerEvent::POINTER_ACTION_HOVER_EXIT, "hover-exit" },
70     { PointerEvent::POINTER_ACTION_FINGERPRINT_DOWN, "fingerprint-down" },
71     { PointerEvent::POINTER_ACTION_FINGERPRINT_UP, "fingerprint-up" },
72     { PointerEvent::POINTER_ACTION_FINGERPRINT_SLIDE, "fingerprint-slide" },
73     { PointerEvent::POINTER_ACTION_FINGERPRINT_RETOUCH, "fingerprint-retouch" },
74     { PointerEvent::POINTER_ACTION_FINGERPRINT_CLICK, "fingerprint-click" },
75     { PointerEvent::POINTER_ACTION_FINGERPRINT_HOLD, "fingerprint-hold" },
76     { PointerEvent::POINTER_ACTION_FINGERPRINT_TOUCH, "fingerprint-touch" },
77     { PointerEvent::TOUCH_ACTION_SWIPE_DOWN, "touch-swipe-down" },
78     { PointerEvent::TOUCH_ACTION_SWIPE_UP, "touch-swipe-up" },
79     { PointerEvent::TOUCH_ACTION_SWIPE_LEFT, "touch-swipe-left" },
80     { PointerEvent::TOUCH_ACTION_SWIPE_RIGHT, "touch-swipe-right" },
81     { PointerEvent::TOUCH_ACTION_PINCH_OPENED, "touch-pinch-open" },
82     { PointerEvent::TOUCH_ACTION_PINCH_CLOSEED, "touch-pinch-close" },
83     { PointerEvent::TOUCH_ACTION_GESTURE_END, "touch-gesture-end" },
84     { PointerEvent::POINTER_ACTION_PROXIMITY_IN, "pen-proximity-in" },
85     { PointerEvent::POINTER_ACTION_PROXIMITY_OUT, "pen-proximity-out" },
86 };
87 static const std::unordered_map<int32_t, std::string> keyActionMap = {
88     { KeyEvent::KEY_ACTION_UNKNOWN, "key_action_unknown" },
89     { KeyEvent::KEY_ACTION_CANCEL, "key_action_cancel" },
90     { KeyEvent::KEY_ACTION_DOWN, "key_action_down" },
91     { KeyEvent::KEY_ACTION_UP, "key_action_up" },
92 };
93 
ConvertInputEventToStr(const std::shared_ptr<InputEvent> eventPtr)94 std::string EventStatistic::ConvertInputEventToStr(const std::shared_ptr<InputEvent> eventPtr)
95 {
96     auto nowTime = std::chrono::system_clock::now();
97     std::time_t timeT = std::chrono::system_clock::to_time_t(nowTime);
98     auto milsecsCount = std::chrono::duration_cast<std::chrono::milliseconds>(nowTime.time_since_epoch()).count();
99     std::string handleTime = ConvertTimeToStr(static_cast<int64_t>(timeT));
100     int32_t milsec = milsecsCount % 1000;
101     std::stringstream strStream;
102     strStream << std::left << std::setw(STRING_WIDTH) << milsec;
103     std::string milsecStr(strStream.str());
104     handleTime += "." + milsecStr;
105     std::string eventStr = "{";
106     eventStr += handleTime;
107     eventStr += ",eventType:";
108     eventStr += ConvertEventTypeToString(eventPtr->GetEventType());
109     eventStr += ",actionTime:" + std::to_string(eventPtr->GetActionTime());
110     eventStr += ",deviceId:" + std::to_string(eventPtr->GetDeviceId());
111     eventStr += ",sourceType:";
112     eventStr += ConvertSourceTypeToString(eventPtr->GetSourceType());
113     return eventStr;
114 }
115 
ConvertTimeToStr(int64_t timestamp)116 std::string EventStatistic::ConvertTimeToStr(int64_t timestamp)
117 {
118     std::string timeStr = std::to_string(timestamp);
119     std::time_t timeT = timestamp;
120     std::tm tmInfo;
121     localtime_r(&timeT, &tmInfo);
122     char buffer[32] = {0};
123     if (std::strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", &tmInfo) > 0) {
124         timeStr = buffer;
125     }
126     return timeStr;
127 }
128 
PushPointerEvent(std::shared_ptr<PointerEvent> eventPtr)129 void EventStatistic::PushPointerEvent(std::shared_ptr<PointerEvent> eventPtr)
130 {
131     CHKPV(eventPtr);
132     PushPointerRecord(eventPtr);
133     int32_t pointerAction = eventPtr->GetPointerAction();
134     if (pointerAction == PointerEvent::POINTER_ACTION_MOVE || pointerAction == PointerEvent::POINTER_ACTION_PULL_MOVE ||
135         pointerAction == PointerEvent::POINTER_ACTION_HOVER_MOVE ||
136         pointerAction == PointerEvent::POINTER_ACTION_AXIS_UPDATE ||
137         pointerAction == PointerEvent::POINTER_ACTION_SWIPE_UPDATE ||
138         pointerAction == PointerEvent::POINTER_ACTION_ROTATE_UPDATE) {
139         MMI_HILOGD("PointEvent is filtered");
140         return;
141     }
142     std::string eventStr = ConvertInputEventToStr(eventPtr);
143     eventStr += ",pointerId:" + std::to_string(eventPtr->GetPointerId());
144     eventStr += ",pointerAction:";
145     eventStr += ConvertPointerActionToString(eventPtr);
146     eventStr += ",buttonId:" + std::to_string(eventPtr->GetButtonId()) + ",pointers:[";
147     size_t pointerSize = 0;
148     std::list<PointerEvent::PointerItem> pointerItems = eventPtr->GetAllPointerItems();
149     for (auto it = pointerItems.begin(); it != pointerItems.end(); it++) {
150         std::string displayX = "***";
151         std::string displayY = "***";
152         pointerSize++;
153         if (!eventPtr->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
154             displayX = std::to_string((*it).GetDisplayX());
155             displayY = std::to_string((*it).GetDisplayY());
156         }
157         eventStr += "{";
158         eventStr += "displayX:" + displayX;
159         eventStr += ",displayY:" + displayY;
160         eventStr += ",pressure:" + std::to_string((*it).GetPressure());
161         eventStr += "}";
162         if (pointerSize != pointerItems.size()) {
163             eventStr += ",";
164         }
165     }
166     eventStr += "],pressedButtons:[";
167     size_t buttonsSize = 0;
168     std::set<int32_t> pressedButtons = eventPtr->GetPressedButtons();
169     for (auto it = pressedButtons.begin(); it != pressedButtons.end(); it++) {
170         buttonsSize++;
171         eventStr += std::to_string(*it);
172         if (buttonsSize != pressedButtons.size()) {
173             eventStr += ",";
174         }
175     }
176     eventStr += "]";
177     eventStr += "}";
178     PushEventStr(eventStr);
179 }
180 
PushKeyEvent(std::shared_ptr<KeyEvent> eventPtr)181 void EventStatistic::PushKeyEvent(std::shared_ptr<KeyEvent> eventPtr)
182 {
183     CHKPV(eventPtr);
184     std::string eventStr = ConvertInputEventToStr(eventPtr);
185     std::string keyCode = "***";
186     if (!eventPtr->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
187         keyCode = std::to_string(eventPtr->GetKeyCode());
188     }
189     eventStr += ",keyCode:" + keyCode;
190     eventStr += ",keyAction:";
191     eventStr += ConvertKeyActionToString(eventPtr->GetKeyAction());
192     auto keyItems = eventPtr->GetKeyItems();
193     eventStr += ",keyItems:[";
194     for (size_t i = 0; i < keyItems.size(); i++) {
195         std::string keyItemCode = "***";
196         int32_t pressed = keyItems[i].IsPressed() ? 1 : 0;
197         if (!eventPtr->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
198             keyItemCode = std::to_string(keyItems[i].GetKeyCode());
199         }
200         eventStr += "{pressed:" + std::to_string(pressed);
201         eventStr += ",deviceId:" + std::to_string(keyItems[i].GetDeviceId());
202         eventStr += ",keyCode:" + keyItemCode;
203         eventStr += ",downTime:" + std::to_string(keyItems[i].GetDownTime());
204         eventStr += ",unicode:" + std::to_string(keyItems[i].GetUnicode()) + "}";
205         if (i != keyItems.size() - 1) {
206             eventStr += ",";
207         }
208     }
209     eventStr += "]";
210     eventStr += "}";
211     PushEventStr(eventStr);
212 }
213 
PushSwitchEvent(std::shared_ptr<SwitchEvent> eventPtr)214 void EventStatistic::PushSwitchEvent(std::shared_ptr<SwitchEvent> eventPtr)
215 {
216     CHKPV(eventPtr);
217     std::string eventStr = ConvertInputEventToStr(eventPtr);
218     eventStr += ",switchValue:" + std::to_string(eventPtr->GetSwitchValue());
219     eventStr += ",switchType:";
220     eventStr += ConvertSwitchTypeToString(eventPtr->GetSwitchType());
221     eventStr += "}";
222     PushEventStr(eventStr);
223 }
224 
PushEventStr(std::string eventStr)225 void EventStatistic::PushEventStr(std::string eventStr)
226 {
227     std::lock_guard<std::mutex> lock(queueMutex_);
228     dumperEventList_.push_back(eventStr);
229     if (dumperEventList_.size() > EVENT_OUT_SIZE) {
230         dumperEventList_.pop_front();
231     }
232     if (writeFileEnabled_) {
233         eventQueue_.push(eventStr);
234         queueCondition_.notify_all();
235     }
236 }
237 
PushPointerRecord(std::shared_ptr<PointerEvent> eventPtr)238 void EventStatistic::PushPointerRecord(std::shared_ptr<PointerEvent> eventPtr)
239 {
240     std::list<PointerEvent::PointerItem> pointerItems = eventPtr->GetAllPointerItems();
241     std::vector<double> pressures;
242     std::vector<double> tiltXs;
243     std::vector<double> tiltYs;
244     for (auto it = pointerItems.begin(); it != pointerItems.end(); ++it) {
245         pressures.push_back(it->GetPressure());
246         tiltXs.push_back(it->GetTiltX());
247         tiltYs.push_back(it->GetTiltY());
248     }
249     pointerRecordDeque_.emplace_back(eventPtr->GetActionTime(),
250         eventPtr->GetSourceType(),
251         eventPtr->HasFlag(InputEvent::EVENT_FLAG_SIMULATE),
252         pressures,
253         tiltXs,
254         tiltYs);
255     if (pointerRecordDeque_.size() > POINTER_RECORD_MAX_SIZE) {
256         pointerRecordDeque_.pop_front();
257     }
258 }
259 
QueryPointerRecord(int32_t count,std::vector<std::shared_ptr<PointerEvent>> & pointerList)260 int32_t EventStatistic::QueryPointerRecord(int32_t count, std::vector<std::shared_ptr<PointerEvent>> &pointerList)
261 {
262     if (count <= 0 || pointerRecordDeque_.empty()) {
263         MMI_HILOGD("Return pointerList is empty");
264         return RET_OK;
265     }
266     count = std::min(count, static_cast<int32_t>(pointerRecordDeque_.size()));
267     for (auto it = pointerRecordDeque_.end() - count; it != pointerRecordDeque_.end(); ++it) {
268         auto pointerEvent = PointerEvent::Create();
269         pointerEvent->SetActionTime(it->actionTime);
270         pointerEvent->SetSourceType(it->sourceType);
271         if (it->isInject) {
272             pointerEvent->AddFlag(InputEvent::EVENT_FLAG_SIMULATE);
273         }
274         for (auto pressuresIt = it->pressures.begin(), tiltXsIt = it->tiltXs.begin(), tiltYsIt = it->tiltYs.begin();
275              pressuresIt != it->pressures.end() && tiltXsIt != it->tiltXs.end() && tiltYsIt != it->tiltYs.end();
276              ++pressuresIt, ++tiltXsIt, ++tiltYsIt) {
277             PointerEvent::PointerItem pointerItem;
278             pointerItem.SetPressure(*pressuresIt);
279             pointerItem.SetTiltX(*tiltXsIt);
280             pointerItem.SetTiltY(*tiltYsIt);
281             pointerEvent->AddPointerItem(pointerItem);
282         }
283         pointerList.push_back(pointerEvent);
284     }
285     return RET_OK;
286 }
287 
PopEvent()288 std::string EventStatistic::PopEvent()
289 {
290     std::unique_lock<std::mutex> lock(queueMutex_);
291     if (eventQueue_.empty()) {
292         queueCondition_.wait(lock, []() { return !eventQueue_.empty(); });
293     }
294     std::string eventStr = eventQueue_.front();
295     eventQueue_.pop();
296     return eventStr;
297 }
298 
WriteEventFile()299 void EventStatistic::WriteEventFile()
300 {
301     while (writeFileEnabled_) {
302         std::string eventStr = PopEvent();
303         struct stat statbuf;
304         int32_t fileSize = 0;
305         if (stat(EVENT_FILE_NAME, &statbuf) == FUNC_EXE_OK) {
306             fileSize = static_cast<int32_t>(statbuf.st_size);
307         }
308         if (fileSize >= FILE_MAX_SIZE) {
309             if (access(EVENT_FILE_NAME_HISTORY, F_OK) == FUNC_EXE_OK &&
310                 remove(EVENT_FILE_NAME_HISTORY) != FUNC_EXE_OK) {
311                 MMI_HILOGE("Remove history file failed");
312             }
313             if (rename(EVENT_FILE_NAME, EVENT_FILE_NAME_HISTORY) != FUNC_EXE_OK) {
314                 MMI_HILOGE("Rename file failed");
315             }
316         }
317         std::ofstream file(EVENT_FILE_NAME, std::ios::app);
318         if (file.is_open()) {
319             file << eventStr << std::endl;
320             file.close();
321         } else {
322             MMI_HILOGE("Open file failed");
323         }
324     }
325 }
326 
Dump(int32_t fd,const std::vector<std::string> & args)327 void EventStatistic::Dump(int32_t fd, const std::vector<std::string> &args)
328 {
329     std::lock_guard<std::mutex> lock(queueMutex_);
330     for (auto it = dumperEventList_.begin(); it != dumperEventList_.end(); ++it) {
331         mprintf(fd, (*it).c_str());
332     }
333 }
334 
ConvertEventTypeToString(int32_t eventType)335 const char* EventStatistic::ConvertEventTypeToString(int32_t eventType)
336 {
337     switch (eventType) {
338         case InputEvent::EVENT_TYPE_BASE: {
339             return "base";
340         }
341         case InputEvent::EVENT_TYPE_KEY: {
342             return "key";
343         }
344         case InputEvent::EVENT_TYPE_POINTER: {
345             return "pointer";
346         }
347         case InputEvent::EVENT_TYPE_AXIS: {
348             return "axis";
349         }
350         case InputEvent::EVENT_TYPE_FINGERPRINT: {
351             return "fingerprint";
352         }
353         default: {
354             MMI_HILOGW("Unknown EventType");
355             return "unknown";
356         }
357     }
358 }
359 
ConvertSourceTypeToString(int32_t sourceType)360 const char* EventStatistic::ConvertSourceTypeToString(int32_t sourceType)
361 {
362     switch (sourceType) {
363         case InputEvent::SOURCE_TYPE_MOUSE: {
364             return "mouse";
365         }
366         case InputEvent::SOURCE_TYPE_TOUCHSCREEN: {
367             return "touch-screen";
368         }
369         case InputEvent::SOURCE_TYPE_TOUCHPAD: {
370             return "touch-pad";
371         }
372         case InputEvent::SOURCE_TYPE_JOYSTICK: {
373             return "joystick";
374         }
375         case InputEvent::SOURCE_TYPE_FINGERPRINT: {
376             return "fingerprint";
377         }
378         case InputEvent::SOURCE_TYPE_CROWN: {
379             return "crown";
380         }
381         default: {
382             MMI_HILOGW("Unknown SourceType");
383             return "unknown";
384         }
385     }
386 }
387 
ConvertPointerActionToString(std::shared_ptr<PointerEvent> eventPtr)388 const char* EventStatistic::ConvertPointerActionToString(std::shared_ptr<PointerEvent> eventPtr)
389 {
390     int32_t pointerAction = eventPtr->GetPointerAction();
391     int32_t axes = eventPtr->GetAxes();
392     if (pointerAction == PointerEvent::POINTER_ACTION_AXIS_BEGIN) {
393         if (PointerEvent::HasAxis(axes, PointerEvent::AXIS_TYPE_SCROLL_VERTICAL) ||
394             PointerEvent::HasAxis(axes, PointerEvent::AXIS_TYPE_SCROLL_HORIZONTAL)) {
395             return "axis-begin";
396         } else if (PointerEvent::HasAxis(axes, PointerEvent::AXIS_TYPE_PINCH)) {
397             return "pinch-begin";
398         }
399     } else if (pointerAction == PointerEvent::POINTER_ACTION_AXIS_UPDATE) {
400         if (PointerEvent::HasAxis(axes, PointerEvent::AXIS_TYPE_SCROLL_VERTICAL) ||
401             PointerEvent::HasAxis(axes, PointerEvent::AXIS_TYPE_SCROLL_HORIZONTAL)) {
402             return "axis-update";
403         } else if (PointerEvent::HasAxis(axes, PointerEvent::AXIS_TYPE_PINCH)) {
404             return "pinch-update";
405         }
406     } else if (pointerAction == PointerEvent::POINTER_ACTION_AXIS_END) {
407         if (PointerEvent::HasAxis(axes, PointerEvent::AXIS_TYPE_SCROLL_VERTICAL) ||
408             PointerEvent::HasAxis(axes, PointerEvent::AXIS_TYPE_SCROLL_HORIZONTAL)) {
409             return "axis-end";
410         } else if (PointerEvent::HasAxis(axes, PointerEvent::AXIS_TYPE_PINCH)) {
411             return "pinch-end";
412         }
413     }
414     auto it = pointerActionMap.find(pointerAction);
415     if (it != pointerActionMap.end()) {
416         return it->second.c_str();
417     }
418     return "unknown";
419 }
420 
ConvertKeyActionToString(int32_t keyAction)421 const char* EventStatistic::ConvertKeyActionToString(int32_t keyAction)
422 {
423     auto it = keyActionMap.find(keyAction);
424     if (it != keyActionMap.end()) {
425         return it->second.c_str();
426     }
427     return "unknown";
428 }
429 
ConvertSwitchTypeToString(int32_t switchType)430 const char* EventStatistic::ConvertSwitchTypeToString(int32_t switchType)
431 {
432     switch (switchType) {
433         case SwitchEvent::SWITCH_DEFAULT: {
434             return "switch_default";
435         }
436         case SwitchEvent::SWITCH_LID: {
437             return "switch_lid";
438         }
439         case SwitchEvent::SWITCH_TABLET: {
440             return "switch_tablet";
441         }
442         case SwitchEvent::SWITCH_PRIVACY: {
443             return "switch_privacy";
444         }
445         default: {
446             MMI_HILOGW("Unknown SwitchType");
447             return "unknown";
448         }
449     }
450 }
451 } // namespace MMI
452 } // namespace OHOS