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

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

Snap for 13914092 from 008621be to 25Q4-release

Change-Id: I17d6147af1a640b5016b597eb0f495127c9e9b89
parents 10b48b16 008621be
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -65,6 +65,11 @@ cc_test {
    tidy_flags: [
        "--config=", // Use the .clang-tidy closest to each source file for the configuration
    ],
    tidy_checks: [
        // Disable this check, as currently it is triggering (as an error) on fields deep in
        // fmtlib's internal `compile_parse_context` are not being initialized by the ctor.
        "-clang-analyzer-optin.cplusplus.UninitializedObject",
    ],
    tidy_checks_as_errors: [
        "*",
    ],
+96 −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 <array>
#include <cstdlib>
#include <string_view>
#include <tuple>
#include <utility>

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

class TypeNameOf {
    template <typename T>
    static consteval auto pretty() -> std::string_view {
        return __PRETTY_FUNCTION__;
    }

    static consteval auto trim(std::string_view name) -> std::string_view {
        constexpr std::string_view expected = "std::string_view";
        constexpr std::string_view ref = pretty<std::string_view>();
        constexpr size_t prefixLength = ref.rfind(expected);
        static_assert(prefixLength != std::string_view::npos);
        constexpr size_t suffixLength = ref.size() - prefixLength - expected.size();
        static_assert(prefixLength + suffixLength + expected.size() == ref.size());

        return name.substr(prefixLength, name.size() - suffixLength - prefixLength);
    }

    static consteval auto trimNamespace(std::string_view name) -> std::string_view {
        if (auto prefix = name.rfind("::"); prefix != std::string_view::npos) {
            name = name.substr(prefix + 2);
        }
        return name;
    }

    template <size_t... Indices>
    static consteval auto copy(std::string_view input, std::index_sequence<Indices...> sequence)
            -> std::array<char, 1 + sizeof...(Indices)> {
        std::ignore = sequence;
        return {input[Indices]..., 0};
    }

  public:
    template <typename T>
    static consteval auto fullyQualifiedName() -> std::string_view {
        constexpr auto name = trim(pretty<T>());
        static constexpr auto copied = copy(name, std::make_index_sequence<name.size()>{});
        return copied.data();
    }

    template <typename T>
    static consteval auto shortName() -> std::string_view {
        constexpr auto name = trimNamespace(trim(pretty<T>()));
        static constexpr auto copied = copy(name, std::make_index_sequence<name.size()>{});
        return copied.data();
    }
};

}  // namespace detail

template <typename T>
consteval auto typeNameOf() -> std::string_view {
    static constexpr auto name = detail::TypeNameOf::fullyQualifiedName<T>();
    return name;
}

template <typename T>
consteval auto shortTypeNameOf() -> std::string_view {
    static constexpr auto name = detail::TypeNameOf::shortName<T>();
    return name;
}

static_assert(typeNameOf<std::string_view>() == "std::string_view");
static_assert(typeNameOf<detail::TypeNameOf>() ==
              "android::surfaceflinger::tests::end2end::test_framework::core::detail::TypeNameOf");

static_assert(shortTypeNameOf<std::string_view>() == "string_view");
static_assert(shortTypeNameOf<detail::TypeNameOf>() == "TypeNameOf");

}  // namespace android::surfaceflinger::tests::end2end::test_framework::core
+5 −41
Original line number Diff line number Diff line
@@ -15,7 +15,6 @@
 */

#include <algorithm>
#include <array>
#include <chrono>
#include <cstddef>
#include <cstdint>
@@ -47,6 +46,7 @@
#include <utils/Mutex.h>

#include "test_framework/core/BufferId.h"
#include "test_framework/core/ConstevaledTypeName.h"
#include "test_framework/hwc3/Hwc3Controller.h"
#include "test_framework/hwc3/ObservingComposer.h"
#include "test_framework/hwc3/delegators/Composer.h"
@@ -72,42 +72,6 @@ using aidl::android::hardware::graphics::composer3::PowerMode;

namespace {

class InterfaceName {
    template <typename T>
    static consteval auto pretty() -> std::string_view {
        return __PRETTY_FUNCTION__;
    }

    static consteval auto trim(std::string_view name) -> std::string_view {
        constexpr std::string_view expected = "std::string_view";
        constexpr std::string_view ref = pretty<std::string_view>();
        constexpr size_t prefixLength = ref.rfind(expected);
        static_assert(prefixLength != std::string_view::npos);
        constexpr size_t suffixLength = ref.size() - prefixLength - expected.size();
        static_assert(prefixLength + suffixLength + expected.size() == ref.size());

        return name.substr(prefixLength, name.size() - suffixLength - prefixLength);
    }

    template <size_t... Indices>
    static consteval auto copy(std::string_view input, std::index_sequence<Indices...> sequence)
            -> std::array<char, 1 + sizeof...(Indices)> {
        ftl::ignore(sequence);
        return {input[Indices]..., 0};
    }

