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