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

Commit 58f19f68 authored by Prabir Pradhan's avatar Prabir Pradhan
Browse files

InputTracer: Read trace configuration from perfetto

Bug: 210460522
Test: manual with perfetto
Change-Id: I5eba37fd2dbf76f92c91504fed403642761cdb1d
parent 4b408beb
Loading
Loading
Loading
Loading
+78 −0
Original line number Diff line number Diff line
@@ -21,6 +21,23 @@

namespace android::inputdispatcher::trace {

namespace {

using namespace ftl::flag_operators;

// The trace config to use for maximal tracing.
const impl::TraceConfig CONFIG_TRACE_ALL{
        .flags = impl::TraceFlag::TRACE_DISPATCHER_INPUT_EVENTS |
                impl::TraceFlag::TRACE_DISPATCHER_WINDOW_DISPATCH,
        .rules = {impl::TraceRule{.level = impl::TraceLevel::TRACE_LEVEL_COMPLETE,
                                  .matchAllPackages = {},
                                  .matchAnyPackages = {},
                                  .matchSecure{},
                                  .matchImeConnectionActive = {}}},
};

} // namespace

void AndroidInputEventProtoConverter::toProtoMotionEvent(const TracedMotionEvent& event,
                                                         proto::AndroidMotionEvent& outProto) {
    outProto.set_event_id(event.id);
@@ -105,4 +122,65 @@ void AndroidInputEventProtoConverter::toProtoWindowDispatchEvent(
    }
}

impl::TraceConfig AndroidInputEventProtoConverter::parseConfig(
        proto::AndroidInputEventConfig::Decoder& protoConfig) {
    if (protoConfig.has_mode() &&
        protoConfig.mode() == proto::AndroidInputEventConfig::TRACE_MODE_TRACE_ALL) {
        // User has requested the preset for maximal tracing
        return CONFIG_TRACE_ALL;
    }

    impl::TraceConfig config;

    // Parse trace flags
    if (protoConfig.has_trace_dispatcher_input_events() &&
        protoConfig.trace_dispatcher_input_events()) {
        config.flags |= impl::TraceFlag::TRACE_DISPATCHER_INPUT_EVENTS;
    }
    if (protoConfig.has_trace_dispatcher_window_dispatch() &&
        protoConfig.trace_dispatcher_window_dispatch()) {
        config.flags |= impl::TraceFlag::TRACE_DISPATCHER_WINDOW_DISPATCH;
    }

    // Parse trace rules
    auto rulesIt = protoConfig.rules();
    while (rulesIt) {
        proto::AndroidInputEventConfig::TraceRule::Decoder protoRule{rulesIt->as_bytes()};
        config.rules.emplace_back();
        auto& rule = config.rules.back();

        rule.level = protoRule.has_trace_level()
                ? static_cast<impl::TraceLevel>(protoRule.trace_level())
                : impl::TraceLevel::TRACE_LEVEL_NONE;

        if (protoRule.has_match_all_packages()) {
            auto pkgIt = protoRule.match_all_packages();
            while (pkgIt) {
                rule.matchAllPackages.emplace_back(pkgIt->as_std_string());
                pkgIt++;
            }
        }

        if (protoRule.has_match_any_packages()) {
            auto pkgIt = protoRule.match_any_packages();
            while (pkgIt) {
                rule.matchAnyPackages.emplace_back(pkgIt->as_std_string());
                pkgIt++;
            }
        }

        if (protoRule.has_match_secure()) {
            rule.matchSecure = protoRule.match_secure();
        }

        if (protoRule.has_match_ime_connection_active()) {
            rule.matchImeConnectionActive = protoRule.match_ime_connection_active();
        }

        rulesIt++;
    }

    return config;
}

} // namespace android::inputdispatcher::trace
+4 −0
Original line number Diff line number Diff line
@@ -16,9 +16,11 @@

#pragma once

#include <perfetto/config/android/android_input_event_config.pbzero.h>
#include <perfetto/trace/android/android_input_event.pbzero.h>

#include "InputTracingBackendInterface.h"
#include "InputTracingPerfettoBackendConfig.h"

namespace proto = perfetto::protos::pbzero;

@@ -34,6 +36,8 @@ public:
    static void toProtoKeyEvent(const TracedKeyEvent& event, proto::AndroidKeyEvent& outProto);
    static void toProtoWindowDispatchEvent(const WindowDispatchArgs&,
                                           proto::AndroidWindowInputDispatchEvent& outProto);

    static impl::TraceConfig parseConfig(proto::AndroidInputEventConfig::Decoder& protoConfig);
};

} // namespace android::inputdispatcher::trace
+19 −4
Original line number Diff line number Diff line
@@ -33,12 +33,25 @@ constexpr auto INPUT_EVENT_TRACE_DATA_SOURCE_NAME = "android.input.inputevent";

// --- PerfettoBackend::InputEventDataSource ---

