• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 package android.os;
18 
19 import static android.os.PerfettoTrace.Category;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 
23 import static perfetto.protos.ChromeLatencyInfoOuterClass.ChromeLatencyInfo.LatencyComponentType.COMPONENT_INPUT_EVENT_LATENCY_BEGIN_RWH;
24 import static perfetto.protos.ChromeLatencyInfoOuterClass.ChromeLatencyInfo.LatencyComponentType.COMPONENT_INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL;
25 
26 import android.platform.test.annotations.DisabledOnRavenwood;
27 import android.platform.test.annotations.RequiresFlagsEnabled;
28 import android.platform.test.flag.junit.CheckFlagsRule;
29 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
30 import android.util.ArraySet;
31 
32 import androidx.test.InstrumentationRegistry;
33 import androidx.test.ext.junit.runners.AndroidJUnit4;
34 
35 import org.junit.Before;
36 import org.junit.Ignore;
37 import org.junit.Rule;
38 import org.junit.Test;
39 import org.junit.runner.RunWith;
40 
41 import perfetto.protos.ChromeLatencyInfoOuterClass.ChromeLatencyInfo;
42 import perfetto.protos.ChromeLatencyInfoOuterClass.ChromeLatencyInfo.ComponentInfo;
43 import perfetto.protos.DataSourceConfigOuterClass.DataSourceConfig;
44 import perfetto.protos.DebugAnnotationOuterClass.DebugAnnotation;
45 import perfetto.protos.DebugAnnotationOuterClass.DebugAnnotationName;
46 import perfetto.protos.InternedDataOuterClass.InternedData;
47 import perfetto.protos.SourceLocationOuterClass.SourceLocation;
48 import perfetto.protos.TraceConfigOuterClass.TraceConfig;
49 import perfetto.protos.TraceConfigOuterClass.TraceConfig.BufferConfig;
50 import perfetto.protos.TraceConfigOuterClass.TraceConfig.DataSource;
51 import perfetto.protos.TraceConfigOuterClass.TraceConfig.TriggerConfig;
52 import perfetto.protos.TraceConfigOuterClass.TraceConfig.TriggerConfig.Trigger;
53 import perfetto.protos.TraceOuterClass.Trace;
54 import perfetto.protos.TracePacketOuterClass.TracePacket;
55 import perfetto.protos.TrackDescriptorOuterClass.TrackDescriptor;
56 import perfetto.protos.TrackEventConfigOuterClass.TrackEventConfig;
57 import perfetto.protos.TrackEventOuterClass.EventCategory;
58 import perfetto.protos.TrackEventOuterClass.EventName;
59 import perfetto.protos.TrackEventOuterClass.TrackEvent;
60 
61 import java.util.List;
62 import java.util.Set;
63 import java.util.concurrent.CountDownLatch;
64 import java.util.concurrent.TimeUnit;
65 
66 /**
67  * This class is used to test the native tracing support. Run this test
68  * while tracing on the emulator and then run traceview to view the trace.
69  */
70 @RunWith(AndroidJUnit4.class)
71 @DisabledOnRavenwood(blockedBy = PerfettoTrace.class)
72 public class PerfettoTraceTest {
73     @Rule
74     public final CheckFlagsRule mCheckFlagsRule =
75             DeviceFlagsValueProvider.createCheckFlagsRule(
76                     InstrumentationRegistry.getInstrumentation().getUiAutomation());
77 
78     private static final String TAG = "PerfettoTraceTest";
79     private static final String FOO = "foo";
80     private static final String BAR = "bar";
81     private static final String TEXT_ABOVE_4K_SIZE =
82             new String(new char[8192]).replace('\0', 'a');
83 
84     private static final Category FOO_CATEGORY = new Category(FOO);
85     private static final int MESSAGE = 1234567;
86     private static final int MESSAGE_COUNT = 3;
87 
88     private final Set<String> mCategoryNames = new ArraySet<>();
89     private final Set<String> mEventNames = new ArraySet<>();
90     private final Set<String> mDebugAnnotationNames = new ArraySet<>();
91     private final Set<String> mTrackNames = new ArraySet<>();
92 
93     @Before
setUp()94     public void setUp() {
95         PerfettoTrace.register(true);
96         FOO_CATEGORY.register();
97 
98         mCategoryNames.clear();
99         mEventNames.clear();
100         mDebugAnnotationNames.clear();
101         mTrackNames.clear();
102     }
103 
104     @Test
105     @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
testDebugAnnotations()106     public void testDebugAnnotations() throws Exception {
107         TraceConfig traceConfig = getTraceConfig(FOO);
108 
109         PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray());
110 
111         PerfettoTrace.instant(FOO_CATEGORY, "event")
112                 .setFlow(2)
113                 .setTerminatingFlow(3)
114                 .addArg("long_val", 10000000000L)
115                 .addArg("bool_val", true)
116                 .addArg("double_val", 3.14)
117                 .addArg("string_val", FOO)
118                 .emit();
119 
120         byte[] traceBytes = session.close();
121 
122         Trace trace = Trace.parseFrom(traceBytes);
123 
124         boolean hasTrackEvent = false;
125         boolean hasDebugAnnotations = false;
126         for (TracePacket packet: trace.getPacketList()) {
127             TrackEvent event;
128             if (packet.hasTrackEvent()) {
129                 hasTrackEvent = true;
130                 event = packet.getTrackEvent();
131 
132                 if (TrackEvent.Type.TYPE_INSTANT.equals(event.getType())
133                         && event.getDebugAnnotationsCount() == 4 && event.getFlowIdsCount() == 1
134                         && event.getTerminatingFlowIdsCount() == 1) {
135                     hasDebugAnnotations = true;
136 
137                     List<DebugAnnotation> annotations = event.getDebugAnnotationsList();
138 
139                     assertThat(annotations.get(0).getIntValue()).isEqualTo(10000000000L);
140                     assertThat(annotations.get(1).getBoolValue()).isTrue();
141                     assertThat(annotations.get(2).getDoubleValue()).isEqualTo(3.14);
142                     assertThat(annotations.get(3).getStringValue()).isEqualTo(FOO);
143                 }
144             }
145 
146             collectInternedData(packet);
147         }
148 
149         assertThat(hasTrackEvent).isTrue();
150         assertThat(hasDebugAnnotations).isTrue();
151         assertThat(mCategoryNames).contains(FOO);
152 
153         assertThat(mDebugAnnotationNames).contains("long_val");
154         assertThat(mDebugAnnotationNames).contains("bool_val");
155         assertThat(mDebugAnnotationNames).contains("double_val");
156         assertThat(mDebugAnnotationNames).contains("string_val");
157     }
158 
159     @Test
160     @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
testNamedTrack()161     public void testNamedTrack() throws Exception {
162         TraceConfig traceConfig = getTraceConfig(FOO);
163 
164         PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray());
165 
166         PerfettoTrace.begin(FOO_CATEGORY, "event")
167                 .usingNamedTrack(PerfettoTrace.getProcessTrackUuid(), FOO)
168                 .emit();
169 
170 
171         PerfettoTrace.end(FOO_CATEGORY)
172                 .usingNamedTrack(PerfettoTrace.getThreadTrackUuid(Process.myTid()), "bar")
173                 .emit();
174 
175         Trace trace = Trace.parseFrom(session.close());
176 
177         boolean hasTrackEvent = false;
178         boolean hasTrackUuid = false;
179         for (TracePacket packet: trace.getPacketList()) {
180             TrackEvent event;
181             if (packet.hasTrackEvent()) {
182                 hasTrackEvent = true;
183                 event = packet.getTrackEvent();
184 
185                 if (TrackEvent.Type.TYPE_SLICE_BEGIN.equals(event.getType())
186                         && event.hasTrackUuid()) {
187                     hasTrackUuid = true;
188                 }
189 
190                 if (TrackEvent.Type.TYPE_SLICE_END.equals(event.getType())
191                         && event.hasTrackUuid()) {
192                     hasTrackUuid &= true;
193                 }
194             }
195 
196             collectInternedData(packet);
197             collectTrackNames(packet);
198         }
199 
200         assertThat(hasTrackEvent).isTrue();
201         assertThat(hasTrackUuid).isTrue();
202         assertThat(mCategoryNames).contains(FOO);
203         assertThat(mTrackNames).contains(FOO);
204         assertThat(mTrackNames).contains("bar");
205     }
206 
207     @Test
208     @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
testProcessThreadNamedTrack()209     public void testProcessThreadNamedTrack() throws Exception {
210         TraceConfig traceConfig = getTraceConfig(FOO);
211 
212         PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray());
213 
214         PerfettoTrace.begin(FOO_CATEGORY, "event")
215                 .usingProcessNamedTrack(FOO)
216                 .emit();
217 
218 
219         PerfettoTrace.end(FOO_CATEGORY)
220                 .usingThreadNamedTrack(Process.myTid(), "bar")
221                 .emit();
222 
223         Trace trace = Trace.parseFrom(session.close());
224 
225         boolean hasTrackEvent = false;
226         boolean hasTrackUuid = false;
227         for (TracePacket packet: trace.getPacketList()) {
228             TrackEvent event;
229             if (packet.hasTrackEvent()) {
230                 hasTrackEvent = true;
231                 event = packet.getTrackEvent();
232 
233                 if (TrackEvent.Type.TYPE_SLICE_BEGIN.equals(event.getType())
234                         && event.hasTrackUuid()) {
235                     hasTrackUuid = true;
236                 }
237 
238                 if (TrackEvent.Type.TYPE_SLICE_END.equals(event.getType())
239                         && event.hasTrackUuid()) {
240                     hasTrackUuid &= true;
241                 }
242             }
243 
244             collectInternedData(packet);
245             collectTrackNames(packet);
246         }
247 
248         assertThat(hasTrackEvent).isTrue();
249         assertThat(hasTrackUuid).isTrue();
250         assertThat(mCategoryNames).contains(FOO);
251         assertThat(mTrackNames).contains(FOO);
252         assertThat(mTrackNames).contains("bar");
253     }
254 
255     @Test
256     @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
testCounterSimple()257     public void testCounterSimple() throws Exception {
258         TraceConfig traceConfig = getTraceConfig(FOO);
259 
260         PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray());
261 
262         PerfettoTrace.counter(FOO_CATEGORY, 16, FOO).emit();
263 
264         PerfettoTrace.counter(FOO_CATEGORY, 3.14, "bar").emit();
265 
266         Trace trace = Trace.parseFrom(session.close());
267 
268         boolean hasTrackEvent = false;
269         boolean hasCounterValue = false;
270         boolean hasDoubleCounterValue = false;
271         for (TracePacket packet: trace.getPacketList()) {
272             TrackEvent event;
273             if (packet.hasTrackEvent()) {
274                 hasTrackEvent = true;
275                 event = packet.getTrackEvent();
276 
277                 if (TrackEvent.Type.TYPE_COUNTER.equals(event.getType())
278                         && event.getCounterValue() == 16) {
279                     hasCounterValue = true;
280                 }
281 
282                 if (TrackEvent.Type.TYPE_COUNTER.equals(event.getType())
283                         && event.getDoubleCounterValue() == 3.14) {
284                     hasDoubleCounterValue = true;
285                 }
286             }
287 
288             collectTrackNames(packet);
289         }
290 
291         assertThat(hasTrackEvent).isTrue();
292         assertThat(hasCounterValue).isTrue();
293         assertThat(hasDoubleCounterValue).isTrue();
294         assertThat(mTrackNames).contains(FOO);
295         assertThat(mTrackNames).contains(BAR);
296     }
297 
298     @Test
299     @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
testCounter()300     public void testCounter() throws Exception {
301         TraceConfig traceConfig = getTraceConfig(FOO);
302 
303         PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray());
304 
305         PerfettoTrace.counter(FOO_CATEGORY, 16)
306                 .usingCounterTrack(PerfettoTrace.getProcessTrackUuid(), FOO).emit();
307 
308         PerfettoTrace.counter(FOO_CATEGORY, 3.14)
309                 .usingCounterTrack(PerfettoTrace.getThreadTrackUuid(Process.myTid()),
310                                    "bar").emit();
311 
312         Trace trace = Trace.parseFrom(session.close());
313 
314         boolean hasTrackEvent = false;
315         boolean hasCounterValue = false;
316         boolean hasDoubleCounterValue = false;
317         for (TracePacket packet: trace.getPacketList()) {
318             TrackEvent event;
319             if (packet.hasTrackEvent()) {
320                 hasTrackEvent = true;
321                 event = packet.getTrackEvent();
322 
323                 if (TrackEvent.Type.TYPE_COUNTER.equals(event.getType())
324                         && event.getCounterValue() == 16) {
325                     hasCounterValue = true;
326                 }
327 
328                 if (TrackEvent.Type.TYPE_COUNTER.equals(event.getType())
329                         && event.getDoubleCounterValue() == 3.14) {
330                     hasDoubleCounterValue = true;
331                 }
332             }
333 
334             collectTrackNames(packet);
335         }
336 
337         assertThat(hasTrackEvent).isTrue();
338         assertThat(hasCounterValue).isTrue();
339         assertThat(hasDoubleCounterValue).isTrue();
340         assertThat(mTrackNames).contains(FOO);
341         assertThat(mTrackNames).contains("bar");
342     }
343 
344     @Test
345     @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
testProcessThreadCounter()346     public void testProcessThreadCounter() throws Exception {
347         TraceConfig traceConfig = getTraceConfig(FOO);
348 
349         PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray());
350 
351         PerfettoTrace.counter(FOO_CATEGORY, 16).usingProcessCounterTrack(FOO).emit();
352 
353         PerfettoTrace.counter(FOO_CATEGORY, 3.14)
354                 .usingThreadCounterTrack(Process.myTid(), "bar").emit();
355 
356         Trace trace = Trace.parseFrom(session.close());
357 
358         boolean hasTrackEvent = false;
359         boolean hasCounterValue = false;
360         boolean hasDoubleCounterValue = false;
361         for (TracePacket packet: trace.getPacketList()) {
362             TrackEvent event;
363             if (packet.hasTrackEvent()) {
364                 hasTrackEvent = true;
365                 event = packet.getTrackEvent();
366 
367                 if (TrackEvent.Type.TYPE_COUNTER.equals(event.getType())
368                         && event.getCounterValue() == 16) {
369                     hasCounterValue = true;
370                 }
371 
372                 if (TrackEvent.Type.TYPE_COUNTER.equals(event.getType())
373                         && event.getDoubleCounterValue() == 3.14) {
374                     hasDoubleCounterValue = true;
375                 }
376             }
377 
378             collectTrackNames(packet);
379         }
380 
381         assertThat(hasTrackEvent).isTrue();
382         assertThat(hasCounterValue).isTrue();
383         assertThat(hasDoubleCounterValue).isTrue();
384         assertThat(mTrackNames).contains(FOO);
385         assertThat(mTrackNames).contains("bar");
386     }
387 
388     @Test
389     @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
testProto()390     public void testProto() throws Exception {
391         TraceConfig traceConfig = getTraceConfig(FOO);
392 
393         PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray());
394 
395         PerfettoTrace.instant(FOO_CATEGORY, "event_proto")
396                 .beginProto()
397                 .beginNested(33L)
398                 .addField(4L, 2L)
399                 .addField(3, "ActivityManagerService.java:11489")
400                 .endNested()
401                 .addField(2001, "AIDL::IActivityManager")
402                 .endProto()
403                 .emit();
404 
405         byte[] traceBytes = session.close();
406 
407         Trace trace = Trace.parseFrom(traceBytes);
408 
409         boolean hasTrackEvent = false;
410         boolean hasSourceLocation = false;
411         for (TracePacket packet: trace.getPacketList()) {
412             TrackEvent event;
413             if (packet.hasTrackEvent()) {
414                 hasTrackEvent = true;
415                 event = packet.getTrackEvent();
416 
417                 if (TrackEvent.Type.TYPE_INSTANT.equals(event.getType())
418                         && event.hasSourceLocation()) {
419                     SourceLocation loc = event.getSourceLocation();
420                     if ("ActivityManagerService.java:11489".equals(loc.getFunctionName())
421                             && loc.getLineNumber() == 2) {
422                         hasSourceLocation = true;
423                     }
424                 }
425             }
426 
427             collectInternedData(packet);
428         }
429 
430         assertThat(hasTrackEvent).isTrue();
431         assertThat(hasSourceLocation).isTrue();
432         assertThat(mCategoryNames).contains(FOO);
433     }
434 
435     @Test
436     @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
testProtoWithSlowPath()437     public void testProtoWithSlowPath() throws Exception {
438         TraceConfig traceConfig = getTraceConfig(FOO);
439 
440         PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray());
441 
442         PerfettoTrace.instant(FOO_CATEGORY, "event_proto")
443                 .beginProto()
444                 .beginNested(33L)
445                 .addField(4L, 2L)
446                 .addField(3, TEXT_ABOVE_4K_SIZE)
447                 .endNested()
448                 .addField(2001, "AIDL::IActivityManager")
449                 .endProto()
450                 .emit();
451 
452         byte[] traceBytes = session.close();
453 
454         Trace trace = Trace.parseFrom(traceBytes);
455 
456         boolean hasTrackEvent = false;
457         boolean hasSourceLocation = false;
458         for (TracePacket packet: trace.getPacketList()) {
459             TrackEvent event;
460             if (packet.hasTrackEvent()) {
461                 hasTrackEvent = true;
462                 event = packet.getTrackEvent();
463 
464                 if (TrackEvent.Type.TYPE_INSTANT.equals(event.getType())
465                         && event.hasSourceLocation()) {
466                     SourceLocation loc = event.getSourceLocation();
467                     if (TEXT_ABOVE_4K_SIZE.equals(loc.getFunctionName())
468                             && loc.getLineNumber() == 2) {
469                         hasSourceLocation = true;
470                     }
471                 }
472             }
473 
474             collectInternedData(packet);
475         }
476 
477         assertThat(hasTrackEvent).isTrue();
478         assertThat(hasSourceLocation).isTrue();
479         assertThat(mCategoryNames).contains(FOO);
480     }
481 
482     @Test
483     @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
testProtoNested()484     public void testProtoNested() throws Exception {
485         TraceConfig traceConfig = getTraceConfig(FOO);
486 
487         PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray());
488 
489         PerfettoTrace.instant(FOO_CATEGORY, "event_proto_nested")
490                 .beginProto()
491                 .beginNested(29L)
492                 .beginNested(4L)
493                 .addField(1L, 2)
494                 .addField(2L, 20000)
495                 .endNested()
496                 .beginNested(4L)
497                 .addField(1L, 1)
498                 .addField(2L, 40000)
499                 .endNested()
500                 .endNested()
501                 .endProto()
502                 .emit();
503 
504         byte[] traceBytes = session.close();
505 
506         Trace trace = Trace.parseFrom(traceBytes);
507 
508         boolean hasTrackEvent = false;
509         boolean hasChromeLatencyInfo = false;
510 
511         for (TracePacket packet: trace.getPacketList()) {
512             TrackEvent event;
513             if (packet.hasTrackEvent()) {
514                 hasTrackEvent = true;
515                 event = packet.getTrackEvent();
516 
517                 if (TrackEvent.Type.TYPE_INSTANT.equals(event.getType())
518                         && event.hasChromeLatencyInfo()) {
519                     ChromeLatencyInfo latencyInfo = event.getChromeLatencyInfo();
520                     if (latencyInfo.getComponentInfoCount() == 2) {
521                         hasChromeLatencyInfo = true;
522                         ComponentInfo cmpInfo1 = latencyInfo.getComponentInfo(0);
523                         assertThat(cmpInfo1.getComponentType())
524                                 .isEqualTo(COMPONENT_INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL);
525                         assertThat(cmpInfo1.getTimeUs()).isEqualTo(20000);
526 
527                         ComponentInfo cmpInfo2 = latencyInfo.getComponentInfo(1);
528                         assertThat(cmpInfo2.getComponentType())
529                                 .isEqualTo(COMPONENT_INPUT_EVENT_LATENCY_BEGIN_RWH);
530                         assertThat(cmpInfo2.getTimeUs()).isEqualTo(40000);
531                     }
532                 }
533             }
534 
535             collectInternedData(packet);
536         }
537 
538         assertThat(hasTrackEvent).isTrue();
539         assertThat(hasChromeLatencyInfo).isTrue();
540         assertThat(mCategoryNames).contains(FOO);
541     }
542 
543     @Test
544     @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
testActivateTrigger()545     public void testActivateTrigger() throws Exception {
546         TraceConfig traceConfig = getTriggerTraceConfig(FOO, FOO);
547 
548         PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray());
549 
550         PerfettoTrace.instant(FOO_CATEGORY, "event_trigger").emit();
551 
552         PerfettoTrace.activateTrigger(FOO, 1000);
553 
554         byte[] traceBytes = session.close();
555 
556         Trace trace = Trace.parseFrom(traceBytes);
557 
558         boolean hasTrackEvent = false;
559         boolean hasChromeLatencyInfo = false;
560 
561         for (TracePacket packet: trace.getPacketList()) {
562             TrackEvent event;
563             if (packet.hasTrackEvent()) {
564                 hasTrackEvent = true;
565             }
566 
567             collectInternedData(packet);
568         }
569 
570         assertThat(mCategoryNames).contains(FOO);
571     }
572 
573     @Test
574     @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
testRegister()575     public void testRegister() throws Exception {
576         TraceConfig traceConfig = getTraceConfig(BAR);
577 
578         Category barCategory = new Category(BAR);
579         PerfettoTrace.Session session = new PerfettoTrace.Session(true, traceConfig.toByteArray());
580 
581         PerfettoTrace.instant(barCategory, "event")
582                 .addArg("before", 1)
583                 .emit();
584 
585         barCategory.register();
586 
587         PerfettoTrace.instant(barCategory, "event")
588                 .addArg("after", 1)
589                 .emit();
590 
591         byte[] traceBytes = session.close();
592 
593         Trace trace = Trace.parseFrom(traceBytes);
594 
595         boolean hasTrackEvent = false;
596         for (TracePacket packet: trace.getPacketList()) {
597             TrackEvent event;
598             if (packet.hasTrackEvent()) {
599                 hasTrackEvent = true;
600                 event = packet.getTrackEvent();
601             }
602 
603             collectInternedData(packet);
604         }
605 
606         assertThat(hasTrackEvent).isTrue();
607         assertThat(mCategoryNames).contains(BAR);
608 
609         assertThat(mDebugAnnotationNames).contains("after");
610         assertThat(mDebugAnnotationNames).doesNotContain("before");
611     }
612 
613     @Test
614     @RequiresFlagsEnabled(android.os.Flags.FLAG_PERFETTO_SDK_TRACING_V2)
615     @Ignore("b/303199244")
testMessageQueue()616     public void testMessageQueue() throws Exception {
617         TraceConfig traceConfig = getTraceConfig("mq");
618 
619         PerfettoTrace.MQ_CATEGORY.register();
620         final HandlerThread thread = new HandlerThread("test");
621         thread.start();
622         final Handler handler = thread.getThreadHandler();
623         final CountDownLatch latch = new CountDownLatch(1);
624 
625         PerfettoTrace.Session session = new PerfettoTrace.Session(true,
626                 getTraceConfig("mq").toByteArray());
627 
628         handler.sendEmptyMessage(MESSAGE);
629         handler.sendEmptyMessageDelayed(MESSAGE, 10);
630         handler.sendEmptyMessage(MESSAGE);
631         handler.postDelayed(() -> {
632             latch.countDown();
633         }, 10);
634         assertThat(latch.await(100, TimeUnit.MILLISECONDS)).isTrue();
635 
636         byte[] traceBytes = session.close();
637 
638         Trace trace = Trace.parseFrom(traceBytes);
639 
640         boolean hasTrackEvent = false;
641         int instantCount = 0;
642         int counterCount = 0;
643         int beginCount = 0;
644         int endCount = 0;
645 
646         Set<Long> flowIds = new ArraySet<>();
647         for (TracePacket packet: trace.getPacketList()) {
648             TrackEvent event;
649             if (packet.hasTrackEvent()) {
650                 hasTrackEvent = true;
651                 event = packet.getTrackEvent();
652             } else {
653                 continue;
654             }
655 
656             List<DebugAnnotation> annotations = event.getDebugAnnotationsList();
657             switch (event.getType()) {
658                 case TrackEvent.Type.TYPE_INSTANT:
659                     if (annotations.get(2).getIntValue() == MESSAGE) {
660                         instantCount++;
661                         assertThat(annotations.get(0).getStringValue()).isEqualTo("test");
662                         assertThat(event.getFlowIdsCount()).isEqualTo(1);
663                         flowIds.addAll(event.getFlowIdsList());
664                     }
665                     break;
666                 case TrackEvent.Type.TYPE_COUNTER:
667                     counterCount++;
668                     break;
669                 case TrackEvent.Type.TYPE_SLICE_BEGIN:
670                     annotations = event.getDebugAnnotationsList();
671                     if (flowIds.containsAll(event.getTerminatingFlowIdsList())) {
672                         beginCount++;
673                         assertThat(event.getTerminatingFlowIdsCount()).isEqualTo(1);
674                     }
675                     break;
676                 case TrackEvent.Type.TYPE_SLICE_END:
677                     endCount++;
678                     break;
679                 default:
680                     break;
681             }
682             collectInternedData(packet);
683         }
684 
685         assertThat(hasTrackEvent).isTrue();
686         assertThat(mCategoryNames).contains("mq");
687         assertThat(mEventNames).contains("message_queue_send");
688         assertThat(mEventNames).contains("message_queue_receive");
689         assertThat(mDebugAnnotationNames).contains("what");
690         assertThat(mDebugAnnotationNames).contains("delay");
691         assertThat(instantCount).isEqualTo(MESSAGE_COUNT);
692         assertThat(beginCount).isEqualTo(MESSAGE_COUNT);
693         assertThat(endCount).isAtLeast(MESSAGE_COUNT);
694         assertThat(counterCount).isAtLeast(MESSAGE_COUNT);
695     }
696 
getTrackEvent(Trace trace, int idx)697     private TrackEvent getTrackEvent(Trace trace, int idx) {
698         int curIdx = 0;
699         for (TracePacket packet: trace.getPacketList()) {
700             if (packet.hasTrackEvent()) {
701                 if (curIdx++ == idx) {
702                     return packet.getTrackEvent();
703                 }
704             }
705         }
706 
707         return null;
708     }
709 
getTraceConfig(String cat)710     private TraceConfig getTraceConfig(String cat) {
711         BufferConfig bufferConfig = BufferConfig.newBuilder().setSizeKb(1024).build();
712         TrackEventConfig trackEventConfig = TrackEventConfig
713                 .newBuilder()
714                 .addEnabledCategories(cat)
715                 .build();
716         DataSourceConfig dsConfig = DataSourceConfig
717                 .newBuilder()
718                 .setName("track_event")
719                 .setTargetBuffer(0)
720                 .setTrackEventConfig(trackEventConfig)
721                 .build();
722         DataSource ds = DataSource.newBuilder().setConfig(dsConfig).build();
723         TraceConfig traceConfig = TraceConfig
724                 .newBuilder()
725                 .addBuffers(bufferConfig)
726                 .addDataSources(ds)
727                 .build();
728         return traceConfig;
729     }
730 
getTriggerTraceConfig(String cat, String triggerName)731     private TraceConfig getTriggerTraceConfig(String cat, String triggerName) {
732         BufferConfig bufferConfig = BufferConfig.newBuilder().setSizeKb(1024).build();
733         TrackEventConfig trackEventConfig = TrackEventConfig
734                 .newBuilder()
735                 .addEnabledCategories(cat)
736                 .build();
737         DataSourceConfig dsConfig = DataSourceConfig
738                 .newBuilder()
739                 .setName("track_event")
740                 .setTargetBuffer(0)
741                 .setTrackEventConfig(trackEventConfig)
742                 .build();
743         DataSource ds = DataSource.newBuilder().setConfig(dsConfig).build();
744         Trigger trigger = Trigger.newBuilder().setName(triggerName).build();
745         TriggerConfig triggerConfig = TriggerConfig
746                 .newBuilder()
747                 .setTriggerMode(TriggerConfig.TriggerMode.STOP_TRACING)
748                 .setTriggerTimeoutMs(1000)
749                 .addTriggers(trigger)
750                 .build();
751         TraceConfig traceConfig = TraceConfig
752                 .newBuilder()
753                 .addBuffers(bufferConfig)
754                 .addDataSources(ds)
755                 .setTriggerConfig(triggerConfig)
756                 .build();
757         return traceConfig;
758     }
759 
collectInternedData(TracePacket packet)760     private void collectInternedData(TracePacket packet) {
761         if (!packet.hasInternedData()) {
762             return;
763         }
764 
765         InternedData data = packet.getInternedData();
766 
767         for (EventCategory cat : data.getEventCategoriesList()) {
768             mCategoryNames.add(cat.getName());
769         }
770         for (EventName ev : data.getEventNamesList()) {
771             mEventNames.add(ev.getName());
772         }
773         for (DebugAnnotationName dbg : data.getDebugAnnotationNamesList()) {
774             mDebugAnnotationNames.add(dbg.getName());
775         }
776     }
777 
collectTrackNames(TracePacket packet)778     private void collectTrackNames(TracePacket packet) {
779         if (!packet.hasTrackDescriptor()) {
780             return;
781         }
782         TrackDescriptor desc = packet.getTrackDescriptor();
783         mTrackNames.add(desc.getName());
784     }
785 }
786