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