diff options
author | 2025-03-21 20:19:16 -0700 | |
---|---|---|
committer | 2025-03-21 20:19:16 -0700 | |
commit | ac284d4683e194b7a05800cf7fbd682972699faa (patch) | |
tree | 127a5fbd6bcbdf2c0c82207671a2b38c26c4991d | |
parent | a105c7bcfb6281b65d0384cf07a774a8235836fc (diff) | |
parent | 520d8fcb8aa54289f2272369d3040635c2fbd4bd (diff) |
Snap for 13256841 from 520d8fcb8aa54289f2272369d3040635c2fbd4bd to 25Q2-release
Change-Id: If86b3c2a4136267c7ea448cd178eb8744a9643fd
58 files changed, 959 insertions, 949 deletions
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 0cd87201fb..279a4ae35c 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -454,4 +454,6 @@ private: InputVerifier mInputVerifier; }; +std::ostream& operator<<(std::ostream& out, const InputMessage& msg); + } // namespace android diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 777c22a63e..2c37624304 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -542,7 +542,7 @@ status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) { return BAD_VALUE; } - if ((mDataSize+len) > mDataCapacity) { + if ((mDataPos + len) > mDataCapacity) { // grow data err = growData(len); if (err != NO_ERROR) { diff --git a/libs/binder/tests/binderParcelUnitTest.cpp b/libs/binder/tests/binderParcelUnitTest.cpp index 6259d9d2d2..a71da3f384 100644 --- a/libs/binder/tests/binderParcelUnitTest.cpp +++ b/libs/binder/tests/binderParcelUnitTest.cpp @@ -197,6 +197,17 @@ TEST(Parcel, AppendPlainDataPartial) { ASSERT_EQ(2, p2.readInt32()); } +TEST(Parcel, AppendWithBadDataPos) { + Parcel p1; + p1.writeInt32(1); + p1.writeInt32(1); + Parcel p2; + p2.setDataCapacity(8); + p2.setDataPosition(10000); + + EXPECT_EQ(android::BAD_VALUE, p2.appendFrom(&p1, 0, 8)); +} + TEST(Parcel, HasBinders) { sp<IBinder> b1 = sp<BBinder>::make(); diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 1aae13c1f4..5b0f21de91 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -1032,7 +1032,7 @@ void BLASTBufferQueue::mergeWithNextTransaction(SurfaceComposerClient::Transacti // Apply the transaction since we have already acquired the desired frame. t->setApplyToken(mApplyToken).apply(); } else { - mPendingTransactions.emplace_back(frameNumber, *t); + mPendingTransactions.emplace_back(frameNumber, std::move(*t)); // Clear the transaction so it can't be applied elsewhere. t->clear(); } @@ -1050,8 +1050,8 @@ void BLASTBufferQueue::applyPendingTransactions(uint64_t frameNumber) { void BLASTBufferQueue::mergePendingTransactions(SurfaceComposerClient::Transaction* t, uint64_t frameNumber) { auto mergeTransaction = - [&t, currentFrameNumber = frameNumber]( - std::tuple<uint64_t, SurfaceComposerClient::Transaction> pendingTransaction) { + [t, currentFrameNumber = frameNumber]( + std::pair<uint64_t, SurfaceComposerClient::Transaction>& pendingTransaction) { auto& [targetFrameNumber, transaction] = pendingTransaction; if (currentFrameNumber < targetFrameNumber) { return false; diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 269936858a..ae4b74e03b 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -26,6 +26,7 @@ #include <gui/ISurfaceComposer.h> #include <gui/LayerState.h> #include <gui/SchedulingPolicy.h> +#include <gui/TransactionState.h> #include <private/gui/ParcelUtils.h> #include <stdint.h> #include <sys/types.h> @@ -60,54 +61,12 @@ public: virtual ~BpSurfaceComposer(); - status_t setTransactionState( - const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& state, - Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, - InputWindowCommands commands, int64_t desiredPresentTime, bool isAutoTimestamp, - const std::vector<client_cache_t>& uncacheBuffers, bool hasListenerCallbacks, - const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId, - const std::vector<uint64_t>& mergedTransactionIds) override { + status_t setTransactionState(TransactionState&& state) override { Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + SAFE_PARCEL(state.writeToParcel, &data); - frameTimelineInfo.writeToParcel(&data); - - SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(state.size())); - for (const auto& s : state) { - SAFE_PARCEL(s.write, data); - } - - SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(displays.size())); - for (const auto& d : displays) { - SAFE_PARCEL(d.write, data); - } - - SAFE_PARCEL(data.writeUint32, flags); - SAFE_PARCEL(data.writeStrongBinder, applyToken); - SAFE_PARCEL(commands.write, data); - SAFE_PARCEL(data.writeInt64, desiredPresentTime); - SAFE_PARCEL(data.writeBool, isAutoTimestamp); - SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(uncacheBuffers.size())); - for (const client_cache_t& uncacheBuffer : uncacheBuffers) { - SAFE_PARCEL(data.writeStrongBinder, uncacheBuffer.token.promote()); - SAFE_PARCEL(data.writeUint64, uncacheBuffer.id); - } - SAFE_PARCEL(data.writeBool, hasListenerCallbacks); - - SAFE_PARCEL(data.writeVectorSize, listenerCallbacks); - for (const auto& [listener, callbackIds] : listenerCallbacks) { - SAFE_PARCEL(data.writeStrongBinder, listener); - SAFE_PARCEL(data.writeParcelableVector, callbackIds); - } - - SAFE_PARCEL(data.writeUint64, transactionId); - - SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(mergedTransactionIds.size())); - for (auto mergedTransactionId : mergedTransactionIds) { - SAFE_PARCEL(data.writeUint64, mergedTransactionId); - } - - if (flags & ISurfaceComposer::eOneWay) { + if (state.mFlags & ISurfaceComposer::eOneWay) { return remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply, IBinder::FLAG_ONEWAY); } else { @@ -132,75 +91,9 @@ status_t BnSurfaceComposer::onTransact( case SET_TRANSACTION_STATE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); - FrameTimelineInfo frameTimelineInfo; - frameTimelineInfo.readFromParcel(&data); - - uint32_t count = 0; - SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize()); - Vector<ComposerState> state; - state.setCapacity(count); - for (size_t i = 0; i < count; i++) { - ComposerState s; - SAFE_PARCEL(s.read, data); - state.add(s); - } - - SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize()); - DisplayState d; - Vector<DisplayState> displays; - displays.setCapacity(count); - for (size_t i = 0; i < count; i++) { - SAFE_PARCEL(d.read, data); - displays.add(d); - } - - uint32_t stateFlags = 0; - SAFE_PARCEL(data.readUint32, &stateFlags); - sp<IBinder> applyToken; - SAFE_PARCEL(data.readStrongBinder, &applyToken); - InputWindowCommands inputWindowCommands; - SAFE_PARCEL(inputWindowCommands.read, data); - - int64_t desiredPresentTime = 0; - bool isAutoTimestamp = true; - SAFE_PARCEL(data.readInt64, &desiredPresentTime); - SAFE_PARCEL(data.readBool, &isAutoTimestamp); - - SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize()); - std::vector<client_cache_t> uncacheBuffers(count); - sp<IBinder> tmpBinder; - for (size_t i = 0; i < count; i++) { - SAFE_PARCEL(data.readNullableStrongBinder, &tmpBinder); - uncacheBuffers[i].token = tmpBinder; - SAFE_PARCEL(data.readUint64, &uncacheBuffers[i].id); - } - - bool hasListenerCallbacks = false; - SAFE_PARCEL(data.readBool, &hasListenerCallbacks); - - std::vector<ListenerCallbacks> listenerCallbacks; - int32_t listenersSize = 0; - SAFE_PARCEL_READ_SIZE(data.readInt32, &listenersSize, data.dataSize()); - for (int32_t i = 0; i < listenersSize; i++) { - SAFE_PARCEL(data.readStrongBinder, &tmpBinder); - std::vector<CallbackId> callbackIds; - SAFE_PARCEL(data.readParcelableVector, &callbackIds); - listenerCallbacks.emplace_back(tmpBinder, callbackIds); - } - - uint64_t transactionId = -1; - SAFE_PARCEL(data.readUint64, &transactionId); - - SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize()); - std::vector<uint64_t> mergedTransactions(count); - for (size_t i = 0; i < count; i++) { - SAFE_PARCEL(data.readUint64, &mergedTransactions[i]); - } - - return setTransactionState(frameTimelineInfo, state, displays, stateFlags, applyToken, - std::move(inputWindowCommands), desiredPresentTime, - isAutoTimestamp, uncacheBuffers, hasListenerCallbacks, - listenerCallbacks, transactionId, mergedTransactions); + TransactionState state; + SAFE_PARCEL(state.readFromParcel, &data); + return setTransactionState(std::move(state)); } case GET_SCHEDULING_POLICY: { gui::SchedulingPolicy policy; diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 63dcfbcb9b..83c6b57289 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -2230,17 +2230,47 @@ int Surface::detachNextBuffer(sp<GraphicBuffer>* outBuffer, return NO_ERROR; } +int Surface::isBufferOwned(const sp<GraphicBuffer>& buffer, bool* outIsOwned) const { + ATRACE_CALL(); + + if (buffer == nullptr) { + ALOGE("%s: Bad input, buffer was null", __FUNCTION__); + return BAD_VALUE; + } + if (outIsOwned == nullptr) { + ALOGE("%s: Bad input, output was null", __FUNCTION__); + return BAD_VALUE; + } + + Mutex::Autolock lock(mMutex); + + int slot = this->getSlotFromBufferLocked(buffer->getNativeBuffer()); + if (slot == BAD_VALUE) { + ALOGV("%s: Buffer %" PRIu64 " is not owned", __FUNCTION__, buffer->getId()); + *outIsOwned = false; + return NO_ERROR; + } else if (slot < 0) { + ALOGV("%s: Buffer %" PRIu64 " look up failed (%d)", __FUNCTION__, buffer->getId(), slot); + *outIsOwned = false; + return slot; + } + + *outIsOwned = true; + return NO_ERROR; +} + int Surface::attachBuffer(ANativeWindowBuffer* buffer) { ATRACE_CALL(); - ALOGV("Surface::attachBuffer"); + sp<GraphicBuffer> graphicBuffer(static_cast<GraphicBuffer*>(buffer)); + + ALOGV("Surface::attachBuffer bufferId=%" PRIu64, graphicBuffer->getId()); Mutex::Autolock lock(mMutex); if (mReportRemovedBuffers) { mRemovedBuffers.clear(); } - sp<GraphicBuffer> graphicBuffer(static_cast<GraphicBuffer*>(buffer)); uint32_t priorGeneration = graphicBuffer->mGenerationNumber; graphicBuffer->mGenerationNumber = mGenerationNumber; int32_t attachedSlot = -1; diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 9854274cb1..69ba1d731d 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -824,34 +824,24 @@ void removeDeadBufferCallback(void* /*context*/, uint64_t graphicBufferId) { // --------------------------------------------------------------------------- SurfaceComposerClient::Transaction::Transaction() { - mId = generateId(); + mState.mId = generateId(); mTransactionCompletedListener = TransactionCompletedListener::getInstance(); } -SurfaceComposerClient::Transaction::Transaction(const Transaction& other) - : mId(other.mId), - mFlags(other.mFlags), - mMayContainBuffer(other.mMayContainBuffer), - mDesiredPresentTime(other.mDesiredPresentTime), - mIsAutoTimestamp(other.mIsAutoTimestamp), - mFrameTimelineInfo(other.mFrameTimelineInfo), - mApplyToken(other.mApplyToken) { - mDisplayStates = other.mDisplayStates; - mComposerStates = other.mComposerStates; - mInputWindowCommands = other.mInputWindowCommands; - mListenerCallbacks = other.mListenerCallbacks; - mTransactionCompletedListener = TransactionCompletedListener::getInstance(); -} +SurfaceComposerClient::Transaction::Transaction(Transaction&& other) + : mTransactionCompletedListener(TransactionCompletedListener::getInstance()), + mState(std::move(other.mState)), + mListenerCallbacks(std::move(other.mListenerCallbacks)) {} void SurfaceComposerClient::Transaction::sanitize(int pid, int uid) { uint32_t permissions = LayerStatePermissions::getTransactionPermissions(pid, uid); - for (auto& composerState : mComposerStates) { + for (auto& composerState : mState.mComposerStates) { composerState.state.sanitize(permissions); } - if (!mInputWindowCommands.empty() && + if (!mState.mInputWindowCommands.empty() && (permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER) == 0) { ALOGE("Only privileged callers are allowed to send input commands."); - mInputWindowCommands.clear(); + mState.mInputWindowCommands.clear(); } } @@ -866,31 +856,10 @@ SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) { status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) { - const uint64_t transactionId = parcel->readUint64(); - const uint32_t flags = parcel->readUint32(); - const int64_t desiredPresentTime = parcel->readInt64(); - const bool isAutoTimestamp = parcel->readBool(); - const bool logCallPoints = parcel->readBool(); - FrameTimelineInfo frameTimelineInfo; - frameTimelineInfo.readFromParcel(parcel); - - sp<IBinder> applyToken; - parcel->readNullableStrongBinder(&applyToken); - size_t count = static_cast<size_t>(parcel->readUint32()); - if (count > parcel->dataSize()) { - return BAD_VALUE; - } - Vector<DisplayState> displayStates; - displayStates.setCapacity(count); - for (size_t i = 0; i < count; i++) { - DisplayState displayState; - if (displayState.read(*parcel) == BAD_VALUE) { - return BAD_VALUE; - } - displayStates.add(displayState); - } + TransactionState tmpState; + SAFE_PARCEL(tmpState.readFromParcel, parcel); - count = static_cast<size_t>(parcel->readUint32()); + size_t count = static_cast<size_t>(parcel->readUint32()); if (count > parcel->dataSize()) { return BAD_VALUE; } @@ -919,57 +888,8 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel } } - count = static_cast<size_t>(parcel->readUint32()); - if (count > parcel->dataSize()) { - return BAD_VALUE; - } - Vector<ComposerState> composerStates; - composerStates.setCapacity(count); - for (size_t i = 0; i < count; i++) { - ComposerState composerState; - if (composerState.read(*parcel) == BAD_VALUE) { - return BAD_VALUE; - } - composerStates.add(composerState); - } - - InputWindowCommands inputWindowCommands; - inputWindowCommands.read(*parcel); - - count = static_cast<size_t>(parcel->readUint32()); - if (count > parcel->dataSize()) { - return BAD_VALUE; - } - std::vector<client_cache_t> uncacheBuffers(count); - for (size_t i = 0; i < count; i++) { - sp<IBinder> tmpBinder; - SAFE_PARCEL(parcel->readStrongBinder, &tmpBinder); - uncacheBuffers[i].token = tmpBinder; - SAFE_PARCEL(parcel->readUint64, &uncacheBuffers[i].id); - } - - count = static_cast<size_t>(parcel->readUint32()); - if (count > parcel->dataSize()) { - return BAD_VALUE; - } - std::vector<uint64_t> mergedTransactionIds(count); - for (size_t i = 0; i < count; i++) { - SAFE_PARCEL(parcel->readUint64, &mergedTransactionIds[i]); - } - - // Parsing was successful. Update the object. - mId = transactionId; - mFlags = flags; - mDesiredPresentTime = desiredPresentTime; - mIsAutoTimestamp = isAutoTimestamp; - mFrameTimelineInfo = frameTimelineInfo; - mDisplayStates = std::move(displayStates); - mListenerCallbacks = listenerCallbacks; - mComposerStates = std::move(composerStates); - mInputWindowCommands = inputWindowCommands; - mApplyToken = applyToken; - mUncacheBuffers = std::move(uncacheBuffers); - mMergedTransactionIds = std::move(mergedTransactionIds); + mState = std::move(tmpState); + mListenerCallbacks = std::move(listenerCallbacks); return NO_ERROR; } @@ -987,17 +907,7 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const const_cast<SurfaceComposerClient::Transaction*>(this)->cacheBuffers(); - parcel->writeUint64(mId); - parcel->writeUint32(mFlags); - parcel->writeInt64(mDesiredPresentTime); - parcel->writeBool(mIsAutoTimestamp); - parcel->writeBool(mLogCallPoints); - mFrameTimelineInfo.writeToParcel(parcel); - parcel->writeStrongBinder(mApplyToken); - parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size())); - for (auto const& displayState : mDisplayStates) { - displayState.write(*parcel); - } + SAFE_PARCEL(mState.writeToParcel, parcel); parcel->writeUint32(static_cast<uint32_t>(mListenerCallbacks.size())); for (auto const& [listener, callbackInfo] : mListenerCallbacks) { @@ -1012,24 +922,6 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const } } - parcel->writeUint32(static_cast<uint32_t>(mComposerStates.size())); - for (auto const& composerState : mComposerStates) { - composerState.write(*parcel); - } - - mInputWindowCommands.write(*parcel); - - SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mUncacheBuffers.size())); - for (const client_cache_t& uncacheBuffer : mUncacheBuffers) { - SAFE_PARCEL(parcel->writeStrongBinder, uncacheBuffer.token.promote()); - SAFE_PARCEL(parcel->writeUint64, uncacheBuffer.id); - } - - SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mMergedTransactionIds.size())); - for (auto mergedTransactionId : mMergedTransactionIds) { - SAFE_PARCEL(parcel->writeUint64, mergedTransactionId); - } - return NO_ERROR; } @@ -1054,50 +946,8 @@ void SurfaceComposerClient::Transaction::releaseBufferIfOverwriting(const layer_ } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) { - while (mMergedTransactionIds.size() + other.mMergedTransactionIds.size() > - MAX_MERGE_HISTORY_LENGTH - 1 && - mMergedTransactionIds.size() > 0) { - mMergedTransactionIds.pop_back(); - } - if (other.mMergedTransactionIds.size() == MAX_MERGE_HISTORY_LENGTH) { - mMergedTransactionIds.insert(mMergedTransactionIds.begin(), - other.mMergedTransactionIds.begin(), - other.mMergedTransactionIds.end() - 1); - } else if (other.mMergedTransactionIds.size() > 0u) { - mMergedTransactionIds.insert(mMergedTransactionIds.begin(), - other.mMergedTransactionIds.begin(), - other.mMergedTransactionIds.end()); - } - mMergedTransactionIds.insert(mMergedTransactionIds.begin(), other.mId); - - for (auto const& otherState : other.mComposerStates) { - if (auto it = std::find_if(mComposerStates.begin(), mComposerStates.end(), - [&otherState](const auto& composerState) { - return composerState.state.surface == - otherState.state.surface; - }); - it != mComposerStates.end()) { - if (otherState.state.what & layer_state_t::eBufferChanged) { - releaseBufferIfOverwriting(it->state); - } - it->state.merge(otherState.state); - } else { - mComposerStates.add(otherState); - } - } - - for (auto const& state : other.mDisplayStates) { - if (auto it = std::find_if(mDisplayStates.begin(), mDisplayStates.end(), - [&state](const auto& displayState) { - return displayState.token == state.token; - }); - it != mDisplayStates.end()) { - it->merge(state); - } else { - mDisplayStates.add(state); - } - } - + mState.merge(std::move(other.mState), + std::bind(&Transaction::releaseBufferIfOverwriting, this, std::placeholders::_1)); for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) { auto& [callbackIds, surfaceControls] = callbackInfo; mListenerCallbacks[listener].callbackIds.insert(std::make_move_iterator( @@ -1121,50 +971,21 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr } } - for (const auto& cacheId : other.mUncacheBuffers) { - mUncacheBuffers.push_back(cacheId); - } - - mInputWindowCommands.merge(other.mInputWindowCommands); - - mMayContainBuffer |= other.mMayContainBuffer; - mFlags |= other.mFlags; - mApplyToken = other.mApplyToken; - - mergeFrameTimelineInfo(mFrameTimelineInfo, other.mFrameTimelineInfo); - - mLogCallPoints |= other.mLogCallPoints; - if (mLogCallPoints) { - ALOG(LOG_DEBUG, LOG_SURFACE_CONTROL_REGISTRY, - "Transaction %" PRIu64 " merged with transaction %" PRIu64, other.getId(), mId); - } - other.clear(); return *this; } void SurfaceComposerClient::Transaction::clear() { - mComposerStates.clear(); - mDisplayStates.clear(); + mState.clear(); mListenerCallbacks.clear(); - mInputWindowCommands.clear(); - mUncacheBuffers.clear(); - mMayContainBuffer = false; - mDesiredPresentTime = 0; - mIsAutoTimestamp = true; - mFrameTimelineInfo = {}; - mApplyToken = nullptr; - mMergedTransactionIds.clear(); - mLogCallPoints = false; - mFlags = 0; } -uint64_t SurfaceComposerClient::Transaction::getId() { - return mId; +uint64_t SurfaceComposerClient::Transaction::getId() const { + return mState.mId; } std::vector<uint64_t> SurfaceComposerClient::Transaction::getMergedTransactionIds() { - return mMergedTransactionIds; + return mState.mMergedTransactionIds; } void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { @@ -1173,12 +994,13 @@ void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { client_cache_t uncacheBuffer; uncacheBuffer.token = BufferCache::getInstance().getToken(); uncacheBuffer.id = cacheId; - Vector<ComposerState> composerStates; - Vector<DisplayState> displayStates; - status_t status = sf->setTransactionState(FrameTimelineInfo{}, composerStates, displayStates, - ISurfaceComposer::eOneWay, - Transaction::getDefaultApplyToken(), {}, systemTime(), - true, {uncacheBuffer}, false, {}, generateId(), {}); + TransactionState state; + state.mId = generateId(); + state.mApplyToken = Transaction::getDefaultApplyToken(); + state.mUncacheBuffers.emplace_back(std::move(uncacheBuffer)); + state.mFlags = ISurfaceComposer::eOneWay; + state.mDesiredPresentTime = systemTime(); + status_t status = sf->setTransactionState(std::move(state)); if (status != NO_ERROR) { ALOGE_AND_TRACE("SurfaceComposerClient::doUncacheBufferTransaction - %s", strerror(-status)); @@ -1186,12 +1008,12 @@ void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { } void SurfaceComposerClient::Transaction::cacheBuffers() { - if (!mMayContainBuffer) { + if (!mState.mMayContainBuffer) { return; } size_t count = 0; - for (auto& cs : mComposerStates) { + for (auto& cs : mState.mComposerStates) { layer_state_t* s = &cs.state; if (!(s->what & layer_state_t::eBufferChanged)) { continue; @@ -1219,7 +1041,7 @@ void SurfaceComposerClient::Transaction::cacheBuffers() { std::optional<client_cache_t> uncacheBuffer; cacheId = BufferCache::getInstance().cache(s->bufferData->buffer, uncacheBuffer); if (uncacheBuffer) { - mUncacheBuffers.push_back(*uncacheBuffer); + mState.mUncacheBuffers.emplace_back(*uncacheBuffer); } } s->bufferData->flags |= BufferData::BufferDataChange::cachedBufferChanged; @@ -1288,8 +1110,7 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay /*callbackContext=*/nullptr); } - bool hasListenerCallbacks = !mListenerCallbacks.empty(); - std::vector<ListenerCallbacks> listenerCallbacks; + mState.mHasListenerCallbacks = !mListenerCallbacks.empty(); // For every listener with registered callbacks for (const auto& [listener, callbackInfo] : mListenerCallbacks) { auto& [callbackIds, surfaceControls] = callbackInfo; @@ -1298,7 +1119,8 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay } if (surfaceControls.empty()) { - listenerCallbacks.emplace_back(IInterface::asBinder(listener), std::move(callbackIds)); + mState.mListenerCallbacks.emplace_back(IInterface::asBinder(listener), + std::move(callbackIds)); } else { // If the listener has any SurfaceControls set on this Transaction update the surface // state @@ -1310,7 +1132,7 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay } std::vector<CallbackId> callbacks(callbackIds.begin(), callbackIds.end()); s->what |= layer_state_t::eHasListenerCallbacksChanged; - s->listeners.emplace_back(IInterface::asBinder(listener), callbacks); + s->listeners.emplace_back(IInterface::asBinder(listener), std::move(callbacks)); } } } @@ -1322,25 +1144,21 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay ALOGE("Transaction attempted to set synchronous and one way at the same time" " this is an invalid request. Synchronous will win for safety"); } else { - mFlags |= ISurfaceComposer::eOneWay; + mState.mFlags |= ISurfaceComposer::eOneWay; } } // If both ISurfaceComposer::eEarlyWakeupStart and ISurfaceComposer::eEarlyWakeupEnd are set // it is equivalent for none uint32_t wakeupFlags = ISurfaceComposer::eEarlyWakeupStart | ISurfaceComposer::eEarlyWakeupEnd; - if ((mFlags & wakeupFlags) == wakeupFlags) { - mFlags &= ~(wakeupFlags); + if ((mState.mFlags & wakeupFlags) == wakeupFlags) { + mState.mFlags &= ~(wakeupFlags); } - sp<IBinder> applyToken = mApplyToken ? mApplyToken : getDefaultApplyToken(); + if (!mState.mApplyToken) mState.mApplyToken = getDefaultApplyToken(); sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - status_t binderStatus = - sf->setTransactionState(mFrameTimelineInfo, mComposerStates, mDisplayStates, mFlags, - applyToken, mInputWindowCommands, mDesiredPresentTime, - mIsAutoTimestamp, mUncacheBuffers, hasListenerCallbacks, - listenerCallbacks, mId, mMergedTransactionIds); - mId = generateId(); + status_t binderStatus = sf->setTransactionState(std::move(mState)); + mState.mId = generateId(); // Clear the current states and flags clear(); @@ -1349,8 +1167,8 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay syncCallback->wait(); } - if (mLogCallPoints) { - ALOG(LOG_DEBUG, LOG_SURFACE_CONTROL_REGISTRY, "Transaction %" PRIu64 " applied", mId); + if (mState.mLogCallPoints) { + ALOG(LOG_DEBUG, LOG_SURFACE_CONTROL_REGISTRY, "Transaction %" PRIu64 " applied", getId()); } mStatus = NO_ERROR; @@ -1385,7 +1203,7 @@ status_t SurfaceComposerClient::Transaction::sendSurfaceFlushJankDataTransaction } void SurfaceComposerClient::Transaction::enableDebugLogCallPoints() { - mLogCallPoints = true; + mState.mLogCallPoints = true; } // --------------------------------------------------------------------------- @@ -1443,34 +1261,19 @@ std::optional<gui::StalledTransactionInfo> SurfaceComposerClient::getStalledTran } void SurfaceComposerClient::Transaction::setAnimationTransaction() { - mFlags |= ISurfaceComposer::eAnimation; + mState.mFlags |= ISurfaceComposer::eAnimation; } void SurfaceComposerClient::Transaction::setEarlyWakeupStart() { - mFlags |= ISurfaceComposer::eEarlyWakeupStart; + mState.mFlags |= ISurfaceComposer::eEarlyWakeupStart; } void SurfaceComposerClient::Transaction::setEarlyWakeupEnd() { - mFlags |= ISurfaceComposer::eEarlyWakeupEnd; + mState.mFlags |= ISurfaceComposer::eEarlyWakeupEnd; } layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) { - auto handle = sc->getLayerStateHandle(); - if (auto it = std::find_if(mComposerStates.begin(), mComposerStates.end(), - [&handle](const auto& composerState) { - return composerState.state.surface == handle; - }); - it != mComposerStates.end()) { - return &it->state; - } - - // we don't have it, add an initialized layer_state to our list - ComposerState s; - s.state.surface = handle; - s.state.layerId = sc->getLayerId(); - mComposerStates.add(s); - - return &mComposerStates.editItemAt(mComposerStates.size() - 1).state; + return mState.getLayerState(sc); } void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback( @@ -1846,8 +1649,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe setReleaseBufferCallback(bufferData.get(), callback); } - if (mIsAutoTimestamp) { - mDesiredPresentTime = systemTime(); + if (mState.mIsAutoTimestamp) { + mState.mDesiredPresentTime = systemTime(); } s->what |= layer_state_t::eBufferChanged; s->bufferData = std::move(bufferData); @@ -1865,7 +1668,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe const std::vector<SurfaceControlStats>&) {}, nullptr); - mMayContainBuffer = true; + mState.mMayContainBuffer = true; return *this; } @@ -2041,8 +1844,8 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSideb SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesiredPresentTime( nsecs_t desiredPresentTime) { - mDesiredPresentTime = desiredPresentTime; - mIsAutoTimestamp = false; + mState.mDesiredPresentTime = desiredPresentTime; + mState.mIsAutoTimestamp = false; return *this; } @@ -2131,14 +1934,14 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInput SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFocusedWindow( const FocusRequest& request) { - mInputWindowCommands.addFocusRequest(request); + mState.mInputWindowCommands.addFocusRequest(request); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addWindowInfosReportedListener( sp<gui::IWindowInfosReportedListener> windowInfosReportedListener) { - mInputWindowCommands.addWindowInfosReportedListener(windowInfosReportedListener); + mState.mInputWindowCommands.addWindowInfosReportedListener(windowInfosReportedListener); return *this; } @@ -2302,7 +2105,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixed SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo( const FrameTimelineInfo& frameTimelineInfo) { - mergeFrameTimelineInfo(mFrameTimelineInfo, frameTimelineInfo); + mState.mergeFrameTimelineInfo(frameTimelineInfo); return *this; } @@ -2341,7 +2144,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTrust SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApplyToken( const sp<IBinder>& applyToken) { - mApplyToken = applyToken; + mState.mApplyToken = applyToken; return *this; } @@ -2469,17 +2272,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setConte // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) { - if (auto it = std::find_if(mDisplayStates.begin(), mDisplayStates.end(), - [token](const auto& display) { return display.token == token; }); - it != mDisplayStates.end()) { - return *it; - } - - // If display state doesn't exist, add a new one. - DisplayState s; - s.token = token; - mDisplayStates.add(s); - return mDisplayStates.editItemAt(mDisplayStates.size() - 1); + return mState.getDisplayState(token); } status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp<IBinder>& token, @@ -2532,20 +2325,6 @@ void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token s.what |= DisplayState::eDisplaySizeChanged; } -// copied from FrameTimelineInfo::merge() -void SurfaceComposerClient::Transaction::mergeFrameTimelineInfo(FrameTimelineInfo& t, - const FrameTimelineInfo& other) { - // When merging vsync Ids we take the oldest valid one - if (t.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID && - other.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { - if (other.vsyncId > t.vsyncId) { - t = other; - } - } else if (t.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) { - t = other; - } -} - SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTrustedPresentationCallback( const sp<SurfaceControl>& sc, TrustedPresentationCallback cb, diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index db1b9fb8eb..c69b0a79ad 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -284,7 +284,7 @@ private: std::function<void(SurfaceComposerClient::Transaction*)> mTransactionReadyCallback GUARDED_BY(mMutex); SurfaceComposerClient::Transaction* mSyncTransaction GUARDED_BY(mMutex); - std::vector<std::tuple<uint64_t /* framenumber */, SurfaceComposerClient::Transaction>> + std::vector<std::pair<uint64_t /* framenumber */, SurfaceComposerClient::Transaction>> mPendingTransactions GUARDED_BY(mMutex); std::queue<std::pair<uint64_t, FrameTimelineInfo>> mPendingFrameTimelines GUARDED_BY(mMutex); diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index 50abadb922..6a1e9f6f03 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -36,8 +36,6 @@ class BufferQueueProducer : public BnGraphicBufferProducer { public: friend class BufferQueue; // Needed to access binderDied - explicit BufferQueueProducer(const sp<BufferQueueCore>& core, - bool consumerIsSurfaceFlinger = false); ~BufferQueueProducer() override; // requestBuffer returns the GraphicBuffer for slot N. @@ -219,6 +217,9 @@ public: #endif protected: + explicit BufferQueueProducer(const sp<BufferQueueCore>& core, + bool consumerIsSurfaceFlinger = false); + friend class sp<BufferQueueProducer>; // see IGraphicsBufferProducer::setMaxDequeuedBufferCount, but with the ability to retrieve the // total maximum buffer count for the buffer queue (dequeued AND acquired) status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers, int* maxBufferCount); diff --git a/libs/gui/include/gui/Choreographer.h b/libs/gui/include/gui/Choreographer.h index 5862967d4a..b436af1eb3 100644 --- a/libs/gui/include/gui/Choreographer.h +++ b/libs/gui/include/gui/Choreographer.h @@ -79,8 +79,6 @@ public: }; static Context gChoreographers; - explicit Choreographer(const sp<Looper>& looper, const sp<IBinder>& layerHandle = nullptr) - EXCLUDES(gChoreographers.lock); void postFrameCallbackDelayed(AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, AChoreographer_vsyncCallback vsyncCallback, void* data, @@ -113,6 +111,10 @@ public: private: Choreographer(const Choreographer&) = delete; + explicit Choreographer(const sp<Looper>& looper, const sp<IBinder>& layerHandle = nullptr) + EXCLUDES(gChoreographers.lock); + friend class sp<Choreographer>; + friend AChoreographer* AChoreographer_create(); void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count, VsyncEventData vsyncEventData) override; diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index b06ad077f4..cdf216c945 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -23,12 +23,6 @@ using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; class DisplayEventDispatcher : public LooperCallback { public: - explicit DisplayEventDispatcher(const sp<Looper>& looper, - gui::ISurfaceComposer::VsyncSource vsyncSource = - gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, - EventRegistrationFlags eventRegistration = {}, - const sp<IBinder>& layerHandle = nullptr); - status_t initialize(); void dispose(); status_t scheduleVsync(); @@ -38,6 +32,14 @@ public: status_t getLatestVsyncEventData(ParcelableVsyncEventData* outVsyncEventData) const; protected: + explicit DisplayEventDispatcher(const sp<Looper>& looper, + gui::ISurfaceComposer::VsyncSource vsyncSource = + gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, + EventRegistrationFlags eventRegistration = {}, + const sp<IBinder>& layerHandle = nullptr); + + friend class sp<DisplayEventDispatcher>; + virtual ~DisplayEventDispatcher() = default; private: diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 9a422fd808..de553aef72 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -65,6 +65,7 @@ struct DisplayState; struct InputWindowCommands; class HdrCapabilities; class Rect; +class TransactionState; using gui::FrameTimelineInfo; using gui::IDisplayEventConnection; @@ -105,13 +106,7 @@ public: }; /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */ - virtual status_t setTransactionState( - const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& state, - Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, - InputWindowCommands inputWindowCommands, int64_t desiredPresentTime, - bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffer, - bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, - uint64_t transactionId, const std::vector<uint64_t>& mergedTransactionIds) = 0; + virtual status_t setTransactionState(TransactionState&& state) = 0; }; // ---------------------------------------------------------------------------- diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 755674d9e6..3cfbed11bf 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -442,6 +442,9 @@ public: status_t detachBuffer(const sp<GraphicBuffer>& buffer); #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) + // Sets outIsOwned to true if the given buffer is currently known to be owned by this Surface. + status_t isBufferOwned(const sp<GraphicBuffer>& buffer, bool* outIsOwned) const; + // Batch version of dequeueBuffer, cancelBuffer and queueBuffer // Note that these batched operations are not supported when shared buffer mode is being used. struct BatchBuffer { diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 4fda8deb9c..668bd6fbb8 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -52,6 +52,7 @@ #include <gui/ITransactionCompletedListener.h> #include <gui/LayerState.h> #include <gui/SurfaceControl.h> +#include <gui/TransactionState.h> #include <gui/WindowInfosListenerReporter.h> #include <math/vec3.h> @@ -442,61 +443,16 @@ public: virtual ~PresentationCallbackRAII(); }; - class Transaction : public Parcelable { + class Transaction { private: static sp<IBinder> sApplyToken; static std::mutex sApplyTokenMutex; void releaseBufferIfOverwriting(const layer_state_t& state); - static void mergeFrameTimelineInfo(FrameTimelineInfo& t, const FrameTimelineInfo& other); // Tracks registered callbacks sp<TransactionCompletedListener> mTransactionCompletedListener = nullptr; - // Prints debug logs when enabled. - bool mLogCallPoints = false; - protected: - Vector<ComposerState> mComposerStates; - Vector<DisplayState> mDisplayStates; - std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash> - mListenerCallbacks; - std::vector<client_cache_t> mUncacheBuffers; - - // We keep track of the last MAX_MERGE_HISTORY_LENGTH merged transaction ids. - // Ordered most recently merged to least recently merged. - static const size_t MAX_MERGE_HISTORY_LENGTH = 10u; - std::vector<uint64_t> mMergedTransactionIds; - - uint64_t mId; - uint32_t mFlags = 0; - - // Indicates that the Transaction may contain buffers that should be cached. The reason this - // is only a guess is that buffers can be removed before cache is called. This is only a - // hint that at some point a buffer was added to this transaction before apply was called. - bool mMayContainBuffer = false; - - // mDesiredPresentTime is the time in nanoseconds that the client would like the transaction - // to be presented. When it is not possible to present at exactly that time, it will be - // presented after the time has passed. - // - // If the client didn't pass a desired presentation time, mDesiredPresentTime will be - // populated to the time setBuffer was called, and mIsAutoTimestamp will be set to true. - // - // Desired present times that are more than 1 second in the future may be ignored. - // When a desired present time has already passed, the transaction will be presented as soon - // as possible. - // - // Transactions from the same process are presented in the same order that they are applied. - // The desired present time does not affect this ordering. - int64_t mDesiredPresentTime = 0; - bool mIsAutoTimestamp = true; - - // The vsync id provided by Choreographer.getVsyncId and the input event id - FrameTimelineInfo mFrameTimelineInfo; - - // If not null, transactions will be queued up using this token otherwise a common token - // per process will be used. - sp<IBinder> mApplyToken = nullptr; + TransactionState mState; - InputWindowCommands mInputWindowCommands; int mStatus = NO_ERROR; layer_state_t* getLayerState(const sp<SurfaceControl>& sc); @@ -506,23 +462,29 @@ public: void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc); void setReleaseBufferCallback(BufferData*, ReleaseBufferCallback); + protected: + // Accessed in tests. + explicit Transaction(Transaction const& other) = default; + std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash> + mListenerCallbacks; + public: Transaction(); - virtual ~Transaction() = default; - Transaction(Transaction const& other); + Transaction(Transaction&& other); + Transaction& operator=(Transaction&& other) = default; // Factory method that creates a new Transaction instance from the parcel. static std::unique_ptr<Transaction> createFromParcel(const Parcel* parcel); - status_t writeToParcel(Parcel* parcel) const override; - status_t readFromParcel(const Parcel* parcel) override; + status_t writeToParcel(Parcel* parcel) const; + status_t readFromParcel(const Parcel* parcel); // Clears the contents of the transaction without applying it. void clear(); // Returns the current id of the transaction. // The id is updated every time the transaction is applied. - uint64_t getId(); + uint64_t getId() const; std::vector<uint64_t> getMergedTransactionIds(); diff --git a/libs/gui/include/gui/TransactionState.h b/libs/gui/include/gui/TransactionState.h index 4358227dae..79124f3ed7 100644 --- a/libs/gui/include/gui/TransactionState.h +++ b/libs/gui/include/gui/TransactionState.h @@ -26,7 +26,8 @@ namespace android { class TransactionState { public: explicit TransactionState() = default; - TransactionState(TransactionState const& other) = default; + TransactionState(TransactionState&& other) = default; + TransactionState& operator=(TransactionState&& other) = default; status_t writeToParcel(Parcel* parcel) const; status_t readFromParcel(const Parcel* parcel); layer_state_t* getLayerState(const sp<SurfaceControl>& sc); @@ -86,6 +87,9 @@ public: std::vector<ListenerCallbacks> mListenerCallbacks; private: + explicit TransactionState(TransactionState const& other) = default; + friend class TransactionApplicationTest; + friend class SurfaceComposerClient; // 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; diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h index 684e21ad96..f9a3acee41 100644 --- a/libs/gui/include/gui/WindowInfosListenerReporter.h +++ b/libs/gui/include/gui/WindowInfosListenerReporter.h @@ -40,6 +40,9 @@ public: void reconnect(const sp<gui::ISurfaceComposer>&); private: + WindowInfosListenerReporter() = default; + friend class sp<WindowInfosListenerReporter>; + std::mutex mListenersMutex; std::unordered_set<sp<gui::WindowInfosListener>, gui::SpHash<gui::WindowInfosListener>> mWindowInfosListeners GUARDED_BY(mListenersMutex); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 61c93cae14..4fee11c2cb 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -648,16 +648,7 @@ public: mSupportsPresent = supportsPresent; } - status_t setTransactionState( - const FrameTimelineInfo& /*frameTimelineInfo*/, Vector<ComposerState>& /*state*/, - Vector<DisplayState>& /*displays*/, uint32_t /*flags*/, - const sp<IBinder>& /*applyToken*/, InputWindowCommands /*inputWindowCommands*/, - int64_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/, - const std::vector<client_cache_t>& /*cachedBuffer*/, bool /*hasListenerCallbacks*/, - const std::vector<ListenerCallbacks>& /*listenerCallbacks*/, uint64_t /*transactionId*/, - const std::vector<uint64_t>& /*mergedTransactionIds*/) override { - return NO_ERROR; - } + status_t setTransactionState(TransactionState&&) override { return NO_ERROR; } protected: IBinder* onAsBinder() override { return nullptr; } @@ -2699,4 +2690,57 @@ TEST_F(SurfaceTest, UnlimitedSlots_BatchOperations) { EXPECT_EQ(128u, outputs.size()); } #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_UNLIMITED_SLOTS) + +TEST_F(SurfaceTest, isBufferOwned) { + const int TEST_USAGE_FLAGS = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER; + auto [bufferItemConsumer, surface] = BufferItemConsumer::create(TEST_USAGE_FLAGS); + + sp<SurfaceListener> listener = sp<StubSurfaceListener>::make(); + ASSERT_EQ(OK, surface->connect(NATIVE_WINDOW_API_CPU, listener)); + + sp<GraphicBuffer> surfaceAttachableBuffer = + sp<GraphicBuffer>::make(10, 10, PIXEL_FORMAT_RGBA_8888, 1, TEST_USAGE_FLAGS); + + // + // Attaching a buffer makes it owned. + // + + bool isOwned; + EXPECT_EQ(OK, surface->isBufferOwned(surfaceAttachableBuffer, &isOwned)); + EXPECT_FALSE(isOwned); + + EXPECT_EQ(OK, surface->attachBuffer(surfaceAttachableBuffer.get())); + EXPECT_EQ(OK, surface->isBufferOwned(surfaceAttachableBuffer, &isOwned)); + EXPECT_TRUE(isOwned); + + // + // A dequeued buffer is always owned. + // + + sp<GraphicBuffer> buffer; + sp<Fence> fence; + EXPECT_EQ(OK, surface->dequeueBuffer(&buffer, &fence)); + EXPECT_EQ(OK, surface->isBufferOwned(buffer, &isOwned)); + EXPECT_TRUE(isOwned); + + // + // A detached buffer is no longer owned. + // + + EXPECT_EQ(OK, surface->detachBuffer(buffer)); + EXPECT_EQ(OK, surface->isBufferOwned(buffer, &isOwned)); + EXPECT_FALSE(isOwned); + + // + // It's not currently possible to verify whether or not a consumer has attached a buffer until + // it shows up on the Surface. + // + + sp<GraphicBuffer> consumerAttachableBuffer = + sp<GraphicBuffer>::make(10, 10, PIXEL_FORMAT_RGBA_8888, 1, TEST_USAGE_FLAGS); + + ASSERT_EQ(OK, bufferItemConsumer->attachBuffer(consumerAttachableBuffer)); + EXPECT_EQ(OK, surface->isBufferOwned(consumerAttachableBuffer, &isOwned)); + EXPECT_FALSE(isOwned); +} } // namespace android diff --git a/libs/input/InputConsumerNoResampling.cpp b/libs/input/InputConsumerNoResampling.cpp index 6087461f6c..9578639e2b 100644 --- a/libs/input/InputConsumerNoResampling.cpp +++ b/libs/input/InputConsumerNoResampling.cpp @@ -171,11 +171,6 @@ InputMessage createTimelineMessage(int32_t inputEventId, nsecs_t gpuCompletedTim return msg; } -std::ostream& operator<<(std::ostream& out, const InputMessage& msg) { - out << ftl::enum_string(msg.header.type); - return out; -} - } // namespace // --- InputConsumerNoResampling --- diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index d388d48e8d..cb6f7f0707 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -436,16 +436,29 @@ android::base::Result<InputMessage> InputChannel::receiveMessage() { if (error == EAGAIN || error == EWOULDBLOCK) { return android::base::Error(WOULD_BLOCK); } - if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED) { - return android::base::Error(DEAD_OBJECT); + if (error == EPIPE) { + return android::base::ResultError("Got EPIPE", DEAD_OBJECT); + } + if (error == ENOTCONN) { + return android::base::ResultError("Got ENOTCONN", DEAD_OBJECT); + } + if (error == ECONNREFUSED) { + return android::base::ResultError("Got ECONNREFUSED", DEAD_OBJECT); + } + if (error == ECONNRESET) { + // This means that the client has closed the channel while there was + // still some data in the buffer. In most cases, subsequent reads + // would result in more data. However, that is not guaranteed, so we + // should not return WOULD_BLOCK here to try again. + return android::base::ResultError("Got ECONNRESET", DEAD_OBJECT); } return android::base::Error(-error); } if (nRead == 0) { // check for EOF - ALOGD_IF(DEBUG_CHANNEL_MESSAGES, - "channel '%s' ~ receive message failed because peer was closed", name.c_str()); - return android::base::Error(DEAD_OBJECT); + LOG_IF(INFO, DEBUG_CHANNEL_MESSAGES) + << "channel '" << name << "' ~ receive message failed because peer was closed"; + return android::base::ResultError("::recv returned 0", DEAD_OBJECT); } if (!msg.isValid(nRead)) { @@ -766,4 +779,9 @@ android::base::Result<InputPublisher::ConsumerResponse> InputPublisher::receiveC return android::base::Error(UNKNOWN_ERROR); } +std::ostream& operator<<(std::ostream& out, const InputMessage& msg) { + out << ftl::enum_string(msg.header.type); + return out; +} + } // namespace android diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp index 25356cfcf0..9b582d99dc 100644 --- a/libs/input/tests/InputChannel_test.cpp +++ b/libs/input/tests/InputChannel_test.cpp @@ -20,6 +20,7 @@ #include <time.h> #include <errno.h> +#include <android-base/logging.h> #include <binder/Binder.h> #include <binder/Parcel.h> #include <gtest/gtest.h> @@ -43,6 +44,39 @@ bool operator==(const InputChannel& left, const InputChannel& right) { return left.getName() == right.getName() && left.getConnectionToken() == right.getConnectionToken() && lhs.st_ino == rhs.st_ino; } + +/** + * Read a message from the provided channel. Read will continue until there's data, so only call + * this if there's data in the channel, or it's closed. If there's no data, this will loop forever. + */ +android::base::Result<InputMessage> readMessage(InputChannel& channel) { + while (true) { + // Keep reading until we get something other than 'WOULD_BLOCK' + android::base::Result<InputMessage> result = channel.receiveMessage(); + if (!result.ok() && result.error().code() == WOULD_BLOCK) { + // The data is not available yet. + continue; // try again + } + return result; + } +} + +InputMessage createFinishedMessage(uint32_t seq) { + InputMessage finish{}; + finish.header.type = InputMessage::Type::FINISHED; + finish.header.seq = seq; + finish.body.finished.handled = true; + return finish; +} + +InputMessage createKeyMessage(uint32_t seq) { + InputMessage key{}; + key.header.type = InputMessage::Type::KEY; + key.header.seq = seq; + key.body.key.action = AKEY_EVENT_ACTION_DOWN; + return key; +} + } // namespace class InputChannelTest : public testing::Test { @@ -227,6 +261,120 @@ TEST_F(InputChannelTest, SendAndReceive_MotionClassification) { } } +/** + * In this test, server writes 3 key events to the client. The client, upon receiving the first key, + * sends a "finished" signal back to server, and then closes the fd. + * + * Next, we check what the server receives. + * + * In most cases, the server will receive the finish event, and then an 'fd closed' event. + * + * However, sometimes, the 'finish' event will not be delivered to the server. This is communicated + * to the server via 'ECONNRESET', which the InputChannel converts into DEAD_OBJECT. + * + * The server needs to be aware of this behaviour and correctly clean up any state associated with + * the client, even if the client did not end up finishing some of the messages. + * + * This test is written to expose a behaviour on the linux side - occasionally, the + * last events written to the fd by the consumer are not delivered to the server. + * + * When tested on 2025 hardware, ECONNRESET was received approximately 1 out of 40 tries. + * In vast majority (~ 29999 / 30000) of cases, after receiving ECONNRESET, the server could still + * read the client data after receiving ECONNRESET. + */ +TEST_F(InputChannelTest, ReceiveAfterCloseMultiThreaded) { + std::unique_ptr<InputChannel> serverChannel, clientChannel; + status_t result = + InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); + ASSERT_EQ(OK, result) << "should have successfully opened a channel pair"; + + // Sender / publisher: publish 3 keys + InputMessage key1 = createKeyMessage(/*seq=*/1); + serverChannel->sendMessage(&key1); + // The client should close the fd after it reads this one, but we will send 2 more here. + InputMessage key2 = createKeyMessage(/*seq=*/2); + serverChannel->sendMessage(&key2); + InputMessage key3 = createKeyMessage(/*seq=*/3); + serverChannel->sendMessage(&key3); + + std::thread consumer = std::thread([clientChannel = std::move(clientChannel)]() mutable { + // Read the first key + android::base::Result<InputMessage> firstKey = readMessage(*clientChannel); + if (!firstKey.ok()) { + FAIL() << "Did not receive the first key"; + } + + // Send finish + const InputMessage finish = createFinishedMessage(firstKey->header.seq); + clientChannel->sendMessage(&finish); + // Now close the fd + clientChannel.reset(); + }); + + // Now try to read the finish message, even though client closed the fd + android::base::Result<InputMessage> response = readMessage(*serverChannel); + consumer.join(); + if (response.ok()) { + ASSERT_EQ(response->header.type, InputMessage::Type::FINISHED); + } else { + // It's possible that after the client closes the fd, server will receive ECONNRESET. + // In those situations, this error code will be translated into DEAD_OBJECT by the + // InputChannel. + ASSERT_EQ(response.error().code(), DEAD_OBJECT); + // In most cases, subsequent attempts to read the client channel at this + // point would succeed. However, for simplicity, we exit here (since + // it's not guaranteed). + return; + } + + // There should not be any more events from the client, since the client closed fd after the + // first key. + android::base::Result<InputMessage> noEvent = serverChannel->receiveMessage(); + ASSERT_FALSE(noEvent.ok()) << "Got event " << *noEvent; +} + +/** + * Similar test as above, but single-threaded. + */ +TEST_F(InputChannelTest, ReceiveAfterCloseSingleThreaded) { + std::unique_ptr<InputChannel> serverChannel, clientChannel; + status_t result = + InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); + ASSERT_EQ(OK, result) << "should have successfully opened a channel pair"; + + // Sender / publisher: publish 3 keys + InputMessage key1 = createKeyMessage(/*seq=*/1); + serverChannel->sendMessage(&key1); + // The client should close the fd after it reads this one, but we will send 2 more here. + InputMessage key2 = createKeyMessage(/*seq=*/2); + serverChannel->sendMessage(&key2); + InputMessage key3 = createKeyMessage(/*seq=*/3); + serverChannel->sendMessage(&key3); + + // Read the first key + android::base::Result<InputMessage> firstKey = readMessage(*clientChannel); + if (!firstKey.ok()) { + FAIL() << "Did not receive the first key"; + } + + // Send finish + const InputMessage finish = createFinishedMessage(firstKey->header.seq); + clientChannel->sendMessage(&finish); + // Now close the fd + clientChannel.reset(); + + // Now try to read the finish message, even though client closed the fd + android::base::Result<InputMessage> response = readMessage(*serverChannel); + ASSERT_FALSE(response.ok()); + ASSERT_EQ(response.error().code(), DEAD_OBJECT); + + // We can still read the finish event (but in practice, the expectation is that the server will + // not be doing this after getting DEAD_OBJECT). + android::base::Result<InputMessage> finishEvent = serverChannel->receiveMessage(); + ASSERT_TRUE(finishEvent.ok()); + ASSERT_EQ(finishEvent->header.type, InputMessage::Type::FINISHED); +} + TEST_F(InputChannelTest, DuplicateChannelAndAssertEqual) { std::unique_ptr<InputChannel> serverChannel, clientChannel; diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 608bec4a0c..c8432005a4 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -443,6 +443,9 @@ public: /* Get the Bluetooth address of an input device, if known. */ virtual std::optional<std::string> getBluetoothAddress(int32_t deviceId) const = 0; + /* Gets the sysfs root path for this device. Returns an empty path if there is none. */ + virtual std::filesystem::path getSysfsRootPath(int32_t deviceId) const = 0; + /* Sysfs node change reported. Recreate device if required to incorporate the new sysfs nodes */ virtual void sysfsNodeChanged(const std::string& sysfsNodePath) = 0; diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index 2fcb5d831f..559bc0aa7a 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -246,7 +246,7 @@ static nsecs_t processEventTimestamp(const struct input_event& event) { /** * Returns the sysfs root path of the input device. */ -static std::optional<std::filesystem::path> getSysfsRootPath(const char* devicePath) { +static std::optional<std::filesystem::path> getSysfsRootForEvdevDevicePath(const char* devicePath) { std::error_code errorCode; // Stat the device path to get the major and minor number of the character file @@ -1619,7 +1619,7 @@ void EventHub::assignDescriptorLocked(InputDeviceIdentifier& identifier) { std::shared_ptr<const EventHub::AssociatedDevice> EventHub::obtainAssociatedDeviceLocked( const std::filesystem::path& devicePath, const std::shared_ptr<PropertyMap>& config) const { const std::optional<std::filesystem::path> sysfsRootPathOpt = - getSysfsRootPath(devicePath.c_str()); + getSysfsRootForEvdevDevicePath(devicePath.c_str()); if (!sysfsRootPathOpt) { return nullptr; } @@ -1897,58 +1897,89 @@ std::vector<RawEvent> EventHub::getEvents(int timeoutMillis) { break; // return to the caller before we actually rescan } - // Report any devices that had last been added/removed. - for (auto it = mClosingDevices.begin(); it != mClosingDevices.end();) { - std::unique_ptr<Device> device = std::move(*it); - ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, device->path.c_str()); - const int32_t deviceId = (device->id == mBuiltInKeyboardId) - ? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID - : device->id; - events.push_back({ - .when = now, - .deviceId = deviceId, - .type = DEVICE_REMOVED, - }); - it = mClosingDevices.erase(it); - if (events.size() == EVENT_BUFFER_SIZE) { - break; + handleSysfsNodeChangeNotificationsLocked(); + + // Use a do-while loop to ensure that we drain the closing and opening devices loop + // at least once, even if there are no devices to re-open. + do { + if (!mDeviceIdsToReopen.empty()) { + // If there are devices that need to be re-opened, ensure that we re-open them + // one at a time to send the DEVICE_REMOVED and DEVICE_ADDED notifications for + // each before moving on to the next. This is to avoid notifying all device + // removals and additions in one batch, which could cause additional unnecessary + // device added/removed notifications for merged InputDevices from InputReader. + const int32_t deviceId = mDeviceIdsToReopen.back(); + mDeviceIdsToReopen.erase(mDeviceIdsToReopen.end() - 1); + if (auto it = mDevices.find(deviceId); it != mDevices.end()) { + ALOGI("Reopening input device: id=%d, name=%s", it->second->id, + it->second->identifier.name.c_str()); + const auto path = it->second->path; + closeDeviceLocked(*it->second); + openDeviceLocked(path); + } } - } - if (mNeedToScanDevices) { - mNeedToScanDevices = false; - scanDevicesLocked(); - } - - while (!mOpeningDevices.empty()) { - std::unique_ptr<Device> device = std::move(*mOpeningDevices.rbegin()); - mOpeningDevices.pop_back(); - ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, device->path.c_str()); - const int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; - events.push_back({ - .when = now, - .deviceId = deviceId, - .type = DEVICE_ADDED, - }); - - // Try to find a matching video device by comparing device names - for (auto it = mUnattachedVideoDevices.begin(); it != mUnattachedVideoDevices.end(); - it++) { - std::unique_ptr<TouchVideoDevice>& videoDevice = *it; - if (tryAddVideoDeviceLocked(*device, videoDevice)) { - // videoDevice was transferred to 'device' - it = mUnattachedVideoDevices.erase(it); + // Report any devices that had last been added/removed. + for (auto it = mClosingDevices.begin(); it != mClosingDevices.end();) { + std::unique_ptr<Device> device = std::move(*it); + ALOGV("Reporting device closed: id=%d, name=%s\n", device->id, + device->path.c_str()); + const int32_t deviceId = (device->id == mBuiltInKeyboardId) + ? ReservedInputDeviceId::BUILT_IN_KEYBOARD_ID + : device->id; + events.push_back({ + .when = now, + .deviceId = deviceId, + .type = DEVICE_REMOVED, + }); + it = mClosingDevices.erase(it); + if (events.size() == EVENT_BUFFER_SIZE) { break; } } - auto [dev_it, inserted] = mDevices.insert_or_assign(device->id, std::move(device)); - if (!inserted) { - ALOGW("Device id %d exists, replaced.", device->id); + if (mNeedToScanDevices) { + mNeedToScanDevices = false; + scanDevicesLocked(); } - if (events.size() == EVENT_BUFFER_SIZE) { - break; + + while (!mOpeningDevices.empty()) { + std::unique_ptr<Device> device = std::move(*mOpeningDevices.rbegin()); + mOpeningDevices.pop_back(); + ALOGV("Reporting device opened: id=%d, name=%s\n", device->id, + device->path.c_str()); + const int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; + events.push_back({ + .when = now, + .deviceId = deviceId, + .type = DEVICE_ADDED, + }); + + // Try to find a matching video device by comparing device names + for (auto it = mUnattachedVideoDevices.begin(); it != mUnattachedVideoDevices.end(); + it++) { + std::unique_ptr<TouchVideoDevice>& videoDevice = *it; + if (tryAddVideoDeviceLocked(*device, videoDevice)) { + // videoDevice was transferred to 'device' + it = mUnattachedVideoDevices.erase(it); + break; + } + } + + auto [dev_it, inserted] = mDevices.insert_or_assign(device->id, std::move(device)); + if (!inserted) { + ALOGW("Device id %d exists, replaced.", device->id); + } + if (events.size() == EVENT_BUFFER_SIZE) { + break; + } } + + // Perform this loop of re-opening devices so that we re-open one device at a time. + } while (!mDeviceIdsToReopen.empty()); + + if (events.size() == EVENT_BUFFER_SIZE) { + break; } // Grab the next input event. @@ -2664,17 +2695,44 @@ status_t EventHub::disableDevice(int32_t deviceId) { return device->disable(); } +std::filesystem::path EventHub::getSysfsRootPath(int32_t deviceId) const { + std::scoped_lock _l(mLock); + Device* device = getDeviceLocked(deviceId); + if (device == nullptr) { + ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__); + return {}; + } + + return device->associatedDevice ? device->associatedDevice->sysfsRootPath + : std::filesystem::path{}; +} + // TODO(b/274755573): Shift to uevent handling on native side and remove this method // Currently using Java UEventObserver to trigger this which uses UEvent infrastructure that uses a // NETLINK socket to observe UEvents. We can create similar infrastructure on Eventhub side to // directly observe UEvents instead of triggering from Java side. void EventHub::sysfsNodeChanged(const std::string& sysfsNodePath) { - std::scoped_lock _l(mLock); + mChangedSysfsNodeNotifications.emplace(sysfsNodePath); +} + +void EventHub::handleSysfsNodeChangeNotificationsLocked() { + // Use a set to de-dup any repeated notifications. + std::set<std::string> changedNodes; + while (true) { + auto node = mChangedSysfsNodeNotifications.popWithTimeout(std::chrono::nanoseconds(0)); + if (!node.has_value()) break; + changedNodes.emplace(*node); + } + if (changedNodes.empty()) { + return; + } // Testing whether a sysfs node changed involves several syscalls, so use a cache to avoid // testing the same node multiple times. + // TODO(b/281822656): Notify InputReader separately when an AssociatedDevice changes, + // instead of needing to re-open all of Devices that are associated with it. std::map<std::shared_ptr<const AssociatedDevice>, bool /*changed*/> testedDevices; - auto isAssociatedDeviceChanged = [&testedDevices, &sysfsNodePath](const Device& dev) { + auto shouldReopenDevice = [&testedDevices, &changedNodes](const Device& dev) { if (!dev.associatedDevice) { return false; } @@ -2683,45 +2741,45 @@ void EventHub::sysfsNodeChanged(const std::string& sysfsNodePath) { return testedIt->second; } // Cache miss - if (sysfsNodePath.find(dev.associatedDevice->sysfsRootPath.string()) == std::string::npos) { + const bool anyNodesChanged = + std::any_of(changedNodes.begin(), changedNodes.end(), [&](const std::string& node) { + return node.find(dev.associatedDevice->sysfsRootPath.string()) != + std::string::npos; + }); + if (!anyNodesChanged) { testedDevices.emplace(dev.associatedDevice, false); return false; } auto reloadedDevice = AssociatedDevice(dev.associatedDevice->sysfsRootPath, dev.associatedDevice->baseDevConfig); const bool changed = *dev.associatedDevice != reloadedDevice; + if (changed) { + ALOGI("sysfsNodeChanged: Identified change in sysfs nodes for device: %s", + dev.identifier.name.c_str()); + } testedDevices.emplace(dev.associatedDevice, changed); return changed; }; - std::set<Device*> devicesToClose; - std::set<std::string /*path*/> devicesToOpen; - - // Check in opening devices. If its associated device changed, - // the device should be removed from mOpeningDevices and needs to be opened again. - std::erase_if(mOpeningDevices, [&](const auto& dev) { - if (isAssociatedDeviceChanged(*dev)) { - devicesToOpen.emplace(dev->path); - return true; + // Check in opening devices. These can be re-opened directly because we have not yet notified + // the Reader about these devices. + for (const auto& dev : mOpeningDevices) { + if (shouldReopenDevice(*dev)) { + ALOGI("Reopening input device from mOpeningDevices: id=%d, name=%s", dev->id, + dev->identifier.name.c_str()); + const auto path = dev->path; + closeDeviceLocked(*dev); // The Device object is deleted by this function. + openDeviceLocked(path); } - return false; - }); + } - // Check in already added device. If its associated device changed, - // the device needs to be re-opened. + // Check in already added devices. Add them to the re-opening list so they can be + // re-opened serially. for (const auto& [id, dev] : mDevices) { - if (isAssociatedDeviceChanged(*dev)) { - devicesToOpen.emplace(dev->path); - devicesToClose.emplace(dev.get()); + if (shouldReopenDevice(*dev)) { + mDeviceIdsToReopen.emplace_back(dev->id); } } - - for (auto* device : devicesToClose) { - closeDeviceLocked(*device); - } - for (const auto& path : devicesToOpen) { - openDeviceLocked(path); - } } void EventHub::createVirtualKeyboardLocked() { @@ -2817,9 +2875,23 @@ void EventHub::closeDeviceLocked(Device& device) { releaseControllerNumberLocked(device.controllerNumber); device.controllerNumber = 0; device.close(); - mClosingDevices.push_back(std::move(mDevices[device.id])); - mDevices.erase(device.id); + // Try to remove this device from mDevices. + if (auto it = mDevices.find(device.id); it != mDevices.end()) { + mClosingDevices.push_back(std::move(mDevices[device.id])); + mDevices.erase(device.id); + return; + } + + // Try to remove this device from mOpeningDevices. + if (auto it = std::find_if(mOpeningDevices.begin(), mOpeningDevices.end(), + [&device](auto& d) { return d->id == device.id; }); + it != mOpeningDevices.end()) { + mOpeningDevices.erase(it); + return; + } + + LOG_ALWAYS_FATAL("%s: Device with id %d was not found!", __func__, device.id); } base::Result<void> EventHub::readNotifyLocked() { diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index 5e42d57f06..594dcba144 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -136,6 +136,8 @@ void InputDevice::dump(std::string& dump, const std::string& eventHubDevStr) { } else { dump += "<none>\n"; } + dump += StringPrintf(INDENT2 "SysfsRootPath: %s\n", + mSysfsRootPath.empty() ? "<none>" : mSysfsRootPath.c_str()); dump += StringPrintf(INDENT2 "HasMic: %s\n", toString(mHasMic)); dump += StringPrintf(INDENT2 "Sources: %s\n", inputEventSourceToString(deviceInfo.getSources()).c_str()); @@ -195,6 +197,10 @@ void InputDevice::addEmptyEventHubDevice(int32_t eventHubId) { DevicePair& devicePair = mDevices[eventHubId]; devicePair.second = createMappers(*devicePair.first, readerConfig); + if (mSysfsRootPath.empty()) { + mSysfsRootPath = devicePair.first->getSysfsRootPath(); + } + // Must change generation to flag this device as changed bumpGeneration(); return out; diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 58df692b3e..74ef972848 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -917,8 +917,19 @@ bool InputReader::canDispatchToDisplay(int32_t deviceId, ui::LogicalDisplayId di return *associatedDisplayId == displayId; } +std::filesystem::path InputReader::getSysfsRootPath(int32_t deviceId) const { + std::scoped_lock _l(mLock); + + const InputDevice* device = findInputDeviceLocked(deviceId); + if (!device) { + return {}; + } + return device->getSysfsRootPath(); +} + void InputReader::sysfsNodeChanged(const std::string& sysfsNodePath) { mEventHub->sysfsNodeChanged(sysfsNodePath); + mEventHub->wake(); } DeviceId InputReader::getLastUsedInputDeviceId() { diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index adbfdebfb0..9f3a57c265 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -31,6 +31,7 @@ #include <batteryservice/BatteryService.h> #include <ftl/flags.h> +#include <input/BlockingQueue.h> #include <input/Input.h> #include <input/InputDevice.h> #include <input/KeyCharacterMap.h> @@ -398,6 +399,9 @@ public: /* Disable an input device. Closes file descriptor to that device. */ virtual status_t disableDevice(int32_t deviceId) = 0; + /* Gets the sysfs root path for this device. Returns an empty path if there is none. */ + virtual std::filesystem::path getSysfsRootPath(int32_t deviceId) const = 0; + /* Sysfs node changed. Reopen the Eventhub device if any new Peripheral like Light, Battery, * etc. is detected. */ virtual void sysfsNodeChanged(const std::string& sysfsNodePath) = 0; @@ -613,6 +617,8 @@ public: status_t disableDevice(int32_t deviceId) override final; + std::filesystem::path getSysfsRootPath(int32_t deviceId) const override final; + void sysfsNodeChanged(const std::string& sysfsNodePath) override final; bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override final; @@ -775,6 +781,8 @@ private: void addDeviceInputInotify(); void addDeviceInotify(); + void handleSysfsNodeChangeNotificationsLocked() REQUIRES(mLock); + // Protect all internal state. mutable std::mutex mLock; @@ -807,6 +815,7 @@ private: bool mNeedToReopenDevices; bool mNeedToScanDevices; std::vector<std::string> mExcludedDevices; + std::vector<int32_t> mDeviceIdsToReopen; int mEpollFd; int mINotifyFd; @@ -824,6 +833,10 @@ private: size_t mPendingEventCount; size_t mPendingEventIndex; bool mPendingINotify; + + // The sysfs node change notifications that have been sent to EventHub. + // Enqueuing notifications does not require the lock to be held. + BlockingQueue<std::string> mChangedSysfsNodeNotifications; }; } // namespace android diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index 4744dd0e4e..a1a8891940 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -81,6 +81,8 @@ public: inline virtual KeyboardType getKeyboardType() const { return mKeyboardType; } + inline std::filesystem::path getSysfsRootPath() const { return mSysfsRootPath; } + bool isEnabled(); void dump(std::string& dump, const std::string& eventHubDevStr); @@ -209,6 +211,7 @@ private: bool mHasMic; bool mDropUntilNextSync; std::optional<bool> mShouldSmoothScroll; + std::filesystem::path mSysfsRootPath; typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); @@ -471,6 +474,9 @@ public: inline void setKeyboardType(KeyboardType keyboardType) { return mDevice.setKeyboardType(keyboardType); } + inline std::filesystem::path getSysfsRootPath() const { + return mEventHub->getSysfsRootPath(mId); + } inline bool setKernelWakeEnabled(bool enabled) { return mEventHub->setKernelWakeEnabled(mId, enabled); } diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index 6a259373df..9212d37966 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -118,6 +118,8 @@ public: std::optional<std::string> getBluetoothAddress(int32_t deviceId) const override; + std::filesystem::path getSysfsRootPath(int32_t deviceId) const override; + void sysfsNodeChanged(const std::string& sysfsNodePath) override; DeviceId getLastUsedInputDeviceId() override; diff --git a/services/inputflinger/tests/FakeEventHub.cpp b/services/inputflinger/tests/FakeEventHub.cpp index e72c440480..8987b99525 100644 --- a/services/inputflinger/tests/FakeEventHub.cpp +++ b/services/inputflinger/tests/FakeEventHub.cpp @@ -627,6 +627,14 @@ void FakeEventHub::setSysfsRootPath(int32_t deviceId, std::string sysfsRootPath) device->sysfsRootPath = sysfsRootPath; } +std::filesystem::path FakeEventHub::getSysfsRootPath(int32_t deviceId) const { + Device* device = getDevice(deviceId); + if (device == nullptr) { + return {}; + } + return device->sysfsRootPath; +} + void FakeEventHub::sysfsNodeChanged(const std::string& sysfsNodePath) { int32_t foundDeviceId = -1; Device* foundDevice = nullptr; diff --git a/services/inputflinger/tests/FakeEventHub.h b/services/inputflinger/tests/FakeEventHub.h index 143b93b245..1cd33c1c98 100644 --- a/services/inputflinger/tests/FakeEventHub.h +++ b/services/inputflinger/tests/FakeEventHub.h @@ -222,6 +222,7 @@ private: std::optional<int32_t> getLightBrightness(int32_t deviceId, int32_t lightId) const override; std::optional<std::unordered_map<LightColor, int32_t>> getLightIntensities( int32_t deviceId, int32_t lightId) const override; + std::filesystem::path getSysfsRootPath(int32_t deviceId) const override; void sysfsNodeChanged(const std::string& sysfsNodePath) override; void dump(std::string&) const override {} void monitor() const override {} diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 43d2378f61..d1d8192395 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -611,8 +611,10 @@ protected: } void addDevice(int32_t eventHubId, const std::string& name, - ftl::Flags<InputDeviceClass> classes, const PropertyMap* configuration) { + ftl::Flags<InputDeviceClass> classes, const PropertyMap* configuration, + std::string sysfsRootPath = "") { mFakeEventHub->addDevice(eventHubId, name, classes); + mFakeEventHub->setSysfsRootPath(eventHubId, sysfsRootPath); if (configuration) { mFakeEventHub->addConfigurationMap(eventHubId, configuration); @@ -664,6 +666,18 @@ TEST_F(InputReaderTest, PolicyGetInputDevices) { ASSERT_EQ(0U, inputDevices[0].getMotionRanges().size()); } +TEST_F(InputReaderTest, GetSysfsRootPath) { + constexpr std::string SYSFS_ROOT = "xyz"; + ASSERT_NO_FATAL_FAILURE( + addDevice(1, "keyboard", InputDeviceClass::KEYBOARD, nullptr, SYSFS_ROOT)); + + // Should also have received a notification describing the new input device. + ASSERT_EQ(1U, mFakePolicy->getInputDevices().size()); + InputDeviceInfo inputDevice = mFakePolicy->getInputDevices()[0]; + + ASSERT_EQ(SYSFS_ROOT, mReader->getSysfsRootPath(inputDevice.getId()).string()); +} + TEST_F(InputReaderTest, InputDeviceRecreatedOnSysfsNodeChanged) { ASSERT_NO_FATAL_FAILURE(addDevice(1, "keyboard", InputDeviceClass::KEYBOARD, nullptr)); mFakeEventHub->setSysfsRootPath(1, "xyz"); diff --git a/services/inputflinger/tests/InterfaceMocks.h b/services/inputflinger/tests/InterfaceMocks.h index d4e4bb00f7..8eded2e279 100644 --- a/services/inputflinger/tests/InterfaceMocks.h +++ b/services/inputflinger/tests/InterfaceMocks.h @@ -181,6 +181,7 @@ public: MOCK_METHOD(bool, isDeviceEnabled, (int32_t deviceId), (const, override)); MOCK_METHOD(status_t, enableDevice, (int32_t deviceId), (override)); MOCK_METHOD(status_t, disableDevice, (int32_t deviceId), (override)); + MOCK_METHOD(std::filesystem::path, getSysfsRootPath, (int32_t deviceId), (const, override)); MOCK_METHOD(void, sysfsNodeChanged, (const std::string& sysfsNodePath), (override)); MOCK_METHOD(bool, setKernelWakeEnabled, (int32_t deviceId, bool enabled), (override)); }; diff --git a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp index 6be922dfdb..0c8ba50776 100644 --- a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp @@ -165,6 +165,10 @@ public: return reader->getBluetoothAddress(deviceId); } + std::filesystem::path getSysfsRootPath(int32_t deviceId) const { + return reader->getSysfsRootPath(deviceId); + } + void sysfsNodeChanged(const std::string& sysfsNodePath) { reader->sysfsNodeChanged(sysfsNodePath); } @@ -297,6 +301,7 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::chrono::microseconds(fdp->ConsumeIntegral<size_t>())); }, [&]() -> void { reader->getBluetoothAddress(fdp->ConsumeIntegral<int32_t>()); }, + [&]() -> void { reader->getSysfsRootPath(fdp->ConsumeIntegral<int32_t>()); }, })(); } diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index 9a5903981b..f619c48f3f 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -296,6 +296,7 @@ public: bool isDeviceEnabled(int32_t deviceId) const override { return mFdp->ConsumeBool(); } status_t enableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); } status_t disableDevice(int32_t deviceId) override { return mFdp->ConsumeIntegral<status_t>(); } + std::filesystem::path getSysfsRootPath(int32_t deviceId) const override { return {}; } void sysfsNodeChanged(const std::string& sysfsNodePath) override {} bool setKernelWakeEnabled(int32_t deviceId, bool enabled) override { return mFdp->ConsumeBool(); diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp index de7d455fa4..bad5e2e3b5 100644 --- a/services/surfaceflinger/DisplayDevice.cpp +++ b/services/surfaceflinger/DisplayDevice.cpp @@ -50,6 +50,17 @@ namespace android { namespace hal = hardware::graphics::composer::hal; +namespace gui { +inline std::string_view to_string(ISurfaceComposer::OptimizationPolicy optimizationPolicy) { + switch (optimizationPolicy) { + case ISurfaceComposer::OptimizationPolicy::optimizeForPower: + return "optimizeForPower"; + case ISurfaceComposer::OptimizationPolicy::optimizeForPerformance: + return "optimizeForPerformance"; + } +} +} // namespace gui + DisplayDeviceCreationArgs::DisplayDeviceCreationArgs( const sp<SurfaceFlinger>& flinger, HWComposer& hwComposer, const wp<IBinder>& displayToken, std::shared_ptr<compositionengine::Display> compositionDisplay) diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h index 1b14145147..7d7c8adb7b 100644 --- a/services/surfaceflinger/DisplayDevice.h +++ b/services/surfaceflinger/DisplayDevice.h @@ -67,17 +67,6 @@ namespace display { class DisplaySnapshot; } // namespace display -namespace gui { -inline const char* to_string(ISurfaceComposer::OptimizationPolicy optimizationPolicy) { - switch (optimizationPolicy) { - case ISurfaceComposer::OptimizationPolicy::optimizeForPower: - return "optimizeForPower"; - case ISurfaceComposer::OptimizationPolicy::optimizeForPerformance: - return "optimizeForPerformance"; - } -} -} // namespace gui - class DisplayDevice : public RefBase { public: constexpr static float sDefaultMinLumiance = 0.0; diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp index da536b6660..00ec863bd9 100644 --- a/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp +++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.cpp @@ -54,7 +54,8 @@ LayerHierarchy::LayerHierarchy(const LayerHierarchy& hierarchy, bool childrenOnl mChildren = hierarchy.mChildren; } -void LayerHierarchy::traverse(const Visitor& visitor, LayerHierarchy::TraversalPath& traversalPath, +void LayerHierarchy::traverse(const Visitor& visitor, + const LayerHierarchy::TraversalPath& traversalPath, uint32_t depth) const { LLOG_ALWAYS_FATAL_WITH_TRACE_IF(depth > 50, "Cycle detected in LayerHierarchy::traverse. See " @@ -70,14 +71,13 @@ void LayerHierarchy::traverse(const Visitor& visitor, LayerHierarchy::TraversalP LLOG_ALWAYS_FATAL_WITH_TRACE_IF(traversalPath.hasRelZLoop(), "Found relative z loop layerId:%d", traversalPath.invalidRelativeRootId); for (auto& [child, childVariant] : mChildren) { - ScopedAddToTraversalPath addChildToTraversalPath(traversalPath, child->mLayer->id, - childVariant); - child->traverse(visitor, traversalPath, depth + 1); + child->traverse(visitor, traversalPath.makeChild(child->mLayer->id, childVariant), + depth + 1); } } void LayerHierarchy::traverseInZOrder(const Visitor& visitor, - LayerHierarchy::TraversalPath& traversalPath) const { + const LayerHierarchy::TraversalPath& traversalPath) const { bool traverseThisLayer = (mLayer != nullptr); for (auto it = mChildren.begin(); it < mChildren.end(); it++) { auto& [child, childVariant] = *it; @@ -91,9 +91,7 @@ void LayerHierarchy::traverseInZOrder(const Visitor& visitor, if (childVariant == LayerHierarchy::Variant::Detached) { continue; } - ScopedAddToTraversalPath addChildToTraversalPath(traversalPath, child->mLayer->id, - childVariant); - child->traverseInZOrder(visitor, traversalPath); + child->traverseInZOrder(visitor, traversalPath.makeChild(child->mLayer->id, childVariant)); } if (traverseThisLayer) { @@ -568,42 +566,23 @@ std::string LayerHierarchy::TraversalPath::toString() const { return ss.str(); } -// Helper class to update a passed in TraversalPath when visiting a child. When the object goes out -// of scope the TraversalPath is reset to its original state. -LayerHierarchy::ScopedAddToTraversalPath::ScopedAddToTraversalPath(TraversalPath& traversalPath, - uint32_t layerId, - LayerHierarchy::Variant variant) - : mTraversalPath(traversalPath), mParentPath(traversalPath) { - // Update the traversal id with the child layer id and variant. Parent id and variant are - // stored to reset the id upon destruction. - traversalPath.id = layerId; - traversalPath.variant = variant; +LayerHierarchy::TraversalPath LayerHierarchy::TraversalPath::makeChild( + uint32_t layerId, LayerHierarchy::Variant variant) const { + TraversalPath child{*this}; + child.id = layerId; + child.variant = variant; if (LayerHierarchy::isMirror(variant)) { - traversalPath.mirrorRootIds.emplace_back(mParentPath.id); + child.mirrorRootIds.emplace_back(id); } else if (variant == LayerHierarchy::Variant::Relative) { - if (std::find(traversalPath.relativeRootIds.begin(), traversalPath.relativeRootIds.end(), - layerId) != traversalPath.relativeRootIds.end()) { - traversalPath.invalidRelativeRootId = layerId; + if (std::find(relativeRootIds.begin(), relativeRootIds.end(), layerId) != + relativeRootIds.end()) { + child.invalidRelativeRootId = layerId; } - traversalPath.relativeRootIds.emplace_back(layerId); + child.relativeRootIds.emplace_back(layerId); } else if (variant == LayerHierarchy::Variant::Detached) { - traversalPath.detached = true; + child.detached = true; } -} -LayerHierarchy::ScopedAddToTraversalPath::~ScopedAddToTraversalPath() { - // Reset the traversal id to its original parent state using the state that was saved in - // the constructor. - if (LayerHierarchy::isMirror(mTraversalPath.variant)) { - mTraversalPath.mirrorRootIds.pop_back(); - } else if (mTraversalPath.variant == LayerHierarchy::Variant::Relative) { - mTraversalPath.relativeRootIds.pop_back(); - } - if (mTraversalPath.invalidRelativeRootId == mTraversalPath.id) { - mTraversalPath.invalidRelativeRootId = UNASSIGNED_LAYER_ID; - } - mTraversalPath.id = mParentPath.id; - mTraversalPath.variant = mParentPath.variant; - mTraversalPath.detached = mParentPath.detached; + return child; } } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/FrontEnd/LayerHierarchy.h b/services/surfaceflinger/FrontEnd/LayerHierarchy.h index 4fdbae1831..c8c6b4df15 100644 --- a/services/surfaceflinger/FrontEnd/LayerHierarchy.h +++ b/services/surfaceflinger/FrontEnd/LayerHierarchy.h @@ -104,6 +104,8 @@ public: TraversalPath getClonedFrom() const { return {.id = id, .variant = variant}; } + TraversalPath makeChild(uint32_t layerId, LayerHierarchy::Variant variant) const; + bool operator==(const TraversalPath& other) const { return id == other.id && mirrorRootIds == other.mirrorRootIds; } @@ -122,18 +124,6 @@ public: } }; - // Helper class to add nodes to an existing traversal id and removes the - // node when it goes out of scope. - class ScopedAddToTraversalPath { - public: - ScopedAddToTraversalPath(TraversalPath& traversalPath, uint32_t layerId, - LayerHierarchy::Variant variantArg); - ~ScopedAddToTraversalPath(); - - private: - TraversalPath& mTraversalPath; - TraversalPath mParentPath; - }; LayerHierarchy(RequestedLayerState* layer); // Visitor function that provides the hierarchy node and a traversal id which uniquely @@ -191,8 +181,9 @@ private: void removeChild(LayerHierarchy*); void sortChildrenByZOrder(); void updateChild(LayerHierarchy*, LayerHierarchy::Variant); - void traverseInZOrder(const Visitor& visitor, LayerHierarchy::TraversalPath& parent) const; - void traverse(const Visitor& visitor, LayerHierarchy::TraversalPath& parent, + void traverseInZOrder(const Visitor& visitor, + const LayerHierarchy::TraversalPath& parent) const; + void traverse(const Visitor& visitor, const LayerHierarchy::TraversalPath& parent, uint32_t depth = 0) const; void dump(std::ostream& out, const std::string& prefix, LayerHierarchy::Variant variant, bool isLastChild, bool includeMirroredHierarchy) const; diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 28a6031c97..50ed72de9e 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -447,15 +447,14 @@ void LayerSnapshotBuilder::updateSnapshots(const Args& args) { if (args.root.getLayer()) { // The hierarchy can have a root layer when used for screenshots otherwise, it will have // multiple children. - LayerHierarchy::ScopedAddToTraversalPath addChildToPath(root, args.root.getLayer()->id, - LayerHierarchy::Variant::Attached); - updateSnapshotsInHierarchy(args, args.root, root, rootSnapshot, /*depth=*/0); + LayerHierarchy::TraversalPath childPath = + root.makeChild(args.root.getLayer()->id, LayerHierarchy::Variant::Attached); + updateSnapshotsInHierarchy(args, args.root, childPath, rootSnapshot, /*depth=*/0); } else { for (auto& [childHierarchy, variant] : args.root.mChildren) { - LayerHierarchy::ScopedAddToTraversalPath addChildToPath(root, - childHierarchy->getLayer()->id, - variant); - updateSnapshotsInHierarchy(args, *childHierarchy, root, rootSnapshot, /*depth=*/0); + LayerHierarchy::TraversalPath childPath = + root.makeChild(childHierarchy->getLayer()->id, variant); + updateSnapshotsInHierarchy(args, *childHierarchy, childPath, rootSnapshot, /*depth=*/0); } } @@ -520,7 +519,7 @@ void LayerSnapshotBuilder::update(const Args& args) { const LayerSnapshot& LayerSnapshotBuilder::updateSnapshotsInHierarchy( const Args& args, const LayerHierarchy& hierarchy, - LayerHierarchy::TraversalPath& traversalPath, const LayerSnapshot& parentSnapshot, + const LayerHierarchy::TraversalPath& traversalPath, const LayerSnapshot& parentSnapshot, int depth) { LLOG_ALWAYS_FATAL_WITH_TRACE_IF(depth > 50, "Cycle detected in LayerSnapshotBuilder. See " @@ -549,12 +548,10 @@ const LayerSnapshot& LayerSnapshotBuilder::updateSnapshotsInHierarchy( bool childHasValidFrameRate = false; for (auto& [childHierarchy, variant] : hierarchy.mChildren) { - LayerHierarchy::ScopedAddToTraversalPath addChildToPath(traversalPath, - childHierarchy->getLayer()->id, - variant); + LayerHierarchy::TraversalPath childPath = + traversalPath.makeChild(childHierarchy->getLayer()->id, variant); const LayerSnapshot& childSnapshot = - updateSnapshotsInHierarchy(args, *childHierarchy, traversalPath, *snapshot, - depth + 1); + updateSnapshotsInHierarchy(args, *childHierarchy, childPath, *snapshot, depth + 1); updateFrameRateFromChildSnapshot(*snapshot, childSnapshot, *childHierarchy->getLayer(), args, &childHasValidFrameRate); } diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h index 486cb33959..94b7e5fa5a 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h @@ -106,9 +106,10 @@ private: void updateSnapshots(const Args& args); - const LayerSnapshot& updateSnapshotsInHierarchy(const Args&, const LayerHierarchy& hierarchy, - LayerHierarchy::TraversalPath& traversalPath, - const LayerSnapshot& parentSnapshot, int depth); + const LayerSnapshot& updateSnapshotsInHierarchy( + const Args&, const LayerHierarchy& hierarchy, + const LayerHierarchy::TraversalPath& traversalPath, const LayerSnapshot& parentSnapshot, + int depth); void updateSnapshot(LayerSnapshot&, const Args&, const RequestedLayerState&, const LayerSnapshot& parentSnapshot, const LayerHierarchy::TraversalPath&); static void updateRelativeState(LayerSnapshot& snapshot, const LayerSnapshot& parentSnapshot, diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp index 84b1a73e0b..280d66e12a 100644 --- a/services/surfaceflinger/LayerProtoHelper.cpp +++ b/services/surfaceflinger/LayerProtoHelper.cpp @@ -278,10 +278,9 @@ LayerProtoFromSnapshotGenerator& LayerProtoFromSnapshotGenerator::with( stackIdsToSkip.find(child->getLayer()->layerStack.id) != stackIdsToSkip.end()) { continue; } - frontend::LayerHierarchy::ScopedAddToTraversalPath addChildToPath(path, - child->getLayer()->id, - variant); - LayerProtoFromSnapshotGenerator::writeHierarchyToProto(*child, path); + LayerProtoFromSnapshotGenerator::writeHierarchyToProto(*child, + path.makeChild(child->getLayer()->id, + variant)); } // fill in relative and parent info @@ -338,7 +337,8 @@ LayerProtoFromSnapshotGenerator& LayerProtoFromSnapshotGenerator::withOffscreenL } frontend::LayerSnapshot* LayerProtoFromSnapshotGenerator::getSnapshot( - frontend::LayerHierarchy::TraversalPath& path, const frontend::RequestedLayerState& layer) { + const frontend::LayerHierarchy::TraversalPath& path, + const frontend::RequestedLayerState& layer) { frontend::LayerSnapshot* snapshot = mSnapshotBuilder.getSnapshot(path); if (snapshot) { return snapshot; @@ -349,7 +349,7 @@ frontend::LayerSnapshot* LayerProtoFromSnapshotGenerator::getSnapshot( } void LayerProtoFromSnapshotGenerator::writeHierarchyToProto( - const frontend::LayerHierarchy& root, frontend::LayerHierarchy::TraversalPath& path) { + const frontend::LayerHierarchy& root, const frontend::LayerHierarchy::TraversalPath& path) { using Variant = frontend::LayerHierarchy::Variant; perfetto::protos::LayerProto* layerProto = mLayersProto.add_layers(); const frontend::RequestedLayerState& layer = *root.getLayer(); @@ -362,10 +362,8 @@ void LayerProtoFromSnapshotGenerator::writeHierarchyToProto( LayerProtoHelper::writeSnapshotToProto(layerProto, layer, *snapshot, mTraceFlags); for (const auto& [child, variant] : root.mChildren) { - frontend::LayerHierarchy::ScopedAddToTraversalPath addChildToPath(path, - child->getLayer()->id, - variant); - frontend::LayerSnapshot* childSnapshot = getSnapshot(path, layer); + frontend::LayerSnapshot* childSnapshot = + getSnapshot(path.makeChild(child->getLayer()->id, variant), layer); if (variant == Variant::Attached || variant == Variant::Detached || frontend::LayerHierarchy::isMirror(variant)) { mChildToParent[childSnapshot->uniqueSequence] = snapshot->uniqueSequence; @@ -388,10 +386,7 @@ void LayerProtoFromSnapshotGenerator::writeHierarchyToProto( if (variant == Variant::Detached) { continue; } - frontend::LayerHierarchy::ScopedAddToTraversalPath addChildToPath(path, - child->getLayer()->id, - variant); - writeHierarchyToProto(*child, path); + writeHierarchyToProto(*child, path.makeChild(child->getLayer()->id, variant)); } } diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h index 3ca553a903..28924e45be 100644 --- a/services/surfaceflinger/LayerProtoHelper.h +++ b/services/surfaceflinger/LayerProtoHelper.h @@ -98,8 +98,8 @@ public: private: void writeHierarchyToProto(const frontend::LayerHierarchy& root, - frontend::LayerHierarchy::TraversalPath& path); - frontend::LayerSnapshot* getSnapshot(frontend::LayerHierarchy::TraversalPath& path, + const frontend::LayerHierarchy::TraversalPath& path); + frontend::LayerSnapshot* getSnapshot(const frontend::LayerHierarchy::TraversalPath& path, const frontend::RequestedLayerState& layer); const frontend::LayerSnapshotBuilder& mSnapshotBuilder; diff --git a/services/surfaceflinger/QueuedTransactionState.h b/services/surfaceflinger/QueuedTransactionState.h index 86683da26c..6a17a0d0cb 100644 --- a/services/surfaceflinger/QueuedTransactionState.h +++ b/services/surfaceflinger/QueuedTransactionState.h @@ -25,6 +25,7 @@ #include <common/FlagManager.h> #include <ftl/flags.h> #include <gui/LayerState.h> +#include <gui/TransactionState.h> #include <system/window.h> namespace android { @@ -50,33 +51,26 @@ public: struct QueuedTransactionState { QueuedTransactionState() = default; - QueuedTransactionState(const FrameTimelineInfo& frameTimelineInfo, - std::vector<ResolvedComposerState>& composerStates, - const Vector<DisplayState>& displayStates, uint32_t transactionFlags, - const sp<IBinder>& applyToken, - const InputWindowCommands& inputWindowCommands, - int64_t desiredPresentTime, bool isAutoTimestamp, - std::vector<uint64_t> uncacheBufferIds, int64_t postTime, - bool hasListenerCallbacks, - std::vector<ListenerCallbacks> listenerCallbacks, int originPid, - int originUid, uint64_t transactionId, - std::vector<uint64_t> mergedTransactionIds) - : frameTimelineInfo(frameTimelineInfo), - states(std::move(composerStates)), - displays(displayStates), - flags(transactionFlags), - applyToken(applyToken), - inputWindowCommands(inputWindowCommands), - desiredPresentTime(desiredPresentTime), - isAutoTimestamp(isAutoTimestamp), + QueuedTransactionState(TransactionState&& transactionState, + std::vector<ResolvedComposerState>&& composerStates, + std::vector<uint64_t>&& uncacheBufferIds, int64_t postTime, + int originPid, int originUid) + : frameTimelineInfo(std::move(transactionState.mFrameTimelineInfo)), + states(composerStates), + displays(std::move(transactionState.mDisplayStates)), + flags(transactionState.mFlags), + applyToken(transactionState.mApplyToken), + inputWindowCommands(std::move(transactionState.mInputWindowCommands)), + desiredPresentTime(transactionState.mDesiredPresentTime), + isAutoTimestamp(transactionState.mIsAutoTimestamp), uncacheBufferIds(std::move(uncacheBufferIds)), postTime(postTime), - hasListenerCallbacks(hasListenerCallbacks), - listenerCallbacks(listenerCallbacks), + hasListenerCallbacks(transactionState.mHasListenerCallbacks), + listenerCallbacks(std::move(transactionState.mListenerCallbacks)), originPid(originPid), originUid(originUid), - id(transactionId), - mergedTransactionIds(std::move(mergedTransactionIds)) {} + id(transactionState.getId()), + mergedTransactionIds(std::move(transactionState.mMergedTransactionIds)) {} // Invokes `void(const layer_state_t&)` visitor for matching layers. template <typename Visitor> @@ -135,7 +129,7 @@ struct QueuedTransactionState { FrameTimelineInfo frameTimelineInfo; std::vector<ResolvedComposerState> states; - Vector<DisplayState> displays; + std::vector<DisplayState> displays; uint32_t flags; sp<IBinder> applyToken; InputWindowCommands inputWindowCommands; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index c9d3b31061..16266c6b00 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -124,7 +124,10 @@ void Scheduler::setPacesetterDisplay(PhysicalDisplayId pacesetterId) { // Cancel the pending refresh rate change, if any, before updating the phase configuration. mVsyncModulator->cancelRefreshRateChange(); - mVsyncConfiguration->reset(); + { + std::scoped_lock lock{mVsyncConfigLock}; + mVsyncConfiguration->reset(); + } updatePhaseConfiguration(pacesetterId, pacesetterSelectorPtr()->getActiveMode().fps); } @@ -211,7 +214,7 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId, .vsyncId = vsyncId, .expectedVsyncTime = expectedVsyncTime, .sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration, - .hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration, + .hwcMinWorkDuration = getCurrentVsyncConfigs().hwcMinWorkDuration, .debugPresentTimeDelay = debugPresentDelay}; ftl::NonNull<const Display*> pacesetterPtr = pacesetterPtrLocked(); @@ -516,12 +519,26 @@ void Scheduler::updatePhaseConfiguration(PhysicalDisplayId displayId, Fps refres if (!isPacesetter) return; mRefreshRateStats->setRefreshRate(refreshRate); - mVsyncConfiguration->setRefreshRateFps(refreshRate); - setVsyncConfig(mVsyncModulator->setVsyncConfigSet(mVsyncConfiguration->getCurrentConfigs()), - refreshRate.getPeriod()); + const auto currentConfigs = [=, this] { + std::scoped_lock lock{mVsyncConfigLock}; + mVsyncConfiguration->setRefreshRateFps(refreshRate); + return mVsyncConfiguration->getCurrentConfigs(); + }(); + setVsyncConfig(mVsyncModulator->setVsyncConfigSet(currentConfigs), refreshRate.getPeriod()); } #pragma clang diagnostic pop +void Scheduler::reloadPhaseConfiguration(Fps refreshRate, Duration minSfDuration, + Duration maxSfDuration, Duration appDuration) { + const auto currentConfigs = [=, this] { + std::scoped_lock lock{mVsyncConfigLock}; + mVsyncConfiguration = std::make_unique<impl::WorkDuration>(refreshRate, minSfDuration, + maxSfDuration, appDuration); + return mVsyncConfiguration->getCurrentConfigs(); + }(); + setVsyncConfig(mVsyncModulator->setVsyncConfigSet(currentConfigs), refreshRate.getPeriod()); +} + void Scheduler::setActiveDisplayPowerModeForRefreshRateStats(hal::PowerMode powerMode) { mRefreshRateStats->setPowerMode(powerMode); } @@ -896,8 +913,11 @@ void Scheduler::dump(utils::Dumper& dumper) const { mFrameRateOverrideMappings.dump(dumper); dumper.eol(); - mVsyncConfiguration->dump(dumper.out()); - dumper.eol(); + { + std::scoped_lock lock{mVsyncConfigLock}; + mVsyncConfiguration->dump(dumper.out()); + dumper.eol(); + } mRefreshRateStats->dump(dumper.out()); dumper.eol(); diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 61469c1b46..694856e9ce 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -53,6 +53,7 @@ #include "RefreshRateSelector.h" #include "SmallAreaDetectionAllowMappings.h" #include "Utils/Dumper.h" +#include "VsyncConfiguration.h" #include "VsyncModulator.h" #include <FrontEnd/LayerHierarchy.h> @@ -95,7 +96,7 @@ public: // TODO: b/241285191 - Remove this API by promoting pacesetter in onScreen{Acquired,Released}. void setPacesetterDisplay(PhysicalDisplayId) REQUIRES(kMainThreadContext) - EXCLUDES(mDisplayLock); + EXCLUDES(mDisplayLock, mVsyncConfigLock); using RefreshRateSelectorPtr = std::shared_ptr<RefreshRateSelector>; @@ -188,9 +189,19 @@ public: } } - void updatePhaseConfiguration(PhysicalDisplayId, Fps); + void updatePhaseConfiguration(PhysicalDisplayId, Fps) EXCLUDES(mVsyncConfigLock); + void reloadPhaseConfiguration(Fps, Duration minSfDuration, Duration maxSfDuration, + Duration appDuration) EXCLUDES(mVsyncConfigLock); - const VsyncConfiguration& getVsyncConfiguration() const { return *mVsyncConfiguration; } + VsyncConfigSet getCurrentVsyncConfigs() const EXCLUDES(mVsyncConfigLock) { + std::scoped_lock lock{mVsyncConfigLock}; + return mVsyncConfiguration->getCurrentConfigs(); + } + + VsyncConfigSet getVsyncConfigsForRefreshRate(Fps refreshRate) const EXCLUDES(mVsyncConfigLock) { + std::scoped_lock lock{mVsyncConfigLock}; + return mVsyncConfiguration->getConfigsForRefreshRate(refreshRate); + } // Sets the render rate for the scheduler to run at. void setRenderRate(PhysicalDisplayId, Fps, bool applyImmediately); @@ -266,7 +277,7 @@ public: bool isVsyncInPhase(TimePoint expectedVsyncTime, Fps frameRate) const; - void dump(utils::Dumper&) const; + void dump(utils::Dumper&) const EXCLUDES(mVsyncConfigLock); void dump(Cycle, std::string&) const; void dumpVsync(std::string&) const EXCLUDES(mDisplayLock); @@ -348,7 +359,7 @@ private: // impl::MessageQueue overrides: void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override - REQUIRES(kMainThreadContext, mDisplayLock); + REQUIRES(kMainThreadContext, mDisplayLock) EXCLUDES(mVsyncConfigLock); // Used to skip event dispatch before EventThread creation during boot. // TODO: b/241285191 - Reorder Scheduler initialization to avoid this. @@ -476,8 +487,9 @@ private: const FeatureFlags mFeatures; + mutable std::mutex mVsyncConfigLock; // Stores phase offsets configured per refresh rate. - const std::unique_ptr<VsyncConfiguration> mVsyncConfiguration; + std::unique_ptr<VsyncConfiguration> mVsyncConfiguration GUARDED_BY(mVsyncConfigLock); // Shifts the VSYNC phase during certain transactions and refresh rate changes. const sp<VsyncModulator> mVsyncModulator; diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp index 6ae10f3d31..8cbb17c06e 100644 --- a/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp +++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.cpp @@ -362,6 +362,17 @@ WorkDuration::WorkDuration(Fps currentRefreshRate) validateSysprops(); } +WorkDuration::WorkDuration(Fps currentRefreshRate, Duration minSfDuration, Duration maxSfDuration, + Duration appDuration) + : WorkDuration(currentRefreshRate, + /*sfDuration*/ minSfDuration.ns(), + /*appDuration*/ appDuration.ns(), + /*sfEarlyDuration*/ maxSfDuration.ns(), + /*appEarlyDuration*/ appDuration.ns(), + /*sfEarlyGpuDuration*/ maxSfDuration.ns(), + /*appEarlyGpuDuration*/ appDuration.ns(), + /*hwcMinWorkDuration*/ 0) {} + WorkDuration::WorkDuration(Fps currentRefreshRate, nsecs_t sfDuration, nsecs_t appDuration, nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration, nsecs_t sfEarlyGpuDuration, nsecs_t appEarlyGpuDuration, diff --git a/services/surfaceflinger/Scheduler/VsyncConfiguration.h b/services/surfaceflinger/Scheduler/VsyncConfiguration.h index b6cb373b7e..3d8ae3e5d4 100644 --- a/services/surfaceflinger/Scheduler/VsyncConfiguration.h +++ b/services/surfaceflinger/Scheduler/VsyncConfiguration.h @@ -144,6 +144,8 @@ private: class WorkDuration : public VsyncConfiguration { public: explicit WorkDuration(Fps currentRefreshRate); + WorkDuration(Fps currentRefreshRate, Duration minSfDuration, Duration maxSfDuration, + Duration appDuration); protected: // Used for unit tests diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6b40c98d0a..03ee3006ae 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1226,8 +1226,8 @@ void SurfaceFlinger::getDynamicDisplayInfoInternal(ui::DynamicDisplayInfo*& info outMode.peakRefreshRate = peakFps.getValue(); outMode.vsyncRate = mode->getVsyncRate().getValue(); - const auto vsyncConfigSet = mScheduler->getVsyncConfiguration().getConfigsForRefreshRate( - Fps::fromValue(outMode.peakRefreshRate)); + const auto vsyncConfigSet = + mScheduler->getVsyncConfigsForRefreshRate(Fps::fromValue(outMode.peakRefreshRate)); outMode.appVsyncOffset = vsyncConfigSet.late.appOffset; outMode.sfVsyncOffset = vsyncConfigSet.late.sfOffset; outMode.group = mode->getGroup(); @@ -3326,8 +3326,7 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, const auto schedule = mScheduler->getVsyncSchedule(); const TimePoint vsyncDeadline = schedule->vsyncDeadlineAfter(presentTime); const Fps renderRate = pacesetterDisplay->refreshRateSelector().getActiveMode().fps; - const nsecs_t vsyncPhase = - mScheduler->getVsyncConfiguration().getCurrentConfigs().late.sfOffset; + const nsecs_t vsyncPhase = mScheduler->getCurrentVsyncConfigs().late.sfOffset; const CompositorTiming compositorTiming(vsyncDeadline.ns(), renderRate.getPeriodNsecs(), vsyncPhase, presentLatency.ns()); @@ -4657,7 +4656,7 @@ void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) { /*applyImmediately*/ true); } - const auto configs = mScheduler->getVsyncConfiguration().getCurrentConfigs(); + const auto configs = mScheduler->getCurrentVsyncConfigs(); mScheduler->createEventThread(scheduler::Cycle::Render, mFrameTimeline->getTokenManager(), /* workDuration */ configs.late.appWorkDuration, @@ -4991,13 +4990,7 @@ bool SurfaceFlinger::shouldLatchUnsignaled(const layer_state_t& state, size_t nu return true; } -status_t SurfaceFlinger::setTransactionState( - const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& states, - Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, - InputWindowCommands inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, - const std::vector<client_cache_t>& uncacheBuffers, bool hasListenerCallbacks, - const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId, - const std::vector<uint64_t>& mergedTransactionIds) { +status_t SurfaceFlinger::setTransactionState(TransactionState&& transactionState) { SFTRACE_CALL(); IPCThreadState* ipc = IPCThreadState::self(); @@ -5005,7 +4998,7 @@ status_t SurfaceFlinger::setTransactionState( const int originUid = ipc->getCallingUid(); uint32_t permissions = LayerStatePermissions::getTransactionPermissions(originPid, originUid); ftl::Flags<adpf::Workload> queuedWorkload; - for (auto& composerState : states) { + for (auto& composerState : transactionState.mComposerStates) { composerState.state.sanitize(permissions); if (composerState.state.what & layer_state_t::COMPOSITION_EFFECTS) { queuedWorkload |= adpf::Workload::EFFECTS; @@ -5015,27 +5008,27 @@ status_t SurfaceFlinger::setTransactionState( } } - for (DisplayState& display : displays) { + for (DisplayState& display : transactionState.mDisplayStates) { display.sanitize(permissions); } - if (!inputWindowCommands.empty() && + if (!transactionState.mInputWindowCommands.empty() && (permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER) == 0) { ALOGE("Only privileged callers are allowed to send input commands."); - inputWindowCommands.clear(); + transactionState.mInputWindowCommands.clear(); } - if (flags & (eEarlyWakeupStart | eEarlyWakeupEnd)) { + if (transactionState.mFlags & (eEarlyWakeupStart | eEarlyWakeupEnd)) { const bool hasPermission = (permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER) || callingThreadHasPermission(sWakeupSurfaceFlinger); if (!hasPermission) { ALOGE("Caller needs permission android.permission.WAKEUP_SURFACE_FLINGER to use " "eEarlyWakeup[Start|End] flags"); - flags &= ~(eEarlyWakeupStart | eEarlyWakeupEnd); + transactionState.mFlags &= ~(eEarlyWakeupStart | eEarlyWakeupEnd); } } - if (flags & eEarlyWakeupStart) { + if (transactionState.mFlags & eEarlyWakeupStart) { queuedWorkload |= adpf::Workload::WAKEUP; } mPowerAdvisor->setQueuedWorkload(queuedWorkload); @@ -5043,8 +5036,8 @@ status_t SurfaceFlinger::setTransactionState( const int64_t postTime = systemTime(); std::vector<uint64_t> uncacheBufferIds; - uncacheBufferIds.reserve(uncacheBuffers.size()); - for (const auto& uncacheBuffer : uncacheBuffers) { + uncacheBufferIds.reserve(transactionState.mUncacheBuffers.size()); + for (const auto& uncacheBuffer : transactionState.mUncacheBuffers) { sp<GraphicBuffer> buffer = ClientCache::getInstance().erase(uncacheBuffer); if (buffer != nullptr) { uncacheBufferIds.push_back(buffer->getId()); @@ -5052,8 +5045,8 @@ status_t SurfaceFlinger::setTransactionState( } std::vector<ResolvedComposerState> resolvedStates; - resolvedStates.reserve(states.size()); - for (auto& state : states) { + resolvedStates.reserve(transactionState.mComposerStates.size()); + for (auto& state : transactionState.mComposerStates) { resolvedStates.emplace_back(std::move(state)); auto& resolvedState = resolvedStates.back(); resolvedState.layerId = LayerHandle::getLayerId(resolvedState.state.surface); @@ -5064,7 +5057,7 @@ status_t SurfaceFlinger::setTransactionState( (layer) ? layer->getDebugName() : std::to_string(resolvedState.state.layerId); resolvedState.externalTexture = getExternalTextureFromBufferData(*resolvedState.state.bufferData, - layerName.c_str(), transactionId); + layerName.c_str(), transactionState.getId()); if (resolvedState.externalTexture) { resolvedState.state.bufferData->buffer = resolvedState.externalTexture->getBuffer(); if (FlagManager::getInstance().monitor_buffer_fences()) { @@ -5092,22 +5085,12 @@ status_t SurfaceFlinger::setTransactionState( } } - QueuedTransactionState state{frameTimelineInfo, - resolvedStates, - displays, - flags, - applyToken, - std::move(inputWindowCommands), - desiredPresentTime, - isAutoTimestamp, + QueuedTransactionState state{std::move(transactionState), + std::move(resolvedStates), std::move(uncacheBufferIds), postTime, - hasListenerCallbacks, - listenerCallbacks, originPid, - originUid, - transactionId, - mergedTransactionIds}; + originUid}; state.workloadHint = queuedWorkload; if (mTransactionTracing) { @@ -5121,6 +5104,9 @@ status_t SurfaceFlinger::setTransactionState( }(state.flags); const auto frameHint = state.isFrameActive() ? FrameHint::kActive : FrameHint::kNone; + // Copy fields of |state| needed after it is moved into queueTransaction + VsyncId vsyncId{state.frameTimelineInfo.vsyncId}; + auto applyToken = state.applyToken; { // Transactions are added via a lockless queue and does not need to be added from the main // thread. @@ -5130,7 +5116,7 @@ status_t SurfaceFlinger::setTransactionState( for (const auto& [displayId, data] : mNotifyExpectedPresentMap) { if (data.hintStatus.load() == NotifyExpectedPresentHintStatus::ScheduleOnTx) { - scheduleNotifyExpectedPresentHint(displayId, VsyncId{frameTimelineInfo.vsyncId}); + scheduleNotifyExpectedPresentHint(displayId, vsyncId); } } setTransactionFlags(eTransactionFlushNeeded, schedule, applyToken, frameHint); @@ -5139,7 +5125,7 @@ status_t SurfaceFlinger::setTransactionState( bool SurfaceFlinger::applyTransactionState( const FrameTimelineInfo& frameTimelineInfo, std::vector<ResolvedComposerState>& states, - Vector<DisplayState>& displays, uint32_t flags, + std::span<DisplayState> displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, bool isAutoTimestamp, const std::vector<uint64_t>& uncacheBufferIds, const int64_t postTime, bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, @@ -5629,7 +5615,8 @@ void SurfaceFlinger::initializeDisplays() { auto layerStack = ui::DEFAULT_LAYER_STACK.id; for (const auto& [id, display] : FTL_FAKE_GUARD(mStateLock, mPhysicalDisplays)) { - state.displays.push(DisplayState(display.token(), ui::LayerStack::fromValue(layerStack++))); + state.displays.emplace_back( + DisplayState(display.token(), ui::LayerStack::fromValue(layerStack++))); } std::vector<QueuedTransactionState> transactions; @@ -5697,13 +5684,7 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa incRefreshableDisplays(); } - if (displayId == mActiveDisplayId && - FlagManager::getInstance().correct_virtual_display_power_state()) { - applyOptimizationPolicy(__func__); - } - const auto activeMode = display->refreshRateSelector().getActiveMode().modePtr; - using OptimizationPolicy = gui::ISurfaceComposer::OptimizationPolicy; if (currentMode == hal::PowerMode::OFF) { // Turn on the display @@ -5718,10 +5699,12 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa onActiveDisplayChangedLocked(activeDisplay.get(), *display); } - if (displayId == mActiveDisplayId && - !FlagManager::getInstance().correct_virtual_display_power_state()) { - optimizeThreadScheduling("setPhysicalDisplayPowerMode(ON/DOZE)", - OptimizationPolicy::optimizeForPerformance); + if (displayId == mActiveDisplayId) { + if (FlagManager::getInstance().correct_virtual_display_power_state()) { + applyOptimizationPolicy("setPhysicalDisplayPowerMode(ON)"); + } else { + disablePowerOptimizations("setPhysicalDisplayPowerMode(ON)"); + } } getHwComposer().setPowerMode(displayId, mode); @@ -5730,8 +5713,7 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa mScheduler->getVsyncSchedule(displayId)->getPendingHardwareVsyncState(); requestHardwareVsync(displayId, enable); - if (displayId == mActiveDisplayId && - !FlagManager::getInstance().correct_virtual_display_power_state()) { + if (displayId == mActiveDisplayId) { mScheduler->enableSyntheticVsync(false); } @@ -5748,13 +5730,13 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa if (const auto display = getActivatableDisplay()) { onActiveDisplayChangedLocked(activeDisplay.get(), *display); } else { - if (!FlagManager::getInstance().correct_virtual_display_power_state()) { - optimizeThreadScheduling("setPhysicalDisplayPowerMode(OFF)", - OptimizationPolicy::optimizeForPower); + if (FlagManager::getInstance().correct_virtual_display_power_state()) { + applyOptimizationPolicy("setPhysicalDisplayPowerMode(OFF)"); + } else { + enablePowerOptimizations("setPhysicalDisplayPowerMode(OFF)"); } - if (currentModeNotDozeSuspend && - !FlagManager::getInstance().correct_virtual_display_power_state()) { + if (currentModeNotDozeSuspend) { mScheduler->enableSyntheticVsync(); } } @@ -5782,9 +5764,7 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa ALOGI("Force repainting for DOZE_SUSPEND -> DOZE or ON."); mVisibleRegionsDirty = true; scheduleRepaint(); - if (!FlagManager::getInstance().correct_virtual_display_power_state()) { - mScheduler->enableSyntheticVsync(false); - } + mScheduler->enableSyntheticVsync(false); } constexpr bool kAllowToEnable = true; mScheduler->resyncToHardwareVsync(displayId, kAllowToEnable, activeMode.get()); @@ -5794,8 +5774,7 @@ void SurfaceFlinger::setPhysicalDisplayPowerMode(const sp<DisplayDevice>& displa constexpr bool kDisallow = true; mScheduler->disableHardwareVsync(displayId, kDisallow); - if (displayId == mActiveDisplayId && - !FlagManager::getInstance().correct_virtual_display_power_state()) { + if (displayId == mActiveDisplayId) { mScheduler->enableSyntheticVsync(); } getHwComposer().setPowerMode(displayId, mode); @@ -5834,44 +5813,43 @@ void SurfaceFlinger::setVirtualDisplayPowerMode(const sp<DisplayDevice>& display to_string(displayId).c_str()); } -void SurfaceFlinger::optimizeThreadScheduling( - const char* whence, gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy) { - ALOGD("%s: Optimizing thread scheduling: %s", whence, to_string(optimizationPolicy)); +bool SurfaceFlinger::shouldOptimizeForPerformance() { + for (const auto& [_, display] : mDisplays) { + // Displays that are optimized for power are always powered on and should not influence + // whether there is an active display for the purpose of power optimization, etc. If these + // displays are being shown somewhere, a different (physical or virtual) display that is + // optimized for performance will be powered on in addition. Displays optimized for + // performance will change power mode, so if they are off then they are not active. + if (display->isPoweredOn() && + display->getOptimizationPolicy() == + gui::ISurfaceComposer::OptimizationPolicy::optimizeForPerformance) { + return true; + } + } + return false; +} + +void SurfaceFlinger::enablePowerOptimizations(const char* whence) { + ALOGD("%s: Enabling power optimizations", whence); + + setSchedAttr(false, whence); + setSchedFifo(false, whence); +} + +void SurfaceFlinger::disablePowerOptimizations(const char* whence) { + ALOGD("%s: Disabling power optimizations", whence); - const bool optimizeForPerformance = - optimizationPolicy == gui::ISurfaceComposer::OptimizationPolicy::optimizeForPerformance; // TODO: b/281692563 - Merge the syscalls. For now, keep uclamp in a separate syscall // and set it before SCHED_FIFO due to b/190237315. - setSchedAttr(optimizeForPerformance, whence); - setSchedFifo(optimizeForPerformance, whence); + setSchedAttr(true, whence); + setSchedFifo(true, whence); } void SurfaceFlinger::applyOptimizationPolicy(const char* whence) { - using OptimizationPolicy = gui::ISurfaceComposer::OptimizationPolicy; - - const bool optimizeForPerformance = - std::any_of(mDisplays.begin(), mDisplays.end(), [](const auto& pair) { - const auto& display = pair.second; - return display->isPoweredOn() && - display->getOptimizationPolicy() == - OptimizationPolicy::optimizeForPerformance; - }); - - optimizeThreadScheduling(whence, - optimizeForPerformance ? OptimizationPolicy::optimizeForPerformance - : OptimizationPolicy::optimizeForPower); - - if (mScheduler) { - const bool disableSyntheticVsync = - std::any_of(mDisplays.begin(), mDisplays.end(), [](const auto& pair) { - const auto& display = pair.second; - const hal::PowerMode powerMode = display->getPowerMode(); - return powerMode != hal::PowerMode::OFF && - powerMode != hal::PowerMode::DOZE_SUSPEND && - display->getOptimizationPolicy() == - OptimizationPolicy::optimizeForPerformance; - }); - mScheduler->enableSyntheticVsync(!disableSyntheticVsync); + if (shouldOptimizeForPerformance()) { + disablePowerOptimizations(whence); + } else { + enablePowerOptimizations(whence); } } @@ -6647,9 +6625,9 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { code == IBinder::SYSPROPS_TRANSACTION) { return OK; } - // Numbers from 1000 to 1045 are currently used for backdoors. The code + // Numbers from 1000 to 1047 are currently used for backdoors. The code // in onTransact verifies that the user is root, and has access to use SF. - if (code >= 1000 && code <= 1046) { + if (code >= 1000 && code <= 1047) { ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code); return OK; } @@ -7192,6 +7170,34 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r mScheduler->setDebugPresentDelay(TimePoint::fromNs(ms2ns(jankDelayMs))); return NO_ERROR; } + // Update WorkDuration + // parameters: + // - (required) i64 minSfNs, used as the late.sf WorkDuration. + // - (required) i64 maxSfNs, used as the early.sf and earlyGl.sf WorkDuration. + // - (required) i64 appDurationNs, used as the late.app, early.app and earlyGl.app + // WorkDuration. + // Usage: + // adb shell service call SurfaceFlinger 1047 i64 12333333 i64 16666666 i64 16666666 + case 1047: { + if (!property_get_bool("debug.sf.use_phase_offsets_as_durations", false)) { + ALOGE("Not supported when work duration is not enabled"); + return INVALID_OPERATION; + } + int64_t minSfNs = 0; + int64_t maxSfNs = 0; + int64_t appDurationNs = 0; + if (data.readInt64(&minSfNs) != NO_ERROR || data.readInt64(&maxSfNs) != NO_ERROR || + data.readInt64(&appDurationNs) != NO_ERROR) { + return BAD_VALUE; + } + mScheduler->reloadPhaseConfiguration(mDisplayModeController + .getActiveMode(mActiveDisplayId) + .fps, + Duration::fromNs(minSfNs), + Duration::fromNs(maxSfNs), + Duration::fromNs(appDurationNs)); + return NO_ERROR; + } } } return err; @@ -8376,8 +8382,7 @@ uint32_t SurfaceFlinger::getMaxAcquiredBufferCountForCurrentRefreshRate(uid_t ui } int SurfaceFlinger::getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const { - const auto vsyncConfig = - mScheduler->getVsyncConfiguration().getConfigsForRefreshRate(refreshRate).late; + const auto vsyncConfig = mScheduler->getVsyncConfigsForRefreshRate(refreshRate).late; const auto presentLatency = vsyncConfig.appWorkDuration + vsyncConfig.sfWorkDuration; return calculateMaxAcquiredBufferCount(refreshRate, presentLatency); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c472c4c6d4..fe8998403e 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -545,13 +545,7 @@ private: } sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const; - status_t setTransactionState( - const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& state, - Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, - InputWindowCommands inputWindowCommands, int64_t desiredPresentTime, - bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffers, - bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, - uint64_t transactionId, const std::vector<uint64_t>& mergedTransactionIds) override; + status_t setTransactionState(TransactionState&&) override; void bootFinished(); status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const; sp<IDisplayEventConnection> createDisplayEventConnection( @@ -739,14 +733,19 @@ private: void setVirtualDisplayPowerMode(const sp<DisplayDevice>& display, hal::PowerMode mode) REQUIRES(mStateLock, kMainThreadContext); - // Adjusts thread scheduling according to the optimization policy - static void optimizeThreadScheduling( - const char* whence, gui::ISurfaceComposer::OptimizationPolicy optimizationPolicy); + // Returns whether to optimize globally for performance instead of power. + bool shouldOptimizeForPerformance() REQUIRES(mStateLock); + + // Turns on power optimizations, for example when there are no displays to be optimized for + // performance. + static void enablePowerOptimizations(const char* whence); + + // Turns off power optimizations. + static void disablePowerOptimizations(const char* whence); // Enables or disables power optimizations depending on whether there are displays that should // be optimized for performance. - void applyOptimizationPolicy(const char* whence) REQUIRES(kMainThreadContext) - REQUIRES(mStateLock); + void applyOptimizationPolicy(const char* whence) REQUIRES(mStateLock); // Returns the preferred mode for PhysicalDisplayId if the Scheduler has selected one for that // display. Falls back to the display's defaultModeId otherwise. @@ -793,7 +792,7 @@ private: */ bool applyTransactionState(const FrameTimelineInfo& info, std::vector<ResolvedComposerState>& state, - Vector<DisplayState>& displays, uint32_t flags, + std::span<DisplayState> displays, uint32_t flags, const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime, bool isAutoTimestamp, const std::vector<uint64_t>& uncacheBufferIds, diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index 3297c16113..6bbc04cf6f 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -321,7 +321,7 @@ QueuedTransactionState TransactionProtoParser::fromProto( int32_t displayCount = proto.display_changes_size(); t.displays.reserve(static_cast<size_t>(displayCount)); for (int i = 0; i < displayCount; i++) { - t.displays.add(fromProto(proto.display_changes(i))); + t.displays.emplace_back(fromProto(proto.display_changes(i))); } return t; } diff --git a/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp b/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp index 46b98f9193..192602d7d2 100644 --- a/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp +++ b/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp @@ -52,6 +52,8 @@ protected: }; TEST_F(DereferenceSurfaceControlTest, LayerNotInTransaction) { + // Last strong pointer is removed, the layer is destroyed and is removed + // from compostion. fgLayer = nullptr; { SCOPED_TRACE("after setting null"); @@ -61,7 +63,9 @@ TEST_F(DereferenceSurfaceControlTest, LayerNotInTransaction) { } TEST_F(DereferenceSurfaceControlTest, LayerInTransaction) { - auto transaction = Transaction().show(fgLayer); + Transaction transaction; + transaction.show(fgLayer); + // |transaction| retains a strong pointer, so layer is retained. fgLayer = nullptr; { SCOPED_TRACE("after setting null"); diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp index 18bd3b92d2..94cb878311 100644 --- a/services/surfaceflinger/tests/IPC_test.cpp +++ b/services/surfaceflinger/tests/IPC_test.cpp @@ -42,14 +42,22 @@ using CallbackInfo = SurfaceComposerClient::CallbackInfo; using TCLHash = SurfaceComposerClient::TCLHash; using android::hardware::graphics::common::V1_1::BufferUsage; -class TransactionHelper : public Transaction { +class TransactionHelper : public Transaction, public Parcelable { public: + TransactionHelper() : Transaction() {} size_t getNumListeners() { return mListenerCallbacks.size(); } std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash> getListenerCallbacks() { return mListenerCallbacks; } + status_t writeToParcel(Parcel* parcel) const override { + return Transaction::writeToParcel(parcel); + } + + status_t readFromParcel(const Parcel* parcel) override { + return Transaction::readFromParcel(parcel); + } }; class IPCTestUtils { diff --git a/services/surfaceflinger/tests/end2end/OWNERS b/services/surfaceflinger/tests/end2end/OWNERS new file mode 100644 index 0000000000..aa5b5957a2 --- /dev/null +++ b/services/surfaceflinger/tests/end2end/OWNERS @@ -0,0 +1,7 @@ +lpique@google.com # primary POC +bwidawsk@google.com +ddavenport@google.com +markyacoub@google.com +sukoo@google.com + +include platform/frameworks/native:/services/surfaceflinger/OWNERS diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp index 6cc6322bfc..9c143fdd41 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp @@ -45,28 +45,15 @@ protected: void setTransactionState() { ASSERT_TRUE(mFlinger.getTransactionQueue().isEmpty()); TransactionInfo transaction; - mFlinger.setTransactionState(FrameTimelineInfo{}, transaction.states, transaction.displays, - transaction.flags, transaction.applyToken, - transaction.inputWindowCommands, - TimePoint::now().ns() + s2ns(1), transaction.isAutoTimestamp, - transaction.unCachedBuffers, - /*HasListenerCallbacks=*/false, transaction.callbacks, - transaction.id, transaction.mergedTransactionIds); + mFlinger.setTransactionState(std::move(transaction)); } - struct TransactionInfo { - Vector<ComposerState> states; - Vector<DisplayState> displays; - uint32_t flags = 0; - sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); - InputWindowCommands inputWindowCommands; - int64_t desiredPresentTime = 0; - bool isAutoTimestamp = false; - FrameTimelineInfo frameTimelineInfo{}; - std::vector<client_cache_t> unCachedBuffers; - uint64_t id = static_cast<uint64_t>(-1); - std::vector<uint64_t> mergedTransactionIds; - std::vector<ListenerCallbacks> callbacks; + struct TransactionInfo : public TransactionState { + TransactionInfo() { + mApplyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); + mIsAutoTimestamp = false; + mId = static_cast<uint64_t>(-1); + } }; struct Compositor final : ICompositor { @@ -383,4 +370,4 @@ TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentRenderRateChanged) { } } } -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp index 2332bf62da..d5c22a9601 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPhysicalDisplayPowerModeTest.cpp @@ -17,7 +17,6 @@ #undef LOG_TAG #define LOG_TAG "LibSurfaceFlingerUnittests" -#include <android_companion_virtualdevice_flags.h> #include <com_android_graphics_surfaceflinger_flags.h> #include <common/test/FlagUtils.h> #include "DisplayTransactionTestHelpers.h" @@ -79,19 +78,11 @@ struct EventThreadBaseSupportedVariant { struct EventThreadNotSupportedVariant : public EventThreadBaseSupportedVariant { static void setupEnableVsyncCallExpectations(DisplayTransactionTest* test) { EXPECT_CALL(test->mFlinger.scheduler()->mockRequestHardwareVsync, Call(_, true)).Times(1); - setupDisableSyntheticVsyncCallExpectations(test); - } - - static void setupDisableSyntheticVsyncCallExpectations(DisplayTransactionTest* test) { EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(_)).Times(0); } static void setupDisableVsyncCallExpectations(DisplayTransactionTest* test) { EXPECT_CALL(test->mFlinger.scheduler()->mockRequestHardwareVsync, Call(_, false)).Times(1); - setupEnableSyntheticVsyncCallExpectations(test); - } - - static void setupEnableSyntheticVsyncCallExpectations(DisplayTransactionTest* test) { EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(_)).Times(0); } }; @@ -100,20 +91,12 @@ struct EventThreadIsSupportedVariant : public EventThreadBaseSupportedVariant { static void setupEnableVsyncCallExpectations(DisplayTransactionTest* test) { // Expect to enable hardware VSYNC and disable synthetic VSYNC. EXPECT_CALL(test->mFlinger.scheduler()->mockRequestHardwareVsync, Call(_, true)).Times(1); - setupDisableSyntheticVsyncCallExpectations(test); - } - - static void setupDisableSyntheticVsyncCallExpectations(DisplayTransactionTest* test) { EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(false)).Times(1); } static void setupDisableVsyncCallExpectations(DisplayTransactionTest* test) { // Expect to disable hardware VSYNC and enable synthetic VSYNC. EXPECT_CALL(test->mFlinger.scheduler()->mockRequestHardwareVsync, Call(_, false)).Times(1); - setupEnableSyntheticVsyncCallExpectations(test); - } - - static void setupEnableSyntheticVsyncCallExpectations(DisplayTransactionTest* test) { EXPECT_CALL(*test->mEventThread, enableSyntheticVsync(true)).Times(1); } }; @@ -168,7 +151,7 @@ struct TransitionOffToDozeSuspendVariant template <typename Case> static void setupCallExpectations(DisplayTransactionTest* test) { Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND); - Case::EventThread::setupEnableSyntheticVsyncCallExpectations(test); + Case::EventThread::setupVsyncNoCallExpectations(test); Case::setupRepaintEverythingCallExpectations(test); } @@ -193,7 +176,7 @@ struct TransitionDozeSuspendToOffVariant : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::OFF> { template <typename Case> static void setupCallExpectations(DisplayTransactionTest* test) { - Case::EventThread::setupEnableSyntheticVsyncCallExpectations(test); + Case::EventThread::setupVsyncNoCallExpectations(test); Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF); } @@ -205,7 +188,7 @@ struct TransitionDozeSuspendToOffVariant struct TransitionOnToDozeVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE> { template <typename Case> static void setupCallExpectations(DisplayTransactionTest* test) { - Case::EventThread::setupDisableSyntheticVsyncCallExpectations(test); + Case::EventThread::setupVsyncNoCallExpectations(test); Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE); } }; @@ -223,7 +206,7 @@ struct TransitionDozeSuspendToDozeVariant struct TransitionDozeToOnVariant : public TransitionVariantCommon<PowerMode::DOZE, PowerMode::ON> { template <typename Case> static void setupCallExpectations(DisplayTransactionTest* test) { - Case::EventThread::setupDisableSyntheticVsyncCallExpectations(test); + Case::EventThread::setupVsyncNoCallExpectations(test); Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON); } }; @@ -251,7 +234,7 @@ struct TransitionOnToUnknownVariant : public TransitionVariantCommon<PowerMode::ON, static_cast<PowerMode>(POWER_MODE_LEET)> { template <typename Case> static void setupCallExpectations(DisplayTransactionTest* test) { - Case::EventThread::setupDisableSyntheticVsyncCallExpectations(test); + Case::EventThread::setupVsyncNoCallExpectations(test); Case::setupNoComposerPowerModeCallExpectations(test); } }; @@ -352,9 +335,6 @@ void SetPhysicalDisplayPowerModeTest::transitionDisplayCommon() { // -------------------------------------------------------------------- // Preconditions - SET_FLAG_FOR_TEST(android::companion::virtualdevice::flags::correct_virtual_display_power_state, - true); - Case::Doze::setupComposerCallExpectations(this); auto display = Case::injectDisplayWithInitialPowerMode(this, Case::Transition::INITIAL_POWER_MODE); diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index c5973db109..13c32bdf08 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -519,18 +519,8 @@ public: return mFlinger->mTransactionHandler.mPendingTransactionCount.load(); } - auto setTransactionState( - const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& states, - Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken, - const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, - bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffers, - bool hasListenerCallbacks, std::vector<ListenerCallbacks>& listenerCallbacks, - uint64_t transactionId, const std::vector<uint64_t>& mergedTransactionIds) { - return mFlinger->setTransactionState(frameTimelineInfo, states, displays, flags, applyToken, - inputWindowCommands, desiredPresentTime, - isAutoTimestamp, uncacheBuffers, hasListenerCallbacks, - listenerCallbacks, transactionId, - mergedTransactionIds); + auto setTransactionState(TransactionState&& state) { + return mFlinger->setTransactionState(std::move(state)); } auto setTransactionStateInternal(QueuedTransactionState& transaction) { diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 69dfcc4a8f..1395fb6af3 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -17,6 +17,8 @@ #undef LOG_TAG #define LOG_TAG "TransactionApplicationTest" +#include <cstdint> + #include <binder/Binder.h> #include <common/test/FlagUtils.h> #include <compositionengine/Display.h> @@ -69,38 +71,32 @@ public: TestableSurfaceFlinger mFlinger; renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine(); - struct TransactionInfo { - Vector<ComposerState> states; - Vector<DisplayState> displays; - uint32_t flags = 0; - sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); - InputWindowCommands inputWindowCommands; - int64_t desiredPresentTime = 0; - bool isAutoTimestamp = true; - FrameTimelineInfo frameTimelineInfo; - std::vector<client_cache_t> uncacheBuffers; - uint64_t id = static_cast<uint64_t>(-1); - std::vector<uint64_t> mergedTransactionIds; - static_assert(0xffffffffffffffff == static_cast<uint64_t>(-1)); + struct TransactionInfo : public TransactionState { + TransactionInfo() { + mApplyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance()); + mId = static_cast<uint64_t>(-1); + } }; - void checkEqual(TransactionInfo info, QueuedTransactionState state) { - EXPECT_EQ(0u, info.states.size()); + void checkEqual(const TransactionInfo& info, const QueuedTransactionState& state) { + EXPECT_EQ(0u, info.mComposerStates.size()); EXPECT_EQ(0u, state.states.size()); - EXPECT_EQ(0u, info.displays.size()); + EXPECT_EQ(0u, info.mDisplayStates.size()); EXPECT_EQ(0u, state.displays.size()); - EXPECT_EQ(info.flags, state.flags); - EXPECT_EQ(info.desiredPresentTime, state.desiredPresentTime); + EXPECT_EQ(info.mFlags, state.flags); + EXPECT_EQ(info.mDesiredPresentTime, state.desiredPresentTime); } void setupSingle(TransactionInfo& transaction, uint32_t flags, int64_t desiredPresentTime, bool isAutoTimestamp, const FrameTimelineInfo& frameTimelineInfo) { mTransactionNumber++; - transaction.flags |= flags; - transaction.desiredPresentTime = desiredPresentTime; - transaction.isAutoTimestamp = isAutoTimestamp; - transaction.frameTimelineInfo = frameTimelineInfo; + transaction.mFlags |= flags; + transaction.mDesiredPresentTime = desiredPresentTime; + transaction.mIsAutoTimestamp = isAutoTimestamp; + transaction.mFrameTimelineInfo = frameTimelineInfo; + transaction.mHasListenerCallbacks = mHasListenerCallbacks; + transaction.mListenerCallbacks = mCallbacks; } void NotPlacedOnTransactionQueue(uint32_t flags) { @@ -111,12 +107,7 @@ public: /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, FrameTimelineInfo{}); nsecs_t applicationTime = systemTime(); - mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, - transaction.displays, transaction.flags, - transaction.applyToken, transaction.inputWindowCommands, - transaction.desiredPresentTime, transaction.isAutoTimestamp, - transaction.uncacheBuffers, mHasListenerCallbacks, mCallbacks, - transaction.id, transaction.mergedTransactionIds); + mFlinger.setTransactionState(std::move(transaction)); // If transaction is synchronous, SF applyTransactionState should time out (5s) wating for // SF to commit the transaction. If this is animation, it should not time out waiting. @@ -138,12 +129,7 @@ public: setupSingle(transaction, flags, /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{}); nsecs_t applicationSentTime = systemTime(); - mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, - transaction.displays, transaction.flags, - transaction.applyToken, transaction.inputWindowCommands, - transaction.desiredPresentTime, transaction.isAutoTimestamp, - transaction.uncacheBuffers, mHasListenerCallbacks, mCallbacks, - transaction.id, transaction.mergedTransactionIds); + mFlinger.setTransactionState(std::move(transaction)); nsecs_t returnedTime = systemTime(); EXPECT_LE(returnedTime, applicationSentTime + TRANSACTION_TIMEOUT); @@ -169,12 +155,7 @@ public: /*isAutoTimestamp*/ true, FrameTimelineInfo{}); nsecs_t applicationSentTime = systemTime(); - mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, - transactionA.displays, transactionA.flags, - transactionA.applyToken, transactionA.inputWindowCommands, - transactionA.desiredPresentTime, transactionA.isAutoTimestamp, - transactionA.uncacheBuffers, mHasListenerCallbacks, mCallbacks, - transactionA.id, transactionA.mergedTransactionIds); + mFlinger.setTransactionState(std::move(transactionA)); // This thread should not have been blocked by the above transaction // (5s is the timeout period that applyTransactionState waits for SF to @@ -184,12 +165,7 @@ public: mFlinger.flushTransactionQueues(); applicationSentTime = systemTime(); - mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states, - transactionB.displays, transactionB.flags, - transactionB.applyToken, transactionB.inputWindowCommands, - transactionB.desiredPresentTime, transactionB.isAutoTimestamp, - transactionB.uncacheBuffers, mHasListenerCallbacks, mCallbacks, - transactionB.id, transactionB.mergedTransactionIds); + mFlinger.setTransactionState(std::move(transactionB)); // this thread should have been blocked by the above transaction // if this is an animation, this thread should be blocked for 5s @@ -222,12 +198,7 @@ TEST_F(TransactionApplicationTest, AddToPendingQueue) { TransactionInfo transactionA; // transaction to go on pending queue setupSingle(transactionA, /*flags*/ 0, /*desiredPresentTime*/ s2ns(1), false, FrameTimelineInfo{}); - mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, - transactionA.displays, transactionA.flags, transactionA.applyToken, - transactionA.inputWindowCommands, transactionA.desiredPresentTime, - transactionA.isAutoTimestamp, transactionA.uncacheBuffers, - mHasListenerCallbacks, mCallbacks, transactionA.id, - transactionA.mergedTransactionIds); + mFlinger.setTransactionState(std::move(transactionA)); auto& transactionQueue = mFlinger.getTransactionQueue(); ASSERT_FALSE(transactionQueue.isEmpty()); @@ -243,12 +214,7 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { TransactionInfo transactionA; // transaction to go on pending queue setupSingle(transactionA, /*flags*/ 0, /*desiredPresentTime*/ s2ns(1), false, FrameTimelineInfo{}); - mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, - transactionA.displays, transactionA.flags, transactionA.applyToken, - transactionA.inputWindowCommands, transactionA.desiredPresentTime, - transactionA.isAutoTimestamp, transactionA.uncacheBuffers, - mHasListenerCallbacks, mCallbacks, transactionA.id, - transactionA.mergedTransactionIds); + mFlinger.setTransactionState(std::move(transactionA)); auto& transactionQueue = mFlinger.getTransactionQueue(); ASSERT_FALSE(transactionQueue.isEmpty()); @@ -257,12 +223,10 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { // transaction here (sending a null applyToken to fake it as from a // different process) to re-query and reset the cached expected present time TransactionInfo empty; - empty.applyToken = sp<IBinder>(); - mFlinger.setTransactionState(empty.frameTimelineInfo, empty.states, empty.displays, empty.flags, - empty.applyToken, empty.inputWindowCommands, - empty.desiredPresentTime, empty.isAutoTimestamp, - empty.uncacheBuffers, mHasListenerCallbacks, mCallbacks, empty.id, - empty.mergedTransactionIds); + empty.mApplyToken = sp<IBinder>(); + empty.mHasListenerCallbacks = mHasListenerCallbacks; + empty.mListenerCallbacks = mCallbacks; + mFlinger.setTransactionState(std::move(empty)); // flush transaction queue should flush as desiredPresentTime has // passed @@ -406,9 +370,9 @@ public: const auto kFrameTimelineInfo = FrameTimelineInfo{}; setupSingle(transaction, kFlags, kDesiredPresentTime, kIsAutoTimestamp, kFrameTimelineInfo); - transaction.applyToken = applyToken; + transaction.mApplyToken = applyToken; for (const auto& state : states) { - transaction.states.push_back(state); + transaction.mComposerStates.push_back(state); } return transaction; @@ -419,8 +383,8 @@ public: EXPECT_TRUE(mFlinger.getTransactionQueue().isEmpty()); EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); std::unordered_set<uint32_t> createdLayers; - for (auto transaction : transactions) { - for (auto& state : transaction.states) { + for (auto& transaction : transactions) { + for (auto& state : transaction.mComposerStates) { auto layerId = static_cast<uint32_t>(state.state.layerId); if (createdLayers.find(layerId) == createdLayers.end()) { mFlinger.addLayer(layerId); @@ -434,8 +398,8 @@ public: for (auto transaction : transactions) { std::vector<ResolvedComposerState> resolvedStates; - resolvedStates.reserve(transaction.states.size()); - for (auto& state : transaction.states) { + resolvedStates.reserve(transaction.mComposerStates.size()); + for (auto& state : transaction.mComposerStates) { ResolvedComposerState resolvedState; resolvedState.state = std::move(state.state); resolvedState.externalTexture = @@ -446,15 +410,9 @@ public: resolvedStates.emplace_back(resolvedState); } - QueuedTransactionState transactionState(transaction.frameTimelineInfo, resolvedStates, - transaction.displays, transaction.flags, - transaction.applyToken, - transaction.inputWindowCommands, - transaction.desiredPresentTime, - transaction.isAutoTimestamp, {}, systemTime(), - mHasListenerCallbacks, mCallbacks, getpid(), - static_cast<int>(getuid()), transaction.id, - transaction.mergedTransactionIds); + QueuedTransactionState transactionState(std::move(transaction), + std::move(resolvedStates), {}, systemTime(), + getpid(), static_cast<int>(getuid())); mFlinger.setTransactionStateInternal(transactionState); } mFlinger.flushTransactionQueues(); diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp index d3eec5c6f3..b36ad213c8 100644 --- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp @@ -66,7 +66,7 @@ TEST(TransactionProtoParserTest, parse) { display.token = nullptr; } display.width = 85; - t1.displays.add(display); + t1.displays.push_back(display); } class TestMapper : public TransactionProtoParser::FlingerDataMapper { diff --git a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp index 21ee071f1b..3589553be0 100644 --- a/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp +++ b/services/surfaceflinger/tests/unittests/VsyncConfigurationTest.cpp @@ -22,6 +22,8 @@ #include <chrono> #include <thread> +#include <scheduler/Time.h> + #include "Scheduler/VsyncConfiguration.h" using namespace testing; @@ -39,6 +41,10 @@ public: : impl::WorkDuration(currentFps, sfDuration, appDuration, sfEarlyDuration, appEarlyDuration, sfEarlyGlDuration, appEarlyGlDuration, hwcMinWorkDuration) {} + + TestableWorkDuration(Fps currentFps, Duration minSfDuration, Duration maxSfDuration, + Duration appDuration) + : impl::WorkDuration(currentFps, minSfDuration, maxSfDuration, appDuration) {} }; class WorkDurationTest : public testing::Test { @@ -168,6 +174,35 @@ TEST_F(WorkDurationTest, minHwcWorkDuration) { EXPECT_EQ(mWorkDuration.getCurrentConfigs().hwcMinWorkDuration, 1234ns); } +TEST_F(WorkDurationTest, workDurationIsARange) { + const Duration minSfDuration = Duration::fromNs(10'500'000); + const Duration maxSfDuration = Duration::fromNs(20'500'000); + const Duration appDuration = Duration::fromNs(16'000'000); + const TestableWorkDuration workDuration{60_Hz, minSfDuration, maxSfDuration, appDuration}; + + auto currentOffsets = workDuration.getCurrentConfigs(); + auto offsets = workDuration.getConfigsForRefreshRate(60_Hz); + + EXPECT_EQ(currentOffsets, offsets); + EXPECT_EQ(offsets.late.sfOffset, 6'166'667); + EXPECT_EQ(offsets.late.appOffset, 6'833'334); + + EXPECT_EQ(offsets.late.sfWorkDuration, 10'500'000ns); + EXPECT_EQ(offsets.late.appWorkDuration, 16'000'000ns); + + EXPECT_EQ(offsets.early.sfOffset, -3'833'333); + EXPECT_EQ(offsets.early.appOffset, 13'500'001); + + EXPECT_EQ(offsets.early.sfWorkDuration, 20'500'000ns); + EXPECT_EQ(offsets.early.appWorkDuration, 16'000'000ns); + + EXPECT_EQ(offsets.earlyGpu.sfOffset, -3'833'333); + EXPECT_EQ(offsets.earlyGpu.appOffset, 13'500'001); + + EXPECT_EQ(offsets.earlyGpu.sfWorkDuration, 20'500'000ns); + EXPECT_EQ(offsets.earlyGpu.appWorkDuration, 16'000'000ns); +} + class TestablePhaseOffsets : public impl::PhaseOffsets { public: TestablePhaseOffsets(nsecs_t vsyncPhaseOffsetNs, nsecs_t sfVSyncPhaseOffsetNs, |