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

Commit 2a6ba16e authored by Kean Mariotti's avatar Kean Mariotti Committed by Android (Google) Code Review
Browse files

Merge changes from topic "sf-perfetto-bugreport-integration" into main

* changes:
  Adapt dumpstate to perfetto-based SurfaceFlinger tracing
  Add layer tracing's MODE_GENERATED_BUGREPORT_ONLY
parents 5791961d 853b73a7
Loading
Loading
Loading
Loading
+31 −54
Original line number Diff line number Diff line
@@ -1089,8 +1089,14 @@ static void MaybeAddSystemTraceToZip() {
    // This function copies into the .zip the system trace that was snapshotted
    // by the early call to MaybeSnapshotSystemTrace(), if any background
    // tracing was happening.
    if (!ds.has_system_trace_) {
        // No background trace was happening at the time dumpstate was invoked.
    bool system_trace_exists = access(SYSTEM_TRACE_SNAPSHOT, F_OK) == 0;
    if (!system_trace_exists) {
        // No background trace was happening at the time MaybeSnapshotSystemTrace() was invoked.
        if (!PropertiesHelper::IsUserBuild()) {
            MYLOGI(
                "No system traces found. Check for previously uploaded traces by looking for "
                "go/trace-uuid in logcat")
        }
        return;
    }
    ds.AddZipEntry(
@@ -1650,8 +1656,6 @@ Dumpstate::RunStatus Dumpstate::dumpstate() {
        dump_board = ds.dump_pool_->enqueueTaskWithFd(
            DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1);
        dump_checkins = ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1);
        post_process_ui_traces = ds.dump_pool_->enqueueTask(
            POST_PROCESS_UI_TRACES_TASK, &Dumpstate::MaybePostProcessUiTraces, &ds);
    }

    // Dump various things. Note that anything that takes "long" (i.e. several seconds) should
@@ -1861,12 +1865,6 @@ Dumpstate::RunStatus Dumpstate::dumpstate() {
                DumpIncidentReport);
    }

    if (ds.dump_pool_) {
        WaitForTask(std::move(post_process_ui_traces));
    } else {
        RUN_SLOW_FUNCTION_AND_LOG(POST_PROCESS_UI_TRACES_TASK, MaybePostProcessUiTraces);
    }

    MaybeAddUiTracesToZip();

    return Dumpstate::RunStatus::OK;
@@ -3078,6 +3076,7 @@ void Dumpstate::Cancel() {
}

void Dumpstate::PreDumpUiData() {
    MaybeSnapshotSystemTrace();
    MaybeSnapshotUiTraces();
}

@@ -3264,25 +3263,23 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid,
    // duration is logged into MYLOG instead.
    PrintHeader();

    bool is_dumpstate_restricted = options_->telephony_only
                                   || options_->wifi_only
                                   || options_->limited_only;
    if (!is_dumpstate_restricted) {
        // Invoke critical dumpsys first to preserve system state, before doing anything else.
        RunDumpsysCritical();
    }
    MaybeTakeEarlyScreenshot();

    bool is_dumpstate_restricted =
        options_->telephony_only || options_->wifi_only || options_->limited_only;
    if (!is_dumpstate_restricted) {
        // Snapshot the system trace now (if running) to avoid that dumpstate's
        // own activity pushes out interesting data from the trace ring buffer.
        // The trace file is added to the zip by MaybeAddSystemTraceToZip().
        MaybeSnapshotSystemTrace();

        // Invoke critical dumpsys to preserve system state, before doing anything else.
        RunDumpsysCritical();

        // Snapshot the UI traces now (if running).
        // The trace files will be added to bugreport later.
        MaybeSnapshotUiTraces();
    }

    MaybeTakeEarlyScreenshot();
    onUiIntensiveBugreportDumpsFinished(calling_uid);
    MaybeCheckUserConsent(calling_uid, calling_package);
    if (options_->telephony_only) {
@@ -3379,6 +3376,19 @@ void Dumpstate::MaybeTakeEarlyScreenshot() {
}

void Dumpstate::MaybeSnapshotSystemTrace() {
    // When capturing traces via bugreport handler (BH), this function will be invoked twice:
    // 1) When BH invokes IDumpstate::PreDumpUiData()
    // 2) When BH invokes IDumpstate::startBugreport(flags = BUGREPORT_USE_PREDUMPED_UI_DATA)
    // In this case we don't want to re-invoke perfetto in step 2.
    // In all other standard invocation states, this function is invoked once
    // without the flag BUGREPORT_USE_PREDUMPED_UI_DATA.
    if (options_->use_predumped_ui_data) {
        return;
    }

    // If a stale file exists already, remove it.
    unlink(SYSTEM_TRACE_SNAPSHOT);

    // If a background system trace is happening and is marked as "suitable for
    // bugreport" (i.e. bugreport_score > 0 in the trace config), this command
    // will stop it and serialize into SYSTEM_TRACE_SNAPSHOT. In the (likely)
@@ -3386,14 +3396,8 @@ void Dumpstate::MaybeSnapshotSystemTrace() {
    // Note: this should not be enqueued as we need to freeze the trace before
    // dumpstate starts. Otherwise the trace ring buffers will contain mostly
    // the dumpstate's own activity which is irrelevant.
    int res = RunCommand(
        "SERIALIZE PERFETTO TRACE",
        {"perfetto", "--save-for-bugreport"},
        CommandOptions::WithTimeout(10)
            .DropRoot()
            .CloseAllFileDescriptorsOnExec()
            .Build());
    has_system_trace_ = res == 0;
    RunCommand("SERIALIZE PERFETTO TRACE", {"perfetto", "--save-for-bugreport"},
               CommandOptions::WithTimeout(10).DropRoot().CloseAllFileDescriptorsOnExec().Build());
    // MaybeAddSystemTraceToZip() will take care of copying the trace in the zip
    // file in the later stages.
}
@@ -3420,33 +3424,6 @@ void Dumpstate::MaybeSnapshotUiTraces() {
            "", command,
            CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build());
    }

    // This command needs to be run as root
    static const auto SURFACEFLINGER_COMMAND_SAVE_ALL_TRACES = std::vector<std::string> {
        "service", "call", "SurfaceFlinger", "1042"
    };
    // Empty name because it's not intended to be classified as a bugreport section.
    // Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport.
    RunCommand(
        "", SURFACEFLINGER_COMMAND_SAVE_ALL_TRACES,
        CommandOptions::WithTimeout(10).Always().AsRoot().RedirectStderr().Build());
}

void Dumpstate::MaybePostProcessUiTraces() {
    if (PropertiesHelper::IsUserBuild()) {
        return;
    }

    RunCommand(
        // Empty name because it's not intended to be classified as a bugreport section.
        // Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport.
        "", {
            "/system/xbin/su", "system",
            "/system/bin/layertracegenerator",
            "/data/misc/wmtrace/transactions_trace.winscope",
            "/data/misc/wmtrace/layers_trace_from_transactions.winscope"
        },
        CommandOptions::WithTimeout(120).Always().RedirectStderr().Build());
}

void Dumpstate::MaybeAddUiTracesToZip() {
+0 −6
Original line number Diff line number Diff line
@@ -476,11 +476,6 @@ class Dumpstate {
    // Whether it should take an screenshot earlier in the process.
    bool do_early_screenshot_ = false;

    // This is set to true when the trace snapshot request in the early call to
    // MaybeSnapshotSystemTrace(). When this is true, the later stages of
    // dumpstate will append the trace to the zip archive.
    bool has_system_trace_ = false;

    std::unique_ptr<Progress> progress_;

    // When set, defines a socket file-descriptor use to report progress to bugreportz
@@ -574,7 +569,6 @@ class Dumpstate {
    void MaybeTakeEarlyScreenshot();
    void MaybeSnapshotSystemTrace();
    void MaybeSnapshotUiTraces();
    void MaybePostProcessUiTraces();
    void MaybeAddUiTracesToZip();

    void onUiIntensiveBugreportDumpsFinished(int32_t calling_uid);
+0 −1
Original line number Diff line number Diff line
@@ -1000,7 +1000,6 @@ TEST_F(DumpstateTest, DumpPool_withParallelRunDisabled_isNull) {
TEST_F(DumpstateTest, PreDumpUiData) {
    // These traces are always enabled, i.e. they are always pre-dumped
    const std::vector<std::filesystem::path> uiTraces = {
        std::filesystem::path{"/data/misc/wmtrace/transactions_trace.winscope"},
        std::filesystem::path{"/data/misc/wmtrace/wm_transition_trace.winscope"},
        std::filesystem::path{"/data/misc/wmtrace/shell_transition_trace.winscope"},
    };
+12 −5
Original line number Diff line number Diff line
@@ -51,8 +51,9 @@ void LayerDataSource::OnSetup(const LayerDataSource::SetupArgs& args) {
    if (config.has_mode() && config.mode() != LayerTracing::Mode::MODE_UNSPECIFIED) {
        mMode = static_cast<LayerTracing::Mode>(config.mode());
    } else {
        mMode = LayerTracing::Mode::MODE_GENERATED;
        ALOGD("Received config with unspecified 'mode'. Using 'GENERATED' as default");
        mMode = LayerTracing::Mode::MODE_GENERATED_BUGREPORT_ONLY;
        ALOGD("Received config with unspecified 'mode'."
              " Using 'MODE_GENERATED_BUGREPORT_ONLY' as default");
    }

    mFlags = 0;
@@ -68,10 +69,16 @@ void LayerDataSource::OnStart(const LayerDataSource::StartArgs&) {
    }
}

void LayerDataSource::OnFlush(const LayerDataSource::FlushArgs&) {
    ALOGD("Received OnFlush event (mode = 0x%02x, flags = 0x%02x)", mMode, mFlags);
void LayerDataSource::OnFlush(const LayerDataSource::FlushArgs& args) {
    ALOGD("Received OnFlush event"
          " (mode = 0x%02x, flags = 0x%02x, reason = 0x%" PRIx64 ", clone_target = 0x%0" PRIx64 ")",
          mMode, mFlags, args.flush_flags.reason(), args.flush_flags.clone_target());

    bool isBugreport = args.flush_flags.reason() == perfetto::FlushFlags::Reason::kTraceClone &&
            args.flush_flags.clone_target() == perfetto::FlushFlags::CloneTarget::kBugreport;

    if (auto* p = mLayerTracing.load()) {
        p->onFlush(mMode, mFlags);
        p->onFlush(mMode, mFlags, isBugreport);
    }
}

+42 −7
Original line number Diff line number Diff line
@@ -67,9 +67,27 @@ void LayerTracing::onStart(Mode mode, uint32_t flags) {
            break;
        }
        case Mode::MODE_GENERATED: {
            // This tracing mode processes the buffer of transactions (owned by TransactionTracing),
            // generates layers snapshots and writes them to perfetto. This happens every time an
            // OnFlush event is received.
            ALOGD("Started generated tracing (waiting for OnFlush event to generated layers)");
            break;
        }
        case Mode::MODE_GENERATED_BUGREPORT_ONLY: {
            // Same as MODE_GENERATED, but only when the received OnFlush event is due to a
            // bugreport being taken. This mode exists because the generated layers trace is very
            // large (hundreds of MB), hence we want to include it only in bugreports and not in
            // field uploads.
            //
            // Note that perfetto communicates only whether the OnFlush event is due to a bugreport
            // or not, hence we need an additional "bugreport only" tracing mode.
            // If perfetto had communicated when the OnFlush is due to a field upload, then we could
            // have had a single "generated" tracing mode that would have been a noop in case of
            // field uploads.
            ALOGD("Started 'generated bugreport only' tracing"
                  " (waiting for bugreport's OnFlush event to generate layers)");
            break;
        }
        case Mode::MODE_DUMP: {
            auto snapshot = mTakeLayersSnapshotProto(flags);
            addProtoSnapshotToOstream(std::move(snapshot), Mode::MODE_DUMP);
@@ -82,10 +100,18 @@ void LayerTracing::onStart(Mode mode, uint32_t flags) {
    }
}

void LayerTracing::onFlush(Mode mode, uint32_t flags) {
void LayerTracing::onFlush(Mode mode, uint32_t flags, bool isBugreport) {
    // In "generated" mode process the buffer of transactions (owned by TransactionTracing),
    // generate a sequence of layers snapshots and write them to perfetto.
    if (mode != Mode::MODE_GENERATED) {
    // generate layers snapshots and write them to perfetto.
    if (mode != Mode::MODE_GENERATED && mode != Mode::MODE_GENERATED_BUGREPORT_ONLY) {
        ALOGD("Skipping layers trace generation (not a 'generated' tracing session)");
        return;
    }

    // In "generated bugreport only" mode skip the layers snapshot generation
    // if the perfetto's OnFlush event is not due to a bugreport being taken.
    if (mode == Mode::MODE_GENERATED_BUGREPORT_ONLY && !isBugreport) {
        ALOGD("Skipping layers trace generation (not a bugreport OnFlush event)");
        return;
    }

@@ -147,14 +173,23 @@ void LayerTracing::writeSnapshotToStream(perfetto::protos::LayersSnapshotProto&&
}

void LayerTracing::writeSnapshotToPerfetto(const perfetto::protos::LayersSnapshotProto& snapshot,
                                           Mode mode) {
                                           Mode srcMode) {
    const auto snapshotBytes = snapshot.SerializeAsString();

    LayerDataSource::Trace([&](LayerDataSource::TraceContext context) {
        if (mode != context.GetCustomTlsState()->mMode) {
        auto dstMode = context.GetCustomTlsState()->mMode;
        if (srcMode == Mode::MODE_GENERATED) {
            // Layers snapshots produced by LayerTraceGenerator have srcMode == MODE_GENERATED
            // and should be written to tracing sessions with MODE_GENERATED
            // or MODE_GENERATED_BUGREPORT_ONLY.
            if (dstMode != Mode::MODE_GENERATED && dstMode != Mode::MODE_GENERATED_BUGREPORT_ONLY) {
                return;
            }
        } else if (srcMode != dstMode) {
            return;
        }
        if (!checkAndUpdateLastVsyncIdWrittenToPerfetto(mode, snapshot.vsync_id())) {

        if (!checkAndUpdateLastVsyncIdWrittenToPerfetto(srcMode, snapshot.vsync_id())) {
            return;
        }
        {
@@ -176,7 +211,7 @@ bool LayerTracing::checkAndUpdateLastVsyncIdWrittenToPerfetto(Mode mode, std::in
    // In some situations (e.g. two bugreports taken shortly one after the other) the generated
    // sequence of layers snapshots might overlap. Here we check the snapshot's vsyncid to make
    // sure that in generated tracing mode a given snapshot is written only once to perfetto.
    if (mode != Mode::MODE_GENERATED) {
    if (mode != Mode::MODE_GENERATED && mode != Mode::MODE_GENERATED_BUGREPORT_ONLY) {
        return true;
    }

Loading