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

Commit e987a0e3 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 11314147 from 55ea9f4a to 24Q2-release

Change-Id: I9712f7d97916a1fe7b4411a75c1ed1e2d515509d
parents 6886c819 55ea9f4a
Loading
Loading
Loading
Loading
+25 −4
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 * 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.
@@ -64,6 +64,8 @@ public:

class VirtualMouse : public VirtualInputDevice {
public:
    // Expose to share with VirtualStylus.
    static const std::map<int, UinputAction> BUTTON_ACTION_MAPPING;
    VirtualMouse(android::base::unique_fd fd);
    virtual ~VirtualMouse() override;
    bool writeButtonEvent(int32_t androidButtonCode, int32_t androidAction,
@@ -74,12 +76,13 @@ public:
                          std::chrono::nanoseconds eventTime);

private:
    static const std::map<int, UinputAction> BUTTON_ACTION_MAPPING;
    static const std::map<int, int> BUTTON_CODE_MAPPING;
};

class VirtualTouchscreen : public VirtualInputDevice {
public:
    // Expose to share with VirtualStylus.
    static const std::map<int, UinputAction> TOUCH_ACTION_MAPPING;
    VirtualTouchscreen(android::base::unique_fd fd);
    virtual ~VirtualTouchscreen() override;
    // TODO(b/259554911): changing float parameters to int32_t.
@@ -88,9 +91,7 @@ public:
                         std::chrono::nanoseconds eventTime);

