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

Commit d90a085a authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "end2end: Use Edids to identify displays [9/N]" into main

parents e8e1468e 402d3f17
Loading
Loading
Loading
Loading
+45 −3
Original line number Diff line number Diff line
@@ -41,8 +41,10 @@
#include <ui/DisplayId.h>
#include <utils/StrongPointer.h>

#include "test_framework/core/DisplayConfiguration.h"
#include "test_framework/surfaceflinger/DisplayEventReceiver.h"
#include "test_framework/surfaceflinger/PollFdThread.h"
#include "test_framework/surfaceflinger/SFController.h"
#include "test_framework/surfaceflinger/events/Hotplug.h"
#include "test_framework/surfaceflinger/events/VSyncTiming.h"

@@ -50,7 +52,8 @@ namespace android::surfaceflinger::tests::end2end::test_framework::surfaceflinge

struct DisplayEventReceiver::Passkey final {};

auto DisplayEventReceiver::make(const sp<gui::ISurfaceComposer>& client, PollFdThread& pollFdThread,
auto DisplayEventReceiver::make(std::weak_ptr<SFController> controller,
                                const sp<gui::ISurfaceComposer>& client, PollFdThread& pollFdThread,
                                gui::ISurfaceComposer::VsyncSource source,
                                const sp<IBinder>& layerHandle,
                                const ftl::Flags<gui::ISurfaceComposer::EventRegistration>& events)
@@ -61,7 +64,9 @@ auto DisplayEventReceiver::make(const sp<gui::ISurfaceComposer>& client, PollFdT
    if (instance == nullptr) {
        return base::unexpected("Failed to construct a DisplayEventReceiver"s);
    }
    if (auto result = instance->init(client, pollFdThread, source, layerHandle, events); !result) {
    if (auto result = instance->init(std::move(controller), client, pollFdThread, source,
                                     layerHandle, events);
        !result) {
        return base::unexpected("Failed to init a DisplayEventReceiver: " + result.error());
    }
    return std::move(instance);
@@ -72,7 +77,9 @@ DisplayEventReceiver::DisplayEventReceiver(Passkey passkey) {
}

[[nodiscard]] auto DisplayEventReceiver::init(
        const sp<gui::ISurfaceComposer>& client, PollFdThread& pollFdThread,
        std::weak_ptr<SFController> controller, const sp<gui::ISurfaceComposer>& client,
        PollFdThread& pollFdThread,

        gui::ISurfaceComposer::VsyncSource source, const sp<IBinder>& layerHandle,
        const ftl::Flags<gui::ISurfaceComposer::EventRegistration>& events)
        -> base::expected<void, std::string> {
@@ -92,6 +99,7 @@ DisplayEventReceiver::DisplayEventReceiver(Passkey passkey) {
        return base::unexpected("failed to steal the receive channel"s);
    }

    mController = std::move(controller);
    mPollFdThread = &pollFdThread;
    mDisplayEventConnection = std::move(displayEventConnection);
    mDataChannel = std::move(dataChannel);
@@ -195,14 +203,38 @@ void DisplayEventReceiver::processReceivedEvents(std::span<Event> events) {
    }
}

auto DisplayEventReceiver::mapPhysicalDisplayIdToTestDisplayId(PhysicalDisplayId displayId)
        -> std::optional<core::DisplayConfiguration::Id> {
    auto controller = mController.lock();
    if (!controller) {
        LOG(WARNING) << "Unable to map physical displayId " << displayId
                     << " to a test display id. SFController gone.";
        return {};
    }

    auto testDisplayId = controller->mapPhysicalDisplayIdToTestDisplayId(displayId);
    if (!testDisplayId) {
        LOG(WARNING) << "Unable to map physical displayId " << displayId << " to a test display id";
        return {};
    }

    return testDisplayId;
}

void DisplayEventReceiver::onVsync(DisplayId displayId, Timestamp timestamp, uint32_t count,
                                   VsyncEventData vsyncData) {
    ftl::ignore(displayId, timestamp, count, vsyncData);
    LOG(VERBOSE) << "onVsync() display " << displayId << " timestamp "
                 << timestamp.time_since_epoch() << " count " << count;

    auto testDisplayId = mapPhysicalDisplayIdToTestDisplayId(displayId);
    if (!testDisplayId) {
        return;
    }

    mCallbacks.onVSyncTiming(events::VSyncTiming{
            .receiver = this,
            .displayId = *testDisplayId,
            .sfEventAt = timestamp,
            .count = count,
            .data = vsyncData,
@@ -216,9 +248,19 @@ void DisplayEventReceiver::onHotplug(DisplayId displayId, Timestamp timestamp, b
                 << timestamp.time_since_epoch() << " connected " << connected
                 << " connectionError " << connectionError;

    if (auto controller = mController.lock()) {
        controller->onDisplayConnectionChanged(displayId, connected);
    }

    auto testDisplayId = mapPhysicalDisplayIdToTestDisplayId(displayId);
    if (!testDisplayId) {
        return;
    }

    if (connectionError == 0) {
        mCallbacks.onHotplug(events::Hotplug{
                .receiver = this,
                .displayId = *testDisplayId,
                .sfEventAt = timestamp,
                .connected = connected,
        });
+14 −3
Original line number Diff line number Diff line
@@ -30,17 +30,20 @@
#include <binder/IBinder.h>
#include <ftl/finalizer.h>
#include <ftl/flags.h>
#include <ftl/function.h>
#include <gui/DisplayEventReceiver.h>
#include <gui/VsyncEventData.h>
#include <ui/DisplayId.h>
#include <utils/StrongPointer.h>

#include "test_framework/core/DisplayConfiguration.h"
#include "test_framework/surfaceflinger/PollFdThread.h"
#include "test_framework/surfaceflinger/events/Hotplug.h"
#include "test_framework/surfaceflinger/events/VSyncTiming.h"

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

class SFController;
class PollFdThread;

class DisplayEventReceiver final {
@@ -58,9 +61,13 @@ class DisplayEventReceiver final {
        events::Hotplug::AsyncConnector onHotplug;
    };

    using PhysicalIdToTestDisplayId = ftl::Function<
            auto(PhysicalDisplayId)->std::optional<test_framework::core::DisplayConfiguration::Id>>;

    [[nodiscard]] static auto make(
            const sp<gui::ISurfaceComposer>& client, PollFdThread& pollFdThread,
            gui::ISurfaceComposer::VsyncSource source, const sp<IBinder>& layerHandle,
            std::weak_ptr<SFController> controller, const sp<gui::ISurfaceComposer>& client,
            PollFdThread& pollFdThread, gui::ISurfaceComposer::VsyncSource source,
            const sp<IBinder>& layerHandle,
            const ftl::Flags<gui::ISurfaceComposer::EventRegistration>& events)
            -> base::expected<std::shared_ptr<DisplayEventReceiver>, std::string>;

@@ -86,7 +93,8 @@ class DisplayEventReceiver final {
    using Timestamp = std::chrono::steady_clock::time_point;
    using VsyncEventData = android::VsyncEventData;

    [[nodiscard]] auto init(const sp<gui::ISurfaceComposer>& client, PollFdThread& pollFdThread,
    [[nodiscard]] auto init(std::weak_ptr<SFController> controller,
                            const sp<gui::ISurfaceComposer>& client, PollFdThread& pollFdThread,
                            gui::ISurfaceComposer::VsyncSource source,
                            const sp<IBinder>& layerHandle,
                            const ftl::Flags<gui::ISurfaceComposer::EventRegistration>& events)
@@ -94,6 +102,8 @@ class DisplayEventReceiver final {

    void processReceivedEvents();
    void processReceivedEvents(std::span<Event> events);
    auto mapPhysicalDisplayIdToTestDisplayId(PhysicalDisplayId displayId)
            -> std::optional<core::DisplayConfiguration::Id>;
    void onVsync(DisplayId displayId, Timestamp timestamp, uint32_t count,
                 VsyncEventData vsyncData);
    void onHotplug(DisplayId displayId, Timestamp timestamp, bool connected,
@@ -105,6 +115,7 @@ class DisplayEventReceiver final {
    static void onHdcpLevelsChange(DisplayId displayId, Timestamp timestamp, int32_t connectedLevel,
                                   int32_t maxLevel);

    std::weak_ptr<SFController> mController;
    Callbacks mCallbacks;

    sp<gui::IDisplayEventConnection> mDisplayEventConnection;
+82 −7
Original line number Diff line number Diff line
@@ -15,15 +15,20 @@
 */

#include <chrono>
#include <cstdint>
#include <cstdlib>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
#include <thread>
#include <utility>
#include <vector>

#include <android-base/expected.h>
#include <android-base/logging.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <android/gui/ISurfaceComposer.h>
#include <binder/IBinder.h>
@@ -31,13 +36,16 @@
#include <binder/IServiceManager.h>
#include <binder/Status.h>
#include <ftl/finalizer.h>
#include <ftl/flags.h>
#include <ftl/ignore.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <ui/DisplayId.h>
#include <utils/String16.h>
#include <utils/String8.h>
#include <utils/StrongPointer.h>

#include "test_framework/core/DisplayConfiguration.h"
#include "test_framework/surfaceflinger/DisplayEventReceiver.h"
#include "test_framework/surfaceflinger/PollFdThread.h"
#include "test_framework/surfaceflinger/SFController.h"
@@ -101,9 +109,9 @@ auto SFController::init() -> base::expected<void, std::string> {
    using namespace std::string_literals;

    LOG(INFO) << "Stopping everything to prepare for tests";
    // NOLINTBEGIN(cert-env33-c)
    // NOLINTBEGIN(cert-env33-c, concurrency-mt-unsafe)
    system("stop");
    // NOLINTEND(cert-env33-c)
    // NOLINTEND(cert-env33-c, concurrency-mt-unsafe)

    auto pollFdThreadResult = PollFdThread::make();
    if (!pollFdThreadResult) {
@@ -140,9 +148,21 @@ auto SFController::startAndConnect() -> base::expected<void, std::string> {
                "Failed to construct a surfaceComposerClient around the aidl interface."s);
    }

    // We need an internal display event receiver so we can listen for hotplug events.
    auto displayEventReceiverResult = DisplayEventReceiver::make(
            shared_from_this(), surfaceComposerAidl, *mPollFdThread,
            gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, nullptr, {});
    if (!displayEventReceiverResult) {
        return base::unexpected(std::move(displayEventReceiverResult).error());
    }
    auto displayEventReceiver = *std::move(displayEventReceiverResult);

    mSurfaceComposerAidl = std::move(surfaceComposerAidl);
    mSurfaceComposerClientAidl = std::move(surfaceComposerClientAidl);
    mSurfaceComposerClient = std::move(surfaceComposerClient);
    mDisplayEventReceiver = std::move(displayEventReceiver);

    initializeDisplayIdMapping();

    LOG(INFO) << "Connected to surfaceflinger";
    return {};
@@ -150,16 +170,16 @@ auto SFController::startAndConnect() -> base::expected<void, std::string> {

void SFController::start() {
    LOG(INFO) << "Starting surfaceflinger";
    // NOLINTBEGIN(cert-env33-c)
    // NOLINTBEGIN(cert-env33-c, concurrency-mt-unsafe)
    system("start surfaceflinger");
    // NOLINTEND(cert-env33-c)
    // NOLINTEND(cert-env33-c, concurrency-mt-unsafe)
}

void SFController::stop() {
    LOG(INFO) << "Stopping surfaceflinger";
    // NOLINTBEGIN(cert-env33-c)
    // NOLINTBEGIN(cert-env33-c, concurrency-mt-unsafe)
    system("stop surfaceflinger");
    // NOLINTEND(cert-env33-c)
    // NOLINTEND(cert-env33-c, concurrency-mt-unsafe)

    if (mSurfaceComposerAidl != nullptr) {
        LOG(INFO) << "Waiting for SF AIDL interface to die";
@@ -184,6 +204,7 @@ void SFController::stop() {
        std::this_thread::sleep_for(kShutdownWait);
    }

    mDisplayEventReceiver = nullptr;
    mSurfaceComposerClient = nullptr;
    mSurfaceComposerClientAidl = nullptr;
    mSurfaceComposerAidl = nullptr;
@@ -192,7 +213,7 @@ void SFController::stop() {
auto SFController::makeDisplayEventReceiver()
        -> base::expected<std::shared_ptr<DisplayEventReceiver>, std::string> {
    CHECK(mSurfaceComposerAidl != nullptr);
    return DisplayEventReceiver::make(mSurfaceComposerAidl, *mPollFdThread,
    return DisplayEventReceiver::make(shared_from_this(), mSurfaceComposerAidl, *mPollFdThread,
                                      gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, nullptr,
                                      {gui::ISurfaceComposer::EventRegistration::frameRateOverride,
                                       gui::ISurfaceComposer::EventRegistration::modeChanged});
@@ -204,4 +225,58 @@ auto SFController::makeSurface(const Surface::CreationArgs& args)
    return Surface::make(mSurfaceComposerClient, args);
}

auto SFController::mapPhysicalDisplayIdToTestDisplayId(PhysicalDisplayId displayId)
        -> std::optional<core::DisplayConfiguration::Id> {
    const std::lock_guard lock(mMutex);
    auto iter = mPhysicalDisplayIdToTestDisplayId.find(displayId);
    return (iter != mPhysicalDisplayIdToTestDisplayId.end()) ? std::make_optional(iter->second)
                                                             : std::nullopt;
}

void SFController::addDisplayIdToMapping(PhysicalDisplayId displayId) {
    gui::StaticDisplayInfo staticInfo;
    CHECK(mSurfaceComposerAidl->getStaticDisplayInfo(displayId.value, &staticInfo).isOk());

    auto name = staticInfo.deviceProductInfo.and_then(
            [](const auto& info) -> std::optional<std::string> { return info.name; });

    constexpr std::string kMagicPrefix = "fake";
    if (!name || !name->starts_with(kMagicPrefix)) {
        LOG(ERROR) << "Unexpected: physical display id " << displayId
                   << " is not a test fake display: " << name.value_or("<missing>");
        return;
    }

    auto remainder = name->substr(kMagicPrefix.size());

    uint32_t testId = 0;
    if (!android::base::ParseUint(remainder.c_str(), &testId)) {
        LOG(ERROR) << "Failed to parse as int: " << remainder;
        return;
    }

    const std::lock_guard lock(mMutex);
    mPhysicalDisplayIdToTestDisplayId[displayId] = testId;
}

void SFController::onDisplayConnectionChanged(PhysicalDisplayId displayId, bool connected) {
    if (connected) {
        addDisplayIdToMapping(displayId);
    } else {
        const std::lock_guard lock(mMutex);
        mPhysicalDisplayIdToTestDisplayId.erase(displayId);
    }
}

void SFController::initializeDisplayIdMapping() {
    CHECK(mSurfaceComposerAidl);

    std::vector<int64_t> rawDisplayIds;
    CHECK(mSurfaceComposerAidl->getPhysicalDisplayIds(&rawDisplayIds).isOk());

    for (auto displayIdValue : rawDisplayIds) {
        addDisplayIdToMapping(PhysicalDisplayId::fromValue(displayIdValue));
    }
}

}  // namespace android::surfaceflinger::tests::end2end::test_framework::surfaceflinger
+19 −1
Original line number Diff line number Diff line
@@ -17,13 +17,20 @@
#pragma once

#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <string_view>
#include <unordered_map>

#include <android-base/expected.h>
#include <android-base/thread_annotations.h>
#include <ftl/finalizer.h>
#include <ui/DisplayId.h>
#include <utils/Mutex.h>
#include <utils/StrongPointer.h>

#include "test_framework/core/DisplayConfiguration.h"
#include "test_framework/surfaceflinger/PollFdThread.h"
#include "test_framework/surfaceflinger/Surface.h"

@@ -45,7 +52,7 @@ namespace android::surfaceflinger::tests::end2end::test_framework::surfaceflinge
class DisplayEventReceiver;
class PollFdThread;

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

  public:
@@ -66,15 +73,26 @@ class SFController final {
    auto makeSurface(const Surface::CreationArgs& args)
            -> base::expected<std::shared_ptr<Surface>, std::string>;

    void onDisplayConnectionChanged(PhysicalDisplayId displayId, bool connected);
    auto mapPhysicalDisplayIdToTestDisplayId(PhysicalDisplayId displayId)
            -> std::optional<core::DisplayConfiguration::Id>;

  private:
    [[nodiscard]] auto init() -> base::expected<void, std::string>;
    static void start();
    void stop();
    void initializeDisplayIdMapping();
    void addDisplayIdToMapping(PhysicalDisplayId displayId);

    std::shared_ptr<PollFdThread> mPollFdThread;
    sp<gui::ISurfaceComposer> mSurfaceComposerAidl;
    sp<gui::ISurfaceComposerClient> mSurfaceComposerClientAidl;
    sp<SurfaceComposerClient> mSurfaceComposerClient;
    std::shared_ptr<DisplayEventReceiver> mDisplayEventReceiver;

    mutable std::mutex mMutex;
    std::unordered_map<PhysicalDisplayId, core::DisplayConfiguration::Id>
            mPhysicalDisplayIdToTestDisplayId GUARDED_BY(mMutex);

    // Finalizers should be last so their destructors are invoked first.
    ftl::FinalizerFtl mCleanup;