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

Commit 749dc49d authored by Anton Ivanov's avatar Anton Ivanov
Browse files

Add TransactionBarriers to TransactionState.

At the moment no validation is made in merge(), this may be revisisted
as the project takes shape.

Bug: 356936695
Test: unit
Flag: EXEMPT not yet used
Change-Id: Icb7dc6be5b043848c51ab0f0dc79aae19f5efb1c
parent 5881eeaf
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <gui/TransactionState.h>
#include <private/gui/ParcelUtils.h>
#include <algorithm>
#include <numeric>

namespace android {

@@ -86,6 +87,8 @@ status_t TransactionState::writeToParcel(Parcel* parcel) const {
        SAFE_PARCEL(d.write, *parcel);
    }

    SAFE_PARCEL(parcel->writeParcelableVector, mBarriers);

    return NO_ERROR;
}

@@ -142,6 +145,8 @@ status_t TransactionState::readFromParcel(const Parcel* parcel) {
        mDisplayStates.emplace_back(std::move(d));
    }

    mBarriers.clear();
    SAFE_PARCEL(parcel->readParcelableVector, &mBarriers);
    return NO_ERROR;
}

@@ -206,6 +211,21 @@ void TransactionState::merge(TransactionState&& other,

    mMergedTransactionIds.insert(mMergedTransactionIds.begin(), other.mId);

    mBarriers.insert(mBarriers.end(), std::make_move_iterator(other.mBarriers.begin()),
                     std::make_move_iterator(other.mBarriers.end()));
    if (mBarriers.size() > MAX_BARRIERS_LENGTH) {
        int numToRemove = mBarriers.size() - MAX_BARRIERS_LENGTH;
        std::string droppedBarriers =
                std::accumulate(mBarriers.begin(), mBarriers.begin() + numToRemove, std::string(),
                                [](std::string&& s,
                                   const gui::TransactionBarrier& barrier) -> std::string {
                                    s += barrier.toString() + ",";
                                    return s;
                                });
        ALOGE("Dropping %d transaction barriers: %s", numToRemove, droppedBarriers.c_str());
        mBarriers.erase(mBarriers.begin(), mBarriers.begin() + numToRemove);
    }

    other.clear();
}

@@ -235,6 +255,7 @@ void TransactionState::clear() {
    mEarlyWakeupInfos.clear();
    mComposerStates.clear();
    mDisplayStates.clear();
    mBarriers.clear();
}

