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