• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.tracing.perfetto;
18 
19 import android.annotation.Nullable;
20 import android.annotation.NonNull;
21 import android.util.proto.ProtoInputStream;
22 
23 /**
24  * Templated base class meant to be derived by embedders to create a custom data
25  * source.
26  *
27  * @param <DataSourceInstanceType> The type for the DataSource instances that will be created from
28  *                                 this DataSource type.
29  * @param <TlsStateType> The type of the custom TLS state, if any is used.
30  * @param <IncrementalStateType> The type of the custom incremental state, if any is used.
31  *
32  * @hide
33  */
34 public abstract class DataSource<DataSourceInstanceType extends DataSourceInstance,
35         TlsStateType, IncrementalStateType> {
36     protected final long mNativeObj;
37 
38     public final String name;
39 
40     /**
41      * A function implemented by each datasource to create a new data source instance.
42      *
43      * @param configStream A ProtoInputStream to read the tracing instance's config.
44      * @return A new data source instance setup with the provided config.
45      */
46     @NonNull
createInstance( ProtoInputStream configStream, int instanceIndex)47     public abstract DataSourceInstanceType createInstance(
48             ProtoInputStream configStream, int instanceIndex);
49 
50     /**
51      * Constructor for datasource base class.
52      *
53      * @param name The fully qualified name of the datasource.
54      */
DataSource(String name)55     public DataSource(String name) {
56         this.name = name;
57         this.mNativeObj = nativeCreate(this, name);
58     }
59 
60     /**
61      * The main tracing method. Tracing code should call this passing a lambda as
62      * argument, with the following signature: void(TraceContext).
63      * <p>
64      * The lambda will be called synchronously (i.e., always before trace()
65      * returns) only if tracing is enabled and the data source has been enabled in
66      * the tracing config.
67      * <p>
68      * The lambda can be called more than once per trace() call, in the case of
69      * concurrent tracing sessions (or even if the data source is instantiated
70      * twice within the same trace config).
71      *
72      * @param fun The tracing lambda that will be called with the tracing contexts of each active
73      *            tracing instance.
74      */
trace( TraceFunction<DataSourceInstanceType, TlsStateType, IncrementalStateType> fun)75     public final void trace(
76             TraceFunction<DataSourceInstanceType, TlsStateType, IncrementalStateType> fun) {
77         boolean startedIterator = nativePerfettoDsTraceIterateBegin(mNativeObj);
78 
79         if (!startedIterator) {
80             return;
81         }
82 
83         try {
84             do {
85                 int instanceIndex = nativeGetPerfettoDsInstanceIndex(mNativeObj);
86 
87                 TracingContext<DataSourceInstanceType, TlsStateType, IncrementalStateType> ctx =
88                         new TracingContext<>(this, instanceIndex);
89                 fun.trace(ctx);
90 
91                 nativeWritePackets(mNativeObj, ctx.getAndClearAllPendingTracePackets());
92             } while (nativePerfettoDsTraceIterateNext(mNativeObj));
93         } finally {
94             nativePerfettoDsTraceIterateBreak(mNativeObj);
95         }
96     }
97 
98     /**
99      * Flush any trace data from this datasource that has not yet been flushed.
100      */
flush()101     public final void flush() {
102         nativeFlushAll(mNativeObj);
103     }
104 
105     /**
106      * Override this method to create a custom TlsState object for your DataSource. A new instance
107      * will be created per trace instance per thread.
108      */
109     @Nullable
createTlsState(CreateTlsStateArgs<DataSourceInstanceType> args)110     public TlsStateType createTlsState(CreateTlsStateArgs<DataSourceInstanceType> args) {
111         return null;
112     }
113 
114     /**
115      * Override this method to create and use a custom IncrementalState object for your DataSource.
116      *
117      */
118     @Nullable
createIncrementalState( CreateIncrementalStateArgs<DataSourceInstanceType> args)119     public IncrementalStateType createIncrementalState(
120             CreateIncrementalStateArgs<DataSourceInstanceType> args) {
121         return null;
122     }
123 
124     /**
125      * Registers the data source on all tracing backends, including ones that
126      * connect after the registration. Doing so enables the data source to receive
127      * Setup/Start/Stop notifications and makes the trace() method work when
128      * tracing is enabled and the data source is selected.
129      * <p>
130      * NOTE: Once registered, we cannot unregister the data source. Therefore, we should avoid
131      * creating and registering data source where not strictly required. This is a fundamental
132      * limitation of Perfetto itself.
133      *
134      * @param params Params to initialize the datasource with.
135      */
register(DataSourceParams params)136     public void register(DataSourceParams params) {
137         nativeRegisterDataSource(this.mNativeObj, params.bufferExhaustedPolicy,
138                 params.willNotifyOnStop, params.noFlush);
139     }
140 
141     /**
142      * Gets the datasource instance with a specified index.
143      * IMPORTANT: releaseDataSourceInstance must be called after using the datasource instance.
144      * @param instanceIndex The index of the datasource to lock and get.
145      * @return The DataSourceInstance at index instanceIndex.
146      *         Null if the datasource instance at the requested index doesn't exist.
147      */
148     @Nullable
getDataSourceInstanceLocked(int instanceIndex)149     public DataSourceInstanceType getDataSourceInstanceLocked(int instanceIndex) {
150         return (DataSourceInstanceType) nativeGetPerfettoInstanceLocked(mNativeObj, instanceIndex);
151     }
152 
153     /**
154      * Unlock the datasource at the specified index.
155      * @param instanceIndex The index of the datasource to unlock.
156      */
releaseDataSourceInstance(int instanceIndex)157     protected void releaseDataSourceInstance(int instanceIndex) {
158         nativeReleasePerfettoInstanceLocked(mNativeObj, instanceIndex);
159     }
160 
161     /**
162      * Called from native side when a new tracing instance starts.
163      *
164      * @param rawConfig byte array of the PerfettoConfig encoded proto.
165      * @return A new Java DataSourceInstance object.
166      */
167     @NonNull
createInstance(byte[] rawConfig, int instanceIndex)168     private DataSourceInstanceType createInstance(byte[] rawConfig, int instanceIndex) {
169         final ProtoInputStream inputStream = new ProtoInputStream(rawConfig);
170         return this.createInstance(inputStream, instanceIndex);
171     }
172 
nativeRegisterDataSource(long dataSourcePtr, int bufferExhaustedPolicy, boolean willNotifyOnStop, boolean noFlush)173     private static native void nativeRegisterDataSource(long dataSourcePtr,
174             int bufferExhaustedPolicy, boolean willNotifyOnStop, boolean noFlush);
175 
nativeCreate(DataSource thiz, String name)176     private static native long nativeCreate(DataSource thiz, String name);
nativeFlushAll(long nativeDataSourcePointer)177     private static native void nativeFlushAll(long nativeDataSourcePointer);
nativeGetFinalizer()178     private static native long nativeGetFinalizer();
179 
nativeGetPerfettoInstanceLocked( long dataSourcePtr, int dsInstanceIdx)180     private static native DataSourceInstance nativeGetPerfettoInstanceLocked(
181             long dataSourcePtr, int dsInstanceIdx);
nativeReleasePerfettoInstanceLocked( long dataSourcePtr, int dsInstanceIdx)182     private static native void nativeReleasePerfettoInstanceLocked(
183             long dataSourcePtr, int dsInstanceIdx);
184 
nativePerfettoDsTraceIterateBegin(long dataSourcePtr)185     private static native boolean nativePerfettoDsTraceIterateBegin(long dataSourcePtr);
nativePerfettoDsTraceIterateNext(long dataSourcePtr)186     private static native boolean nativePerfettoDsTraceIterateNext(long dataSourcePtr);
nativePerfettoDsTraceIterateBreak(long dataSourcePtr)187     private static native void nativePerfettoDsTraceIterateBreak(long dataSourcePtr);
nativeGetPerfettoDsInstanceIndex(long dataSourcePtr)188     private static native int nativeGetPerfettoDsInstanceIndex(long dataSourcePtr);
189 
nativeWritePackets(long dataSourcePtr, byte[][] packetData)190     private static native void nativeWritePackets(long dataSourcePtr, byte[][] packetData);
191 }
192