    template <typename T>
    static consteval auto operator()() -> std::string_view {
        constexpr auto name = trim(pretty<T>());
        static constexpr auto copied = copy(name, std::make_index_sequence<name.size()>{});
        return copied.data();
    }

  public:
    template <typename T>
    static constexpr auto value = operator()<T>();
};

// Implements a generic forwarder for an interface, given also an matching delegator.
template <typename Interface, template <typename> typename Delegator, bool VersionMustMatch = true>
struct Forwarder : public Delegator<Forwarder<Interface, Delegator, VersionMustMatch>> {
@@ -124,14 +88,14 @@ struct Forwarder : public Delegator<Forwarder<Interface, Delegator, VersionMustM
                return base::unexpected(fmt::format(
                        "{} forwarding interface version mismatch. Destination uses {}, "
                        "forwarder uses {}, and they must be the same.",
                        InterfaceName::value<Interface>, destinationVersion, Interface::version));
                        core::typeNameOf<Interface>(), destinationVersion, Interface::version));
            }
        } else {
            if (destinationVersion < Interface::version) {
                return base::unexpected(fmt::format(
                        "{} forwarding interface version mismatch. Destination uses {}, "
                        "forwarder uses {} and must not be newer.",
                        InterfaceName::value<Interface>, destinationVersion, Interface::version));
                        core::typeNameOf<Interface>(), destinationVersion, Interface::version));
            }
        }

