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