• 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 #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