186 lines
7.3 KiB
Java
186 lines
7.3 KiB
Java
/*
|
|
* Copyright (C) 2023 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package android.tracing.perfetto;
|
|
|
|
import android.util.proto.ProtoInputStream;
|
|
|
|
/**
|
|
* Templated base class meant to be derived by embedders to create a custom data
|
|
* source.
|
|
*
|
|
* @param <DataSourceInstanceType> The type for the DataSource instances that will be created from
|
|
* this DataSource type.
|
|
* @param <TlsStateType> The type of the custom TLS state, if any is used.
|
|
* @param <IncrementalStateType> The type of the custom incremental state, if any is used.
|
|
*
|
|
* @hide
|
|
*/
|
|
public abstract class DataSource<DataSourceInstanceType extends DataSourceInstance,
|
|
TlsStateType, IncrementalStateType> {
|
|
protected final long mNativeObj;
|
|
|
|
public final String name;
|
|
|
|
/**
|
|
* A function implemented by each datasource to create a new data source instance.
|
|
*
|
|
* @param configStream A ProtoInputStream to read the tracing instance's config.
|
|
* @return A new data source instance setup with the provided config.
|
|
*/
|
|
public abstract DataSourceInstanceType createInstance(
|
|
ProtoInputStream configStream, int instanceIndex);
|
|
|
|
/**
|
|
* Constructor for datasource base class.
|
|
*
|
|
* @param name The fully qualified name of the datasource.
|
|
*/
|
|
public DataSource(String name) {
|
|
this.name = name;
|
|
this.mNativeObj = nativeCreate(this, name);
|
|
}
|
|
|
|
/**
|
|
* The main tracing method. Tracing code should call this passing a lambda as
|
|
* argument, with the following signature: void(TraceContext).
|
|
* <p>
|
|
* The lambda will be called synchronously (i.e., always before trace()
|
|
* returns) only if tracing is enabled and the data source has been enabled in
|
|
* the tracing config.
|
|
* <p>
|
|
* The lambda can be called more than once per trace() call, in the case of
|
|
* concurrent tracing sessions (or even if the data source is instantiated
|
|
* twice within the same trace config).
|
|
*
|
|
* @param fun The tracing lambda that will be called with the tracing contexts of each active
|
|
* tracing instance.
|
|
*/
|
|
public final void trace(
|
|
TraceFunction<DataSourceInstanceType, TlsStateType, IncrementalStateType> fun) {
|
|
boolean startedIterator = nativePerfettoDsTraceIterateBegin(mNativeObj);
|
|
|
|
if (!startedIterator) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
do {
|
|
int instanceIndex = nativeGetPerfettoDsInstanceIndex(mNativeObj);
|
|
|
|
TracingContext<DataSourceInstanceType, TlsStateType, IncrementalStateType> ctx =
|
|
new TracingContext<>(this, instanceIndex);
|
|
fun.trace(ctx);
|
|
|
|
nativeWritePackets(mNativeObj, ctx.getAndClearAllPendingTracePackets());
|
|
} while (nativePerfettoDsTraceIterateNext(mNativeObj));
|
|
} finally {
|
|
nativePerfettoDsTraceIterateBreak(mNativeObj);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Flush any trace data from this datasource that has not yet been flushed.
|
|
*/
|
|
public final void flush() {
|
|
nativeFlushAll(mNativeObj);
|
|
}
|
|
|
|
/**
|
|
* Override this method to create a custom TlsState object for your DataSource. A new instance
|
|
* will be created per trace instance per thread.
|
|
*
|
|
*/
|
|
public TlsStateType createTlsState(CreateTlsStateArgs<DataSourceInstanceType> args) {
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Override this method to create and use a custom IncrementalState object for your DataSource.
|
|
*
|
|
*/
|
|
public IncrementalStateType createIncrementalState(
|
|
CreateIncrementalStateArgs<DataSourceInstanceType> args) {
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Registers the data source on all tracing backends, including ones that
|
|
* connect after the registration. Doing so enables the data source to receive
|
|
* Setup/Start/Stop notifications and makes the trace() method work when
|
|
* tracing is enabled and the data source is selected.
|
|
* <p>
|
|
* NOTE: Once registered, we cannot unregister the data source. Therefore, we should avoid
|
|
* creating and registering data source where not strictly required. This is a fundamental
|
|
* limitation of Perfetto itself.
|
|
*
|
|
* @param params Params to initialize the datasource with.
|
|
*/
|
|
public void register(DataSourceParams params) {
|
|
nativeRegisterDataSource(this.mNativeObj, params.bufferExhaustedPolicy,
|
|
params.willNotifyOnStop, params.noFlush);
|
|
}
|
|
|
|
/**
|
|
* Gets the datasource instance with a specified index.
|
|
* IMPORTANT: releaseDataSourceInstance must be called after using the datasource instance.
|
|
* @param instanceIndex The index of the datasource to lock and get.
|
|
* @return The DataSourceInstance at index instanceIndex.
|
|
* Null if the datasource instance at the requested index doesn't exist.
|
|
*/
|
|
public DataSourceInstanceType getDataSourceInstanceLocked(int instanceIndex) {
|
|
return (DataSourceInstanceType) nativeGetPerfettoInstanceLocked(mNativeObj, instanceIndex);
|
|
}
|
|
|
|
/**
|
|
* Unlock the datasource at the specified index.
|
|
* @param instanceIndex The index of the datasource to unlock.
|
|
*/
|
|
protected void releaseDataSourceInstance(int instanceIndex) {
|
|
nativeReleasePerfettoInstanceLocked(mNativeObj, instanceIndex);
|
|
}
|
|
|
|
/**
|
|
* Called from native side when a new tracing instance starts.
|
|
*
|
|
* @param rawConfig byte array of the PerfettoConfig encoded proto.
|
|
* @return A new Java DataSourceInstance object.
|
|
*/
|
|
private DataSourceInstanceType createInstance(byte[] rawConfig, int instanceIndex) {
|
|
final ProtoInputStream inputStream = new ProtoInputStream(rawConfig);
|
|
return this.createInstance(inputStream, instanceIndex);
|
|
}
|
|
|
|
private static native void nativeRegisterDataSource(long dataSourcePtr,
|
|
int bufferExhaustedPolicy, boolean willNotifyOnStop, boolean noFlush);
|
|
|
|
private static native long nativeCreate(DataSource thiz, String name);
|
|
private static native void nativeFlushAll(long nativeDataSourcePointer);
|
|
private static native long nativeGetFinalizer();
|
|
|
|
private static native DataSourceInstance nativeGetPerfettoInstanceLocked(
|
|
long dataSourcePtr, int dsInstanceIdx);
|
|
private static native void nativeReleasePerfettoInstanceLocked(
|
|
long dataSourcePtr, int dsInstanceIdx);
|
|
|
|
private static native boolean nativePerfettoDsTraceIterateBegin(long dataSourcePtr);
|
|
private static native boolean nativePerfettoDsTraceIterateNext(long dataSourcePtr);
|
|
private static native void nativePerfettoDsTraceIterateBreak(long dataSourcePtr);
|
|
private static native int nativeGetPerfettoDsInstanceIndex(long dataSourcePtr);
|
|
|
|
private static native void nativeWritePackets(long dataSourcePtr, byte[][] packetData);
|
|
}
|