• 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 dev.perfetto.sdk;
18 
19 import dalvik.annotation.optimization.CriticalNative;
20 import dalvik.annotation.optimization.FastNative;
21 
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.concurrent.atomic.AtomicLong;
25 import java.util.function.Supplier;
26 
27 /**
28  * Holds extras to be passed to Perfetto track events in {@link PerfettoTrace}.
29  *
30  * @hide
31  */
32 public final class PerfettoTrackEventExtra {
33     private static final boolean DEBUG = false;
34     private static final int DEFAULT_EXTRA_CACHE_SIZE = 5;
35     private static final Builder NO_OP_BUILDER = new Builder(/* extra= */ null, /* isCategoryEnabled= */ false);
36     private static final ThreadLocal<PerfettoTrackEventExtra> sTrackEventExtra =
37             new ThreadLocal<PerfettoTrackEventExtra>() {
38                 @Override
39                 protected PerfettoTrackEventExtra initialValue() {
40                     return new PerfettoTrackEventExtra();
41                 }
42             };
43     private static final AtomicLong sNamedTrackId = new AtomicLong();
44     private static final Supplier<Flow> sFlowSupplier = Flow::new;
45     private static final Supplier<Builder> sBuilderSupplier = Builder::new;
46     private static final Supplier<FieldInt64> sFieldInt64Supplier = FieldInt64::new;
47     private static final Supplier<FieldDouble> sFieldDoubleSupplier = FieldDouble::new;
48     private static final Supplier<FieldString> sFieldStringSupplier = FieldString::new;
49     private static final Supplier<FieldNested> sFieldNestedSupplier = FieldNested::new;
50 
51     private final List<PerfettoPointer> mPendingPointers = new ArrayList<>();
52     private CounterInt64 mCounterInt64;
53     private CounterDouble mCounterDouble;
54     private Proto mProto;
55     private Flow mFlow;
56     private Flow mTerminatingFlow;
57 
58     static class NativeAllocationRegistry {
createMalloced( ClassLoader classLoader, long freeFunction)59         public static NativeAllocationRegistry createMalloced(
60                 ClassLoader classLoader, long freeFunction) {
61             // do nothing
62             return new NativeAllocationRegistry();
63         }
registerNativeAllocation(Object obj, long ptr)64         public void registerNativeAllocation(Object obj, long ptr) {
65             // do nothing
66         }
67     }
68 
69     /**
70      * Represents a native pointer to a Perfetto C SDK struct. E.g. PerfettoTeHlExtra.
71      */
72     public interface PerfettoPointer {
73         /**
74          * Returns the perfetto struct native pointer.
75          */
getPtr()76         long getPtr();
77     }
78 
79     /**
80      * Container for {@link Field} instances.
81      */
82     public interface FieldContainer {
83         /**
84          * Add {@link Field} to the container.
85          */
addField(PerfettoPointer field)86         void addField(PerfettoPointer field);
87     }
88 
89     /**
90      * RingBuffer implemented on top of a SparseArray.
91      *
92      * Bounds a SparseArray with a FIFO algorithm.
93      */
94     private static final class RingBuffer<T> {
95         private final int mCapacity;
96         private final int[] mKeyArray;
97         private final T[] mValueArray;
98         private int mWriteEnd = 0;
99 
RingBuffer(int capacity)100         RingBuffer(int capacity) {
101             mCapacity = capacity;
102             mKeyArray = new int[capacity];
103             mValueArray = (T[]) new Object[capacity];
104         }
105 
put(int key, T value)106         public void put(int key, T value) {
107             mKeyArray[mWriteEnd] = key;
108             mValueArray[mWriteEnd] = value;
109             mWriteEnd = (mWriteEnd + 1) % mCapacity;
110         }
111 
get(int key)112         public T get(int key) {
113             for (int i = 0; i < mCapacity; i++) {
114                 if (mKeyArray[i] == key) {
115                     return mValueArray[i];
116                 }
117             }
118             return null;
119         }
120     }
121 
122     private static final class Pool<T> {
123         private final int mCapacity;
124         private final T[] mValueArray;
125         private int mIdx = 0;
126 
Pool(int capacity)127         Pool(int capacity) {
128             mCapacity = capacity;
129             mValueArray = (T[]) new Object[capacity];
130         }
131 
reset()132         public void reset() {
133             mIdx = 0;
134         }
135 
get(Supplier<T> supplier)136         public T get(Supplier<T> supplier) {
137             if (mIdx >= mCapacity) {
138                 return supplier.get();
139             }
140             if (mValueArray[mIdx] == null) {
141                 mValueArray[mIdx] = supplier.get();
142             }
143             return mValueArray[mIdx++];
144         }
145     }
146 
147     /**
148      * Builder for Perfetto track event extras.
149      */
150     public static final class Builder {
151         // For performance reasons, we hold a reference to mExtra as a holder for
152         // perfetto pointers being added. This way, we avoid an additional list to hold
153         // the pointers in Java and we can pass them down directly to native code.
154         private final PerfettoTrackEventExtra mExtra;
155 
156         private int mTraceType;
157         private PerfettoTrace.Category mCategory;
158         private String mEventName;
159         private boolean mIsBuilt;
160 
161         private Builder mParent;
162         private FieldContainer mCurrentContainer;
163 
164         private final boolean mIsCategoryEnabled;
165         private final CounterInt64 mCounterInt64;
166         private final CounterDouble mCounterDouble;
167         private final Proto mProto;
168         private final Flow mFlow;
169         private final Flow mTerminatingFlow;
170 
171         private final RingBuffer<NamedTrack> mNamedTrackCache;
172         private final RingBuffer<CounterTrack> mCounterTrackCache;
173         private final RingBuffer<ArgInt64> mArgInt64Cache;
174         private final RingBuffer<ArgBool> mArgBoolCache;
175         private final RingBuffer<ArgDouble> mArgDoubleCache;
176         private final RingBuffer<ArgString> mArgStringCache;
177 
178         private final Pool<FieldInt64> mFieldInt64Cache;
179         private final Pool<FieldDouble> mFieldDoubleCache;
180         private final Pool<FieldString> mFieldStringCache;
181         private final Pool<FieldNested> mFieldNestedCache;
182         private final Pool<Builder> mBuilderCache;
183 
Builder()184         private Builder() {
185             this(sTrackEventExtra.get(), true);
186         }
187 
Builder(PerfettoTrackEventExtra extra, boolean isCategoryEnabled)188         public Builder(PerfettoTrackEventExtra extra, boolean isCategoryEnabled) {
189             mIsCategoryEnabled = isCategoryEnabled;
190             mExtra = extra;
191             mNamedTrackCache = mExtra == null ? null : mExtra.mNamedTrackCache;
192             mCounterTrackCache = mExtra == null ? null : mExtra.mCounterTrackCache;
193             mArgInt64Cache = mExtra == null ? null : mExtra.mArgInt64Cache;
194             mArgDoubleCache = mExtra == null ? null : mExtra.mArgDoubleCache;
195             mArgBoolCache = mExtra == null ? null : mExtra.mArgBoolCache;
196             mArgStringCache = mExtra == null ? null : mExtra.mArgStringCache;
197             mFieldInt64Cache = mExtra == null ? null : mExtra.mFieldInt64Cache;
198             mFieldDoubleCache = mExtra == null ? null : mExtra.mFieldDoubleCache;
199             mFieldStringCache = mExtra == null ? null : mExtra.mFieldStringCache;
200             mFieldNestedCache = mExtra == null ? null : mExtra.mFieldNestedCache;
201             mBuilderCache = mExtra == null ? null : mExtra.mBuilderCache;
202 
203             mCounterInt64 = mExtra == null ? null : mExtra.getCounterInt64();
204             mCounterDouble = mExtra == null ? null : mExtra.getCounterDouble();
205             mProto = mExtra == null ? null : mExtra.getProto();
206             mFlow = mExtra == null ? null : mExtra.getFlow();
207             mTerminatingFlow = mExtra == null ? null : mExtra.getTerminatingFlow();
208         }
209 
210         /**
211          * Emits the track event.
212          */
emit()213         public void emit() {
214             if (!mIsCategoryEnabled) {
215                 return;
216             }
217             if (DEBUG) {
218                 checkParent();
219             }
220 
221             mIsBuilt = true;
222             native_emit(mTraceType, mCategory.getPtr(), mEventName, mExtra.getPtr());
223         }
224 
225         /**
226          * Initialize the builder for a new trace event.
227          */
init(int traceType, PerfettoTrace.Category category)228         public Builder init(int traceType, PerfettoTrace.Category category) {
229             if (!mIsCategoryEnabled) {
230                 return this;
231             }
232 
233             mTraceType = traceType;
234             mCategory = category;
235             mEventName = "";
236             mFieldInt64Cache.reset();
237             mFieldDoubleCache.reset();
238             mFieldStringCache.reset();
239             mFieldNestedCache.reset();
240             mBuilderCache.reset();
241 
242             mExtra.reset();
243             // Reset after on init in case the thread created builders without calling emit
244             return initInternal(this, null);
245         }
246 
247         /**
248          * Sets the event name for the track event.
249          */
setEventName(String eventName)250         public Builder setEventName(String eventName) {
251             mEventName = eventName;
252             return this;
253         }
254 
255         /**
256          * Adds a debug arg with key {@code name} and value {@code val}.
257          */
addArg(String name, long val)258         public Builder addArg(String name, long val) {
259             if (!mIsCategoryEnabled) {
260                 return this;
261             }
262             if (DEBUG) {
263                 checkParent();
264             }
265             ArgInt64 arg = mArgInt64Cache.get(name.hashCode());
266             if (arg == null || !arg.getName().equals(name)) {
267                 arg = new ArgInt64(name);
268                 mArgInt64Cache.put(name.hashCode(), arg);
269             }
270             arg.setValue(val);
271             mExtra.addPerfettoPointer(arg);
272             return this;
273         }
274 
275         /**
276          * Adds a debug arg with key {@code name} and value {@code val}.
277          */
addArg(String name, boolean val)278         public Builder addArg(String name, boolean val) {
279             if (!mIsCategoryEnabled) {
280                 return this;
281             }
282             if (DEBUG) {
283                 checkParent();
284             }
285             ArgBool arg = mArgBoolCache.get(name.hashCode());
286             if (arg == null || !arg.getName().equals(name)) {
287                 arg = new ArgBool(name);
288                 mArgBoolCache.put(name.hashCode(), arg);
289             }
290             arg.setValue(val);
291             mExtra.addPerfettoPointer(arg);
292             return this;
293         }
294 
295         /**
296          * Adds a debug arg with key {@code name} and value {@code val}.
297          */
addArg(String name, double val)298         public Builder addArg(String name, double val) {
299             if (!mIsCategoryEnabled) {
300                 return this;
301             }
302             if (DEBUG) {
303                 checkParent();
304             }
305             ArgDouble arg = mArgDoubleCache.get(name.hashCode());
306             if (arg == null || !arg.getName().equals(name)) {
307                 arg = new ArgDouble(name);
308                 mArgDoubleCache.put(name.hashCode(), arg);
309             }
310             arg.setValue(val);
311             mExtra.addPerfettoPointer(arg);
312             return this;
313         }
314 
315         /**
316          * Adds a debug arg with key {@code name} and value {@code val}.
317          */
addArg(String name, String val)318         public Builder addArg(String name, String val) {
319             if (!mIsCategoryEnabled) {
320                 return this;
321             }
322             if (DEBUG) {
323                 checkParent();
324             }
325             ArgString arg = mArgStringCache.get(name.hashCode());
326             if (arg == null || !arg.getName().equals(name)) {
327                 arg = new ArgString(name);
328                 mArgStringCache.put(name.hashCode(), arg);
329             }
330             arg.setValue(val);
331             mExtra.addPerfettoPointer(arg);
332             return this;
333         }
334 
335         /**
336          * Adds a flow with {@code id}.
337          */
setFlow(long id)338         public Builder setFlow(long id) {
339             if (!mIsCategoryEnabled) {
340                 return this;
341             }
342             if (DEBUG) {
343                 checkParent();
344             }
345             mFlow.setProcessFlow(id);
346             mExtra.addPerfettoPointer(mFlow);
347             return this;
348         }
349 
350         /**
351          * Adds a terminating flow with {@code id}.
352          */
setTerminatingFlow(long id)353         public Builder setTerminatingFlow(long id) {
354             if (!mIsCategoryEnabled) {
355                 return this;
356             }
357             if (DEBUG) {
358                 checkParent();
359             }
360             mTerminatingFlow.setProcessTerminatingFlow(id);
361             mExtra.addPerfettoPointer(mTerminatingFlow);
362             return this;
363         }
364 
365         /**
366          * Adds the events to a named track instead of the thread track where the
367          * event occurred.
368          */
usingNamedTrack(long parentUuid, String name)369         public Builder usingNamedTrack(long parentUuid, String name) {
370             if (!mIsCategoryEnabled) {
371                 return this;
372             }
373             if (DEBUG) {
374                 checkParent();
375             }
376 
377             NamedTrack track = mNamedTrackCache.get(name.hashCode());
378             if (track == null || !track.getName().equals(name)) {
379                 track = new NamedTrack(name, parentUuid);
380                 mNamedTrackCache.put(name.hashCode(), track);
381             }
382             mExtra.addPerfettoPointer(track);
383             return this;
384         }
385 
386         /**
387          * Adds the events to a process scoped named track instead of the thread track where the
388          * event occurred.
389          */
usingProcessNamedTrack(String name)390         public Builder usingProcessNamedTrack(String name) {
391             if (!mIsCategoryEnabled) {
392                 return this;
393             }
394             return usingNamedTrack(PerfettoTrace.getProcessTrackUuid(), name);
395         }
396 
397         /**
398          * Adds the events to a thread scoped named track instead of the thread track where the
399          * event occurred.
400          */
usingThreadNamedTrack(long tid, String name)401         public Builder usingThreadNamedTrack(long tid, String name) {
402             if (!mIsCategoryEnabled) {
403                 return this;
404             }
405             return usingNamedTrack(PerfettoTrace.getThreadTrackUuid(tid), name);
406         }
407 
408         /**
409          * Adds the events to a counter track instead. This is required for
410          * setting counter values.
411          */
usingCounterTrack(long parentUuid, String name)412         public Builder usingCounterTrack(long parentUuid, String name) {
413             if (!mIsCategoryEnabled) {
414                 return this;
415             }
416             if (DEBUG) {
417                 checkParent();
418             }
419 
420             CounterTrack track = mCounterTrackCache.get(name.hashCode());
421             if (track == null || !track.getName().equals(name)) {
422                 track = new CounterTrack(name, parentUuid);
423                 mCounterTrackCache.put(name.hashCode(), track);
424             }
425             mExtra.addPerfettoPointer(track);
426             return this;
427         }
428 
429         /**
430          * Adds the events to a process scoped counter track instead. This is required for
431          * setting counter values.
432          */
usingProcessCounterTrack(String name)433         public Builder usingProcessCounterTrack(String name) {
434             if (!mIsCategoryEnabled) {
435                 return this;
436             }
437             return usingCounterTrack(PerfettoTrace.getProcessTrackUuid(), name);
438         }
439 
440         /**
441          * Adds the events to a thread scoped counter track instead. This is required for
442          * setting counter values.
443          */
usingThreadCounterTrack(long tid, String name)444         public Builder usingThreadCounterTrack(long tid, String name) {
445             if (!mIsCategoryEnabled) {
446                 return this;
447             }
448             return usingCounterTrack(PerfettoTrace.getThreadTrackUuid(tid), name);
449         }
450 
451         /**
452          * Sets a long counter value on the event.
453          *
454          */
setCounter(long val)455         public Builder setCounter(long val) {
456             if (!mIsCategoryEnabled) {
457                 return this;
458             }
459             if (DEBUG) {
460                 checkParent();
461             }
462             mCounterInt64.setValue(val);
463             mExtra.addPerfettoPointer(mCounterInt64);
464             return this;
465         }
466 
467         /**
468          * Sets a double counter value on the event.
469          *
470          */
setCounter(double val)471         public Builder setCounter(double val) {
472             if (!mIsCategoryEnabled) {
473                 return this;
474             }
475             if (DEBUG) {
476                 checkParent();
477             }
478             mCounterDouble.setValue(val);
479             mExtra.addPerfettoPointer(mCounterDouble);
480             return this;
481         }
482 
483         /**
484          * Adds a proto field with field id {@code id} and value {@code val}.
485          */
addField(long id, long val)486         public Builder addField(long id, long val) {
487             if (!mIsCategoryEnabled) {
488                 return this;
489             }
490             if (DEBUG) {
491                 checkContainer();
492             }
493             FieldInt64 field = mFieldInt64Cache.get(sFieldInt64Supplier);
494             field.setValue(id, val);
495             mExtra.addPerfettoPointer(mCurrentContainer, field);
496             return this;
497         }
498 
499         /**
500          * Adds a proto field with field id {@code id} and value {@code val}.
501          */
addField(long id, double val)502         public Builder addField(long id, double val) {
503             if (!mIsCategoryEnabled) {
504                 return this;
505             }
506             if (DEBUG) {
507                 checkContainer();
508             }
509             FieldDouble field = mFieldDoubleCache.get(sFieldDoubleSupplier);
510             field.setValue(id, val);
511             mExtra.addPerfettoPointer(mCurrentContainer, field);
512             return this;
513         }
514 
515         /**
516          * Adds a proto field with field id {@code id} and value {@code val}.
517          */
addField(long id, String val)518         public Builder addField(long id, String val) {
519             if (!mIsCategoryEnabled) {
520                 return this;
521             }
522             if (DEBUG) {
523                 checkContainer();
524             }
525             FieldString field = mFieldStringCache.get(sFieldStringSupplier);
526             field.setValue(id, val);
527             mExtra.addPerfettoPointer(mCurrentContainer, field);
528             return this;
529         }
530 
531         /**
532          * Begins a proto field.
533          * Fields can be added from this point and there must be a corresponding
534          * {@link endProto}.
535          *
536          * The proto field is a singleton and all proto fields get added inside the
537          * one {@link beginProto} and {@link endProto} within the {@link Builder}.
538          */
beginProto()539         public Builder beginProto() {
540             if (!mIsCategoryEnabled) {
541                 return this;
542             }
543             if (DEBUG) {
544                 checkParent();
545             }
546             mProto.clearFields();
547             mExtra.addPerfettoPointer(mProto);
548             return mBuilderCache.get(sBuilderSupplier).initInternal(this, mProto);
549         }
550 
551         /**
552          * Ends a proto field.
553          */
endProto()554         public Builder endProto() {
555             if (!mIsCategoryEnabled) {
556                 return this;
557             }
558             if (mParent == null || mCurrentContainer == null) {
559                 throw new IllegalStateException("No proto to end");
560             }
561             return mParent;
562         }
563 
564         /**
565          * Begins a nested proto field with field id {@code id}.
566          * Fields can be added from this point and there must be a corresponding
567          * {@link endNested}.
568          */
beginNested(long id)569         public Builder beginNested(long id) {
570             if (!mIsCategoryEnabled) {
571                 return this;
572             }
573             if (DEBUG) {
574                 checkContainer();
575             }
576             FieldNested field = mFieldNestedCache.get(sFieldNestedSupplier);
577             field.setId(id);
578             mExtra.addPerfettoPointer(mCurrentContainer, field);
579             return mBuilderCache.get(sBuilderSupplier).initInternal(this, field);
580         }
581 
582         /**
583          * Ends a nested proto field.
584          */
endNested()585         public Builder endNested() {
586             if (!mIsCategoryEnabled) {
587                 return this;
588             }
589             if (mParent == null || mCurrentContainer == null) {
590                 throw new IllegalStateException("No nested field to end");
591             }
592             return mParent;
593         }
594 
595 
initInternal(Builder parent, FieldContainer field)596         private Builder initInternal(Builder parent, FieldContainer field) {
597             mParent = parent;
598             mCurrentContainer = field;
599             mIsBuilt = false;
600 
601             return this;
602         }
603 
checkState()604         private void checkState() {
605             if (mIsBuilt) {
606                 throw new IllegalStateException(
607                     "This builder has already been used. Create a new builder for another event.");
608             }
609         }
610 
checkParent()611         private void checkParent() {
612             checkState();
613             if (!this.equals(mParent)) {
614                 throw new IllegalStateException("Operation not supported for proto");
615             }
616         }
617 
checkContainer()618         private void checkContainer() {
619             checkState();
620             if (mCurrentContainer == null) {
621                 throw new IllegalStateException(
622                     "Field operations must be within beginProto/endProto block");
623             }
624         }
625     }
626 
627     /**
628      * Start a {@link Builder} to build a {@link PerfettoTrackEventExtra}.
629      */
builder(boolean isCategoryEnabled)630     public static Builder builder(boolean isCategoryEnabled) {
631         if (isCategoryEnabled) {
632             return sTrackEventExtra.get().mBuilderCache.get(sBuilderSupplier)
633                 .initInternal(null, null);
634         }
635         return NO_OP_BUILDER;
636     }
637 
638     private final RingBuffer<NamedTrack> mNamedTrackCache =
639             new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE);
640     private final RingBuffer<CounterTrack> mCounterTrackCache =
641             new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE);
642 
643     private final RingBuffer<ArgInt64> mArgInt64Cache = new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE);
644     private final RingBuffer<ArgBool> mArgBoolCache = new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE);
645     private final RingBuffer<ArgDouble> mArgDoubleCache = new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE);
646     private final RingBuffer<ArgString> mArgStringCache = new RingBuffer(DEFAULT_EXTRA_CACHE_SIZE);
647 
648     private final Pool<FieldInt64> mFieldInt64Cache = new Pool(DEFAULT_EXTRA_CACHE_SIZE);
649     private final Pool<FieldDouble> mFieldDoubleCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE);
650     private final Pool<FieldString> mFieldStringCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE);
651     private final Pool<FieldNested> mFieldNestedCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE);
652     private final Pool<Builder> mBuilderCache = new Pool(DEFAULT_EXTRA_CACHE_SIZE);
653 
654     private static final NativeAllocationRegistry sRegistry =
655             NativeAllocationRegistry.createMalloced(
656                     PerfettoTrackEventExtra.class.getClassLoader(), native_delete());
657 
658     private final long mPtr;
659     private static final String TAG = "PerfettoTrackEventExtra";
660 
PerfettoTrackEventExtra()661     private PerfettoTrackEventExtra() {
662         mPtr = native_init();
663     }
664 
665     /**
666      * Returns the native pointer.
667      */
getPtr()668     public long getPtr() {
669         return mPtr;
670     }
671 
672     /**
673      * Adds a pointer representing a track event parameter.
674      */
addPerfettoPointer(PerfettoPointer extra)675     public void addPerfettoPointer(PerfettoPointer extra) {
676         native_add_arg(mPtr, extra.getPtr());
677         mPendingPointers.add(extra);
678     }
679 
680     /**
681      * Adds a pointer representing a track event parameter to the {@code container}.
682      */
addPerfettoPointer(FieldContainer container, PerfettoPointer extra)683     public void addPerfettoPointer(FieldContainer container, PerfettoPointer extra) {
684         container.addField(extra);
685         mPendingPointers.add(extra);
686     }
687 
688     /**
689      * Resets the track event extra.
690      */
reset()691     public void reset() {
692         native_clear_args(mPtr);
693         mPendingPointers.clear();
694     }
695 
getCounterInt64()696     private CounterInt64 getCounterInt64() {
697         if (mCounterInt64 == null) {
698             mCounterInt64 = new CounterInt64();
699         }
700         return mCounterInt64;
701     }
702 
getCounterDouble()703     private CounterDouble getCounterDouble() {
704         if (mCounterDouble == null) {
705             mCounterDouble = new CounterDouble();
706         }
707         return mCounterDouble;
708     }
709 
getProto()710     private Proto getProto() {
711         if (mProto == null) {
712             mProto = new Proto();
713         }
714         return mProto;
715     }
716 
getFlow()717     private Flow getFlow() {
718         if (mFlow == null) {
719             mFlow = new Flow();
720         }
721         return mFlow;
722     }
723 
getTerminatingFlow()724     private Flow getTerminatingFlow() {
725         if (mTerminatingFlow == null) {
726             mTerminatingFlow = new Flow();
727         }
728         return mTerminatingFlow;
729     }
730 
731     private static final class Flow implements PerfettoPointer {
732         private final long mPtr;
733         private final long mExtraPtr;
734 
Flow()735         Flow() {
736             mPtr = native_init();
737             mExtraPtr = native_get_extra_ptr(mPtr);
738             sRegistry.registerNativeAllocation(this, mPtr);
739         }
740 
setProcessFlow(long type)741         public void setProcessFlow(long type) {
742             native_set_process_flow(mPtr, type);
743         }
744 
setProcessTerminatingFlow(long id)745         public void setProcessTerminatingFlow(long id) {
746             native_set_process_terminating_flow(mPtr, id);
747         }
748 
749         @Override
getPtr()750         public long getPtr() {
751             return mExtraPtr;
752         }
753 
754         @CriticalNative
native_init()755         private static native long native_init();
756         @CriticalNative
native_delete()757         private static native long native_delete();
758         @CriticalNative
native_set_process_flow(long ptr, long type)759         private static native void native_set_process_flow(long ptr, long type);
760         @CriticalNative
native_set_process_terminating_flow(long ptr, long id)761         private static native void native_set_process_terminating_flow(long ptr, long id);
762         @CriticalNative
native_get_extra_ptr(long ptr)763         private static native long native_get_extra_ptr(long ptr);
764     }
765 
766     private static class NamedTrack implements PerfettoPointer {
767         private static final NativeAllocationRegistry sRegistry =
768                 NativeAllocationRegistry.createMalloced(
769                         NamedTrack.class.getClassLoader(), native_delete());
770 
771         private final long mPtr;
772         private final long mExtraPtr;
773         private final String mName;
774 
NamedTrack(String name, long parentUuid)775         NamedTrack(String name, long parentUuid) {
776             mPtr = native_init(sNamedTrackId.incrementAndGet(), name, parentUuid);
777             mExtraPtr = native_get_extra_ptr(mPtr);
778             mName = name;
779             sRegistry.registerNativeAllocation(this, mPtr);
780         }
781 
782         @Override
getPtr()783         public long getPtr() {
784             return mExtraPtr;
785         }
786 
getName()787         public String getName() {
788             return mName;
789         }
790 
791         @FastNative
native_init(long id, String name, long parentUuid)792         private static native long native_init(long id, String name, long parentUuid);
793         @CriticalNative
native_delete()794         private static native long native_delete();
795         @CriticalNative
native_get_extra_ptr(long ptr)796         private static native long native_get_extra_ptr(long ptr);
797     }
798 
799     private static final class CounterTrack implements PerfettoPointer {
800         private static final NativeAllocationRegistry sRegistry =
801                 NativeAllocationRegistry.createMalloced(
802                         CounterTrack.class.getClassLoader(), native_delete());
803 
804         private final long mPtr;
805         private final long mExtraPtr;
806         private final String mName;
807 
CounterTrack(String name, long parentUuid)808         CounterTrack(String name, long parentUuid) {
809             mPtr = native_init(name, parentUuid);
810             mExtraPtr = native_get_extra_ptr(mPtr);
811             mName = name;
812             sRegistry.registerNativeAllocation(this, mPtr);
813         }
814 
815         @Override
getPtr()816         public long getPtr() {
817             return mExtraPtr;
818         }
819 
getName()820         public String getName() {
821             return mName;
822         }
823 
824         @FastNative
native_init(String name, long parentUuid)825         private static native long native_init(String name, long parentUuid);
826         @CriticalNative
native_delete()827         private static native long native_delete();
828         @CriticalNative
native_get_extra_ptr(long ptr)829         private static native long native_get_extra_ptr(long ptr);
830     }
831 
832     private static final class CounterInt64 implements PerfettoPointer {
833         private static final NativeAllocationRegistry sRegistry =
834                 NativeAllocationRegistry.createMalloced(
835                         CounterInt64.class.getClassLoader(), native_delete());
836 
837         private final long mPtr;
838         private final long mExtraPtr;
839 
CounterInt64()840         CounterInt64() {
841             mPtr = native_init();
842             mExtraPtr = native_get_extra_ptr(mPtr);
843             sRegistry.registerNativeAllocation(this, mPtr);
844         }
845 
846         @Override
getPtr()847         public long getPtr() {
848             return mExtraPtr;
849         }
850 
setValue(long value)851         public void setValue(long value) {
852             native_set_value(mPtr, value);
853         }
854 
855         @CriticalNative
native_init()856         private static native long native_init();
857         @CriticalNative
native_delete()858         private static native long native_delete();
859         @CriticalNative
native_set_value(long ptr, long value)860         private static native void native_set_value(long ptr, long value);
861         @CriticalNative
native_get_extra_ptr(long ptr)862         private static native long native_get_extra_ptr(long ptr);
863     }
864 
865     private static final class CounterDouble implements PerfettoPointer {
866         private static final NativeAllocationRegistry sRegistry =
867                 NativeAllocationRegistry.createMalloced(
868                         CounterDouble.class.getClassLoader(), native_delete());
869 
870         private final long mPtr;
871         private final long mExtraPtr;
872 
CounterDouble()873         CounterDouble() {
874             mPtr = native_init();
875             mExtraPtr = native_get_extra_ptr(mPtr);
876             sRegistry.registerNativeAllocation(this, mPtr);
877         }
878 
879         @Override
getPtr()880         public long getPtr() {
881             return mExtraPtr;
882         }
883 
setValue(double value)884         public void setValue(double value) {
885             native_set_value(mPtr, value);
886         }
887 
888         @CriticalNative
native_init()889         private static native long native_init();
890         @CriticalNative
native_delete()891         private static native long native_delete();
892         @CriticalNative
native_set_value(long ptr, double value)893         private static native void native_set_value(long ptr, double value);
894         @CriticalNative
native_get_extra_ptr(long ptr)895         private static native long native_get_extra_ptr(long ptr);
896     }
897 
898     private static final class ArgInt64 implements PerfettoPointer {
899         private static final NativeAllocationRegistry sRegistry =
900                 NativeAllocationRegistry.createMalloced(
901                         ArgInt64.class.getClassLoader(), native_delete());
902 
903         // Private pointer holding Perfetto object with metadata
904         private final long mPtr;
905 
906         // Public pointer to Perfetto object itself
907         private final long mExtraPtr;
908 
909         private final String mName;
910 
ArgInt64(String name)911         ArgInt64(String name) {
912             mPtr = native_init(name);
913             mExtraPtr = native_get_extra_ptr(mPtr);
914             mName = name;
915             sRegistry.registerNativeAllocation(this, mPtr);
916         }
917 
918         @Override
getPtr()919         public long getPtr() {
920             return mExtraPtr;
921         }
922 
getName()923         public String getName() {
924             return mName;
925         }
926 
setValue(long val)927         public void setValue(long val) {
928             native_set_value(mPtr, val);
929         }
930 
931         @FastNative
native_init(String name)932         private static native long native_init(String name);
933         @CriticalNative
native_delete()934         private static native long native_delete();
935         @CriticalNative
native_get_extra_ptr(long ptr)936         private static native long native_get_extra_ptr(long ptr);
937         @CriticalNative
native_set_value(long ptr, long val)938         private static native void native_set_value(long ptr, long val);
939     }
940 
941     private static final class ArgBool implements PerfettoPointer {
942         private static final NativeAllocationRegistry sRegistry =
943                 NativeAllocationRegistry.createMalloced(
944                         ArgBool.class.getClassLoader(), native_delete());
945 
946         // Private pointer holding Perfetto object with metadata
947         private final long mPtr;
948 
949         // Public pointer to Perfetto object itself
950         private final long mExtraPtr;
951 
952         private final String mName;
953 
ArgBool(String name)954         ArgBool(String name) {
955             mPtr = native_init(name);
956             mExtraPtr = native_get_extra_ptr(mPtr);
957             mName = name;
958             sRegistry.registerNativeAllocation(this, mPtr);
959         }
960 
961         @Override
getPtr()962         public long getPtr() {
963             return mExtraPtr;
964         }
965 
getName()966         public String getName() {
967             return mName;
968         }
969 
setValue(boolean val)970         public void setValue(boolean val) {
971             native_set_value(mPtr, val);
972         }
973 
974         @FastNative
native_init(String name)975         private static native long native_init(String name);
976         @CriticalNative
native_delete()977         private static native long native_delete();
978         @CriticalNative
native_get_extra_ptr(long ptr)979         private static native long native_get_extra_ptr(long ptr);
980         @CriticalNative
native_set_value(long ptr, boolean val)981         private static native void native_set_value(long ptr, boolean val);
982     }
983 
984     private static final class ArgDouble implements PerfettoPointer {
985         private static final NativeAllocationRegistry sRegistry =
986                 NativeAllocationRegistry.createMalloced(
987                         ArgDouble.class.getClassLoader(), native_delete());
988 
989         // Private pointer holding Perfetto object with metadata
990         private final long mPtr;
991 
992         // Public pointer to Perfetto object itself
993         private final long mExtraPtr;
994 
995         private final String mName;
996 
ArgDouble(String name)997         ArgDouble(String name) {
998             mPtr = native_init(name);
999             mExtraPtr = native_get_extra_ptr(mPtr);
1000             mName = name;
1001             sRegistry.registerNativeAllocation(this, mPtr);
1002         }
1003 
1004         @Override
getPtr()1005         public long getPtr() {
1006             return mExtraPtr;
1007         }
1008 
getName()1009         public String getName() {
1010             return mName;
1011         }
1012 
setValue(double val)1013         public void setValue(double val) {
1014             native_set_value(mPtr, val);
1015         }
1016 
1017         @FastNative
native_init(String name)1018         private static native long native_init(String name);
1019         @CriticalNative
native_delete()1020         private static native long native_delete();
1021         @CriticalNative
native_get_extra_ptr(long ptr)1022         private static native long native_get_extra_ptr(long ptr);
1023         @CriticalNative
native_set_value(long ptr, double val)1024         private static native void native_set_value(long ptr, double val);
1025     }
1026 
1027     private static final class ArgString implements PerfettoPointer {
1028         private static final NativeAllocationRegistry sRegistry =
1029                 NativeAllocationRegistry.createMalloced(
1030                         ArgString.class.getClassLoader(), native_delete());
1031 
1032         // Private pointer holding Perfetto object with metadata
1033         private final long mPtr;
1034 
1035         // Public pointer to Perfetto object itself
1036         private final long mExtraPtr;
1037 
1038         private final String mName;
1039 
ArgString(String name)1040         ArgString(String name) {
1041             mPtr = native_init(name);
1042             mExtraPtr = native_get_extra_ptr(mPtr);
1043             mName = name;
1044             sRegistry.registerNativeAllocation(this, mPtr);
1045         }
1046 
1047         @Override
getPtr()1048         public long getPtr() {
1049             return mExtraPtr;
1050         }
1051 
getName()1052         public String getName() {
1053             return mName;
1054         }
1055 
setValue(String val)1056         public void setValue(String val) {
1057             native_set_value(mPtr, val);
1058         }
1059 
1060         @FastNative
native_init(String name)1061         private static native long native_init(String name);
1062         @CriticalNative
native_delete()1063         private static native long native_delete();
1064         @CriticalNative
native_get_extra_ptr(long ptr)1065         private static native long native_get_extra_ptr(long ptr);
1066         @FastNative
native_set_value(long ptr, String val)1067         private static native void native_set_value(long ptr, String val);
1068     }
1069 
1070     private static final class Proto implements PerfettoPointer, FieldContainer {
1071         private static final NativeAllocationRegistry sRegistry =
1072                 NativeAllocationRegistry.createMalloced(
1073                         Proto.class.getClassLoader(), native_delete());
1074 
1075         // Private pointer holding Perfetto object with metadata
1076         private final long mPtr;
1077 
1078         // Public pointer to Perfetto object itself
1079         private final long mExtraPtr;
1080 
Proto()1081         Proto() {
1082             mPtr = native_init();
1083             mExtraPtr = native_get_extra_ptr(mPtr);
1084             sRegistry.registerNativeAllocation(this, mPtr);
1085         }
1086 
1087         @Override
getPtr()1088         public long getPtr() {
1089             return mExtraPtr;
1090         }
1091 
1092         @Override
addField(PerfettoPointer field)1093         public void addField(PerfettoPointer field) {
1094             native_add_field(mPtr, field.getPtr());
1095         }
1096 
clearFields()1097         public void clearFields() {
1098             native_clear_fields(mPtr);
1099         }
1100 
1101         @CriticalNative
native_init()1102         private static native long native_init();
1103         @CriticalNative
native_delete()1104         private static native long native_delete();
1105         @CriticalNative
native_get_extra_ptr(long ptr)1106         private static native long native_get_extra_ptr(long ptr);
1107         @CriticalNative
native_add_field(long ptr, long extraPtr)1108         private static native void native_add_field(long ptr, long extraPtr);
1109         @CriticalNative
native_clear_fields(long ptr)1110         private static native void native_clear_fields(long ptr);
1111     }
1112 
1113     private static final class FieldInt64 implements PerfettoPointer {
1114         private static final NativeAllocationRegistry sRegistry =
1115                 NativeAllocationRegistry.createMalloced(
1116                         FieldInt64.class.getClassLoader(), native_delete());
1117 
1118         // Private pointer holding Perfetto object with metadata
1119         private final long mPtr;
1120 
1121         // Public pointer to Perfetto object itself
1122         private final long mFieldPtr;
1123 
FieldInt64()1124         FieldInt64() {
1125             mPtr = native_init();
1126             mFieldPtr = native_get_extra_ptr(mPtr);
1127             sRegistry.registerNativeAllocation(this, mPtr);
1128         }
1129 
1130         @Override
getPtr()1131         public long getPtr() {
1132             return mFieldPtr;
1133         }
1134 
setValue(long id, long val)1135         public void setValue(long id, long val) {
1136             native_set_value(mPtr, id, val);
1137         }
1138 
1139         @CriticalNative
native_init()1140         private static native long native_init();
1141         @CriticalNative
native_delete()1142         private static native long native_delete();
1143         @CriticalNative
native_get_extra_ptr(long ptr)1144         private static native long native_get_extra_ptr(long ptr);
1145         @CriticalNative
native_set_value(long ptr, long id, long val)1146         private static native void native_set_value(long ptr, long id, long val);
1147     }
1148 
1149     private static final class FieldDouble implements PerfettoPointer {
1150         private static final NativeAllocationRegistry sRegistry =
1151                 NativeAllocationRegistry.createMalloced(
1152                         FieldDouble.class.getClassLoader(), native_delete());
1153 
1154         // Private pointer holding Perfetto object with metadata
1155         private final long mPtr;
1156 
1157         // Public pointer to Perfetto object itself
1158         private final long mFieldPtr;
1159 
FieldDouble()1160         FieldDouble() {
1161             mPtr = native_init();
1162             mFieldPtr = native_get_extra_ptr(mPtr);
1163             sRegistry.registerNativeAllocation(this, mPtr);
1164         }
1165 
1166         @Override
getPtr()1167         public long getPtr() {
1168             return mFieldPtr;
1169         }
1170 
setValue(long id, double val)1171         public void setValue(long id, double val) {
1172             native_set_value(mPtr, id, val);
1173         }
1174 
1175         @CriticalNative
native_init()1176         private static native long native_init();
1177         @CriticalNative
native_delete()1178         private static native long native_delete();
1179         @CriticalNative
native_get_extra_ptr(long ptr)1180         private static native long native_get_extra_ptr(long ptr);
1181         @CriticalNative
native_set_value(long ptr, long id, double val)1182         private static native void native_set_value(long ptr, long id, double val);
1183     }
1184 
1185     private static final class FieldString implements PerfettoPointer {
1186         private static final NativeAllocationRegistry sRegistry =
1187                 NativeAllocationRegistry.createMalloced(
1188                         FieldString.class.getClassLoader(), native_delete());
1189 
1190         // Private pointer holding Perfetto object with metadata
1191         private final long mPtr;
1192 
1193         // Public pointer to Perfetto object itself
1194         private final long mFieldPtr;
1195 
FieldString()1196         FieldString() {
1197             mPtr = native_init();
1198             mFieldPtr = native_get_extra_ptr(mPtr);
1199             sRegistry.registerNativeAllocation(this, mPtr);
1200         }
1201 
1202         @Override
getPtr()1203         public long getPtr() {
1204             return mFieldPtr;
1205         }
1206 
setValue(long id, String val)1207         public void setValue(long id, String val) {
1208             native_set_value(mPtr, id, val);
1209         }
1210 
1211         @CriticalNative
native_init()1212         private static native long native_init();
1213         @CriticalNative
native_delete()1214         private static native long native_delete();
1215         @CriticalNative
native_get_extra_ptr(long ptr)1216         private static native long native_get_extra_ptr(long ptr);
1217         @FastNative
native_set_value(long ptr, long id, String val)1218         private static native void native_set_value(long ptr, long id, String val);
1219     }
1220 
1221     private static final class FieldNested implements PerfettoPointer, FieldContainer {
1222         private static final NativeAllocationRegistry sRegistry =
1223                 NativeAllocationRegistry.createMalloced(
1224                         FieldNested.class.getClassLoader(), native_delete());
1225 
1226         // Private pointer holding Perfetto object with metadata
1227         private final long mPtr;
1228 
1229         // Public pointer to Perfetto object itself
1230         private final long mFieldPtr;
1231 
FieldNested()1232         FieldNested() {
1233             mPtr = native_init();
1234             mFieldPtr = native_get_extra_ptr(mPtr);
1235             sRegistry.registerNativeAllocation(this, mPtr);
1236         }
1237 
1238         @Override
getPtr()1239         public long getPtr() {
1240             return mFieldPtr;
1241         }
1242 
1243         @Override
addField(PerfettoPointer field)1244         public void addField(PerfettoPointer field) {
1245             native_add_field(mPtr, field.getPtr());
1246         }
1247 
setId(long id)1248         public void setId(long id) {
1249             native_set_id(mPtr, id);
1250         }
1251 
1252         @CriticalNative
native_init()1253         private static native long native_init();
1254         @CriticalNative
native_delete()1255         private static native long native_delete();
1256         @CriticalNative
native_get_extra_ptr(long ptr)1257         private static native long native_get_extra_ptr(long ptr);
1258         @CriticalNative
native_add_field(long ptr, long extraPtr)1259         private static native void native_add_field(long ptr, long extraPtr);
1260         @CriticalNative
native_set_id(long ptr, long id)1261         private static native void native_set_id(long ptr, long id);
1262     }
1263 
1264     @CriticalNative
native_init()1265     private static native long native_init();
1266     @CriticalNative
native_delete()1267     private static native long native_delete();
1268     @CriticalNative
native_add_arg(long ptr, long extraPtr)1269     private static native void native_add_arg(long ptr, long extraPtr);
1270     @CriticalNative
native_clear_args(long ptr)1271     private static native void native_clear_args(long ptr);
1272     @FastNative
native_emit(int type, long tag, String name, long ptr)1273     private static native void native_emit(int type, long tag, String name, long ptr);
1274 }
1275