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

Commit b568238e authored by Prabir Pradhan's avatar Prabir Pradhan
Browse files

InputTracer: Distinguish sensitive events

There are three levels of tracing: complete, redacted, and none.

Write events that are redacted into a separate proto, while also
omitting certain fields from being written.

The redacted level will be used in subsequent CLs.

Bug: 210460522
Test: manual with perfetto
Change-Id: Ie65e7915c3aa5fc972e675c43e46970363bab3a4
parent 4c49aad7
Loading
Loading
Loading
Loading
+25 −9
Original line number Diff line number Diff line
@@ -39,7 +39,8 @@ const impl::TraceConfig CONFIG_TRACE_ALL{
} // namespace

void AndroidInputEventProtoConverter::toProtoMotionEvent(const TracedMotionEvent& event,
                                                         proto::AndroidMotionEvent& outProto) {
                                                         proto::AndroidMotionEvent& outProto,
                                                         bool isRedacted) {
    outProto.set_event_id(event.id);
    outProto.set_event_time_nanos(event.eventTime);
    outProto.set_down_time_nanos(event.downTime);
@@ -48,11 +49,15 @@ void AndroidInputEventProtoConverter::toProtoMotionEvent(const TracedMotionEvent
    outProto.set_device_id(event.deviceId);
    outProto.set_display_id(event.displayId);
    outProto.set_classification(static_cast<int32_t>(event.classification));
    outProto.set_cursor_position_x(event.xCursorPosition);
    outProto.set_cursor_position_y(event.yCursorPosition);
    outProto.set_flags(event.flags);
    outProto.set_policy_flags(event.policyFlags);

    if (!isRedacted) {
        outProto.set_cursor_position_x(event.xCursorPosition);
        outProto.set_cursor_position_y(event.yCursorPosition);
        outProto.set_meta_state(event.metaState);
    }

    for (uint32_t i = 0; i < event.pointerProperties.size(); i++) {
        auto* pointer = outProto.add_pointer();

@@ -66,13 +71,17 @@ void AndroidInputEventProtoConverter::toProtoMotionEvent(const TracedMotionEvent
            const auto axis = bits.clearFirstMarkedBit();
            auto axisEntry = pointer->add_axis_value();
            axisEntry->set_axis(axis);

            if (!isRedacted) {
                axisEntry->set_value(coords.values[axisIndex]);
            }
        }
    }
}

void AndroidInputEventProtoConverter::toProtoKeyEvent(const TracedKeyEvent& event,
                                                      proto::AndroidKeyEvent& outProto) {
                                                      proto::AndroidKeyEvent& outProto,
                                                      bool isRedacted) {
    outProto.set_event_id(event.id);
    outProto.set_event_time_nanos(event.eventTime);
    outProto.set_down_time_nanos(event.downTime);
@@ -80,21 +89,28 @@ void AndroidInputEventProtoConverter::toProtoKeyEvent(const TracedKeyEvent& even
    outProto.set_action(event.action);
    outProto.set_device_id(event.deviceId);
    outProto.set_display_id(event.displayId);
    outProto.set_key_code(event.keyCode);
    outProto.set_scan_code(event.scanCode);
    outProto.set_meta_state(event.metaState);
    outProto.set_repeat_count(event.repeatCount);
    outProto.set_flags(event.flags);
    outProto.set_policy_flags(event.policyFlags);

    if (!isRedacted) {
        outProto.set_key_code(event.keyCode);
        outProto.set_scan_code(event.scanCode);
        outProto.set_meta_state(event.metaState);
    }
}

void AndroidInputEventProtoConverter::toProtoWindowDispatchEvent(
        const WindowDispatchArgs& args, proto::AndroidWindowInputDispatchEvent& outProto) {
        const WindowDispatchArgs& args, proto::AndroidWindowInputDispatchEvent& outProto,
        bool isRedacted) {
    std::visit([&](auto entry) { outProto.set_event_id(entry.id); }, args.eventEntry);
    outProto.set_vsync_id(args.vsyncId);
    outProto.set_window_id(args.windowId);
    outProto.set_resolved_flags(args.resolvedFlags);

    if (isRedacted) {
        return;
    }
    if (auto* motion = std::get_if<TracedMotionEvent>(&args.eventEntry); motion != nullptr) {
        for (size_t i = 0; i < motion->pointerProperties.size(); i++) {
            auto* pointerProto = outProto.add_dispatched_pointer();
+5 −3
Original line number Diff line number Diff line
@@ -32,10 +32,12 @@ namespace android::inputdispatcher::trace {
class AndroidInputEventProtoConverter {
public:
    static void toProtoMotionEvent(const TracedMotionEvent& event,
                                   proto::AndroidMotionEvent& outProto);
    static void toProtoKeyEvent(const TracedKeyEvent& event, proto::AndroidKeyEvent& outProto);
                                   proto::AndroidMotionEvent& outProto, bool isRedacted);
    static void toProtoKeyEvent(const TracedKeyEvent& event, proto::AndroidKeyEvent& outProto,
                                bool isRedacted);
    static void toProtoWindowDispatchEvent(const WindowDispatchArgs&,
                                           proto::AndroidWindowInputDispatchEvent& outProto);
                                           proto::AndroidWindowInputDispatchEvent& outProto,
                                           bool isRedacted);

    static impl::TraceConfig parseConfig(proto::AndroidInputEventConfig::Decoder& protoConfig);
};
+50 −18
Original line number Diff line number Diff line
@@ -69,6 +69,30 @@ bool PerfettoBackend::InputEventDataSource::shouldIgnoreTracedInputEvent(
    return false;
}

TraceLevel PerfettoBackend::InputEventDataSource::resolveTraceLevel(
        const TracedEventArgs& args) const {
    // Check for matches with the rules in the order that they are defined.
    for (const auto& rule : mConfig.rules) {
        if (ruleMatches(rule, args)) {
            return rule.level;
        }
    }

    // The event is not traced if it matched zero rules.
    return TraceLevel::TRACE_LEVEL_NONE;
}

bool PerfettoBackend::InputEventDataSource::ruleMatches(const TraceRule& rule,
                                                        const TracedEventArgs& args) const {
    // By default, a rule will match all events. Return early if the rule does not match.

    if (rule.matchSecure.has_value() && *rule.matchSecure != args.isSecure) {
        return false;
    }

    return true;
}

// --- PerfettoBackend ---

std::once_flag PerfettoBackend::sDataSourceRegistrationFlag{};
@@ -94,54 +118,62 @@ PerfettoBackend::PerfettoBackend() {

void PerfettoBackend::traceMotionEvent(const TracedMotionEvent& event,
                                       const TracedEventArgs& args) {
    if (args.isSecure) {
        // For now, avoid tracing secure event entirely.
        return;
    }
    InputEventDataSource::Trace([&](InputEventDataSource::TraceContext ctx) {
        auto dataSource = ctx.GetDataSourceLocked();
        if (dataSource->shouldIgnoreTracedInputEvent(event.eventType)) {
            return;
        }
        const TraceLevel traceLevel = dataSource->resolveTraceLevel(args);
        if (traceLevel == TraceLevel::TRACE_LEVEL_NONE) {
            return;
        }
        const bool isRedacted = traceLevel == TraceLevel::TRACE_LEVEL_REDACTED;
        auto tracePacket = ctx.NewTracePacket();
        auto* inputEvent = tracePacket->set_android_input_event();
        auto* dispatchMotion = inputEvent->set_dispatcher_motion_event();
        AndroidInputEventProtoConverter::toProtoMotionEvent(event, *dispatchMotion);
        auto* dispatchMotion = isRedacted ? inputEvent->set_dispatcher_motion_event_redacted()
                                          : inputEvent->set_dispatcher_motion_event();
        AndroidInputEventProtoConverter::toProtoMotionEvent(event, *dispatchMotion, isRedacted);
    });
}

void PerfettoBackend::traceKeyEvent(const TracedKeyEvent& event, const TracedEventArgs& args) {
    if (args.isSecure) {
        // For now, avoid tracing secure event entirely.
        return;
    }
    InputEventDataSource::Trace([&](InputEventDataSource::TraceContext ctx) {
        auto dataSource = ctx.GetDataSourceLocked();
        if (dataSource->shouldIgnoreTracedInputEvent(event.eventType)) {
            return;
        }
        const TraceLevel traceLevel = dataSource->resolveTraceLevel(args);
        if (traceLevel == TraceLevel::TRACE_LEVEL_NONE) {
            return;
        }
        const bool isRedacted = traceLevel == TraceLevel::TRACE_LEVEL_REDACTED;
        auto tracePacket = ctx.NewTracePacket();
        auto* inputEvent = tracePacket->set_android_input_event();
        auto* dispatchKey = inputEvent->set_dispatcher_key_event();
        AndroidInputEventProtoConverter::toProtoKeyEvent(event, *dispatchKey);
        auto* dispatchKey = isRedacted ? inputEvent->set_dispatcher_key_event_redacted()
                                       : inputEvent->set_dispatcher_key_event();
        AndroidInputEventProtoConverter::toProtoKeyEvent(event, *dispatchKey, isRedacted);
    });
}

void PerfettoBackend::traceWindowDispatch(const WindowDispatchArgs& dispatchArgs,
                                          const TracedEventArgs& args) {
    if (args.isSecure) {
        // For now, avoid tracing secure event entirely.
        return;
    }
    InputEventDataSource::Trace([&](InputEventDataSource::TraceContext ctx) {
        auto dataSource = ctx.GetDataSourceLocked();
        if (!dataSource->getFlags().test(TraceFlag::TRACE_DISPATCHER_WINDOW_DISPATCH)) {
            return;
        }
        const TraceLevel traceLevel = dataSource->resolveTraceLevel(args);
        if (traceLevel == TraceLevel::TRACE_LEVEL_NONE) {
            return;
        }
        const bool isRedacted = traceLevel == TraceLevel::TRACE_LEVEL_REDACTED;
        auto tracePacket = ctx.NewTracePacket();
        auto* inputEvent = tracePacket->set_android_input_event();
        auto* dispatchEvent = inputEvent->set_dispatcher_window_dispatch_event();
        AndroidInputEventProtoConverter::toProtoWindowDispatchEvent(dispatchArgs, *dispatchEvent);
        auto* dispatchEvent = isRedacted
                ? inputEvent->set_dispatcher_window_dispatch_event_redacted()
                : inputEvent->set_dispatcher_window_dispatch_event();
        AndroidInputEventProtoConverter::toProtoWindowDispatchEvent(dispatchArgs, *dispatchEvent,
                                                                    isRedacted);
    });
}

+3 −0
Original line number Diff line number Diff line
@@ -68,10 +68,13 @@ private:

        bool shouldIgnoreTracedInputEvent(const EventType&) const;
        inline ftl::Flags<TraceFlag> getFlags() const { return mConfig.flags; }
        TraceLevel resolveTraceLevel(const TracedEventArgs&) const;

    private:
        const int32_t mInstanceId;
        TraceConfig mConfig;

        bool ruleMatches(const TraceRule&, const TracedEventArgs&) const;
    };

    static std::once_flag sDataSourceRegistrationFlag;