@@ -186,8 +150,8 @@ struct ComposerClientObserver final : public ComposerClientForwarder {

        // begin IComposerCallback overrides

        auto onVsync(int64_t in_display, int64_t in_timestamp,
                     int32_t in_vsyncPeriodNanos) -> ::ndk::ScopedAStatus override {
        auto onVsync(int64_t in_display, int64_t in_timestamp, int32_t in_vsyncPeriodNanos)
                -> ::ndk::ScopedAStatus override {
            if (auto controller = mController.lock()) {
                controller->callbacks().onVSyncCallbackSent(events::VSync{
                        .displayId = in_display,
+1 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#pragma once

#include <chrono>
#include <string>

#include <fmt/chrono.h>  // NOLINT(misc-include-cleaner)
#include <fmt/format.h>
+65 −26
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#include "test_framework/surfaceflinger/SimpleBufferPool.h"
#include "test_framework/surfaceflinger/Surface.h"
#include "test_framework/surfaceflinger/events/BufferReleased.h"
#include "test_framework/surfaceflinger/events/TransactionCommitted.h"
#include "test_framework/surfaceflinger/events/TransactionCompleted.h"
#include "test_framework/surfaceflinger/events/TransactionInitiated.h"

@@ -70,8 +71,8 @@ Surface::Surface(Passkey passkey) {
    ftl::ignore(passkey);
}

auto Surface::init(const sp<SurfaceComposerClient>& flinger,
                   const Surface::CreationArgs& args) -> base::expected<void, std::string> {
auto Surface::init(const sp<SurfaceComposerClient>& flinger, const Surface::CreationArgs& args)
        -> base::expected<void, std::string> {
    using namespace std::string_literals;

    constexpr auto kFlags = gui::ISurfaceComposerClient::eOpaque;
@@ -121,30 +122,57 @@ auto Surface::commitNextBuffer() -> uint64_t {

    commitBufferInternal(
            frameNumber, buffer,
            /* buffer release */
            [weak = weak_from_this(), buffer, bufferId, frameNumber](
                    const ReleaseCallbackId& callbackId, const sp<Fence>& releaseFence,
                    std::optional<uint32_t> currentMaxAcquiredBufferCount) {
                ftl::ignore(callbackId, releaseFence, currentMaxAcquiredBufferCount);
                if (auto self = weak.lock()) {
                    self->onBufferRelease(frameNumber, buffer, bufferId);
                    self->onBufferRelease(
                            events::BufferReleased{
                                    .surfaceId = self->id(),
                                    .frameNumber = frameNumber,
                                    .bufferId = bufferId,
                            },
                            buffer);
                } else {
                    LOG(DEBUG) << "Target surface for buffer release callback is dead";
                }
            },
            /* committed */
            [weak = weak_from_this(), frameNumber, bufferId](
                    void* context, nsecs_t latchTime, const sp<Fence>& presentFence,
                    const std::vector<SurfaceControlStats>& stats) {
                ftl::ignore(context, presentFence, stats);
                if (auto self = weak.lock()) {
                    self->onTransactionCommitted(events::TransactionCommitted{
                            .surfaceId = self->id(),
                            .frameNumber = frameNumber,
                            .bufferId = bufferId,
                            .latchTime = Timestamp(std::chrono::nanoseconds(latchTime))});
                } else {
                    LOG(DEBUG) << "Target surface for transaction committed callback is dead.";
                }
            },
            /* completed */
            [weak = weak_from_this(), frameNumber, bufferId](
                    void* context, nsecs_t latchTime, const sp<Fence>& presentFence,
                    const std::vector<SurfaceControlStats>& stats) {
                ftl::ignore(context, presentFence, stats);
                if (auto self = weak.lock()) {
                    const auto timestamp = Timestamp(std::chrono::nanoseconds(latchTime));
                    self->onTransactionCompleted(frameNumber, bufferId, timestamp);
                    self->onTransactionCompleted(events::TransactionCompleted{
                            .surfaceId = self->id(),
                            .frameNumber = frameNumber,
                            .bufferId = bufferId,
                            .latchTime = Timestamp(std::chrono::nanoseconds(latchTime))});
                } else {
                    LOG(DEBUG) << "Target surface for transaction completed callback is dead.";
                }
            });

    mCallbacks.onTransactionInitiated(events::TransactionInitiated{
            .surface = this,
    onTransactionInitiated(events::TransactionInitiated{
            .surfaceId = id(),
            .frameNumber = frameNumber,
            .bufferId = bufferId,
    });
@@ -155,6 +183,7 @@ auto Surface::commitNextBuffer() -> uint64_t {
void Surface::commitBufferInternal(
        uint64_t frameNumber, const sp<GraphicBuffer>& buffer,
        ReleaseBufferCallback releaseCallback,
        TransactionCompletedCallbackTakesContext transactionCommittedCallback,
        TransactionCompletedCallbackTakesContext transactionCompletedCallback) {
    SurfaceComposerClient::Transaction transaction;

@@ -166,6 +195,8 @@ void Surface::commitBufferInternal(
    transaction.setBuffer(mSurfaceControl, buffer, fence, frameNumber, producerId,
                          std::move(releaseCallback));

    transaction.addTransactionCommittedCallback(std::move(transactionCommittedCallback), nullptr);

    // Note: transaction.setBuffer() internally and unconditionally sets a no-op transaction
    // completion callback. We must set ours AFTER that call, not before.
    transaction.addTransactionCompletedCallback(std::move(transactionCompletedCallback), nullptr);
@@ -173,28 +204,31 @@ void Surface::commitBufferInternal(
    transaction.apply();
}

void Surface::onBufferRelease(uint64_t frameNumber, sp<GraphicBuffer> buffer,
                              core::BufferId bufferId) {
    LOG(VERBOSE) << __func__ << " framenumber " << frameNumber << " buffer "
                 << (buffer ? buffer->getId() : 0);
    mBufferPool->enqueue(std::move(buffer));
    mCallbacks.onBufferReleased(events::BufferReleased{
            .surface = this,
            .frameNumber = frameNumber,
            .bufferId = bufferId,
    });
void Surface::onBufferRelease(const events::BufferReleased& event,
                              const sp<GraphicBuffer>& buffer) {
    mBufferPool->enqueue(buffer);

    LOG(VERBOSE) << __func__ << " " << toString(event);

    mCallbacks.onBufferReleased(event);
}

void Surface::onTransactionCompleted(uint64_t frameNumber, core::BufferId bufferId,
                                     Timestamp latchTime) {
    LOG(VERBOSE) << __func__ << " framenumber " << frameNumber << " latchTime "
                 << latchTime.time_since_epoch();
    mCallbacks.onTransactionCompleted(events::TransactionCompleted{
            .surface = this,
            .frameNumber = frameNumber,
            .bufferId = bufferId,
            .latchTime = latchTime,
    });
void Surface::onTransactionInitiated(const events::TransactionInitiated& event) const {
    LOG(VERBOSE) << __func__ << " " << toString(event);

    mCallbacks.onTransactionInitiated(event);
}

void Surface::onTransactionCommitted(const events::TransactionCommitted& event) const {
    LOG(VERBOSE) << __func__ << " " << toString(event);

    mCallbacks.onTransactionCommitted(event);
}

void Surface::onTransactionCompleted(const events::TransactionCompleted& event) const {
    LOG(VERBOSE) << __func__ << " " << toString(event);

    mCallbacks.onTransactionCompleted(event);
}

void Surface::ensureCallbacksCompletedBeforeShutdown() {
@@ -234,6 +268,11 @@ void Surface::ensureCallbacksCompletedBeforeShutdown() {
                // Note: We don't signal a promise as this doesn't actually seem to be invoked by
                // the next transaction!
            },
            [](void* context, nsecs_t latchTime, const sp<Fence>& presentFence,
               const std::vector<SurfaceControlStats>& stats) {
                ftl::ignore(context, latchTime, presentFence, stats);
                LOG(VERBOSE) << "first cleanup transaction committed";
            },
            [&firstTransactionPromise](void* context, nsecs_t latchTime,
                                       const sp<Fence>& presentFence,
                                       const std::vector<SurfaceControlStats>& stats) {
Loading