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 #endif
48 dumpList.emplace_back(std::make_pair(depth, oss.str()));
49 }
50
TouchPointSnapshot(const TouchEvent & event)51 TouchPointSnapshot::TouchPointSnapshot(const TouchEvent& event)
52 {
53 id = event.id;
54 point = OffsetF(event.x, event.y);
55 screenPoint = OffsetF(event.screenX, event.screenY);
56 type = event.type;
57 timestamp = GetCurrentTimestamp();
58 isInjected = event.isInjected;
59 auto pipeline = PipelineContext::GetCurrentContext();
60 CHECK_NULL_VOID(pipeline);
61 auto eventManager = pipeline->GetEventManager();
62 CHECK_NULL_VOID(eventManager);
63 downFingerIds = eventManager->GetDownFingerIds();
64 }
65
AxisSnapshot(const AxisEvent & event)66 AxisSnapshot::AxisSnapshot(const AxisEvent& event)
67 {
68 id = event.id;
69 point = OffsetF(event.x, event.y);
70 screenPoint = OffsetF(event.screenX, event.screenY);
71 action = event.action;
72 timestamp = GetCurrentTimestamp();
73 isInjected = event.isInjected;
74 }
75
Dump(std::list<std::pair<int32_t,std::string>> & dumpList,int32_t depth) const76 void TouchPointSnapshot::Dump(std::list<std::pair<int32_t, std::string>>& dumpList, int32_t depth) const
77 {
78 std::string downFingerIdStr = "";
79 for (const auto& iter : downFingerIds) {
80 downFingerIdStr += std::to_string(iter.first) + " ";
81 }
82 std::stringstream oss;
83 #ifdef IS_RELEASE_VERSION
84 oss << "id: " << id << ", "
85 << "type: " << GestureSnapshot::TransTouchType(type) << ", "
86 << "timestamp: " << ConvertTimestampToStr(timestamp) << ", "
87 << "isInjected: " << isInjected << ", "
88 << "downFingerIds: " << downFingerIdStr;
89 #else
90 oss << "id: " << id << ", "
91 << "point: " << point.ToString() << ", "
92 << "screenPoint: " << screenPoint.ToString() << ", "
93 << "type: " << GestureSnapshot::TransTouchType(type) << ", "
94 << "timestamp: " << ConvertTimestampToStr(timestamp) << ", "
95 << "isInjected: " << isInjected << ", "
96 << "downFingerIds: " << downFingerIdStr;
97 #endif
98 dumpList.emplace_back(std::make_pair(depth, oss.str()));
99 }
100
Dump(std::list<std::pair<int32_t,std::string>> & dumpList,int32_t depth) const101 void AxisSnapshot::Dump(std::list<std::pair<int32_t, std::string>>& dumpList, int32_t depth) const
102 {
103 std::stringstream oss;
104 std::string strAction = std::string("Node");
105 switch (action) {
106 case AxisAction::BEGIN:
107 strAction = std::string("BEGIN");
108 break;
109 case AxisAction::UPDATE:
110 strAction = std::string("UPDATE");
111 break;
112 case AxisAction::END:
113 strAction = std::string("END");
114 break;
115 default:
116 LOGW("AxisAction: Unknown AxisAction action %{public}d", action);
117 break;
118 }
119 #ifdef IS_RELEASE_VERSION
120 oss << "id: " << id << ", "
121 << "action: " << strAction << ", "
122 << "timestamp: " << ConvertTimestampToStr(timestamp) << ", "
123 << "isInjected: " << isInjected;
124 #else
125 oss << "id: " << id << ", "
126 << "point: " << point.ToString() << ", "
127 << "screenPoint: " << screenPoint.ToString() << ", "
128 << "action: " << strAction << ", "
129 << "timestamp: " << ConvertTimestampToStr(timestamp) << ", "
130 << "isInjected: " << isInjected;
131 #endif
132 dumpList.emplace_back(std::make_pair(depth, oss.str()));
133 }
134
AddAxis(const AxisEvent & event)135 void EventTreeRecord::AddAxis(const AxisEvent& event)
136 {
137 if (!eventTreeList.empty() && eventTreeList.back().axis.size() > MAX_EVENT_TREE_AXIS_CNT) {
138 eventTreeList.pop_back();
139 TAG_LOGW(AceLogTag::ACE_INPUTTRACKING,
140 "EventTreeList last record axis size is over limit! Last record is cleaned.");
141 }
142 if (!eventTreeList.empty() && event.action == Ace::AxisAction::BEGIN &&
143 eventTreeList.back().updateAxisIds_.count(event.id) > 0) {
144 eventTreeList.pop_back();
145 TAG_LOGW(AceLogTag::ACE_INPUTTRACKING,
146 "EventTreeList last record receive BEGIN event twice. Last record is cleaned.");
147 }
148 AxisAction action = event.action;
149 if (action == Ace::AxisAction::BEGIN) {
150 if (eventTreeList.empty() || eventTreeList.back().axisUpdateCount <= 0 ||
151 eventTreeList.back().axisUpdateCount >= MAX_EVENT_TREE_AXIS_UPDATE_CNT) {
152 eventTreeList.emplace_back(EventTree());
153 if (eventTreeList.size() > MAX_EVENT_TREE_RECORD_CNT) {
154 eventTreeList.erase(eventTreeList.begin());
155 }
156 }
157 eventTreeList.back().axisUpdateCount++;
158 eventTreeList.back().updateAxisIds_.insert(event.id);
159 }
160 if (eventTreeList.empty()) {
161 return;
162 }
163 if (action == AxisAction::END || action == AxisAction::CANCEL) {
164 eventTreeList.back().axisUpdateCount--;
165 eventTreeList.back().updateAxisIds_.erase(event.id);
166 }
167 eventTreeList.back().axis.emplace_back(AxisSnapshot(event));
168 }
169
AddTouchPoint(const TouchEvent & event)170 void EventTreeRecord::AddTouchPoint(const TouchEvent& event)
171 {
172 if (!eventTreeList.empty()) {
173 if (eventTreeList.back().touchPoints.size() > MAX_EVENT_TREE_TOUCH_POINT_CNT) {
174 eventTreeList.pop_back();
175 TAG_LOGW(AceLogTag::ACE_INPUTTRACKING,
176 "EventTreeList last record touchPoint size is over limit! Last record is cleaned.");
177 }
178 if (!eventTreeList.empty() && event.type == Ace::TouchType::DOWN &&
179 eventTreeList.back().downFingerIds_.count(event.id) > 0) {
180 eventTreeList.pop_back();
181 TAG_LOGW(AceLogTag::ACE_INPUTTRACKING,
182 "EventTreeList last record receive DOWN event twice. Last record is cleaned.");
183 }
184 }
185 TouchType type = event.type;
186 if (type == Ace::TouchType::DOWN) {
187 // multi fingers touch down will be in one tree
188 if (eventTreeList.empty() || eventTreeList.back().touchDownCount <= 0 ||
189 eventTreeList.back().touchDownCount >= MAX_EVENT_TREE_TOUCH_DOWN_CNT) {
190 eventTreeList.emplace_back(EventTree());
191 if (eventTreeList.size() > MAX_EVENT_TREE_RECORD_CNT) {
192 eventTreeList.erase(eventTreeList.begin());
193 }
194 }
195 eventTreeList.back().touchDownCount++;
196 eventTreeList.back().downFingerIds_.insert(event.id);
197 }
198
199 if (eventTreeList.empty()) {
200 return;
201 }
202
203 if (type == TouchType::UP || type == TouchType::CANCEL || type == TouchType::PULL_UP ||
204 type == TouchType::PULL_OUT_WINDOW) {
205 eventTreeList.back().touchDownCount--;
206 eventTreeList.back().downFingerIds_.erase(event.id);
207 }
208 eventTreeList.back().touchPoints.emplace_back(TouchPointSnapshot(event));
209 }
210
AddFrameNodeSnapshot(FrameNodeSnapshot && node)211 void EventTreeRecord::AddFrameNodeSnapshot(FrameNodeSnapshot&& node)
212 {
213 if (eventTreeList.empty()) {
214 return;
215 }
216 if (eventTreeList.back().hitTestTree.size() < MAX_FRAME_NODE_CNT) {
217 bool isInList = false;
218 for (auto& iter : eventTreeList.back().hitTestTree) {
219 if (iter.nodeId == node.nodeId) {
220 isInList = true;
221 break;
222 }
223 }
224 if (isInList) {
225 return;
226 }
227 eventTreeList.back().hitTestTree.emplace_back(node);
228 }
229 }
230
AddGestureSnapshot(int32_t finger,RefPtr<GestureSnapshot> && gesture)231 void EventTreeRecord::AddGestureSnapshot(int32_t finger, RefPtr<GestureSnapshot>&& gesture)
232 {
233 if (eventTreeList.empty()) {
234 return;
235 }
236 if (eventTreeList.size() > MAX_EVENT_TREE_RECORD_CNT) {
237 eventTreeList.clear();
238 TAG_LOGW(AceLogTag::ACE_INPUTTRACKING, "EventTreeList size is over MAX, clean event tree.");
239 return;
240 }
241 auto& gestureTree = eventTreeList.back().gestureTree;
242 auto& gestureMap = eventTreeList.back().gestureMap;
243 if (gestureMap.size() > MAX_EVENT_TREE_GESTURE_CNT) {
244 eventTreeList.clear();
245 TAG_LOGW(AceLogTag::ACE_INPUTTRACKING, "GestureMap size is over MAX, clean event tree.");
246 return;
247 }
248 gestureMap[gesture->id] = gesture;
249 gestureTree[finger].emplace_back(gesture);
250 }
251
AddGestureProcedure(uint64_t id,const std::string & procedure,const std::string & extraInfo,const std::string & state,const std::string & disposal,int64_t timestamp)252 void EventTreeRecord::AddGestureProcedure(uint64_t id, const std::string& procedure, const std::string& extraInfo,
253 const std::string& state, const std::string& disposal, int64_t timestamp)
254 {
255 if (eventTreeList.empty()) {
256 return;
257 }
258 auto& gestureMap = eventTreeList.back().gestureMap;
259 auto iter = gestureMap.find(id);
260 if (iter == gestureMap.end()) {
261 return;
262 }
263 // TouchEventActuator don't record move
264 if (iter->second->type == "TouchEventActuator") {
265 return;
266 }
267 iter->second->AddProcedure(procedure, extraInfo, state, disposal, timestamp);
268 }
269
AddGestureProcedure(uint64_t id,const TouchEvent & point,const std::string & extraInfo,const std::string & state,const std::string & disposal,int64_t timestamp)270 void EventTreeRecord::AddGestureProcedure(uint64_t id, const TouchEvent& point, const std::string& extraInfo,
271 const std::string& state, const std::string& disposal, int64_t timestamp)
272 {
273 if (eventTreeList.empty()) {
274 return;
275 }
276 auto& gestureMap = eventTreeList.back().gestureMap;
277 auto iter = gestureMap.find(id);
278 if (iter == gestureMap.end()) {
279 return;
280 }
281
282 if ((point.type == TouchType::MOVE || point.type == TouchType::PULL_MOVE) &&
283 !iter->second->CheckNeedAddMove(state, disposal)) {
284 return;
285 }
286 std::string procedure = std::string("Handle").append(GestureSnapshot::TransTouchType(point.type));
287 iter->second->AddProcedure(procedure, extraInfo, state, disposal, timestamp);
288 }
289
Dump(std::list<std::pair<int32_t,std::string>> & dumpList,int32_t depth,int32_t startNumber) const290 void EventTreeRecord::Dump(std::list<std::pair<int32_t, std::string>>& dumpList,
291 int32_t depth, int32_t startNumber) const
292 {
293 int32_t index = 0;
294 int32_t listDepth = depth + 1;
295 int32_t detailDepth = listDepth + 1;
296 for (auto& tree : eventTreeList) {
297 if (index < startNumber) {
298 index++;
299 continue;
300 }
301 std::string header = std::to_string(index).append(": event tree =>");
302
303 // dump needful touch points:
304 dumpList.emplace_back(std::make_pair(depth, header));
305 dumpList.emplace_back(std::make_pair(listDepth, "touch points:"));
306 for (auto& item : tree.touchPoints) {
307 item.Dump(dumpList, detailDepth);
308 }
309
310 // dump needful axis:
311 dumpList.emplace_back(std::make_pair(listDepth, "axis:"));
312 for (auto& item : tree.axis) {
313 item.Dump(dumpList, detailDepth);
314 }
315
316 // dump hit test frame nodes:
317 dumpList.emplace_back(std::make_pair(listDepth, "hittest:"));
318 for (auto& item : tree.hitTestTree) {
319 item.Dump(dumpList, detailDepth);
320 }
321
322 // dump gesture event and procedure:
323 dumpList.emplace_back(std::make_pair(listDepth, "event procedures:"));
324 for (auto iter = tree.gestureTree.begin(); iter != tree.gestureTree.end(); ++iter) {
325 dumpList.emplace_back(std::make_pair(detailDepth,
326 std::string("finger:").append(std::to_string(iter->first))));
327 for (const auto& item : iter->second) {
328 item->Dump(dumpList, detailDepth + 1);
329 }
330 }
331 ++index;
332 }
333 }
334
Dump(std::unique_ptr<JsonValue> & json) const335 void AxisSnapshot::Dump(std::unique_ptr<JsonValue>& json) const
336 {
337 json->Put("point", point.ToString().c_str());
338 json->Put("screenPoint", screenPoint.ToString().c_str());
339 switch (action) {
340 case AxisAction::BEGIN:
341 json->Put("action", "BEGIN");
342 break;
343 case AxisAction::UPDATE:
344 json->Put("action", "UPDATE");
345 break;
346 case AxisAction::END:
347 json->Put("action", "END");
348 break;
349 default:
350 LOGW("AxisAction: Unknown AxisAction action %{public}d", action);
351 break;
352 }
353 json->Put("timestamp", ConvertTimestampToStr(timestamp).c_str());
354 json->Put("isInjected", isInjected);
355 }
356
BuildAxis(std::list<AxisSnapshot> axis,std::unique_ptr<JsonValue> & json) const357 void EventTreeRecord::BuildAxis(
358 std::list<AxisSnapshot> axis, std::unique_ptr<JsonValue>& json) const
359 {
360 std::unique_ptr<JsonValue> axisEvent = JsonUtil::CreateArray(true);
361 for (auto& item : axis) {
362 std::unique_ptr<JsonValue> child = JsonUtil::Create(true);
363 item.Dump(child);
364 axisEvent->Put(child);
365 }
366 json->Put("axis", axisEvent);
367 }
368 } // end of namespace
369