• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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