diff options
Diffstat (limited to 'libs')
51 files changed, 1452 insertions, 687 deletions
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index ea5343a2a0..a3499c1963 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -277,15 +277,6 @@ cc_defaults { "-fvisibility=hidden", "-DBUILDING_LIBBINDER", ], - - target: { - vendor: { - // Trimming the exported symbols reveals a bug in vendor code, so - // disable it for the vendor variant for now. http://b/349657329 - // TODO: Fix the issue and remove this override. - cflags: ["-fvisibility=default"], - }, - }, } cc_defaults { diff --git a/libs/binder/BackendUnifiedServiceManager.cpp b/libs/binder/BackendUnifiedServiceManager.cpp index 7c0319aead..b1c8994b05 100644 --- a/libs/binder/BackendUnifiedServiceManager.cpp +++ b/libs/binder/BackendUnifiedServiceManager.cpp @@ -130,7 +130,13 @@ os::ServiceWithMetadata createServiceWithMetadata(const sp<IBinder>& service, bo bool BinderCacheWithInvalidation::isClientSideCachingEnabled(const std::string& serviceName) { sp<ProcessState> self = ProcessState::selfOrNull(); - if (!self || self->getThreadPoolMaxTotalThreadCount() <= 0) { + // Should not cache if process state could not be found, or if thread pool + // max could is not greater than zero. + if (!self) { + ALOGW("Service retrieved before binder threads started. If they are to be started, " + "consider starting binder threads earlier."); + return false; + } else if (self->getThreadPoolMaxTotalThreadCount() <= 0) { ALOGW("Thread Pool max thread count is 0. Cannot cache binder as linkToDeath cannot be " "implemented. serviceName: %s", serviceName.c_str()); diff --git a/libs/binder/rust/rpcbinder/src/lib.rs b/libs/binder/rust/rpcbinder/src/lib.rs index 7e5c9ddc35..774bb21efe 100644 --- a/libs/binder/rust/rpcbinder/src/lib.rs +++ b/libs/binder/rust/rpcbinder/src/lib.rs @@ -20,6 +20,8 @@ mod server; mod session; pub use server::RpcServer; +#[cfg(target_os = "trusty")] +pub use server::RpcServerConnection; #[cfg(not(target_os = "trusty"))] pub use server::RpcServerRef; pub use session::{FileDescriptorTransportMode, RpcSession, RpcSessionRef}; diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs index 6a8a69843a..771c65bf92 100644 --- a/libs/binder/rust/src/binder.rs +++ b/libs/binder/rust/src/binder.rs @@ -1160,6 +1160,12 @@ macro_rules! declare_binder_enum { pub const fn enum_values() -> [Self; $size] { [$(Self::$name),*] } + + #[inline(always)] + #[allow(missing_docs)] + pub const fn get(&self) -> $backing { + self.0 + } } impl std::fmt::Debug for $enum { diff --git a/libs/binder/trusty/include/binder/RpcServerTrusty.h b/libs/binder/trusty/include/binder/RpcServerTrusty.h index 583ad015e1..127676bf9a 100644 --- a/libs/binder/trusty/include/binder/RpcServerTrusty.h +++ b/libs/binder/trusty/include/binder/RpcServerTrusty.h @@ -94,9 +94,8 @@ private: static sp<RpcServer> makeRpcServer(std::unique_ptr<RpcTransportCtx> ctx) { auto rpcServer = sp<RpcServer>::make(std::move(ctx)); - // TODO(b/266741352): follow-up to prevent needing this in the future - // Trusty needs to be set to the latest stable version that is in prebuilts there. - LOG_ALWAYS_FATAL_IF(!rpcServer->setProtocolVersion(0)); + // By default we use the latest stable version. + LOG_ALWAYS_FATAL_IF(!rpcServer->setProtocolVersion(RPC_WIRE_PROTOCOL_VERSION)); return rpcServer; } diff --git a/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp index 451383a90a..12e347e4f3 100644 --- a/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp +++ b/libs/binder/trusty/rust/binder_rpc_server_bindgen/cpp/ARpcServerTrusty.cpp @@ -27,6 +27,13 @@ using android::RpcTransportCtxFactoryTipcTrusty; using android::sp; using android::wp; +// The default behavior in trusty is to allow handles to be passed with tipc IPC. +// We add mode NONE so that servers do not reject connections from clients who do +// not change their default transport mode. +static const std::vector<RpcSession::FileDescriptorTransportMode> TRUSTY_SERVER_SUPPORTED_FD_MODES = + {RpcSession::FileDescriptorTransportMode::TRUSTY, + RpcSession::FileDescriptorTransportMode::NONE}; + struct ARpcServerTrusty { sp<RpcServer> mRpcServer; @@ -53,6 +60,8 @@ ARpcServerTrusty* ARpcServerTrusty_newPerSession(AIBinder* (*cb)(const void*, si return nullptr; } + rpcServer->setSupportedFileDescriptorTransportModes(TRUSTY_SERVER_SUPPORTED_FD_MODES); + rpcServer->setPerSessionRootObject( [cb, cbArgSp](wp<RpcSession> /*session*/, const void* addrPtr, size_t len) { auto* aib = (*cb)(addrPtr, len, cbArgSp.get()); diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 626581cc2a..03e6456ea6 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -639,7 +639,7 @@ const std::vector<std::string>& GraphicsEnv::getAngleEglFeatures() { // List of ANGLE features to override (enabled or disable). // The list of overrides is loaded and parsed by GpuService. void GraphicsEnv::updateAngleFeatureOverrides() { - if (!graphicsenv_flags::feature_overrides()) { + if (!graphicsenv_flags::angle_feature_overrides()) { return; } @@ -654,7 +654,7 @@ void GraphicsEnv::updateAngleFeatureOverrides() { void GraphicsEnv::getAngleFeatureOverrides(std::vector<const char*>& enabled, std::vector<const char*>& disabled) { - if (!graphicsenv_flags::feature_overrides()) { + if (!graphicsenv_flags::angle_feature_overrides()) { return; } diff --git a/libs/graphicsenv/graphicsenv_flags.aconfig b/libs/graphicsenv/graphicsenv_flags.aconfig index ac66362242..efa4bca892 100644 --- a/libs/graphicsenv/graphicsenv_flags.aconfig +++ b/libs/graphicsenv/graphicsenv_flags.aconfig @@ -2,8 +2,8 @@ package: "com.android.graphics.graphicsenv.flags" container: "system" flag { - name: "feature_overrides" - namespace: "core_graphics" - description: "This flag controls the Feature Overrides in GraphicsEnv." + name: "angle_feature_overrides" + namespace: "gpu" + description: "This flag controls the ANGLE Feature Overrides in GraphicsEnv." bug: "372694741" } diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 5ab31dbaba..b5fa321fc2 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -281,6 +281,7 @@ filegroup { "SurfaceControl.cpp", "SurfaceComposerClient.cpp", "SyncFeatures.cpp", + "TransactionState.cpp", "VsyncEventData.cpp", "view/Surface.cpp", "WindowInfosListenerReporter.cpp", diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index fa971426a7..1aae13c1f4 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -937,15 +937,22 @@ public: : Surface(igbp, controlledByApp, scHandle), mBbq(bbq) {} void allocateBuffers() override { + ATRACE_CALL(); uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth; uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight; auto gbp = getIGraphicBufferProducer(); - std::thread ([reqWidth, reqHeight, gbp=getIGraphicBufferProducer(), - reqFormat=mReqFormat, reqUsage=mReqUsage] () { + std::thread allocateThread([reqWidth, reqHeight, gbp = getIGraphicBufferProducer(), + reqFormat = mReqFormat, reqUsage = mReqUsage]() { + if (com_android_graphics_libgui_flags_allocate_buffer_priority()) { + androidSetThreadName("allocateBuffers"); + pid_t tid = gettid(); + androidSetThreadPriority(tid, ANDROID_PRIORITY_DISPLAY); + } + gbp->allocateBuffers(reqWidth, reqHeight, reqFormat, reqUsage); - - }).detach(); + }); + allocateThread.detach(); } status_t setFrameRate(float frameRate, int8_t compatibility, diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp index 1585aae45c..4926ceb619 100644 --- a/libs/gui/BufferItemConsumer.cpp +++ b/libs/gui/BufferItemConsumer.cpp @@ -17,6 +17,7 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "BufferItemConsumer" //#define ATRACE_TAG ATRACE_TAG_GRAPHICS +#include <utils/Errors.h> #include <utils/Log.h> #include <inttypes.h> @@ -132,13 +133,36 @@ status_t BufferItemConsumer::acquireBuffer(BufferItem *item, return OK; } +status_t BufferItemConsumer::attachBuffer(const sp<GraphicBuffer>& buffer) { + if (!buffer) { + BI_LOGE("BufferItemConsumer::attachBuffer no input buffer specified."); + return BAD_VALUE; + } + + Mutex::Autolock _l(mMutex); + + int slot = INVALID_BUFFER_SLOT; + status_t status = mConsumer->attachBuffer(&slot, buffer); + if (status != OK) { + BI_LOGE("BufferItemConsumer::attachBuffer unable to attach buffer %d", status); + return status; + } + + mSlots[slot] = { + .mGraphicBuffer = buffer, + .mFence = nullptr, + .mFrameNumber = 0, + }; + + return OK; +} + status_t BufferItemConsumer::releaseBuffer(const BufferItem &item, const sp<Fence>& releaseFence) { Mutex::Autolock _l(mMutex); return releaseBufferSlotLocked(item.mSlot, item.mGraphicBuffer, releaseFence); } -#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) status_t BufferItemConsumer::releaseBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& releaseFence) { Mutex::Autolock _l(mMutex); @@ -154,7 +178,6 @@ status_t BufferItemConsumer::releaseBuffer(const sp<GraphicBuffer>& buffer, return releaseBufferSlotLocked(slotIndex, buffer, releaseFence); } -#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) status_t BufferItemConsumer::releaseBufferSlotLocked(int slotIndex, const sp<GraphicBuffer>& buffer, const sp<Fence>& releaseFence) { diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 270bfbdc64..4681c9ecbe 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -14,10 +14,6 @@ * limitations under the License. */ -#include <inttypes.h> -#include <pwd.h> -#include <sys/types.h> - #define LOG_TAG "BufferQueueConsumer" #define ATRACE_TAG ATRACE_TAG_GRAPHICS //#define LOG_NDEBUG 0 @@ -48,6 +44,11 @@ #include <com_android_graphics_libgui_flags.h> +#include <inttypes.h> +#include <pwd.h> +#include <sys/types.h> +#include <optional> + namespace android { // Macros for include BufferQueueCore information in log messages @@ -767,11 +768,15 @@ status_t BufferQueueConsumer::setMaxBufferCount(int bufferCount) { return NO_ERROR; } +status_t BufferQueueConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { + return setMaxAcquiredBufferCount(maxAcquiredBuffers, std::nullopt); +} + status_t BufferQueueConsumer::setMaxAcquiredBufferCount( - int maxAcquiredBuffers) { + int maxAcquiredBuffers, std::optional<OnBufferReleasedCallback> onBuffersReleasedCallback) { ATRACE_FORMAT("%s(%d)", __func__, maxAcquiredBuffers); - sp<IConsumerListener> listener; + std::optional<OnBufferReleasedCallback> callback; { // Autolock scope std::unique_lock<std::mutex> lock(mCore->mMutex); @@ -833,13 +838,20 @@ status_t BufferQueueConsumer::setMaxAcquiredBufferCount( BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers); mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers; VALIDATE_CONSISTENCY(); - if (delta < 0 && mCore->mBufferReleasedCbEnabled) { - listener = mCore->mConsumerListener; + if (delta < 0) { + if (onBuffersReleasedCallback) { + callback = std::move(onBuffersReleasedCallback); + } else if (mCore->mBufferReleasedCbEnabled) { + callback = [listener = mCore->mConsumerListener]() { + listener->onBuffersReleased(); + }; + } } } + // Call back without lock held - if (listener != nullptr) { - listener->onBuffersReleased(); + if (callback) { + (*callback)(); } return NO_ERROR; diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 5961b41478..bcf61e45de 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -364,8 +364,10 @@ status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller, // Producers are not allowed to dequeue more than // mMaxDequeuedBufferCount buffers. // This check is only done if a buffer has already been queued - if (mCore->mBufferHasBeenQueued && - dequeuedCount >= mCore->mMaxDequeuedBufferCount) { + using namespace com::android::graphics::libgui::flags; + bool flagGatedBufferHasBeenQueued = + bq_always_use_max_dequeued_buffer_count() || mCore->mBufferHasBeenQueued; + if (flagGatedBufferHasBeenQueued && dequeuedCount >= mCore->mMaxDequeuedBufferCount) { // Supress error logs when timeout is non-negative. if (mDequeueTimeout < 0) { BQ_LOGE("%s: attempting to exceed the max dequeued buffer " diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp index 117a362661..5b89c6e17e 100644 --- a/libs/gui/ConsumerBase.cpp +++ b/libs/gui/ConsumerBase.cpp @@ -264,7 +264,10 @@ void ConsumerBase::onFrameReplaced(const BufferItem &item) { void ConsumerBase::onBuffersReleased() { Mutex::Autolock lock(mMutex); + onBuffersReleasedLocked(); +} +void ConsumerBase::onBuffersReleasedLocked() { CB_LOGV("onBuffersReleased"); if (mAbandoned) { @@ -481,7 +484,8 @@ status_t ConsumerBase::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { CB_LOGE("setMaxAcquiredBufferCount: ConsumerBase is abandoned!"); return NO_INIT; } - return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers); + return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers, + {[this]() { onBuffersReleasedLocked(); }}); } status_t ConsumerBase::setConsumerIsProtected(bool isProtected) { 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/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index e407a63d10..b0650d56ff 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -824,34 +824,25 @@ 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; +SurfaceComposerClient::Transaction::Transaction(const Transaction& other) { + mState = other.mState; mListenerCallbacks = other.mListenerCallbacks; mTransactionCompletedListener = TransactionCompletedListener::getInstance(); } 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 +857,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 +889,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 +908,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 +923,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 +947,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 +972,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 +995,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 +1009,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 +1042,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 +1111,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 +1120,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 +1133,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 +1145,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 +1168,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 +1204,7 @@ status_t SurfaceComposerClient::Transaction::sendSurfaceFlushJankDataTransaction } void SurfaceComposerClient::Transaction::enableDebugLogCallPoints() { - mLogCallPoints = true; + mState.mLogCallPoints = true; } // --------------------------------------------------------------------------- @@ -1443,34 +1262,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 +1650,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 +1669,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffe const std::vector<SurfaceControlStats>&) {}, nullptr); - mMayContainBuffer = true; + mState.mMayContainBuffer = true; return *this; } @@ -2041,8 +1845,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 +1935,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 +2106,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixed SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo( const FrameTimelineInfo& frameTimelineInfo) { - mergeFrameTimelineInfo(mFrameTimelineInfo, frameTimelineInfo); + mState.mergeFrameTimelineInfo(frameTimelineInfo); return *this; } @@ -2341,7 +2145,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTrust SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApplyToken( const sp<IBinder>& applyToken) { - mApplyToken = applyToken; + mState.mApplyToken = applyToken; return *this; } @@ -2469,17 +2273,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 +2326,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, @@ -2766,6 +2546,7 @@ status_t SurfaceComposerClient::getStaticDisplayInfo(int64_t displayId, if (status.isOk()) { // convert gui::StaticDisplayInfo to ui::StaticDisplayInfo outInfo->connectionType = static_cast<ui::DisplayConnectionType>(ginfo.connectionType); + outInfo->port = ginfo.port; outInfo->density = ginfo.density; outInfo->secure = ginfo.secure; outInfo->installOrientation = static_cast<ui::Rotation>(ginfo.installOrientation); diff --git a/libs/gui/TransactionState.cpp b/libs/gui/TransactionState.cpp new file mode 100644 index 0000000000..9e09bc2644 --- /dev/null +++ b/libs/gui/TransactionState.cpp @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "TransactionState" +#include <gui/LayerState.h> +#include <gui/SurfaceComposerClient.h> +#include <gui/TransactionState.h> +#include <private/gui/ParcelUtils.h> +#include <algorithm> + +namespace android { + +status_t TransactionState::writeToParcel(Parcel* parcel) const { + SAFE_PARCEL(parcel->writeUint64, mId); + SAFE_PARCEL(parcel->writeUint32, mFlags); + SAFE_PARCEL(parcel->writeInt64, mDesiredPresentTime); + SAFE_PARCEL(parcel->writeBool, mIsAutoTimestamp); + SAFE_PARCEL(parcel->writeParcelable, mFrameTimelineInfo); + SAFE_PARCEL(parcel->writeStrongBinder, mApplyToken); + SAFE_PARCEL(parcel->writeBool, mMayContainBuffer); + SAFE_PARCEL(parcel->writeBool, mLogCallPoints); + + SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mDisplayStates.size())); + for (auto const& displayState : mDisplayStates) { + displayState.write(*parcel); + } + SAFE_PARCEL(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); + } + + SAFE_PARCEL(parcel->writeBool, mHasListenerCallbacks); + SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mListenerCallbacks.size())); + for (const auto& [listener, callbackIds] : mListenerCallbacks) { + SAFE_PARCEL(parcel->writeStrongBinder, listener); + SAFE_PARCEL(parcel->writeParcelableVector, callbackIds); + } + + return NO_ERROR; +} + +status_t TransactionState::readFromParcel(const Parcel* parcel) { + SAFE_PARCEL(parcel->readUint64, &mId); + SAFE_PARCEL(parcel->readUint32, &mFlags); + SAFE_PARCEL(parcel->readInt64, &mDesiredPresentTime); + SAFE_PARCEL(parcel->readBool, &mIsAutoTimestamp); + SAFE_PARCEL(parcel->readParcelable, &mFrameTimelineInfo); + SAFE_PARCEL(parcel->readNullableStrongBinder, &mApplyToken); + SAFE_PARCEL(parcel->readBool, &mMayContainBuffer); + SAFE_PARCEL(parcel->readBool, &mLogCallPoints); + + uint32_t count; + SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize()) + mDisplayStates.clear(); + mDisplayStates.reserve(count); + for (size_t i = 0; i < count; i++) { + DisplayState displayState; + if (displayState.read(*parcel) == BAD_VALUE) { + return BAD_VALUE; + } + mDisplayStates.emplace_back(std::move(displayState)); + } + + SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize()) + mComposerStates.clear(); + mComposerStates.reserve(count); + for (size_t i = 0; i < count; i++) { + ComposerState composerState; + if (composerState.read(*parcel) == BAD_VALUE) { + return BAD_VALUE; + } + mComposerStates.emplace_back(std::move(composerState)); + } + + if (status_t status = mInputWindowCommands.read(*parcel) != NO_ERROR) { + return status; + } + + SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize()) + mUncacheBuffers.clear(); + mUncacheBuffers.reserve(count); + for (size_t i = 0; i < count; i++) { + client_cache_t client_cache; + sp<IBinder> tmpBinder; + SAFE_PARCEL(parcel->readStrongBinder, &tmpBinder); + client_cache.token = tmpBinder; + SAFE_PARCEL(parcel->readUint64, &client_cache.id); + mUncacheBuffers.emplace_back(std::move(client_cache)); + } + + SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize()) + mMergedTransactionIds.clear(); + mMergedTransactionIds.resize(count); + for (size_t i = 0; i < count; i++) { + SAFE_PARCEL(parcel->readUint64, &mMergedTransactionIds[i]); + } + + SAFE_PARCEL(parcel->readBool, &mHasListenerCallbacks); + SAFE_PARCEL_READ_SIZE(parcel->readUint32, &count, parcel->dataSize()); + mListenerCallbacks.clear(); + mListenerCallbacks.reserve(count); + for (uint32_t i = 0; i < count; i++) { + sp<IBinder> tmpBinder; + SAFE_PARCEL(parcel->readStrongBinder, &tmpBinder); + std::vector<CallbackId> callbackIds; + SAFE_PARCEL(parcel->readParcelableVector, &callbackIds); + mListenerCallbacks.emplace_back(tmpBinder, callbackIds); + } + + return NO_ERROR; +} + +void TransactionState::merge(TransactionState&& other, + const std::function<void(layer_state_t&)>& onBufferOverwrite) { + 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) { + onBufferOverwrite(it->state); + } + it->state.merge(otherState.state); + } else { + mComposerStates.push_back(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.push_back(state); + } + } + + for (const auto& cacheId : other.mUncacheBuffers) { + mUncacheBuffers.push_back(cacheId); + } + + mInputWindowCommands.merge(other.mInputWindowCommands); + // TODO(b/385156191) Consider merging desired present time. + mFlags |= other.mFlags; + mMayContainBuffer |= other.mMayContainBuffer; + mLogCallPoints |= other.mLogCallPoints; + + // mApplyToken is explicitly not merged. Token should be set before applying the transactions to + // make synchronization decisions a bit simpler. + mergeFrameTimelineInfo(other.mFrameTimelineInfo); + other.clear(); +} + +// copied from FrameTimelineInfo::merge() +void TransactionState::mergeFrameTimelineInfo(const FrameTimelineInfo& other) { + // When merging vsync Ids we take the oldest valid one + if (mFrameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID && + other.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { + if (other.vsyncId > mFrameTimelineInfo.vsyncId) { + mFrameTimelineInfo = other; + } + } else if (mFrameTimelineInfo.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) { + mFrameTimelineInfo = other; + } +} + +void TransactionState::clear() { + mComposerStates.clear(); + mDisplayStates.clear(); + mListenerCallbacks.clear(); + mHasListenerCallbacks = false; + mInputWindowCommands.clear(); + mUncacheBuffers.clear(); + mDesiredPresentTime = 0; + mIsAutoTimestamp = true; + mApplyToken = nullptr; + mFrameTimelineInfo = {}; + mMergedTransactionIds.clear(); + mFlags = 0; + mMayContainBuffer = false; + mLogCallPoints = false; +} + +layer_state_t* TransactionState::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.push_back(s); + + return &mComposerStates.back().state; +} + +DisplayState& TransactionState::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.push_back(s); + return mDisplayStates.back(); +} + +}; // namespace android diff --git a/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl b/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl index 0ccda56ef5..7ff332c29e 100644 --- a/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl +++ b/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl @@ -23,6 +23,7 @@ import android.gui.Rotation; /** @hide */ parcelable StaticDisplayInfo { DisplayConnectionType connectionType = DisplayConnectionType.Internal; + int port = -1; float density; boolean secure; @nullable DeviceProductInfo deviceProductInfo; diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h index 0bfa7b222e..fc31f4636c 100644 --- a/libs/gui/include/gui/BufferItemConsumer.h +++ b/libs/gui/include/gui/BufferItemConsumer.h @@ -96,6 +96,14 @@ class BufferItemConsumer: public ConsumerBase status_t acquireBuffer(BufferItem* item, nsecs_t presentWhen, bool waitForFence = true); + // Transfer ownership of a buffer to the BufferQueue. On NO_ERROR, the buffer + // is considered as if it were acquired. Buffer must not be null. + // + // Returns + // - BAD_VALUE if buffer is null + // - INVALID_OPERATION if too many buffers have already been acquired + status_t attachBuffer(const sp<GraphicBuffer>& buffer); + // Returns an acquired buffer to the queue, allowing it to be reused. Since // only a fixed number of buffers may be acquired at a time, old buffers // must be released by calling releaseBuffer to ensure new buffers can be @@ -105,10 +113,8 @@ class BufferItemConsumer: public ConsumerBase status_t releaseBuffer(const BufferItem &item, const sp<Fence>& releaseFence = Fence::NO_FENCE); -#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) status_t releaseBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& releaseFence = Fence::NO_FENCE); -#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) protected: #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h index ab1231ad6b..ba6a6a73f4 100644 --- a/libs/gui/include/gui/BufferQueueConsumer.h +++ b/libs/gui/include/gui/BufferQueueConsumer.h @@ -122,7 +122,10 @@ public: // setMaxAcquiredBufferCount sets the maximum number of buffers that can // be acquired by the consumer at one time (default 1). This call will // fail if a producer is connected to the BufferQueue. - virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); + virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) override; + virtual status_t setMaxAcquiredBufferCount( + int maxAcquiredBuffers, + std::optional<OnBufferReleasedCallback> onBuffersReleasedCallback) override; // setConsumerName sets the name used in logging status_t setConsumerName(const String8& name) override; diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h index fd67f09a4a..d2215ef7e6 100644 --- a/libs/gui/include/gui/ConsumerBase.h +++ b/libs/gui/include/gui/ConsumerBase.h @@ -191,6 +191,8 @@ protected: #endif virtual int getSlotForBufferLocked(const sp<GraphicBuffer>& buffer); + virtual void onBuffersReleasedLocked(); + virtual status_t detachBufferLocked(int slotIndex); // freeBufferLocked frees up the given buffer slot. If the slot has been diff --git a/libs/gui/include/gui/IGraphicBufferConsumer.h b/libs/gui/include/gui/IGraphicBufferConsumer.h index 8272a591da..8066b070fb 100644 --- a/libs/gui/include/gui/IGraphicBufferConsumer.h +++ b/libs/gui/include/gui/IGraphicBufferConsumer.h @@ -243,6 +243,9 @@ public: // maxAcquiredBuffers must be (inclusive) between 1 and MAX_MAX_ACQUIRED_BUFFERS. It also cannot // cause the maxBufferCount value to be exceeded. // + // If called with onBuffersReleasedCallback, that call back will be called in lieu of + // IConsumerListener::onBuffersReleased. + // // Return of a value other than NO_ERROR means an error has occurred: // * NO_INIT - the BufferQueue has been abandoned // * BAD_VALUE - one of the below conditions occurred: @@ -253,6 +256,11 @@ public: // * INVALID_OPERATION - attempting to call this after a producer connected. virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0; + using OnBufferReleasedCallback = std::function<void(void)>; + virtual status_t setMaxAcquiredBufferCount( + int maxAcquiredBuffers, + std::optional<OnBufferReleasedCallback> onBuffersReleasedCallback) = 0; + // setConsumerName sets the name used in logging virtual status_t setConsumerName(const String8& name) = 0; 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/InputTransferToken.h b/libs/gui/include/gui/InputTransferToken.h index fb4aaa73ae..b83f24562b 100644 --- a/libs/gui/include/gui/InputTransferToken.h +++ b/libs/gui/include/gui/InputTransferToken.h @@ -39,15 +39,9 @@ public: return NO_ERROR; }; + bool operator==(const InputTransferToken& other) const { return mToken == other.mToken; } + sp<IBinder> mToken; }; -static inline bool operator==(const sp<InputTransferToken>& token1, - const sp<InputTransferToken>& token2) { - if (token1.get() == token2.get()) { - return true; - } - return token1->mToken == token2->mToken; -} - } // namespace android diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 4fda8deb9c..15e3341ca2 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> @@ -447,56 +448,11 @@ public: 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,6 +462,11 @@ public: void registerSurfaceControlForCallback(const sp<SurfaceControl>& sc); void setReleaseBufferCallback(BufferData*, ReleaseBufferCallback); + protected: + // Accessed in tests. + std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash> + mListenerCallbacks; + public: Transaction(); virtual ~Transaction() = default; @@ -522,7 +483,7 @@ public: // 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 new file mode 100644 index 0000000000..4358227dae --- /dev/null +++ b/libs/gui/include/gui/TransactionState.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <android/gui/FrameTimelineInfo.h> +#include <binder/Parcelable.h> +#include <gui/LayerState.h> + +namespace android { + +// Class to store all the transaction data and the parcelling logic +class TransactionState { +public: + explicit TransactionState() = default; + TransactionState(TransactionState const& other) = default; + status_t writeToParcel(Parcel* parcel) const; + status_t readFromParcel(const Parcel* parcel); + layer_state_t* getLayerState(const sp<SurfaceControl>& sc); + DisplayState& getDisplayState(const sp<IBinder>& token); + + // Returns the current id of the transaction. + // The id is updated every time the transaction is applied. + uint64_t getId() const { return mId; } + std::vector<uint64_t> getMergedTransactionIds() const { return mMergedTransactionIds; } + void enableDebugLogCallPoints() { mLogCallPoints = true; } + void merge(TransactionState&& other, + const std::function<void(layer_state_t&)>& onBufferOverwrite); + + // copied from FrameTimelineInfo::merge() + void mergeFrameTimelineInfo(const FrameTimelineInfo& other); + void clear(); + bool operator==(const TransactionState& rhs) const = default; + bool operator!=(const TransactionState& rhs) const = default; + + uint64_t mId = 0; + std::vector<uint64_t> mMergedTransactionIds; + uint32_t mFlags = 0; + // The vsync id provided by Choreographer.getVsyncId and the input event id + gui::FrameTimelineInfo mFrameTimelineInfo; + // 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; + // If not null, transactions will be queued up using this token otherwise a common token + // per process will be used. + sp<IBinder> mApplyToken; + // 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; + // Prints debug logs when enabled. + bool mLogCallPoints = false; + + std::vector<DisplayState> mDisplayStates; + std::vector<ComposerState> mComposerStates; + InputWindowCommands mInputWindowCommands; + std::vector<client_cache_t> mUncacheBuffers; + // Note: mHasListenerCallbacks can be true even if mListenerCallbacks is + // empty. + bool mHasListenerCallbacks = false; + std::vector<ListenerCallbacks> mListenerCallbacks; + +private: + // We keep track of the last MAX_MERGE_HISTORY_LENGTH merged transaction ids. + // Ordered most recently merged to least recently merged. + static constexpr size_t MAX_MERGE_HISTORY_LENGTH = 10u; +}; + +}; // namespace android diff --git a/libs/gui/include/gui/mock/GraphicBufferConsumer.h b/libs/gui/include/gui/mock/GraphicBufferConsumer.h index 24d26b12a1..18a7e12fa7 100644 --- a/libs/gui/include/gui/mock/GraphicBufferConsumer.h +++ b/libs/gui/include/gui/mock/GraphicBufferConsumer.h @@ -47,6 +47,7 @@ public: MOCK_METHOD2(setDefaultBufferSize, status_t(uint32_t, uint32_t)); MOCK_METHOD1(setMaxBufferCount, status_t(int)); MOCK_METHOD1(setMaxAcquiredBufferCount, status_t(int)); + MOCK_METHOD2(setMaxAcquiredBufferCount, status_t(int, std::optional<OnBufferReleasedCallback>)); MOCK_METHOD1(setConsumerName, status_t(const String8&)); MOCK_METHOD1(setDefaultBufferFormat, status_t(PixelFormat)); MOCK_METHOD1(setDefaultBufferDataSpace, status_t(android_dataspace)); diff --git a/libs/gui/libgui_flags.aconfig b/libs/gui/libgui_flags.aconfig index 534f05e987..ce1bc9512c 100644 --- a/libs/gui/libgui_flags.aconfig +++ b/libs/gui/libgui_flags.aconfig @@ -130,9 +130,6 @@ flag { description: "Remove BufferQueueProducer::dequeue's wait on this fence (or the fence entirely) to prevent deadlocks" bug: "339705065" is_fixed_read_only: true - metadata { - purpose: PURPOSE_BUGFIX - } } # bq_gl_fence_cleanup flag { @@ -142,3 +139,25 @@ flag { bug: "340934031" is_fixed_read_only: true } # wb_media_migration + +flag { + name: "allocate_buffer_priority" + namespace: "wear_system_health" + description: "Boost priority for buffer allocation" + bug: "399701430" + metadata { + purpose: PURPOSE_BUGFIX + } + is_fixed_read_only: true +} # allocate_buffer_priority + +flag { + name: "bq_always_use_max_dequeued_buffer_count" + namespace: "core_graphics" + description: "BufferQueueProducer::dequeue's respects setMaxDequeuedBufferCount even before a buffer is dequeued." + bug: "399328309" + metadata { + purpose: PURPOSE_BUGFIX + } + is_fixed_read_only: true +} # bq_always_use_max_dequeued_buffer_count diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 87051a7aac..e20345dd1a 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -90,6 +90,7 @@ cc_test { "testserver/TestServerClient.cpp", "testserver/TestServerHost.cpp", "TextureRenderer.cpp", + "TransactionState_test.cpp", "VsyncEventData_test.cpp", "WindowInfo_test.cpp", ], diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp index b980f882ff..80eea267bf 100644 --- a/libs/gui/tests/BufferItemConsumer_test.cpp +++ b/libs/gui/tests/BufferItemConsumer_test.cpp @@ -24,6 +24,7 @@ #include <gui/Surface.h> #include <ui/BufferQueueDefs.h> #include <ui/GraphicBuffer.h> +#include <utils/Errors.h> #include <unordered_set> @@ -235,6 +236,38 @@ TEST_F(BufferItemConsumerTest, TriggerBufferFreed_DeleteBufferItemConsumer) { ASSERT_EQ(1, GetFreedBufferCount()); } +TEST_F(BufferItemConsumerTest, ResizeAcquireCount) { + EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers + 1)); + EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers + 2)); + EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers - 1)); + EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers - 2)); + EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers + 1)); + EXPECT_EQ(OK, mBIC->setMaxAcquiredBufferCount(kMaxLockedBuffers - 1)); +} + +TEST_F(BufferItemConsumerTest, AttachBuffer) { + ASSERT_EQ(OK, mBIC->setMaxAcquiredBufferCount(1)); + + int slot; + DequeueBuffer(&slot); + QueueBuffer(slot); + AcquireBuffer(&slot); + + sp<GraphicBuffer> newBuffer1 = sp<GraphicBuffer>::make(kWidth, kHeight, kFormat, kUsage); + sp<GraphicBuffer> newBuffer2 = sp<GraphicBuffer>::make(kWidth, kHeight, kFormat, kUsage); + + // For some reason, you can attach an extra buffer? + // b/400973991 to investigate + EXPECT_EQ(OK, mBIC->attachBuffer(newBuffer1)); + EXPECT_EQ(INVALID_OPERATION, mBIC->attachBuffer(newBuffer2)); + + ReleaseBuffer(slot); + + EXPECT_EQ(OK, mBIC->attachBuffer(newBuffer2)); + EXPECT_EQ(OK, mBIC->releaseBuffer(newBuffer1, Fence::NO_FENCE)); + EXPECT_EQ(OK, mBIC->releaseBuffer(newBuffer2, Fence::NO_FENCE)); +} + #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) // Test that delete BufferItemConsumer triggers onBufferFreed. TEST_F(BufferItemConsumerTest, DetachBufferWithBuffer) { diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp index cf05fd4ba5..adf8fce472 100644 --- a/libs/gui/tests/EndToEndNativeInputTest.cpp +++ b/libs/gui/tests/EndToEndNativeInputTest.cpp @@ -222,8 +222,8 @@ public: ASSERT_EQ(InputEventType::MOTION, ev->getType()); MotionEvent* mev = static_cast<MotionEvent*>(ev); EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction()); - EXPECT_EQ(x, mev->getX(0)); - EXPECT_EQ(y, mev->getY(0)); + EXPECT_NEAR(x, mev->getX(0), EPSILON); + EXPECT_NEAR(y, mev->getY(0), EPSILON); EXPECT_EQ(flags, mev->getFlags() & flags); ev = consumeEvent(); @@ -241,8 +241,8 @@ public: MotionEvent* mev = static_cast<MotionEvent*>(ev); EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, mev->getAction()); const PointerCoords& coords = *mev->getRawPointerCoords(0 /*pointerIndex*/); - EXPECT_EQ(displayX, coords.getX()); - EXPECT_EQ(displayY, coords.getY()); + EXPECT_NEAR(displayX, coords.getX(), EPSILON); + EXPECT_NEAR(displayY, coords.getY(), EPSILON); EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS); ev = consumeEvent(); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index e7690e2530..c4dcba856a 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; } @@ -2246,6 +2237,52 @@ TEST_F(SurfaceTest, BatchIllegalOperations) { ASSERT_EQ(NO_ERROR, surface->disconnect(NATIVE_WINDOW_API_CPU)); } +TEST_F(SurfaceTest, setMaxDequeuedBufferCount_setMaxAcquiredBufferCount_allocations) { + // + // Set up the consumer and producer--nothing fancy. + // + auto [consumer, surface] = + BufferItemConsumer::create(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER); + sp<SurfaceListener> surfaceListener = sp<StubSurfaceListener>::make(); + surface->connect(NATIVE_WINDOW_API_CPU, surfaceListener); + sp<GraphicBuffer> buffer; + sp<Fence> fence; + + // + // These values are independent. The consumer can dequeue 3 and the consumer can acquire 3 at + // the same time. + // + ASSERT_EQ(OK, consumer->setMaxAcquiredBufferCount(3)); + ASSERT_EQ(OK, surface->setMaxDequeuedBufferCount(3)); + + // + // Take all three buffers out of the queue--a fourth can't be retrieved. Then queue them. + // + std::vector<Surface::BatchBuffer> dequeuedBuffers(3); + EXPECT_EQ(OK, surface->dequeueBuffers(&dequeuedBuffers)); + if (::com::android::graphics::libgui::flags::bq_always_use_max_dequeued_buffer_count()) { + EXPECT_EQ(INVALID_OPERATION, surface->dequeueBuffer(&buffer, &fence)); + } + + for (auto& batchBuffer : dequeuedBuffers) { + EXPECT_EQ(OK, + surface->queueBuffer(GraphicBuffer::from(batchBuffer.buffer), + sp<Fence>::make(batchBuffer.fenceFd))); + } + dequeuedBuffers.assign(3, {}); + + // + // Acquire all three, then we should be able to dequeue 3 more. + // + std::vector<BufferItem> acquiredBuffers(3); + for (auto& bufferItem : acquiredBuffers) { + EXPECT_EQ(OK, consumer->acquireBuffer(&bufferItem, 0)); + } + + EXPECT_EQ(OK, surface->dequeueBuffers(&dequeuedBuffers)); + EXPECT_EQ(INVALID_OPERATION, surface->dequeueBuffer(&buffer, &fence)); +} + #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) TEST_F(SurfaceTest, PlatformBufferMethods) { diff --git a/libs/gui/tests/TransactionState_test.cpp b/libs/gui/tests/TransactionState_test.cpp new file mode 100644 index 0000000000..179b264dbf --- /dev/null +++ b/libs/gui/tests/TransactionState_test.cpp @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gmock/gmock.h> + +#include <gtest/gtest.h> +#include <unordered_map> +#include "android/gui/FocusRequest.h" +#include "binder/Binder.h" +#include "binder/Parcel.h" +#include "gtest/gtest.h" +#include "gui/LayerState.h" +#include "gui/WindowInfo.h" + +#include "gui/TransactionState.h" + +namespace android { + +void sprintf(std::string& out, const char* format, ...) { + va_list arg_list; + va_start(arg_list, format); + + int len = vsnprintf(nullptr, 0, format, arg_list); + if (len < 0) { + va_end(arg_list); + } + std::string line(len, '\0'); + int written = vsnprintf(line.data(), len + 1, format, arg_list); + if (written != len) { + va_end(arg_list); + } + line.pop_back(); + out += line; + va_end(arg_list); +} + +constexpr std::string dump_struct(auto& x) { + std::string s; +#if __has_builtin(__builtin_dump_struct) + __builtin_dump_struct(&x, sprintf, s); +#else + (void)x; +#endif + return s; +} + +void PrintTo(const TransactionState& state, ::std::ostream* os) { + *os << dump_struct(state); + *os << state.mFrameTimelineInfo.toString(); + for (auto mergedId : state.mMergedTransactionIds) { + *os << mergedId << ","; + } +} + +void PrintTo(const ComposerState& state, ::std::ostream* os) { + *os << dump_struct(state.state); + *os << state.state.getWindowInfo(); +} + +// In case EXPECT_EQ fails, this function is useful to pinpoint exactly which +// field did not compare ==. +void Compare(const TransactionState& s1, const TransactionState& s2) { + EXPECT_EQ(s1.mId, s2.mId); + EXPECT_EQ(s1.mMergedTransactionIds, s2.mMergedTransactionIds); + EXPECT_EQ(s1.mFlags, s2.mFlags); + EXPECT_EQ(s1.mFrameTimelineInfo, s2.mFrameTimelineInfo); + EXPECT_EQ(s1.mDesiredPresentTime, s2.mDesiredPresentTime); + EXPECT_EQ(s1.mIsAutoTimestamp, s2.mIsAutoTimestamp); + EXPECT_EQ(s1.mApplyToken, s2.mApplyToken); + EXPECT_EQ(s1.mMayContainBuffer, s2.mMayContainBuffer); + EXPECT_EQ(s1.mLogCallPoints, s2.mLogCallPoints); + EXPECT_EQ(s1.mDisplayStates.size(), s2.mDisplayStates.size()); + EXPECT_THAT(s1.mDisplayStates, ::testing::ContainerEq(s2.mDisplayStates)); + EXPECT_EQ(s1.mComposerStates.size(), s2.mComposerStates.size()); + EXPECT_EQ(s1.mComposerStates, s2.mComposerStates); + EXPECT_EQ(s1.mInputWindowCommands, s2.mInputWindowCommands); + EXPECT_EQ(s1.mUncacheBuffers, s2.mUncacheBuffers); + EXPECT_EQ(s1.mHasListenerCallbacks, s2.mHasListenerCallbacks); + EXPECT_EQ(s1.mListenerCallbacks.size(), s2.mListenerCallbacks.size()); + EXPECT_EQ(s1.mListenerCallbacks, s2.mListenerCallbacks); +} + +std::unique_ptr<std::unordered_map<int, sp<BBinder>>> createTokenMap(size_t maxSize) { + auto result = std::make_unique<std::unordered_map<int, sp<BBinder>>>(); + for (size_t i = 0; i < maxSize; ++i) { + result->emplace(i, sp<BBinder>::make()); + } + return result; +} + +constexpr size_t kMaxComposerStates = 2; +ComposerState createComposerStateForTest(size_t i) { + static const auto* const sLayerHandle = createTokenMap(kMaxComposerStates).release(); + + ComposerState state; + state.state.what = layer_state_t::eFlagsChanged; + state.state.surface = sLayerHandle->at(i); + state.state.layerId = i; + state.state.flags = 20 * i; + return state; +} + +constexpr size_t kMaxDisplayStates = 5; +DisplayState createDisplayStateForTest(size_t i) { + static const auto* const sDisplayTokens = createTokenMap(kMaxDisplayStates).release(); + + DisplayState displayState; + displayState.what = DisplayState::eFlagsChanged; + displayState.token = sDisplayTokens->at(i); + displayState.flags = 20 * i; + return displayState; +} + +TransactionState createTransactionStateForTest() { + static sp<BBinder> sApplyToken = sp<BBinder>::make(); + + TransactionState state; + state.mId = 123; + state.mMergedTransactionIds.push_back(15); + state.mMergedTransactionIds.push_back(0); + state.mFrameTimelineInfo.vsyncId = 14; + state.mDesiredPresentTime = 11; + state.mIsAutoTimestamp = true; + state.mApplyToken = sApplyToken; + for (size_t i = 0; i < kMaxDisplayStates; i++) { + state.mDisplayStates.push_back(createDisplayStateForTest(i)); + } + for (size_t i = 0; i < kMaxComposerStates; i++) { + state.mComposerStates.push_back(createComposerStateForTest(i)); + } + static const auto* const sFocusRequestTokens = createTokenMap(5).release(); + for (int i = 0; i < 5; i++) { + gui::FocusRequest request; + request.token = sFocusRequestTokens->at(i); + request.timestamp = i; + state.mInputWindowCommands.addFocusRequest(request); + } + static const auto* const sCacheToken = createTokenMap(5).release(); + for (int i = 0; i < 5; i++) { + client_cache_t cache; + cache.token = sCacheToken->at(i); + cache.id = i; + state.mUncacheBuffers.emplace_back(std::move(cache)); + } + static const auto* const sListenerCallbacks = []() { + auto* callbacks = new std::vector<ListenerCallbacks>(); + for (int i = 0; i < 5; i++) { + callbacks->emplace_back(sp<BBinder>::make(), + std::unordered_set<CallbackId, CallbackIdHash>{}); + } + return callbacks; + }(); + state.mHasListenerCallbacks = true; + state.mListenerCallbacks = *sListenerCallbacks; + return state; +} + +TransactionState createEmptyTransaction(uint64_t id) { + TransactionState state; + state.mId = id; + return state; +} + +TEST(TransactionStateTest, parcel) { + TransactionState state = createTransactionStateForTest(); + Parcel p; + state.writeToParcel(&p); + p.setDataPosition(0); + TransactionState parcelledState; + parcelledState.readFromParcel(&p); + EXPECT_EQ(state, parcelledState); +}; + +TEST(TransactionStateTest, parcelDisplayState) { + DisplayState state = createDisplayStateForTest(0); + Parcel p; + state.write(p); + p.setDataPosition(0); + DisplayState parcelledState; + parcelledState.read(p); + EXPECT_EQ(state, parcelledState); +}; + +TEST(TransactionStateTest, parcelLayerState) { + ComposerState state = createComposerStateForTest(0); + Parcel p; + state.write(p); + p.setDataPosition(0); + ComposerState parcelledState; + parcelledState.read(p); + EXPECT_EQ(state, parcelledState); +}; + +TEST(TransactionStateTest, parcelEmptyState) { + TransactionState state; + Parcel p; + state.writeToParcel(&p); + p.setDataPosition(0); + TransactionState parcelledState; + state.readFromParcel(&p); + EXPECT_EQ(state, parcelledState); +}; + +TEST(TransactionStateTest, mergeLayerState) { + ComposerState composerState = createComposerStateForTest(0); + ComposerState update; + update.state.surface = composerState.state.surface; + update.state.layerId = 0; + update.state.what = layer_state_t::eAlphaChanged; + update.state.color.a = .42; + composerState.state.merge(update.state); + + ComposerState expectedMergedState = createComposerStateForTest(0); + expectedMergedState.state.what |= layer_state_t::eAlphaChanged; + expectedMergedState.state.color.a = .42; + EXPECT_EQ(composerState, expectedMergedState); +}; + +TEST(TransactionStateTest, merge) { + // Setup. + static constexpr uint64_t kUpdateTransactionId = 200; + + TransactionState state = createTransactionStateForTest(); + + TransactionState update; + update.mId = kUpdateTransactionId; + { + ComposerState composerState; + composerState.state.surface = state.mComposerStates[0].state.surface; + composerState.state.what = layer_state_t::eAlphaChanged; + composerState.state.color.a = .42; + update.mComposerStates.push_back(composerState); + } + { + ComposerState composerState; + composerState.state.surface = state.mComposerStates[1].state.surface; + composerState.state.what = layer_state_t::eBufferChanged; + update.mComposerStates.push_back(composerState); + } + int32_t overrwiteLayerId = -1; + // Mutation. + state.merge(std::move(update), + [&overrwiteLayerId](layer_state_t ls) { overrwiteLayerId = ls.layerId; }); + // Assertions. + EXPECT_EQ(1, overrwiteLayerId); + EXPECT_EQ(update, createEmptyTransaction(update.getId())); + + TransactionState expectedMergedState = createTransactionStateForTest(); + expectedMergedState.mMergedTransactionIds + .insert(expectedMergedState.mMergedTransactionIds.begin(), kUpdateTransactionId); + expectedMergedState.mComposerStates.at(0).state.what |= layer_state_t::eAlphaChanged; + expectedMergedState.mComposerStates.at(0).state.color.a = .42; + expectedMergedState.mComposerStates.at(1).state.what |= layer_state_t::eBufferChanged; + auto inputCommands = expectedMergedState.mInputWindowCommands; + + // desired present time is not merged. + expectedMergedState.mDesiredPresentTime = state.mDesiredPresentTime; + + EXPECT_EQ(state.mComposerStates[0], expectedMergedState.mComposerStates[0]); + EXPECT_EQ(state.mInputWindowCommands, expectedMergedState.mInputWindowCommands); + EXPECT_EQ(state, expectedMergedState); +}; + +TEST(TransactionStateTest, clear) { + TransactionState state = createTransactionStateForTest(); + state.clear(); + TransactionState emptyState = createEmptyTransaction(state.getId()); + EXPECT_EQ(state, emptyState); +}; + +} // namespace android diff --git a/libs/input/Android.bp b/libs/input/Android.bp index ff26184a33..52e0276cad 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -225,6 +225,7 @@ cc_library { srcs: [ "AccelerationCurve.cpp", "CoordinateFilter.cpp", + "DisplayTopologyGraph.cpp", "Input.cpp", "InputConsumer.cpp", "InputConsumerNoResampling.cpp", @@ -270,6 +271,7 @@ cc_library { shared_libs: [ "android.companion.virtualdevice.flags-aconfig-cc", + "com.android.window.flags.window-aconfig_flags_c_lib", "libPlatformProperties", "libaconfig_storage_read_api_cc", "libbase", diff --git a/libs/input/DisplayTopologyGraph.cpp b/libs/input/DisplayTopologyGraph.cpp new file mode 100644 index 0000000000..934f2e8135 --- /dev/null +++ b/libs/input/DisplayTopologyGraph.cpp @@ -0,0 +1,144 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "DisplayTopologyValidator" + +#include <android-base/logging.h> +#include <android-base/stringprintf.h> +#include <ftl/enum.h> +#include <input/DisplayTopologyGraph.h> +#include <input/PrintTools.h> +#include <ui/LogicalDisplayId.h> + +#include <algorithm> + +#define INDENT " " + +namespace android { + +namespace { + +DisplayTopologyPosition getOppositePosition(DisplayTopologyPosition position) { + switch (position) { + case DisplayTopologyPosition::LEFT: + return DisplayTopologyPosition::RIGHT; + case DisplayTopologyPosition::TOP: + return DisplayTopologyPosition::BOTTOM; + case DisplayTopologyPosition::RIGHT: + return DisplayTopologyPosition::LEFT; + case DisplayTopologyPosition::BOTTOM: + return DisplayTopologyPosition::TOP; + } +} + +bool validatePrimaryDisplay(const android::DisplayTopologyGraph& displayTopologyGraph) { + return displayTopologyGraph.primaryDisplayId != ui::LogicalDisplayId::INVALID && + displayTopologyGraph.graph.contains(displayTopologyGraph.primaryDisplayId); +} + +bool validateTopologyGraph(const android::DisplayTopologyGraph& displayTopologyGraph) { + for (const auto& [sourceDisplay, adjacentDisplays] : displayTopologyGraph.graph) { + for (const DisplayTopologyAdjacentDisplay& adjacentDisplay : adjacentDisplays) { + const auto adjacentGraphIt = displayTopologyGraph.graph.find(adjacentDisplay.displayId); + if (adjacentGraphIt == displayTopologyGraph.graph.end()) { + LOG(ERROR) << "Missing adjacent display in topology graph: " + << adjacentDisplay.displayId << " for source " << sourceDisplay; + return false; + } + const auto reverseEdgeIt = + std::find_if(adjacentGraphIt->second.begin(), adjacentGraphIt->second.end(), + [sourceDisplay](const DisplayTopologyAdjacentDisplay& + reverseAdjacentDisplay) { + return sourceDisplay == reverseAdjacentDisplay.displayId; + }); + if (reverseEdgeIt == adjacentGraphIt->second.end()) { + LOG(ERROR) << "Missing reverse edge in topology graph for: " << sourceDisplay + << " -> " << adjacentDisplay.displayId; + return false; + } + DisplayTopologyPosition expectedPosition = + getOppositePosition(adjacentDisplay.position); + if (reverseEdgeIt->position != expectedPosition) { + LOG(ERROR) << "Unexpected reverse edge for: " << sourceDisplay << " -> " + << adjacentDisplay.displayId + << " expected position: " << ftl::enum_string(expectedPosition) + << " actual " << ftl::enum_string(reverseEdgeIt->position); + return false; + } + if (reverseEdgeIt->offsetDp != -adjacentDisplay.offsetDp) { + LOG(ERROR) << "Unexpected reverse edge offset: " << sourceDisplay << " -> " + << adjacentDisplay.displayId + << " expected offset: " << -adjacentDisplay.offsetDp << " actual " + << reverseEdgeIt->offsetDp; + return false; + } + } + } + return true; +} + +bool validateDensities(const android::DisplayTopologyGraph& displayTopologyGraph) { + for (const auto& [sourceDisplay, adjacentDisplays] : displayTopologyGraph.graph) { + if (!displayTopologyGraph.displaysDensity.contains(sourceDisplay)) { + LOG(ERROR) << "Missing density value in topology graph for display: " << sourceDisplay; + return false; + } + } + return true; +} + +std::string logicalDisplayIdToString(const ui::LogicalDisplayId& displayId) { + return base::StringPrintf("displayId(%d)", displayId.val()); +} + +std::string adjacentDisplayToString(const DisplayTopologyAdjacentDisplay& adjacentDisplay) { + return adjacentDisplay.dump(); +} + +std::string adjacentDisplayVectorToString( + const std::vector<DisplayTopologyAdjacentDisplay>& adjacentDisplays) { + return dumpVector(adjacentDisplays, adjacentDisplayToString); +} + +} // namespace + +std::string DisplayTopologyAdjacentDisplay::dump() const { + std::string dump; + dump += base::StringPrintf("DisplayTopologyAdjacentDisplay: {displayId: %d, position: %s, " + "offsetDp: %f}", + displayId.val(), ftl::enum_string(position).c_str(), offsetDp); + return dump; +} + +bool DisplayTopologyGraph::isValid() const { + return validatePrimaryDisplay(*this) && validateTopologyGraph(*this) && + validateDensities(*this); +} + +std::string DisplayTopologyGraph::dump() const { + std::string dump; + dump += base::StringPrintf("PrimaryDisplayId: %d\n", primaryDisplayId.val()); + dump += base::StringPrintf("TopologyGraph:\n"); + dump += addLinePrefix(dumpMap(graph, logicalDisplayIdToString, adjacentDisplayVectorToString), + INDENT); + dump += "\n"; + dump += base::StringPrintf("DisplaysDensity:\n"); + dump += addLinePrefix(dumpMap(displaysDensity, logicalDisplayIdToString), INDENT); + dump += "\n"; + return dump; +} + +} // namespace android diff --git a/libs/input/InputFlags.cpp b/libs/input/InputFlags.cpp index f866f9b8f0..6aa9ae6b16 100644 --- a/libs/input/InputFlags.cpp +++ b/libs/input/InputFlags.cpp @@ -18,6 +18,7 @@ #include <android-base/logging.h> #include <com_android_input_flags.h> +#include <com_android_window_flags.h> #include <cutils/properties.h> #include <string> @@ -25,6 +26,9 @@ namespace android { bool InputFlags::connectedDisplaysCursorEnabled() { + if (!com::android::window::flags::enable_desktop_mode_through_dev_option()) { + return com::android::input::flags::connected_displays_cursor(); + } static std::optional<bool> cachedDevOption; if (!cachedDevOption.has_value()) { char value[PROPERTY_VALUE_MAX]; diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig index fc859cb0f8..983bbdee6e 100644 --- a/libs/input/input_flags.aconfig +++ b/libs/input/input_flags.aconfig @@ -26,13 +26,6 @@ flag { } flag { - name: "remove_input_channel_from_windowstate" - namespace: "input" - description: "Do not store a copy of input channel inside WindowState." - bug: "323450804" -} - -flag { name: "enable_input_event_tracing" namespace: "input" description: "Set to true to enable input event tracing, including always-on tracing on non-user builds" @@ -61,13 +54,6 @@ flag { } flag { - name: "enable_touchpad_typing_palm_rejection" - namespace: "input" - description: "Enabling additional touchpad palm rejection will disable the tap to click while the user is typing on a physical keyboard" - bug: "301055381" -} - -flag { name: "enable_v2_touchpad_typing_palm_rejection" namespace: "input" description: "In addition to touchpad palm rejection v1, v2 will also cancel ongoing move gestures while typing and add delay in re-enabling the tap to click." @@ -127,13 +113,6 @@ flag { } flag { - name: "hide_pointer_indicators_for_secure_windows" - namespace: "input" - description: "Hide touch and pointer indicators if a secure window is present on display" - bug: "325252005" -} - -flag { name: "enable_keyboard_classifier" namespace: "input" description: "Keyboard classifier that classifies all keyboards into alphabetic or non-alphabetic" @@ -260,3 +239,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "enable_display_topology_validation" + namespace: "input" + description: "Set to true to enable display topology validation" + bug: "401219231" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp index 7f207f0670..f9b84fa948 100644 --- a/libs/renderengine/Android.bp +++ b/libs/renderengine/Android.bp @@ -25,6 +25,7 @@ cc_defaults { defaults: [ "android.hardware.graphics.composer3-ndk_shared", "renderengine_defaults", + "libsurfaceflinger_common_deps", ], cflags: [ "-DGL_GLEXT_PROTOTYPES", @@ -117,7 +118,10 @@ filegroup { // possible if libskia_renderengine is just pulled into librenderengine via whole_static_libs. cc_defaults { name: "librenderengine_deps", - defaults: ["skia_renderengine_deps"], + defaults: [ + "skia_renderengine_deps", + "libsurfaceflinger_common_deps", + ], static_libs: ["libskia_renderengine"], } diff --git a/libs/renderengine/benchmark/Android.bp b/libs/renderengine/benchmark/Android.bp index f84db0b04c..2d18ddb0aa 100644 --- a/libs/renderengine/benchmark/Android.bp +++ b/libs/renderengine/benchmark/Android.bp @@ -28,6 +28,7 @@ cc_benchmark { "android.hardware.graphics.composer3-ndk_shared", "librenderengine_deps", "surfaceflinger_defaults", + "libsurfaceflinger_common_deps", ], srcs: [ "main.cpp", @@ -38,7 +39,6 @@ cc_benchmark { static_libs: [ "librenderengine", "libshaders", - "libsurfaceflinger_common", "libtonemap", ], cflags: [ diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index 5f2d1b1be6..9e1c226371 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -347,6 +347,7 @@ void SkiaRenderEngine::useProtectedContext(bool useProtectedContext) { if (useProtectedContextImpl( useProtectedContext ? GrProtected::kYes : GrProtected::kNo)) { mInProtectedContext = useProtectedContext; + SFTRACE_INT("RE inProtectedContext", mInProtectedContext); // given that we are sharing the same thread between two contexts we need to // make sure that the thread state is reset when switching between the two. if (getActiveContext()) { @@ -1235,6 +1236,16 @@ void SkiaRenderEngine::drawLayersInternal( LOG_ALWAYS_FATAL_IF(activeSurface != dstSurface); auto drawFence = sp<Fence>::make(flushAndSubmit(context, dstSurface)); trace(drawFence); + FenceTimePtr fenceTime = FenceTime::makeValid(drawFence); + for (const auto& layer : layers) { + if (FlagManager::getInstance().monitor_buffer_fences()) { + if (layer.source.buffer.buffer) { + layer.source.buffer.buffer->getBuffer() + ->getDependencyMonitor() + .addAccessCompletion(fenceTime, "RE"); + } + } + } resultPromise->set_value(std::move(drawFence)); } diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 87e213e394..10cb992835 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -122,6 +122,7 @@ cc_library_shared { srcs: [ "DebugUtils.cpp", + "DependencyMonitor.cpp", "DeviceProductInfo.cpp", "DisplayIdentification.cpp", "DynamicDisplayInfo.cpp", diff --git a/libs/ui/DependencyMonitor.cpp b/libs/ui/DependencyMonitor.cpp new file mode 100644 index 0000000000..b7e490eba4 --- /dev/null +++ b/libs/ui/DependencyMonitor.cpp @@ -0,0 +1,144 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// #define LOG_NDEBUG 0 +#undef LOG_TAG +#define LOG_TAG "DependencyMonitor" + +#include <ui/DependencyMonitor.h> +#include <ui/Fence.h> +#include <utils/Timers.h> + +#include <inttypes.h> + +namespace android { + +void DependencyMonitor::addIngress(FenceTimePtr fence, std::string annotation) { + std::lock_guard lock(mMutex); + resolveLocked(); + if (mDependencies.isFull() && !mDependencies.front().updateSignalTimes(true)) { + ALOGD("%s: Clobbering unresolved dependencies -- make me bigger!", mToken.c_str()); + } + + auto& entry = mDependencies.next(); + entry.reset(mToken.c_str()); + ALOGV("%" PRId64 "/%s: addIngress at CPU time %" PRId64 " (%s)", mDependencies.back().id, + mToken.c_str(), systemTime(), annotation.c_str()); + + mDependencies.back().ingress = {std::move(fence), std::move(annotation)}; +} + +void DependencyMonitor::addAccessCompletion(FenceTimePtr fence, std::string annotation) { + std::lock_guard lock(mMutex); + if (mDependencies.size() == 0) { + return; + } + ALOGV("%" PRId64 "/%s: addAccessCompletion at CPU time %" PRId64 " (%s)", + mDependencies.back().id, mToken.c_str(), systemTime(), annotation.c_str()); + mDependencies.back().accessCompletions.emplace_back(std::move(fence), std::move(annotation)); +} + +void DependencyMonitor::addEgress(FenceTimePtr fence, std::string annotation) { + std::lock_guard lock(mMutex); + if (mDependencies.size() == 0) { + return; + } + ALOGV("%" PRId64 "/%s: addEgress at CPU time %" PRId64 " (%s)", mDependencies.back().id, + mToken.c_str(), systemTime(), annotation.c_str()); + mDependencies.back().egress = {std::move(fence), std::move(annotation)}; +} + +void DependencyMonitor::resolveLocked() { + if (mDependencies.size() == 0) { + return; + } + + for (size_t i = mDependencies.size(); i > 0; i--) { + auto& dependencyBlock = mDependencies[i - 1]; + + if (dependencyBlock.validated) { + continue; + } + + if (!dependencyBlock.updateSignalTimes(false)) { + break; + } + + dependencyBlock.validated = true; + dependencyBlock.checkUnsafeAccess(); + } +} + +bool DependencyMonitor::DependencyBlock::updateSignalTimes(bool excludeIngress) { + if (egress.fence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) { + return false; + } + + if (!excludeIngress && ingress.fence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) { + return false; + } + + for (auto& accessCompletion : accessCompletions) { + if (accessCompletion.fence->getSignalTime() == Fence::SIGNAL_TIME_PENDING) { + return false; + } + } + + return true; +} + +void DependencyMonitor::DependencyBlock::checkUnsafeAccess() const { + const nsecs_t egressTime = egress.fence->getCachedSignalTime(); + const nsecs_t ingressTime = ingress.fence->getCachedSignalTime(); + + ALOGV_IF(egressTime != Fence::SIGNAL_TIME_INVALID, + "%" PRId64 "/%s: Egress time: %" PRId64 " (%s)", token, id, egressTime, + egress.annotation.c_str()); + ALOGV_IF(Fence::isValidTimestamp(egressTime) && Fence::isValidTimestamp(ingressTime) && + egressTime < ingressTime, + "%" PRId64 "/%s: Detected egress before ingress!: %" PRId64 " (%s) < %" PRId64 " (%s)", + id, token, egressTime, egress.annotation, ingressTime, ingress.annotation.c_str()); + + for (auto& accessCompletion : accessCompletions) { + const nsecs_t accessCompletionTime = accessCompletion.fence->getCachedSignalTime(); + if (!Fence::isValidTimestamp(accessCompletionTime)) { + ALOGI("%" PRId64 "/%s: Detected invalid access completion! <%s>", id, token, + accessCompletion.annotation.c_str()); + continue; + } else { + ALOGV("%" PRId64 "/%s: Access completion time: %" PRId64 " <%s>", id, token, + accessCompletionTime, accessCompletion.annotation.c_str()); + } + + ALOGI_IF(Fence::isValidTimestamp(egressTime) && accessCompletionTime > egressTime, + "%" PRId64 "/%s: Detected access completion after egress!: %" PRId64 + " (%s) > %" PRId64 " (%s)", + id, token, accessCompletionTime, accessCompletion.annotation.c_str(), egressTime, + egress.annotation.c_str()); + + ALOGI_IF(Fence::isValidTimestamp(ingressTime) && accessCompletionTime < ingressTime, + "%" PRId64 "/%s: Detected access completion prior to ingress!: %" PRId64 + " (%s) < %" PRId64 " (%s)", + id, token, accessCompletionTime, accessCompletion.annotation.c_str(), ingressTime, + ingress.annotation.c_str()); + } + + ALOGV_IF(ingressTime != Fence::SIGNAL_TIME_INVALID, + "%" PRId64 "/%s: Ingress time: %" PRId64 " (%s)", id, token, ingressTime, + ingress.annotation.c_str()); +} + +} // namespace android
\ No newline at end of file diff --git a/libs/ui/FenceTime.cpp b/libs/ui/FenceTime.cpp index 4246c40f64..81afe9ef0e 100644 --- a/libs/ui/FenceTime.cpp +++ b/libs/ui/FenceTime.cpp @@ -59,6 +59,14 @@ FenceTime::FenceTime(nsecs_t signalTime) } } +FenceTimePtr FenceTime::makeValid(const sp<Fence>& fence) { + if (fence && fence->isValid()) { + return std::make_shared<FenceTime>(fence); + } else { + return std::make_shared<FenceTime>(systemTime()); + } +} + void FenceTime::applyTrustedSnapshot(const Snapshot& src) { if (CC_UNLIKELY(src.state != Snapshot::State::SIGNAL_TIME)) { // Applying Snapshot::State::FENCE, could change the valid state of the @@ -289,9 +297,10 @@ status_t FenceTime::Snapshot::unflatten( // ============================================================================ void FenceTimeline::push(const std::shared_ptr<FenceTime>& fence) { std::lock_guard<std::mutex> lock(mMutex); - while (mQueue.size() >= MAX_ENTRIES) { + static constexpr size_t MAX_QUEUE_SIZE = 64; + while (mQueue.size() >= MAX_QUEUE_SIZE) { // This is a sanity check to make sure the queue doesn't grow unbounded. - // MAX_ENTRIES should be big enough not to trigger this path. + // MAX_QUEUE_SIZE should be big enough not to trigger this path. // In case this path is taken though, users of FenceTime must make sure // not to rely solely on FenceTimeline to get the final timestamp and // should eventually call Fence::getSignalTime on their own. diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index 18c9a6bc48..f7c94005f1 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -27,6 +27,8 @@ #include <ui/GraphicBufferMapper.h> #include <utils/Trace.h> +#include <string> + namespace android { // =========================================================================== @@ -104,6 +106,7 @@ GraphicBuffer::GraphicBuffer() usage = 0; layerCount = 0; handle = nullptr; + mDependencyMonitor.setToken(std::to_string(mId)); } // deprecated @@ -155,6 +158,8 @@ GraphicBuffer::GraphicBuffer(const GraphicBufferAllocator::AllocationRequest& re layerCount = request.layerCount; usage = request.usage; usage_deprecated = int(usage); + std::string name = request.requestorName; + mDependencyMonitor.setToken(name.append(":").append(std::to_string(mId))); } } @@ -252,6 +257,7 @@ status_t GraphicBuffer::initWithSize(uint32_t inWidth, uint32_t inHeight, usage = inUsage; usage_deprecated = int(usage); stride = static_cast<int>(outStride); + mDependencyMonitor.setToken(requestorName.append(":").append(std::to_string(mId))); } return err; } @@ -609,6 +615,14 @@ status_t GraphicBuffer::unflatten(void const*& buffer, size_t& size, int const*& mBufferMapper.getTransportSize(handle, &mTransportNumFds, &mTransportNumInts); } + std::string name; + status_t err = mBufferMapper.getName(handle, &name); + if (err != NO_ERROR) { + name = "<Unknown>"; + } + + mDependencyMonitor.setToken(name.append(":").append(std::to_string(mId))); + buffer = static_cast<void const*>(static_cast<uint8_t const*>(buffer) + sizeNeeded); size -= sizeNeeded; fds += numFds; diff --git a/libs/ui/include/ui/DependencyMonitor.h b/libs/ui/include/ui/DependencyMonitor.h new file mode 100644 index 0000000000..5ad1fd9528 --- /dev/null +++ b/libs/ui/include/ui/DependencyMonitor.h @@ -0,0 +1,104 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <ui/FatVector.h> +#include <ui/FenceTime.h> +#include <ui/RingBuffer.h> + +namespace android { + +// Debugging class for that tries to add userspace logging for fence depencencies. +// The model that a DependencyMonitor tries to follow is, for each access of some resource: +// 1. There is a single ingress fence, that guards whether a resource is now safe to read from +// another system. +// 2. There are multiple access fences, that are fired when a resource is read. +// 3. There is a single egress fence, that is fired when a resource is released and sent to another +// system. +// +// Note that there can be repeated ingress and egress of a resource, but the assumption is that +// there is exactly one egress for every ingress, unless the resource is destroyed rather than +// released. +// +// The DependencyMonitor will log if there is an anomaly in the fences tracked for some resource. +// This includes: +// * If (2) happens before (1) +// * If (2) happens after (3) +// +// Note that this class has no knowledge of the "other system". I.e., if the other system ignores +// the fence reported in (3), but still takes a long time to write to the resource and produce (1), +// then nothing will be logged. That other system must have its own DependencyMonitor. Conversely, +// this class has imperfect knowledge of the system it is monitoring. For example, this class does +// not know the precise start times of reading from a resource, the exact time that a read might +// occur from a hardware unit is not known to userspace. +// +// In other words, this class logs specific classes of fence violations, but is not sensitive to +// *all* violations. One property of this is that unless the system tracked by a DependencyMonitor +// is feeding in literally incorrect fences, then there is no chance of a false positive. +// +// This class is thread safe. +class DependencyMonitor { +public: + // Sets a debug token identifying the resource this monitor is tracking. + void setToken(std::string token) { mToken = std::move(token); } + + // Adds a fence that is fired when the resource ready to be ingested by the system using the + // DependencyMonitor. + void addIngress(FenceTimePtr fence, std::string annotation); + // Adds a fence that is fired when the resource is accessed. + void addAccessCompletion(FenceTimePtr fence, std::string annotation); + // Adds a fence that is fired when the resource is released to another system. + void addEgress(FenceTimePtr fence, std::string annotation); + +private: + struct AnnotatedFenceTime { + FenceTimePtr fence; + std::string annotation; + }; + + struct DependencyBlock { + int64_t id = -1; + AnnotatedFenceTime ingress = {FenceTime::NO_FENCE, ""}; + FatVector<AnnotatedFenceTime> accessCompletions; + AnnotatedFenceTime egress = {FenceTime::NO_FENCE, ""}; + bool validated = false; + const char* token = nullptr; + + void reset(const char* newToken) { + static std::atomic<int64_t> counter = 0; + id = counter++; + ingress = {FenceTime::NO_FENCE, ""}; + accessCompletions.clear(); + egress = {FenceTime::NO_FENCE, ""}; + validated = false; + token = newToken; + } + + // Returns true if all fences in this block have valid signal times. + bool updateSignalTimes(bool excludeIngress); + + void checkUnsafeAccess() const; + }; + + void resolveLocked() REQUIRES(mMutex); + + std::string mToken; + std::mutex mMutex; + ui::RingBuffer<DependencyBlock, 10> mDependencies GUARDED_BY(mMutex); +}; + +} // namespace android
\ No newline at end of file diff --git a/libs/ui/include/ui/DisplayId.h b/libs/ui/include/ui/DisplayId.h index 937e3f1486..1e1c77b9fc 100644 --- a/libs/ui/include/ui/DisplayId.h +++ b/libs/ui/include/ui/DisplayId.h @@ -20,6 +20,7 @@ #include <ostream> #include <string> +#include <ftl/match.h> #include <ftl/optional.h> namespace android { @@ -36,7 +37,6 @@ struct DisplayId { DisplayId& operator=(const DisplayId&) = default; static constexpr DisplayId fromValue(uint64_t value) { return DisplayId(value); } - constexpr bool isVirtual() const { return value & FLAG_VIRTUAL; } uint64_t value; @@ -66,13 +66,6 @@ struct PhysicalDisplayId : DisplayId { // TODO: b/162612135 - Remove default constructor. PhysicalDisplayId() = default; - static constexpr ftl::Optional<PhysicalDisplayId> tryCast(DisplayId id) { - if (id.isVirtual()) { - return std::nullopt; - } - return PhysicalDisplayId(id); - } - // Returns a stable ID based on EDID and port information. static constexpr PhysicalDisplayId fromEdid(uint8_t port, uint16_t manufacturerId, uint32_t modelHash) { @@ -90,8 +83,6 @@ struct PhysicalDisplayId : DisplayId { return PhysicalDisplayId(value); } - constexpr uint8_t getPort() const { return static_cast<uint8_t>(value); } - private: // Flag indicating that the ID is stable across reboots. static constexpr uint64_t FLAG_STABLE = 1ULL << 62; @@ -112,13 +103,6 @@ struct VirtualDisplayId : DisplayId { // Flag indicating that this virtual display is backed by the GPU. static constexpr uint64_t FLAG_GPU = 1ULL << 61; - static constexpr std::optional<VirtualDisplayId> tryCast(DisplayId id) { - if (id.isVirtual()) { - return VirtualDisplayId(id); - } - return std::nullopt; - } - static constexpr VirtualDisplayId fromValue(uint64_t value) { return VirtualDisplayId(SkipVirtualFlag{}, value); } @@ -134,13 +118,6 @@ protected: struct HalVirtualDisplayId : VirtualDisplayId { explicit constexpr HalVirtualDisplayId(BaseId baseId) : VirtualDisplayId(baseId) {} - static constexpr std::optional<HalVirtualDisplayId> tryCast(DisplayId id) { - if (id.isVirtual() && !(id.value & FLAG_GPU)) { - return HalVirtualDisplayId(id); - } - return std::nullopt; - } - static constexpr HalVirtualDisplayId fromValue(uint64_t value) { return HalVirtualDisplayId(SkipVirtualFlag{}, value); } @@ -152,13 +129,6 @@ private: struct GpuVirtualDisplayId : VirtualDisplayId { explicit constexpr GpuVirtualDisplayId(BaseId baseId) : VirtualDisplayId(FLAG_GPU | baseId) {} - static constexpr std::optional<GpuVirtualDisplayId> tryCast(DisplayId id) { - if (id.isVirtual() && (id.value & FLAG_GPU)) { - return GpuVirtualDisplayId(id); - } - return std::nullopt; - } - static constexpr GpuVirtualDisplayId fromValue(uint64_t value) { return GpuVirtualDisplayId(SkipVirtualFlag{}, value); } @@ -172,14 +142,6 @@ private: struct HalDisplayId : DisplayId { constexpr HalDisplayId(HalVirtualDisplayId other) : DisplayId(other) {} constexpr HalDisplayId(PhysicalDisplayId other) : DisplayId(other) {} - - static constexpr std::optional<HalDisplayId> tryCast(DisplayId id) { - if (GpuVirtualDisplayId::tryCast(id)) { - return std::nullopt; - } - return HalDisplayId(id); - } - static constexpr HalDisplayId fromValue(uint64_t value) { return HalDisplayId(value); } private: @@ -187,6 +149,47 @@ private: explicit constexpr HalDisplayId(DisplayId other) : DisplayId(other) {} }; +using DisplayIdVariant = std::variant<PhysicalDisplayId, GpuVirtualDisplayId, HalVirtualDisplayId>; +using VirtualDisplayIdVariant = std::variant<GpuVirtualDisplayId, HalVirtualDisplayId>; + +template <typename DisplayIdType> +inline auto asDisplayIdOfType(DisplayIdVariant variant) -> ftl::Optional<DisplayIdType> { + return ftl::match( + variant, + [](DisplayIdType id) -> ftl::Optional<DisplayIdType> { return ftl::Optional(id); }, + [](auto) -> ftl::Optional<DisplayIdType> { return std::nullopt; }); +} + +template <typename Variant> +inline auto asHalDisplayId(Variant variant) -> ftl::Optional<HalDisplayId> { + return ftl::match( + variant, + [](GpuVirtualDisplayId) -> ftl::Optional<HalDisplayId> { return std::nullopt; }, + [](auto id) -> ftl::Optional<HalDisplayId> { + return ftl::Optional(static_cast<HalDisplayId>(id)); + }); +} + +inline auto asPhysicalDisplayId(DisplayIdVariant variant) -> ftl::Optional<PhysicalDisplayId> { + return asDisplayIdOfType<PhysicalDisplayId>(variant); +} + +inline auto asVirtualDisplayId(DisplayIdVariant variant) -> ftl::Optional<VirtualDisplayId> { + return ftl::match( + variant, + [](GpuVirtualDisplayId id) -> ftl::Optional<VirtualDisplayId> { + return ftl::Optional(static_cast<VirtualDisplayId>(id)); + }, + [](HalVirtualDisplayId id) -> ftl::Optional<VirtualDisplayId> { + return ftl::Optional(static_cast<VirtualDisplayId>(id)); + }, + [](auto) -> ftl::Optional<VirtualDisplayId> { return std::nullopt; }); +} + +inline auto asDisplayId(DisplayIdVariant variant) -> DisplayId { + return ftl::match(variant, [](auto id) -> DisplayId { return static_cast<DisplayId>(id); }); +} + static_assert(sizeof(DisplayId) == sizeof(uint64_t)); static_assert(sizeof(HalDisplayId) == sizeof(uint64_t)); static_assert(sizeof(VirtualDisplayId) == sizeof(uint64_t)); diff --git a/libs/ui/include/ui/FenceTime.h b/libs/ui/include/ui/FenceTime.h index 334106f0cf..3560d57cff 100644 --- a/libs/ui/include/ui/FenceTime.h +++ b/libs/ui/include/ui/FenceTime.h @@ -17,6 +17,7 @@ #ifndef ANDROID_FENCE_TIME_H #define ANDROID_FENCE_TIME_H +#include <stddef.h> #include <ui/Fence.h> #include <utils/Flattenable.h> #include <utils/Mutex.h> @@ -30,6 +31,8 @@ namespace android { class FenceToFenceTimeMap; +class FenceTime; +using FenceTimePtr = std::shared_ptr<FenceTime>; // A wrapper around fence that only implements isValid and getSignalTime. // It automatically closes the fence in a thread-safe manner once the signal @@ -95,6 +98,10 @@ public: FenceTime& operator=(const FenceTime&) = delete; FenceTime& operator=(FenceTime&&) = delete; + // Constructs a FenceTime, falling back to a timestamp if the fence is + // invalid. + static FenceTimePtr makeValid(const sp<Fence>& fence); + // This method should only be called when replacing the fence with // a signalTime. Since this is an indirect way of setting the signal time // of a fence, the snapshot should come from a trusted source. @@ -142,8 +149,6 @@ private: std::atomic<nsecs_t> mSignalTime{Fence::SIGNAL_TIME_INVALID}; }; -using FenceTimePtr = std::shared_ptr<FenceTime>; - // A queue of FenceTimes that are expected to signal in FIFO order. // Only maintains a queue of weak pointers so it doesn't keep references // to Fences on its own. @@ -162,8 +167,6 @@ using FenceTimePtr = std::shared_ptr<FenceTime>; // different threads. class FenceTimeline { public: - static constexpr size_t MAX_ENTRIES = 64; - void push(const std::shared_ptr<FenceTime>& fence); void updateSignalTimes(); diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h index 936bf8f862..9305180ecb 100644 --- a/libs/ui/include/ui/GraphicBuffer.h +++ b/libs/ui/include/ui/GraphicBuffer.h @@ -23,6 +23,7 @@ #include <string> #include <utility> #include <vector> +#include "ui/DependencyMonitor.h" #include <android/hardware_buffer.h> #include <ui/ANativeObjectBase.h> @@ -229,6 +230,8 @@ public: void addDeathCallback(GraphicBufferDeathCallback deathCallback, void* context); + DependencyMonitor& getDependencyMonitor() { return mDependencyMonitor; } + private: ~GraphicBuffer(); @@ -295,6 +298,8 @@ private: // and informs SurfaceFlinger that it should drop its strong pointer reference to the buffer. std::vector<std::pair<GraphicBufferDeathCallback, void* /*mDeathCallbackContext*/>> mDeathCallbacks; + + DependencyMonitor mDependencyMonitor; }; } // namespace android diff --git a/libs/ui/include/ui/StaticDisplayInfo.h b/libs/ui/include/ui/StaticDisplayInfo.h index 83da821f37..53164487f3 100644 --- a/libs/ui/include/ui/StaticDisplayInfo.h +++ b/libs/ui/include/ui/StaticDisplayInfo.h @@ -28,6 +28,7 @@ enum class DisplayConnectionType { Internal, External, ftl_last = External }; // Immutable information about physical display. struct StaticDisplayInfo { DisplayConnectionType connectionType = DisplayConnectionType::Internal; + uint8_t port; float density = 0.f; bool secure = false; std::optional<DeviceProductInfo> deviceProductInfo; diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp index 2b11786df3..d950f2a23f 100644 --- a/libs/ui/tests/Android.bp +++ b/libs/ui/tests/Android.bp @@ -45,16 +45,6 @@ cc_test { } cc_test { - name: "DisplayId_test", - shared_libs: ["libui"], - srcs: ["DisplayId_test.cpp"], - cflags: [ - "-Wall", - "-Werror", - ], -} - -cc_test { name: "DisplayIdentification_test", shared_libs: ["libui"], static_libs: ["libgmock"], diff --git a/libs/ui/tests/DisplayId_test.cpp b/libs/ui/tests/DisplayId_test.cpp deleted file mode 100644 index 209acba672..0000000000 --- a/libs/ui/tests/DisplayId_test.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <ui/DisplayId.h> - -#include <gtest/gtest.h> - -namespace android::ui { - -TEST(DisplayIdTest, createPhysicalIdFromEdid) { - constexpr uint8_t port = 1; - constexpr uint16_t manufacturerId = 13; - constexpr uint32_t modelHash = 42; - const PhysicalDisplayId id = PhysicalDisplayId::fromEdid(port, manufacturerId, modelHash); - EXPECT_EQ(port, id.getPort()); - EXPECT_FALSE(VirtualDisplayId::tryCast(id)); - EXPECT_FALSE(HalVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id)); - EXPECT_TRUE(PhysicalDisplayId::tryCast(id)); - EXPECT_TRUE(HalDisplayId::tryCast(id)); - - EXPECT_EQ(id, DisplayId::fromValue(id.value)); - EXPECT_EQ(id, PhysicalDisplayId::fromValue(id.value)); -} - -TEST(DisplayIdTest, createPhysicalIdFromPort) { - constexpr uint8_t port = 3; - const PhysicalDisplayId id = PhysicalDisplayId::fromPort(port); - EXPECT_EQ(port, id.getPort()); - EXPECT_FALSE(VirtualDisplayId::tryCast(id)); - EXPECT_FALSE(HalVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id)); - EXPECT_TRUE(PhysicalDisplayId::tryCast(id)); - EXPECT_TRUE(HalDisplayId::tryCast(id)); - - EXPECT_EQ(id, DisplayId::fromValue(id.value)); - EXPECT_EQ(id, PhysicalDisplayId::fromValue(id.value)); -} - -TEST(DisplayIdTest, createGpuVirtualId) { - const GpuVirtualDisplayId id(42); - EXPECT_TRUE(VirtualDisplayId::tryCast(id)); - EXPECT_TRUE(GpuVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(HalVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(PhysicalDisplayId::tryCast(id)); - EXPECT_FALSE(HalDisplayId::tryCast(id)); - - EXPECT_EQ(id, DisplayId::fromValue(id.value)); - EXPECT_EQ(id, GpuVirtualDisplayId::fromValue(id.value)); -} - -TEST(DisplayIdTest, createVirtualIdFromGpuVirtualId) { - const VirtualDisplayId id(GpuVirtualDisplayId(42)); - EXPECT_TRUE(VirtualDisplayId::tryCast(id)); - EXPECT_TRUE(GpuVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(HalVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(PhysicalDisplayId::tryCast(id)); - EXPECT_FALSE(HalDisplayId::tryCast(id)); - - const bool isGpuVirtualId = (id.value & VirtualDisplayId::FLAG_GPU); - EXPECT_EQ((id.isVirtual() && isGpuVirtualId), GpuVirtualDisplayId::tryCast(id).has_value()); -} - -TEST(DisplayIdTest, createHalVirtualId) { - const HalVirtualDisplayId id(42); - EXPECT_TRUE(VirtualDisplayId::tryCast(id)); - EXPECT_TRUE(HalVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(PhysicalDisplayId::tryCast(id)); - EXPECT_TRUE(HalDisplayId::tryCast(id)); - - EXPECT_EQ(id, DisplayId::fromValue(id.value)); - EXPECT_EQ(id, HalVirtualDisplayId::fromValue(id.value)); -} - -TEST(DisplayIdTest, createVirtualIdFromHalVirtualId) { - const VirtualDisplayId id(HalVirtualDisplayId(42)); - EXPECT_TRUE(VirtualDisplayId::tryCast(id)); - EXPECT_TRUE(HalVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(GpuVirtualDisplayId::tryCast(id)); - EXPECT_FALSE(PhysicalDisplayId::tryCast(id)); - EXPECT_TRUE(HalDisplayId::tryCast(id)); - - const bool isGpuVirtualId = (id.value & VirtualDisplayId::FLAG_GPU); - EXPECT_EQ((id.isVirtual() && !isGpuVirtualId), HalVirtualDisplayId::tryCast(id).has_value()); -} - -} // namespace android::ui |