private:
    static const std::map<int, UinputAction> TOUCH_ACTION_MAPPING;
    static const std::map<int, int> TOOL_TYPE_MAPPING;

    /* The set of active touch pointers on this device.
     * We only allow pointer id to go up to MAX_POINTERS because the maximum slots of virtual
     * touchscreen is set up with MAX_POINTERS. Note that in other cases Android allows pointer id
@@ -101,4 +102,24 @@ private:
    bool handleTouchDown(int32_t pointerId, std::chrono::nanoseconds eventTime);
    bool handleTouchUp(int32_t pointerId, std::chrono::nanoseconds eventTime);
};

class VirtualStylus : public VirtualInputDevice {
public:
    VirtualStylus(android::base::unique_fd fd);
    ~VirtualStylus() override;
    bool writeMotionEvent(int32_t toolType, int32_t action, int32_t locationX, int32_t locationY,
                          int32_t pressure, int32_t tiltX, int32_t tiltY,
                          std::chrono::nanoseconds eventTime);
    bool writeButtonEvent(int32_t androidButtonCode, int32_t androidAction,
                          std::chrono::nanoseconds eventTime);

private:
    static const std::map<int, int> TOOL_TYPE_MAPPING;
    static const std::map<int, int> BUTTON_CODE_MAPPING;
    // True if the stylus is touching or hovering on the screen.
    bool mIsStylusDown;
    bool handleStylusDown(uint16_t tool, std::chrono::nanoseconds eventTime);
    bool handleStylusUp(uint16_t tool, std::chrono::nanoseconds eventTime);
};

} // namespace android
+32 −20
Original line number Diff line number Diff line
@@ -220,11 +220,15 @@ void worker_fx(int num,
        workers.push_back(serviceMgr->waitForService(generateServiceName(i)));
    }

    // Run the benchmark if client
    ProcResults results(iterations);
    p.signal();
    p.wait();

    ProcResults results(iterations);
    chrono::time_point<chrono::high_resolution_clock> start, end;
    for (int i = 0; (!cs_pair || num >= server_count) && i < iterations; i++) {

    // Skip the benchmark if server of a cs_pair.
    if (!(cs_pair && num < server_count)) {
        for (int i = 0; i < iterations; i++) {
            Parcel data, reply;
            int target = cs_pair ? num % server_count : rand() % workers.size();
            int sz = payload_size;
@@ -245,6 +249,7 @@ void worker_fx(int num,
               exit(EXIT_FAILURE);
            }
        }
    }

    // Signal completion to master and wait.
    p.signal();
@@ -300,8 +305,15 @@ void run_main(int iterations,
        pipes.push_back(make_worker(i, iterations, workers, payload_size, cs_pair));
    }
    wait_all(pipes);
    // All workers have now been spawned and added themselves to service
    // manager. Signal each worker to obtain a handle to the server workers from
    // servicemanager.
    signal_all(pipes);
    // Wait for each worker to finish obtaining a handle to all server workers
    // from servicemanager.
    wait_all(pipes);

    // Run the workers and wait for completion.
    // Run the benchmark and wait for completion.
    chrono::time_point<chrono::high_resolution_clock> start, end;
    cout << "waiting for workers to complete" << endl;
    start = chrono::high_resolution_clock::now();
+120 −4
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 * 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.
@@ -39,7 +39,9 @@ static bool isDebug() {
}

namespace android {

VirtualInputDevice::VirtualInputDevice(unique_fd fd) : mFd(std::move(fd)) {}

VirtualInputDevice::~VirtualInputDevice() {
    ioctl(mFd, UI_DEV_DESTROY);
}
@@ -56,7 +58,7 @@ bool VirtualInputDevice::writeInputEvent(uint16_t type, uint16_t code, int32_t v
    return TEMP_FAILURE_RETRY(write(mFd, &ev, sizeof(struct input_event))) == sizeof(ev);
}

/** Utility method to write keyboard key events or mouse button events. */
/** Utility method to write keyboard key events or mouse/stylus button events. */
bool VirtualInputDevice::writeEvKeyEvent(int32_t androidCode, int32_t androidAction,
                                         const std::map<int, int>& evKeyCodeMapping,
                                         const std::map<int, UinputAction>& actionMapping,
@@ -68,13 +70,17 @@ bool VirtualInputDevice::writeEvKeyEvent(int32_t androidCode, int32_t androidAct
    }
    auto actionIterator = actionMapping.find(androidAction);
    if (actionIterator == actionMapping.end()) {
        ALOGE("Unsupported native action for android action %d", androidAction);
        return false;
    }
    if (!writeInputEvent(EV_KEY, static_cast<uint16_t>(evKeyCodeIterator->second),
                         static_cast<int32_t>(actionIterator->second), eventTime)) {
    int32_t action = static_cast<int32_t>(actionIterator->second);
    uint16_t evKeyCode = static_cast<uint16_t>(evKeyCodeIterator->second);
    if (!writeInputEvent(EV_KEY, evKeyCode, action, eventTime)) {
        ALOGE("Failed to write native action %d and EV keycode %u.", action, evKeyCode);
        return false;
    }
    if (!writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime)) {
        ALOGE("Failed to write SYN_REPORT for EV_KEY event.");
        return false;
    }
    return true;
@@ -85,6 +91,7 @@ const std::map<int, UinputAction> VirtualKeyboard::KEY_ACTION_MAPPING = {
        {AKEY_EVENT_ACTION_DOWN, UinputAction::PRESS},
        {AKEY_EVENT_ACTION_UP, UinputAction::RELEASE},
};

// Keycode mapping from https://source.android.com/devices/input/keyboard-devices
const std::map<int, int> VirtualKeyboard::KEY_CODE_MAPPING = {
        {AKEYCODE_0, KEY_0},
@@ -195,7 +202,9 @@ const std::map<int, int> VirtualKeyboard::KEY_CODE_MAPPING = {
        {AKEYCODE_NUMPAD_COMMA, KEY_KPCOMMA},
        {AKEYCODE_LANGUAGE_SWITCH, KEY_LANGUAGE},
};

VirtualKeyboard::VirtualKeyboard(unique_fd fd) : VirtualInputDevice(std::move(fd)) {}

VirtualKeyboard::~VirtualKeyboard() {}

bool VirtualKeyboard::writeKeyEvent(int32_t androidKeyCode, int32_t androidAction,
@@ -275,6 +284,7 @@ const std::map<int, UinputAction> VirtualTouchscreen::TOUCH_ACTION_MAPPING = {
        {AMOTION_EVENT_ACTION_MOVE, UinputAction::MOVE},
        {AMOTION_EVENT_ACTION_CANCEL, UinputAction::CANCEL},
};

// Tool type mapping from https://source.android.com/devices/input/touch-devices
const std::map<int, int> VirtualTouchscreen::TOOL_TYPE_MAPPING = {
        {AMOTION_EVENT_TOOL_TYPE_FINGER, MT_TOOL_FINGER},
@@ -393,4 +403,110 @@ bool VirtualTouchscreen::handleTouchDown(int32_t pointerId, std::chrono::nanosec
    return true;
}

// --- VirtualStylus ---
const std::map<int, int> VirtualStylus::TOOL_TYPE_MAPPING = {
        {AMOTION_EVENT_TOOL_TYPE_STYLUS, BTN_TOOL_PEN},
        {AMOTION_EVENT_TOOL_TYPE_ERASER, BTN_TOOL_RUBBER},
};

// Button code mapping from https://source.android.com/devices/input/touch-devices
const std::map<int, int> VirtualStylus::BUTTON_CODE_MAPPING = {
        {AMOTION_EVENT_BUTTON_STYLUS_PRIMARY, BTN_STYLUS},
        {AMOTION_EVENT_BUTTON_STYLUS_SECONDARY, BTN_STYLUS2},
};

VirtualStylus::VirtualStylus(unique_fd fd)
      : VirtualInputDevice(std::move(fd)), mIsStylusDown(false) {}

VirtualStylus::~VirtualStylus() {}

bool VirtualStylus::writeMotionEvent(int32_t toolType, int32_t action, int32_t locationX,
                                     int32_t locationY, int32_t pressure, int32_t tiltX,
                                     int32_t tiltY, std::chrono::nanoseconds eventTime) {
    auto actionIterator = VirtualTouchscreen::TOUCH_ACTION_MAPPING.find(action);
    if (actionIterator == VirtualTouchscreen::TOUCH_ACTION_MAPPING.end()) {
        ALOGE("Unsupported action passed for stylus: %d.", action);
        return false;
    }
    UinputAction uinputAction = actionIterator->second;
    auto toolTypeIterator = TOOL_TYPE_MAPPING.find(toolType);
    if (toolTypeIterator == TOOL_TYPE_MAPPING.end()) {
        ALOGE("Unsupported tool type passed for stylus: %d.", toolType);
        return false;
    }
    uint16_t tool = static_cast<uint16_t>(toolTypeIterator->second);
    if (uinputAction == UinputAction::PRESS && !handleStylusDown(tool, eventTime)) {
        return false;
    }
    if (!mIsStylusDown) {
        ALOGE("Action UP or MOVE received with no prior action DOWN for stylus %d.", mFd.get());
        return false;
    }
    if (uinputAction == UinputAction::RELEASE && !handleStylusUp(tool, eventTime)) {
        return false;
    }
    if (!writeInputEvent(EV_ABS, ABS_X, locationX, eventTime)) {
        ALOGE("Unsupported x-axis location passed for stylus: %d.", locationX);
        return false;
    }
    if (!writeInputEvent(EV_ABS, ABS_Y, locationY, eventTime)) {
        ALOGE("Unsupported y-axis location passed for stylus: %d.", locationY);
        return false;
    }
    if (!writeInputEvent(EV_ABS, ABS_TILT_X, tiltX, eventTime)) {
        ALOGE("Unsupported x-axis tilt passed for stylus: %d.", tiltX);
        return false;
    }
    if (!writeInputEvent(EV_ABS, ABS_TILT_Y, tiltY, eventTime)) {
        ALOGE("Unsupported y-axis tilt passed for stylus: %d.", tiltY);
        return false;
    }
    if (!writeInputEvent(EV_ABS, ABS_PRESSURE, pressure, eventTime)) {
        ALOGE("Unsupported pressure passed for stylus: %d.", pressure);
        return false;
    }
    if (!writeInputEvent(EV_SYN, SYN_REPORT, 0, eventTime)) {
        ALOGE("Failed to write SYN_REPORT for stylus motion event.");
        return false;
    }
    return true;
}

bool VirtualStylus::writeButtonEvent(int32_t androidButtonCode, int32_t androidAction,
                                     std::chrono::nanoseconds eventTime) {
    return writeEvKeyEvent(androidButtonCode, androidAction, BUTTON_CODE_MAPPING,
                           VirtualMouse::BUTTON_ACTION_MAPPING, eventTime);
}

bool VirtualStylus::handleStylusDown(uint16_t tool, std::chrono::nanoseconds eventTime) {
    if (mIsStylusDown) {
        ALOGE("Repetitive action DOWN event received for a stylus that is already down.");
        return false;
    }
    if (!writeInputEvent(EV_KEY, tool, static_cast<int32_t>(UinputAction::PRESS), eventTime)) {
        ALOGE("Failed to write EV_KEY for stylus tool type: %u.", tool);
        return false;
    }
    if (!writeInputEvent(EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::PRESS), eventTime)) {
        ALOGE("Failed to write BTN_TOUCH for stylus press.");
        return false;
    }
    mIsStylusDown = true;
    return true;
}

bool VirtualStylus::handleStylusUp(uint16_t tool, std::chrono::nanoseconds eventTime) {
    if (!writeInputEvent(EV_KEY, tool, static_cast<int32_t>(UinputAction::RELEASE), eventTime)) {
        ALOGE("Failed to write EV_KEY for stylus tool type: %u.", tool);
        return false;
    }
    if (!writeInputEvent(EV_KEY, BTN_TOUCH, static_cast<int32_t>(UinputAction::RELEASE),
                         eventTime)) {
        ALOGE("Failed to write BTN_TOUCH for stylus release.");
        return false;
    }
    mIsStylusDown = false;
    return true;
}

} // namespace android
+127 −37
Original line number Diff line number Diff line
@@ -179,23 +179,35 @@ TEST_F(FrameTracerTest, canTraceAfterAddingLayer) {
        tracingSession->StopBlocking();

        auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
        EXPECT_EQ(packets.size(), 1);
        ASSERT_EQ(packets.size(), 2);

        const auto& packet = packets[0];
        ASSERT_TRUE(packet.has_timestamp());
        EXPECT_EQ(packet.timestamp(), timestamp);
        ASSERT_TRUE(packet.has_graphics_frame_event());
        const auto& frame_event = packet.graphics_frame_event();
        ASSERT_TRUE(frame_event.has_buffer_event());
        const auto& buffer_event = frame_event.buffer_event();
        ASSERT_TRUE(buffer_event.has_buffer_id());
        EXPECT_EQ(buffer_event.buffer_id(), bufferID);
        ASSERT_TRUE(buffer_event.has_frame_number());
        EXPECT_EQ(buffer_event.frame_number(), frameNumber);
        ASSERT_TRUE(buffer_event.has_type());
        EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
        ASSERT_TRUE(buffer_event.has_duration_ns());
        EXPECT_EQ(buffer_event.duration_ns(), duration);
        const auto& packet1 = packets[0];
        ASSERT_TRUE(packet1.has_timestamp());
        EXPECT_EQ(packet1.timestamp(), timestamp);
        ASSERT_TRUE(packet1.has_graphics_frame_event());
        const auto& frame_event1 = packet1.graphics_frame_event();
        ASSERT_TRUE(frame_event1.has_buffer_event());
        const auto& buffer_event1 = frame_event1.buffer_event();
        ASSERT_TRUE(buffer_event1.has_buffer_id());
        EXPECT_EQ(buffer_event1.buffer_id(), bufferID);
        ASSERT_TRUE(buffer_event1.has_frame_number());
        EXPECT_EQ(buffer_event1.frame_number(), frameNumber);
        ASSERT_TRUE(buffer_event1.has_type());
        EXPECT_EQ(buffer_event1.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
        ASSERT_TRUE(buffer_event1.has_duration_ns());
        EXPECT_EQ(buffer_event1.duration_ns(), duration);

        const auto& packet2 = packets[1];
        ASSERT_TRUE(packet2.has_timestamp());
        EXPECT_EQ(packet2.timestamp(), 0);
        ASSERT_TRUE(packet2.has_graphics_frame_event());
        const auto& frame_event2 = packet2.graphics_frame_event();
        ASSERT_TRUE(frame_event2.has_buffer_event());
        const auto& buffer_event2 = frame_event2.buffer_event();
        ASSERT_TRUE(buffer_event2.has_type());
        EXPECT_EQ(buffer_event2.type(),
                  perfetto::protos::GraphicsFrameEvent_BufferEventType(
                          FrameTracer::FrameEvent::UNSPECIFIED));
    }
}

@@ -219,7 +231,18 @@ TEST_F(FrameTracerTest, traceFenceTriggersOnNextTraceAfterFenceFired) {
        tracingSession->StopBlocking();

        auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
        EXPECT_EQ(packets.size(), 0);
        ASSERT_EQ(packets.size(), 1);
        const auto& packet = packets[0];
        ASSERT_TRUE(packet.has_timestamp());
        EXPECT_EQ(packet.timestamp(), 0);
        ASSERT_TRUE(packet.has_graphics_frame_event());
        const auto& frame_event = packet.graphics_frame_event();
        ASSERT_TRUE(frame_event.has_buffer_event());
        const auto& buffer_event = frame_event.buffer_event();
        ASSERT_TRUE(buffer_event.has_type());
        EXPECT_EQ(buffer_event.type(),
                  perfetto::protos::GraphicsFrameEvent_BufferEventType(
                          FrameTracer::FrameEvent::UNSPECIFIED));
    }

    {
@@ -235,22 +258,56 @@ TEST_F(FrameTracerTest, traceFenceTriggersOnNextTraceAfterFenceFired) {
        tracingSession->StopBlocking();

        auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
        EXPECT_EQ(packets.size(), 2); // Two packets because of the extra trace made above.
        ASSERT_EQ(packets.size(), 3);

        const auto& packet = packets[1];
        ASSERT_TRUE(packet.has_timestamp());
        EXPECT_EQ(packet.timestamp(), timestamp);
        ASSERT_TRUE(packet.has_graphics_frame_event());
        const auto& frame_event = packet.graphics_frame_event();
        ASSERT_TRUE(frame_event.has_buffer_event());
        const auto& buffer_event = frame_event.buffer_event();
        ASSERT_TRUE(buffer_event.has_buffer_id());
        EXPECT_EQ(buffer_event.buffer_id(), bufferID);
        ASSERT_TRUE(buffer_event.has_frame_number());
        EXPECT_EQ(buffer_event.frame_number(), frameNumber);
        ASSERT_TRUE(buffer_event.has_type());
        EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
        EXPECT_FALSE(buffer_event.has_duration_ns());
        const auto& packet1 = packets[0];
        ASSERT_TRUE(packet1.has_timestamp());
        EXPECT_EQ(packet1.timestamp(), timestamp);
        ASSERT_TRUE(packet1.has_graphics_frame_event());
        const auto& frame_event1 = packet1.graphics_frame_event();
        ASSERT_TRUE(frame_event1.has_buffer_event());
        const auto& buffer_event1 = frame_event1.buffer_event();
        ASSERT_TRUE(buffer_event1.has_buffer_id());
        EXPECT_EQ(buffer_event1.buffer_id(), bufferID);
        ASSERT_TRUE(buffer_event1.has_frame_number());
        EXPECT_EQ(buffer_event1.frame_number(), frameNumber);
        ASSERT_TRUE(buffer_event1.has_type());
        EXPECT_EQ(buffer_event1.type(),
                  perfetto::protos::GraphicsFrameEvent::BufferEventType(type));
        EXPECT_FALSE(buffer_event1.has_duration_ns());

        const auto& packet2 = packets[1];
        ASSERT_TRUE(packet2.has_timestamp());
        EXPECT_EQ(packet2.timestamp(), timestamp);
        ASSERT_TRUE(packet2.has_graphics_frame_event());
        const auto& frame_event2 = packet2.graphics_frame_event();
        ASSERT_TRUE(frame_event2.has_buffer_event());
        const auto& buffer_event2 = frame_event2.buffer_event();
        ASSERT_TRUE(buffer_event2.has_buffer_id());
        EXPECT_EQ(buffer_event2.buffer_id(), bufferID);
        ASSERT_TRUE(buffer_event2.has_frame_number());
        EXPECT_EQ(buffer_event2.frame_number(), frameNumber);
        ASSERT_TRUE(buffer_event2.has_type());
        EXPECT_EQ(buffer_event2.type(),
                  perfetto::protos::GraphicsFrameEvent::BufferEventType(type));
        EXPECT_FALSE(buffer_event2.has_duration_ns());

        const auto& packet3 = packets[2];
        ASSERT_TRUE(packet3.has_timestamp());
        EXPECT_EQ(packet3.timestamp(), 0);
        ASSERT_TRUE(packet3.has_graphics_frame_event());
        const auto& frame_event3 = packet3.graphics_frame_event();
        ASSERT_TRUE(frame_event3.has_buffer_event());
        const auto& buffer_event3 = frame_event3.buffer_event();
        ASSERT_TRUE(buffer_event3.has_buffer_id());
        EXPECT_EQ(buffer_event3.buffer_id(), bufferID);
        ASSERT_TRUE(buffer_event3.has_frame_number());
        EXPECT_EQ(buffer_event3.frame_number(), 0);
        ASSERT_TRUE(buffer_event3.has_type());
        EXPECT_EQ(buffer_event3.type(),
                  perfetto::protos::GraphicsFrameEvent::BufferEventType(
                          FrameTracer::FrameEvent::UNSPECIFIED));
        EXPECT_FALSE(buffer_event3.has_duration_ns());
    }
}

@@ -285,7 +342,7 @@ TEST_F(FrameTracerTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDurat
    tracingSession->StopBlocking();

    auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
    EXPECT_EQ(packets.size(), 2);
    ASSERT_EQ(packets.size(), 3);

    const auto& packet1 = packets[0];
    ASSERT_TRUE(packet1.has_timestamp());
@@ -293,6 +350,8 @@ TEST_F(FrameTracerTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDurat
    ASSERT_TRUE(packet1.has_graphics_frame_event());
    ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
    ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
    EXPECT_EQ(packet1.graphics_frame_event().buffer_event().type(),
              perfetto::protos::GraphicsFrameEvent::BufferEventType(type));

    const auto& packet2 = packets[1];
    ASSERT_TRUE(packet2.has_timestamp());
@@ -300,6 +359,17 @@ TEST_F(FrameTracerTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDurat
    ASSERT_TRUE(packet2.has_graphics_frame_event());
    ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
    ASSERT_FALSE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
    EXPECT_EQ(packet2.graphics_frame_event().buffer_event().type(),
              perfetto::protos::GraphicsFrameEvent::BufferEventType(type));

    const auto& packet3 = packets[2];
    ASSERT_TRUE(packet3.has_timestamp());
    EXPECT_EQ(packet3.timestamp(), 0);
    ASSERT_TRUE(packet3.has_graphics_frame_event());
    ASSERT_TRUE(packet3.graphics_frame_event().has_buffer_event());
    EXPECT_EQ(packet3.graphics_frame_event().buffer_event().type(),
              perfetto::protos::GraphicsFrameEvent::BufferEventType(
                      FrameTracer::FrameEvent::UNSPECIFIED));
}

TEST_F(FrameTracerTest, traceFenceOlderThanDeadline_ShouldBeIgnored) {
@@ -322,7 +392,15 @@ TEST_F(FrameTracerTest, traceFenceOlderThanDeadline_ShouldBeIgnored) {
    tracingSession->StopBlocking();

    auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
    EXPECT_EQ(packets.size(), 0);
    ASSERT_EQ(packets.size(), 1);
    const auto& packet = packets[0];
    ASSERT_TRUE(packet.has_timestamp());
    EXPECT_EQ(packet.timestamp(), 0);
    ASSERT_TRUE(packet.has_graphics_frame_event());
    ASSERT_TRUE(packet.graphics_frame_event().has_buffer_event());
    EXPECT_EQ(packet.graphics_frame_event().buffer_event().type(),
              perfetto::protos::GraphicsFrameEvent::BufferEventType(
                      FrameTracer::FrameEvent::UNSPECIFIED));
}

TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) {
@@ -357,7 +435,7 @@ TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration)
    tracingSession->StopBlocking();

    auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
    EXPECT_EQ(packets.size(), 2);
    ASSERT_EQ(packets.size(), 3);

    const auto& packet1 = packets[0];
    ASSERT_TRUE(packet1.has_timestamp());
@@ -367,6 +445,7 @@ TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration)
    ASSERT_TRUE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
    const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event();
    EXPECT_EQ(buffer_event1.duration_ns(), duration);
    EXPECT_EQ(buffer_event1.type(), perfetto::protos::GraphicsFrameEvent::BufferEventType(type));

    const auto& packet2 = packets[1];
    ASSERT_TRUE(packet2.has_timestamp());
@@ -376,6 +455,17 @@ TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration)
    ASSERT_TRUE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
    const auto& buffer_event2 = packet2.graphics_frame_event().buffer_event();
    EXPECT_EQ(buffer_event2.duration_ns(), duration);
    EXPECT_EQ(buffer_event2.type(), perfetto::protos::GraphicsFrameEvent::BufferEventType(type));

    const auto& packet3 = packets[2];
    ASSERT_TRUE(packet3.has_timestamp());
    EXPECT_EQ(packet3.timestamp(), 0);
    ASSERT_TRUE(packet3.has_graphics_frame_event());
    ASSERT_TRUE(packet3.graphics_frame_event().has_buffer_event());
    const auto& buffer_event3 = packet3.graphics_frame_event().buffer_event();
    EXPECT_EQ(buffer_event3.type(),
              perfetto::protos::GraphicsFrameEvent::BufferEventType(
                      FrameTracer::FrameEvent::UNSPECIFIED));
}

} // namespace