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

Commit 3e68a203 authored by Kean Mariotti's avatar Kean Mariotti
Browse files

Revert^2 Integrate transaction tracing with perfetto

Define the perfetto custom data source TransactionDataSource.
TransactionDataSource is registered with perfetto and is used
to listen to perfetto events (setup, start, stop, flush)
and to write trace packets to perfetto.

The user can configure/start/stop tracing via /system/bin/perfetto.

Tracing can operate in the following modes.

ACTIVE mode:
The transactions ring buffer (starting state + following committed
transactions) is written (only once) to perfetto when the 'start'
event is received.
Transactions are then written to perfetto each time they are committed.
On the receiver side, the data source is to be configured to periodically
flush data to disk providing a virtually infinite storage.

CONTINUOUS mode:
Listens to the perfetto 'flush' event (e.g. when a bugreport is taken).
When a 'flush' event is received, the ring buffer (starting state + following
committed transactions) hold by TransactionTracing is written to perfetto.
On the receiver side, the data source is to be configured with a dedicated
buffer large enough to store all the flushed data.

Bug: b/284424784
Test: atest libsurfaceflinger_unittest && atest transactiontrace_testsuite
Change-Id: I703ed53e71f442e2f6af7c4a638d2f847107167a
parent 639b54fb
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -200,6 +200,7 @@ filegroup {
        "SurfaceFlingerDefaultFactory.cpp",
        "Tracing/LayerDataSource.cpp",
        "Tracing/LayerTracing.cpp",
        "Tracing/TransactionDataSource.cpp",
        "Tracing/TransactionTracing.cpp",
        "Tracing/TransactionProtoParser.cpp",
        "Tracing/tools/LayerTraceGenerator.cpp",
+2 −2
Original line number Diff line number Diff line
@@ -6941,7 +6941,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
                        // Transaction tracing is always running but allow the user to temporarily
                        // increase the buffer when actively debugging.
                        mTransactionTracing->setBufferSize(
                                TransactionTracing::ACTIVE_TRACING_BUFFER_SIZE);
                                TransactionTracing::LEGACY_ACTIVE_TRACING_BUFFER_SIZE);
                    } else {
                        TransactionTraceWriter::getInstance().invoke("", /* overwrite= */ true);
                        mTransactionTracing->setBufferSize(
@@ -6951,7 +6951,7 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r
                reply->writeInt32(NO_ERROR);
                return NO_ERROR;
            }
            case 1042: { // Write layers trace or transaction trace to file
            case 1042: { // Write transaction trace to file
                if (mTransactionTracing) {
                    mTransactionTracing->writeToFile();
                }
+82 −0
Original line number Diff line number Diff line
/*
 * Copyright 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.
 */

#include "TransactionDataSource.h"
#include "TransactionTracing.h"

#undef LOG_TAG
#define LOG_TAG "TransactionTracing"

#include <log/log.h>

namespace android {

void TransactionDataSource::Initialize(TransactionTracing& transactionTracing) {
    mTransactionTracing.store(&transactionTracing);

    auto args = perfetto::TracingInitArgs{};
    args.backends = perfetto::kSystemBackend;
    perfetto::Tracing::Initialize(args);

    perfetto::DataSourceDescriptor descriptor;
    descriptor.set_name(kName);
    TransactionDataSource::Register(descriptor);
}

void TransactionDataSource::UnregisterTransactionTracing() {
    mTransactionTracing.store(nullptr);
}

void TransactionDataSource::OnSetup(const TransactionDataSource::SetupArgs& args) {
    const auto configRaw = args.config->surfaceflinger_transactions_config_raw();
    const auto config =
            perfetto::protos::pbzero::SurfaceFlingerTransactionsConfig::Decoder{configRaw};

    if (config.has_mode() && config.mode() != TransactionTracing::Mode::MODE_UNSPECIFIED) {
        mMode = static_cast<TransactionTracing::Mode>(config.mode());
    } else {
        mMode = TransactionTracing::Mode::MODE_CONTINUOUS;
        ALOGV("Received config with unspecified 'mode'. Using 'CONTINUOUS' as default");
    }
}

void TransactionDataSource::OnStart(const StartArgs&) {
    ALOGV("Received OnStart event");
    if (auto* p = mTransactionTracing.load()) {
        p->onStart(mMode);
    }
}

void TransactionDataSource::OnFlush(const FlushArgs&) {
    ALOGV("Received OnFlush event");
    if (auto* p = mTransactionTracing.load()) {
        p->onFlush(mMode);
    }
}

void TransactionDataSource::OnStop(const StopArgs&) {
    ALOGV("Received OnStop event");
}

TransactionTracing::Mode TransactionDataSource::GetMode() const {
    return mMode;
}

std::atomic<TransactionTracing*> TransactionDataSource::mTransactionTracing = nullptr;

} // namespace android

PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::TransactionDataSource);
+74 −0
Original line number Diff line number Diff line
/*
 * Copyright 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.
 */

#pragma once

#include "TransactionTracing.h"

#include <perfetto/tracing.h>

namespace android {

/*
 * Thread local storage used for fast (lock free) read of data source's properties.
 *
 */
struct TransactionDataSourceTlsState {
    template <typename TraceContext>
    explicit TransactionDataSourceTlsState(const TraceContext& trace_context) {
        auto dataSource = trace_context.GetDataSourceLocked();
        mMode = dataSource.valid() ? dataSource->GetMode()
                                   : TransactionTracing::Mode::MODE_CONTINUOUS;
    }

    TransactionTracing::Mode mMode;
};

struct TransactionDataSourceTraits : public perfetto::DefaultDataSourceTraits {
    using TlsStateType = TransactionDataSourceTlsState;
};

/*
 * Defines the Perfetto custom data source 'android.surfaceflinger.transactions'.
 *
 * Registers the data source with Perfetto, listens to Perfetto events (setup/start/flush/stop)
 * and writes trace packets to Perfetto.
 *
 */
class TransactionDataSource
      : public perfetto::DataSource<TransactionDataSource, TransactionDataSourceTraits> {
public:
    static void Initialize(TransactionTracing&);
    static void UnregisterTransactionTracing();
    void OnSetup(const SetupArgs&) override;
    void OnStart(const StartArgs&) override;
    void OnFlush(const FlushArgs&) override;
    void OnStop(const StopArgs&) override;
    TransactionTracing::Mode GetMode() const;

    static constexpr auto* kName = "android.surfaceflinger.transactions";
    static constexpr perfetto::BufferExhaustedPolicy kBufferExhaustedPolicy =
            perfetto::BufferExhaustedPolicy::kStall;
    static constexpr bool kRequiresCallbacksUnderLock = false;

private:
    static std::atomic<TransactionTracing*> mTransactionTracing;
    TransactionTracing::Mode mMode;
};

} // namespace android

PERFETTO_DECLARE_DATA_SOURCE_STATIC_MEMBERS(android::TransactionDataSource);
+1 −19
Original line number Diff line number Diff line
@@ -47,7 +47,7 @@ public:
        mUsedInBytes = 0U;
    }

    void writeToProto(FileProto& fileProto) {
    void writeToProto(FileProto& fileProto) const {
        fileProto.mutable_entry()->Reserve(static_cast<int>(mStorage.size()) +
                                           fileProto.entry().size());
        for (const std::string& entry : mStorage) {
@@ -56,24 +56,6 @@ public:
        }
    }

    status_t writeToFile(FileProto& fileProto, std::string filename) {
        ATRACE_CALL();
        writeToProto(fileProto);
        std::string output;
        if (!fileProto.SerializeToString(&output)) {
            ALOGE("Could not serialize proto.");
            return UNKNOWN_ERROR;
        }

        // -rw-r--r--
        const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
        if (!android::base::WriteStringToFile(output, filename, mode, getuid(), getgid(), true)) {
            ALOGE("Could not save the proto file %s", filename.c_str());
            return PERMISSION_DENIED;
        }
        return NO_ERROR;
    }

    status_t appendToStream(FileProto& fileProto, std::ofstream& out) {
        ATRACE_CALL();
        writeToProto(fileProto);
Loading