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

Commit e65f95f7 authored by Lloyd Pique's avatar Lloyd Pique
Browse files

end2end: Introduce Hwc3 observer [6/N]

The HWC3 observer intercepts Aidl calls made from SurfaceFlinger to the
a target Composer implementation and visa versa, allowing the test to
know about those events without modifications to SurfaceFlinger or the
target implementation. The calls are otherwise passed on to the intended
destination unchanged.

For now the observer intercepts calls made to the fake composer
implementation, but in the future it will be used to intercept calls
made to drm_hwcomposer.

Flag: TEST_ONLY
Bug: 372735083
Test: atest surfaceflinger_end2end_tests

Change-Id: Ife22c56ed1dca1228dceff8536a7527ad60889c9
parent f7edd4f7
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -32,12 +32,14 @@ cc_test {
    ],
    srcs: [
        "main.cpp",
        "test_framework/core/BufferId.cpp",
        "test_framework/core/EdidBuilder.cpp",
        "test_framework/core/TestService.cpp",
        "test_framework/hwc3/DisplayVSyncEventService.cpp",
        "test_framework/hwc3/FakeComposer.cpp",
        "test_framework/hwc3/Hwc3Controller.cpp",
        "test_framework/hwc3/MultiDisplayRefreshEventGenerator.cpp",
        "test_framework/hwc3/ObservingComposer.cpp",
        "test_framework/hwc3/SingleDisplayRefreshEventGenerator.cpp",
        "test_framework/hwc3/SingleDisplayRefreshSchedule.cpp",
        "test_framework/hwc3/TimeKeeperThread.cpp",
+67 −0
Original line number Diff line number Diff line
/*
 * Copyright 2025 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 <cstdint>
#include <string>

#include <sys/stat.h>

#include <aidl/android/hardware/common/NativeHandle.h>
#include <android-base/logging.h>
#include <cutils/native_handle.h>
#include <fmt/format.h>
#include <ftl/cast.h>
#include <ui/GraphicBuffer.h>
#include <utils/StrongPointer.h>

#include "test_framework/core/BufferId.h"

namespace android::surfaceflinger::tests::end2end::test_framework::core {
namespace {

auto bufferFdToBufferId(int rawFd) -> BufferId {
    struct stat stat{};
    const int result = fstat(rawFd, &stat);
    CHECK(result == 0);
    CHECK(ftl::cast_safety<uint64_t>(stat.st_ino) == ftl::CastSafety::kSafe);
    CHECK(ftl::cast_safety<uint64_t>(stat.st_dev) == ftl::CastSafety::kSafe);
    return {.inode = static_cast<uint64_t>(stat.st_ino),
            .device = static_cast<uint64_t>(stat.st_dev)};
}

}  // namespace

auto toBufferId(const aidl::android::hardware::common::NativeHandle& handle) -> BufferId {
    CHECK(!handle.fds.empty());
    return bufferFdToBufferId(handle.fds[0].get());
}

auto toBufferId(const native_handle_t* handle) -> BufferId {
    CHECK(handle != nullptr);
    CHECK(handle->numFds > 0);
    return bufferFdToBufferId(handle->data[0]);
}

auto toBufferId(const sp<GraphicBuffer>& buffer) -> BufferId {
    CHECK(buffer != nullptr);
    return toBufferId(buffer->getNativeBuffer()->handle);
}

auto toString(const BufferId& value) -> std::string {
    return fmt::format("BufferId{{inode: {}, device: {}}}", value.inode, value.device);
}

}  // namespace android::surfaceflinger::tests::end2end::test_framework::core
 No newline at end of file
+46 −0
Original line number Diff line number Diff line
/*
 * Copyright 2025 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 <cstdint>
#include <string>

#include <aidl/android/hardware/common/NativeHandle.h>
#include <cutils/native_handle.h>
#include <ui/GraphicBuffer.h>
#include <utils/StrongPointer.h>

namespace android::surfaceflinger::tests::end2end::test_framework::core {

struct BufferId final {
    uint64_t inode;
    uint64_t device;

    friend auto operator==(const BufferId&, const BufferId&) -> bool = default;
};

auto toBufferId(const native_handle_t* handle) -> BufferId;
auto toBufferId(const sp<GraphicBuffer>& buffer) -> BufferId;
auto toBufferId(const aidl::android::hardware::common::NativeHandle& handle) -> BufferId;

auto toString(const BufferId& value) -> std::string;

inline auto format_as(const BufferId& event) -> std::string {
    return toString(event);
}

}  // namespace android::surfaceflinger::tests::end2end::test_framework::core
+20 −4
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include "test_framework/core/DisplayConfiguration.h"
#include "test_framework/hwc3/FakeComposer.h"
#include "test_framework/hwc3/Hwc3Controller.h"
#include "test_framework/hwc3/ObservingComposer.h"

namespace android::surfaceflinger::tests::end2end::test_framework::hwc3 {

@@ -39,7 +40,7 @@ auto Hwc3Controller::make(std::span<const core::DisplayConfiguration> displays)
        -> base::expected<std::shared_ptr<hwc3::Hwc3Controller>, std::string> {
    using namespace std::string_literals;

    auto controller = std::make_unique<Hwc3Controller>(Passkey{});
    auto controller = std::make_shared<Hwc3Controller>(Passkey{});
    if (controller == nullptr) {
        return base::unexpected("Failed to construct the Hwc3Controller instance"s);
    }
@@ -60,8 +61,6 @@ auto Hwc3Controller::init(const std::span<const core::DisplayConfiguration> disp
        -> base::expected<void, std::string> {
    using namespace std::string_literals;

    auto qualifiedServiceName = FakeComposer::getServiceName(baseServiceName);

    auto fakeComposerResult = FakeComposer::make();
    if (!fakeComposerResult) {
        return base::unexpected(std::move(fakeComposerResult).error());
@@ -72,7 +71,15 @@ auto Hwc3Controller::init(const std::span<const core::DisplayConfiguration> disp
        fakeComposer->addDisplay(display);
    }

    auto binder = fakeComposer->getComposer()->asBinder();
    auto observingComposerResult =
            ObservingComposer::make(shared_from_this(), fakeComposer->getComposer());
    if (!observingComposerResult) {
        return base::unexpected(std::move(observingComposerResult).error());
    }
    auto observingComposer = *std::move(observingComposerResult);

    const auto qualifiedServiceName = ObservingComposer::getServiceName(baseServiceName);
    auto binder = observingComposer->getComposer()->asBinder();

    // This downgrade allows us to use the fake service name without it being defined in the
    // VINTF manifest.
@@ -86,9 +93,18 @@ auto Hwc3Controller::init(const std::span<const core::DisplayConfiguration> disp
    LOG(INFO) << "Registered service " << qualifiedServiceName << ". Error: " << status;

    mFakeComposer = std::move(fakeComposer);
    mObservingComposer = std::move(observingComposer);
    return {};
}

auto Hwc3Controller::editCallbacks() -> Callbacks& {
    return mCallbacks;
}

auto Hwc3Controller::callbacks() const -> const Callbacks& {
    return mCallbacks;
}

auto Hwc3Controller::getServiceName() -> std::string {
    return FakeComposer::getServiceName(baseServiceName);
}
+36 −3
Original line number Diff line number Diff line
@@ -22,18 +22,43 @@

#include <android-base/expected.h>

#include <aidl/android/hardware/graphics/composer3/PowerMode.h>

#include "test_framework/core/DisplayConfiguration.h"
#include "test_framework/hwc3/events/ClientDestroyed.h"
#include "test_framework/hwc3/events/DisplayPresented.h"
#include "test_framework/hwc3/events/PendingBufferSwap.h"
#include "test_framework/hwc3/events/PowerMode.h"
#include "test_framework/hwc3/events/VSync.h"
#include "test_framework/hwc3/events/VSyncEnabled.h"

namespace android::surfaceflinger::tests::end2end::test_framework::hwc3 {

class FakeComposer;
class ObservingComposer;

class Hwc3Controller final {
class Hwc3Controller final : public std::enable_shared_from_this<Hwc3Controller> {
    struct Passkey;  // Uses the passkey idiom to restrict construction.

  public:
    struct Callbacks final {
        // Invoked when SF destroys its HWC client connection.
        events::ClientDestroyed::AsyncConnector onClientDestroyed;

        // Invoked when SF configures the power mode for a display.
        events::PowerMode::AsyncConnector onPowerModeChanged;

        // Invoked when SF enables or disables vsync callbacks for a display.
        events::VSyncEnabled::AsyncConnector onVsyncEnabledChanged;

        // Invoked when SF presents a display.
        events::DisplayPresented::AsyncConnector onDisplayPresented;

        // Invoked when SF is swapping the buffer content of a hardware overlay.
        events::PendingBufferSwap::AsyncConnector onPendingBufferSwap;

        // Invoked when the client sends SF a vsync callback.
        events::VSync::AsyncConnector onVSyncCallbackSent;
    };

    // Gets the service name for the HWC3 instance that will be created and registered
    [[nodiscard]] static auto getServiceName() -> std::string;

@@ -43,6 +68,12 @@ class Hwc3Controller final {

    explicit Hwc3Controller(Passkey passkey);

    // Allows the callbacks to be routed.
    [[nodiscard]] auto editCallbacks() -> Callbacks&;

    // Allows the callbacks to be sent.
    [[nodiscard]] auto callbacks() const -> const Callbacks&;

    // Adds a new display to the HWC3, which will become a hotplug connect event.
    void addDisplay(const core::DisplayConfiguration& config);

@@ -56,6 +87,8 @@ class Hwc3Controller final {
            -> base::expected<void, std::string>;

    std::shared_ptr<FakeComposer> mFakeComposer;
    std::shared_ptr<ObservingComposer> mObservingComposer;
    Callbacks mCallbacks;
};

}  // namespace android::surfaceflinger::tests::end2end::test_framework::hwc3
Loading