Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 102daa4f authored by Pablo Gamito's avatar Pablo Gamito
Browse files

Update Perfetto API used by Java side

Use the more programmatic approach to tracing. The loop is started and controlled by the Java side. We get rid of the callback back to the Java side doing this and all calls are now one way from the Java side to the native, except for the callbacks to create the incremental and TLS states.

Bug: 326541928
Change-Id: I8b71baec334ff0336aaff0b2b472debec35f3c8a
parent fc05d49c
Loading
Loading
Loading
Loading
+22 −5
Original line number Diff line number Diff line
@@ -71,9 +71,24 @@ public abstract class DataSource<DataSourceInstanceType extends DataSourceInstan
     * @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) {
        nativeTrace(mNativeObj, fun);
    public final void trace(TraceFunction<TlsStateType, IncrementalStateType> fun) {
        boolean startedIterator = nativePerfettoDsTraceIterateBegin(mNativeObj);

        if (!startedIterator) {
            return;
        }

        try {
            do {
                TracingContext<TlsStateType, IncrementalStateType> ctx =
                        new TracingContext<>(mNativeObj);
                fun.trace(ctx);

                ctx.flush();
            } while (nativePerfettoDsTraceIterateNext(mNativeObj));
        } finally {
            nativePerfettoDsTraceIterateBreak(mNativeObj);
        }
    }

    /**
@@ -154,8 +169,6 @@ public abstract class DataSource<DataSourceInstanceType extends DataSourceInstan
            long dataSourcePtr, int bufferExhaustedPolicy);

    private static native long nativeCreate(DataSource thiz, String name);
    private static native void nativeTrace(
            long nativeDataSourcePointer, TraceFunction traceFunction);
    private static native void nativeFlushAll(long nativeDataSourcePointer);
    private static native long nativeGetFinalizer();

@@ -163,4 +176,8 @@ public abstract class DataSource<DataSourceInstanceType extends DataSourceInstan
            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);
}
+2 −4
Original line number Diff line number Diff line
@@ -21,14 +21,12 @@ import java.io.IOException;
/**
 * The interface for the trace function called from native on a trace call with a context.
 *
 * @param <DataSourceInstanceType> The type of DataSource this tracing context is for.
 * @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 interface TraceFunction<DataSourceInstanceType extends DataSourceInstance,
        TlsStateType, IncrementalStateType> {
public interface TraceFunction<TlsStateType, IncrementalStateType> {

    /**
     * This function will be called synchronously (i.e., always before trace() returns) only if
@@ -38,6 +36,6 @@ public interface TraceFunction<DataSourceInstanceType extends DataSourceInstance
     *
     * @param ctx the tracing context to trace for in the trace function.
     */
    void trace(TracingContext<DataSourceInstanceType, TlsStateType, IncrementalStateType> ctx)
    void trace(TracingContext<TlsStateType, IncrementalStateType> ctx)
            throws IOException;
}
+10 −17
Original line number Diff line number Diff line
@@ -24,26 +24,18 @@ import java.util.List;
/**
 * Argument passed to the lambda function passed to Trace().
 *
 * @param <DataSourceInstanceType> The type of the datasource this tracing context is for.
 * @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 class TracingContext<DataSourceInstanceType extends DataSourceInstance,
        TlsStateType, IncrementalStateType> {
public class TracingContext<TlsStateType, IncrementalStateType> {

    private final long mContextPtr;
    private final TlsStateType mTlsState;
    private final IncrementalStateType mIncrementalState;
    private final long mNativeDsPtr;
    private final List<ProtoOutputStream> mTracePackets = new ArrayList<>();

    // Should only be created from the native side.
    private TracingContext(long contextPtr, TlsStateType tlsState,
            IncrementalStateType incrementalState) {
        this.mContextPtr = contextPtr;
        this.mTlsState = tlsState;
        this.mIncrementalState = incrementalState;
    TracingContext(long nativeDsPtr) {
        this.mNativeDsPtr = nativeDsPtr;
    }

    /**
@@ -69,7 +61,7 @@ public class TracingContext<DataSourceInstanceType extends DataSourceInstance,
     * Stop timeout expires.
     */
    public void flush() {
        nativeFlush(this, mContextPtr);
        nativeFlush(mNativeDsPtr, getAndClearAllPendingTracePackets());
    }

    /**
@@ -80,7 +72,7 @@ public class TracingContext<DataSourceInstanceType extends DataSourceInstance,
     * @return The TlsState instance for the tracing thread and instance.
     */
    public TlsStateType getCustomTlsState() {
        return this.mTlsState;
        return (TlsStateType) nativeGetCustomTls(mNativeDsPtr);
    }

    /**
@@ -90,10 +82,9 @@ public class TracingContext<DataSourceInstanceType extends DataSourceInstance,
     * @return The current IncrementalState object instance.
     */
    public IncrementalStateType getIncrementalState() {
        return this.mIncrementalState;
        return (IncrementalStateType) nativeGetIncrementalState(mNativeDsPtr);
    }

    // Called from native to get trace packets
    private byte[][] getAndClearAllPendingTracePackets() {
        byte[][] res = new byte[mTracePackets.size()][];
        for (int i = 0; i < mTracePackets.size(); i++) {
@@ -105,5 +96,7 @@ public class TracingContext<DataSourceInstanceType extends DataSourceInstance,
        return res;
    }

    private static native void nativeFlush(TracingContext thiz, long ctxPointer);
    private static native void nativeFlush(long dataSourcePtr, byte[][] packetData);
    private static native Object nativeGetCustomTls(long nativeDsPtr);
    private static native Object nativeGetIncrementalState(long nativeDsPtr);
}
+3 −7
Original line number Diff line number Diff line
@@ -423,7 +423,7 @@ public class PerfettoProtoLogImpl implements IProtoLog {
        return sw.toString();
    }

    private int internStacktraceString(TracingContext<ProtoLogDataSource.Instance,
    private int internStacktraceString(TracingContext<
            ProtoLogDataSource.TlsState,
            ProtoLogDataSource.IncrementalState> ctx,
            String stacktrace) {
@@ -433,9 +433,7 @@ public class PerfettoProtoLogImpl implements IProtoLog {
    }

    private int internStringArg(
            TracingContext<ProtoLogDataSource.Instance,
            ProtoLogDataSource.TlsState,
            ProtoLogDataSource.IncrementalState> ctx,
            TracingContext<ProtoLogDataSource.TlsState, ProtoLogDataSource.IncrementalState> ctx,
            String string
    ) {
        final ProtoLogDataSource.IncrementalState incrementalState = ctx.getIncrementalState();
@@ -444,9 +442,7 @@ public class PerfettoProtoLogImpl implements IProtoLog {
    }

    private int internString(
            TracingContext<ProtoLogDataSource.Instance,
                ProtoLogDataSource.TlsState,
                ProtoLogDataSource.IncrementalState> ctx,
            TracingContext<ProtoLogDataSource.TlsState, ProtoLogDataSource.IncrementalState> ctx,
            Map<String, Integer> internMap,
            long fieldId,
            String string
+116 −86
Original line number Diff line number Diff line
@@ -42,12 +42,6 @@ static struct {
    jmethodID createIncrementalState;
} gPerfettoDataSourceClassInfo;

static struct {
    jclass clazz;
    jmethodID init;
    jmethodID getAndClearAllPendingTracePackets;
} gTracingContextClassInfo;

static struct {
    jclass clazz;
    jmethodID init;
@@ -68,32 +62,10 @@ struct IncrementalState {
    jobject jobj;
};

static void traceAllPendingPackets(JNIEnv* env, jobject jCtx, PerfettoDsTracerIterator* ctx) {
    jobjectArray packets =
            (jobjectArray)env
                    ->CallObjectMethod(jCtx,
                                       gTracingContextClassInfo.getAndClearAllPendingTracePackets);
    if (env->ExceptionOccurred()) {
        env->ExceptionDescribe();
        env->ExceptionClear();

        LOG_ALWAYS_FATAL("Failed to call java context finalize method");
    }

    int packets_count = env->GetArrayLength(packets);
    for (int i = 0; i < packets_count; i++) {
        jbyteArray packet_proto_buffer = (jbyteArray)env->GetObjectArrayElement(packets, i);

        jbyte* raw_proto_buffer = env->GetByteArrayElements(packet_proto_buffer, 0);
        int buffer_size = env->GetArrayLength(packet_proto_buffer);

        struct PerfettoDsRootTracePacket trace_packet;
        PerfettoDsTracerPacketBegin(ctx, &trace_packet);
        PerfettoPbMsgAppendBytes(&trace_packet.msg.msg, (const uint8_t*)raw_proto_buffer,
                                 buffer_size);
        PerfettoDsTracerPacketEnd(ctx, &trace_packet);
    }
}
// In a single thread there can be only one trace point active across all data source, so we can use
// a single global thread_local variable to keep track of the active tracer iterator.
thread_local static bool gInIteration;
thread_local static struct PerfettoDsTracerIterator gIterator;

PerfettoDataSource::PerfettoDataSource(JNIEnv* env, jobject javaDataSource,
                                       std::string dataSourceName)
@@ -164,44 +136,89 @@ jobject PerfettoDataSource::createIncrementalStateGlobalRef(JNIEnv* env,
    return env->NewGlobalRef(incrementalState.get());
}

void PerfettoDataSource::trace(JNIEnv* env, jobject traceFunction) {
    PERFETTO_DS_TRACE(dataSource, ctx) {
        ALOG(LOG_DEBUG, LOG_TAG, "\tin native trace callback function %p", this);
        TlsState* tls_state =
                reinterpret_cast<TlsState*>(PerfettoDsGetCustomTls(&dataSource, &ctx));
        IncrementalState* incr_state = reinterpret_cast<IncrementalState*>(
                PerfettoDsGetIncrementalState(&dataSource, &ctx));
bool PerfettoDataSource::TraceIterateBegin() {
    if (gInIteration) {
        return false;
    }

        ALOG(LOG_DEBUG, LOG_TAG, "\t tls_state = %p", tls_state);
        ALOG(LOG_DEBUG, LOG_TAG, "\t incr_state = %p", incr_state);
    gIterator = PerfettoDsTraceIterateBegin(&dataSource);

    if (gIterator.impl.tracer == nullptr) {
        return false;
    }

        ALOG(LOG_DEBUG, LOG_TAG, "\t tls_state->jobj = %p", tls_state->jobj);
        ALOG(LOG_DEBUG, LOG_TAG, "\t incr_state->jobj = %p", incr_state->jobj);
    gInIteration = true;
    return true;
}

        ScopedLocalRef<jobject> jCtx(env,
                                     env->NewObject(gTracingContextClassInfo.clazz,
                                                    gTracingContextClassInfo.init, &ctx,
                                                    tls_state->jobj, incr_state->jobj));
bool PerfettoDataSource::TraceIterateNext() {
    if (!gInIteration) {
        LOG_ALWAYS_FATAL("Tried calling TraceIterateNext outside of a tracer iteration.");
        return false;
    }

        ALOG(LOG_DEBUG, LOG_TAG, "\t jCtx = %p", jCtx.get());
    PerfettoDsTraceIterateNext(&dataSource, &gIterator);

        jclass objclass = env->GetObjectClass(traceFunction);
        jmethodID method =
                env->GetMethodID(objclass, "trace", "(Landroid/tracing/perfetto/TracingContext;)V");
        if (method == 0) {
            LOG_ALWAYS_FATAL("Failed to get method id");
    if (gIterator.impl.tracer == nullptr) {
        // Reached end of iterator. No more datasource instances.
        gInIteration = false;
        return false;
    }

        env->ExceptionClear();
    return true;
}

        env->CallVoidMethod(traceFunction, method, jCtx.get());
        if (env->ExceptionOccurred()) {
            env->ExceptionDescribe();
            env->ExceptionClear();
            LOG_ALWAYS_FATAL("Failed to call java trace method");
void PerfettoDataSource::TraceIterateBreak() {
    if (!gInIteration) {
        return;
    }

        traceAllPendingPackets(env, jCtx.get(), &ctx);
    PerfettoDsTraceIterateBreak(&dataSource, &gIterator);
    gInIteration = false;
}

jobject PerfettoDataSource::GetCustomTls() {
    if (!gInIteration) {
        LOG_ALWAYS_FATAL("Tried getting CustomTls outside of a tracer iteration.");
        return nullptr;
    }

    TlsState* tls_state =
            reinterpret_cast<TlsState*>(PerfettoDsGetCustomTls(&dataSource, &gIterator));

    return tls_state->jobj;
}

jobject PerfettoDataSource::GetIncrementalState() {
    if (!gInIteration) {
        LOG_ALWAYS_FATAL("Tried getting IncrementalState outside of a tracer iteration.");
        return nullptr;
    }

    IncrementalState* incr_state = reinterpret_cast<IncrementalState*>(
            PerfettoDsGetIncrementalState(&dataSource, &gIterator));

    return incr_state->jobj;
}

void PerfettoDataSource::WritePackets(JNIEnv* env, jobjectArray packets) {
    if (!gInIteration) {
        LOG_ALWAYS_FATAL("Tried writing packets outside of a tracer iteration.");
        return;
    }

    int packets_count = env->GetArrayLength(packets);
    for (int i = 0; i < packets_count; i++) {
        jbyteArray packet_proto_buffer = (jbyteArray)env->GetObjectArrayElement(packets, i);

        jbyte* raw_proto_buffer = env->GetByteArrayElements(packet_proto_buffer, 0);
        int buffer_size = env->GetArrayLength(packet_proto_buffer);

        struct PerfettoDsRootTracePacket trace_packet;
        PerfettoDsTracerPacketBegin(&gIterator, &trace_packet);
        PerfettoPbMsgAppendBytes(&trace_packet.msg.msg, (const uint8_t*)raw_proto_buffer,
                                 buffer_size);
        PerfettoDsTracerPacketEnd(&gIterator, &trace_packet);
    }
}

@@ -229,7 +246,7 @@ jlong nativeCreate(JNIEnv* env, jclass clazz, jobject javaDataSource, jstring na
}

void nativeDestroy(void* ptr) {
    ALOG(LOG_DEBUG, LOG_TAG, "nativeCreate(%p)", ptr);
    ALOG(LOG_DEBUG, LOG_TAG, "nativeDestroy(%p)", ptr);
    PerfettoDataSource* dataSource = reinterpret_cast<PerfettoDataSource*>(ptr);
    dataSource->decStrong((void*)nativeCreate);
}
@@ -239,18 +256,10 @@ static jlong nativeGetFinalizer(JNIEnv* /* env */, jclass /* clazz */) {
    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&nativeDestroy));
}

void nativeTrace(JNIEnv* env, jclass clazz, jlong dataSourcePtr, jobject traceFunctionInterface) {
    ALOG(LOG_DEBUG, LOG_TAG, "nativeTrace(%p)", (void*)dataSourcePtr);
    sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);

    datasource->trace(env, traceFunctionInterface);
}

void nativeFlush(JNIEnv* env, jclass clazz, jobject jCtx, jlong ctxPtr) {
    ALOG(LOG_DEBUG, LOG_TAG, "nativeFlush(%p, %p)", jCtx, (void*)ctxPtr);
    auto* ctx = reinterpret_cast<struct PerfettoDsTracerIterator*>(ctxPtr);
    traceAllPendingPackets(env, jCtx, ctx);
    PerfettoDsTracerFlush(ctx, nullptr, nullptr);
void nativeFlush(JNIEnv* env, jclass clazz, jlong ds_ptr, jobjectArray packets) {
    ALOG(LOG_DEBUG, LOG_TAG, "nativeFlush(%p)", (void*)ds_ptr);
    sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(ds_ptr);
    datasource->WritePackets(env, packets);
}

void nativeFlushAll(JNIEnv* env, jclass clazz, jlong ptr) {
@@ -414,11 +423,35 @@ void nativeReleasePerfettoInstanceLocked(JNIEnv* env, jclass clazz, jlong dataSo
    PerfettoDsImplReleaseInstanceLocked(datasource->dataSource.impl, instance_idx);
}

bool nativePerfettoDsTraceIterateBegin(JNIEnv* env, jclass clazz, jlong dataSourcePtr) {
    sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
    return datasource->TraceIterateBegin();
}

bool nativePerfettoDsTraceIterateNext(JNIEnv* env, jclass clazz, jlong dataSourcePtr) {
    sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
    return datasource->TraceIterateNext();
}

void nativePerfettoDsTraceIterateBreak(JNIEnv* env, jclass clazz, jlong dataSourcePtr) {
    sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
    return datasource->TraceIterateBreak();
}

jobject nativeGetCustomTls(JNIEnv* env, jclass clazz, jlong dataSourcePtr) {
    sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
    return datasource->GetCustomTls();
}

jobject nativeGetIncrementalState(JNIEnv* env, jclass clazz, jlong dataSourcePtr) {
    sp<PerfettoDataSource> datasource = reinterpret_cast<PerfettoDataSource*>(dataSourcePtr);
    return datasource->GetIncrementalState();
}

const JNINativeMethod gMethods[] = {
        /* name, signature, funcPtr */
        {"nativeCreate", "(Landroid/tracing/perfetto/DataSource;Ljava/lang/String;)J",
         (void*)nativeCreate},
        {"nativeTrace", "(JLandroid/tracing/perfetto/TraceFunction;)V", (void*)nativeTrace},
        {"nativeFlushAll", "(J)V", (void*)nativeFlushAll},
        {"nativeGetFinalizer", "()J", (void*)nativeGetFinalizer},
        {"nativeRegisterDataSource", "(JI)V", (void*)nativeRegisterDataSource},
@@ -426,11 +459,16 @@ const JNINativeMethod gMethods[] = {
         (void*)nativeGetPerfettoInstanceLocked},
        {"nativeReleasePerfettoInstanceLocked", "(JI)V",
         (void*)nativeReleasePerfettoInstanceLocked},
};

        {"nativePerfettoDsTraceIterateBegin", "(J)Z", (void*)nativePerfettoDsTraceIterateBegin},
        {"nativePerfettoDsTraceIterateNext", "(J)Z", (void*)nativePerfettoDsTraceIterateNext},
        {"nativePerfettoDsTraceIterateBreak", "(J)V", (void*)nativePerfettoDsTraceIterateBreak}};

const JNINativeMethod gMethodsTracingContext[] = {
        /* name, signature, funcPtr */
        {"nativeFlush", "(Landroid/tracing/perfetto/TracingContext;J)V", (void*)nativeFlush},
        {"nativeFlush", "(J[[B)V", (void*)nativeFlush},
        {"nativeGetCustomTls", "(J)Ljava/lang/Object;", (void*)nativeGetCustomTls},
        {"nativeGetIncrementalState", "(J)Ljava/lang/Object;", (void*)nativeGetIncrementalState},
};

int register_android_tracing_PerfettoDataSource(JNIEnv* env) {
@@ -461,14 +499,6 @@ int register_android_tracing_PerfettoDataSource(JNIEnv* env) {
                             "(Landroid/tracing/perfetto/CreateIncrementalStateArgs;)Ljava/lang/"
                             "Object;");

    clazz = env->FindClass("android/tracing/perfetto/TracingContext");
    gTracingContextClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
    gTracingContextClassInfo.init = env->GetMethodID(gTracingContextClassInfo.clazz, "<init>",
                                                     "(JLjava/lang/Object;Ljava/lang/Object;)V");
    gTracingContextClassInfo.getAndClearAllPendingTracePackets =
            env->GetMethodID(gTracingContextClassInfo.clazz, "getAndClearAllPendingTracePackets",
                             "()[[B");

    clazz = env->FindClass("android/tracing/perfetto/CreateTlsStateArgs");
    gCreateTlsStateArgsClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
    gCreateTlsStateArgsClassInfo.init =
Loading