Skip to content

Commit 15bfd3d

Browse files
author
Anton Ivanov
committed
Introduce TransactionState.
Encapsulate all the data inside transaction that we need to pass into SurfaceFlinger. This will remove some duplicate parcelling logic and clean up the interface into SF. Flag: EXEMPT refactor Bug: 385156191 Test: presubmit Change-Id: Ia6fab8539e48900700524a127cbcbbebd9acaf7a
1 parent 2f70649 commit 15bfd3d

5 files changed

Lines changed: 643 additions & 0 deletions

File tree

libs/gui/Android.bp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ filegroup {
281281
"SurfaceControl.cpp",
282282
"SurfaceComposerClient.cpp",
283283
"SyncFeatures.cpp",
284+
"TransactionState.cpp",
284285
"VsyncEventData.cpp",
285286
"view/Surface.cpp",
286287
"WindowInfosListenerReporter.cpp",

libs/gui/TransactionState.cpp

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
/*
2+
* Copyright (C) 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#define LOG_TAG "TransactionState"
18+
#include <gui/LayerState.h>
19+
#include <gui/SurfaceComposerClient.h>
20+
#include <gui/TransactionState.h>
21+
#include <private/gui/ParcelUtils.h>
22+
#include <algorithm>
23+
24+
namespace android {
25+
26+
status_t TransactionState::writeToParcel(Parcel* parcel) const {
27+
SAFE_PARCEL(parcel->writeUint64, mId);
28+
SAFE_PARCEL(parcel->writeUint32, mFlags);
29+
SAFE_PARCEL(parcel->writeInt64, mDesiredPresentTime);
30+
SAFE_PARCEL(parcel->writeBool, mIsAutoTimestamp);
31+
SAFE_PARCEL(parcel->writeParcelable, mFrameTimelineInfo);
32+
SAFE_PARCEL(parcel->writeStrongBinder, mApplyToken);
33+
SAFE_PARCEL(parcel->writeBool, mMayContainBuffer);
34+
SAFE_PARCEL(parcel->writeBool, mLogCallPoints);
35+
36+
SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mDisplayStates.size()));
37+
for (auto const& displayState : mDisplayStates) {
38+
displayState.write(*parcel);
39+
}
40+
SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mComposerStates.size()));
41+
for (auto const& composerState : mComposerStates) {
42+
composerState.write(*parcel);
43+
}
44+
45+
mInputWindowCommands.write(*parcel);
46+
SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mUncacheBuffers.size()));
47+
for (const client_cache_t& uncacheBuffer : mUncacheBuffers) {
48+
SAFE_PARCEL(parcel->writeStrongBinder, uncacheBuffer.token.promote());
49+
SAFE_PARCEL(parcel->writeUint64, uncacheBuffer.id);
50+
}
51+
52+
SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mMergedTransactionIds.size()));
53+
for (auto mergedTransactionId : mMergedTransactionIds) {
54+
SAFE_PARCEL(parcel->writeUint64, mergedTransactionId);
55+
}
56+
57+
SAFE_PARCEL(parcel->writeBool, mHasListenerCallbacks);
58+
SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mListenerCallbacks.size()));
59+
for (const auto& [listener, callbackIds] : mListenerCallbacks) {
60+
SAFE_PARCEL(parcel->writeStrongBinder, listener);
61+
SAFE_PARCEL(parcel->writeParcelableVector, callbackIds);
62+
}
63+
64+
return NO_ERROR;
65+
}
66+
67+
status_t TransactionState::readFromParcel(const Parcel* parcel) {
68+
SAFE_PARCEL(parcel->readUint64, &mId);
69+
SAFE_PARCEL(parcel->readUint32, &mFlags);
70+
SAFE_PARCEL(parcel->readInt64, &mDesiredPresentTime);
71+
SAFE_PARCEL(parcel->readBool, &mIsAutoTimestamp);
72+
SAFE_PARCEL(parcel->readParcelable, &mFrameTimelineInfo);
73+
SAFE_PARCEL(parcel->readNullableStrongBinder, &mApplyToken);
74+
SAFE_PARCEL(parcel->readBool, &mMayContainBuffer);
75+
SAFE_PARCEL(parcel->readBool, &mLogCallPoints);
76+
77+
uint32_t count;
78+
SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize())
79+
mDisplayStates.clear();
80+
mDisplayStates.reserve(count);
81+
for (size_t i = 0; i < count; i++) {
82+
DisplayState displayState;
83+
if (displayState.read(*parcel) == BAD_VALUE) {
84+
return BAD_VALUE;
85+
}
86+
mDisplayStates.emplace_back(std::move(displayState));
87+
}
88+
89+
SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize())
90+
mComposerStates.clear();
91+
mComposerStates.reserve(count);
92+
for (size_t i = 0; i < count; i++) {
93+
ComposerState composerState;
94+
if (composerState.read(*parcel) == BAD_VALUE) {
95+
return BAD_VALUE;
96+
}
97+
mComposerStates.emplace_back(std::move(composerState));
98+
}
99+
100+
if (status_t status = mInputWindowCommands.read(*parcel) != NO_ERROR) {
101+
return status;
102+
}
103+
104+
SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize())
105+
mUncacheBuffers.clear();
106+
mUncacheBuffers.reserve(count);
107+
for (size_t i = 0; i < count; i++) {
108+
client_cache_t client_cache;
109+
sp<IBinder> tmpBinder;
110+
SAFE_PARCEL(parcel->readStrongBinder, &tmpBinder);
111+
client_cache.token = tmpBinder;
112+
SAFE_PARCEL(parcel->readUint64, &client_cache.id);
113+
mUncacheBuffers.emplace_back(std::move(client_cache));
114+
}
115+
116+
SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize())
117+
mMergedTransactionIds.clear();
118+
mMergedTransactionIds.resize(count);
119+
for (size_t i = 0; i < count; i++) {
120+
SAFE_PARCEL(parcel->readUint64, &mMergedTransactionIds[i]);
121+
}
122+
123+
SAFE_PARCEL(parcel->readBool, &mHasListenerCallbacks);
124+
SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize());
125+
mListenerCallbacks.clear();
126+
mListenerCallbacks.reserve(count);
127+
for (uint32_t i = 0; i < count; i++) {
128+
sp<IBinder> tmpBinder;
129+
SAFE_PARCEL(parcel->readStrongBinder, &tmpBinder);
130+
std::vector<CallbackId> callbackIds;
131+
SAFE_PARCEL(parcel->readParcelableVector, &callbackIds);
132+
mListenerCallbacks.emplace_back(tmpBinder, callbackIds);
133+
}
134+
135+
return NO_ERROR;
136+
}
137+
138+
void TransactionState::merge(TransactionState&& other,
139+
const std::function<void(layer_state_t&)>& onBufferOverwrite) {
140+
while (mMergedTransactionIds.size() + other.mMergedTransactionIds.size() >
141+
MAX_MERGE_HISTORY_LENGTH - 1 &&
142+
mMergedTransactionIds.size() > 0) {
143+
mMergedTransactionIds.pop_back();
144+
}
145+
if (other.mMergedTransactionIds.size() == MAX_MERGE_HISTORY_LENGTH) {
146+
mMergedTransactionIds.insert(mMergedTransactionIds.begin(),
147+
other.mMergedTransactionIds.begin(),
148+
other.mMergedTransactionIds.end() - 1);
149+
} else if (other.mMergedTransactionIds.size() > 0u) {
150+
mMergedTransactionIds.insert(mMergedTransactionIds.begin(),
151+
other.mMergedTransactionIds.begin(),
152+
other.mMergedTransactionIds.end());
153+
}
154+
mMergedTransactionIds.insert(mMergedTransactionIds.begin(), other.mId);
155+
156+
for (auto const& otherState : other.mComposerStates) {
157+
if (auto it = std::find_if(mComposerStates.begin(), mComposerStates.end(),
158+
[&otherState](const auto& composerState) {
159+
return composerState.state.surface ==
160+
otherState.state.surface;
161+
});
162+
it != mComposerStates.end()) {
163+
if (otherState.state.what & layer_state_t::eBufferChanged) {
164+
onBufferOverwrite(it->state);
165+
}
166+
it->state.merge(otherState.state);
167+
} else {
168+
mComposerStates.push_back(otherState);
169+
}
170+
}
171+
172+
for (auto const& state : other.mDisplayStates) {
173+
if (auto it = std::find_if(mDisplayStates.begin(), mDisplayStates.end(),
174+
[&state](const auto& displayState) {
175+
return displayState.token == state.token;
176+
});
177+
it != mDisplayStates.end()) {
178+
it->merge(state);
179+
} else {
180+
mDisplayStates.push_back(state);
181+
}
182+
}
183+
184+
for (const auto& cacheId : other.mUncacheBuffers) {
185+
mUncacheBuffers.push_back(cacheId);
186+
}
187+
188+
mInputWindowCommands.merge(other.mInputWindowCommands);
189+
// TODO(b/385156191) Consider merging desired present time.
190+
mFlags |= other.mFlags;
191+
mMayContainBuffer |= other.mMayContainBuffer;
192+
mLogCallPoints |= other.mLogCallPoints;
193+
194+
// mApplyToken is explicitly not merged. Token should be set before applying the transactions to
195+
// make synchronization decisions a bit simpler.
196+
mergeFrameTimelineInfo(other.mFrameTimelineInfo);
197+
other.clear();
198+
}
199+
200+
// copied from FrameTimelineInfo::merge()
201+
void TransactionState::mergeFrameTimelineInfo(const FrameTimelineInfo& other) {
202+
// When merging vsync Ids we take the oldest valid one
203+
if (mFrameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID &&
204+
other.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
205+
if (other.vsyncId > mFrameTimelineInfo.vsyncId) {
206+
mFrameTimelineInfo = other;
207+
}
208+
} else if (mFrameTimelineInfo.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) {
209+
mFrameTimelineInfo = other;
210+
}
211+
}
212+
213+
void TransactionState::clear() {
214+
mComposerStates.clear();
215+
mDisplayStates.clear();
216+
mListenerCallbacks.clear();
217+
mHasListenerCallbacks = false;
218+
mInputWindowCommands.clear();
219+
mUncacheBuffers.clear();
220+
mDesiredPresentTime = 0;
221+
mIsAutoTimestamp = true;
222+
mApplyToken = nullptr;
223+
mFrameTimelineInfo = {};
224+
mMergedTransactionIds.clear();
225+
mFlags = 0;
226+
mMayContainBuffer = false;
227+
mLogCallPoints = false;
228+
}
229+
230+
layer_state_t* TransactionState::getLayerState(const sp<SurfaceControl>& sc) {
231+
auto handle = sc->getLayerStateHandle();
232+
if (auto it = std::find_if(mComposerStates.begin(), mComposerStates.end(),
233+
[&handle](const auto& composerState) {
234+
return composerState.state.surface == handle;
235+
});
236+
it != mComposerStates.end()) {
237+
return &it->state;
238+
}
239+
240+
// we don't have it, add an initialized layer_state to our list
241+
ComposerState s;
242+
s.state.surface = handle;
243+
s.state.layerId = sc->getLayerId();
244+
mComposerStates.push_back(s);
245+
246+
return &mComposerStates.back().state;
247+
}
248+
249+
DisplayState& TransactionState::getDisplayState(const sp<IBinder>& token) {
250+
if (auto it = std::find_if(mDisplayStates.begin(), mDisplayStates.end(),
251+
[token](const auto& display) { return display.token == token; });
252+
it != mDisplayStates.end()) {
253+
return *it;
254+
}
255+
256+
// If display state doesn't exist, add a new one.
257+
DisplayState s;
258+
s.token = token;
259+
mDisplayStates.push_back(s);
260+
return mDisplayStates.back();
261+
}
262+
263+
}; // namespace android
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright (C) 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#pragma once
18+
19+
#include <android/gui/FrameTimelineInfo.h>
20+
#include <binder/Parcelable.h>
21+
#include <gui/LayerState.h>
22+
23+
namespace android {
24+
25+
// Class to store all the transaction data and the parcelling logic
26+
class TransactionState {
27+
public:
28+
explicit TransactionState() = default;
29+
TransactionState(TransactionState const& other) = default;
30+
status_t writeToParcel(Parcel* parcel) const;
31+
status_t readFromParcel(const Parcel* parcel);
32+
layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
33+
DisplayState& getDisplayState(const sp<IBinder>& token);
34+
35+
// Returns the current id of the transaction.
36+
// The id is updated every time the transaction is applied.
37+
uint64_t getId() const { return mId; }
38+
std::vector<uint64_t> getMergedTransactionIds() const { return mMergedTransactionIds; }
39+
void enableDebugLogCallPoints() { mLogCallPoints = true; }
40+
void merge(TransactionState&& other,
41+
const std::function<void(layer_state_t&)>& onBufferOverwrite);
42+
43+
// copied from FrameTimelineInfo::merge()
44+
void mergeFrameTimelineInfo(const FrameTimelineInfo& other);
45+
void clear();
46+
bool operator==(const TransactionState& rhs) const = default;
47+
bool operator!=(const TransactionState& rhs) const = default;
48+
49+
uint64_t mId = 0;
50+
std::vector<uint64_t> mMergedTransactionIds;
51+
uint32_t mFlags = 0;
52+
// The vsync id provided by Choreographer.getVsyncId and the input event id
53+
gui::FrameTimelineInfo mFrameTimelineInfo;
54+
// mDesiredPresentTime is the time in nanoseconds that the client would like the transaction
55+
// to be presented. When it is not possible to present at exactly that time, it will be
56+
// presented after the time has passed.
57+
//
58+
// If the client didn't pass a desired presentation time, mDesiredPresentTime will be
59+
// populated to the time setBuffer was called, and mIsAutoTimestamp will be set to true.
60+
//
61+
// Desired present times that are more than 1 second in the future may be ignored.
62+
// When a desired present time has already passed, the transaction will be presented as soon
63+
// as possible.
64+
//
65+
// Transactions from the same process are presented in the same order that they are applied.
66+
// The desired present time does not affect this ordering.
67+
int64_t mDesiredPresentTime = 0;
68+
bool mIsAutoTimestamp = true;
69+
// If not null, transactions will be queued up using this token otherwise a common token
70+
// per process will be used.
71+
sp<IBinder> mApplyToken;
72+
// Indicates that the Transaction may contain buffers that should be cached. The reason this
73+
// is only a guess is that buffers can be removed before cache is called. This is only a
74+
// hint that at some point a buffer was added to this transaction before apply was called.
75+
bool mMayContainBuffer = false;
76+
// Prints debug logs when enabled.
77+
bool mLogCallPoints = false;
78+
79+
std::vector<DisplayState> mDisplayStates;
80+
std::vector<ComposerState> mComposerStates;
81+
InputWindowCommands mInputWindowCommands;
82+
std::vector<client_cache_t> mUncacheBuffers;
83+
// Note: mHasListenerCallbacks can be true even if mListenerCallbacks is
84+
// empty.
85+
bool mHasListenerCallbacks = false;
86+
std::vector<ListenerCallbacks> mListenerCallbacks;
87+
88+
private:
89+
// We keep track of the last MAX_MERGE_HISTORY_LENGTH merged transaction ids.
90+
// Ordered most recently merged to least recently merged.
91+
static constexpr size_t MAX_MERGE_HISTORY_LENGTH = 10u;
92+
};
93+
94+
}; // namespace android

libs/gui/tests/Android.bp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ cc_test {
9090
"testserver/TestServerClient.cpp",
9191
"testserver/TestServerHost.cpp",
9292
"TextureRenderer.cpp",
93+
"TransactionState_test.cpp",
9394
"VsyncEventData_test.cpp",
9495
"WindowInfo_test.cpp",
9596
],

0 commit comments

Comments
 (0)