• 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 <cinttypes>
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   if (jank_type & FrameTimelineEvent::JANK_DROPPED)
86     jank_reasons.emplace_back("Dropped Frame");
87 
88   std::string jank_str(
89       std::accumulate(jank_reasons.begin(), jank_reasons.end(), std::string(),
90                       [](const std::string& l, const std::string& r) {
91                         return l.empty() ? r : l + ", " + r;
92                       }));
93   return context->storage->InternString(base::StringView(jank_str));
94 }
95 
DisplayFrameJanky(int32_t jank_type)96 static bool DisplayFrameJanky(int32_t jank_type) {
97   if (jank_type == FrameTimelineEvent::JANK_UNSPECIFIED ||
98       jank_type == FrameTimelineEvent::JANK_NONE)
99     return false;
100 
101   int32_t display_frame_jank_bitmask =
102       FrameTimelineEvent::JANK_SF_SCHEDULING |
103       FrameTimelineEvent::JANK_PREDICTION_ERROR |
104       FrameTimelineEvent::JANK_DISPLAY_HAL |
105       FrameTimelineEvent::JANK_SF_CPU_DEADLINE_MISSED |
106       FrameTimelineEvent::JANK_SF_GPU_DEADLINE_MISSED;
107   if (jank_type & display_frame_jank_bitmask)
108     return true;
109   return false;
110 }
111 
SurfaceFrameJanky(int32_t jank_type)112 static bool SurfaceFrameJanky(int32_t jank_type) {
113   if (jank_type == FrameTimelineEvent::JANK_UNSPECIFIED ||
114       jank_type == FrameTimelineEvent::JANK_NONE)
115     return false;
116 
117   int32_t surface_frame_jank_bitmask =
118       FrameTimelineEvent::JANK_APP_DEADLINE_MISSED |
119       FrameTimelineEvent::JANK_UNKNOWN;
120   if (jank_type & surface_frame_jank_bitmask)
121     return true;
122   return false;
123 }
124 
ValidatePredictionType(TraceProcessorContext * context,int32_t prediction_type)125 static bool ValidatePredictionType(TraceProcessorContext* context,
126                                    int32_t prediction_type) {
127   if (prediction_type >= FrameTimelineEvent::PREDICTION_VALID /*1*/ &&
128       prediction_type <= FrameTimelineEvent::PREDICTION_UNKNOWN /*3*/)
129     return true;
130   context->storage->IncrementStats(stats::frame_timeline_event_parser_errors);
131   return false;
132 }
133 
ValidatePresentType(TraceProcessorContext * context,int32_t present_type)134 static bool ValidatePresentType(TraceProcessorContext* context,
135                                 int32_t present_type) {
136   if (present_type >= FrameTimelineEvent::PRESENT_ON_TIME /*1*/ &&
137       present_type <= FrameTimelineEvent::PRESENT_UNKNOWN /*5*/)
138     return true;
139   context->storage->IncrementStats(stats::frame_timeline_event_parser_errors);
140   return false;
141 }
142 
FrameTimelineEventParser(TraceProcessorContext * context)143 FrameTimelineEventParser::FrameTimelineEventParser(
144     TraceProcessorContext* context)
145     : context_(context),
146       present_type_ids_{
147           {context->storage->InternString(
148                "Unspecified Present") /* PRESENT_UNSPECIFIED */,
149            context->storage->InternString(
150                "On-time Present") /* PRESENT_ON_TIME */,
151            context->storage->InternString("Late Present") /* PRESENT_LATE */,
152            context->storage->InternString("Early Present") /* PRESENT_EARLY */,
153            context->storage->InternString(
154                "Dropped Frame") /* PRESENT_DROPPED */,
155            context->storage->InternString(
156                "Unknown Present") /* PRESENT_UNKNOWN */}},
157       prediction_type_ids_{
158           {context->storage->InternString(
159                "Unspecified Prediction") /* PREDICTION_UNSPECIFIED */,
160            context->storage->InternString(
161                "Valid Prediction") /* PREDICTION_VALID */,
162            context->storage->InternString(
163                "Expired Prediction") /* PREDICTION_EXPIRED */,
164            context->storage->InternString(
165                "Unknown Prediction") /* PREDICTION_UNKNOWN */}},
166       expected_timeline_track_name_(
167           context->storage->InternString("Expected Timeline")),
168       actual_timeline_track_name_(
169           context->storage->InternString("Actual Timeline")),
170       surface_frame_token_id_(
171           context->storage->InternString("Surface frame token")),
172       display_frame_token_id_(
173           context->storage->InternString("Display frame token")),
174       present_type_id_(context->storage->InternString("Present type")),
175       on_time_finish_id_(context->storage->InternString("On time finish")),
176       gpu_composition_id_(context->storage->InternString("GPU composition")),
177       jank_type_id_(context->storage->InternString("Jank type")),
178       layer_name_id_(context->storage->InternString("Layer name")),
179       prediction_type_id_(context->storage->InternString("Prediction type")),
180       is_buffer_id_(context->storage->InternString("Is Buffer?")),
181       jank_tag_none_id_(context->storage->InternString("No Jank")),
182       jank_tag_self_id_(context->storage->InternString("Self Jank")),
183       jank_tag_other_id_(context->storage->InternString("Other Jank")),
184       jank_tag_dropped_id_(context->storage->InternString("Dropped Frame")),
185       jank_tag_buffer_stuffing_id_(
186           context->storage->InternString("Buffer Stuffing")),
187       jank_tag_sf_stuffing_id_(
188           context->storage->InternString("SurfaceFlinger Stuffing")) {}
189 
ParseExpectedDisplayFrameStart(int64_t timestamp,ConstBytes bufferBlob)190 void FrameTimelineEventParser::ParseExpectedDisplayFrameStart(
191     int64_t timestamp,
192     ConstBytes bufferBlob) {
193   ExpectedDisplayFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
194   if (!event.has_cookie()) {
195     context_->storage->IncrementStats(
196         stats::frame_timeline_event_parser_errors);
197     return;
198   }
199 
200   if (!event.has_token()) {
201     context_->storage->IncrementStats(
202         stats::frame_timeline_event_parser_errors);
203     return;
204   }
205 
206   if (!event.has_pid()) {
207     context_->storage->IncrementStats(
208         stats::frame_timeline_event_parser_errors);
209     return;
210   }
211 
212   int64_t cookie = event.cookie();
213   int64_t token = event.token();
214   StringId name_id =
215       context_->storage->InternString(base::StringView(std::to_string(token)));
216 
217   UniquePid upid = context_->process_tracker->GetOrCreateProcess(
218       static_cast<uint32_t>(event.pid()));
219   auto expected_track_set_id =
220       context_->async_track_set_tracker->InternProcessTrackSet(
221           upid, expected_timeline_track_name_);
222   cookie_track_set_id_map_[cookie] = expected_track_set_id;
223 
224   tables::ExpectedFrameTimelineSliceTable::Row expected_row;
225   expected_row.ts = timestamp;
226   expected_row.track_id =
227       context_->async_track_set_tracker->Begin(expected_track_set_id, cookie);
228   expected_row.name = name_id;
229 
230   expected_row.display_frame_token = token;
231   expected_row.upid = upid;
232 
233   context_->slice_tracker->BeginTyped(
234       context_->storage->mutable_expected_frame_timeline_slice_table(),
235       expected_row, [this, token](ArgsTracker::BoundInserter* inserter) {
236         inserter->AddArg(display_frame_token_id_, Variadic::Integer(token));
237       });
238 }
239 
ParseActualDisplayFrameStart(int64_t timestamp,ConstBytes bufferBlob)240 void FrameTimelineEventParser::ParseActualDisplayFrameStart(
241     int64_t timestamp,
242     ConstBytes bufferBlob) {
243   ActualDisplayFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
244   if (!event.has_cookie()) {
245     context_->storage->IncrementStats(
246         stats::frame_timeline_event_parser_errors);
247     return;
248   }
249 
250   if (!event.has_token()) {
251     context_->storage->IncrementStats(
252         stats::frame_timeline_event_parser_errors);
253     return;
254   }
255   if (!event.has_pid()) {
256     context_->storage->IncrementStats(
257         stats::frame_timeline_event_parser_errors);
258     return;
259   }
260 
261   int64_t cookie = event.cookie();
262   int64_t token = event.token();
263   StringId name_id =
264       context_->storage->InternString(base::StringView(std::to_string(token)));
265 
266   UniquePid upid = context_->process_tracker->GetOrCreateProcess(
267       static_cast<uint32_t>(event.pid()));
268   auto actual_track_set_id =
269       context_->async_track_set_tracker->InternProcessTrackSet(
270           upid, actual_timeline_track_name_);
271   cookie_track_set_id_map_[cookie] = actual_track_set_id;
272 
273   tables::ActualFrameTimelineSliceTable::Row actual_row;
274   actual_row.ts = timestamp;
275   actual_row.track_id =
276       context_->async_track_set_tracker->Begin(actual_track_set_id, cookie);
277   actual_row.name = name_id;
278   actual_row.display_frame_token = token;
279   actual_row.upid = upid;
280   StringId present_type = present_type_ids_[0];
281   if (event.has_present_type() &&
282       ValidatePresentType(context_, event.present_type())) {
283     present_type = present_type_ids_[static_cast<size_t>(event.present_type())];
284   }
285   actual_row.present_type = present_type;
286   actual_row.on_time_finish = event.on_time_finish();
287   actual_row.gpu_composition = event.gpu_composition();
288   StringId jank_type = JankTypeBitmaskToStringId(context_, event.jank_type());
289   actual_row.jank_type = jank_type;
290   StringId prediction_type = prediction_type_ids_[0];
291   if (event.has_prediction_type() &&
292       ValidatePredictionType(context_, event.prediction_type())) {
293     prediction_type =
294         prediction_type_ids_[static_cast<size_t>(event.prediction_type())];
295   }
296   actual_row.prediction_type = prediction_type;
297   if (DisplayFrameJanky(event.jank_type())) {
298     actual_row.jank_tag = jank_tag_self_id_;
299   } else if (event.jank_type() == FrameTimelineEvent::JANK_SF_STUFFING) {
300     actual_row.jank_tag = jank_tag_sf_stuffing_id_;
301   } else {
302     actual_row.jank_tag = jank_tag_none_id_;
303   }
304 
305   std::optional<SliceId> opt_slice_id = context_->slice_tracker->BeginTyped(
306       context_->storage->mutable_actual_frame_timeline_slice_table(),
307       actual_row,
308       [this, token, jank_type, present_type, prediction_type,
309        &event](ArgsTracker::BoundInserter* inserter) {
310         inserter->AddArg(display_frame_token_id_, Variadic::Integer(token));
311         inserter->AddArg(present_type_id_, Variadic::String(present_type));
312         inserter->AddArg(on_time_finish_id_,
313                          Variadic::Integer(event.on_time_finish()));
314         inserter->AddArg(gpu_composition_id_,
315                          Variadic::Integer(event.gpu_composition()));
316         inserter->AddArg(jank_type_id_, Variadic::String(jank_type));
317         inserter->AddArg(prediction_type_id_,
318                          Variadic::String(prediction_type));
319       });
320 
321   // SurfaceFrames will always be parsed before the matching DisplayFrame
322   // (since the app works on the frame before SurfaceFlinger does). Because
323   // of this it's safe to add all the flow events here and then forget the
324   // surface_slice id - we shouldn't see more surfaces_slices that should be
325   // connected to this slice after this point.
326   auto range = display_token_to_surface_slice_.equal_range(token);
327   if (opt_slice_id) {
328     for (auto it = range.first; it != range.second; ++it) {
329       SliceId display_slice = *opt_slice_id;  // SurfaceFlinger
330       SliceId surface_slice = it->second;     // App
331       context_->flow_tracker->InsertFlow(display_slice, surface_slice);
332     }
333   }
334   display_token_to_surface_slice_.erase(range.first, range.second);
335 }
336 
ParseExpectedSurfaceFrameStart(int64_t timestamp,ConstBytes bufferBlob)337 void FrameTimelineEventParser::ParseExpectedSurfaceFrameStart(
338     int64_t timestamp,
339     ConstBytes bufferBlob) {
340   ExpectedSurfaceFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
341 
342   if (!event.has_cookie()) {
343     context_->storage->IncrementStats(
344         stats::frame_timeline_event_parser_errors);
345     return;
346   }
347 
348   if (!event.has_token()) {
349     context_->storage->IncrementStats(
350         stats::frame_timeline_event_parser_errors);
351     return;
352   }
353 
354   if (!event.has_display_frame_token()) {
355     context_->storage->IncrementStats(
356         stats::frame_timeline_event_parser_errors);
357     return;
358   }
359 
360   if (!event.has_pid()) {
361     context_->storage->IncrementStats(
362         stats::frame_timeline_event_parser_errors);
363     return;
364   }
365 
366   int64_t cookie = event.cookie();
367   int64_t token = event.token();
368   int64_t display_frame_token = event.display_frame_token();
369   UniquePid upid = context_->process_tracker->GetOrCreateProcess(
370       static_cast<uint32_t>(event.pid()));
371   auto token_set_it = expected_timeline_token_map_.find(upid);
372   if (token_set_it != expected_timeline_token_map_.end()) {
373     auto& token_set = token_set_it->second;
374     if (token_set.find(token) != token_set.end()) {
375       // If we already have an expected timeline for a token, the expectations
376       // are same for all frames that use the token. No need to add duplicate
377       // entries.
378       return;
379     }
380   }
381   // This is the first time we are seeing this token for this process. Add to
382   // the map.
383   expected_timeline_token_map_[upid].insert(token);
384 
385   StringId layer_name_id = event.has_layer_name()
386                                ? context_->storage->InternString(
387                                      base::StringView(event.layer_name()))
388                                : kNullStringId;
389   StringId name_id =
390       context_->storage->InternString(base::StringView(std::to_string(token)));
391 
392   auto expected_track_set_id =
393       context_->async_track_set_tracker->InternProcessTrackSet(
394           upid, expected_timeline_track_name_);
395   cookie_track_set_id_map_[cookie] = expected_track_set_id;
396 
397   tables::ExpectedFrameTimelineSliceTable::Row expected_row;
398   expected_row.ts = timestamp;
399   expected_row.track_id =
400       context_->async_track_set_tracker->Begin(expected_track_set_id, cookie);
401   expected_row.name = name_id;
402 
403   expected_row.surface_frame_token = token;
404   expected_row.display_frame_token = display_frame_token;
405   expected_row.upid = upid;
406   expected_row.layer_name = layer_name_id;
407   context_->slice_tracker->BeginTyped(
408       context_->storage->mutable_expected_frame_timeline_slice_table(),
409       expected_row,
410       [this, token, layer_name_id](ArgsTracker::BoundInserter* inserter) {
411         inserter->AddArg(display_frame_token_id_, Variadic::Integer(token));
412         inserter->AddArg(layer_name_id_, Variadic::String(layer_name_id));
413       });
414 }
415 
ParseActualSurfaceFrameStart(int64_t timestamp,ConstBytes bufferBlob)416 void FrameTimelineEventParser::ParseActualSurfaceFrameStart(
417     int64_t timestamp,
418     ConstBytes bufferBlob) {
419   ActualSurfaceFrameStartDecoder event(bufferBlob.data, bufferBlob.size);
420 
421   if (!event.has_cookie()) {
422     context_->storage->IncrementStats(
423         stats::frame_timeline_event_parser_errors);
424     return;
425   }
426 
427   if (!event.has_token()) {
428     context_->storage->IncrementStats(
429         stats::frame_timeline_event_parser_errors);
430     return;
431   }
432 
433   if (!event.has_display_frame_token()) {
434     context_->storage->IncrementStats(
435         stats::frame_timeline_event_parser_errors);
436     return;
437   }
438 
439   if (!event.has_pid()) {
440     context_->storage->IncrementStats(
441         stats::frame_timeline_event_parser_errors);
442     return;
443   }
444 
445   int64_t cookie = event.cookie();
446   int64_t token = event.token();
447   int64_t display_frame_token = event.display_frame_token();
448 
449   UniquePid upid = context_->process_tracker->GetOrCreateProcess(
450       static_cast<uint32_t>(event.pid()));
451   StringId layer_name_id;
452   if (event.has_layer_name())
453     layer_name_id =
454         context_->storage->InternString(base::StringView(event.layer_name()));
455   StringId name_id =
456       context_->storage->InternString(base::StringView(std::to_string(token)));
457 
458   auto actual_track_set_id =
459       context_->async_track_set_tracker->InternProcessTrackSet(
460           upid, actual_timeline_track_name_);
461   cookie_track_set_id_map_[cookie] = actual_track_set_id;
462 
463   tables::ActualFrameTimelineSliceTable::Row actual_row;
464   actual_row.ts = timestamp;
465   actual_row.track_id =
466       context_->async_track_set_tracker->Begin(actual_track_set_id, cookie);
467   actual_row.name = name_id;
468   actual_row.surface_frame_token = token;
469   actual_row.display_frame_token = display_frame_token;
470   actual_row.upid = upid;
471   actual_row.layer_name = layer_name_id;
472   StringId present_type = present_type_ids_[0];
473   bool present_type_validated = false;
474   if (event.has_present_type() &&
475       ValidatePresentType(context_, event.present_type())) {
476     present_type_validated = true;
477     present_type = present_type_ids_[static_cast<size_t>(event.present_type())];
478   }
479   actual_row.present_type = present_type;
480   actual_row.on_time_finish = event.on_time_finish();
481   actual_row.gpu_composition = event.gpu_composition();
482   StringId jank_type = JankTypeBitmaskToStringId(context_, event.jank_type());
483   actual_row.jank_type = jank_type;
484   StringId prediction_type = prediction_type_ids_[0];
485   if (event.has_prediction_type() &&
486       ValidatePredictionType(context_, event.prediction_type())) {
487     prediction_type =
488         prediction_type_ids_[static_cast<size_t>(event.prediction_type())];
489   }
490   actual_row.prediction_type = prediction_type;
491   if (SurfaceFrameJanky(event.jank_type())) {
492     actual_row.jank_tag = jank_tag_self_id_;
493   } else if (DisplayFrameJanky(event.jank_type())) {
494     actual_row.jank_tag = jank_tag_other_id_;
495   } else if (event.jank_type() == FrameTimelineEvent::JANK_BUFFER_STUFFING) {
496     actual_row.jank_tag = jank_tag_buffer_stuffing_id_;
497   } else if (present_type_validated &&
498              event.present_type() == FrameTimelineEvent::PRESENT_DROPPED) {
499     actual_row.jank_tag = jank_tag_dropped_id_;
500   } else {
501     actual_row.jank_tag = jank_tag_none_id_;
502   }
503   StringId is_buffer = context_->storage->InternString("Unspecified");
504   if (event.has_is_buffer()) {
505     if (event.is_buffer())
506       is_buffer = context_->storage->InternString("Yes");
507     else
508       is_buffer = context_->storage->InternString("No");
509   }
510 
511   std::optional<SliceId> opt_slice_id = context_->slice_tracker->BeginTyped(
512       context_->storage->mutable_actual_frame_timeline_slice_table(),
513       actual_row,
514       [this, jank_type, present_type, token, layer_name_id, display_frame_token,
515        prediction_type, is_buffer,
516        &event](ArgsTracker::BoundInserter* inserter) {
517         inserter->AddArg(surface_frame_token_id_, Variadic::Integer(token));
518         inserter->AddArg(display_frame_token_id_,
519                          Variadic::Integer(display_frame_token));
520         inserter->AddArg(layer_name_id_, Variadic::String(layer_name_id));
521         inserter->AddArg(present_type_id_, Variadic::String(present_type));
522         inserter->AddArg(on_time_finish_id_,
523                          Variadic::Integer(event.on_time_finish()));
524         inserter->AddArg(gpu_composition_id_,
525                          Variadic::Integer(event.gpu_composition()));
526         inserter->AddArg(jank_type_id_, Variadic::String(jank_type));
527         inserter->AddArg(prediction_type_id_,
528                          Variadic::String(prediction_type));
529         inserter->AddArg(is_buffer_id_, Variadic::String(is_buffer));
530       });
531 
532   if (opt_slice_id) {
533     display_token_to_surface_slice_.emplace(display_frame_token, *opt_slice_id);
534   }
535 }
536 
ParseFrameEnd(int64_t timestamp,ConstBytes bufferBlob)537 void FrameTimelineEventParser::ParseFrameEnd(int64_t timestamp,
538                                              ConstBytes bufferBlob) {
539   FrameEndDecoder event(bufferBlob.data, bufferBlob.size);
540 
541   if (!event.has_cookie()) {
542     context_->storage->IncrementStats(
543         stats::frame_timeline_event_parser_errors);
544     return;
545   }
546 
547   int64_t cookie = event.cookie();
548   auto it = cookie_track_set_id_map_.find(cookie);
549   if (it == cookie_track_set_id_map_.end()) {
550     context_->storage->IncrementStats(stats::frame_timeline_unpaired_end_event);
551     return;
552   }
553   auto track_set_id = it->second;
554   auto track_id = context_->async_track_set_tracker->End(track_set_id, cookie);
555   context_->slice_tracker->End(timestamp, track_id);
556   cookie_track_set_id_map_.erase(it);
557 }
558 
ParseFrameTimelineEvent(int64_t timestamp,ConstBytes blob)559 void FrameTimelineEventParser::ParseFrameTimelineEvent(int64_t timestamp,
560                                                        ConstBytes blob) {
561   protos::pbzero::FrameTimelineEvent_Decoder frame_event(blob.data, blob.size);
562 
563   if (IsBadTimestamp(timestamp)) {
564     context_->storage->IncrementStats(
565         stats::frame_timeline_event_parser_errors);
566     return;
567   }
568 
569   if (frame_event.has_expected_display_frame_start()) {
570     ParseExpectedDisplayFrameStart(timestamp,
571                                    frame_event.expected_display_frame_start());
572   } else if (frame_event.has_actual_display_frame_start()) {
573     ParseActualDisplayFrameStart(timestamp,
574                                  frame_event.actual_display_frame_start());
575   } else if (frame_event.has_expected_surface_frame_start()) {
576     ParseExpectedSurfaceFrameStart(timestamp,
577                                    frame_event.expected_surface_frame_start());
578   } else if (frame_event.has_actual_surface_frame_start()) {
579     ParseActualSurfaceFrameStart(timestamp,
580                                  frame_event.actual_surface_frame_start());
581   } else if (frame_event.has_frame_end()) {
582     ParseFrameEnd(timestamp, frame_event.frame_end());
583   } else {
584     context_->storage->IncrementStats(
585         stats::frame_timeline_event_parser_errors);
586   }
587 }
588 }  // namespace trace_processor
589 }  // namespace perfetto
590