/* * Copyright (C) 2007 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 "SurfaceComposerClient" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // This server size should always be smaller than the server cache size #define BUFFER_CACHE_MAX_SIZE 4096 namespace android { using aidl::android::hardware::graphics::common::DisplayDecorationSupport; using gui::FocusRequest; using gui::IRegionSamplingListener; using gui::TrustedPresentationThresholds; using gui::WindowInfo; using gui::WindowInfoHandle; using gui::WindowInfosListener; using gui::aidl_utils::statusTFromBinderStatus; using ui::ColorMode; // --------------------------------------------------------------------------- ANDROID_SINGLETON_STATIC_INSTANCE(ComposerService); ANDROID_SINGLETON_STATIC_INSTANCE(ComposerServiceAIDL); namespace { // Initialize transaction id counter used to generate transaction ids std::atomic idCounter = 0; int64_t generateId() { return (((int64_t)getpid()) << 32) | ++idCounter; } constexpr int64_t INVALID_VSYNC = -1; const constexpr char* LOG_SURFACE_CONTROL_REGISTRY = "SurfaceControlRegistry"; } // namespace const std::string SurfaceComposerClient::kEmpty{}; ComposerService::ComposerService() : Singleton() { Mutex::Autolock _l(mLock); connectLocked(); } bool ComposerService::connectLocked() { const String16 name("SurfaceFlinger"); mComposerService = waitForService(name); if (mComposerService == nullptr) { return false; // fatal error or permission problem } // Create the death listener. class DeathObserver : public IBinder::DeathRecipient { ComposerService& mComposerService; virtual void binderDied(const wp& who) { ALOGW("ComposerService remote (surfaceflinger) died [%p]", who.unsafe_get()); mComposerService.composerServiceDied(); } public: explicit DeathObserver(ComposerService& mgr) : mComposerService(mgr) { } }; mDeathObserver = new DeathObserver(*const_cast(this)); IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver); return true; } /*static*/ sp ComposerService::getComposerService() { ComposerService& instance = ComposerService::getInstance(); Mutex::Autolock _l(instance.mLock); if (instance.mComposerService == nullptr) { if (ComposerService::getInstance().connectLocked()) { ALOGD("ComposerService reconnected"); } } return instance.mComposerService; } void ComposerService::composerServiceDied() { Mutex::Autolock _l(mLock); mComposerService = nullptr; mDeathObserver = nullptr; } ComposerServiceAIDL::ComposerServiceAIDL() : Singleton() { std::scoped_lock lock(mMutex); connectLocked(); } bool ComposerServiceAIDL::connectLocked() { const String16 name("SurfaceFlingerAIDL"); mComposerService = waitForService(name); if (mComposerService == nullptr) { return false; // fatal error or permission problem } // Create the death listener. class DeathObserver : public IBinder::DeathRecipient { ComposerServiceAIDL& mComposerService; virtual void binderDied(const wp& who) { ALOGW("ComposerService aidl remote (surfaceflinger) died [%p]", who.unsafe_get()); mComposerService.composerServiceDied(); } public: explicit DeathObserver(ComposerServiceAIDL& mgr) : mComposerService(mgr) {} }; mDeathObserver = new DeathObserver(*const_cast(this)); IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver); return true; } /*static*/ sp ComposerServiceAIDL::getComposerService() { ComposerServiceAIDL& instance = ComposerServiceAIDL::getInstance(); std::scoped_lock lock(instance.mMutex); if (instance.mComposerService == nullptr) { if (ComposerServiceAIDL::getInstance().connectLocked()) { ALOGD("ComposerServiceAIDL reconnected"); WindowInfosListenerReporter::getInstance()->reconnect(instance.mComposerService); } } return instance.mComposerService; } void ComposerServiceAIDL::composerServiceDied() { std::scoped_lock lock(mMutex); mComposerService = nullptr; mDeathObserver = nullptr; } class DefaultComposerClient: public Singleton { Mutex mLock; sp mClient; friend class Singleton; public: static sp getComposerClient() { DefaultComposerClient& dc = DefaultComposerClient::getInstance(); Mutex::Autolock _l(dc.mLock); if (dc.mClient == nullptr) { dc.mClient = new SurfaceComposerClient; } return dc.mClient; } }; ANDROID_SINGLETON_STATIC_INSTANCE(DefaultComposerClient); sp SurfaceComposerClient::getDefault() { return DefaultComposerClient::getComposerClient(); } // --------------------------------------------------------------------------- JankDataListener::~JankDataListener() { } status_t JankDataListener::flushJankData() { if (mLayerId == -1) { return INVALID_OPERATION; } binder::Status status = ComposerServiceAIDL::getComposerService()->flushJankData(mLayerId); return statusTFromBinderStatus(status); } std::mutex JankDataListenerFanOut::sFanoutInstanceMutex; std::unordered_map> JankDataListenerFanOut::sFanoutInstances; binder::Status JankDataListenerFanOut::onJankData(const std::vector& jankData) { // Find the highest VSync ID. int64_t lastVsync = jankData.empty() ? 0 : std::max_element(jankData.begin(), jankData.end(), [](const gui::JankData& jd1, const gui::JankData& jd2) { return jd1.frameVsyncId < jd2.frameVsyncId; }) ->frameVsyncId; // Fan out the jank data callback. std::vector> listenersToRemove; for (auto listener : getActiveListeners()) { if (!listener->onJankDataAvailable(jankData) || (listener->mRemoveAfter >= 0 && listener->mRemoveAfter <= lastVsync)) { listenersToRemove.push_back(listener); } } return removeListeners(listenersToRemove) ? binder::Status::ok() : binder::Status::fromExceptionCode(binder::Status::EX_NULL_POINTER); } status_t JankDataListenerFanOut::addListener(sp sc, sp listener) { sp layer = sc->getHandle(); if (layer == nullptr) { return UNEXPECTED_NULL; } int32_t layerId = sc->getLayerId(); sFanoutInstanceMutex.lock(); auto it = sFanoutInstances.find(layerId); bool registerNeeded = it == sFanoutInstances.end(); sp fanout; if (registerNeeded) { fanout = sp::make(layerId); sFanoutInstances.insert({layerId, fanout}); } else { fanout = it->second; } fanout->mMutex.lock(); fanout->mListeners.insert(listener); fanout->mMutex.unlock(); sFanoutInstanceMutex.unlock(); if (registerNeeded) { binder::Status status = ComposerServiceAIDL::getComposerService()->addJankListener(layer, fanout); return statusTFromBinderStatus(status); } return OK; } status_t JankDataListenerFanOut::removeListener(sp listener) { int32_t layerId = listener->mLayerId; if (layerId == -1) { return INVALID_OPERATION; } int64_t removeAfter = INVALID_VSYNC; sp fanout; sFanoutInstanceMutex.lock(); auto it = sFanoutInstances.find(layerId); if (it != sFanoutInstances.end()) { fanout = it->second; removeAfter = fanout->updateAndGetRemovalVSync(); } if (removeAfter != INVALID_VSYNC) { // Remove this instance from the map, so that no new listeners are added // while we're scheduled to be removed. sFanoutInstances.erase(layerId); } sFanoutInstanceMutex.unlock(); if (removeAfter < 0) { return OK; } binder::Status status = ComposerServiceAIDL::getComposerService()->removeJankListener(layerId, fanout, removeAfter); return statusTFromBinderStatus(status); } std::vector> JankDataListenerFanOut::getActiveListeners() { std::scoped_lock lock(mMutex); std::vector> listeners; for (auto it = mListeners.begin(); it != mListeners.end();) { auto listener = it->promote(); if (!listener) { it = mListeners.erase(it); } else { listeners.push_back(std::move(listener)); it++; } } return listeners; } bool JankDataListenerFanOut::removeListeners(const std::vector>& listeners) { std::scoped_lock fanoutLock(sFanoutInstanceMutex); std::scoped_lock listenersLock(mMutex); for (auto listener : listeners) { mListeners.erase(listener); } if (mListeners.empty()) { sFanoutInstances.erase(mLayerId); return false; } return true; } int64_t JankDataListenerFanOut::updateAndGetRemovalVSync() { std::scoped_lock lock(mMutex); if (mRemoveAfter >= 0) { // We've already been scheduled to be removed. Don't schedule again. return INVALID_VSYNC; } int64_t removeAfter = 0; for (auto it = mListeners.begin(); it != mListeners.end();) { auto listener = it->promote(); if (!listener) { it = mListeners.erase(it); } else if (listener->mRemoveAfter < 0) { // We have at least one listener that's still interested. Don't remove. return INVALID_VSYNC; } else { removeAfter = std::max(removeAfter, listener->mRemoveAfter); it++; } } mRemoveAfter = removeAfter; return removeAfter; } // --------------------------------------------------------------------------- // TransactionCompletedListener does not use ANDROID_SINGLETON_STATIC_INSTANCE because it needs // to be able to return a sp<> to its instance to pass to SurfaceFlinger. // ANDROID_SINGLETON_STATIC_INSTANCE only allows a reference to an instance. // 0 is an invalid callback id TransactionCompletedListener::TransactionCompletedListener() : mCallbackIdCounter(1) {} int64_t TransactionCompletedListener::getNextIdLocked() { return mCallbackIdCounter++; } sp TransactionCompletedListener::sInstance = nullptr; static std::mutex sListenerInstanceMutex; void TransactionCompletedListener::setInstance(const sp& listener) { sInstance = listener; } sp TransactionCompletedListener::getInstance() { std::lock_guard lock(sListenerInstanceMutex); if (sInstance == nullptr) { sInstance = new TransactionCompletedListener; } return sInstance; } sp TransactionCompletedListener::getIInstance() { return static_cast>(getInstance()); } void TransactionCompletedListener::startListeningLocked() { if (mListening) { return; } ProcessState::self()->startThreadPool(); mListening = true; } CallbackId TransactionCompletedListener::addCallbackFunction( const TransactionCompletedCallback& callbackFunction, const std::unordered_set, SurfaceComposerClient::SCHash>& surfaceControls, CallbackId::Type callbackType) { std::lock_guard lock(mMutex); startListeningLocked(); CallbackId callbackId(getNextIdLocked(), callbackType); mCallbacks[callbackId].callbackFunction = callbackFunction; auto& callbackSurfaceControls = mCallbacks[callbackId].surfaceControls; for (const auto& surfaceControl : surfaceControls) { callbackSurfaceControls[surfaceControl->getHandle()] = surfaceControl; } return callbackId; } void TransactionCompletedListener::setReleaseBufferCallback(const ReleaseCallbackId& callbackId, ReleaseBufferCallback listener) { std::scoped_lock lock(mMutex); mReleaseBufferCallbacks[callbackId] = listener; } void TransactionCompletedListener::addSurfaceStatsListener(void* context, void* cookie, sp surfaceControl, SurfaceStatsCallback listener) { std::scoped_lock lock(mSurfaceStatsListenerMutex); mSurfaceStatsListeners.insert( {surfaceControl->getLayerId(), SurfaceStatsCallbackEntry(context, cookie, listener)}); } void TransactionCompletedListener::removeSurfaceStatsListener(void* context, void* cookie) { std::scoped_lock lock(mSurfaceStatsListenerMutex); for (auto it = mSurfaceStatsListeners.begin(); it != mSurfaceStatsListeners.end();) { auto [itContext, itCookie, itListener] = it->second; if (itContext == context && itCookie == cookie) { it = mSurfaceStatsListeners.erase(it); } else { it++; } } } void TransactionCompletedListener::addSurfaceControlToCallbacks( const sp& surfaceControl, const std::unordered_set& callbackIds) { std::lock_guard lock(mMutex); for (auto callbackId : callbackIds) { mCallbacks[callbackId].surfaceControls.emplace(std::piecewise_construct, std::forward_as_tuple( surfaceControl->getHandle()), std::forward_as_tuple(surfaceControl)); } } void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) { std::unordered_map callbacksMap; { std::lock_guard lock(mMutex); /* This listener knows all the sp to sp for all its registered * callbackIds, except for when Transactions are merged together. This probably cannot be * solved before this point because the Transactions could be merged together and applied in * a different process. * * Fortunately, we get all the callbacks for this listener for the same frame together at * the same time. This means if any Transactions were merged together, we will get their * callbacks at the same time. We can combine all the sp to sp maps * for all the callbackIds to generate one super map that contains all the sp to * sp that could possibly exist for the callbacks. */ callbacksMap = mCallbacks; for (const auto& transactionStats : listenerStats.transactionStats) { for (auto& callbackId : transactionStats.callbackIds) { mCallbacks.erase(callbackId); } } } for (const auto& transactionStats : listenerStats.transactionStats) { // handle on commit callbacks for (auto callbackId : transactionStats.callbackIds) { if (callbackId.type != CallbackId::Type::ON_COMMIT) { continue; } auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId]; if (!callbackFunction) { continue; } std::vector surfaceControlStats; for (const auto& surfaceStats : transactionStats.surfaceStats) { surfaceControlStats .emplace_back(callbacksMap[callbackId] .surfaceControls[surfaceStats.surfaceControl], transactionStats.latchTime, surfaceStats.acquireTimeOrFence, transactionStats.presentFence, surfaceStats.previousReleaseFence, surfaceStats.transformHint, surfaceStats.eventStats, surfaceStats.currentMaxAcquiredBufferCount); } callbackFunction(transactionStats.latchTime, transactionStats.presentFence, surfaceControlStats); // More than one transaction may contain the same callback id. Erase the callback from // the map to ensure that it is only called once. This can happen if transactions are // parcelled out of process and applied in both processes. callbacksMap.erase(callbackId); } // handle on complete callbacks for (auto callbackId : transactionStats.callbackIds) { if (callbackId.type != CallbackId::Type::ON_COMPLETE) { continue; } auto& [callbackFunction, callbackSurfaceControls] = callbacksMap[callbackId]; if (!callbackFunction) { ALOGE("cannot call null callback function, skipping"); continue; } std::vector surfaceControlStats; for (const auto& surfaceStats : transactionStats.surfaceStats) { surfaceControlStats .emplace_back(callbacksMap[callbackId] .surfaceControls[surfaceStats.surfaceControl], transactionStats.latchTime, surfaceStats.acquireTimeOrFence, transactionStats.presentFence, surfaceStats.previousReleaseFence, surfaceStats.transformHint, surfaceStats.eventStats, surfaceStats.currentMaxAcquiredBufferCount); if (callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl] && surfaceStats.transformHint.has_value()) { callbacksMap[callbackId] .surfaceControls[surfaceStats.surfaceControl] ->setTransformHint(*surfaceStats.transformHint); } // If there is buffer id set, we look up any pending client release buffer callbacks // and call them. This is a performance optimization when we have a transaction // callback and a release buffer callback happening at the same time to avoid an // additional ipc call from the server. if (surfaceStats.previousReleaseCallbackId != ReleaseCallbackId::INVALID_ID) { ReleaseBufferCallback callback; { std::scoped_lock lock(mMutex); callback = popReleaseBufferCallbackLocked( surfaceStats.previousReleaseCallbackId); } if (callback) { callback(surfaceStats.previousReleaseCallbackId, surfaceStats.previousReleaseFence ? surfaceStats.previousReleaseFence : Fence::NO_FENCE, surfaceStats.currentMaxAcquiredBufferCount); } } } callbackFunction(transactionStats.latchTime, transactionStats.presentFence, surfaceControlStats); } } for (const auto& transactionStats : listenerStats.transactionStats) { for (const auto& surfaceStats : transactionStats.surfaceStats) { // The callbackMap contains the SurfaceControl object, which we need to look up the // layerId. Since we don't know which callback contains the SurfaceControl, iterate // through all until the SC is found. int32_t layerId = -1; for (auto callbackId : transactionStats.callbackIds) { if (callbackId.type != CallbackId::Type::ON_COMPLETE) { // We only want to run the stats callback for ON_COMPLETE continue; } sp sc = callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl]; if (sc != nullptr) { layerId = sc->getLayerId(); break; } } if (layerId != -1) { // Acquire surface stats listener lock such that we guarantee that after calling // unregister, there won't be any further callback. std::scoped_lock lock(mSurfaceStatsListenerMutex); auto listenerRange = mSurfaceStatsListeners.equal_range(layerId); for (auto it = listenerRange.first; it != listenerRange.second; it++) { auto entry = it->second; entry.callback(entry.context, transactionStats.latchTime, transactionStats.presentFence, surfaceStats); } } } } } void TransactionCompletedListener::onTransactionQueueStalled(const String8& reason) { std::unordered_map> callbackCopy; { std::scoped_lock lock(mMutex); callbackCopy = mQueueStallListeners; } for (auto const& it : callbackCopy) { it.second(reason.c_str()); } } void TransactionCompletedListener::addQueueStallListener( std::function stallListener, void* id) { std::scoped_lock lock(mMutex); mQueueStallListeners[id] = stallListener; } void TransactionCompletedListener::removeQueueStallListener(void* id) { std::scoped_lock lock(mMutex); mQueueStallListeners.erase(id); } void TransactionCompletedListener::onReleaseBuffer(ReleaseCallbackId callbackId, sp releaseFence, uint32_t currentMaxAcquiredBufferCount) { ReleaseBufferCallback callback; { std::scoped_lock lock(mMutex); callback = popReleaseBufferCallbackLocked(callbackId); } if (!callback) { ALOGE("Could not call release buffer callback, buffer not found %s", callbackId.to_string().c_str()); return; } std::optional optionalMaxAcquiredBufferCount = currentMaxAcquiredBufferCount == UINT_MAX ? std::nullopt : std::make_optional(currentMaxAcquiredBufferCount); callback(callbackId, releaseFence, optionalMaxAcquiredBufferCount); } ReleaseBufferCallback TransactionCompletedListener::popReleaseBufferCallbackLocked( const ReleaseCallbackId& callbackId) { ReleaseBufferCallback callback; auto itr = mReleaseBufferCallbacks.find(callbackId); if (itr == mReleaseBufferCallbacks.end()) { return nullptr; } callback = itr->second; mReleaseBufferCallbacks.erase(itr); return callback; } void TransactionCompletedListener::removeReleaseBufferCallback( const ReleaseCallbackId& callbackId) { { std::scoped_lock lock(mMutex); popReleaseBufferCallbackLocked(callbackId); } } SurfaceComposerClient::PresentationCallbackRAII::PresentationCallbackRAII( TransactionCompletedListener* tcl, int id) { mTcl = tcl; mId = id; } SurfaceComposerClient::PresentationCallbackRAII::~PresentationCallbackRAII() { mTcl->clearTrustedPresentationCallback(mId); } sp TransactionCompletedListener::addTrustedPresentationCallback(TrustedPresentationCallback tpc, int id, void* context) { std::scoped_lock lock(mMutex); mTrustedPresentationCallbacks[id] = std::tuple(tpc, context); return new SurfaceComposerClient::PresentationCallbackRAII(this, id); } void TransactionCompletedListener::clearTrustedPresentationCallback(int id) { std::scoped_lock lock(mMutex); mTrustedPresentationCallbacks.erase(id); } void TransactionCompletedListener::onTrustedPresentationChanged(int id, bool presentedWithinThresholds) { TrustedPresentationCallback tpc; void* context; { std::scoped_lock lock(mMutex); auto it = mTrustedPresentationCallbacks.find(id); if (it == mTrustedPresentationCallbacks.end()) { return; } std::tie(tpc, context) = it->second; } tpc(context, presentedWithinThresholds); } // --------------------------------------------------------------------------- void removeDeadBufferCallback(void* /*context*/, uint64_t graphicBufferId); /** * We use the BufferCache to reduce the overhead of exchanging GraphicBuffers with * the server. If we were to simply parcel the GraphicBuffer we would pay two overheads * 1. Cost of sending the FD * 2. Cost of importing the GraphicBuffer with the mapper in the receiving process. * To ease this cost we implement the following scheme of caching buffers to integers, * or said-otherwise, naming them with integers. This is the scheme known as slots in * the legacy BufferQueue system. * 1. When sending Buffers to SurfaceFlinger we look up the Buffer in the cache. * 2. If there is a cache-hit we remove the Buffer from the Transaction and instead * send the cached integer. * 3. If there is a cache miss, we cache the new buffer and send the integer * along with the Buffer, SurfaceFlinger on it's side creates a new cache * entry, and we use the integer for further communication. * A few details about lifetime: * 1. The cache evicts by LRU. The server side cache is keyed by BufferCache::getToken * which is per process Unique. The server side cache is larger than the client side * cache so that the server will never evict entries before the client. * 2. When the client evicts an entry it notifies the server via an uncacheBuffer * transaction. * 3. The client only references the Buffers by ID, and uses buffer->addDeathCallback * to auto-evict destroyed buffers. */ class BufferCache : public Singleton { public: BufferCache() : token(new BBinder()) {} sp getToken() { return IInterface::asBinder(TransactionCompletedListener::getIInstance()); } status_t getCacheId(const sp& buffer, uint64_t* cacheId) { std::lock_guard lock(mMutex); auto itr = mBuffers.find(buffer->getId()); if (itr == mBuffers.end()) { return BAD_VALUE; } itr->second = getCounter(); *cacheId = buffer->getId(); return NO_ERROR; } uint64_t cache(const sp& buffer, std::optional& outUncacheBuffer) { std::lock_guard lock(mMutex); if (mBuffers.size() >= BUFFER_CACHE_MAX_SIZE) { outUncacheBuffer = findLeastRecentlyUsedBuffer(); mBuffers.erase(outUncacheBuffer->id); } buffer->addDeathCallback(removeDeadBufferCallback, nullptr); mBuffers[buffer->getId()] = getCounter(); return buffer->getId(); } void uncache(uint64_t cacheId) { std::lock_guard lock(mMutex); if (mBuffers.erase(cacheId)) { SurfaceComposerClient::doUncacheBufferTransaction(cacheId); } } private: client_cache_t findLeastRecentlyUsedBuffer() REQUIRES(mMutex) { auto itr = mBuffers.begin(); uint64_t minCounter = itr->second; auto minBuffer = itr; itr++; while (itr != mBuffers.end()) { uint64_t counter = itr->second; if (counter < minCounter) { minCounter = counter; minBuffer = itr; } itr++; } return {.token = getToken(), .id = minBuffer->first}; } uint64_t getCounter() REQUIRES(mMutex) { static uint64_t counter = 0; return counter++; } std::mutex mMutex; std::map mBuffers GUARDED_BY(mMutex); // Used by ISurfaceComposer to identify which process is sending the cached buffer. sp token; }; ANDROID_SINGLETON_STATIC_INSTANCE(BufferCache); void removeDeadBufferCallback(void* /*context*/, uint64_t graphicBufferId) { // GraphicBuffer id's are used as the cache ids. BufferCache::getInstance().uncache(graphicBufferId); } // --------------------------------------------------------------------------- SurfaceComposerClient::Transaction::Transaction() { mId = generateId(); mTransactionCompletedListener = TransactionCompletedListener::getInstance(); } SurfaceComposerClient::Transaction::Transaction(const Transaction& other) : mId(other.mId), mAnimation(other.mAnimation), mEarlyWakeupStart(other.mEarlyWakeupStart), mEarlyWakeupEnd(other.mEarlyWakeupEnd), mMayContainBuffer(other.mMayContainBuffer), mDesiredPresentTime(other.mDesiredPresentTime), mIsAutoTimestamp(other.mIsAutoTimestamp), mFrameTimelineInfo(other.mFrameTimelineInfo), mApplyToken(other.mApplyToken) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; mInputWindowCommands = other.mInputWindowCommands; mListenerCallbacks = other.mListenerCallbacks; mTransactionCompletedListener = TransactionCompletedListener::getInstance(); } void SurfaceComposerClient::Transaction::sanitize(int pid, int uid) { uint32_t permissions = LayerStatePermissions::getTransactionPermissions(pid, uid); for (auto & [handle, composerState] : mComposerStates) { composerState.state.sanitize(permissions); } if (!mInputWindowCommands.empty() && (permissions & layer_state_t::Permission::ACCESS_SURFACE_FLINGER) == 0) { ALOGE("Only privileged callers are allowed to send input commands."); mInputWindowCommands.clear(); } } std::unique_ptr SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) { auto transaction = std::make_unique(); if (transaction->readFromParcel(parcel) == NO_ERROR) { return transaction; } return nullptr; } status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) { const uint64_t transactionId = parcel->readUint64(); const bool animation = parcel->readBool(); const bool earlyWakeupStart = parcel->readBool(); const bool earlyWakeupEnd = parcel->readBool(); const int64_t desiredPresentTime = parcel->readInt64(); const bool isAutoTimestamp = parcel->readBool(); const bool logCallPoints = parcel->readBool(); FrameTimelineInfo frameTimelineInfo; frameTimelineInfo.readFromParcel(parcel); sp applyToken; parcel->readNullableStrongBinder(&applyToken); size_t count = static_cast(parcel->readUint32()); if (count > parcel->dataSize()) { return BAD_VALUE; } SortedVector 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); } count = static_cast(parcel->readUint32()); if (count > parcel->dataSize()) { return BAD_VALUE; } std::unordered_map, CallbackInfo, TCLHash> listenerCallbacks; listenerCallbacks.reserve(count); for (size_t i = 0; i < count; i++) { sp listener = interface_cast(parcel->readStrongBinder()); size_t numCallbackIds = parcel->readUint32(); if (numCallbackIds > parcel->dataSize()) { return BAD_VALUE; } for (size_t j = 0; j < numCallbackIds; j++) { CallbackId id; parcel->readParcelable(&id); listenerCallbacks[listener].callbackIds.insert(id); } size_t numSurfaces = parcel->readUint32(); if (numSurfaces > parcel->dataSize()) { return BAD_VALUE; } for (size_t j = 0; j < numSurfaces; j++) { sp surface; SAFE_PARCEL(SurfaceControl::readFromParcel, *parcel, &surface); listenerCallbacks[listener].surfaceControls.insert(surface); } } count = static_cast(parcel->readUint32()); if (count > parcel->dataSize()) { return BAD_VALUE; } std::unordered_map, ComposerState, IBinderHash> composerStates; composerStates.reserve(count); for (size_t i = 0; i < count; i++) { sp surfaceControlHandle; SAFE_PARCEL(parcel->readStrongBinder, &surfaceControlHandle); ComposerState composerState; if (composerState.read(*parcel) == BAD_VALUE) { return BAD_VALUE; } composerStates[surfaceControlHandle] = composerState; } InputWindowCommands inputWindowCommands; inputWindowCommands.read(*parcel); count = static_cast(parcel->readUint32()); if (count > parcel->dataSize()) { return BAD_VALUE; } std::vector uncacheBuffers(count); for (size_t i = 0; i < count; i++) { sp tmpBinder; SAFE_PARCEL(parcel->readStrongBinder, &tmpBinder); uncacheBuffers[i].token = tmpBinder; SAFE_PARCEL(parcel->readUint64, &uncacheBuffers[i].id); } count = static_cast(parcel->readUint32()); if (count > parcel->dataSize()) { return BAD_VALUE; } std::vector mergedTransactionIds(count); for (size_t i = 0; i < count; i++) { SAFE_PARCEL(parcel->readUint64, &mergedTransactionIds[i]); } // Parsing was successful. Update the object. mId = transactionId; mAnimation = animation; mEarlyWakeupStart = earlyWakeupStart; mEarlyWakeupEnd = earlyWakeupEnd; mDesiredPresentTime = desiredPresentTime; mIsAutoTimestamp = isAutoTimestamp; mFrameTimelineInfo = frameTimelineInfo; mDisplayStates = displayStates; mListenerCallbacks = listenerCallbacks; mComposerStates = composerStates; mInputWindowCommands = inputWindowCommands; mApplyToken = applyToken; mUncacheBuffers = std::move(uncacheBuffers); mMergedTransactionIds = std::move(mergedTransactionIds); return NO_ERROR; } status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const { // If we write the Transaction to a parcel, we want to ensure the Buffers are cached // before crossing the IPC boundary. Otherwise the receiving party will cache the buffers // but is unlikely to use them again as they are owned by the other process. // You may be asking yourself, is this const cast safe? Const cast is safe up // until the point where you try and write to an object that was originally const at which // point we enter undefined behavior. In this case we are safe though, because there are // two possibilities: // 1. The SurfaceComposerClient::Transaction was originally non-const. Safe. // 2. It was originall const! In this case not only was it useless, but it by definition // contains no composer states and so cacheBuffers will not perform any writes. const_cast(this)->cacheBuffers(); parcel->writeUint64(mId); parcel->writeBool(mAnimation); parcel->writeBool(mEarlyWakeupStart); parcel->writeBool(mEarlyWakeupEnd); parcel->writeInt64(mDesiredPresentTime); parcel->writeBool(mIsAutoTimestamp); parcel->writeBool(mLogCallPoints); mFrameTimelineInfo.writeToParcel(parcel); parcel->writeStrongBinder(mApplyToken); parcel->writeUint32(static_cast(mDisplayStates.size())); for (auto const& displayState : mDisplayStates) { displayState.write(*parcel); } parcel->writeUint32(static_cast(mListenerCallbacks.size())); for (auto const& [listener, callbackInfo] : mListenerCallbacks) { parcel->writeStrongBinder(ITransactionCompletedListener::asBinder(listener)); parcel->writeUint32(static_cast(callbackInfo.callbackIds.size())); for (auto callbackId : callbackInfo.callbackIds) { parcel->writeParcelable(callbackId); } parcel->writeUint32(static_cast(callbackInfo.surfaceControls.size())); for (auto surfaceControl : callbackInfo.surfaceControls) { SAFE_PARCEL(surfaceControl->writeToParcel, *parcel); } } parcel->writeUint32(static_cast(mComposerStates.size())); for (auto const& [handle, composerState] : mComposerStates) { SAFE_PARCEL(parcel->writeStrongBinder, handle); composerState.write(*parcel); } mInputWindowCommands.write(*parcel); SAFE_PARCEL(parcel->writeUint32, static_cast(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(mMergedTransactionIds.size())); for (auto mergedTransactionId : mMergedTransactionIds) { SAFE_PARCEL(parcel->writeUint64, mergedTransactionId); } return NO_ERROR; } void SurfaceComposerClient::Transaction::releaseBufferIfOverwriting(const layer_state_t& state) { if (!(state.what & layer_state_t::eBufferChanged) || !state.bufferData->hasBuffer()) { return; } auto listener = state.bufferData->releaseBufferListener; sp fence = state.bufferData->acquireFence ? state.bufferData->acquireFence : Fence::NO_FENCE; if (state.bufferData->releaseBufferEndpoint == IInterface::asBinder(TransactionCompletedListener::getIInstance())) { // if the callback is in process, run on a different thread to avoid any lock contigency // issues in the client. SurfaceComposerClient::getDefault() ->mReleaseCallbackThread .addReleaseCallback(state.bufferData->generateReleaseCallbackId(), fence); } else { listener->onReleaseBuffer(state.bufferData->generateReleaseCallbackId(), fence, UINT_MAX); } } 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& [handle, composerState] : other.mComposerStates) { if (mComposerStates.count(handle) == 0) { mComposerStates[handle] = composerState; } else { if (composerState.state.what & layer_state_t::eBufferChanged) { releaseBufferIfOverwriting(mComposerStates[handle].state); } mComposerStates[handle].state.merge(composerState.state); } } for (auto const& state : other.mDisplayStates) { ssize_t index = mDisplayStates.indexOf(state); if (index < 0) { mDisplayStates.add(state); } else { mDisplayStates.editItemAt(static_cast(index)).merge(state); } } for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) { auto& [callbackIds, surfaceControls] = callbackInfo; mListenerCallbacks[listener].callbackIds.insert(std::make_move_iterator( callbackIds.begin()), std::make_move_iterator(callbackIds.end())); mListenerCallbacks[listener].surfaceControls.insert(surfaceControls.begin(), surfaceControls.end()); auto& currentProcessCallbackInfo = mListenerCallbacks[TransactionCompletedListener::getIInstance()]; currentProcessCallbackInfo.surfaceControls .insert(std::make_move_iterator(surfaceControls.begin()), std::make_move_iterator(surfaceControls.end())); // register all surface controls for all callbackIds for this listener that is merging for (const auto& surfaceControl : currentProcessCallbackInfo.surfaceControls) { mTransactionCompletedListener ->addSurfaceControlToCallbacks(surfaceControl, currentProcessCallbackInfo.callbackIds); } } for (const auto& cacheId : other.mUncacheBuffers) { mUncacheBuffers.push_back(cacheId); } mInputWindowCommands.merge(other.mInputWindowCommands); mMayContainBuffer |= other.mMayContainBuffer; mEarlyWakeupStart = mEarlyWakeupStart || other.mEarlyWakeupStart; mEarlyWakeupEnd = mEarlyWakeupEnd || other.mEarlyWakeupEnd; 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(); mListenerCallbacks.clear(); mInputWindowCommands.clear(); mUncacheBuffers.clear(); mMayContainBuffer = false; mAnimation = false; mEarlyWakeupStart = false; mEarlyWakeupEnd = false; mDesiredPresentTime = 0; mIsAutoTimestamp = true; mFrameTimelineInfo = {}; mApplyToken = nullptr; mMergedTransactionIds.clear(); mLogCallPoints = false; } uint64_t SurfaceComposerClient::Transaction::getId() { return mId; } std::vector SurfaceComposerClient::Transaction::getMergedTransactionIds() { return mMergedTransactionIds; } void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) { sp sf(ComposerService::getComposerService()); client_cache_t uncacheBuffer; uncacheBuffer.token = BufferCache::getInstance().getToken(); uncacheBuffer.id = cacheId; Vector composerStates; Vector displayStates; status_t status = sf->setTransactionState(FrameTimelineInfo{}, composerStates, displayStates, ISurfaceComposer::eOneWay, Transaction::getDefaultApplyToken(), {}, systemTime(), true, {uncacheBuffer}, false, {}, generateId(), {}); if (status != NO_ERROR) { ALOGE_AND_TRACE("SurfaceComposerClient::doUncacheBufferTransaction - %s", strerror(-status)); } } void SurfaceComposerClient::Transaction::cacheBuffers() { if (!mMayContainBuffer) { return; } size_t count = 0; for (auto& [handle, cs] : mComposerStates) { layer_state_t* s = &(mComposerStates[handle].state); if (!(s->what & layer_state_t::eBufferChanged)) { continue; } else if (s->bufferData && s->bufferData->flags.test(BufferData::BufferDataChange::cachedBufferChanged)) { // If eBufferChanged and eCachedBufferChanged are both trued then that means // we already cached the buffer in a previous call to cacheBuffers, perhaps // from writeToParcel on a Transaction that was merged in to this one. continue; } // Don't try to cache a null buffer. Sending null buffers is cheap so we shouldn't waste // time trying to cache them. if (!s->bufferData || !s->bufferData->buffer) { continue; } uint64_t cacheId = 0; status_t ret = BufferCache::getInstance().getCacheId(s->bufferData->buffer, &cacheId); if (ret == NO_ERROR) { // Cache-hit. Strip the buffer and send only the id. s->bufferData->buffer = nullptr; } else { // Cache-miss. Include the buffer and send the new cacheId. std::optional uncacheBuffer; cacheId = BufferCache::getInstance().cache(s->bufferData->buffer, uncacheBuffer); if (uncacheBuffer) { mUncacheBuffers.push_back(*uncacheBuffer); } } s->bufferData->flags |= BufferData::BufferDataChange::cachedBufferChanged; s->bufferData->cachedBuffer.token = BufferCache::getInstance().getToken(); s->bufferData->cachedBuffer.id = cacheId; // If we have more buffers than the size of the cache, we should stop caching so we don't // evict other buffers in this transaction count++; if (count >= BUFFER_CACHE_MAX_SIZE) { break; } } } class SyncCallback { public: static auto getCallback(std::shared_ptr& callbackContext) { return [callbackContext](void* /* unused context */, nsecs_t /* latchTime */, const sp& /* presentFence */, const std::vector& /* stats */) { if (!callbackContext) { ALOGE("failed to get callback context for SyncCallback"); return; } LOG_ALWAYS_FATAL_IF(sem_post(&callbackContext->mSemaphore), "sem_post failed"); }; } ~SyncCallback() { if (mInitialized) { LOG_ALWAYS_FATAL_IF(sem_destroy(&mSemaphore), "sem_destroy failed"); } } void init() { LOG_ALWAYS_FATAL_IF(clock_gettime(CLOCK_MONOTONIC, &mTimeoutTimespec) == -1, "clock_gettime() fail! in SyncCallback::init"); mTimeoutTimespec.tv_sec += 4; LOG_ALWAYS_FATAL_IF(sem_init(&mSemaphore, 0, 0), "sem_init failed"); mInitialized = true; } void wait() { int result = sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &mTimeoutTimespec); if (result && errno != ETIMEDOUT && errno != EINTR) { LOG_ALWAYS_FATAL("sem_clockwait failed(%d)", errno); } else if (errno == ETIMEDOUT) { ALOGW("Sync transaction timed out waiting for commit callback."); } } void* getContext() { return static_cast(this); } private: sem_t mSemaphore; bool mInitialized = false; timespec mTimeoutTimespec; }; status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay) { if (mStatus != NO_ERROR) { return mStatus; } std::shared_ptr syncCallback = std::make_shared(); if (synchronous) { syncCallback->init(); addTransactionCommittedCallback(SyncCallback::getCallback(syncCallback), /*callbackContext=*/nullptr); } bool hasListenerCallbacks = !mListenerCallbacks.empty(); std::vector listenerCallbacks; // For every listener with registered callbacks for (const auto& [listener, callbackInfo] : mListenerCallbacks) { auto& [callbackIds, surfaceControls] = callbackInfo; if (callbackIds.empty()) { continue; } if (surfaceControls.empty()) { listenerCallbacks.emplace_back(IInterface::asBinder(listener), std::move(callbackIds)); } else { // If the listener has any SurfaceControls set on this Transaction update the surface // state for (const auto& surfaceControl : surfaceControls) { layer_state_t* s = getLayerState(surfaceControl); if (!s) { ALOGE("failed to get layer state"); continue; } std::vector callbacks(callbackIds.begin(), callbackIds.end()); s->what |= layer_state_t::eHasListenerCallbacksChanged; s->listeners.emplace_back(IInterface::asBinder(listener), callbacks); } } } cacheBuffers(); Vector composerStates; Vector displayStates; uint32_t flags = 0; for (auto const& kv : mComposerStates) { composerStates.add(kv.second); } displayStates = std::move(mDisplayStates); if (mAnimation) { flags |= ISurfaceComposer::eAnimation; } if (oneWay) { if (synchronous) { ALOGE("Transaction attempted to set synchronous and one way at the same time" " this is an invalid request. Synchronous will win for safety"); } else { flags |= ISurfaceComposer::eOneWay; } } // If both mEarlyWakeupStart and mEarlyWakeupEnd are set // it is equivalent for none if (mEarlyWakeupStart && !mEarlyWakeupEnd) { flags |= ISurfaceComposer::eEarlyWakeupStart; } if (mEarlyWakeupEnd && !mEarlyWakeupStart) { flags |= ISurfaceComposer::eEarlyWakeupEnd; } sp applyToken = mApplyToken ? mApplyToken : getDefaultApplyToken(); sp sf(ComposerService::getComposerService()); status_t binderStatus = sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken, mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp, mUncacheBuffers, hasListenerCallbacks, listenerCallbacks, mId, mMergedTransactionIds); mId = generateId(); // Clear the current states and flags clear(); if (synchronous && binderStatus == OK) { syncCallback->wait(); } if (mLogCallPoints) { ALOG(LOG_DEBUG, LOG_SURFACE_CONTROL_REGISTRY, "Transaction %" PRIu64 " applied", mId); } mStatus = NO_ERROR; return binderStatus; } sp SurfaceComposerClient::Transaction::sApplyToken = new BBinder(); std::mutex SurfaceComposerClient::Transaction::sApplyTokenMutex; sp SurfaceComposerClient::Transaction::getDefaultApplyToken() { std::scoped_lock lock{sApplyTokenMutex}; return sApplyToken; } void SurfaceComposerClient::Transaction::setDefaultApplyToken(sp applyToken) { std::scoped_lock lock{sApplyTokenMutex}; sApplyToken = std::move(applyToken); } status_t SurfaceComposerClient::Transaction::sendSurfaceFlushJankDataTransaction( const sp& sc) { Transaction t; layer_state_t* s = t.getLayerState(sc); if (!s) { return BAD_INDEX; } s->what |= layer_state_t::eFlushJankData; t.registerSurfaceControlForCallback(sc); return t.apply(/*sync=*/false, /* oneWay=*/true); } void SurfaceComposerClient::Transaction::enableDebugLogCallPoints() { mLogCallPoints = true; } // --------------------------------------------------------------------------- sp SurfaceComposerClient::createVirtualDisplay(const std::string& displayName, bool isSecure, const std::string& uniqueId, float requestedRefreshRate) { sp display = nullptr; binder::Status status = ComposerServiceAIDL::getComposerService()->createVirtualDisplay(displayName, isSecure, uniqueId, requestedRefreshRate, &display); return status.isOk() ? display : nullptr; } status_t SurfaceComposerClient::destroyVirtualDisplay(const sp& displayToken) { return ComposerServiceAIDL::getComposerService() ->destroyVirtualDisplay(displayToken) .transactionError(); } std::vector SurfaceComposerClient::getPhysicalDisplayIds() { std::vector displayIds; std::vector physicalDisplayIds; binder::Status status = ComposerServiceAIDL::getComposerService()->getPhysicalDisplayIds(&displayIds); if (status.isOk()) { physicalDisplayIds.reserve(displayIds.size()); for (auto item : displayIds) { auto id = DisplayId::fromValue(static_cast(item)); physicalDisplayIds.push_back(*id); } } return physicalDisplayIds; } sp SurfaceComposerClient::getPhysicalDisplayToken(PhysicalDisplayId displayId) { sp display = nullptr; binder::Status status = ComposerServiceAIDL::getComposerService()->getPhysicalDisplayToken(displayId.value, &display); return status.isOk() ? display : nullptr; } std::optional SurfaceComposerClient::getStalledTransactionInfo( pid_t pid) { std::optional result; ComposerServiceAIDL::getComposerService()->getStalledTransactionInfo(pid, &result); return result; } void SurfaceComposerClient::Transaction::setAnimationTransaction() { mAnimation = true; } void SurfaceComposerClient::Transaction::setEarlyWakeupStart() { mEarlyWakeupStart = true; } void SurfaceComposerClient::Transaction::setEarlyWakeupEnd() { mEarlyWakeupEnd = true; } layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp& sc) { auto handle = sc->getLayerStateHandle(); if (mComposerStates.count(handle) == 0) { // 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[handle] = s; } return &(mComposerStates[handle].state); } void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback( const sp& sc) { auto& callbackInfo = mListenerCallbacks[TransactionCompletedListener::getIInstance()]; callbackInfo.surfaceControls.insert(sc); mTransactionCompletedListener->addSurfaceControlToCallbacks(sc, callbackInfo.callbackIds); } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPosition( const sp& sc, float x, float y) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::ePositionChanged; s->x = x; s->y = y; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::show( const sp& sc) { return setFlags(sc, 0, layer_state_t::eLayerHidden); } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::hide( const sp& sc) { return setFlags(sc, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden); } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayer( const sp& sc, int32_t z) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eLayerChanged; s->what &= ~layer_state_t::eRelativeLayerChanged; s->z = z; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setRelativeLayer( const sp& sc, const sp& relativeTo, int32_t z) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eRelativeLayerChanged; s->what &= ~layer_state_t::eLayerChanged; s->relativeLayerSurfaceControl = relativeTo; s->z = z; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFlags( const sp& sc, uint32_t flags, uint32_t mask) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eFlagsChanged; s->flags &= ~mask; s->flags |= (flags & mask); s->mask |= mask; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTransparentRegionHint( const sp& sc, const Region& transparentRegion) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eTransparentRegionChanged; s->transparentRegion = transparentRegion; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDimmingEnabled( const sp& sc, bool dimmingEnabled) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eDimmingEnabledChanged; s->dimmingEnabled = dimmingEnabled; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAlpha( const sp& sc, float alpha) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } if (alpha < 0.0f || alpha > 1.0f) { ALOGE("SurfaceComposerClient::Transaction::setAlpha: invalid alpha %f, clamping", alpha); } s->what |= layer_state_t::eAlphaChanged; s->color.a = std::clamp(alpha, 0.f, 1.f); registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLayerStack( const sp& sc, ui::LayerStack layerStack) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eLayerStackChanged; s->layerStack = layerStack; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMetadata( const sp& sc, uint32_t key, const Parcel& p) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eMetadataChanged; s->metadata.mMap[key] = {p.data(), p.data() + p.dataSize()}; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMatrix( const sp& sc, float dsdx, float dtdx, float dtdy, float dsdy) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eMatrixChanged; layer_state_t::matrix22_t matrix; matrix.dsdx = dsdx; matrix.dtdx = dtdx; matrix.dsdy = dsdy; matrix.dtdy = dtdy; s->matrix = matrix; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop( const sp& sc, const Rect& crop) { return setCrop(sc, crop.toFloatRect()); } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCrop( const sp& sc, const FloatRect& crop) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eCropChanged; s->crop = crop; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCornerRadius( const sp& sc, float cornerRadius) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eCornerRadiusChanged; s->cornerRadius = cornerRadius; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBackgroundBlurRadius( const sp& sc, int backgroundBlurRadius) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eBackgroundBlurRadiusChanged; s->backgroundBlurRadius = backgroundBlurRadius; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBlurRegions( const sp& sc, const std::vector& blurRegions) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eBlurRegionsChanged; s->blurRegions = blurRegions; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::reparent( const sp& sc, const sp& newParent) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } if (SurfaceControl::isSameSurface(sc, newParent)) { return *this; } s->what |= layer_state_t::eReparent; s->parentSurfaceControlForChild = newParent ? newParent->getParentingLayer() : nullptr; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColor( const sp& sc, const half3& color) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eColorChanged; s->color.rgb = color; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBackgroundColor( const sp& sc, const half3& color, float alpha, ui::Dataspace dataspace) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eBackgroundColorChanged; s->bgColor.rgb = color; s->bgColor.a = alpha; s->bgColorDataspace = dataspace; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTransform( const sp& sc, uint32_t transform) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eBufferTransformChanged; s->bufferTransform = transform; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTransformToDisplayInverse(const sp& sc, bool transformToDisplayInverse) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eTransformToDisplayInverseChanged; s->transformToDisplayInverse = transformToDisplayInverse; registerSurfaceControlForCallback(sc); return *this; } std::shared_ptr SurfaceComposerClient::Transaction::getAndClearBuffer( const sp& sc) { layer_state_t* s = getLayerState(sc); if (!s) { return nullptr; } if (!(s->what & layer_state_t::eBufferChanged)) { return nullptr; } std::shared_ptr bufferData = std::move(s->bufferData); mTransactionCompletedListener->removeReleaseBufferCallback( bufferData->generateReleaseCallbackId()); s->what &= ~layer_state_t::eBufferChanged; s->bufferData = nullptr; return bufferData; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBufferHasBarrier( const sp& sc, uint64_t barrierFrameNumber) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->bufferData->hasBarrier = true; s->bufferData->barrierFrameNumber = barrierFrameNumber; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBuffer( const sp& sc, const sp& buffer, const std::optional>& fence, const std::optional& optFrameNumber, uint32_t producerId, ReleaseBufferCallback callback, nsecs_t dequeueTime) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } releaseBufferIfOverwriting(*s); std::shared_ptr bufferData = std::make_shared(); bufferData->buffer = buffer; if (buffer) { uint64_t frameNumber = sc->resolveFrameNumber(optFrameNumber); bufferData->frameNumber = frameNumber; bufferData->producerId = producerId; bufferData->flags |= BufferData::BufferDataChange::frameNumberChanged; bufferData->dequeueTime = dequeueTime; if (fence) { bufferData->acquireFence = *fence; bufferData->flags |= BufferData::BufferDataChange::fenceChanged; } bufferData->releaseBufferEndpoint = IInterface::asBinder(mTransactionCompletedListener); setReleaseBufferCallback(bufferData.get(), callback); } if (mIsAutoTimestamp) { mDesiredPresentTime = systemTime(); } s->what |= layer_state_t::eBufferChanged; s->bufferData = std::move(bufferData); registerSurfaceControlForCallback(sc); // With the current infrastructure, a release callback will not be invoked if there's no // transaction callback in the case when a buffer is latched and not released early. This is // because the legacy implementation didn't have a release callback and sent releases in the // transaction callback. Because of this, we need to make sure to have a transaction callback // set up when a buffer is sent in a transaction to ensure the caller gets the release // callback, regardless if they set up a transaction callback. // // TODO (b/230380821): Remove when release callbacks are separated from transaction callbacks addTransactionCompletedCallback([](void*, nsecs_t, const sp&, const std::vector&) {}, nullptr); mMayContainBuffer = true; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::unsetBuffer( const sp& sc) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } if (!(s->what & layer_state_t::eBufferChanged)) { return *this; } releaseBufferIfOverwriting(*s); s->what &= ~layer_state_t::eBufferChanged; s->bufferData = nullptr; return *this; } void SurfaceComposerClient::Transaction::setReleaseBufferCallback(BufferData* bufferData, ReleaseBufferCallback callback) { if (!callback) { return; } if (!bufferData->buffer) { ALOGW("Transaction::setReleaseBufferCallback" "ignored trying to set a callback on a null buffer."); return; } bufferData->releaseBufferListener = static_cast>(mTransactionCompletedListener); mTransactionCompletedListener->setReleaseBufferCallback(bufferData->generateReleaseCallbackId(), callback); } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDataspace( const sp& sc, ui::Dataspace dataspace) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eDataspaceChanged; s->dataspace = dataspace; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setExtendedRangeBrightness( const sp& sc, float currentBufferRatio, float desiredRatio) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eExtendedRangeBrightnessChanged; s->currentHdrSdrRatio = currentBufferRatio; s->desiredHdrSdrRatio = desiredRatio; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesiredHdrHeadroom( const sp& sc, float desiredRatio) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eDesiredHdrHeadroomChanged; s->desiredHdrSdrRatio = desiredRatio; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLuts( const sp& sc, const base::unique_fd& lutFd, const std::vector& offsets, const std::vector& dimensions, const std::vector& sizes, const std::vector& samplingKeys) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eLutsChanged; if (lutFd.ok()) { s->luts = std::make_shared(base::unique_fd(dup(lutFd.get())), offsets, dimensions, sizes, samplingKeys); } else { s->luts = nullptr; } registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setCachingHint( const sp& sc, gui::CachingHint cachingHint) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eCachingHintChanged; s->cachingHint = cachingHint; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setHdrMetadata( const sp& sc, const HdrMetadata& hdrMetadata) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eHdrMetadataChanged; s->hdrMetadata = hdrMetadata; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSurfaceDamageRegion( const sp& sc, const Region& surfaceDamageRegion) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eSurfaceDamageRegionChanged; s->surfaceDamageRegion = surfaceDamageRegion; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApi( const sp& sc, int32_t api) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eApiChanged; s->api = api; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setSidebandStream( const sp& sc, const sp& sidebandStream) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eSidebandStreamChanged; s->sidebandStream = sidebandStream; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDesiredPresentTime( nsecs_t desiredPresentTime) { mDesiredPresentTime = desiredPresentTime; mIsAutoTimestamp = false; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorSpaceAgnostic( const sp& sc, const bool agnostic) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eColorSpaceAgnosticChanged; s->colorSpaceAgnostic = agnostic; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRateSelectionPriority(const sp& sc, int32_t priority) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eFrameRateSelectionPriority; s->frameRateSelectionPriority = priority; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTransactionCallback( TransactionCompletedCallbackTakesContext callback, void* callbackContext, CallbackId::Type callbackType) { auto callbackWithContext = std::bind(std::move(callback), callbackContext, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); const auto& surfaceControls = mListenerCallbacks[mTransactionCompletedListener].surfaceControls; CallbackId callbackId = mTransactionCompletedListener->addCallbackFunction(callbackWithContext, surfaceControls, callbackType); mListenerCallbacks[mTransactionCompletedListener].callbackIds.emplace(callbackId); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTransactionCompletedCallback( TransactionCompletedCallbackTakesContext callback, void* callbackContext) { return addTransactionCallback(std::move(callback), callbackContext, CallbackId::Type::ON_COMPLETE); } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addTransactionCommittedCallback( TransactionCompletedCallbackTakesContext callback, void* callbackContext) { return addTransactionCallback(std::move(callback), callbackContext, CallbackId::Type::ON_COMMIT); } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::notifyProducerDisconnect( const sp& sc) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eProducerDisconnect; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo( const sp& sc, sp info) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->windowInfoHandle = std::move(info); s->what |= layer_state_t::eInputInfoChanged; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFocusedWindow( const FocusRequest& request) { mInputWindowCommands.focusRequests.push_back(request); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::addWindowInfosReportedListener( sp windowInfosReportedListener) { mInputWindowCommands.windowInfosReportedListeners.insert(windowInfosReportedListener); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setColorTransform( const sp& sc, const mat3& matrix, const vec3& translation) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eColorTransformChanged; s->colorTransform = mat4(matrix, translation); registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometry( const sp& sc, const Rect& source, const Rect& dst, int transform) { setCrop(sc, source); int x = dst.left; int y = dst.top; float sourceWidth = source.getWidth(); float sourceHeight = source.getHeight(); float xScale = sourceWidth < 0 ? 1.0f : dst.getWidth() / sourceWidth; float yScale = sourceHeight < 0 ? 1.0f : dst.getHeight() / sourceHeight; float matrix[4] = {1, 0, 0, 1}; switch (transform) { case NATIVE_WINDOW_TRANSFORM_FLIP_H: matrix[0] = -xScale; matrix[1] = 0; matrix[2] = 0; matrix[3] = yScale; x += source.getWidth(); break; case NATIVE_WINDOW_TRANSFORM_FLIP_V: matrix[0] = xScale; matrix[1] = 0; matrix[2] = 0; matrix[3] = -yScale; y += source.getHeight(); break; case NATIVE_WINDOW_TRANSFORM_ROT_90: matrix[0] = 0; matrix[1] = -yScale; matrix[2] = xScale; matrix[3] = 0; x += source.getHeight(); break; case NATIVE_WINDOW_TRANSFORM_ROT_180: matrix[0] = -xScale; matrix[1] = 0; matrix[2] = 0; matrix[3] = -yScale; x += source.getWidth(); y += source.getHeight(); break; case NATIVE_WINDOW_TRANSFORM_ROT_270: matrix[0] = 0; matrix[1] = yScale; matrix[2] = -xScale; matrix[3] = 0; y += source.getWidth(); break; default: matrix[0] = xScale; matrix[1] = 0; matrix[2] = 0; matrix[3] = yScale; break; } setMatrix(sc, matrix[0], matrix[1], matrix[2], matrix[3]); float offsetX = xScale * source.left; float offsetY = yScale * source.top; setPosition(sc, x - offsetX, y - offsetY); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setShadowRadius( const sp& sc, float shadowRadius) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eShadowRadiusChanged; s->shadowRadius = shadowRadius; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRate( const sp& sc, float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } // Allow privileged values as well here, those will be ignored by SF if // the caller is not privileged if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, "Transaction::setFrameRate", /*privileged=*/true)) { mStatus = BAD_VALUE; return *this; } s->what |= layer_state_t::eFrameRateChanged; s->frameRate = frameRate; s->frameRateCompatibility = compatibility; s->changeFrameRateStrategy = changeFrameRateStrategy; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDefaultFrameRateCompatibility(const sp& sc, int8_t compatibility) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eDefaultFrameRateCompatibilityChanged; s->defaultFrameRateCompatibility = compatibility; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRateCategory( const sp& sc, int8_t category, bool smoothSwitchOnly) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eFrameRateCategoryChanged; s->frameRateCategory = category; s->frameRateCategorySmoothSwitchOnly = smoothSwitchOnly; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameRateSelectionStrategy(const sp& sc, int8_t strategy) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eFrameRateSelectionStrategyChanged; s->frameRateSelectionStrategy = strategy; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixedTransformHint( const sp& sc, int32_t fixedTransformHint) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } const ui::Transform::RotationFlags transform = fixedTransformHint == -1 ? ui::Transform::ROT_INVALID : ui::Transform::toRotationFlags(static_cast(fixedTransformHint)); s->what |= layer_state_t::eFixedTransformHintChanged; s->fixedTransformHint = transform; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo( const FrameTimelineInfo& frameTimelineInfo) { mergeFrameTimelineInfo(mFrameTimelineInfo, frameTimelineInfo); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setAutoRefresh( const sp& sc, bool autoRefresh) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eAutoRefreshChanged; s->autoRefresh = autoRefresh; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTrustedOverlay( const sp& sc, bool isTrustedOverlay) { return setTrustedOverlay(sc, isTrustedOverlay ? gui::TrustedOverlay::ENABLED : gui::TrustedOverlay::UNSET); } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setTrustedOverlay( const sp& sc, gui::TrustedOverlay trustedOverlay) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eTrustedOverlayChanged; s->trustedOverlay = trustedOverlay; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setApplyToken( const sp& applyToken) { mApplyToken = applyToken; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setStretchEffect( const sp& sc, const StretchEffect& stretchEffect) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eStretchChanged; s->stretchEffect = stretchEffect; return *this; } bool SurfaceComposerClient::flagEdgeExtensionEffectUseShader() { return com::android::graphics::libgui::flags::edge_extension_shader(); } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setEdgeExtensionEffect( const sp& sc, const gui::EdgeExtensionParameters& effect) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eEdgeExtensionChanged; s->edgeExtensionParameters = effect; return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBufferCrop( const sp& sc, const Rect& bufferCrop) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eBufferCropChanged; s->bufferCrop = bufferCrop; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDestinationFrame( const sp& sc, const Rect& destinationFrame) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eDestinationFrameChanged; s->destinationFrame = destinationFrame; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDropInputMode( const sp& sc, gui::DropInputMode mode) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eDropInputModeChanged; s->dropInputMode = mode; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBufferReleaseChannel( const sp& sc, const std::shared_ptr& channel) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eBufferReleaseChannelChanged; s->bufferReleaseChannel = channel; registerSurfaceControlForCallback(sc); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setPictureProfileHandle( const sp& sc, const PictureProfileHandle& pictureProfileHandle) { if (com_android_graphics_libgui_flags_apply_picture_profiles()) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::ePictureProfileHandleChanged; s->pictureProfileHandle = pictureProfileHandle; registerSurfaceControlForCallback(sc); } return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setContentPriority( const sp& sc, int32_t priority) { if (com_android_graphics_libgui_flags_apply_picture_profiles()) { layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eAppContentPriorityChanged; s->appContentPriority = priority; registerSurfaceControlForCallback(sc); } return *this; } // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp& token) { DisplayState s; s.token = token; ssize_t index = mDisplayStates.indexOf(s); if (index < 0) { // we don't have it, add an initialized layer_state to our list s.what = 0; index = mDisplayStates.add(s); } return mDisplayStates.editItemAt(static_cast(index)); } status_t SurfaceComposerClient::Transaction::setDisplaySurface(const sp& token, const sp& bufferProducer) { if (bufferProducer.get() != nullptr) { // Make sure that composition can never be stalled by a virtual display // consumer that isn't processing buffers fast enough. status_t err = bufferProducer->setAsyncMode(true); if (err != NO_ERROR) { ALOGE("Composer::setDisplaySurface Failed to enable async mode on the " "BufferQueue. This BufferQueue cannot be used for virtual " "display. (%d)", err); return err; } } DisplayState& s(getDisplayState(token)); s.surface = bufferProducer; s.what |= DisplayState::eSurfaceChanged; return NO_ERROR; } void SurfaceComposerClient::Transaction::setDisplayLayerStack(const sp& token, ui::LayerStack layerStack) { DisplayState& s(getDisplayState(token)); s.layerStack = layerStack; s.what |= DisplayState::eLayerStackChanged; } void SurfaceComposerClient::Transaction::setDisplayFlags(const sp& token, uint32_t flags) { DisplayState& s(getDisplayState(token)); s.flags = flags; s.what |= DisplayState::eFlagsChanged; } void SurfaceComposerClient::Transaction::setDisplayProjection(const sp& token, ui::Rotation orientation, const Rect& layerStackRect, const Rect& displayRect) { DisplayState& s(getDisplayState(token)); s.orientation = orientation; s.layerStackSpaceRect = layerStackRect; s.orientedDisplaySpaceRect = displayRect; s.what |= DisplayState::eDisplayProjectionChanged; } void SurfaceComposerClient::Transaction::setDisplaySize(const sp& token, uint32_t width, uint32_t height) { DisplayState& s(getDisplayState(token)); s.width = width; s.height = height; 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& sc, TrustedPresentationCallback cb, const TrustedPresentationThresholds& thresholds, void* context, sp& outCallbackRef) { outCallbackRef = mTransactionCompletedListener->addTrustedPresentationCallback(cb, sc->getLayerId(), context); layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eTrustedPresentationInfoChanged; s->trustedPresentationThresholds = thresholds; s->trustedPresentationListener.callbackInterface = TransactionCompletedListener::getIInstance(); s->trustedPresentationListener.callbackId = sc->getLayerId(); return *this; } SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::clearTrustedPresentationCallback(const sp& sc) { mTransactionCompletedListener->clearTrustedPresentationCallback(sc->getLayerId()); layer_state_t* s = getLayerState(sc); if (!s) { mStatus = BAD_INDEX; return *this; } s->what |= layer_state_t::eTrustedPresentationInfoChanged; s->trustedPresentationThresholds = TrustedPresentationThresholds(); s->trustedPresentationListener.callbackInterface = nullptr; s->trustedPresentationListener.callbackId = -1; return *this; } // --------------------------------------------------------------------------- SurfaceComposerClient::SurfaceComposerClient() : mStatus(NO_INIT) {} SurfaceComposerClient::SurfaceComposerClient(const sp& client) : mStatus(NO_ERROR), mClient(client) {} void SurfaceComposerClient::onFirstRef() { sp sf(ComposerServiceAIDL::getComposerService()); if (sf != nullptr && mStatus == NO_INIT) { sp conn; binder::Status status = sf->createConnection(&conn); if (status.isOk() && conn != nullptr) { mClient = conn; mStatus = NO_ERROR; } } } SurfaceComposerClient::~SurfaceComposerClient() { dispose(); } status_t SurfaceComposerClient::initCheck() const { return mStatus; } sp SurfaceComposerClient::connection() const { return IInterface::asBinder(mClient); } status_t SurfaceComposerClient::linkToComposerDeath( const sp& recipient, void* cookie, uint32_t flags) { sp sf(ComposerService::getComposerService()); return IInterface::asBinder(sf)->linkToDeath(recipient, cookie, flags); } void SurfaceComposerClient::dispose() { // this can be called more than once. sp client; Mutex::Autolock _lm(mLock); if (mClient != nullptr) { client = mClient; // hold ref while lock is held mClient.clear(); } mStatus = NO_INIT; } status_t SurfaceComposerClient::bootFinished() { sp sf(ComposerServiceAIDL::getComposerService()); binder::Status status = sf->bootFinished(); return statusTFromBinderStatus(status); } sp SurfaceComposerClient::createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, int32_t flags, const sp& parentHandle, LayerMetadata metadata, uint32_t* outTransformHint) { sp s; createSurfaceChecked(name, w, h, format, &s, flags, parentHandle, std::move(metadata), outTransformHint); return s; } static std::string toString(const String16& string) { return std::string(String8(string).c_str()); } status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h, PixelFormat format, sp* outSurface, int32_t flags, const sp& parentHandle, LayerMetadata metadata, uint32_t* outTransformHint) { status_t err = mStatus; if (mStatus == NO_ERROR) { gui::CreateSurfaceResult result; binder::Status status = mClient->createSurface(std::string(name.c_str()), flags, parentHandle, std::move(metadata), &result); err = statusTFromBinderStatus(status); if (outTransformHint) { *outTransformHint = result.transformHint; } ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err)); if (err == NO_ERROR) { *outSurface = new SurfaceControl(this, result.handle, result.layerId, toString(result.layerName), w, h, format, result.transformHint, flags); } } return err; } sp SurfaceComposerClient::mirrorSurface(SurfaceControl* mirrorFromSurface) { if (mirrorFromSurface == nullptr) { return nullptr; } sp mirrorFromHandle = mirrorFromSurface->getHandle(); gui::CreateSurfaceResult result; const binder::Status status = mClient->mirrorSurface(mirrorFromHandle, &result); const status_t err = statusTFromBinderStatus(status); if (err == NO_ERROR) { return new SurfaceControl(this, result.handle, result.layerId, toString(result.layerName)); } return nullptr; } sp SurfaceComposerClient::mirrorDisplay(DisplayId displayId) { gui::CreateSurfaceResult result; const binder::Status status = mClient->mirrorDisplay(displayId.value, &result); const status_t err = statusTFromBinderStatus(status); if (err == NO_ERROR) { return new SurfaceControl(this, result.handle, result.layerId, toString(result.layerName)); } return nullptr; } status_t SurfaceComposerClient::clearLayerFrameStats(const sp& token) const { if (mStatus != NO_ERROR) { return mStatus; } const binder::Status status = mClient->clearLayerFrameStats(token); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getLayerFrameStats(const sp& token, FrameStats* outStats) const { if (mStatus != NO_ERROR) { return mStatus; } gui::FrameStats stats; const binder::Status status = mClient->getLayerFrameStats(token, &stats); if (status.isOk()) { outStats->refreshPeriodNano = stats.refreshPeriodNano; outStats->desiredPresentTimesNano.setCapacity(stats.desiredPresentTimesNano.size()); for (const auto& t : stats.desiredPresentTimesNano) { outStats->desiredPresentTimesNano.add(t); } outStats->actualPresentTimesNano.setCapacity(stats.actualPresentTimesNano.size()); for (const auto& t : stats.actualPresentTimesNano) { outStats->actualPresentTimesNano.add(t); } outStats->frameReadyTimesNano.setCapacity(stats.frameReadyTimesNano.size()); for (const auto& t : stats.frameReadyTimesNano) { outStats->frameReadyTimesNano.add(t); } } return statusTFromBinderStatus(status); } // ---------------------------------------------------------------------------- status_t SurfaceComposerClient::getDisplayState(const sp& display, ui::DisplayState* state) { gui::DisplayState ds; binder::Status status = ComposerServiceAIDL::getComposerService()->getDisplayState(display, &ds); if (status.isOk()) { state->layerStack = ui::LayerStack::fromValue(ds.layerStack); state->orientation = static_cast(ds.orientation); state->layerStackSpaceRect = ui::Size(ds.layerStackSpaceRect.width, ds.layerStackSpaceRect.height); } return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getStaticDisplayInfo(int64_t displayId, ui::StaticDisplayInfo* outInfo) { using Tag = android::gui::DeviceProductInfo::ManufactureOrModelDate::Tag; gui::StaticDisplayInfo ginfo; binder::Status status = ComposerServiceAIDL::getComposerService()->getStaticDisplayInfo(displayId, &ginfo); if (status.isOk()) { // convert gui::StaticDisplayInfo to ui::StaticDisplayInfo outInfo->connectionType = static_cast(ginfo.connectionType); outInfo->density = ginfo.density; outInfo->secure = ginfo.secure; outInfo->installOrientation = static_cast(ginfo.installOrientation); if (const std::optional dpi = ginfo.deviceProductInfo) { DeviceProductInfo info; info.name = dpi->name; if (dpi->manufacturerPnpId.size() > 0) { // copid from PnpId = std::array in ui/DeviceProductInfo.h constexpr int kMaxPnpIdSize = 4; size_t count = std::max(kMaxPnpIdSize, dpi->manufacturerPnpId.size()); std::copy_n(dpi->manufacturerPnpId.begin(), count, info.manufacturerPnpId.begin()); } if (dpi->relativeAddress.size() > 0) { std::copy(dpi->relativeAddress.begin(), dpi->relativeAddress.end(), std::back_inserter(info.relativeAddress)); } info.productId = dpi->productId; const gui::DeviceProductInfo::ManufactureOrModelDate& date = dpi->manufactureOrModelDate; if (date.getTag() == Tag::modelYear) { DeviceProductInfo::ModelYear modelYear; modelYear.year = static_cast(date.get().year); info.manufactureOrModelDate = modelYear; } else if (date.getTag() == Tag::manufactureYear) { DeviceProductInfo::ManufactureYear manufactureYear; manufactureYear.year = date.get().modelYear.year; info.manufactureOrModelDate = manufactureYear; } else if (date.getTag() == Tag::manufactureWeekAndYear) { DeviceProductInfo::ManufactureWeekAndYear weekAndYear; weekAndYear.year = date.get().manufactureYear.modelYear.year; weekAndYear.week = date.get().week; info.manufactureOrModelDate = weekAndYear; } outInfo->deviceProductInfo = info; } } return statusTFromBinderStatus(status); } void SurfaceComposerClient::getDynamicDisplayInfoInternal(gui::DynamicDisplayInfo& ginfo, ui::DynamicDisplayInfo*& outInfo) { // convert gui::DynamicDisplayInfo to ui::DynamicDisplayInfo outInfo->supportedDisplayModes.clear(); outInfo->supportedDisplayModes.reserve(ginfo.supportedDisplayModes.size()); for (const auto& mode : ginfo.supportedDisplayModes) { ui::DisplayMode outMode; outMode.id = mode.id; outMode.resolution.width = mode.resolution.width; outMode.resolution.height = mode.resolution.height; outMode.xDpi = mode.xDpi; outMode.yDpi = mode.yDpi; outMode.peakRefreshRate = mode.peakRefreshRate; outMode.vsyncRate = mode.vsyncRate; outMode.appVsyncOffset = mode.appVsyncOffset; outMode.sfVsyncOffset = mode.sfVsyncOffset; outMode.presentationDeadline = mode.presentationDeadline; outMode.group = mode.group; std::transform(mode.supportedHdrTypes.begin(), mode.supportedHdrTypes.end(), std::back_inserter(outMode.supportedHdrTypes), [](const int32_t& value) { return static_cast(value); }); outInfo->supportedDisplayModes.push_back(outMode); } outInfo->activeDisplayModeId = ginfo.activeDisplayModeId; outInfo->renderFrameRate = ginfo.renderFrameRate; outInfo->supportedColorModes.clear(); outInfo->supportedColorModes.reserve(ginfo.supportedColorModes.size()); for (const auto& cmode : ginfo.supportedColorModes) { outInfo->supportedColorModes.push_back(static_cast(cmode)); } outInfo->activeColorMode = static_cast(ginfo.activeColorMode); std::vector types; types.reserve(ginfo.hdrCapabilities.supportedHdrTypes.size()); for (const auto& hdr : ginfo.hdrCapabilities.supportedHdrTypes) { types.push_back(static_cast(hdr)); } outInfo->hdrCapabilities = HdrCapabilities(types, ginfo.hdrCapabilities.maxLuminance, ginfo.hdrCapabilities.maxAverageLuminance, ginfo.hdrCapabilities.minLuminance); outInfo->autoLowLatencyModeSupported = ginfo.autoLowLatencyModeSupported; outInfo->gameContentTypeSupported = ginfo.gameContentTypeSupported; outInfo->preferredBootDisplayMode = ginfo.preferredBootDisplayMode; outInfo->hasArrSupport = ginfo.hasArrSupport; outInfo->frameRateCategoryRate = ui::FrameRateCategoryRate(ginfo.frameRateCategoryRate.normal, ginfo.frameRateCategoryRate.high); outInfo->supportedRefreshRates.clear(); outInfo->supportedRefreshRates.reserve(ginfo.supportedRefreshRates.size()); for (const auto rate : ginfo.supportedRefreshRates) { outInfo->supportedRefreshRates.push_back(static_cast(rate)); } } status_t SurfaceComposerClient::getDynamicDisplayInfoFromId(int64_t displayId, ui::DynamicDisplayInfo* outInfo) { gui::DynamicDisplayInfo ginfo; binder::Status status = ComposerServiceAIDL::getComposerService()->getDynamicDisplayInfoFromId(displayId, &ginfo); if (status.isOk()) { getDynamicDisplayInfoInternal(ginfo, outInfo); } return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDynamicDisplayInfoFromToken(const sp& display, ui::DynamicDisplayInfo* outInfo) { gui::DynamicDisplayInfo ginfo; binder::Status status = ComposerServiceAIDL::getComposerService()->getDynamicDisplayInfoFromToken(display, &ginfo); if (status.isOk()) { getDynamicDisplayInfoInternal(ginfo, outInfo); } return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getActiveDisplayMode(const sp& display, ui::DisplayMode* mode) { ui::DynamicDisplayInfo info; status_t result = getDynamicDisplayInfoFromToken(display, &info); if (result != NO_ERROR) { return result; } if (const auto activeMode = info.getActiveDisplayMode()) { *mode = *activeMode; return NO_ERROR; } ALOGE("Active display mode not found."); return NAME_NOT_FOUND; } status_t SurfaceComposerClient::setDesiredDisplayModeSpecs(const sp& displayToken, const gui::DisplayModeSpecs& specs) { binder::Status status = ComposerServiceAIDL::getComposerService()->setDesiredDisplayModeSpecs(displayToken, specs); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDesiredDisplayModeSpecs(const sp& displayToken, gui::DisplayModeSpecs* outSpecs) { if (!outSpecs) { return BAD_VALUE; } binder::Status status = ComposerServiceAIDL::getComposerService()->getDesiredDisplayModeSpecs(displayToken, outSpecs); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDisplayNativePrimaries(const sp& display, ui::DisplayPrimaries& outPrimaries) { gui::DisplayPrimaries primaries; binder::Status status = ComposerServiceAIDL::getComposerService()->getDisplayNativePrimaries(display, &primaries); if (status.isOk()) { outPrimaries.red.X = primaries.red.X; outPrimaries.red.Y = primaries.red.Y; outPrimaries.red.Z = primaries.red.Z; outPrimaries.green.X = primaries.green.X; outPrimaries.green.Y = primaries.green.Y; outPrimaries.green.Z = primaries.green.Z; outPrimaries.blue.X = primaries.blue.X; outPrimaries.blue.Y = primaries.blue.Y; outPrimaries.blue.Z = primaries.blue.Z; outPrimaries.white.X = primaries.white.X; outPrimaries.white.Y = primaries.white.Y; outPrimaries.white.Z = primaries.white.Z; } return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setActiveColorMode(const sp& display, ColorMode colorMode) { binder::Status status = ComposerServiceAIDL::getComposerService() ->setActiveColorMode(display, static_cast(colorMode)); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getBootDisplayModeSupport(bool* support) { binder::Status status = ComposerServiceAIDL::getComposerService()->getBootDisplayModeSupport(support); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getOverlaySupport(gui::OverlayProperties* outProperties) { binder::Status status = ComposerServiceAIDL::getComposerService()->getOverlaySupport(outProperties); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setBootDisplayMode(const sp& display, ui::DisplayModeId displayModeId) { binder::Status status = ComposerServiceAIDL::getComposerService() ->setBootDisplayMode(display, static_cast(displayModeId)); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::clearBootDisplayMode(const sp& display) { binder::Status status = ComposerServiceAIDL::getComposerService()->clearBootDisplayMode(display); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getHdrConversionCapabilities( std::vector* hdrConversionCapabilities) { binder::Status status = ComposerServiceAIDL::getComposerService()->getHdrConversionCapabilities( hdrConversionCapabilities); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setHdrConversionStrategy( gui::HdrConversionStrategy hdrConversionStrategy, ui::Hdr* outPreferredHdrOutputType) { int hdrType; binder::Status status = ComposerServiceAIDL::getComposerService() ->setHdrConversionStrategy(hdrConversionStrategy, &hdrType); *outPreferredHdrOutputType = static_cast(hdrType); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getHdrOutputConversionSupport(bool* isSupported) { binder::Status status = ComposerServiceAIDL::getComposerService()->getHdrOutputConversionSupport(isSupported); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setGameModeFrameRateOverride(uid_t uid, float frameRate) { binder::Status status = ComposerServiceAIDL::getComposerService()->setGameModeFrameRateOverride(uid, frameRate); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setGameDefaultFrameRateOverride(uid_t uid, float frameRate) { binder::Status status = ComposerServiceAIDL::getComposerService()->setGameDefaultFrameRateOverride(uid, frameRate); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::updateSmallAreaDetection(std::vector& appIds, std::vector& thresholds) { binder::Status status = ComposerServiceAIDL::getComposerService()->updateSmallAreaDetection(appIds, thresholds); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setSmallAreaDetectionThreshold(int32_t appId, float threshold) { binder::Status status = ComposerServiceAIDL::getComposerService()->setSmallAreaDetectionThreshold(appId, threshold); return statusTFromBinderStatus(status); } void SurfaceComposerClient::setAutoLowLatencyMode(const sp& display, bool on) { ComposerServiceAIDL::getComposerService()->setAutoLowLatencyMode(display, on); } void SurfaceComposerClient::setGameContentType(const sp& display, bool on) { ComposerServiceAIDL::getComposerService()->setGameContentType(display, on); } void SurfaceComposerClient::setDisplayPowerMode(const sp& token, int mode) { ComposerServiceAIDL::getComposerService()->setPowerMode(token, mode); } status_t SurfaceComposerClient::getMaxLayerPictureProfiles(const sp& token, int32_t* outMaxProfiles) { binder::Status status = ComposerServiceAIDL::getComposerService()->getMaxLayerPictureProfiles(token, outMaxProfiles); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getCompositionPreference( ui::Dataspace* defaultDataspace, ui::PixelFormat* defaultPixelFormat, ui::Dataspace* wideColorGamutDataspace, ui::PixelFormat* wideColorGamutPixelFormat) { gui::CompositionPreference pref; binder::Status status = ComposerServiceAIDL::getComposerService()->getCompositionPreference(&pref); if (status.isOk()) { *defaultDataspace = static_cast(pref.defaultDataspace); *defaultPixelFormat = static_cast(pref.defaultPixelFormat); *wideColorGamutDataspace = static_cast(pref.wideColorGamutDataspace); *wideColorGamutPixelFormat = static_cast(pref.wideColorGamutPixelFormat); } return statusTFromBinderStatus(status); } bool SurfaceComposerClient::getProtectedContentSupport() { bool supported = false; ComposerServiceAIDL::getComposerService()->getProtectedContentSupport(&supported); return supported; } status_t SurfaceComposerClient::clearAnimationFrameStats() { binder::Status status = ComposerServiceAIDL::getComposerService()->clearAnimationFrameStats(); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getAnimationFrameStats(FrameStats* outStats) { gui::FrameStats stats; binder::Status status = ComposerServiceAIDL::getComposerService()->getAnimationFrameStats(&stats); if (status.isOk()) { outStats->refreshPeriodNano = stats.refreshPeriodNano; outStats->desiredPresentTimesNano.setCapacity(stats.desiredPresentTimesNano.size()); for (const auto& t : stats.desiredPresentTimesNano) { outStats->desiredPresentTimesNano.add(t); } outStats->actualPresentTimesNano.setCapacity(stats.actualPresentTimesNano.size()); for (const auto& t : stats.actualPresentTimesNano) { outStats->actualPresentTimesNano.add(t); } outStats->frameReadyTimesNano.setCapacity(stats.frameReadyTimesNano.size()); for (const auto& t : stats.frameReadyTimesNano) { outStats->frameReadyTimesNano.add(t); } } return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::overrideHdrTypes(const sp& display, const std::vector& hdrTypes) { std::vector hdrTypesVector; hdrTypesVector.reserve(hdrTypes.size()); for (auto t : hdrTypes) { hdrTypesVector.push_back(static_cast(t)); } binder::Status status = ComposerServiceAIDL::getComposerService()->overrideHdrTypes(display, hdrTypesVector); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::onPullAtom(const int32_t atomId, std::string* outData, bool* success) { gui::PullAtomData pad; binder::Status status = ComposerServiceAIDL::getComposerService()->onPullAtom(atomId, &pad); if (status.isOk()) { outData->assign(pad.data.begin(), pad.data.end()); *success = pad.success; } return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp& display, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, uint8_t* outComponentMask) { if (!outFormat || !outDataspace || !outComponentMask) { return BAD_VALUE; } gui::ContentSamplingAttributes attrs; binder::Status status = ComposerServiceAIDL::getComposerService() ->getDisplayedContentSamplingAttributes(display, &attrs); if (status.isOk()) { *outFormat = static_cast(attrs.format); *outDataspace = static_cast(attrs.dataspace); *outComponentMask = static_cast(attrs.componentMask); } return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setDisplayContentSamplingEnabled(const sp& display, bool enable, uint8_t componentMask, uint64_t maxFrames) { binder::Status status = ComposerServiceAIDL::getComposerService() ->setDisplayContentSamplingEnabled(display, enable, static_cast(componentMask), static_cast(maxFrames)); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDisplayedContentSample(const sp& display, uint64_t maxFrames, uint64_t timestamp, DisplayedFrameStats* outStats) { if (!outStats) { return BAD_VALUE; } gui::DisplayedFrameStats stats; binder::Status status = ComposerServiceAIDL::getComposerService()->getDisplayedContentSample(display, maxFrames, timestamp, &stats); if (status.isOk()) { // convert gui::DisplayedFrameStats to ui::DisplayedFrameStats outStats->numFrames = static_cast(stats.numFrames); outStats->component_0_sample.reserve(stats.component_0_sample.size()); for (const auto& s : stats.component_0_sample) { outStats->component_0_sample.push_back(static_cast(s)); } outStats->component_1_sample.reserve(stats.component_1_sample.size()); for (const auto& s : stats.component_1_sample) { outStats->component_1_sample.push_back(static_cast(s)); } outStats->component_2_sample.reserve(stats.component_2_sample.size()); for (const auto& s : stats.component_2_sample) { outStats->component_2_sample.push_back(static_cast(s)); } outStats->component_3_sample.reserve(stats.component_3_sample.size()); for (const auto& s : stats.component_3_sample) { outStats->component_3_sample.push_back(static_cast(s)); } } return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::isWideColorDisplay(const sp& display, bool* outIsWideColorDisplay) { binder::Status status = ComposerServiceAIDL::getComposerService()->isWideColorDisplay(display, outIsWideColorDisplay); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::addRegionSamplingListener( const Rect& samplingArea, const sp& stopLayerHandle, const sp& listener) { gui::ARect rect; rect.left = samplingArea.left; rect.top = samplingArea.top; rect.right = samplingArea.right; rect.bottom = samplingArea.bottom; binder::Status status = ComposerServiceAIDL::getComposerService()->addRegionSamplingListener(rect, stopLayerHandle, listener); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::removeRegionSamplingListener( const sp& listener) { binder::Status status = ComposerServiceAIDL::getComposerService()->removeRegionSamplingListener(listener); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::addFpsListener(int32_t taskId, const sp& listener) { binder::Status status = ComposerServiceAIDL::getComposerService()->addFpsListener(taskId, listener); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::removeFpsListener(const sp& listener) { binder::Status status = ComposerServiceAIDL::getComposerService()->removeFpsListener(listener); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::addTunnelModeEnabledListener( const sp& listener) { binder::Status status = ComposerServiceAIDL::getComposerService()->addTunnelModeEnabledListener(listener); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::removeTunnelModeEnabledListener( const sp& listener) { binder::Status status = ComposerServiceAIDL::getComposerService()->removeTunnelModeEnabledListener(listener); return statusTFromBinderStatus(status); } bool SurfaceComposerClient::getDisplayBrightnessSupport(const sp& displayToken) { bool support = false; binder::Status status = ComposerServiceAIDL::getComposerService()->getDisplayBrightnessSupport(displayToken, &support); return status.isOk() ? support : false; } status_t SurfaceComposerClient::setDisplayBrightness(const sp& displayToken, const gui::DisplayBrightness& brightness) { binder::Status status = ComposerServiceAIDL::getComposerService()->setDisplayBrightness(displayToken, brightness); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::addHdrLayerInfoListener( const sp& displayToken, const sp& listener) { binder::Status status = ComposerServiceAIDL::getComposerService()->addHdrLayerInfoListener(displayToken, listener); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::removeHdrLayerInfoListener( const sp& displayToken, const sp& listener) { binder::Status status = ComposerServiceAIDL::getComposerService()->removeHdrLayerInfoListener(displayToken, listener); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setActivePictureListener( const sp& listener) { binder::Status status = ComposerServiceAIDL::getComposerService()->setActivePictureListener(listener); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::notifyPowerBoost(int32_t boostId) { binder::Status status = ComposerServiceAIDL::getComposerService()->notifyPowerBoost(boostId); return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) { gui::Color ambientColorG, spotColorG; ambientColorG.r = ambientColor.r; ambientColorG.g = ambientColor.g; ambientColorG.b = ambientColor.b; ambientColorG.a = ambientColor.a; spotColorG.r = spotColor.r; spotColorG.g = spotColor.g; spotColorG.b = spotColor.b; spotColorG.a = spotColor.a; binder::Status status = ComposerServiceAIDL::getComposerService()->setGlobalShadowSettings(ambientColorG, spotColorG, lightPosY, lightPosZ, lightRadius); return statusTFromBinderStatus(status); } std::optional SurfaceComposerClient::getDisplayDecorationSupport( const sp& displayToken) { std::optional gsupport; binder::Status status = ComposerServiceAIDL::getComposerService()->getDisplayDecorationSupport(displayToken, &gsupport); std::optional support; if (status.isOk() && gsupport.has_value()) { support.emplace(DisplayDecorationSupport{ .format = static_cast( gsupport->format), .alphaInterpretation = static_cast( gsupport->alphaInterpretation) }); } return support; } int SurfaceComposerClient::getGpuContextPriority() { int priority; binder::Status status = ComposerServiceAIDL::getComposerService()->getGpuContextPriority(&priority); if (!status.isOk()) { status_t err = statusTFromBinderStatus(status); ALOGE("getGpuContextPriority failed to read data: %s (%d)", strerror(-err), err); return 0; } return priority; } status_t SurfaceComposerClient::addWindowInfosListener( const sp& windowInfosListener, std::pair, std::vector>* outInitialInfo) { return WindowInfosListenerReporter::getInstance() ->addWindowInfosListener(windowInfosListener, ComposerServiceAIDL::getComposerService(), outInitialInfo); } status_t SurfaceComposerClient::removeWindowInfosListener( const sp& windowInfosListener) { return WindowInfosListenerReporter::getInstance() ->removeWindowInfosListener(windowInfosListener, ComposerServiceAIDL::getComposerService()); } void SurfaceComposerClient::notifyShutdown() { ComposerServiceAIDL::getComposerService()->notifyShutdown(); } // ---------------------------------------------------------------------------- status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs, const sp& captureListener) { sp s(ComposerServiceAIDL::getComposerService()); if (s == nullptr) return NO_INIT; binder::Status status = s->captureDisplay(captureArgs, captureListener); return statusTFromBinderStatus(status); } status_t ScreenshotClient::captureDisplay(DisplayId displayId, const gui::CaptureArgs& captureArgs, const sp& captureListener) { sp s(ComposerServiceAIDL::getComposerService()); if (s == nullptr) return NO_INIT; binder::Status status = s->captureDisplayById(displayId.value, captureArgs, captureListener); return statusTFromBinderStatus(status); } status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs, const sp& captureListener, bool sync) { sp s(ComposerServiceAIDL::getComposerService()); if (s == nullptr) return NO_INIT; binder::Status status; if (sync) { gui::ScreenCaptureResults captureResults; status = s->captureLayersSync(captureArgs, &captureResults); captureListener->onScreenCaptureCompleted(captureResults); } else { status = s->captureLayers(captureArgs, captureListener); } return statusTFromBinderStatus(status); } // --------------------------------------------------------------------------------- void ReleaseCallbackThread::addReleaseCallback(const ReleaseCallbackId callbackId, sp releaseFence) { std::scoped_lock lock(mMutex); if (!mStarted) { mThread = std::thread(&ReleaseCallbackThread::threadMain, this); mStarted = true; } mCallbackInfos.emplace(callbackId, std::move(releaseFence)); mReleaseCallbackPending.notify_one(); } void ReleaseCallbackThread::threadMain() { const auto listener = TransactionCompletedListener::getInstance(); std::queue>> callbackInfos; while (true) { { std::unique_lock lock(mMutex); base::ScopedLockAssertion assumeLocked(mMutex); callbackInfos = std::move(mCallbackInfos); mCallbackInfos = {}; } while (!callbackInfos.empty()) { auto [callbackId, releaseFence] = callbackInfos.front(); listener->onReleaseBuffer(callbackId, std::move(releaseFence), UINT_MAX); callbackInfos.pop(); } { std::unique_lock lock(mMutex); base::ScopedLockAssertion assumeLocked(mMutex); if (mCallbackInfos.size() == 0) { mReleaseCallbackPending.wait(lock); } } } } } // namespace android