1 /*
2 * Copyright (c) 2023 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 "core/common/event_dump.h"
17 #include "core/pipeline_ng/pipeline_context.h"
18
19 namespace OHOS::Ace::NG {
20 namespace {
21 constexpr size_t MAX_EVENT_TREE_RECORD_CNT = 5;
22 constexpr size_t MAX_FRAME_NODE_CNT = 256;
23 constexpr int32_t MAX_EVENT_TREE_TOUCH_DOWN_CNT = 10;
24 constexpr int32_t MAX_EVENT_TREE_TOUCH_POINT_CNT = 20;
25 constexpr int32_t MAX_EVENT_TREE_AXIS_UPDATE_CNT = 20;
26 constexpr int32_t MAX_EVENT_TREE_AXIS_CNT = 20;
27 constexpr int32_t MAX_EVENT_TREE_GESTURE_CNT = 100;
28 } // end of namespace
29
Dump(std::list<std::pair<int32_t,std::string>> & dumpList,int32_t depth) const30 void FrameNodeSnapshot::Dump(std::list<std::pair<int32_t, std::string>>& dumpList, int32_t depth) const
31 {
32 std::stringstream oss;
33 oss << "nodeId: " << nodeId << ", "
34 << "parentId: " << parentNodeId << ", "
35 << "tag: " << tag << ", ";
36 if (!comId.empty()) {
37 oss << "comId: " << comId << ", ";
38 }
39 oss << "monopolizeEvents: " << monopolizeEvents << ", "
40 << "isHit: " << isHit << ", "
41 << "hitTestMode: " << hitTestMode << ", "
42 << "active: " << active << ", ";
43 #ifndef IS_RELEASE_VERSION
44 oss << "responseRegion: ";
45 for (const auto& rect : responseRegionList) {
46 oss << rect.ToString().c_str();
47 }
48 #else
49 oss << "responseRegionSize: ";
50 for (const auto& rect : responseRegionList) {
51 oss << rect.GetSize().ToString().c_str();
52 }
53 #endif
54 dumpList.emplace_back(std::make_pair(depth, oss.str()));
55 }
56
TouchPointSnapshot(const TouchEvent & event)57 TouchPointSnapshot::TouchPointSnapshot(const TouchEvent& event)
58 {
59 id = event.id;
60 point = OffsetF(event.x, event.y);
61 screenPoint = OffsetF(event.screenX, event.screenY);
62 type = event.type;
63 timestamp = GetCurrentTimestamp();
64 isInjected = event.isInjected;
65 auto pipeline = PipelineContext::GetCurrentContext();
66 CHECK_NULL_VOID(pipeline);
67 auto eventManager = pipeline->GetEventManager();
68 CHECK_NULL_VOID(eventManager);
69 downFingerIds = eventManager->GetDownFingerIds();
70 }
71
AxisSnapshot(const AxisEvent & event)72 AxisSnapshot::AxisSnapshot(const AxisEvent& event)
73 {
74 id = event.id;
75 point = OffsetF(event.x, event.y);
76 screenPoint = OffsetF(event.screenX, event.screenY);
77 action = event.action;
78 timestamp = GetCurrentTimestamp();
79 isInjected = event.isInjected;
80 }
81
Dump(std::list<std::pair<int32_t,std::string>> & dumpList,int32_t depth) const82 void TouchPointSnapshot::Dump(std::list<std::pair<int32_t, std::string>>& dumpList, int32_t depth) const
83 {
84 std::string downFingerIdStr = "";
85 for (const auto& iter : downFingerIds) {
86 downFingerIdStr += std::to_string(iter.first) + " ";
87 }
88 std::stringstream oss;
89 #ifdef IS_RELEASE_VERSION
90 oss << "id: " << id << ", "
91 << "type: " << GestureSnapshot::TransTouchType(type) << ", "
92 << "timestamp: " << ConvertTimestampToStr(timestamp) << ", "
93 << "isInjected: " << isInjected << ", "
94 << "downFingerIds: " << downFingerIdStr;
95 #else
96 oss << "id: " << id << ", "
97 << "point: " << point.ToString() << ", "
98 << "screenPoint: " << screenPoint.ToString() << ", "
99 << "type: " << GestureSnapshot::TransTouchType(type) << ", "
100 << "timestamp: " << ConvertTimestampToStr(timestamp) << ", "
101 << "isInjected: " << isInjected << ", "
102 << "downFingerIds: " << downFingerIdStr;
103 #endif
104 dumpList.emplace_back(std::make_pair(depth, oss.str()));
105 }
106
Dump(std::list<std::pair<int32_t,std::string>> & dumpList,int32_t depth) const107 void AxisSnapshot::Dump(std::list<std::pair<int32_t, std::string>>& dumpList, int32_t depth) const
108 {
109 std::stringstream oss;
110 std::string strAction = std::string("Node");
111 switch (action) {
112 case AxisAction::BEGIN:
113 strAction = std::string("BEGIN");
114 break;
115 case AxisAction::UPDATE:
116 strAction = std::string("UPDATE");
117 break;
118 case AxisAction::END:
119 strAction = std::string("END");
120 break;
121 default:
122 LOGW("AxisAction: Unknown AxisAction action %{public}d", action);
123 break;
124 }
125 #ifdef IS_RELEASE_VERSION
126 oss << "id: " << id << ", "
127 << "action: " << strAction << ", "
128 << "timestamp: " << ConvertTimestampToStr(timestamp) << ", "
129 << "isInjected: " << isInjected;
130 #else
131 oss << "id: " << id << ", "
132 << "point: " << point.ToString() << ", "
133 << "screenPoint: " << screenPoint.ToString() << ", "
134 << "action: " << strAction << ", "
135 << "timestamp: " << ConvertTimestampToStr(timestamp) << ", "
136 << "isInjected: " << isInjected;
137 #endif
138 dumpList.emplace_back(std::make_pair(depth, oss.str()));
139 }
140
AddAxis(const AxisEvent & event)141 void EventTreeRecord::AddAxis(const AxisEvent& event)
142 {
143 if (!eventTreeList.empty() && eventTreeList.back().axis.size() > MAX_EVENT_TREE_AXIS_CNT) {
144 eventTreeList.pop_back();
145 TAG_LOGW(AceLogTag::ACE_INPUTTRACKING,
146 "EventTreeList last record axis size is over limit! Last record is cleaned.");
147 }
148 if (!eventTreeList.empty() && event.action == Ace::AxisAction::BEGIN &&
149 eventTreeList.back().updateAxisIds_.count(event.id) > 0) {
150 eventTreeList.pop_back();
151 TAG_LOGW(AceLogTag::ACE_INPUTTRACKING,
152 "EventTreeList last record receive BEGIN event twice. Last record is cleaned.");
153 }
154 AxisAction action = event.action;
155 if (action == Ace::AxisAction::BEGIN) {
156 if (eventTreeList.empty() || eventTreeList.back().axisUpdateCount <= 0 ||
157 eventTreeList.back().axisUpdateCount >= MAX_EVENT_TREE_AXIS_UPDATE_CNT) {
158 eventTreeList.emplace_back(EventTree());
159 if (eventTreeList.size() > MAX_EVENT_TREE_RECORD_CNT) {
160 eventTreeList.erase(eventTreeList.begin());
161 }
162 }
163 eventTreeList.back().axisUpdateCount++;
164 eventTreeList.back().updateAxisIds_.insert(event.id);
165 }
166 if (eventTreeList.empty()) {
167 return;
168 }
169 if (action == AxisAction::END || action == AxisAction::CANCEL) {
170 eventTreeList.back().axisUpdateCount--;
171 eventTreeList.back().updateAxisIds_.erase(event.id);
172 }
173 eventTreeList.back().axis.emplace_back(AxisSnapshot(event));
174 }
175
AddTouchPoint(const TouchEvent & event)176 void EventTreeRecord::AddTouchPoint(const TouchEvent& event)
177 {
178 if (!eventTreeList.empty() && eventTreeList.back().touchPoints.size() > MAX_EVENT_TREE_TOUCH_POINT_CNT) {
179 eventTreeList.pop_back();
180 TAG_LOGW(AceLogTag::ACE_INPUTTRACKING,
181 "EventTreeList last record touchPoint size is over limit! Last record is cleaned.");
182 }
183 if (!eventTreeList.empty() && event.type == Ace::TouchType::DOWN &&
184 eventTreeList.back().downFingerIds_.count(event.id) > 0) {
185 eventTreeList.pop_back();
186 TAG_LOGW(AceLogTag::ACE_INPUTTRACKING,
187 "EventTreeList last record receive DOWN event twice. Last record is cleaned.");
188 }
189 TouchType type = event.type;
190 if (type == Ace::TouchType::DOWN) {
191 // multi fingers touch down will be in one tree
192 if (eventTreeList.empty() || eventTreeList.back().touchDownCount <= 0 ||
193 eventTreeList.back().touchDownCount >= MAX_EVENT_TREE_TOUCH_DOWN_CNT) {
194 eventTreeList.emplace_back(EventTree());
195 if (eventTreeList.size() > MAX_EVENT_TREE_RECORD_CNT) {
196 eventTreeList.erase(eventTreeList.begin());
197 }
198 }
199 eventTreeList.back().touchDownCount++;
200 eventTreeList.back().downFingerIds_.insert(event.id);
201 }
202
203 if (eventTreeList.empty()) {
204 return;
205 }
206
207 if (type == TouchType::UP || type == TouchType::CANCEL || type == TouchType::PULL_UP ||
208 type == TouchType::PULL_OUT_WINDOW) {
209 eventTreeList.back().touchDownCount--;
210 eventTreeList.back().downFingerIds_.erase(event.id);
211 }
212 eventTreeList.back().touchPoints.emplace_back(TouchPointSnapshot(event));
213 }
214
AddFrameNodeSnapshot(FrameNodeSnapshot && node)215 void EventTreeRecord::AddFrameNodeSnapshot(FrameNodeSnapshot&& node)
216 {
217 if (eventTreeList.empty()) {
218 return;
219 }
220 if (eventTreeList.back().hitTestTree.size() < MAX_FRAME_NODE_CNT) {
221 bool isInList = false;
222 for (auto& iter : eventTreeList.back().hitTestTree) {
223 if (iter.nodeId == node.nodeId) {
224 isInList = true;
225 break;
226 }
227 }
228 if (isInList) {
229 return;
230 }
231 eventTreeList.back().hitTestTree.emplace_back(node);
232 }
233 }
234
AddGestureSnapshot(int32_t finger,RefPtr<GestureSnapshot> && gesture)235 void EventTreeRecord::AddGestureSnapshot(int32_t finger, RefPtr<GestureSnapshot>&& gesture)
236 {
237 if (eventTreeList.empty()) {
238 return;
239 }
240 if (eventTreeList.size() > MAX_EVENT_TREE_RECORD_CNT) {
241 eventTreeList.clear();
242 TAG_LOGW(AceLogTag::ACE_INPUTTRACKING, "EventTreeList size is over MAX, clean event tree.");
243 return;
244 }
245 auto& gestureTree = eventTreeList.back().gestureTree;
246 auto& gestureMap = eventTreeList.back().gestureMap;
247 if (gestureMap.size() > MAX_EVENT_TREE_GESTURE_CNT) {
248 eventTreeList.clear();
249 TAG_LOGW(AceLogTag::ACE_INPUTTRACKING, "GestureMap size is over MAX, clean event tree.");
250 return;
251 }
252 gestureMap[gesture->id] = gesture;
253 gestureTree[finger].emplace_back(gesture);
254 }
255
AddGestureProcedure(uint64_t id,const std::string & procedure,const std::string & extraInfo,const std::string & state,const std::string & disposal,int64_t timestamp)256 void EventTreeRecord::AddGestureProcedure(uint64_t id, const std::string& procedure, const std::string& extraInfo,
257 const std::string& state, const std::string& disposal, int64_t timestamp)
258 {
259 if (eventTreeList.empty()) {
260 return;
261 }
262 auto& gestureMap = eventTreeList.back().gestureMap;
263 auto iter = gestureMap.find(id);
264 if (iter == gestureMap.end()) {
265 return;
266 }
267 // TouchEventActuator don't record move
268 if (iter->second->type == "TouchEventActuator") {
269 return;
270 }
271 iter->second->AddProcedure(procedure, extraInfo, state, disposal, timestamp);
272 }
273
AddGestureProcedure(uint64_t id,const TouchEvent & point,const std::string & extraInfo,const std::string & state,const std::string & disposal,int64_t timestamp)274 void EventTreeRecord::AddGestureProcedure(uint64_t id, const TouchEvent& point, const std::string& extraInfo,
275 const std::string& state, const std::string& disposal, int64_t timestamp)
276 {
277 if (eventTreeList.empty()) {
278 return;
279 }
280 auto& gestureMap = eventTreeList.back().gestureMap;
281 auto iter = gestureMap.find(id);
282 if (iter == gestureMap.end()) {
283 return;
284 }
285
286 if ((point.type == TouchType::MOVE || point.type == TouchType::PULL_MOVE) &&
287 !iter->second->CheckNeedAddMove(state, disposal)) {
288 return;
289 }
290 std::string procedure = std::string("Handle").append(GestureSnapshot::TransTouchType(point.type));
291 iter->second->AddProcedure(procedure, extraInfo, state, disposal, timestamp);
292 }
293
AddGestureProcedure(uint64_t id,const AxisEvent & event,const std::string & extraInfo,const std::string & state,const std::string & disposal,int64_t timestamp)294 void EventTreeRecord::AddGestureProcedure(uint64_t id, const AxisEvent& event, const std::string& extraInfo,
295 const std::string& state, const std::string& disposal, int64_t timestamp)
296 {
297 if (eventTreeList.empty()) {
298 return;
299 }
300 auto& gestureMap = eventTreeList.back().gestureMap;
301 auto iter = gestureMap.find(id);
302 if (iter == gestureMap.end()) {
303 return;
304 }
305
306 if (event.action == AxisAction::UPDATE && !iter->second->CheckNeedAddMove(state, disposal)) {
307 return;
308 }
309 std::string procedure = std::string("Handle").append(GestureSnapshot::TransAxisType(event.action));
310 iter->second->AddProcedure(procedure, extraInfo, state, disposal, timestamp);
311 }
312
Dump(std::list<std::pair<int32_t,std::string>> & dumpList,int32_t depth,int32_t startNumber) const313 void EventTreeRecord::Dump(std::list<std::pair<int32_t, std::string>>& dumpList,
314 int32_t depth, int32_t startNumber) const
315 {
316 int32_t index = 0;
317 int32_t listDepth = depth + 1;
318 int32_t detailDepth = listDepth + 1;
319 for (auto& tree : eventTreeList) {
320 if (index < startNumber) {
321 index++;
322 continue;
323 }
324 std::string header = std::to_string(index - startNumber).append(": event tree =>");
325
326 // dump needful touch points:
327 dumpList.emplace_back(std::make_pair(depth, header));
328 dumpList.emplace_back(std::make_pair(listDepth, "touch points:"));
329 for (auto& item : tree.touchPoints) {
330 item.Dump(dumpList, detailDepth);
331 }
332
333 // dump needful axis:
334 dumpList.emplace_back(std::make_pair(listDepth, "axis:"));
335 for (auto& item : tree.axis) {
336 item.Dump(dumpList, detailDepth);
337 }
338
339 // dump hit test frame nodes:
340 dumpList.emplace_back(std::make_pair(listDepth, "hittest:"));
341 for (auto& item : tree.hitTestTree) {
342 item.Dump(dumpList, detailDepth);
343 }
344
345 // dump gesture event and procedure:
346 dumpList.emplace_back(std::make_pair(listDepth, "event procedures:"));
347 for (auto iter = tree.gestureTree.begin(); iter != tree.gestureTree.end(); ++iter) {
348 dumpList.emplace_back(std::make_pair(detailDepth,
349 std::string("finger:").append(std::to_string(iter->first))));
350 for (const auto& item : iter->second) {
351 item->Dump(dumpList, detailDepth + 1);
352 }
353 }
354 ++index;
355 }
356 }
357
Dump(std::unique_ptr<JsonValue> & json) const358 void FrameNodeSnapshot::Dump(std::unique_ptr<JsonValue>& json) const
359 {
360 json->Put("nodeId", nodeId);
361 json->Put("parentId", parentNodeId);
362 json->Put("tag", tag.c_str());
363 if (!comId.empty()) {
364 json->Put("comId", comId.c_str());
365 }
366 json->Put("monopolizeEvents", monopolizeEvents);
367 json->Put("isHit", isHit);
368 json->Put("hitTestMode", hitTestMode);
369 std::string region = "";
370 for (const auto& rect : responseRegionList) {
371 region.append(rect.ToString());
372 }
373 json->Put("responseRegion", region.c_str());
374 }
375
Dump(std::unique_ptr<JsonValue> & json) const376 void TouchPointSnapshot::Dump(std::unique_ptr<JsonValue>& json) const
377 {
378 std::string downFingerIdStr = "";
379 for (const auto& iter : downFingerIds) {
380 downFingerIdStr += std::to_string(iter.first) + " ";
381 }
382 json->Put("point", point.ToString().c_str());
383 json->Put("screenPoint", screenPoint.ToString().c_str());
384 json->Put("type", GestureSnapshot::TransTouchType(type).c_str());
385 json->Put("timestamp", ConvertTimestampToStr(timestamp).c_str());
386 json->Put("isInjected", isInjected);
387 json->Put("downFingerIds", downFingerIdStr.c_str());
388 }
389
Dump(std::unique_ptr<JsonValue> & json) const390 void AxisSnapshot::Dump(std::unique_ptr<JsonValue>& json) const
391 {
392 json->Put("point", point.ToString().c_str());
393 json->Put("screenPoint", screenPoint.ToString().c_str());
394 switch (action) {
395 case AxisAction::BEGIN:
396 json->Put("action", "BEGIN");
397 break;
398 case AxisAction::UPDATE:
399 json->Put("action", "UPDATE");
400 break;
401 case AxisAction::END:
402 json->Put("action", "END");
403 break;
404 default:
405 LOGW("AxisAction: Unknown AxisAction action %{public}d", action);
406 break;
407 }
408 json->Put("timestamp", ConvertTimestampToStr(timestamp).c_str());
409 json->Put("isInjected", isInjected);
410 }
411
BuildTouchPoints(std::list<TouchPointSnapshot> touchPoints,std::unique_ptr<JsonValue> & json) const412 void EventTreeRecord::BuildTouchPoints(
413 std::list<TouchPointSnapshot> touchPoints, std::unique_ptr<JsonValue>& json) const
414 {
415 std::unique_ptr<JsonValue> touch = JsonUtil::CreateArray(true);
416 for (auto& item : touchPoints) {
417 std::unique_ptr<JsonValue> child = JsonUtil::Create(true);
418 item.Dump(child);
419 touch->Put(child);
420 }
421 json->Put("touch points", touch);
422 }
423
BuildAxis(std::list<AxisSnapshot> axis,std::unique_ptr<JsonValue> & json) const424 void EventTreeRecord::BuildAxis(
425 std::list<AxisSnapshot> axis, std::unique_ptr<JsonValue>& json) const
426 {
427 std::unique_ptr<JsonValue> axisEvent = JsonUtil::CreateArray(true);
428 for (auto& item : axis) {
429 std::unique_ptr<JsonValue> child = JsonUtil::Create(true);
430 item.Dump(child);
431 axisEvent->Put(child);
432 }
433 json->Put("axis", axisEvent);
434 }
435
BuildHitTestTree(std::list<FrameNodeSnapshot> hitTestTree,std::unique_ptr<JsonValue> & json) const436 void EventTreeRecord::BuildHitTestTree(std::list<FrameNodeSnapshot> hitTestTree, std::unique_ptr<JsonValue>& json) const
437 {
438 std::unique_ptr<JsonValue> hittest = JsonUtil::CreateArray(true);
439 for (auto& item : hitTestTree) {
440 std::unique_ptr<JsonValue> child = JsonUtil::Create(true);
441 item.Dump(child);
442 hittest->Put(child);
443 }
444 json->Put("hittest", hittest);
445 }
446
MountToParent(std::vector<std::pair<std::string,std::pair<std::string,std::unique_ptr<JsonValue>>>> stateInfoList,std::unique_ptr<JsonValue> & json) const447 void EventTreeRecord::MountToParent(
448 std::vector<std::pair<std::string, std::pair<std::string, std::unique_ptr<JsonValue>>>> stateInfoList,
449 std::unique_ptr<JsonValue>& json) const
450 {
451 for (auto entry = stateInfoList.rbegin(); entry != stateInfoList.rend(); ++entry) {
452 std::string parentId = entry->second.first;
453 if (parentId == "0x0") {
454 continue;
455 }
456 auto it = std::find_if(
457 stateInfoList.begin(), stateInfoList.end(), [&](const auto& pair) { return pair.first == parentId; });
458 if (it != stateInfoList.end()) {
459 std::string key = "detail_" + entry->first;
460 it->second.second->Put(key.c_str(), entry->second.second);
461 }
462 }
463
464 for (const auto& entry : stateInfoList) {
465 if (entry.second.first == "0x0") {
466 json->Put(("detail_" + entry.first).c_str(), std::move(entry.second.second));
467 }
468 }
469 }
470
BuildGestureTree(std::map<int32_t,std::list<RefPtr<GestureSnapshot>>> gestureTreeMap,std::unique_ptr<JsonValue> & json) const471 void EventTreeRecord::BuildGestureTree(
472 std::map<int32_t, std::list<RefPtr<GestureSnapshot>>> gestureTreeMap, std::unique_ptr<JsonValue>& json) const
473 {
474 std::unique_ptr<JsonValue> procedures = JsonUtil::Create(true);
475 std::unique_ptr<JsonValue> gestureTree = JsonUtil::Create(true);
476 std::vector<std::pair<std::string, std::pair<std::string, std::unique_ptr<JsonValue>>>> stateInfoList;
477 for (auto iter = gestureTreeMap.begin(); iter != gestureTreeMap.end(); ++iter) {
478 stateInfoList.clear();
479 for (const auto& item : iter->second) {
480 auto result = item->GetIds();
481 std::string id = std::get<0>(result);
482 std::string parentId = std::get<1>(result);
483 stateInfoList.push_back(std::make_pair(id, std::make_pair(parentId, JsonUtil::Create(true))));
484 auto it = std::find_if(
485 stateInfoList.begin(), stateInfoList.end(), [&](const auto& pair) { return pair.first == id; });
486 if (it != stateInfoList.end()) {
487 item->Dump(it->second.second);
488 }
489 }
490 MountToParent(std::move(stateInfoList), gestureTree);
491 procedures->Put(("finger_" + std::to_string(iter->first)).c_str(), gestureTree);
492 }
493 json->Put("event procedures", procedures);
494 }
495
Dump(std::unique_ptr<JsonValue> & json,int32_t depth,int32_t startNumber) const496 void EventTreeRecord::Dump(std::unique_ptr<JsonValue>& json, int32_t depth, int32_t startNumber) const
497 {
498 int32_t index = 0;
499 for (auto& tree : eventTreeList) {
500 if (index < startNumber) {
501 index++;
502 continue;
503 }
504 std::unique_ptr<JsonValue> children = JsonUtil::Create(true);
505 BuildTouchPoints(tree.touchPoints, children);
506 BuildAxis(tree.axis, children);
507 BuildHitTestTree(tree.hitTestTree, children);
508 BuildGestureTree(tree.gestureTree, children);
509 std::string header = "event tree_" + std::to_string(index - startNumber);
510 json->Put(header.c_str(), children);
511 ++index;
512 }
513 }
514 } // namespace OHOS::Ace::NG
515