void PerfettoBackend::InputEventDataSource::OnStart(const perfetto::DataSourceBase::StartArgs&) {
    LOG(INFO) << "Starting perfetto trace for: " << INPUT_EVENT_TRACE_DATA_SOURCE_NAME;
PerfettoBackend::InputEventDataSource::InputEventDataSource() : mInstanceId(sNextInstanceId++) {}

void PerfettoBackend::InputEventDataSource::OnSetup(const InputEventDataSource::SetupArgs& args) {
    LOG(INFO) << "Setting up perfetto trace for: " << INPUT_EVENT_TRACE_DATA_SOURCE_NAME
              << ", instanceId: " << mInstanceId;
    const auto rawConfig = args.config->android_input_event_config_raw();
    auto protoConfig = perfetto::protos::pbzero::AndroidInputEventConfig::Decoder{rawConfig};

    mConfig = AndroidInputEventProtoConverter::parseConfig(protoConfig);
}

void PerfettoBackend::InputEventDataSource::OnStop(const perfetto::DataSourceBase::StopArgs&) {
    LOG(INFO) << "Stopping perfetto trace for: " << INPUT_EVENT_TRACE_DATA_SOURCE_NAME;
void PerfettoBackend::InputEventDataSource::OnStart(const InputEventDataSource::StartArgs&) {
    LOG(INFO) << "Starting perfetto trace for: " << INPUT_EVENT_TRACE_DATA_SOURCE_NAME
              << ", instanceId: " << mInstanceId;
}

void PerfettoBackend::InputEventDataSource::OnStop(const InputEventDataSource::StopArgs&) {
    LOG(INFO) << "Stopping perfetto trace for: " << INPUT_EVENT_TRACE_DATA_SOURCE_NAME
              << ", instanceId: " << mInstanceId;
    InputEventDataSource::Trace([&](InputEventDataSource::TraceContext ctx) { ctx.Flush(); });
}

@@ -46,6 +59,8 @@ void PerfettoBackend::InputEventDataSource::OnStop(const perfetto::DataSourceBas

std::once_flag PerfettoBackend::sDataSourceRegistrationFlag{};

std::atomic<int32_t> PerfettoBackend::sNextInstanceId{1};

PerfettoBackend::PerfettoBackend() {
    // Use a once-flag to ensure that the data source is only registered once per boot, since
    // we never unregister the InputEventDataSource.
+13 −2
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@

#include "InputTracingBackendInterface.h"

#include "InputTracingPerfettoBackendConfig.h"

#include <perfetto/tracing.h>
#include <mutex>

@@ -52,15 +54,24 @@ public:
    void traceMotionEvent(const TracedMotionEvent&, const TracedEventArgs&) override;
    void traceWindowDispatch(const WindowDispatchArgs&, const TracedEventArgs&) override;

private:
    // Implementation of the perfetto data source.
    // Each instance of the InputEventDataSource represents a different tracing session.
    class InputEventDataSource : public perfetto::DataSource<InputEventDataSource> {
    public:
        void OnSetup(const SetupArgs&) override {}
        explicit InputEventDataSource();

        void OnSetup(const SetupArgs&) override;
        void OnStart(const StartArgs&) override;
        void OnStop(const StopArgs&) override;
    };

    private:
        const int32_t mInstanceId;
        TraceConfig mConfig;
    };

    static std::once_flag sDataSourceRegistrationFlag;
    static std::atomic<int32_t> sNextInstanceId;
};

} // namespace android::inputdispatcher::trace::impl
+60 −0
Original line number Diff line number Diff line
/*
 * Copyright 2024 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 <ftl/enum.h>
#include <ftl/flags.h>
#include <perfetto/config/android/android_input_event_config.pbzero.h>
#include <vector>

namespace android::inputdispatcher::trace::impl {

/** Flags representing the configurations that are enabled in the trace. */
enum class TraceFlag : uint32_t {
    // Trace details about input events processed by InputDispatcher.
    TRACE_DISPATCHER_INPUT_EVENTS = 0x1,
    // Trace details about an event being sent to a window by InputDispatcher.
    TRACE_DISPATCHER_WINDOW_DISPATCH = 0x2,

    ftl_last = TRACE_DISPATCHER_WINDOW_DISPATCH,
};

/** Representation of AndroidInputEventConfig::TraceLevel. */
using TraceLevel = perfetto::protos::pbzero::AndroidInputEventConfig::TraceLevel;

/** Representation of AndroidInputEventConfig::TraceRule. */
struct TraceRule {
    TraceLevel level;

    std::vector<std::string> matchAllPackages;
    std::vector<std::string> matchAnyPackages;
    std::optional<bool> matchSecure;
    std::optional<bool> matchImeConnectionActive;
};

/**
 * A complete configuration for a tracing session.
 *
 * The trace rules are applied as documented in the perfetto config:
 *   /external/perfetto/protos/perfetto/config/android/android_input_event_config.proto
 */
struct TraceConfig {
    ftl::Flags<TraceFlag> flags;
    std::vector<TraceRule> rules;
};

} // namespace android::inputdispatcher::trace::impl