layer_state_t* TransactionState::getLayerState(const sp<SurfaceControl>& sc) {
+28 −0
Original line number Diff line number Diff line
/**
 * Copyright (c) 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.
 */

package android.gui;

/** @hide */
parcelable TransactionBarrier {
    String barrierToken;
    enum BarrierKind  {
        KIND_INVALID,
        KIND_SIGNAL,
        KIND_WAIT,
    }
    BarrierKind kind;
}
+6 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#pragma once

#include <android/gui/FrameTimelineInfo.h>
#include <android/gui/TransactionBarrier.h>
#include <binder/Parcelable.h>
#include <gui/LayerState.h>

@@ -93,8 +94,12 @@ public:
    std::vector<gui::EarlyWakeupInfo> mEarlyWakeupInfos = {};
    std::vector<ComposerState> mComposerStates = {};
    std::vector<DisplayState> mDisplayStates = {};
    std::vector<gui::TransactionBarrier> mBarriers = {};

    // Keep track of the last MAX_BARRIERS_LENGTH transaction barriers.
    // Ordered most recently merged to least recently merged.
    static constexpr size_t MAX_BARRIERS_LENGTH = 10u;

private:
    // We keep track of the last MAX_MERGE_HISTORY_LENGTH merged transaction ids.
    // Ordered most recently merged to least recently merged.
    static constexpr size_t MAX_MERGE_HISTORY_LENGTH = 10u;
+57 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <gtest/gtest.h>
#include <unordered_map>
#include "android/gui/FocusRequest.h"
#include "android/gui/TransactionBarrier.h"
#include "binder/Binder.h"
#include "binder/Parcel.h"
#include "gtest/gtest.h"
@@ -29,6 +30,8 @@

namespace android {

using ::testing::Eq;

void sprintf(std::string& out, const char* format, ...) {
    va_list arg_list;
    va_start(arg_list, format);
@@ -83,11 +86,16 @@ void Compare(const TransactionListenerCallbacks& s1, const TransactionListenerCa
    EXPECT_EQ(s1.mFlattenedListenerCallbacks, s2.mFlattenedListenerCallbacks);
}

void Compare(const gui::TransactionBarrier& b1, const gui::TransactionBarrier& b2) {
    EXPECT_EQ(b1.barrierToken, b2.barrierToken);
    EXPECT_EQ(b1.kind, b2.kind);
}

void CompareComplex(const TransactionState& s1, const TransactionState& s2) {
    EXPECT_EQ(s1.mMergedTransactionIds, s2.mMergedTransactionIds);
    EXPECT_EQ(s1.mFrameTimelineInfo, s2.mFrameTimelineInfo);
    EXPECT_EQ(s1.mUncacheBuffers, s2.mUncacheBuffers);
    EXPECT_EQ(s1.mCallbacks, s2.mCallbacks);
    Compare(s1.mCallbacks, s2.mCallbacks);
    EXPECT_EQ(s1.mInputWindowCommands, s2.mInputWindowCommands);
    EXPECT_EQ(s1.mDisplayStates.size(), s2.mDisplayStates.size());
    for (size_t i = 0; i < s1.mDisplayStates.size(); ++i) {
@@ -97,6 +105,11 @@ void CompareComplex(const TransactionState& s1, const TransactionState& s2) {
    for (size_t i = 0; i < s1.mComposerStates.size(); ++i) {
        EXPECT_EQ(s1.mComposerStates.at(i), s2.mComposerStates.at(i));
    }

    EXPECT_EQ(s1.mBarriers.size(), s2.mBarriers.size());
    for (size_t i = 0; i < s1.mBarriers.size(); ++i) {
        Compare(s1.mBarriers.at(i), s2.mBarriers.at(i));
    }
}

// In case EXPECT_EQ fails, this function is useful to pinpoint exactly which
@@ -183,7 +196,6 @@ TransactionState createTransactionStateForTest() {
    for (size_t i = 0; i < kMaxComposerStates; i++) {
        state.mComposerStates.push_back(createComposerStateForTest(i));
    }
    return state;

    return state;
}
@@ -194,6 +206,22 @@ TransactionState createEmptyTransaction(uint64_t id) {
    return state;
}

gui::TransactionBarrier createTransactionBarrier(std::string_view token,
                                                 gui::TransactionBarrier::BarrierKind kind) {
    gui::TransactionBarrier barrier;
    barrier.barrierToken = String16(token.data(), token.size());
    barrier.kind = kind;
    return barrier;
}

gui::TransactionBarrier createSignalBarrier(std::string_view token) {
    return createTransactionBarrier(token, gui::TransactionBarrier::BarrierKind::KIND_SIGNAL);
}

gui::TransactionBarrier createWaitBarrier(std::string_view token) {
    return createTransactionBarrier(token, gui::TransactionBarrier::BarrierKind::KIND_WAIT);
}

TEST(SimpleTransactionStateTest, parcel) {
    TransactionState state = createSimpleTransactionStateForTest();
    Parcel p;
@@ -206,6 +234,7 @@ TEST(SimpleTransactionStateTest, parcel) {

TEST(TransactionStateTest, parcel) {
    TransactionState state = createTransactionStateForTest();
    state.mBarriers.emplace_back(createSignalBarrier("sig"));
    Parcel p;
    state.writeToParcel(&p);
    p.setDataPosition(0);
@@ -287,6 +316,7 @@ TEST(TransactionStateTest, merge) {
    static constexpr uint64_t kUpdateTransactionId = 200;

    TransactionState state = createTransactionStateForTest();
    state.mBarriers.emplace_back(createSignalBarrier("sig"));

    TransactionState update;
    update.mId = kUpdateTransactionId;
@@ -303,6 +333,8 @@ TEST(TransactionStateTest, merge) {
        composerState.state.what = layer_state_t::eBufferChanged;
        update.mComposerStates.push_back(composerState);
    }
    update.mBarriers.emplace_back(
            createTransactionBarrier("wait", gui::TransactionBarrier::BarrierKind::KIND_WAIT));
    int32_t overrwiteLayerId = -1;
    auto updateCopy = update;
    // Mutation.
@@ -322,11 +354,34 @@ TEST(TransactionStateTest, merge) {
    // desired present time is not merged.
    expectedMergedState.mDesiredPresentTime = state.mDesiredPresentTime;

    expectedMergedState.mBarriers.emplace_back(createSignalBarrier("sig"));
    expectedMergedState.mBarriers.emplace_back(createWaitBarrier("wait"));

    EXPECT_EQ(state.mComposerStates[0], expectedMergedState.mComposerStates[0]);
    EXPECT_EQ(state.mInputWindowCommands, expectedMergedState.mInputWindowCommands);
    EXPECT_EQ(state, expectedMergedState);
};

TEST(TransactionStateTest, mergeMoreThanMaxBarriers) {
    TransactionState state = createTransactionStateForTest();
    for (size_t i = 0; i < TransactionState::MAX_BARRIERS_LENGTH; ++i) {
        std::string token = std::format("sig{}", i);
        state.mBarriers.emplace_back(createSignalBarrier(token));
    }

    TransactionState update;
    update.mId = 200;
    update.mBarriers.emplace_back(createWaitBarrier("wait"));

    state.merge(std::move(update), [](layer_state_t) {});

    EXPECT_EQ(TransactionState::MAX_BARRIERS_LENGTH, state.mBarriers.size());
    EXPECT_THAT(state.mBarriers.front().toString(),
                Eq("TransactionBarrier{barrierToken: sig1, kind: KIND_SIGNAL}"));
    EXPECT_THAT(state.mBarriers.back().toString(),
                Eq("TransactionBarrier{barrierToken: wait, kind: KIND_WAIT}"));
}

TEST(TransactionStateTest, clear) {
    TransactionState state = createTransactionStateForTest();
    state.clear();