• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_processor/importers/proto/frame_timeline_event_parser.h"
18 
19 #include <inttypes.h>
20 
21 #include "perfetto/ext/base/utils.h"
22 #include "perfetto/protozero/field.h"
23 #include "src/trace_processor/importers/common/args_tracker.h"
24 #include "src/trace_processor/importers/common/event_tracker.h"
25 #include "src/trace_processor/importers/common/flow_tracker.h"
26 #include "src/trace_processor/importers/common/process_tracker.h"
27 #include "src/trace_processor/importers/common/slice_tracker.h"
28 #include "src/trace_processor/importers/common/track_tracker.h"
29 #include "src/trace_processor/types/trace_processor_context.h"
30 
31 #include "protos/perfetto/trace/interned_data/interned_data.pbzero.h"
32 
33 namespace perfetto {
34 namespace trace_processor {
35 namespace {
36 
IsBadTimestamp(int64_t ts)37 bool IsBadTimestamp(int64_t ts) {
38   // Very small or very large timestamps are likely a mistake.
39   // See b/185978397
40   constexpr int64_t kBadTimestamp =
41       std::numeric_limits<int64_t>::max() - (10LL * 1000 * 1000 * 1000);
42   return std::abs(ts) >= kBadTimestamp;
43 }
44 
45 }  // namespace
46 
47 using ExpectedDisplayFrameStartDecoder =
48     protos::pbzero::FrameTimelineEvent_ExpectedDisplayFrameStart_Decoder;
49 using ActualDisplayFrameStartDecoder =
50     protos::pbzero::FrameTimelineEvent_ActualDisplayFrameStart_Decoder;
51 
52 using ExpectedSurfaceFrameStartDecoder =
53     protos::pbzero::FrameTimelineEvent_ExpectedSurfaceFrameStart_Decoder;
54 using ActualSurfaceFrameStartDecoder =
55     protos::pbzero::FrameTimelineEvent_ActualSurfaceFrameStart_Decoder;
56 
57 using FrameEndDecoder = protos::pbzero::FrameTimelineEvent_FrameEnd_Decoder;
58 
JankTypeBitmaskToStringId(TraceProcessorContext * context,int32_t jank_type)59 static StringId JankTypeBitmaskToStringId(TraceProcessorContext* context,
60                                           int32_t jank_type) {
61   if (jank_type == FrameTimelineEvent::JANK_UNSPECIFIED)
62     return context->storage->InternString("Unspecified");
63   if (jank_type == FrameTimelineEvent::JANK_NONE)
64     return context->storage->InternString("None");
65 
66   std::vector<std::string> jank_reasons;
67   if (jank_type & FrameTimelineEvent::JANK_SF_SCHEDULING)
68     jank_reasons.emplace_back("SurfaceFlinger Scheduling");
69   if (jank_type & FrameTimelineEvent::JANK_PREDICTION_ERROR)
70     jank_reasons.emplace_back("Prediction Error");
71   if (jank_type & FrameTimelineEvent::JANK_DISPLAY_HAL)
72     jank_reasons.emplace_back("Display HAL");
73   if (jank_type & FrameTimelineEvent::JANK_SF_CPU_DEADLINE_MISSED)
74     jank_reasons.emplace_back("SurfaceFlinger CPU Deadline Missed");
75   if (jank_type & FrameTimelineEvent::JANK_SF_GPU_DEADLINE_MISSED)
76     jank_reasons.emplace_back("SurfaceFlinger GPU Deadline Missed");
77   if (jank_type & FrameTimelineEvent::JANK_APP_DEADLINE_MISSED)
78     jank_reasons.emplace_back("App Deadline Missed");
79   if (jank_type & FrameTimelineEvent::JANK_BUFFER_STUFFING)
80     jank_reasons.emplace_back("Buffer Stuffing");
81   if (jank_type & FrameTimelineEvent::JANK_UNKNOWN)
82     jank_reasons.emplace_back("Unknown Jank");
83   if (jank_type & FrameTimelineEvent::JANK_SF_STUFFING)
84     jank_reasons.emplace_back("SurfaceFlinger Stuffing");
85 
86   std::string jank_str(
87       std::accumulate(jank_reasons.begin(), jank_reasons.end(), std::string(),
88                       [](const std::string& l, const std::string& r) {
89                         return l.empty() ? r : l + ", " + r;
90                       }));
91   return context->storage->InternString(base::StringView(jank_str));
92 }
93 
DisplayFrameJanky(int32_t jank_type)94 static bool DisplayFrameJanky(int32_t jank_type) {
95   if (jank_type == FrameTimelineEvent::JANK_UNSPECIFIED || jank_type == FrameTimelineEvent::JANK_NONE)
96     return false;
97 
98   int32_t display_frame_jank_bitmask = FrameTimelineEvent::JANK_SF_SCHEDULING | FrameTimelineEvent::JANK_PREDICTION_ERROR | FrameTimelineEvent::JANK_DISPLAY_HAL | FrameTimelineEvent::JANK_SF_CPU_DEADLINE_MISSED | FrameTimelineEvent::JANK_SF_GPU_DEADLINE_MISSED;
99   if (jank_type & display_frame_jank_bitmask)
100       return true;
101   return false;
102 }
103 
SurfaceFrameJanky(int32_t jank_type)104 static bool SurfaceFrameJanky(int32_t jank_type) {
105   if (jank_type == FrameTimelineEvent::JANK_UNSPECIFIED || jank_type == FrameTimelineEvent::JANK_NONE)
106     return false;
107 
108   int32_t surface_frame_jank_bitmask = FrameTimelineEvent::JANK_APP_DEADLINE_MISSED | FrameTimelineEvent::JANK_UNKNOWN;
109   if (jank_type & surface_frame_jank_bitmask)
110     return true;
111   return false;
112 }
113 
ValidatePredictionType(TraceProcessorContext * context,int32_t prediction_type)114 static bool ValidatePredictionType(TraceProcessorContext* context,
115                                    int32_t prediction_type) {
116   if (prediction_type >= FrameTimelineEvent::PREDICTION_VALID /*1*/ &&
117       prediction_type <= FrameTimelineEvent::PREDICTION_UNKNOWN /*3*/)
118     return true;
119   context->storage->IncrementStats(stats::frame_timeline_event_parser_errors);
120   return false;
121 }
122 
ValidatePresentType(TraceProcessorContext * context,int32_t present_type)123 static bool ValidatePresentType(TraceProcessorContext* context,
124                                 int32_t present_type) {
125   if (present_type >= FrameTimelineEvent::PRESENT_ON_TIME /*1*/ &&
126       present_type <= FrameTimelineEvent::PRESENT_UNKNOWN /*5*/)
127     return true;
128   context->storage->IncrementStats(stats::frame_timeline_event_parser_errors);
129   return false;
130 }
131 
FrameTimelineEventParser(TraceProcessorContext * context)132 FrameTimelineEventParser::FrameTimelineEventParser(
133     TraceProcessorContext* context)
134     : context_(context),
135       present_type_ids_{
136           {context->storage->InternString(
137                "Unspecified Present") /* PRESENT_UNSPECIFIED */,
138            context->storage->InternString(
139                "On-time Present") /* PRESENT_ON_TIME */,
140            context->storage->InternString("Late Present") /* PRESENT_LATE */,
141            context->storage->InternString("Early Present") /* PRESENT_EARLY */,
142            context->storage->InternString(
143                "Dropped Frame") /* PRESENT_DROPPED */,
144            context->storage->InternString(
145                "Unknown Present") /* PRESENT_UNKNOWN */}},
146       prediction_type_ids_{
147           {context->storage->InternString(
148                "Unspecified Prediction") /* PREDICTION_UNSPECIFIED */,
149            context->storage->InternString(
150                "Valid Prediction") /* PREDICTION_VALID */,
151            context->storage->InternString(
152                "Expired Prediction") /* PREDICTION_EXPIRED */,
153            context->storage->InternString(
154                "Unknown Prediction") /* PREDICTION_UNKNOWN */}},
155       expected_timeline_track_name_(
156           context->storage->InternString("Expected Timeline")),
157       actual_timeline_track_name_(
158           context->storage->InternString("Actual Timeline")),
159       surface_frame_token_id_(
160           context->storage->InternString("Surface frame token")),
161       display_frame_token_id_(
162           context->storage->InternString("Display frame token")),
163       present_type_id_(context->storage->InternString("Present type")),
164       on_time_finish_id_(context->storage->InternString("On time finish")),
165       gpu_composition_id_(context->storage->InternString("GPU composition")),
166       jank_type_id_(context->storage->InternString("Jank type")),
167       layer_name_id_(context->storage->InternString("Layer name")),
168       prediction_type_id_(context->storage->InternString("Prediction type")),
169       is_buffer_id_(context->storage->InternString("Is Buffer?")),
170       jank_tag_none_id_(context->storage->InternString("No Jank")),
171       jank_tag_self_id_(context->storage->InternString("Self Jank")),
172       jank_tag_other_id_(context->storage->InternString("Other Jank")),
173       jank_tag_dropped_id_(context->storage->InternString("Dropped Frame")),
174       jank_tag_buffer_stuffing_id_(
175           context->storage->InternString("Buffer Stuffing")),
176       jank_tag_sf_stuffing_id_(
177           context->storage->InternString("SurfaceFlinger Stuffing")) {}
178 
ParseExpectedDisplayFrameStart(int64_t timestamp,ConstBytes bufferBlob)179 void FrameTimelineEventParser::ParseExpectedDisplayFrameStart(
180     int64_t timestamp,
181     ConstBytes bufferBlob) {
182   ExpectedDisplayFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
183   if (!event.has_cookie()) {
184     context_->storage->IncrementStats(
185         stats::frame_timeline_event_parser_errors);
186     return;
187   }
188 
189   if (!event.has_token()) {
190     context_->storage->IncrementStats(
191         stats::frame_timeline_event_parser_errors);
192     return;
193   }
194 
195   if (!event.has_pid()) {
196     context_->storage->IncrementStats(
197         stats::frame_timeline_event_parser_errors);
198     return;
199   }
200 
201   int64_t cookie = event.cookie();
202   int64_t token = event.token();
203   StringId name_id =
204       context_->storage->InternString(base::StringView(std::to_string(token)));
205 
206   UniquePid upid = context_->process_tracker->GetOrCreateProcess(
207       static_cast<uint32_t>(event.pid()));
208   auto expected_track_set_id =
209       context_->async_track_set_tracker->InternFrameTimelineSet(
210           upid, expected_timeline_track_name_);
211   cookie_track_set_id_map_[cookie] = expected_track_set_id;
212 
213   tables::ExpectedFrameTimelineSliceTable::Row expected_row;
214   expected_row.ts = timestamp;
215   expected_row.track_id =
216       context_->async_track_set_tracker->Begin(expected_track_set_id, cookie);
217   expected_row.name = name_id;
218 
219   expected_row.display_frame_token = token;
220   expected_row.upid = upid;
221 
222   context_->slice_tracker->BeginTyped(
223       context_->storage->mutable_expected_frame_timeline_slice_table(),
224       expected_row, [this, token](ArgsTracker::BoundInserter* inserter) {
225         inserter->AddArg(display_frame_token_id_, Variadic::Integer(token));
226       });
227 }
228 
ParseActualDisplayFrameStart(int64_t timestamp,ConstBytes bufferBlob)229 void FrameTimelineEventParser::ParseActualDisplayFrameStart(
230     int64_t timestamp,
231     ConstBytes bufferBlob) {
232   ActualDisplayFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
233   if (!event.has_cookie()) {
234     context_->storage->IncrementStats(
235         stats::frame_timeline_event_parser_errors);
236     return;
237   }
238 
239   if (!event.has_token()) {
240     context_->storage->IncrementStats(
241         stats::frame_timeline_event_parser_errors);
242     return;
243   }
244   if (!event.has_pid()) {
245     context_->storage->IncrementStats(
246         stats::frame_timeline_event_parser_errors);
247     return;
248   }
249 
250   int64_t cookie = event.cookie();
251   int64_t token = event.token();
252   StringId name_id =
253       context_->storage->InternString(base::StringView(std::to_string(token)));
254 
255   UniquePid upid = context_->process_tracker->GetOrCreateProcess(
256       static_cast<uint32_t>(event.pid()));
257   auto actual_track_set_id =
258       context_->async_track_set_tracker->InternFrameTimelineSet(
259           upid, actual_timeline_track_name_);
260   cookie_track_set_id_map_[cookie] = actual_track_set_id;
261 
262   tables::ActualFrameTimelineSliceTable::Row actual_row;
263   actual_row.ts = timestamp;
264   actual_row.track_id =
265       context_->async_track_set_tracker->Begin(actual_track_set_id, cookie);
266   actual_row.name = name_id;
267   actual_row.display_frame_token = token;
268   actual_row.upid = upid;
269   StringId present_type = present_type_ids_[0];
270   if (event.has_present_type() &&
271       ValidatePresentType(context_, event.present_type())) {
272     present_type = present_type_ids_[static_cast<size_t>(event.present_type())];
273   }
274   actual_row.present_type = present_type;
275   actual_row.on_time_finish = event.on_time_finish();
276   actual_row.gpu_composition = event.gpu_composition();
277   StringId jank_type = JankTypeBitmaskToStringId(context_, event.jank_type());
278   actual_row.jank_type = jank_type;
279   StringId prediction_type = prediction_type_ids_[0];
280   if (event.has_prediction_type() &&
281       ValidatePredictionType(context_, event.prediction_type())) {
282     prediction_type =
283         prediction_type_ids_[static_cast<size_t>(event.prediction_type())];
284   }
285   actual_row.prediction_type = prediction_type;
286   if (DisplayFrameJanky(event.jank_type())) {
287     actual_row.jank_tag = jank_tag_self_id_;
288   } else if (event.jank_type() == FrameTimelineEvent::JANK_SF_STUFFING) {
289     actual_row.jank_tag = jank_tag_sf_stuffing_id_;
290   } else {
291     actual_row.jank_tag = jank_tag_none_id_;
292   }
293 
294   base::Optional<SliceId> opt_slice_id =
295       context_->slice_tracker->BeginTyped(
296           context_->storage->mutable_actual_frame_timeline_slice_table(),
297           actual_row,
298           [this, token, jank_type, present_type, prediction_type,
299            &event](ArgsTracker::BoundInserter* inserter) {
300             inserter->AddArg(display_frame_token_id_, Variadic::Integer(token));
301             inserter->AddArg(present_type_id_, Variadic::String(present_type));
302             inserter->AddArg(on_time_finish_id_,
303                              Variadic::Integer(event.on_time_finish()));
304             inserter->AddArg(gpu_composition_id_,
305                              Variadic::Integer(event.gpu_composition()));
306             inserter->AddArg(jank_type_id_, Variadic::String(jank_type));
307             inserter->AddArg(prediction_type_id_,
308                              Variadic::String(prediction_type));
309           });
310 
311   // SurfaceFrames will always be parsed before the matching DisplayFrame
312   // (since the app works on the frame before SurfaceFlinger does). Because
313   // of this it's safe to add all the flow events here and then forget the
314   // surface_slice id - we shouldn't see more surfaces_slices that should be
315   // connected to this slice after this point.
316   auto range = display_token_to_surface_slice_.equal_range(token);
317   if (opt_slice_id) {
318     for (auto it = range.first; it != range.second; ++it) {
319       SliceId display_slice = *opt_slice_id;  // SurfaceFlinger
320       SliceId surface_slice = it->second;     // App
321       context_->flow_tracker->InsertFlow(display_slice, surface_slice);
322     }
323   }
324   display_token_to_surface_slice_.erase(range.first, range.second);
325 }
326 
ParseExpectedSurfaceFrameStart(int64_t timestamp,ConstBytes bufferBlob)327 void FrameTimelineEventParser::ParseExpectedSurfaceFrameStart(
328     int64_t timestamp,
329     ConstBytes bufferBlob) {
330   ExpectedSurfaceFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
331 
332   if (!event.has_cookie()) {
333     context_->storage->IncrementStats(
334         stats::frame_timeline_event_parser_errors);
335     return;
336   }
337 
338   if (!event.has_token()) {
339     context_->storage->IncrementStats(
340         stats::frame_timeline_event_parser_errors);
341     return;
342   }
343 
344   if (!event.has_display_frame_token()) {
345     context_->storage->IncrementStats(
346         stats::frame_timeline_event_parser_errors);
347     return;
348   }
349 
350   if (!event.has_pid()) {
351     context_->storage->IncrementStats(
352         stats::frame_timeline_event_parser_errors);
353     return;
354   }
355 
356   int64_t cookie = event.cookie();
357   int64_t token = event.token();
358   int64_t display_frame_token = event.display_frame_token();
359   UniquePid upid = context_->process_tracker->GetOrCreateProcess(
360       static_cast<uint32_t>(event.pid()));
361   auto token_set_it = expected_timeline_token_map_.find(upid);
362   if (token_set_it != expected_timeline_token_map_.end()) {
363     auto& token_set = token_set_it->second;
364     if (token_set.find(token) != token_set.end()) {
365       // If we already have an expected timeline for a token, the expectations
366       // are same for all frames that use the token. No need to add duplicate
367       // entries.
368       return;
369     }
370   }
371   // This is the first time we are seeing this token for this process. Add to
372   // the map.
373   expected_timeline_token_map_[upid].insert(token);
374 
375   StringId layer_name_id = event.has_layer_name()
376                                ? context_->storage->InternString(
377                                      base::StringView(event.layer_name()))
378                                : kNullStringId;
379   StringId name_id =
380       context_->storage->InternString(base::StringView(std::to_string(token)));
381 
382   auto expected_track_set_id =
383       context_->async_track_set_tracker->InternFrameTimelineSet(
384           upid, expected_timeline_track_name_);
385   cookie_track_set_id_map_[cookie] = expected_track_set_id;
386 
387   tables::ExpectedFrameTimelineSliceTable::Row expected_row;
388   expected_row.ts = timestamp;
389   expected_row.track_id =
390       context_->async_track_set_tracker->Begin(expected_track_set_id, cookie);
391   expected_row.name = name_id;
392 
393   expected_row.surface_frame_token = token;
394   expected_row.display_frame_token = display_frame_token;
395   expected_row.upid = upid;
396   expected_row.layer_name = layer_name_id;
397   context_->slice_tracker->BeginTyped(
398       context_->storage->mutable_expected_frame_timeline_slice_table(),
399       expected_row,
400       [this, token, layer_name_id](ArgsTracker::BoundInserter* inserter) {
401         inserter->AddArg(display_frame_token_id_, Variadic::Integer(token));
402         inserter->AddArg(layer_name_id_, Variadic::String(layer_name_id));
403       });
404 }
405 
ParseActualSurfaceFrameStart(int64_t timestamp,ConstBytes bufferBlob)406 void FrameTimelineEventParser::ParseActualSurfaceFrameStart(
407     int64_t timestamp,
408     ConstBytes bufferBlob) {
409   ActualSurfaceFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
410 
411   if (!event.has_cookie()) {
412     context_->storage->IncrementStats(
413         stats::frame_timeline_event_parser_errors);
414     return;
415   }
416 
417   if (!event.has_token()) {
418     context_->storage->IncrementStats(
419         stats::frame_timeline_event_parser_errors);
420     return;
421   }
422 
423   if (!event.has_display_frame_token()) {
424     context_->storage->IncrementStats(
425         stats::frame_timeline_event_parser_errors);
426     return;
427   }
428 
429   if (!event.has_pid()) {
430     context_->storage->IncrementStats(
431         stats::frame_timeline_event_parser_errors);
432     return;
433   }
434 
435   int64_t cookie = event.cookie();
436   int64_t token = event.token();
437   int64_t display_frame_token = event.display_frame_token();
438 
439   UniquePid upid = context_->process_tracker->GetOrCreateProcess(
440       static_cast<uint32_t>(event.pid()));
441   StringId layer_name_id;
442   if (event.has_layer_name())
443     layer_name_id =
444         context_->storage->InternString(base::StringView(event.layer_name()));
445   StringId name_id =
446       context_->storage->InternString(base::StringView(std::to_string(token)));
447 
448   auto actual_track_set_id =
449       context_->async_track_set_tracker->InternFrameTimelineSet(
450           upid, actual_timeline_track_name_);
451   cookie_track_set_id_map_[cookie] = actual_track_set_id;
452 
453   tables::ActualFrameTimelineSliceTable::Row actual_row;
454   actual_row.ts = timestamp;
455   actual_row.track_id =
456       context_->async_track_set_tracker->Begin(actual_track_set_id, cookie);
457   actual_row.name = name_id;
458   actual_row.surface_frame_token = token;
459   actual_row.display_frame_token = display_frame_token;
460   actual_row.upid = upid;
461   actual_row.layer_name = layer_name_id;
462   StringId present_type = present_type_ids_[0];
463   bool present_type_validated = false;
464   if (event.has_present_type() &&
465       ValidatePresentType(context_, event.present_type())) {
466     present_type_validated = true;
467     present_type = present_type_ids_[static_cast<size_t>(event.present_type())];
468   }
469   actual_row.present_type = present_type;
470   actual_row.on_time_finish = event.on_time_finish();
471   actual_row.gpu_composition = event.gpu_composition();
472   StringId jank_type = JankTypeBitmaskToStringId(context_, event.jank_type());
473   actual_row.jank_type = jank_type;
474   StringId prediction_type = prediction_type_ids_[0];
475   if (event.has_prediction_type() &&
476       ValidatePredictionType(context_, event.prediction_type())) {
477     prediction_type =
478         prediction_type_ids_[static_cast<size_t>(event.prediction_type())];
479   }
480   actual_row.prediction_type = prediction_type;
481   if (SurfaceFrameJanky(event.jank_type())) {
482     actual_row.jank_tag = jank_tag_self_id_;
483   } else if (DisplayFrameJanky(event.jank_type())) {
484     actual_row.jank_tag = jank_tag_other_id_;
485   } else if (event.jank_type() == FrameTimelineEvent::JANK_BUFFER_STUFFING) {
486     actual_row.jank_tag = jank_tag_buffer_stuffing_id_;
487   } else if (present_type_validated &&
488              event.present_type() == FrameTimelineEvent::PRESENT_DROPPED) {
489     actual_row.jank_tag = jank_tag_dropped_id_;
490   } else {
491     actual_row.jank_tag = jank_tag_none_id_;
492   }
493   StringId is_buffer = context_->storage->InternString("Unspecified");
494   if (event.has_is_buffer()) {
495     if (event.is_buffer())
496       is_buffer = context_->storage->InternString("Yes");
497     else
498       is_buffer = context_->storage->InternString("No");
499   }
500 
501   base::Optional<SliceId> opt_slice_id =
502       context_->slice_tracker->BeginTyped(
503           context_->storage->mutable_actual_frame_timeline_slice_table(),
504           actual_row,
505           [this, jank_type, present_type, token, layer_name_id,
506            display_frame_token, prediction_type, is_buffer,
507            &event](ArgsTracker::BoundInserter* inserter) {
508             inserter->AddArg(surface_frame_token_id_, Variadic::Integer(token));
509             inserter->AddArg(display_frame_token_id_,
510                              Variadic::Integer(display_frame_token));
511             inserter->AddArg(layer_name_id_, Variadic::String(layer_name_id));
512             inserter->AddArg(present_type_id_, Variadic::String(present_type));
513             inserter->AddArg(on_time_finish_id_,
514                              Variadic::Integer(event.on_time_finish()));
515             inserter->AddArg(gpu_composition_id_,
516                              Variadic::Integer(event.gpu_composition()));
517             inserter->AddArg(jank_type_id_, Variadic::String(jank_type));
518             inserter->AddArg(prediction_type_id_,
519                              Variadic::String(prediction_type));
520             inserter->AddArg(is_buffer_id_, Variadic::String(is_buffer));
521           });
522 
523   if (opt_slice_id) {
524     display_token_to_surface_slice_.emplace(display_frame_token, *opt_slice_id);
525   }
526 }
527 
ParseFrameEnd(int64_t timestamp,ConstBytes bufferBlob)528 void FrameTimelineEventParser::ParseFrameEnd(int64_t timestamp,
529                                              ConstBytes bufferBlob) {
530   FrameEndDecoder event(bufferBlob.data, bufferBlob.size);
531 
532   if (!event.has_cookie()) {
533     context_->storage->IncrementStats(
534         stats::frame_timeline_event_parser_errors);
535     return;
536   }
537 
538   int64_t cookie = event.cookie();
539   auto it = cookie_track_set_id_map_.find(cookie);
540   if (it == cookie_track_set_id_map_.end())
541     return;
542   auto track_set_id = it->second;
543   auto track_id = context_->async_track_set_tracker->End(track_set_id, cookie);
544   context_->slice_tracker->End(timestamp, track_id);
545   cookie_track_set_id_map_.erase(it);
546 }
547 
ParseFrameTimelineEvent(int64_t timestamp,ConstBytes blob)548 void FrameTimelineEventParser::ParseFrameTimelineEvent(int64_t timestamp,
549                                                        ConstBytes blob) {
550   protos::pbzero::FrameTimelineEvent_Decoder frame_event(blob.data, blob.size);
551 
552   if (IsBadTimestamp(timestamp)) {
553     context_->storage->IncrementStats(
554         stats::frame_timeline_event_parser_errors);
555     return;
556   }
557 
558   if (frame_event.has_expected_display_frame_start()) {
559     ParseExpectedDisplayFrameStart(timestamp,
560                                    frame_event.expected_display_frame_start());
561   } else if (frame_event.has_actual_display_frame_start()) {
562     ParseActualDisplayFrameStart(timestamp,
563                                  frame_event.actual_display_frame_start());
564   } else if (frame_event.has_expected_surface_frame_start()) {
565     ParseExpectedSurfaceFrameStart(timestamp,
566                                    frame_event.expected_surface_frame_start());
567   } else if (frame_event.has_actual_surface_frame_start()) {
568     ParseActualSurfaceFrameStart(timestamp,
569                                  frame_event.actual_surface_frame_start());
570   } else if (frame_event.has_frame_end()) {
571     ParseFrameEnd(timestamp, frame_event.frame_end());
572   } else {
573     context_->storage->IncrementStats(
574         stats::frame_timeline_event_parser_errors);
575   }
576 }
577 }  // namespace trace_processor
578 }  // namespace perfetto
579