diff options
115 files changed, 2507 insertions, 1085 deletions
@@ -1,3 +1,3 @@ -third_party { + third_party { license_type: NOTICE } diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp index 809872417d..6e2abf65e2 100644 --- a/cmds/servicemanager/Access.cpp +++ b/cmds/servicemanager/Access.cpp @@ -34,7 +34,9 @@ constexpr bool kIsVendor = false; #ifdef __ANDROID__ static std::string getPidcon(pid_t pid) { - android_errorWriteLog(0x534e4554, "121035042"); + CHECK_EQ(nullptr, IPCThreadState::self()->getServingStackPointer()) + << "Did not get context from PID " << pid + << ". We should always get contexts from other processes."; char* lookup = nullptr; if (getpidcon(pid, &lookup) < 0) { diff --git a/include/android/looper.h b/include/android/looper.h index 8cf13965bb..409db848f8 100644 --- a/include/android/looper.h +++ b/include/android/looper.h @@ -106,7 +106,7 @@ enum { /** * Result from ALooper_pollOnce() and ALooper_pollAll(): * An error occurred. The poll may also have been explicitly woken by - * ALooper_wake(()). + * ALooper_wake(). */ ALOOPER_POLL_ERROR = -4, }; @@ -224,11 +224,11 @@ int ALooper_pollOnce(int timeoutMillis, int* outFd, int* outEvents, void** outDa * hidden and callers should migrate to ALooper_pollOnce. Binary compatibility * is preserved to support already-compiled apps. * - * \bug ALooper_pollAll will not wake in response to ALooper_wake calls if it + * \bug ALooper_pollAll() will not wake in response to ALooper_wake() calls if it * also handles another event at the same time. * - * \deprecated Calls to ALooper_pollAll should be replaced with - * ALooper_pollOnce. If you call ALooper_pollOnce in a loop, you *must* treat + * \deprecated Calls to ALooper_pollAll() should be replaced with + * ALooper_pollOnce(). If you call ALooper_pollOnce() in a loop, you *must* treat * all return values as if they also indicate ALOOPER_POLL_WAKE. */ int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outData) @@ -242,7 +242,7 @@ int ALooper_pollAll(int timeoutMillis, int* outFd, int* outEvents, void** outDat * This method can be called on any thread. * This method returns immediately. * - * \bug ALooper_pollAll will not reliably wake in response to ALooper_wake. + * \bug ALooper_pollAll() will not reliably wake in response to ALooper_wake(). */ void ALooper_wake(ALooper* looper); diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h index 2b4a5f5f53..9ea6549e8a 100644 --- a/include/android/performance_hint.h +++ b/include/android/performance_hint.h @@ -478,8 +478,13 @@ void AWorkDuration_setActualGpuDurationNanos(AWorkDuration* _Nonnull aWorkDurati /** * Return the APerformanceHintSession wrapped by a Java PerformanceHintManager.Session object. * - * The Java session maintains ownership over the wrapped native session, so it cannot be - * closed using {@link APerformanceHint_closeSession}. + * The Java session maintains ownership over the wrapped native session, so it cannot be closed + * using {@link APerformanceHint_closeSession}. The return value is valid until the Java object + * containing this value dies. + * + * The returned pointer is intended to be used by JNI calls to access native performance APIs using + * a Java hint session wrapper, and then immediately discarded. Using the pointer after the death of + * the Java container results in undefined behavior. * * @param env The Java environment where the PerformanceHintManager.Session lives. * @param sessionObj The Java Session to unwrap. diff --git a/include/android/system_health.h b/include/android/system_health.h index 69620df16e..352eb72b0c 100644 --- a/include/android/system_health.h +++ b/include/android/system_health.h @@ -81,10 +81,10 @@ typedef struct AGpuHeadroomParams AGpuHeadroomParams; * * @return A new instance of ACpuHeadroomParams. */ -ACpuHeadroomParams *_Nonnull ACpuHeadroomParams_create() +ACpuHeadroomParams* _Nonnull ACpuHeadroomParams_create(void) __INTRODUCED_IN(36); -enum ACpuHeadroomCalculationType { +typedef enum ACpuHeadroomCalculationType : int32_t { /** * Use the minimum headroom value within the calculation window. * Introduced in API level 36. @@ -95,10 +95,9 @@ enum ACpuHeadroomCalculationType { * Introduced in API level 36. */ ACPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1, -}; -typedef enum ACpuHeadroomCalculationType ACpuHeadroomCalculationType; +} ACpuHeadroomCalculationType; -enum AGpuHeadroomCalculationType { +typedef enum AGpuHeadroomCalculationType : int32_t { /** * Use the minimum headroom value within the calculation window. * Introduced in API level 36. @@ -109,8 +108,7 @@ enum AGpuHeadroomCalculationType { * Introduced in API level 36. */ AGPU_HEADROOM_CALCULATION_TYPE_AVERAGE = 1, -}; -typedef enum AGpuHeadroomCalculationType AGpuHeadroomCalculationType; +} AGpuHeadroomCalculationType; /** * Sets the headroom calculation window size in ACpuHeadroomParams. @@ -124,7 +122,7 @@ typedef enum AGpuHeadroomCalculationType AGpuHeadroomCalculationType; * {@link #ACpuHeadroomParams_getCalculationWindowMillis} if not set. The device * will try to use the closest feasible window size to this param. */ -void ACpuHeadroomParams_setCalculationWindowMillis(ACpuHeadroomParams *_Nonnull params, +void ACpuHeadroomParams_setCalculationWindowMillis(ACpuHeadroomParams* _Nonnull params, int windowMillis) __INTRODUCED_IN(36); @@ -136,7 +134,7 @@ __INTRODUCED_IN(36); * @param params The params to be set. * @return This will return the default value chosen by the device if the params is not set. */ -int ACpuHeadroomParams_getCalculationWindowMillis(ACpuHeadroomParams *_Nonnull params) +int ACpuHeadroomParams_getCalculationWindowMillis(ACpuHeadroomParams* _Nonnull params) __INTRODUCED_IN(36); /** @@ -151,7 +149,7 @@ __INTRODUCED_IN(36); * {@link #AGpuHeadroomParams_getCalculationWindowMillis} if not set. The device * will try to use the closest feasible window size to this param. */ -void AGpuHeadroomParams_setCalculationWindowMillis(AGpuHeadroomParams *_Nonnull params, +void AGpuHeadroomParams_setCalculationWindowMillis(AGpuHeadroomParams* _Nonnull params, int windowMillis) __INTRODUCED_IN(36); @@ -163,7 +161,7 @@ __INTRODUCED_IN(36); * @param params The params to be set. * @return This will return the default value chosen by the device if the params is not set. */ -int AGpuHeadroomParams_getCalculationWindowMillis(AGpuHeadroomParams *_Nonnull params) +int AGpuHeadroomParams_getCalculationWindowMillis(AGpuHeadroomParams* _Nonnull params) __INTRODUCED_IN(36); /** @@ -174,7 +172,7 @@ __INTRODUCED_IN(36); * @param params The params to be set. * @param calculationType The headroom calculation type. */ -void ACpuHeadroomParams_setCalculationType(ACpuHeadroomParams *_Nonnull params, +void ACpuHeadroomParams_setCalculationType(ACpuHeadroomParams* _Nonnull params, ACpuHeadroomCalculationType calculationType) __INTRODUCED_IN(36); @@ -187,7 +185,7 @@ __INTRODUCED_IN(36); * @return The headroom calculation type. */ ACpuHeadroomCalculationType -ACpuHeadroomParams_getCalculationType(ACpuHeadroomParams *_Nonnull params) +ACpuHeadroomParams_getCalculationType(ACpuHeadroomParams* _Nonnull params) __INTRODUCED_IN(36); /** @@ -198,7 +196,7 @@ __INTRODUCED_IN(36); * @param params The params to be set. * @param calculationType The headroom calculation type. */ -void AGpuHeadroomParams_setCalculationType(AGpuHeadroomParams *_Nonnull params, +void AGpuHeadroomParams_setCalculationType(AGpuHeadroomParams* _Nonnull params, AGpuHeadroomCalculationType calculationType) __INTRODUCED_IN(36); @@ -211,7 +209,7 @@ __INTRODUCED_IN(36); * @return The headroom calculation type. */ AGpuHeadroomCalculationType -AGpuHeadroomParams_getCalculationType(AGpuHeadroomParams *_Nonnull params) +AGpuHeadroomParams_getCalculationType(AGpuHeadroomParams* _Nonnull params) __INTRODUCED_IN(36); /** @@ -223,7 +221,7 @@ __INTRODUCED_IN(36); * @param tids Non-null array of TIDs, maximum 5. * @param tidsSize The size of the tids array. */ -void ACpuHeadroomParams_setTids(ACpuHeadroomParams *_Nonnull params, const int *_Nonnull tids, +void ACpuHeadroomParams_setTids(ACpuHeadroomParams* _Nonnull params, const int* _Nonnull tids, int tidsSize) __INTRODUCED_IN(36); @@ -238,7 +236,7 @@ __INTRODUCED_IN(36); * * @return A new instance of AGpuHeadroomParams. */ -AGpuHeadroomParams *_Nonnull AGpuHeadroomParams_create() +AGpuHeadroomParams* _Nonnull AGpuHeadroomParams_create(void) __INTRODUCED_IN(36); /** @@ -248,7 +246,7 @@ __INTRODUCED_IN(36); * * @param params The params to be deleted. */ -void ACpuHeadroomParams_destroy(ACpuHeadroomParams *_Nonnull params) +void ACpuHeadroomParams_destroy(ACpuHeadroomParams* _Nonnull params) __INTRODUCED_IN(36); /** @@ -258,7 +256,7 @@ __INTRODUCED_IN(36); * * @param params The params to be deleted. */ -void AGpuHeadroomParams_destroy(AGpuHeadroomParams *_Nonnull params) +void AGpuHeadroomParams_destroy(AGpuHeadroomParams* _Nonnull params) __INTRODUCED_IN(36); /** @@ -282,8 +280,8 @@ __INTRODUCED_IN(36); * EPERM if the TIDs do not belong to the same process. * ENOTSUP if API or requested params is unsupported. */ -int ASystemHealth_getCpuHeadroom(const ACpuHeadroomParams *_Nullable params, - float *_Nonnull outHeadroom) +int ASystemHealth_getCpuHeadroom(const ACpuHeadroomParams* _Nullable params, + float* _Nonnull outHeadroom) __INTRODUCED_IN(36); /** @@ -306,8 +304,8 @@ __INTRODUCED_IN(36); * EPIPE if failed to get the GPU headroom. * ENOTSUP if API or requested params is unsupported. */ -int ASystemHealth_getGpuHeadroom(const AGpuHeadroomParams *_Nullable params, - float *_Nonnull outHeadroom) +int ASystemHealth_getGpuHeadroom(const AGpuHeadroomParams* _Nullable params, + float* _Nonnull outHeadroom) __INTRODUCED_IN(36); /** @@ -323,7 +321,7 @@ __INTRODUCED_IN(36); * EPIPE if failed to get the minimum polling interval. * ENOTSUP if API is unsupported. */ -int ASystemHealth_getCpuHeadroomMinIntervalMillis(int64_t *_Nonnull outMinIntervalMillis) +int ASystemHealth_getCpuHeadroomMinIntervalMillis(int64_t* _Nonnull outMinIntervalMillis) __INTRODUCED_IN(36); /** @@ -339,7 +337,7 @@ __INTRODUCED_IN(36); * EPIPE if failed to get the minimum polling interval. * ENOTSUP if API is unsupported. */ -int ASystemHealth_getGpuHeadroomMinIntervalMillis(int64_t *_Nonnull outMinIntervalMillis) +int ASystemHealth_getGpuHeadroomMinIntervalMillis(int64_t* _Nonnull outMinIntervalMillis) __INTRODUCED_IN(36); #ifdef __cplusplus diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 6698d0c0cd..623e7b9139 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -775,6 +775,7 @@ void IPCThreadState::joinThreadPool(bool isMain) { LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid()); + mProcess->checkExpectingThreadPoolStart(); mProcess->mCurrentThreads++; mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index a5f416f1ba..0b7cd8154d 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -156,7 +156,7 @@ enum { #ifdef BINDER_WITH_KERNEL_IPC static void acquire_object(const sp<ProcessState>& proc, const flat_binder_object& obj, - const void* who) { + const void* who, bool tagFds) { switch (obj.hdr.type) { case BINDER_TYPE_BINDER: if (obj.binder) { @@ -173,7 +173,7 @@ static void acquire_object(const sp<ProcessState>& proc, const flat_binder_objec return; } case BINDER_TYPE_FD: { - if (obj.cookie != 0) { // owned + if (tagFds && obj.cookie != 0) { // owned FdTag(obj.handle, nullptr, who); } return; @@ -611,7 +611,7 @@ status_t Parcel::appendFrom(const Parcel* parcel, size_t offset, size_t len) { } } - acquire_object(proc, *flat, this); + acquire_object(proc, *flat, this, true /*tagFds*/); } } #else @@ -1797,13 +1797,22 @@ restart_write: // Need to write meta-data? if (nullMetaData || val.binder != 0) { kernelFields->mObjects[kernelFields->mObjectsSize] = mDataPos; - acquire_object(ProcessState::self(), val, this); + acquire_object(ProcessState::self(), val, this, true /*tagFds*/); kernelFields->mObjectsSize++; } return finishWrite(sizeof(flat_binder_object)); } + if (mOwner) { + // continueWrite does have the logic to convert this from an + // owned to an unowned Parcel. However, this is pretty inefficient, + // and it's really strange to need to do so, so prefer to avoid + // these paths than try to support them. + ALOGE("writing objects not supported on owned Parcels"); + return PERMISSION_DENIED; + } + if (!enoughData) { const status_t err = growData(sizeof(val)); if (err != NO_ERROR) return err; @@ -2719,6 +2728,65 @@ size_t Parcel::ipcObjectsCount() const return 0; } +static void do_nothing_release_func(const uint8_t* data, size_t dataSize, + const binder_size_t* objects, size_t objectsCount) { + (void)data; + (void)dataSize; + (void)objects; + (void)objectsCount; +} +static void delete_data_release_func(const uint8_t* data, size_t dataSize, + const binder_size_t* objects, size_t objectsCount) { + delete[] data; + (void)dataSize; + (void)objects; + (void)objectsCount; +} + +void Parcel::makeDangerousViewOf(Parcel* p) { + if (p->isForRpc()) { + // warning: this must match the logic in rpcSetDataReference + auto* rf = p->maybeRpcFields(); + LOG_ALWAYS_FATAL_IF(rf == nullptr); + std::vector<std::variant<binder::unique_fd, binder::borrowed_fd>> fds; + if (rf->mFds) { + fds.reserve(rf->mFds->size()); + for (const auto& fd : *rf->mFds) { + fds.push_back(binder::borrowed_fd(toRawFd(fd))); + } + } + status_t result = + rpcSetDataReference(rf->mSession, p->mData, p->mDataSize, + rf->mObjectPositions.data(), rf->mObjectPositions.size(), + std::move(fds), do_nothing_release_func); + LOG_ALWAYS_FATAL_IF(result != OK, "Failed: %s", statusToString(result).c_str()); + } else { +#ifdef BINDER_WITH_KERNEL_IPC + // warning: this must match the logic in ipcSetDataReference + auto* kf = p->maybeKernelFields(); + LOG_ALWAYS_FATAL_IF(kf == nullptr); + + // Ownership of FDs is passed to the Parcel from kernel binder. This should be refactored + // to move this ownership out of Parcel and into release_func. However, today, Parcel + // always assums it can own and close FDs today. So, for purposes of testing consistency, + // , create new FDs it can own. + + uint8_t* newData = new uint8_t[p->mDataSize]; // deleted by delete_data_release_func + memcpy(newData, p->mData, p->mDataSize); + for (size_t i = 0; i < kf->mObjectsSize; i++) { + flat_binder_object* flat = + reinterpret_cast<flat_binder_object*>(newData + kf->mObjects[i]); + if (flat->hdr.type == BINDER_TYPE_FD) { + flat->handle = fcntl(flat->handle, F_DUPFD_CLOEXEC, 0); + } + } + + ipcSetDataReference(newData, p->mDataSize, kf->mObjects, kf->mObjectsSize, + delete_data_release_func); +#endif // BINDER_WITH_KERNEL_IPC + } +} + void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, const binder_size_t* objects, size_t objectsCount, release_func relFunc) { // this code uses 'mOwner == nullptr' to understand whether it owns memory @@ -2729,6 +2797,7 @@ void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize, const bin auto* kernelFields = maybeKernelFields(); LOG_ALWAYS_FATAL_IF(kernelFields == nullptr); // guaranteed by freeData. + // must match makeDangerousViewOf mData = const_cast<uint8_t*>(data); mDataSize = mDataCapacity = dataSize; kernelFields->mObjects = const_cast<binder_size_t*>(objects); @@ -2807,6 +2876,7 @@ status_t Parcel::rpcSetDataReference( auto* rpcFields = maybeRpcFields(); LOG_ALWAYS_FATAL_IF(rpcFields == nullptr); // guaranteed by markForRpc. + // must match makeDangerousViewOf mData = const_cast<uint8_t*>(data); mDataSize = mDataCapacity = dataSize; mOwner = relFunc; @@ -2874,15 +2944,17 @@ void Parcel::releaseObjects() #endif // BINDER_WITH_KERNEL_IPC } -void Parcel::acquireObjects() -{ +void Parcel::reacquireObjects(size_t objectsSize) { auto* kernelFields = maybeKernelFields(); if (kernelFields == nullptr) { return; } #ifdef BINDER_WITH_KERNEL_IPC - size_t i = kernelFields->mObjectsSize; + LOG_ALWAYS_FATAL_IF(objectsSize > kernelFields->mObjectsSize, + "Object size %zu out of range of %zu", objectsSize, + kernelFields->mObjectsSize); + size_t i = objectsSize; if (i == 0) { return; } @@ -2892,8 +2964,10 @@ void Parcel::acquireObjects() while (i > 0) { i--; const flat_binder_object* flat = reinterpret_cast<flat_binder_object*>(data + objects[i]); - acquire_object(proc, *flat, this); + acquire_object(proc, *flat, this, false /*tagFds*/); // they are already tagged } +#else + (void) objectsSize; #endif // BINDER_WITH_KERNEL_IPC } @@ -3110,12 +3184,8 @@ status_t Parcel::continueWrite(size_t desired) return NO_MEMORY; } - // Little hack to only acquire references on objects - // we will be keeping. - size_t oldObjectsSize = kernelFields->mObjectsSize; - kernelFields->mObjectsSize = objectsSize; - acquireObjects(); - kernelFields->mObjectsSize = oldObjectsSize; + // only acquire references on objects we are keeping + reacquireObjects(objectsSize); } if (rpcFields) { if (status_t status = truncateRpcObjects(objectsSize); status != OK) { diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 5e7f1510bc..0e1e9b4127 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -501,6 +501,21 @@ bool ProcessState::isThreadPoolStarted() const { return mThreadPoolStarted; } +void ProcessState::checkExpectingThreadPoolStart() const { + if (mThreadPoolStarted) return; + + // this is also racey, but you should setup the threadpool in the main thread. If that is an + // issue, we can check if we are the process leader, but haven't seen the issue in practice. + size_t requestedThreads = mMaxThreads.load(); + + // if it's manually set to the default, we do ignore it here... + if (requestedThreads == DEFAULT_MAX_BINDER_THREADS) return; + if (requestedThreads == 0) return; + + ALOGW("Thread pool configuration of size %zu requested, but startThreadPool was not called.", + requestedThreads); +} + #define DRIVER_FEATURES_PATH "/dev/binderfs/features/" bool ProcessState::isDriverFeatureEnabled(const DriverFeature feature) { // Use static variable to cache the results. diff --git a/libs/binder/binder_module.h b/libs/binder/binder_module.h index 65cdcd7735..b3a2d9ec28 100644 --- a/libs/binder/binder_module.h +++ b/libs/binder/binder_module.h @@ -32,34 +32,4 @@ #include <linux/android/binder.h> #include <sys/ioctl.h> -struct binder_frozen_state_info { - binder_uintptr_t cookie; - __u32 is_frozen; -}; - -#ifndef BR_FROZEN_BINDER -// Temporary definition of BR_FROZEN_BINDER until UAPI binder.h includes it. -#define BR_FROZEN_BINDER _IOR('r', 21, struct binder_frozen_state_info) -#endif // BR_FROZEN_BINDER - -#ifndef BR_CLEAR_FREEZE_NOTIFICATION_DONE -// Temporary definition of BR_CLEAR_FREEZE_NOTIFICATION_DONE until UAPI binder.h includes it. -#define BR_CLEAR_FREEZE_NOTIFICATION_DONE _IOR('r', 22, binder_uintptr_t) -#endif // BR_CLEAR_FREEZE_NOTIFICATION_DONE - -#ifndef BC_REQUEST_FREEZE_NOTIFICATION -// Temporary definition of BC_REQUEST_FREEZE_NOTIFICATION until UAPI binder.h includes it. -#define BC_REQUEST_FREEZE_NOTIFICATION _IOW('c', 19, struct binder_handle_cookie) -#endif // BC_REQUEST_FREEZE_NOTIFICATION - -#ifndef BC_CLEAR_FREEZE_NOTIFICATION -// Temporary definition of BC_CLEAR_FREEZE_NOTIFICATION until UAPI binder.h includes it. -#define BC_CLEAR_FREEZE_NOTIFICATION _IOW('c', 20, struct binder_handle_cookie) -#endif // BC_CLEAR_FREEZE_NOTIFICATION - -#ifndef BC_FREEZE_NOTIFICATION_DONE -// Temporary definition of BC_FREEZE_NOTIFICATION_DONE until UAPI binder.h includes it. -#define BC_FREEZE_NOTIFICATION_DONE _IOW('c', 21, binder_uintptr_t) -#endif // BC_FREEZE_NOTIFICATION_DONE - #endif // _BINDER_MODULE_H_ diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index 5924a2d878..cdee17c2ee 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -219,7 +219,6 @@ namespace internal { constexpr const char* const kManualInterfaces[] = { "android.app.IActivityManager", "android.app.IUidObserver", - "android.drm.IDrm", "android.gfx.tests.ICallback", "android.gfx.tests.IIPCTest", "android.gfx.tests.ISafeInterfaceTest", @@ -233,17 +232,13 @@ constexpr const char* const kManualInterfaces[] = { "android.hardware.ICameraClient", "android.hardware.ICameraRecordingProxy", "android.hardware.ICameraRecordingProxyListener", - "android.hardware.ICrypto", "android.hardware.IOMXObserver", "android.hardware.IStreamListener", "android.hardware.IStreamSource", "android.media.IAudioService", "android.media.IDataSource", - "android.media.IDrmClient", "android.media.IMediaCodecList", - "android.media.IMediaDrmService", "android.media.IMediaExtractor", - "android.media.IMediaExtractorService", "android.media.IMediaHTTPConnection", "android.media.IMediaHTTPService", "android.media.IMediaLogService", @@ -258,9 +253,6 @@ constexpr const char* const kManualInterfaces[] = { "android.media.IMediaSource", "android.media.IRemoteDisplay", "android.media.IRemoteDisplayClient", - "android.media.IResourceManagerClient", - "android.media.IResourceManagerService", - "android.os.IComplexTypeInterface", "android.os.IPermissionController", "android.os.IProcessInfoService", "android.os.ISchedulingPolicyService", diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h index 0c7366e683..b4efa0af6d 100644 --- a/libs/binder/include/binder/Parcel.h +++ b/libs/binder/include/binder/Parcel.h @@ -649,6 +649,11 @@ public: LIBBINDER_EXPORTED void print(std::ostream& to, uint32_t flags = 0) const; + // This API is to quickly become a view of another Parcel, so that we can also + // test 'owner' paths quickly. It's extremely dangerous to use this API in + // practice, and you should never ever do it. + LIBBINDER_EXPORTED void makeDangerousViewOf(Parcel* p); + private: // Close all file descriptors in the parcel at object positions >= newObjectsSize. void closeFileDescriptors(size_t newObjectsSize); @@ -664,7 +669,7 @@ private: void ipcSetDataReference(const uint8_t* data, size_t dataSize, const binder_size_t* objects, size_t objectsCount, release_func relFunc); // Takes ownership even when an error is returned. - status_t rpcSetDataReference( + [[nodiscard]] status_t rpcSetDataReference( const sp<RpcSession>& session, const uint8_t* data, size_t dataSize, const uint32_t* objectTable, size_t objectTableSize, std::vector<std::variant<binder::unique_fd, binder::borrowed_fd>>&& ancillaryFds, @@ -672,7 +677,7 @@ private: status_t finishWrite(size_t len); void releaseObjects(); - void acquireObjects(); + void reacquireObjects(size_t objectSize); status_t growData(size_t len); // Clear the Parcel and set the capacity to `desired`. // Doesn't reset the RPC session association. diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h index 21bfd42fcc..ced49c19c2 100644 --- a/libs/binder/include/binder/ProcessState.h +++ b/libs/binder/include/binder/ProcessState.h @@ -141,6 +141,8 @@ public: private: static sp<ProcessState> init(const char* defaultDriver, bool requireDefault); + void checkExpectingThreadPoolStart() const; + static void onFork(); static void parentPostFork(); static void childPostFork(); diff --git a/libs/binder/libbinder_rpc_unstable.cpp b/libs/binder/libbinder_rpc_unstable.cpp index a84a0c6e0b..64b1be25d2 100644 --- a/libs/binder/libbinder_rpc_unstable.cpp +++ b/libs/binder/libbinder_rpc_unstable.cpp @@ -23,11 +23,8 @@ #ifndef __TRUSTY__ #include <cutils/sockets.h> -#endif - -#ifdef __linux__ -#include <linux/vm_sockets.h> -#endif // __linux__ +#include "vm_sockets.h" +#endif // !__TRUSTY__ using android::OK; using android::RpcServer; diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs index 1b24b0a1e1..e08a76312d 100644 --- a/libs/binder/rust/src/lib.rs +++ b/libs/binder/rust/src/lib.rs @@ -104,7 +104,7 @@ mod proxy; mod service; #[cfg(not(any(trusty, android_ndk)))] mod state; -#[cfg(not(any(android_vendor, android_ndk, android_vndk)))] +#[cfg(not(any(android_vendor, android_ndk, android_vndk, trusty)))] mod system_only; use binder_ndk_sys as sys; @@ -125,7 +125,7 @@ pub use service::{ pub use service::{get_interface, get_service}; #[cfg(not(any(trusty, android_ndk)))] pub use state::{ProcessState, ThreadState}; -#[cfg(not(any(android_vendor, android_vndk, android_ndk)))] +#[cfg(not(any(android_vendor, android_vndk, android_ndk, trusty)))] pub use system_only::{delegate_accessor, Accessor, AccessorProvider, ConnectionInfo}; /// Binder result containing a [`Status`] on error. diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp index 08fa03cfd6..c038c95b07 100644 --- a/libs/binder/tests/binderLibTest.cpp +++ b/libs/binder/tests/binderLibTest.cpp @@ -344,7 +344,12 @@ class BinderLibTest : public ::testing::Test { } bool checkFreezeSupport() { - std::ifstream freezer_file("/sys/fs/cgroup/uid_0/cgroup.freeze"); + std::string path; + if (!CgroupGetAttributePathForTask("FreezerState", getpid(), &path)) { + return false; + } + + std::ifstream freezer_file(path); // Pass test on devices where the cgroup v2 freezer is not supported if (freezer_file.fail()) { return false; diff --git a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h index 2812da79fa..11fcb061f6 100644 --- a/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h +++ b/libs/binder/tests/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h @@ -28,6 +28,9 @@ struct RandomParcelOptions { std::function<void(Parcel* p, FuzzedDataProvider& provider)> writeHeader; std::vector<sp<IBinder>> extraBinders; std::vector<binder::unique_fd> extraFds; + + // internal state owned by fillRandomParcel, for Parcel views + std::vector<std::unique_ptr<Parcel>> extraParcels; }; /** diff --git a/libs/binder/tests/parcel_fuzzer/main.cpp b/libs/binder/tests/parcel_fuzzer/main.cpp index 192f9d5dce..d06b2d9020 100644 --- a/libs/binder/tests/parcel_fuzzer/main.cpp +++ b/libs/binder/tests/parcel_fuzzer/main.cpp @@ -70,7 +70,7 @@ void doTransactFuzz(const char* backend, const sp<B>& binder, FuzzedDataProvider uint32_t code = provider.ConsumeIntegral<uint32_t>(); uint32_t flag = provider.ConsumeIntegral<uint32_t>(); - FUZZ_LOG() << "backend: " << backend; + FUZZ_LOG() << "doTransactFuzz backend: " << backend; RandomParcelOptions options; @@ -101,7 +101,7 @@ void doReadFuzz(const char* backend, const std::vector<ParcelRead<P>>& reads, // since we are only using a byte to index CHECK_LE(reads.size(), 255u) << reads.size(); - FUZZ_LOG() << "backend: " << backend; + FUZZ_LOG() << "doReadFuzz backend: " << backend; FUZZ_LOG() << "input: " << HexString(p.data(), p.dataSize()); FUZZ_LOG() << "instructions: " << HexString(instructions.data(), instructions.size()); @@ -122,10 +122,15 @@ void doReadWriteFuzz(const char* backend, const std::vector<ParcelRead<P>>& read RandomParcelOptions options; P p; + // small amount of initial Parcel data, since fillRandomParcel uses makeDangerousViewOf + std::vector<uint8_t> parcelData = + provider.ConsumeBytes<uint8_t>(provider.ConsumeIntegralInRange<size_t>(0, 20)); + fillRandomParcel(&p, FuzzedDataProvider(parcelData.data(), parcelData.size()), &options); + // since we are only using a byte to index CHECK_LE(reads.size() + writes.size(), 255u) << reads.size(); - FUZZ_LOG() << "backend: " << backend; + FUZZ_LOG() << "doReadWriteFuzz backend: " << backend; while (provider.remaining_bytes() > 0) { uint8_t idx = provider.ConsumeIntegralInRange<uint8_t>(0, reads.size() + writes.size() - 1); diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp index 7c196142e8..dfd178a450 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp @@ -17,6 +17,7 @@ #include <fuzzbinder/random_parcel.h> #include <android-base/logging.h> +#include <binder/Functional.h> #include <binder/RpcSession.h> #include <binder/RpcTransportRaw.h> #include <fuzzbinder/random_binder.h> @@ -32,10 +33,29 @@ static void fillRandomParcelData(Parcel* p, FuzzedDataProvider&& provider) { CHECK(OK == p->write(data.data(), data.size())); } -void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider, RandomParcelOptions* options) { +void fillRandomParcel(Parcel* outputParcel, FuzzedDataProvider&& provider, + RandomParcelOptions* options) { CHECK_NE(options, nullptr); - if (provider.ConsumeBool()) { + const uint8_t fuzzerParcelOptions = provider.ConsumeIntegral<uint8_t>(); + const bool resultShouldBeView = fuzzerParcelOptions & 1; + const bool resultShouldBeRpc = fuzzerParcelOptions & 2; + + Parcel* p; + if (resultShouldBeView) { + options->extraParcels.push_back(std::make_unique<Parcel>()); + // held for duration of test, so that view will be valid + p = options->extraParcels[options->extraParcels.size() - 1].get(); + } else { + p = outputParcel; // directly fill out the output Parcel + } + auto viewify_guard = binder::impl::make_scope_guard([&]() { + if (resultShouldBeView) { + outputParcel->makeDangerousViewOf(p); + } + }); + + if (resultShouldBeRpc) { auto session = RpcSession::make(RpcTransportCtxFactoryRaw::make()); CHECK_EQ(OK, session->addNullDebuggingClient()); // Set the protocol version so that we don't crash if the session diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp index 0ed8a554ac..3cb628925c 100644 --- a/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp +++ b/libs/binder/tests/parcel_fuzzer/random_parcel_seeds.cpp @@ -281,9 +281,9 @@ void generateSeedsFromRecording(borrowed_fd fd, // This buffer holds the bytes which will be used for fillRandomParcel API std::vector<uint8_t> fillParcelBuffer; - // Don't take rpc path - uint8_t rpcBranch = 0; - impl::writeReversedBuffer(fillParcelBuffer, rpcBranch); + // Use all default options. + uint8_t parcelOptions = 0; + impl::writeReversedBuffer(fillParcelBuffer, parcelOptions); // Implicit branch on this path -> options->writeHeader(p, provider) uint8_t writeHeaderInternal = 0; diff --git a/libs/binder/trusty/rules.mk b/libs/binder/trusty/rules.mk index 5e38ad0d0c..dd9d4d12ee 100644 --- a/libs/binder/trusty/rules.mk +++ b/libs/binder/trusty/rules.mk @@ -64,14 +64,24 @@ MODULE_EXPORT_INCLUDES += \ MODULE_EXPORT_INCLUDES += \ $(LIBBINDER_DIR)/ndk/include_cpp \ +ifeq (false,$(call TOBOOL,$(USE_SYSTEM_BINDER))) +BINDER_EXTRA_COMPILE_FLAGS := \ + -D__ANDROID_VENDOR__ \ + -D__ANDROID_VNDK__ \ + +else +BINDER_EXTRA_COMPILE_FLAGS := \ + -DANDROID_PLATFORM \ + +endif + MODULE_EXPORT_COMPILEFLAGS += \ -DBINDER_RPC_SINGLE_THREADED \ -DBINDER_ENABLE_LIBLOG_ASSERT \ -DBINDER_DISABLE_NATIVE_HANDLE \ -DBINDER_DISABLE_BLOB \ -DBINDER_NO_LIBBASE \ - -D__ANDROID_VENDOR__ \ - -D__ANDROID_VNDK__ \ + $(BINDER_EXTRA_COMPILE_FLAGS) # libbinder has some deprecated declarations that we want to produce warnings # not errors diff --git a/libs/binder/trusty/rust/binder_ndk_sys/rules.mk b/libs/binder/trusty/rust/binder_ndk_sys/rules.mk index 2aaa061ddf..56d711efae 100644 --- a/libs/binder/trusty/rust/binder_ndk_sys/rules.mk +++ b/libs/binder/trusty/rust/binder_ndk_sys/rules.mk @@ -30,9 +30,14 @@ MODULE_LIBRARY_DEPS += \ trusty/user/base/lib/trusty-sys \ MODULE_RUSTFLAGS += \ - --cfg 'android_vendor' \ --cfg 'trusty' \ +ifeq (false,$(call TOBOOL,$(USE_SYSTEM_BINDER))) +MODULE_RUSTFLAGS += \ + --cfg 'android_vendor' \ + +endif + MODULE_BINDGEN_SRC_HEADER := $(LIBBINDER_DIR)/rust/sys/BinderBindings.hpp # Add the flags from the flag file diff --git a/libs/binder/trusty/rust/rules.mk b/libs/binder/trusty/rust/rules.mk index e622b22246..acd74d2c86 100644 --- a/libs/binder/trusty/rust/rules.mk +++ b/libs/binder/trusty/rust/rules.mk @@ -32,9 +32,15 @@ MODULE_LIBRARY_DEPS += \ trusty/user/base/lib/trusty-sys \ MODULE_RUSTFLAGS += \ - --cfg 'android_vendor' \ --cfg 'trusty' \ +ifeq (false,$(call TOBOOL,$(USE_SYSTEM_BINDER))) +MODULE_RUSTFLAGS += \ + --cfg 'android_vendor' \ + +endif + + # Trusty does not have `ProcessState`, so there are a few # doc links in `IBinder` that are still broken. MODULE_RUSTFLAGS += \ diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 7aee90393b..38465b0de2 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -1032,7 +1032,7 @@ void BLASTBufferQueue::mergeWithNextTransaction(SurfaceComposerClient::Transacti std::lock_guard _lock{mMutex}; if (mLastAcquiredFrameNumber >= frameNumber) { // Apply the transaction since we have already acquired the desired frame. - t->apply(); + t->setApplyToken(mApplyToken).apply(); } else { mPendingTransactions.emplace_back(frameNumber, *t); // Clear the transaction so it can't be applied elsewhere. @@ -1232,6 +1232,11 @@ public: return OK; } + // Provide a callback for Choreographer to start buffer stuffing recovery when blocked + // on buffer release. + std::function<void()> callbackCopy = bbq->getWaitForBufferReleaseCallback(); + if (callbackCopy) callbackCopy(); + // BufferQueue has already checked if we have a free buffer. If there's an unread interrupt, // we want to ignore it. This must be done before unlocking the BufferQueue lock to ensure // we don't miss an interrupt. @@ -1344,6 +1349,16 @@ void BLASTBufferQueue::setApplyToken(sp<IBinder> applyToken) { mApplyToken = std::move(applyToken); } +void BLASTBufferQueue::setWaitForBufferReleaseCallback(std::function<void()> callback) { + std::lock_guard _lock{mWaitForBufferReleaseMutex}; + mWaitForBufferReleaseCallback = std::move(callback); +} + +std::function<void()> BLASTBufferQueue::getWaitForBufferReleaseCallback() const { + std::lock_guard _lock{mWaitForBufferReleaseMutex}; + return mWaitForBufferReleaseCallback; +} + #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) void BLASTBufferQueue::updateBufferReleaseProducer() { diff --git a/libs/gui/Flags.cpp b/libs/gui/Flags.cpp index 85ee2cddad..ee2802f706 100644 --- a/libs/gui/Flags.cpp +++ b/libs/gui/Flags.cpp @@ -29,6 +29,14 @@ sp<SurfaceType> surfaceToSurfaceType(const sp<Surface>& surface) { #endif } +ParcelableSurfaceType surfaceToParcelableSurfaceType(const sp<Surface>& surface) { +#if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES + return view::Surface::fromSurface(surface); +#else + return surface->getIGraphicBufferProducer(); +#endif +} + sp<IGraphicBufferProducer> surfaceTypeToIGBP(const sp<SurfaceType>& surface) { #if WB_LIBCAMERASERVICE_WITH_DEPENDENCIES return surface->getIGraphicBufferProducer(); diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index be88b11b9c..cabde22c6d 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -3293,10 +3293,17 @@ status_t SurfaceComposerClient::removeHdrLayerInfoListener( return statusTFromBinderStatus(status); } -status_t SurfaceComposerClient::setActivePictureListener( +status_t SurfaceComposerClient::addActivePictureListener( const sp<gui::IActivePictureListener>& listener) { binder::Status status = - ComposerServiceAIDL::getComposerService()->setActivePictureListener(listener); + ComposerServiceAIDL::getComposerService()->addActivePictureListener(listener); + return statusTFromBinderStatus(status); +} + +status_t SurfaceComposerClient::removeActivePictureListener( + const sp<gui::IActivePictureListener>& listener) { + binder::Status status = + ComposerServiceAIDL::getComposerService()->removeActivePictureListener(listener); return statusTFromBinderStatus(status); } diff --git a/libs/gui/aidl/android/gui/CaptureArgs.aidl b/libs/gui/aidl/android/gui/CaptureArgs.aidl index 4920344e0e..2bbed2b9d6 100644 --- a/libs/gui/aidl/android/gui/CaptureArgs.aidl +++ b/libs/gui/aidl/android/gui/CaptureArgs.aidl @@ -69,10 +69,5 @@ parcelable CaptureArgs { // exact colorspace is not an appropriate intermediate result. // Note that if the caller is requesting a specific dataspace, this hint does nothing. boolean hintForSeamlessTransition = false; - - // Allows the screenshot to attach a gainmap, which allows for a per-pixel - // transformation of the screenshot to another luminance range, typically - // mapping an SDR base image into HDR. - boolean attachGainmap = false; } diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index 8c19bbbba9..da47ee27ba 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -607,8 +607,14 @@ interface ISurfaceComposer { oneway void removeJankListener(int layerId, IJankListener listener, long afterVsync); /** - * Sets the listener used to monitor visible content that is being processed with picture + * Adds a listener used to monitor visible content that is being processed with picture * profiles. */ - oneway void setActivePictureListener(IActivePictureListener listener); + oneway void addActivePictureListener(IActivePictureListener listener); + + /** + * Removes a listener used to monitor visible content that is being processed with picture + * profiles. + */ + oneway void removeActivePictureListener(IActivePictureListener listener); } diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 07558aa49d..1bc1dd0685 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -144,6 +144,12 @@ public: */ void setTransactionHangCallback(std::function<void(const std::string&)> callback); void setApplyToken(sp<IBinder>); + + void setWaitForBufferReleaseCallback(std::function<void()> callback) + EXCLUDES(mWaitForBufferReleaseMutex); + std::function<void()> getWaitForBufferReleaseCallback() const + EXCLUDES(mWaitForBufferReleaseMutex); + virtual ~BLASTBufferQueue(); void onFirstRef() override; @@ -186,6 +192,7 @@ private: sp<SurfaceControl> mSurfaceControl GUARDED_BY(mMutex); mutable std::mutex mMutex; + mutable std::mutex mWaitForBufferReleaseMutex; std::condition_variable mCallbackCV; // BufferQueue internally allows 1 more than @@ -324,6 +331,7 @@ private: std::unordered_set<uint64_t> mSyncedFrameNumbers GUARDED_BY(mMutex); + std::function<void()> mWaitForBufferReleaseCallback GUARDED_BY(mWaitForBufferReleaseMutex); #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL) // BufferReleaseChannel is used to communicate buffer releases from SurfaceFlinger to the // client. diff --git a/libs/gui/include/gui/Flags.h b/libs/gui/include/gui/Flags.h index 845bc54c71..446841bcd2 100644 --- a/libs/gui/include/gui/Flags.h +++ b/libs/gui/include/gui/Flags.h @@ -46,6 +46,7 @@ typedef android::sp<android::IGraphicBufferProducer> ParcelableSurfaceType; namespace flagtools { sp<SurfaceType> surfaceToSurfaceType(const sp<Surface>& surface); +ParcelableSurfaceType surfaceToParcelableSurfaceType(const sp<Surface>& surface); ParcelableSurfaceType toParcelableSurfaceType(const view::Surface& surface); sp<IGraphicBufferProducer> surfaceTypeToIGBP(const sp<SurfaceType>& surface); bool isSurfaceTypeValid(const sp<SurfaceType>& surface); diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 1c31e46cb4..64f191b867 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -425,7 +425,7 @@ struct layer_state_t { PictureProfileHandle pictureProfileHandle{PictureProfileHandle::NONE}; // A value indicating the significance of the layer's content to the app's desired user - // experience. A lower priority will result in more likelihood of getting access to limited + // experience. A higher value will result in more likelihood of getting access to limited // resources, such as picture processing hardware. int32_t appContentPriority = 0; diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index 0ce0c0a9c3..0f66c8b492 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -298,7 +298,9 @@ public: static status_t removeHdrLayerInfoListener(const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener); - static status_t setActivePictureListener(const sp<gui::IActivePictureListener>& listener); + static status_t addActivePictureListener(const sp<gui::IActivePictureListener>& listener); + + static status_t removeActivePictureListener(const sp<gui::IActivePictureListener>& listener); /* * Sends a power boost to the composer. This function is asynchronous. diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index e771d6db7f..646e30e5a8 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -1019,7 +1019,11 @@ public: return binder::Status::ok(); } - binder::Status setActivePictureListener(const sp<gui::IActivePictureListener>&) { + binder::Status addActivePictureListener(const sp<gui::IActivePictureListener>&) { + return binder::Status::ok(); + } + + binder::Status removeActivePictureListener(const sp<gui::IActivePictureListener>&) { return binder::Status::ok(); } diff --git a/libs/gui/tests/benchmarks/Android.bp b/libs/gui/tests/benchmarks/Android.bp new file mode 100644 index 0000000000..a728bef977 --- /dev/null +++ b/libs/gui/tests/benchmarks/Android.bp @@ -0,0 +1,27 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_native_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_native_license"], +} + +cc_benchmark { + name: "libgui_benchmarks", + srcs: [ + "*.cpp", + ], + defaults: ["libgui-defaults"], + static_libs: [ + "libgmock", + "libgtest", + ], + shared_libs: [ + "libgui", + ], + header_libs: [ + "libsurfaceflinger_mocks_headers", + "surfaceflinger_tests_common_headers", + ], +} diff --git a/libs/gui/tests/benchmarks/Transaction_benchmarks.cpp b/libs/gui/tests/benchmarks/Transaction_benchmarks.cpp new file mode 100644 index 0000000000..0a5189538b --- /dev/null +++ b/libs/gui/tests/benchmarks/Transaction_benchmarks.cpp @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <benchmark/benchmark.h> +#include <cstddef> +#include <optional> +#include <vector> +#include "binder/Parcel.h" +#include "gui/SurfaceComposerClient.h" +#include "gui/SurfaceControl.h" +#include "log/log_main.h" + +namespace android { +namespace { +using android::hardware::graphics::common::V1_1::BufferUsage; + +std::vector<sp<SurfaceControl>> createSurfaceControl(const char* name, size_t num) { + sp<SurfaceComposerClient> client = sp<SurfaceComposerClient>::make(); + LOG_FATAL_IF(client->initCheck() != OK, "Could not init SurfaceComposerClient"); + std::vector<sp<SurfaceControl>> surfaceControls; + for (size_t i = 0; i < num; i++) { + surfaceControls.push_back( + client->createSurface(String8(name), 0, 0, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState)); + } + return surfaceControls; +} + +void applyTransaction(benchmark::State& state) { + std::vector<sp<SurfaceControl>> surfaceControls = createSurfaceControl(__func__, 5 /* num */); + for (auto _ : state) { + SurfaceComposerClient::Transaction t; + for (auto& sc : surfaceControls) { + t.setCrop(sc, FloatRect{1, 2, 3, 4}); + t.setAutoRefresh(sc, true); + t.hide(sc); + t.setAlpha(sc, 0.5); + t.setCornerRadius(sc, 0.8); + } + Parcel p; + t.writeToParcel(&p); + t.clear(); + benchmark::DoNotOptimize(t); + } +} +BENCHMARK(applyTransaction); + +// Mimic a buffer transaction with callbacks +void applyBufferTransaction(benchmark::State& state) { + std::vector<sp<SurfaceControl>> surfaceControls = createSurfaceControl(__func__, 5 /* num */); + std::vector<sp<GraphicBuffer>> buffers; + for (size_t i = 0; i < surfaceControls.size(); i++) { + int64_t usageFlags = BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE; + buffers.emplace_back( + sp<GraphicBuffer>::make(5, 5, PIXEL_FORMAT_RGBA_8888, 1, usageFlags, "test")); + } + + for (auto _ : state) { + SurfaceComposerClient::Transaction t; + int i = 0; + for (auto& sc : surfaceControls) { + std::function<void(const ReleaseCallbackId&, const sp<Fence>& /*releaseFence*/, + std::optional<uint32_t> currentMaxAcquiredBufferCount)> + releaseBufferCallback; + t.setBuffer(sc, buffers[i], std::nullopt, std::nullopt, 5, releaseBufferCallback); + } + Parcel p; + // proxy for applying the transaction + t.writeToParcel(&p); + t.clear(); + benchmark::DoNotOptimize(t); + } +} +BENCHMARK(applyBufferTransaction); + +void mergeTransaction(benchmark::State& state) { + std::vector<sp<SurfaceControl>> surfaceControls = createSurfaceControl(__func__, 5 /* num */); + for (auto _ : state) { + SurfaceComposerClient::Transaction t1; + for (auto& sc : surfaceControls) { + t1.setCrop(sc, FloatRect{1, 2, 3, 4}); + t1.setAutoRefresh(sc, true); + t1.hide(sc); + t1.setAlpha(sc, 0.5); + t1.setCornerRadius(sc, 0.8); + } + + SurfaceComposerClient::Transaction t2; + for (auto& sc : surfaceControls) { + t2.hide(sc); + t2.setAlpha(sc, 0.5); + t2.setCornerRadius(sc, 0.8); + t2.setBackgroundBlurRadius(sc, 5); + } + t1.merge(std::move(t2)); + benchmark::DoNotOptimize(t1); + } +} +BENCHMARK(mergeTransaction); + +void readTransactionFromParcel(benchmark::State& state) { + std::vector<sp<SurfaceControl>> surfaceControls = createSurfaceControl(__func__, 5 /* num */); + SurfaceComposerClient::Transaction t; + for (auto& sc : surfaceControls) { + t.setCrop(sc, FloatRect{1, 2, 3, 4}); + t.setAutoRefresh(sc, true); + t.hide(sc); + t.setAlpha(sc, 0.5); + t.setCornerRadius(sc, 0.8); + } + Parcel p; + t.writeToParcel(&p); + t.clear(); + + for (auto _ : state) { + SurfaceComposerClient::Transaction t2; + t2.readFromParcel(&p); + p.setDataPosition(0); + benchmark::DoNotOptimize(t2); + } +} +BENCHMARK(readTransactionFromParcel); + +} // namespace +} // namespace android diff --git a/libs/gui/tests/benchmarks/main.cpp b/libs/gui/tests/benchmarks/main.cpp new file mode 100644 index 0000000000..685c7c6a26 --- /dev/null +++ b/libs/gui/tests/benchmarks/main.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <benchmark/benchmark.h> +BENCHMARK_MAIN(); diff --git a/libs/input/Android.bp b/libs/input/Android.bp index a4ae54b351..389fb7f6ab 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -262,6 +262,7 @@ cc_library { shared_libs: [ "android.companion.virtualdevice.flags-aconfig-cc", + "libaconfig_storage_read_api_cc", "libbase", "libbinder", "libbinder_ndk", diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index d1c564d020..0167c433cb 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -66,6 +66,7 @@ cc_test { }, }, shared_libs: [ + "libaconfig_storage_read_api_cc", "libbase", "libbinder", "libcutils", diff --git a/libs/permission/include/binder/AppOpsManager.h b/libs/permission/include/binder/AppOpsManager.h index 243532bc4d..7e179d6f7c 100644 --- a/libs/permission/include/binder/AppOpsManager.h +++ b/libs/permission/include/binder/AppOpsManager.h @@ -148,7 +148,10 @@ public: OP_BLUETOOTH_ADVERTISE = 114, OP_RECORD_INCOMING_PHONE_AUDIO = 115, OP_NEARBY_WIFI_DEVICES = 116, - _NUM_OP = 117 + // 116 - 154 omitted due to lack of use in native + OP_CONTROL_AUDIO = 154, + OP_CONTROL_AUDIO_PARTIAL = 155, + _NUM_OP = 156, }; enum { diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index 907590a236..873fc67c65 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -107,16 +107,15 @@ ftl::Future<FenceResult> RenderEngine::drawLayers(const DisplaySettings& display return resultFuture; } -ftl::Future<FenceResult> RenderEngine::drawGainmap( - const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, +ftl::Future<FenceResult> RenderEngine::tonemapAndDrawGainmap( const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, - float hdrSdrRatio, ui::Dataspace dataspace, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, const std::shared_ptr<ExternalTexture>& gainmap) { const auto resultPromise = std::make_shared<std::promise<FenceResult>>(); std::future<FenceResult> resultFuture = resultPromise->get_future(); updateProtectedContext({}, {sdr.get(), hdr.get(), gainmap.get()}); - drawGainmapInternal(std::move(resultPromise), sdr, std::move(sdrFence), hdr, - std::move(hdrFence), hdrSdrRatio, dataspace, gainmap); + tonemapAndDrawGainmapInternal(std::move(resultPromise), hdr, std::move(hdrFence), hdrSdrRatio, + dataspace, sdr, gainmap); return resultFuture; } diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 95c4d033e2..c2dd4ae97e 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -217,12 +217,17 @@ public: const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence); - virtual ftl::Future<FenceResult> drawGainmap(const std::shared_ptr<ExternalTexture>& sdr, - base::borrowed_fd&& sdrFence, - const std::shared_ptr<ExternalTexture>& hdr, - base::borrowed_fd&& hdrFence, float hdrSdrRatio, - ui::Dataspace dataspace, - const std::shared_ptr<ExternalTexture>& gainmap); + // Tonemaps an HDR input image and draws an SDR rendition, plus a gainmap + // describing how to recover the HDR image. + // + // The HDR input image is ALWAYS encoded with an sRGB transfer function and + // is a floating point format. Accordingly, the hdrSdrRatio describes the + // max luminance in the HDR input image above SDR, and the dataspace + // describes the input primaries. + virtual ftl::Future<FenceResult> tonemapAndDrawGainmap( + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, + const std::shared_ptr<ExternalTexture>& gainmap); // Clean-up method that should be called on the main thread after the // drawFence returned by drawLayers fires. This method will free up @@ -310,11 +315,10 @@ protected: const DisplaySettings& display, const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) = 0; - virtual void drawGainmapInternal( + virtual void tonemapAndDrawGainmapInternal( const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, - const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, - float hdrSdrRatio, ui::Dataspace dataspace, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, const std::shared_ptr<ExternalTexture>& gainmap) = 0; }; diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h index fb8331d870..c42e4034e0 100644 --- a/libs/renderengine/include/renderengine/mock/RenderEngine.h +++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h @@ -46,17 +46,16 @@ public: ftl::Future<FenceResult>(const DisplaySettings&, const std::vector<LayerSettings>&, const std::shared_ptr<ExternalTexture>&, base::unique_fd&&)); - MOCK_METHOD7(drawGainmap, + MOCK_METHOD6(tonemapAndDrawGainmap, ftl::Future<FenceResult>(const std::shared_ptr<ExternalTexture>&, - base::borrowed_fd&&, - const std::shared_ptr<ExternalTexture>&, base::borrowed_fd&&, float, ui::Dataspace, + const std::shared_ptr<ExternalTexture>&, const std::shared_ptr<ExternalTexture>&)); - MOCK_METHOD8(drawGainmapInternal, + MOCK_METHOD7(tonemapAndDrawGainmapInternal, void(const std::shared_ptr<std::promise<FenceResult>>&&, - const std::shared_ptr<ExternalTexture>&, base::borrowed_fd&&, const std::shared_ptr<ExternalTexture>&, base::borrowed_fd&&, float, - ui::Dataspace, const std::shared_ptr<ExternalTexture>&)); + ui::Dataspace, const std::shared_ptr<ExternalTexture>&, + const std::shared_ptr<ExternalTexture>&)); MOCK_METHOD5(drawLayersInternal, void(const std::shared_ptr<std::promise<FenceResult>>&&, const DisplaySettings&, const std::vector<LayerSettings>&, const std::shared_ptr<ExternalTexture>&, diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp index b9869672de..7e8ccef18e 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaRenderEngine.cpp @@ -567,9 +567,7 @@ sk_sp<SkShader> SkiaRenderEngine::createRuntimeEffectShader( if (usingLocalTonemap) { const float inputRatio = hdrType == HdrRenderType::GENERIC_HDR ? 1.0f : parameters.layerDimmingRatio; - static MouriMap kMapper; - shader = kMapper.mouriMap(getActiveContext(), shader, inputRatio, - parameters.display.targetHdrSdrRatio); + shader = localTonemap(shader, inputRatio, parameters.display.targetHdrSdrRatio); } // disable tonemapping if we already locally tonemapped @@ -610,6 +608,12 @@ sk_sp<SkShader> SkiaRenderEngine::createRuntimeEffectShader( return shader; } +sk_sp<SkShader> SkiaRenderEngine::localTonemap(sk_sp<SkShader> shader, float inputMultiplier, + float targetHdrSdrRatio) { + static MouriMap kMapper; + return kMapper.mouriMap(getActiveContext(), shader, inputMultiplier, targetHdrSdrRatio); +} + void SkiaRenderEngine::initCanvas(SkCanvas* canvas, const DisplaySettings& display) { if (CC_UNLIKELY(mCapture->isCaptureRunning())) { // Record display settings when capture is running. @@ -1212,44 +1216,58 @@ void SkiaRenderEngine::drawLayersInternal( resultPromise->set_value(std::move(drawFence)); } -void SkiaRenderEngine::drawGainmapInternal( +void SkiaRenderEngine::tonemapAndDrawGainmapInternal( const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, - const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, - float hdrSdrRatio, ui::Dataspace dataspace, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, const std::shared_ptr<ExternalTexture>& gainmap) { std::lock_guard<std::mutex> lock(mRenderingMutex); auto context = getActiveContext(); - auto surfaceTextureRef = getOrCreateBackendTexture(gainmap->getBuffer(), true); - sk_sp<SkSurface> dstSurface = - surfaceTextureRef->getOrCreateSurface(ui::Dataspace::V0_SRGB_LINEAR); - - waitFence(context, sdrFence); - const auto sdrTextureRef = getOrCreateBackendTexture(sdr->getBuffer(), false); - const auto sdrImage = sdrTextureRef->makeImage(dataspace, kPremul_SkAlphaType); - const auto sdrShader = - sdrImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, - SkSamplingOptions({SkFilterMode::kLinear, SkMipmapMode::kNone}), - nullptr); + auto gainmapTextureRef = getOrCreateBackendTexture(gainmap->getBuffer(), true); + sk_sp<SkSurface> gainmapSurface = + gainmapTextureRef->getOrCreateSurface(ui::Dataspace::V0_SRGB_LINEAR); + + auto sdrTextureRef = getOrCreateBackendTexture(sdr->getBuffer(), true); + sk_sp<SkSurface> sdrSurface = sdrTextureRef->getOrCreateSurface(dataspace); + waitFence(context, hdrFence); const auto hdrTextureRef = getOrCreateBackendTexture(hdr->getBuffer(), false); const auto hdrImage = hdrTextureRef->makeImage(dataspace, kPremul_SkAlphaType); const auto hdrShader = hdrImage->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, - SkSamplingOptions({SkFilterMode::kLinear, SkMipmapMode::kNone}), + SkSamplingOptions({SkFilterMode::kNearest, SkMipmapMode::kNone}), nullptr); + const auto tonemappedShader = localTonemap(hdrShader, 1.0f, 1.0f); + static GainmapFactory kGainmapFactory; - const auto gainmapShader = kGainmapFactory.createSkShader(sdrShader, hdrShader, hdrSdrRatio); + const auto gainmapShader = + kGainmapFactory.createSkShader(tonemappedShader, hdrShader, hdrSdrRatio); - const auto canvas = dstSurface->getCanvas(); - SkPaint paint; - paint.setShader(gainmapShader); - paint.setBlendMode(SkBlendMode::kSrc); - canvas->drawPaint(paint); + sp<Fence> drawFence; - auto drawFence = sp<Fence>::make(flushAndSubmit(context, dstSurface)); - trace(drawFence); + { + const auto canvas = sdrSurface->getCanvas(); + SkPaint paint; + paint.setShader(tonemappedShader); + paint.setBlendMode(SkBlendMode::kSrc); + canvas->drawPaint(paint); + + drawFence = sp<Fence>::make(flushAndSubmit(context, sdrSurface)); + trace(drawFence); + } + + { + const auto canvas = gainmapSurface->getCanvas(); + SkPaint paint; + paint.setShader(gainmapShader); + paint.setBlendMode(SkBlendMode::kSrc); + canvas->drawPaint(paint); + + auto gmFence = sp<Fence>::make(flushAndSubmit(context, gainmapSurface)); + trace(gmFence); + drawFence = Fence::merge("gm-ss", drawFence, gmFence); + } resultPromise->set_value(std::move(drawFence)); } diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index 7be4c253e7..92b7af985c 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -143,13 +143,11 @@ private: const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) override final; - void drawGainmapInternal(const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, - const std::shared_ptr<ExternalTexture>& sdr, - base::borrowed_fd&& sdrFence, - const std::shared_ptr<ExternalTexture>& hdr, - base::borrowed_fd&& hdrFence, float hdrSdrRatio, - ui::Dataspace dataspace, - const std::shared_ptr<ExternalTexture>& gainmap) override final; + void tonemapAndDrawGainmapInternal( + const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, + const std::shared_ptr<ExternalTexture>& gainmap) override final; void dump(std::string& result) override final; @@ -168,6 +166,8 @@ private: }; sk_sp<SkShader> createRuntimeEffectShader(const RuntimeEffectShaderParameters&); + sk_sp<SkShader> localTonemap(sk_sp<SkShader>, float inputMultiplier, float targetHdrSdrRatio); + const PixelFormat mDefaultPixelFormat; // Identifier used for various mappings of layers to various diff --git a/libs/renderengine/skia/filters/LutShader.cpp b/libs/renderengine/skia/filters/LutShader.cpp index 5e9dfbba3e..10218bb822 100644 --- a/libs/renderengine/skia/filters/LutShader.cpp +++ b/libs/renderengine/skia/filters/LutShader.cpp @@ -39,10 +39,13 @@ static const SkString kShader = SkString(R"( uniform int key; uniform int dimension; uniform vec3 luminanceCoefficients; // for CIE_Y + // for hlg/pq transfer function, we need normalize it to [0.0, 1.0] + // we use `normalizeScalar` to do so + uniform float normalizeScalar; vec4 main(vec2 xy) { float4 rgba = image.eval(xy); - float3 linear = toLinearSrgb(rgba.rgb); + float3 linear = toLinearSrgb(rgba.rgb) * normalizeScalar; if (dimension == 1) { // RGB if (key == 0) { @@ -52,19 +55,19 @@ static const SkString kShader = SkString(R"( float gainR = lut.eval(vec2(indexR, 0.0) + 0.5).r; float gainG = lut.eval(vec2(indexG, 0.0) + 0.5).r; float gainB = lut.eval(vec2(indexB, 0.0) + 0.5).r; - return float4(linear.r * gainR, linear.g * gainG, linear.b * gainB, rgba.a); + linear = float3(linear.r * gainR, linear.g * gainG, linear.b * gainB); // MAX_RGB } else if (key == 1) { float maxRGB = max(linear.r, max(linear.g, linear.b)); float index = maxRGB * float(size - 1); float gain = lut.eval(vec2(index, 0.0) + 0.5).r; - return float4(linear * gain, rgba.a); + linear = linear * gain; // CIE_Y } else if (key == 2) { float y = dot(linear, luminanceCoefficients) / 3.0; float index = y * float(size - 1); float gain = lut.eval(vec2(index, 0.0) + 0.5).r; - return float4(linear * gain, rgba.a); + linear = linear * gain; } } else if (dimension == 3) { if (key == 0) { @@ -110,12 +113,10 @@ static const SkString kShader = SkString(R"( float3 c0 = mix(c00, c10, linear.g); float3 c1 = mix(c01, c11, linear.g); - float3 val = mix(c0, c1, linear.b); - - return float4(val, rgba.a); + linear = mix(c0, c1, linear.b); } } - return rgba; + return float4(linear, rgba.a); })"); // same as shader::toColorSpace function @@ -186,10 +187,16 @@ sk_sp<SkShader> LutShader::generateLutShader(sk_sp<SkShader> input, SkBitmap bitmap; bitmap.allocPixels(info); if (!bitmap.installPixels(info, buffer.data(), info.minRowBytes())) { - LOG_ALWAYS_FATAL("unable to install pixels"); + ALOGW("bitmap.installPixels failed, skip this Lut!"); + return input; } sk_sp<SkImage> lutImage = SkImages::RasterFromBitmap(bitmap); + if (!lutImage) { + ALOGW("Got a nullptr from SkImages::RasterFromBitmap, skip this Lut!"); + return input; + } + mBuilder->child("image") = input; mBuilder->child("lut") = lutImage->makeRawShader(SkTileMode::kClamp, SkTileMode::kClamp, @@ -197,9 +204,22 @@ sk_sp<SkShader> LutShader::generateLutShader(sk_sp<SkShader> input, ? SkSamplingOptions(SkFilterMode::kLinear) : SkSamplingOptions()); + float normalizeScalar = 1.0; + switch (srcDataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_HLG: + normalizeScalar = 0.203; + break; + case HAL_DATASPACE_TRANSFER_ST2084: + normalizeScalar = 0.0203; + break; + default: + normalizeScalar = 1.0; + } const int uSize = static_cast<int>(size); const int uKey = static_cast<int>(samplingKey); const int uDimension = static_cast<int>(dimension); + const float uNormalizeScalar = static_cast<float>(normalizeScalar); + if (static_cast<LutProperties::SamplingKey>(samplingKey) == LutProperties::SamplingKey::CIE_Y) { // Use predefined colorspaces of input dataspace so that we can get D65 illuminant mat3 toXYZMatrix(toColorSpace(srcDataspace).getRGBtoXYZ()); @@ -211,6 +231,7 @@ sk_sp<SkShader> LutShader::generateLutShader(sk_sp<SkShader> input, mBuilder->uniform("size") = uSize; mBuilder->uniform("key") = uKey; mBuilder->uniform("dimension") = uDimension; + mBuilder->uniform("normalizeScalar") = uNormalizeScalar; return mBuilder->makeShader(); } diff --git a/libs/renderengine/skia/filters/MouriMap.cpp b/libs/renderengine/skia/filters/MouriMap.cpp index b099bcf3d7..aa12cef615 100644 --- a/libs/renderengine/skia/filters/MouriMap.cpp +++ b/libs/renderengine/skia/filters/MouriMap.cpp @@ -30,12 +30,12 @@ sk_sp<SkRuntimeEffect> makeEffect(const SkString& sksl) { } const SkString kCrosstalkAndChunk16x16(R"( uniform shader bitmap; - uniform float hdrSdrRatio; + uniform float inputMultiplier; vec4 main(vec2 xy) { float maximum = 0.0; for (int y = 0; y < 16; y++) { for (int x = 0; x < 16; x++) { - float3 linear = toLinearSrgb(bitmap.eval((xy - 0.5) * 16 + 0.5 + vec2(x, y)).rgb) * hdrSdrRatio; + float3 linear = toLinearSrgb(bitmap.eval((xy - 0.5) * 16 + 0.5 + vec2(x, y)).rgb) * inputMultiplier; float maxRGB = max(linear.r, max(linear.g, linear.b)); maximum = max(maximum, log2(max(maxRGB, 1.0))); } @@ -77,12 +77,12 @@ const SkString kTonemap(R"( uniform shader image; uniform shader lux; uniform float scaleFactor; - uniform float hdrSdrRatio; + uniform float inputMultiplier; uniform float targetHdrSdrRatio; vec4 main(vec2 xy) { float localMax = lux.eval(xy * scaleFactor).r; float4 rgba = image.eval(xy); - float3 linear = toLinearSrgb(rgba.rgb) * hdrSdrRatio; + float3 linear = toLinearSrgb(rgba.rgb) * inputMultiplier; if (localMax <= targetHdrSdrRatio) { return float4(fromLinearSrgb(linear), rgba.a); @@ -116,19 +116,19 @@ MouriMap::MouriMap() mTonemap(makeEffect(kTonemap)) {} sk_sp<SkShader> MouriMap::mouriMap(SkiaGpuContext* context, sk_sp<SkShader> input, - float hdrSdrRatio, float targetHdrSdrRatio) { - auto downchunked = downchunk(context, input, hdrSdrRatio); + float inputMultiplier, float targetHdrSdrRatio) { + auto downchunked = downchunk(context, input, inputMultiplier); auto localLux = blur(context, downchunked.get()); - return tonemap(input, localLux.get(), hdrSdrRatio, targetHdrSdrRatio); + return tonemap(input, localLux.get(), inputMultiplier, targetHdrSdrRatio); } sk_sp<SkImage> MouriMap::downchunk(SkiaGpuContext* context, sk_sp<SkShader> input, - float hdrSdrRatio) const { + float inputMultiplier) const { SkMatrix matrix; SkImage* image = input->isAImage(&matrix, (SkTileMode*)nullptr); SkRuntimeShaderBuilder crosstalkAndChunk16x16Builder(mCrosstalkAndChunk16x16); crosstalkAndChunk16x16Builder.child("bitmap") = input; - crosstalkAndChunk16x16Builder.uniform("hdrSdrRatio") = hdrSdrRatio; + crosstalkAndChunk16x16Builder.uniform("inputMultiplier") = inputMultiplier; // TODO: fp16 might be overkill. Most practical surfaces use 8-bit RGB for HDR UI and 10-bit YUV // for HDR video. These downsample operations compute log2(max(linear RGB, 1.0)). So we don't // care about LDR precision since they all resolve to LDR-max. For appropriately mastered HDR @@ -168,7 +168,7 @@ sk_sp<SkImage> MouriMap::blur(SkiaGpuContext* context, SkImage* input) const { LOG_ALWAYS_FATAL_IF(!blurSurface, "%s: Failed to create surface!", __func__); return makeImage(blurSurface.get(), blurBuilder); } -sk_sp<SkShader> MouriMap::tonemap(sk_sp<SkShader> input, SkImage* localLux, float hdrSdrRatio, +sk_sp<SkShader> MouriMap::tonemap(sk_sp<SkShader> input, SkImage* localLux, float inputMultiplier, float targetHdrSdrRatio) const { static constexpr float kScaleFactor = 1.0f / 128.0f; SkRuntimeShaderBuilder tonemapBuilder(mTonemap); @@ -177,7 +177,7 @@ sk_sp<SkShader> MouriMap::tonemap(sk_sp<SkShader> input, SkImage* localLux, floa localLux->makeRawShader(SkTileMode::kClamp, SkTileMode::kClamp, SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone)); tonemapBuilder.uniform("scaleFactor") = kScaleFactor; - tonemapBuilder.uniform("hdrSdrRatio") = hdrSdrRatio; + tonemapBuilder.uniform("inputMultiplier") = inputMultiplier; tonemapBuilder.uniform("targetHdrSdrRatio") = targetHdrSdrRatio; return tonemapBuilder.makeShader(); } diff --git a/libs/renderengine/skia/filters/MouriMap.h b/libs/renderengine/skia/filters/MouriMap.h index 9ba2b6ff9d..f4bfa1549e 100644 --- a/libs/renderengine/skia/filters/MouriMap.h +++ b/libs/renderengine/skia/filters/MouriMap.h @@ -62,10 +62,13 @@ class MouriMap { public: MouriMap(); // Apply the MouriMap tonemmaping operator to the input. - // The HDR/SDR ratio describes the luminace range of the input. 1.0 means SDR. Anything larger - // then 1.0 means that there is headroom above the SDR region. - // Similarly, the target HDR/SDR ratio describes the luminance range of the output. - sk_sp<SkShader> mouriMap(SkiaGpuContext* context, sk_sp<SkShader> input, float inputHdrSdrRatio, + // The inputMultiplier informs how to interpret the luminance encoding of the input. + // For a fixed point input, this is necessary to interpret what "1.0" means for the input + // pixels, so that the luminance can be scaled appropriately, such that the operator can + // transform SDR values to be within 1.0. For a floating point input, "1.0" always means SDR, + // so the caller must pass 1.0. + // The target HDR/SDR ratio describes the luminance range of the output. + sk_sp<SkShader> mouriMap(SkiaGpuContext* context, sk_sp<SkShader> input, float inputMultiplier, float targetHdrSdrRatio); private: diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index c187f93089..ea5605d4bd 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -249,11 +249,10 @@ void RenderEngineThreaded::drawLayersInternal( return; } -void RenderEngineThreaded::drawGainmapInternal( +void RenderEngineThreaded::tonemapAndDrawGainmapInternal( const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, - const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, - float hdrSdrRatio, ui::Dataspace dataspace, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, const std::shared_ptr<ExternalTexture>& gainmap) { resultPromise->set_value(Fence::NO_FENCE); return; @@ -281,10 +280,9 @@ ftl::Future<FenceResult> RenderEngineThreaded::drawLayers( return resultFuture; } -ftl::Future<FenceResult> RenderEngineThreaded::drawGainmap( - const std::shared_ptr<ExternalTexture>& sdr, base::borrowed_fd&& sdrFence, +ftl::Future<FenceResult> RenderEngineThreaded::tonemapAndDrawGainmap( const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, - float hdrSdrRatio, ui::Dataspace dataspace, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, const std::shared_ptr<ExternalTexture>& gainmap) { SFTRACE_CALL(); const auto resultPromise = std::make_shared<std::promise<FenceResult>>(); @@ -292,13 +290,14 @@ ftl::Future<FenceResult> RenderEngineThreaded::drawGainmap( { std::lock_guard lock(mThreadMutex); mNeedsPostRenderCleanup = true; - mFunctionCalls.push([resultPromise, sdr, sdrFence = std::move(sdrFence), hdr, - hdrFence = std::move(hdrFence), hdrSdrRatio, dataspace, + mFunctionCalls.push([resultPromise, hdr, hdrFence = std::move(hdrFence), hdrSdrRatio, + dataspace, sdr, gainmap](renderengine::RenderEngine& instance) mutable { - SFTRACE_NAME("REThreaded::drawGainmap"); - instance.updateProtectedContext({}, {sdr.get(), hdr.get(), gainmap.get()}); - instance.drawGainmapInternal(std::move(resultPromise), sdr, std::move(sdrFence), hdr, - std::move(hdrFence), hdrSdrRatio, dataspace, gainmap); + SFTRACE_NAME("REThreaded::tonemapAndDrawGainmap"); + instance.updateProtectedContext({}, {hdr.get(), sdr.get(), gainmap.get()}); + instance.tonemapAndDrawGainmapInternal(std::move(resultPromise), hdr, + std::move(hdrFence), hdrSdrRatio, dataspace, sdr, + gainmap); }); } mCondition.notify_one(); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index cb6e924d81..8554b55030 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -55,12 +55,10 @@ public: const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) override; - ftl::Future<FenceResult> drawGainmap(const std::shared_ptr<ExternalTexture>& sdr, - base::borrowed_fd&& sdrFence, - const std::shared_ptr<ExternalTexture>& hdr, - base::borrowed_fd&& hdrFence, float hdrSdrRatio, - ui::Dataspace dataspace, - const std::shared_ptr<ExternalTexture>& gainmap) override; + ftl::Future<FenceResult> tonemapAndDrawGainmap( + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, + const std::shared_ptr<ExternalTexture>& gainmap) override; int getContextPriority() override; bool supportsBackgroundBlur() override; @@ -77,13 +75,11 @@ protected: const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, base::unique_fd&& bufferFence) override; - void drawGainmapInternal(const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, - const std::shared_ptr<ExternalTexture>& sdr, - base::borrowed_fd&& sdrFence, - const std::shared_ptr<ExternalTexture>& hdr, - base::borrowed_fd&& hdrFence, float hdrSdrRatio, - ui::Dataspace dataspace, - const std::shared_ptr<ExternalTexture>& gainmap) override; + void tonemapAndDrawGainmapInternal( + const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const std::shared_ptr<ExternalTexture>& hdr, base::borrowed_fd&& hdrFence, + float hdrSdrRatio, ui::Dataspace dataspace, const std::shared_ptr<ExternalTexture>& sdr, + const std::shared_ptr<ExternalTexture>& gainmap) override; private: void threadMain(CreateInstanceFactory factory); diff --git a/libs/tracing_perfetto/Android.bp b/libs/tracing_perfetto/Android.bp index 9a2d4f7463..8bd0d0f33d 100644 --- a/libs/tracing_perfetto/Android.bp +++ b/libs/tracing_perfetto/Android.bp @@ -43,7 +43,6 @@ cc_library_shared { "libbase", "libcutils", "libperfetto_c", - "android.os.flags-aconfig-cc-host", ], host_supported: true, diff --git a/libs/tracing_perfetto/tracing_perfetto_internal.cpp b/libs/tracing_perfetto/tracing_perfetto_internal.cpp index a58bc77131..f92f6df990 100644 --- a/libs/tracing_perfetto/tracing_perfetto_internal.cpp +++ b/libs/tracing_perfetto/tracing_perfetto_internal.cpp @@ -47,7 +47,6 @@ #include <atomic> #include <mutex> -#include <android_os.h> #include <android-base/properties.h> #include <cutils/trace.h> #include <inttypes.h> @@ -228,10 +227,6 @@ struct PerfettoTeCategory* toPerfettoCategory(uint64_t category) { } void registerWithPerfetto(bool test) { - if (!android::os::perfetto_sdk_tracing()) { - return; - } - static std::once_flag registration; std::call_once(registration, [test]() { struct PerfettoProducerInitArgs args = PERFETTO_PRODUCER_INIT_ARGS_INIT(); diff --git a/libs/ui/DisplayIdentification.cpp b/libs/ui/DisplayIdentification.cpp index 8d6f74b605..c9f0761a01 100644 --- a/libs/ui/DisplayIdentification.cpp +++ b/libs/ui/DisplayIdentification.cpp @@ -417,6 +417,7 @@ std::optional<DisplayIdentificationInfo> parseDisplayIdentificationData( return DisplayIdentificationInfo{ .id = displayId, .name = std::string(edid->displayName), + .port = port, .deviceProductInfo = buildDeviceProductInfo(*edid), .preferredDetailedTimingDescriptor = edid->preferredDetailedTimingDescriptor, }; diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp index b0c6e44b2b..18c9a6bc48 100644 --- a/libs/ui/GraphicBuffer.cpp +++ b/libs/ui/GraphicBuffer.cpp @@ -596,6 +596,8 @@ status_t GraphicBuffer::unflatten(void const*& buffer, size_t& size, int const*& width = height = stride = format = usage_deprecated = 0; layerCount = 0; usage = 0; + native_handle_close(handle); + native_handle_delete(const_cast<native_handle_t*>(handle)); handle = nullptr; ALOGE("unflatten: registerBuffer failed: %s (%d)", strerror(-err), err); return err; diff --git a/libs/ui/include/ui/DisplayIdentification.h b/libs/ui/include/ui/DisplayIdentification.h index cf67d7bf93..cdac2698dd 100644 --- a/libs/ui/include/ui/DisplayIdentification.h +++ b/libs/ui/include/ui/DisplayIdentification.h @@ -42,6 +42,7 @@ struct DetailedTimingDescriptor { struct DisplayIdentificationInfo { PhysicalDisplayId id; std::string name; + uint8_t port; std::optional<DeviceProductInfo> deviceProductInfo; std::optional<DetailedTimingDescriptor> preferredDetailedTimingDescriptor; }; diff --git a/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java b/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java index 5c12323633..fc0aef4964 100644 --- a/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java +++ b/services/gpuservice/vts/src/com/android/tests/gpuservice/GpuWorkTracepointTest.java @@ -39,29 +39,9 @@ import java.util.stream.Collectors; @RunWith(DeviceJUnit4ClassRunner.class) public class GpuWorkTracepointTest extends BaseHostJUnit4Test { - private static final String CPU_FREQUENCY_TRACEPOINT_FORMAT_PATH = - "/sys/kernel/tracing/events/power/cpu_frequency/format"; private static final String GPU_WORK_PERIOD_TRACEPOINT_FORMAT_PATH = "/sys/kernel/tracing/events/power/gpu_work_period/format"; - @Test - public void testReadTracingEvents() throws Exception { - // Test |testGpuWorkPeriodTracepointFormat| is dependent on whether certain tracepoint - // paths exist. This means the test will vacuously pass if the tracepoint file system is - // inaccessible. Thus, as a basic check, we make sure the CPU frequency tracepoint format - // is accessible. If not, something is probably fundamentally broken about the tracing - // file system. - CommandResult commandResult = getDevice().executeShellV2Command( - String.format("cat %s", CPU_FREQUENCY_TRACEPOINT_FORMAT_PATH)); - - assertEquals(String.format( - "Failed to read \"%s\". This probably means that the tracing file system " - + "is fundamentally broken in some way, possibly due to bad " - + "permissions.", - CPU_FREQUENCY_TRACEPOINT_FORMAT_PATH), - commandResult.getStatus(), CommandStatus.SUCCESS); - } - @VsrTest(requirements={"VSR-3.3-004"}) @RequiresDevice @Test diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp index 811692f1bf..5bf6ebbb46 100644 --- a/services/inputflinger/PointerChoreographer.cpp +++ b/services/inputflinger/PointerChoreographer.cpp @@ -98,6 +98,22 @@ std::unordered_set<ui::LogicalDisplayId> getPrivacySensitiveDisplaysFromWindowIn return privacySensitiveDisplays; } +vec2 calculatePositionOnDestinationViewport(const DisplayViewport& destinationViewport, + float pointerOffset, + DisplayTopologyPosition sourceBoundary) { + // destination is opposite of the source boundary + switch (sourceBoundary) { + case DisplayTopologyPosition::RIGHT: + return {0, pointerOffset}; // left edge + case DisplayTopologyPosition::TOP: + return {pointerOffset, destinationViewport.logicalBottom}; // bottom edge + case DisplayTopologyPosition::LEFT: + return {destinationViewport.logicalRight, pointerOffset}; // right edge + case DisplayTopologyPosition::BOTTOM: + return {pointerOffset, 0}; // top edge + } +} + } // namespace // --- PointerChoreographer --- @@ -327,19 +343,19 @@ void PointerChoreographer::handleUnconsumedDeltaLocked(PointerControllerInterfac // except sometimes near the corners. // In these cases this behaviour is not noticeable. We also do not apply unconsumed delta on // the destination display for the same reason. - DisplayPosition sourceBoundary; + DisplayTopologyPosition sourceBoundary; float cursorOffset = 0.0f; if (rotatedUnconsumedDelta.x > 0) { - sourceBoundary = DisplayPosition::RIGHT; + sourceBoundary = DisplayTopologyPosition::RIGHT; cursorOffset = rotatedCursorPosition.y; } else if (rotatedUnconsumedDelta.x < 0) { - sourceBoundary = DisplayPosition::LEFT; + sourceBoundary = DisplayTopologyPosition::LEFT; cursorOffset = rotatedCursorPosition.y; } else if (rotatedUnconsumedDelta.y > 0) { - sourceBoundary = DisplayPosition::BOTTOM; + sourceBoundary = DisplayTopologyPosition::BOTTOM; cursorOffset = rotatedCursorPosition.x; } else { - sourceBoundary = DisplayPosition::TOP; + sourceBoundary = DisplayTopologyPosition::TOP; cursorOffset = rotatedCursorPosition.x; } @@ -369,8 +385,9 @@ void PointerChoreographer::handleUnconsumedDeltaLocked(PointerControllerInterfac pc.fade(PointerControllerInterface::Transition::IMMEDIATE); pc.setDisplayViewport(destinationViewport); vec2 destinationPosition = - calculateDestinationPosition(destinationViewport, cursorOffset - destinationOffset, - sourceBoundary); + calculatePositionOnDestinationViewport(destinationViewport, + cursorOffset - destinationOffset, + sourceBoundary); // Transform position back to un-rotated coordinate space before sending it to controller destinationPosition = pc.getDisplayTransform().inverse().transform(destinationPosition.x, @@ -379,22 +396,6 @@ void PointerChoreographer::handleUnconsumedDeltaLocked(PointerControllerInterfac pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); } -vec2 PointerChoreographer::calculateDestinationPosition(const DisplayViewport& destinationViewport, - float pointerOffset, - DisplayPosition sourceBoundary) { - // destination is opposite of the source boundary - switch (sourceBoundary) { - case DisplayPosition::RIGHT: - return {0, pointerOffset}; // left edge - case DisplayPosition::TOP: - return {pointerOffset, destinationViewport.logicalBottom}; // bottom edge - case DisplayPosition::LEFT: - return {destinationViewport.logicalRight, pointerOffset}; // right edge - case DisplayPosition::BOTTOM: - return {pointerOffset, 0}; // top edge - } -} - void PointerChoreographer::processDrawingTabletEventLocked(const android::NotifyMotionArgs& args) { if (args.displayId == ui::LogicalDisplayId::INVALID) { return; @@ -540,8 +541,7 @@ void PointerChoreographer::processDeviceReset(const NotifyDeviceResetArgs& args) } void PointerChoreographer::onControllerAddedOrRemovedLocked() { - if (!com::android::input::flags::hide_pointer_indicators_for_secure_windows() && - !com::android::input::flags::connected_displays_cursor()) { + if (!com::android::input::flags::hide_pointer_indicators_for_secure_windows()) { return; } bool requireListener = !mTouchPointersByDevice.empty() || !mMousePointersByDisplay.empty() || @@ -607,11 +607,16 @@ void PointerChoreographer::notifyPointerCaptureChanged( mNextListener.notify(args); } -void PointerChoreographer::setDisplayTopology( - const std::unordered_map<ui::LogicalDisplayId, std::vector<AdjacentDisplay>>& - displayTopology) { +void PointerChoreographer::setDisplayTopology(const DisplayTopologyGraph& displayTopologyGraph) { std::scoped_lock _l(getLock()); - mTopology = displayTopology; + mTopology = displayTopologyGraph; + + // make primary display default mouse display, if it was not set + // or the existing display was removed + if (mDefaultMouseDisplayId == ui::LogicalDisplayId::INVALID || + mTopology.graph.find(mDefaultMouseDisplayId) != mTopology.graph.end()) { + mDefaultMouseDisplayId = mTopology.primaryDisplayId; + } } void PointerChoreographer::dump(std::string& dump) { @@ -985,73 +990,17 @@ PointerChoreographer::ControllerConstructor PointerChoreographer::getStylusContr return ConstructorDelegate(std::move(ctor)); } -void PointerChoreographer::populateFakeDisplayTopologyLocked( - const std::vector<gui::DisplayInfo>& displayInfos) { - if (!com::android::input::flags::connected_displays_cursor()) { - return; - } - - if (displayInfos.size() == mTopology.size()) { - bool displaysChanged = false; - for (const auto& displayInfo : displayInfos) { - if (mTopology.find(displayInfo.displayId) == mTopology.end()) { - displaysChanged = true; - break; - } - } - - if (!displaysChanged) { - return; - } - } - - // create a fake topology assuming following order - // default-display (top-edge) -> next-display (right-edge) -> next-display (right-edge) ... - // This also adds a 100px offset on corresponding edge for better manual testing - // ┌────────┐ - // │ next ├─────────┐ - // ┌─└───────┐┤ next 2 │ ... - // │ default │└─────────┘ - // └─────────┘ - mTopology.clear(); - - // treat default display as base, in real topology it should be the primary-display - ui::LogicalDisplayId previousDisplay = ui::LogicalDisplayId::DEFAULT; - for (const auto& displayInfo : displayInfos) { - if (displayInfo.displayId == ui::LogicalDisplayId::DEFAULT) { - continue; - } - if (previousDisplay == ui::LogicalDisplayId::DEFAULT) { - mTopology[previousDisplay].push_back( - {displayInfo.displayId, DisplayPosition::TOP, 100}); - mTopology[displayInfo.displayId].push_back( - {previousDisplay, DisplayPosition::BOTTOM, -100}); - } else { - mTopology[previousDisplay].push_back( - {displayInfo.displayId, DisplayPosition::RIGHT, 100}); - mTopology[displayInfo.displayId].push_back( - {previousDisplay, DisplayPosition::LEFT, -100}); - } - previousDisplay = displayInfo.displayId; - } - - // update default pointer display. In real topology it should be the primary-display - if (mTopology.find(mDefaultMouseDisplayId) == mTopology.end()) { - mDefaultMouseDisplayId = ui::LogicalDisplayId::DEFAULT; - } -} - std::optional<std::pair<const DisplayViewport*, float /*offset*/>> PointerChoreographer::findDestinationDisplayLocked(const ui::LogicalDisplayId sourceDisplayId, - const DisplayPosition sourceBoundary, + const DisplayTopologyPosition sourceBoundary, float cursorOffset) const { - const auto& sourceNode = mTopology.find(sourceDisplayId); - if (sourceNode == mTopology.end()) { + const auto& sourceNode = mTopology.graph.find(sourceDisplayId); + if (sourceNode == mTopology.graph.end()) { // Topology is likely out of sync with viewport info, wait for it to be updated LOG(WARNING) << "Source display missing from topology " << sourceDisplayId; return std::nullopt; } - for (const AdjacentDisplay& adjacentDisplay : sourceNode->second) { + for (const DisplayTopologyAdjacentDisplay& adjacentDisplay : sourceNode->second) { if (adjacentDisplay.position != sourceBoundary) { continue; } @@ -1064,8 +1013,8 @@ PointerChoreographer::findDestinationDisplayLocked(const ui::LogicalDisplayId so continue; } // target position must be within target display boundary - const int32_t edgeSize = - sourceBoundary == DisplayPosition::TOP || sourceBoundary == DisplayPosition::BOTTOM + const int32_t edgeSize = sourceBoundary == DisplayTopologyPosition::TOP || + sourceBoundary == DisplayTopologyPosition::BOTTOM ? (destinationViewport->logicalRight - destinationViewport->logicalLeft) : (destinationViewport->logicalBottom - destinationViewport->logicalTop); if (cursorOffset >= adjacentDisplay.offsetPx && @@ -1093,7 +1042,6 @@ void PointerChoreographer::PointerChoreographerDisplayInfoListener::onWindowInfo mPrivacySensitiveDisplays = std::move(newPrivacySensitiveDisplays); mPointerChoreographer->onPrivacySensitiveDisplaysChangedLocked(mPrivacySensitiveDisplays); } - mPointerChoreographer->populateFakeDisplayTopologyLocked(windowInfosUpdate.displayInfos); } void PointerChoreographer::PointerChoreographerDisplayInfoListener::setInitialDisplayInfosLocked( diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h index 939529f774..c2f5ec0e87 100644 --- a/services/inputflinger/PointerChoreographer.h +++ b/services/inputflinger/PointerChoreographer.h @@ -22,6 +22,7 @@ #include <android-base/thread_annotations.h> #include <gui/WindowInfosListener.h> +#include <input/DisplayTopologyGraph.h> #include <type_traits> #include <unordered_set> @@ -80,6 +81,11 @@ public: */ virtual void setFocusedDisplay(ui::LogicalDisplayId displayId) = 0; + /* + * Used by InputManager to notify changes in the DisplayTopology + */ + virtual void setDisplayTopology(const DisplayTopologyGraph& displayTopologyGraph) = 0; + /** * This method may be called on any thread (usually by the input manager on a binder thread). */ @@ -103,6 +109,7 @@ public: ui::LogicalDisplayId displayId, DeviceId deviceId) override; void setPointerIconVisibility(ui::LogicalDisplayId displayId, bool visible) override; void setFocusedDisplay(ui::LogicalDisplayId displayId) override; + void setDisplayTopology(const DisplayTopologyGraph& displayTopologyGraph); void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override; void notifyKey(const NotifyKeyArgs& args) override; @@ -113,24 +120,6 @@ public: void notifyDeviceReset(const NotifyDeviceResetArgs& args) override; void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override; - // TODO(b/362719483) remove these when real topology is available - enum class DisplayPosition { - RIGHT, - TOP, - LEFT, - BOTTOM, - ftl_last = BOTTOM, - }; - - struct AdjacentDisplay { - ui::LogicalDisplayId displayId; - DisplayPosition position; - float offsetPx; - }; - void setDisplayTopology( - const std::unordered_map<ui::LogicalDisplayId, std::vector<AdjacentDisplay>>& - displayTopology); - void dump(std::string& dump) override; private: @@ -174,18 +163,16 @@ private: void handleUnconsumedDeltaLocked(PointerControllerInterface& pc, const vec2& unconsumedDelta) REQUIRES(getLock()); - void populateFakeDisplayTopologyLocked(const std::vector<gui::DisplayInfo>& displayInfos) - REQUIRES(getLock()); - std::optional<std::pair<const DisplayViewport*, float /*offset*/>> findDestinationDisplayLocked( - const ui::LogicalDisplayId sourceDisplayId, const DisplayPosition sourceBoundary, - float cursorOffset) const REQUIRES(getLock()); - - static vec2 calculateDestinationPosition(const DisplayViewport& destinationViewport, - float pointerOffset, DisplayPosition sourceBoundary); + const ui::LogicalDisplayId sourceDisplayId, + const DisplayTopologyPosition sourceBoundary, float cursorOffset) const + REQUIRES(getLock()); - std::unordered_map<ui::LogicalDisplayId, std::vector<AdjacentDisplay>> mTopology - GUARDED_BY(getLock()); + /* Topology is initialized with default-constructed value, which is an empty topology. Till we + * receive setDisplayTopology call. + * Meanwhile Choreographer will treat every display as independent disconnected display. + */ + DisplayTopologyGraph mTopology GUARDED_BY(getLock()); /* This listener keeps tracks of visible privacy sensitive displays and updates the * choreographer if there are any changes. diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp index 27da3d33f9..1ca2998f6b 100644 --- a/services/inputflinger/tests/PointerChoreographer_test.cpp +++ b/services/inputflinger/tests/PointerChoreographer_test.cpp @@ -2633,16 +2633,14 @@ protected: ui::ROTATION_0), }; - std::unordered_map<ui::LogicalDisplayId, std::vector<PointerChoreographer::AdjacentDisplay>> - mTopology{ - {DISPLAY_CENTER_ID, - {{DISPLAY_TOP_ID, PointerChoreographer::DisplayPosition::TOP, 10.0f}, - {DISPLAY_RIGHT_ID, PointerChoreographer::DisplayPosition::RIGHT, 10.0f}, - {DISPLAY_BOTTOM_ID, PointerChoreographer::DisplayPosition::BOTTOM, 10.0f}, - {DISPLAY_LEFT_ID, PointerChoreographer::DisplayPosition::LEFT, 10.0f}, - {DISPLAY_TOP_RIGHT_CORNER_ID, PointerChoreographer::DisplayPosition::RIGHT, - -90.0f}}}, - }; + DisplayTopologyGraph mTopology{DISPLAY_CENTER_ID, + {{DISPLAY_CENTER_ID, + {{DISPLAY_TOP_ID, DisplayTopologyPosition::TOP, 10.0f}, + {DISPLAY_RIGHT_ID, DisplayTopologyPosition::RIGHT, 10.0f}, + {DISPLAY_BOTTOM_ID, DisplayTopologyPosition::BOTTOM, 10.0f}, + {DISPLAY_LEFT_ID, DisplayTopologyPosition::LEFT, 10.0f}, + {DISPLAY_TOP_RIGHT_CORNER_ID, DisplayTopologyPosition::RIGHT, + -90.0f}}}}}; private: DisplayViewport createViewport(ui::LogicalDisplayId displayId, int32_t width, int32_t height, @@ -2706,6 +2704,11 @@ INSTANTIATE_TEST_SUITE_P( testing::Values( // Note: Upon viewport transition cursor will be positioned at the boundary of the // destination, as we drop any unconsumed delta. + std::make_tuple("PrimaryDisplayIsDefault", AINPUT_SOURCE_MOUSE, + ControllerType::MOUSE, ToolType::MOUSE, + vec2(50, 50) /* initial x/y */, vec2(0, 0) /* delta x/y */, + PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID, + vec2(50, 50) /* destination x/y */), std::make_tuple("UnchangedDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE, ToolType::MOUSE, vec2(50, 50) /* initial x/y */, vec2(25, 25) /* delta x/y */, diff --git a/services/surfaceflinger/ActivePictureUpdater.cpp b/services/surfaceflinger/ActivePictureTracker.cpp index 210e948a49..4e6fa66ed8 100644 --- a/services/surfaceflinger/ActivePictureUpdater.cpp +++ b/services/surfaceflinger/ActivePictureTracker.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "ActivePictureUpdater.h" +#include "ActivePictureTracker.h" #include <algorithm> @@ -23,7 +23,10 @@ namespace android { -void ActivePictureUpdater::onLayerComposed(const Layer& layer, const LayerFE& layerFE, +using gui::ActivePicture; +using gui::IActivePictureListener; + +void ActivePictureTracker::onLayerComposed(const Layer& layer, const LayerFE& layerFE, const CompositionResult& result) { if (result.wasPictureProfileCommitted) { gui::ActivePicture picture; @@ -39,10 +42,47 @@ void ActivePictureUpdater::onLayerComposed(const Layer& layer, const LayerFE& la } } -bool ActivePictureUpdater::updateAndHasChanged() { +void ActivePictureTracker::updateAndNotifyListeners(const Listeners& listenersToAdd, + const Listeners& listenersToRemove) { + Listeners newListeners = updateListeners(listenersToAdd, listenersToRemove); + if (updateAndHasChanged()) { + for (auto listener : mListeners) { + listener->onActivePicturesChanged(getActivePictures()); + } + } else { + for (auto listener : newListeners) { + listener->onActivePicturesChanged(getActivePictures()); + } + } +} + +ActivePictureTracker::Listeners ActivePictureTracker::updateListeners( + const Listeners& listenersToAdd, const Listeners& listenersToRemove) { + Listeners newListeners; + for (auto listener : listenersToRemove) { + std::erase_if(mListeners, [listener](const sp<IActivePictureListener>& otherListener) { + return IInterface::asBinder(listener) == IInterface::asBinder(otherListener); + }); + } + for (auto listener : listenersToAdd) { + if (std::find_if(mListeners.begin(), mListeners.end(), + [listener](const sp<IActivePictureListener>& otherListener) { + return IInterface::asBinder(listener) == + IInterface::asBinder(otherListener); + }) == mListeners.end()) { + newListeners.push_back(listener); + } + } + for (auto listener : newListeners) { + mListeners.push_back(listener); + } + return newListeners; +} + +bool ActivePictureTracker::updateAndHasChanged() { bool hasChanged = true; if (mNewActivePictures.size() == mOldActivePictures.size()) { - auto compare = [](const gui::ActivePicture& lhs, const gui::ActivePicture& rhs) -> int { + auto compare = [](const ActivePicture& lhs, const ActivePicture& rhs) -> int { if (lhs.layerId == rhs.layerId) { return lhs.pictureProfileId < rhs.pictureProfileId; } @@ -59,7 +99,7 @@ bool ActivePictureUpdater::updateAndHasChanged() { return hasChanged; } -const std::vector<gui::ActivePicture>& ActivePictureUpdater::getActivePictures() const { +const std::vector<ActivePicture>& ActivePictureTracker::getActivePictures() const { return mOldActivePictures; } diff --git a/services/surfaceflinger/ActivePictureUpdater.h b/services/surfaceflinger/ActivePictureTracker.h index 20779bb0ff..cb319a58be 100644 --- a/services/surfaceflinger/ActivePictureUpdater.h +++ b/services/surfaceflinger/ActivePictureTracker.h @@ -19,6 +19,7 @@ #include <vector> #include <android/gui/ActivePicture.h> +#include <android/gui/IActivePictureListener.h> namespace android { @@ -27,21 +28,28 @@ class LayerFE; struct CompositionResult; // Keeps track of active pictures - layers that are undergoing picture processing. -class ActivePictureUpdater { +class ActivePictureTracker { public: + typedef std::vector<sp<gui::IActivePictureListener>> Listeners; + // Called for each visible layer when SurfaceFlinger finishes composing. void onLayerComposed(const Layer& layer, const LayerFE& layerFE, const CompositionResult& result); // Update internals and return whether the set of active pictures have changed. - bool updateAndHasChanged(); + void updateAndNotifyListeners(const Listeners& activePictureListenersToAdd, + const Listeners& activePictureListenersToRemove); // The current set of active pictures. const std::vector<gui::ActivePicture>& getActivePictures() const; private: + Listeners updateListeners(const Listeners& listenersToAdd, const Listeners& listenersToRemove); + bool updateAndHasChanged(); + std::vector<gui::ActivePicture> mOldActivePictures; std::vector<gui::ActivePicture> mNewActivePictures; + Listeners mListeners; }; } // namespace android diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 3f3d2c6cc6..05f7d1ba21 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -42,12 +42,12 @@ cc_defaults { name: "libsurfaceflinger_defaults", defaults: [ "android.hardware.graphics.composer3-ndk_shared", - "android.hardware.power-ndk_shared", "librenderengine_deps", "libtimestats_deps", "libsurfaceflinger_common_deps", "surfaceflinger_defaults", "libsurfaceflinger_proto_deps", + "poweradvisor_deps", ], cflags: [ "-DLOG_TAG=\"SurfaceFlinger\"", @@ -67,6 +67,7 @@ cc_defaults { "android.hardware.graphics.composer@2.2", "android.hardware.graphics.composer@2.3", "android.hardware.graphics.composer@2.4", + "android.os.flags-aconfig-cc-host", "libbase", "libbinder", "libbinder_ndk", @@ -79,7 +80,6 @@ cc_defaults { "libhidlbase", "liblog", "libnativewindow", - "libpowermanager", "libprocessgroup", "libprotobuf-cpp-lite", "libstatslog_surfaceflinger", @@ -199,7 +199,7 @@ filegroup { name: "libsurfaceflinger_sources", srcs: [ ":libsurfaceflinger_backend_sources", - "ActivePictureUpdater.cpp", + "ActivePictureTracker.cpp", "BackgroundExecutor.cpp", "Client.cpp", "ClientCache.cpp", diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 82eafd4fa8..2d0f874ad0 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -13,11 +13,11 @@ cc_defaults { defaults: [ "aconfig_lib_cc_static_link.defaults", "android.hardware.graphics.composer3-ndk_shared", - "android.hardware.power-ndk_shared", "librenderengine_deps", "libtimestats_deps", "surfaceflinger_defaults", "libsurfaceflinger_proto_deps", + "poweradvisor_deps", ], cflags: [ "-DLOG_TAG=\"CompositionEngine\"", diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h index 2e7a7d9c5a..c1b864df02 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h @@ -118,7 +118,8 @@ public: // isPeekingThrough specifies whether this layer will be shown through a // hole punch in a layer above it. virtual void writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, - bool zIsOverridden, bool isPeekingThrough) = 0; + bool zIsOverridden, bool isPeekingThrough, + bool isLutSupported) = 0; // Updates the cursor position with the HWC virtual void writeCursorPositionToHWC() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h index 712b55123f..0063eee0e1 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h @@ -58,7 +58,7 @@ public: const std::optional<std::vector<std::optional<LutProperties>>> properties = std::nullopt) override; void writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, bool zIsOverridden, - bool isPeekingThrough) override; + bool isPeekingThrough, bool hasLutsProperties) override; void writeCursorPositionToHWC() const override; HWC2::Layer* getHwcLayer() const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h index 9333ebb8cd..09c47f0224 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h @@ -47,7 +47,7 @@ public: (bool, bool, ui::Transform::RotationFlags, (const std::optional<std::vector<std::optional< aidl::android::hardware::graphics::composer3::LutProperties>>>))); - MOCK_METHOD5(writeStateToHWC, void(bool, bool, uint32_t, bool, bool)); + MOCK_METHOD(void, writeStateToHWC, (bool, bool, uint32_t, bool, bool, bool)); MOCK_CONST_METHOD0(writeCursorPositionToHWC, void()); MOCK_CONST_METHOD0(getHwcLayer, HWC2::Layer*()); diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index f9ed92d1ee..734d76404e 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -810,7 +810,7 @@ void Output::commitPictureProfilesToCompositionState() { } auto compare = [](const ::android::compositionengine::OutputLayer* lhs, const ::android::compositionengine::OutputLayer* rhs) { - return lhs->getPictureProfilePriority() > rhs->getPictureProfilePriority(); + return lhs->getPictureProfilePriority() < rhs->getPictureProfilePriority(); }; std::priority_queue<::android::compositionengine::OutputLayer*, std::vector<::android::compositionengine::OutputLayer*>, decltype(compare)> @@ -909,6 +909,9 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr applyPictureProfile(); + auto* properties = getOverlaySupport(); + bool hasLutsProperties = properties && properties->lutProperties.has_value(); + compositionengine::OutputLayer* peekThroughLayer = nullptr; sp<GraphicBuffer> previousOverride = nullptr; bool includeGeometry = refreshArgs.updatingGeometryThisFrame; @@ -940,7 +943,7 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr includeGeometry = true; constexpr bool isPeekingThrough = true; peekThroughLayer->writeStateToHWC(includeGeometry, false, z++, overrideZ, - isPeekingThrough); + isPeekingThrough, hasLutsProperties); outputLayerHash ^= android::hashCombine( reinterpret_cast<uint64_t>(&peekThroughLayer->getLayerFE()), z, includeGeometry, overrideZ, isPeekingThrough, @@ -952,7 +955,8 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr } constexpr bool isPeekingThrough = false; - layer->writeStateToHWC(includeGeometry, skipLayer, z++, overrideZ, isPeekingThrough); + layer->writeStateToHWC(includeGeometry, skipLayer, z++, overrideZ, isPeekingThrough, + hasLutsProperties); if (!skipLayer) { outputLayerHash ^= android::hashCombine( reinterpret_cast<uint64_t>(&layer->getLayerFE()), diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index a040c88e78..96b86d5a31 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -449,7 +449,8 @@ void OutputLayer::commitPictureProfileToCompositionState() { } void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t z, - bool zIsOverridden, bool isPeekingThrough) { + bool zIsOverridden, bool isPeekingThrough, + bool hasLutsProperties) { const auto& state = getState(); // Skip doing this if there is no HWC interface if (!state.hwc) { @@ -491,8 +492,9 @@ void OutputLayer::writeStateToHWC(bool includeGeometry, bool skipLayer, uint32_t writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType, isPeekingThrough, skipLayer); - - writeLutToHWC(hwcLayer.get(), *outputIndependentState); + if (hasLutsProperties) { + writeLutToHWC(hwcLayer.get(), *outputIndependentState); + } if (requestedCompositionType == Composition::SOLID_COLOR) { writeSolidColorStateToHWC(hwcLayer.get(), *outputIndependentState); @@ -589,29 +591,30 @@ void OutputLayer::writeOutputIndependentGeometryStateToHWC( void OutputLayer::writeLutToHWC(HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) { - if (!outputIndependentState.luts) { - return; - } - auto& lutFileDescriptor = outputIndependentState.luts->getLutFileDescriptor(); - auto lutOffsets = outputIndependentState.luts->offsets; - auto& lutProperties = outputIndependentState.luts->lutProperties; + Luts luts; + // if outputIndependentState.luts is nullptr, it means we want to clear the LUTs + // and we pass an empty Luts object to the HWC. + if (outputIndependentState.luts) { + auto& lutFileDescriptor = outputIndependentState.luts->getLutFileDescriptor(); + auto lutOffsets = outputIndependentState.luts->offsets; + auto& lutProperties = outputIndependentState.luts->lutProperties; + + std::vector<LutProperties> aidlProperties; + aidlProperties.reserve(lutProperties.size()); + for (size_t i = 0; i < lutOffsets.size(); i++) { + aidlProperties.emplace_back( + LutProperties{.dimension = static_cast<LutProperties::Dimension>( + lutProperties[i].dimension), + .size = lutProperties[i].size, + .samplingKeys = {static_cast<LutProperties::SamplingKey>( + lutProperties[i].samplingKey)}}); + } - std::vector<LutProperties> aidlProperties; - aidlProperties.reserve(lutProperties.size()); - for (size_t i = 0; i < lutOffsets.size(); i++) { - LutProperties properties; - properties.dimension = static_cast<LutProperties::Dimension>(lutProperties[i].dimension); - properties.size = lutProperties[i].size; - properties.samplingKeys = { - static_cast<LutProperties::SamplingKey>(lutProperties[i].samplingKey)}; - aidlProperties.emplace_back(properties); + luts.pfd = ndk::ScopedFileDescriptor(dup(lutFileDescriptor.get())); + luts.offsets = lutOffsets; + luts.lutProperties = std::move(aidlProperties); } - Luts luts; - luts.pfd = ndk::ScopedFileDescriptor(dup(lutFileDescriptor.get())); - luts.offsets = lutOffsets; - luts.lutProperties = std::move(aidlProperties); - switch (auto error = hwcLayer->setLuts(luts)) { case hal::Error::NONE: break; diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index dbffe80a3a..ca262ee16a 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -541,6 +541,9 @@ struct OutputLayerPartialMockForUpdateCompositionState : public impl::OutputLaye MOCK_CONST_METHOD1(calculateOutputSourceCrop, FloatRect(uint32_t)); MOCK_CONST_METHOD0(calculateOutputDisplayFrame, Rect()); MOCK_CONST_METHOD1(calculateOutputRelativeBufferTransform, uint32_t(uint32_t)); + MOCK_METHOD(void, updateLuts, + (const LayerFECompositionState&, + const std::optional<std::vector<std::optional<LutProperties>>>&)); // compositionengine::OutputLayer overrides const compositionengine::Output& getOutput() const override { return mOutput; } @@ -985,21 +988,24 @@ TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoFECompositionState) { EXPECT_CALL(mLayerFE, getCompositionState()).WillOnce(Return(nullptr)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCState) { mOutputLayer.editState().hwc.reset(); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCLayer) { mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc(nullptr); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) { @@ -1010,7 +1016,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) { EXPECT_CALL(mLayerFE, hasRoundedCorners()).WillOnce(Return(false)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerTest, displayInstallOrientationBufferTransformSetTo90) { @@ -1041,7 +1048,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) { expectSetColorCall(); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) { @@ -1052,7 +1060,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) { expectSetCompositionTypeCall(Composition::SIDEBAND); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) { @@ -1063,7 +1072,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) { expectSetCompositionTypeCall(Composition::CURSOR); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) { @@ -1074,7 +1084,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) { expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) { @@ -1087,7 +1098,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) { expectNoSetCompositionTypeCall(); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransformNotSupported) { @@ -1098,7 +1110,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransf expectSetCompositionTypeCall(Composition::CLIENT); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompositionForced) { @@ -1111,7 +1124,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompo expectSetCompositionTypeCall(Composition::CLIENT); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) { @@ -1125,7 +1139,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, allStateIncludesMetadataIfPresent) { expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPresent) { @@ -1137,7 +1152,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, perFrameStateDoesNotIncludeMetadataIfPres expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerDoesNotSendBuffer) { @@ -1152,7 +1168,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerDoesNotSendBuffer) { expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerForSolidColorDoesNotSendBuffer) { @@ -1167,7 +1184,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, overriddenSkipLayerForSolidColorDoesNotSe expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) { @@ -1182,7 +1200,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoIfPresent) { expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoForSolidColorIfPresent) { @@ -1197,7 +1216,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, includesOverrideInfoForSolidColorIfPresen expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, previousOverriddenLayerSendsSurfaceDamage) { @@ -1211,7 +1231,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, previousOverriddenLayerSendsSurfaceDamage expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, previousSkipLayerSendsUpdatedDeviceCompositionInfo) { @@ -1227,7 +1248,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, previousSkipLayerSendsUpdatedDeviceCompos expectSetCompositionTypeCall(Composition::DEVICE); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, previousSkipLayerSendsUpdatedClientCompositionInfo) { @@ -1244,7 +1266,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, previousSkipLayerSendsUpdatedClientCompos expectSetCompositionTypeCall(Composition::CLIENT); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, peekThroughChangesBlendMode) { @@ -1258,7 +1281,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, peekThroughChangesBlendMode) { expectPerFrameCommonCalls(); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, isPeekingThroughSetsOverride) { @@ -1266,7 +1290,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, isPeekingThroughSetsOverride) { expectPerFrameCommonCalls(); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ true); + /*zIsOverridden*/ false, /*isPeekingThrough*/ true, + /*hasLutsProperties*/ false); EXPECT_TRUE(mOutputLayer.getState().hwc->stateOverridden); } @@ -1276,7 +1301,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, zIsOverriddenSetsOverride) { mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, /*zIsOverridden*/ true, /*isPeekingThrough*/ - false); + false, /*hasLutsProperties*/ false); EXPECT_TRUE(mOutputLayer.getState().hwc->stateOverridden); } @@ -1288,7 +1313,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, roundedCornersForceClientComposition) { mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, /*zIsOverridden*/ false, /*isPeekingThrough*/ - false); + false, /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, roundedCornersPeekingThroughAllowsDeviceComposition) { @@ -1301,7 +1326,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, roundedCornersPeekingThroughAllowsDeviceC mLayerFEState.compositionType = Composition::DEVICE; mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, /*zIsOverridden*/ false, /*isPeekingThrough*/ - true); + true, /*hasLutsProperties*/ false); EXPECT_EQ(Composition::DEVICE, mOutputLayer.getState().hwc->hwcCompositionType); } @@ -1318,7 +1343,7 @@ TEST_F(OutputLayerWriteStateToHWCTest, setBlockingRegion) { mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, /*zIsOverridden*/ false, /*isPeekingThrough*/ - false); + false, /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, setCompositionTypeRefreshRateIndicator) { @@ -1330,7 +1355,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, setCompositionTypeRefreshRateIndicator) { expectSetCompositionTypeCall(Composition::REFRESH_RATE_INDICATOR); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, setsPictureProfileWhenCommitted) { @@ -1349,7 +1375,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, setsPictureProfileWhenCommitted) { mOutputLayer.commitPictureProfileToCompositionState(); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, doesNotSetPictureProfileWhenNotCommitted) { @@ -1367,7 +1394,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, doesNotSetPictureProfileWhenNotCommitted) EXPECT_CALL(*mHwcLayer, setPictureProfileHandle(_)).Times(0); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } TEST_F(OutputLayerWriteStateToHWCTest, doesNotSetPictureProfileWhenNotCommittedLater) { @@ -1386,7 +1414,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, doesNotSetPictureProfileWhenNotCommittedL mOutputLayer.commitPictureProfileToCompositionState(); mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); expectGeometryCommonCalls(); expectPerFrameCommonCalls(); @@ -1395,7 +1424,8 @@ TEST_F(OutputLayerWriteStateToHWCTest, doesNotSetPictureProfileWhenNotCommittedL EXPECT_CALL(*mHwcLayer, setPictureProfileHandle(PictureProfileHandle(1))).Times(0); // No committing of picture profile before writing the state mOutputLayer.writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); } /* @@ -1441,21 +1471,24 @@ TEST_F(OutputLayerUncacheBufferTest, canUncacheAndReuseSlot) { mLayerFEState.buffer = kBuffer1; EXPECT_CALL(mHwcLayer, setBuffer(/*slot*/ 0, kBuffer1, kFence)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); Mock::VerifyAndClearExpectations(&mHwcLayer); // Buffer2 is stored in slot 1 mLayerFEState.buffer = kBuffer2; EXPECT_CALL(mHwcLayer, setBuffer(/*slot*/ 1, kBuffer2, kFence)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); Mock::VerifyAndClearExpectations(&mHwcLayer); // Buffer3 is stored in slot 2 mLayerFEState.buffer = kBuffer3; EXPECT_CALL(mHwcLayer, setBuffer(/*slot*/ 2, kBuffer3, kFence)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); Mock::VerifyAndClearExpectations(&mHwcLayer); // Buffer2 becomes the active buffer again (with a nullptr) and reuses slot 1 @@ -1463,7 +1496,8 @@ TEST_F(OutputLayerUncacheBufferTest, canUncacheAndReuseSlot) { sp<GraphicBuffer> nullBuffer = nullptr; EXPECT_CALL(mHwcLayer, setBuffer(/*slot*/ 1, nullBuffer, kFence)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); Mock::VerifyAndClearExpectations(&mHwcLayer); // Buffer slots are cleared @@ -1481,7 +1515,8 @@ TEST_F(OutputLayerUncacheBufferTest, canUncacheAndReuseSlot) { mLayerFEState.buffer = kBuffer1; EXPECT_CALL(mHwcLayer, setBuffer(/*slot*/ 1, kBuffer1, kFence)); mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false); Mock::VerifyAndClearExpectations(&mHwcLayer); } diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 442b603ca0..09ad9fa497 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -813,19 +813,22 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerContentForAllLayers updateCompositionState(false, false, ui::Transform::ROT_180, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_180, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); injectOutputLayer(layer1); @@ -852,17 +855,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, updatesLayerGeometryAndContentF EXPECT_CALL(*layer1.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(true, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); injectOutputLayer(layer1); @@ -888,17 +894,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, forcesClientCompositionForAllLa EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); injectOutputLayer(layer1); @@ -932,7 +941,8 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) { uint32_t z = 0; EXPECT_CALL(*layer0.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer0.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); // After calling planComposition (which clears overrideInfo), this test sets @@ -942,15 +952,17 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, peekThroughLayerChangesOrder) { EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, /*zIsOverridden*/ true, /*isPeekingThrough*/ - true)); + true, /*hasLutsProperties*/ false)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ false, z++, - /*zIsOverridden*/ true, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ true, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ true, /*skipLayer*/ true, z++, - /*zIsOverridden*/ true, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ true, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); injectOutputLayer(layer0); @@ -4962,12 +4974,14 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, noBackgroundBlurWhenOpaque) { EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); layer2.layerFEState.backgroundBlurRadius = 10; @@ -4996,17 +5010,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBackgroundBlurRequests) EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); layer2.layerFEState.backgroundBlurRadius = 10; @@ -5036,17 +5053,20 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) { EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0, _)); EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, z++, - /*zIsOverridden*/ false, /*isPeekingThrough*/ false)); + /*zIsOverridden*/ false, /*isPeekingThrough*/ false, + /*hasLutsProperties*/ false)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); BlurRegion region; @@ -5080,14 +5100,14 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, assignsDisplayProfileBasedOnLay InjectedLayer layer1; injectOutputLayer(layer1); PictureProfileHandle profileForLayer1(1); - EXPECT_CALL(*layer1.outputLayer, getPictureProfilePriority()).WillRepeatedly(Return(3)); + EXPECT_CALL(*layer1.outputLayer, getPictureProfilePriority()).WillRepeatedly(Return(1)); EXPECT_CALL(*layer1.outputLayer, getPictureProfileHandle()) .WillRepeatedly(ReturnRef(profileForLayer1)); InjectedLayer layer2; injectOutputLayer(layer2); PictureProfileHandle profileForLayer2(2); - EXPECT_CALL(*layer2.outputLayer, getPictureProfilePriority()).WillRepeatedly(Return(1)); + EXPECT_CALL(*layer2.outputLayer, getPictureProfilePriority()).WillRepeatedly(Return(3)); EXPECT_CALL(*layer2.outputLayer, getPictureProfileHandle()) .WillRepeatedly(ReturnRef(profileForLayer2)); @@ -5101,13 +5121,13 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, assignsDisplayProfileBasedOnLay // Because StrictMock EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer1.outputLayer, updateCompositionState(_, _, _, _)); - EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(_, _, _, _, _, _)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(_, _, _, _)); - EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(_, _, _, _, _, _)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(_, _, _, _)); - EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(_, _, _, _, _, _)); // No layer picture profiles should be committed EXPECT_CALL(*layer1.outputLayer, commitPictureProfileToCompositionState).Times(0); @@ -5143,14 +5163,14 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, assignsLayerProfileBasedOnLayer InjectedLayer layer1; injectOutputLayer(layer1); PictureProfileHandle profileForLayer1(1); - EXPECT_CALL(*layer1.outputLayer, getPictureProfilePriority()).WillRepeatedly(Return(3)); + EXPECT_CALL(*layer1.outputLayer, getPictureProfilePriority()).WillRepeatedly(Return(1)); EXPECT_CALL(*layer1.outputLayer, getPictureProfileHandle()) .WillRepeatedly(ReturnRef(profileForLayer1)); InjectedLayer layer2; injectOutputLayer(layer2); PictureProfileHandle profileForLayer2(2); - EXPECT_CALL(*layer2.outputLayer, getPictureProfilePriority()).WillRepeatedly(Return(1)); + EXPECT_CALL(*layer2.outputLayer, getPictureProfilePriority()).WillRepeatedly(Return(3)); EXPECT_CALL(*layer2.outputLayer, getPictureProfileHandle()) .WillRepeatedly(ReturnRef(profileForLayer2)); @@ -5164,13 +5184,13 @@ TEST_F(OutputUpdateAndWriteCompositionStateTest, assignsLayerProfileBasedOnLayer // Because StrictMock EXPECT_CALL(*layer1.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer1.outputLayer, updateCompositionState(_, _, _, _)); - EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(_, _, _, _, _, _)); EXPECT_CALL(*layer2.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer2.outputLayer, updateCompositionState(_, _, _, _)); - EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(_, _, _, _, _, _)); EXPECT_CALL(*layer3.outputLayer, requiresClientComposition()).WillRepeatedly(Return(false)); EXPECT_CALL(*layer3.outputLayer, updateCompositionState(_, _, _, _)); - EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(_, _, _, _, _)); + EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(_, _, _, _, _, _)); // The two highest priority layers should have their picture profiles committed EXPECT_CALL(*layer1.outputLayer, commitPictureProfileToCompositionState).Times(0); diff --git a/services/surfaceflinger/Display/DisplaySnapshot.cpp b/services/surfaceflinger/Display/DisplaySnapshot.cpp index 0c7a58ee71..39607400d6 100644 --- a/services/surfaceflinger/Display/DisplaySnapshot.cpp +++ b/services/surfaceflinger/Display/DisplaySnapshot.cpp @@ -26,11 +26,12 @@ namespace android::display { -DisplaySnapshot::DisplaySnapshot(PhysicalDisplayId displayId, +DisplaySnapshot::DisplaySnapshot(PhysicalDisplayId displayId, uint8_t port, ui::DisplayConnectionType connectionType, DisplayModes&& displayModes, ui::ColorModes&& colorModes, std::optional<DeviceProductInfo>&& deviceProductInfo) : mDisplayId(displayId), + mPort(port), mConnectionType(connectionType), mDisplayModes(std::move(displayModes)), mColorModes(std::move(colorModes)), @@ -62,6 +63,8 @@ ui::ColorModes DisplaySnapshot::filterColorModes(bool supportsWideColor) const { void DisplaySnapshot::dump(utils::Dumper& dumper) const { using namespace std::string_view_literals; + dumper.dump("port"sv, mPort); + dumper.dump("connectionType"sv, ftl::enum_string(mConnectionType)); dumper.dump("colorModes"sv); diff --git a/services/surfaceflinger/Display/DisplaySnapshot.h b/services/surfaceflinger/Display/DisplaySnapshot.h index 23471f5d8e..0030aad91e 100644 --- a/services/surfaceflinger/Display/DisplaySnapshot.h +++ b/services/surfaceflinger/Display/DisplaySnapshot.h @@ -16,6 +16,7 @@ #pragma once +#include <cstdint> #include <optional> #include <ui/ColorMode.h> @@ -30,13 +31,14 @@ namespace android::display { // Immutable state of a physical display, captured on hotplug. class DisplaySnapshot { public: - DisplaySnapshot(PhysicalDisplayId, ui::DisplayConnectionType, DisplayModes&&, ui::ColorModes&&, - std::optional<DeviceProductInfo>&&); + DisplaySnapshot(PhysicalDisplayId, uint8_t, ui::DisplayConnectionType, DisplayModes&&, + ui::ColorModes&&, std::optional<DeviceProductInfo>&&); DisplaySnapshot(const DisplaySnapshot&) = delete; DisplaySnapshot(DisplaySnapshot&&) = default; PhysicalDisplayId displayId() const { return mDisplayId; } + uint8_t port() const { return mPort; } ui::DisplayConnectionType connectionType() const { return mConnectionType; } std::optional<DisplayModeId> translateModeId(hal::HWConfigId) const; @@ -51,6 +53,7 @@ public: private: const PhysicalDisplayId mDisplayId; + const uint8_t mPort; const ui::DisplayConnectionType mConnectionType; // Effectively const except in move constructor. diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp index 25f6513ffa..8529c72419 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp @@ -1678,6 +1678,29 @@ Error AidlComposer::setLayerPictureProfileId(Display display, Layer layer, Pictu return error; } +Error AidlComposer::getLuts(Display display, const std::vector<sp<GraphicBuffer>>& buffers, + std::vector<aidl::android::hardware::graphics::composer3::Luts>* luts) { + std::vector<aidl::android::hardware::graphics::composer3::Buffer> aidlBuffers; + aidlBuffers.reserve(buffers.size()); + + for (auto& buffer : buffers) { + if (buffer.get()) { + aidl::android::hardware::graphics::composer3::Buffer aidlBuffer; + aidlBuffer.handle.emplace(::android::dupToAidl(buffer->getNativeBuffer()->handle)); + aidlBuffers.emplace_back(std::move(aidlBuffer)); + } + } + + const auto status = + mAidlComposerClient->getLuts(translate<int64_t>(display), aidlBuffers, luts); + if (!status.isOk()) { + ALOGE("getLuts failed %s", status.getDescription().c_str()); + return static_cast<Error>(status.getServiceSpecificError()); + } + + return Error::NONE; +} + ftl::Optional<std::reference_wrapper<ComposerClientWriter>> AidlComposer::getWriter(Display display) REQUIRES_SHARED(mMutex) { return mWriters.get(display); diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h index 6b5ebc59a3..82006f407b 100644 --- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h @@ -245,6 +245,8 @@ public: Error getMaxLayerPictureProfiles(Display, int32_t* outMaxProfiles) override; Error setDisplayPictureProfileId(Display, PictureProfileId id) override; Error setLayerPictureProfileId(Display, Layer, PictureProfileId id) override; + Error getLuts(Display, const std::vector<sp<GraphicBuffer>>&, + std::vector<aidl::android::hardware::graphics::composer3::Luts>*) override; private: // Many public functions above simply write a command into the command diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h index ff292fa350..6e431bb878 100644 --- a/services/surfaceflinger/DisplayHardware/ComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h @@ -46,6 +46,7 @@ #include <aidl/android/hardware/graphics/composer3/DisplayConfiguration.h> #include <aidl/android/hardware/graphics/composer3/DisplayLuts.h> #include <aidl/android/hardware/graphics/composer3/IComposerCallback.h> +#include <aidl/android/hardware/graphics/composer3/Luts.h> #include <aidl/android/hardware/graphics/composer3/OverlayProperties.h> #include <optional> @@ -313,6 +314,8 @@ public: virtual Error getMaxLayerPictureProfiles(Display display, int32_t* outMaxProfiles) = 0; virtual Error setDisplayPictureProfileId(Display display, PictureProfileId id) = 0; virtual Error setLayerPictureProfileId(Display display, Layer layer, PictureProfileId id) = 0; + virtual Error getLuts(Display display, const std::vector<sp<GraphicBuffer>>&, + std::vector<V3_0::Luts>*) = 0; }; } // namespace Hwc2 diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp index 081f4aa269..99a67e4b26 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.cpp +++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp @@ -669,6 +669,12 @@ Error Display::setPictureProfileHandle(const PictureProfileHandle& handle) { return static_cast<Error>(error); } +Error Display::getLuts(const std::vector<sp<GraphicBuffer>>& buffers, + std::vector<aidl::android::hardware::graphics::composer3::Luts>* outLuts) { + const auto error = mComposer.getLuts(mId, buffers, outLuts); + return static_cast<Error>(error); +} + // For use by Device void Display::setConnected(bool connected) { diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 6740d8a832..c3deb8429a 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -203,6 +203,9 @@ public: [[nodiscard]] virtual hal::Error getMaxLayerPictureProfiles(int32_t* maxProfiles) = 0; [[nodiscard]] virtual hal::Error setPictureProfileHandle( const PictureProfileHandle& handle) = 0; + [[nodiscard]] virtual hal::Error getLuts( + const std::vector<android::sp<android::GraphicBuffer>>&, + std::vector<aidl::android::hardware::graphics::composer3::Luts>*) = 0; }; namespace impl { @@ -288,6 +291,8 @@ public: hal::Error setIdleTimerEnabled(std::chrono::milliseconds timeout) override; hal::Error getMaxLayerPictureProfiles(int32_t* maxProfiles) override; hal::Error setPictureProfileHandle(const android::PictureProfileHandle& handle) override; + hal::Error getLuts(const std::vector<android::sp<android::GraphicBuffer>>&, + std::vector<aidl::android::hardware::graphics::composer3::Luts>*) override; // Other Display methods hal::HWDisplayId getId() const override { return mId; } diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 55ccdefa7a..7f94428617 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -1046,6 +1046,16 @@ status_t HWComposer::setDisplayPictureProfileHandle(PhysicalDisplayId displayId, return NO_ERROR; } +status_t HWComposer::getLuts( + PhysicalDisplayId displayId, const std::vector<sp<GraphicBuffer>>& buffers, + std::vector<aidl::android::hardware::graphics::composer3::Luts>* luts) { + RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); + auto& hwcDisplay = mDisplayData[displayId].hwcDisplay; + auto error = hwcDisplay->getLuts(buffers, luts); + RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR); + return NO_ERROR; +} + const std::unordered_map<std::string, bool>& HWComposer::getSupportedLayerGenericMetadata() const { return mSupportedLayerGenericMetadata; } @@ -1180,6 +1190,7 @@ std::optional<DisplayIdentificationInfo> HWComposer::onHotplugConnect( return DisplayIdentificationInfo{.id = PhysicalDisplayId::fromPort(port), .name = isPrimary ? "Primary display" : "Secondary display", + .port = port, .deviceProductInfo = std::nullopt}; }(); diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index 52662cffbb..b1b997a197 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -55,6 +55,7 @@ #include <aidl/android/hardware/graphics/composer3/DisplayCapability.h> #include <aidl/android/hardware/graphics/composer3/DisplayLuts.h> #include <aidl/android/hardware/graphics/composer3/LutProperties.h> +#include <aidl/android/hardware/graphics/composer3/Luts.h> #include <aidl/android/hardware/graphics/composer3/OutputType.h> #include <aidl/android/hardware/graphics/composer3/OverlayProperties.h> @@ -324,6 +325,8 @@ public: virtual int32_t getMaxLayerPictureProfiles(PhysicalDisplayId) = 0; virtual status_t setDisplayPictureProfileHandle(PhysicalDisplayId, const PictureProfileHandle& handle) = 0; + virtual status_t getLuts(PhysicalDisplayId, const std::vector<sp<GraphicBuffer>>&, + std::vector<aidl::android::hardware::graphics::composer3::Luts>*) = 0; }; static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs, @@ -491,6 +494,8 @@ public: int32_t getMaxLayerPictureProfiles(PhysicalDisplayId) override; status_t setDisplayPictureProfileHandle(PhysicalDisplayId, const android::PictureProfileHandle& profile) override; + status_t getLuts(PhysicalDisplayId, const std::vector<sp<GraphicBuffer>>&, + std::vector<aidl::android::hardware::graphics::composer3::Luts>*) override; // for debugging ---------------------------------------------------------- void dump(std::string& out) const override; diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp index 5703a2d37c..ec155392eb 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp @@ -1452,6 +1452,11 @@ Error HidlComposer::getMaxLayerPictureProfiles(Display, int32_t*) { return Error::UNSUPPORTED; } +Error HidlComposer::getLuts(Display, const std::vector<sp<GraphicBuffer>>&, + std::vector<aidl::android::hardware::graphics::composer3::Luts>*) { + return Error::UNSUPPORTED; +} + Error HidlComposer::setDisplayPictureProfileId(Display, PictureProfileId) { return Error::UNSUPPORTED; } diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h index 42ba9a957b..cacdb8ce52 100644 --- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h +++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h @@ -359,6 +359,8 @@ public: Error getMaxLayerPictureProfiles(Display, int32_t* outMaxProfiles) override; Error setDisplayPictureProfileId(Display, PictureProfileId) override; Error setLayerPictureProfileId(Display, Layer, PictureProfileId) override; + Error getLuts(Display, const std::vector<sp<GraphicBuffer>>&, + std::vector<aidl::android::hardware::graphics::composer3::Luts>*) override; private: class CommandWriter : public CommandWriterBase { diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp index 58f6b96e57..367132c113 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp @@ -418,7 +418,7 @@ void LayerSnapshot::merge(const RequestedLayerState& requested, bool forceUpdate } if (forceUpdate || requested.what & layer_state_t::eAppContentPriorityChanged) { // TODO(b/337330263): Also consider the system-determined priority of the app - pictureProfilePriority = requested.appContentPriority; + pictureProfilePriority = int64_t(requested.appContentPriority) + INT_MAX; } if (forceUpdate || requested.what & layer_state_t::eDefaultFrameRateCompatibilityChanged) { diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp index 4d9a9ca06e..022588deef 100644 --- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp +++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp @@ -262,7 +262,10 @@ void updateVisibility(LayerSnapshot& snapshot, bool visible) { snapshot.isVisible = visible; if (FlagManager::getInstance().skip_invisible_windows_in_input()) { - snapshot.inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, !visible); + const bool visibleForInput = + snapshot.isVisible || (snapshot.hasInputInfo() && !snapshot.isHiddenByPolicy()); + snapshot.inputInfo.setInputConfig(gui::WindowInfo::InputConfig::NOT_VISIBLE, + !visibleForInput); } else { // TODO(b/238781169) we are ignoring this compat for now, since we will have // to remove any optimization based on visibility. diff --git a/services/surfaceflinger/PowerAdvisor/Common.h b/services/surfaceflinger/PowerAdvisor/Common.h new file mode 100644 index 0000000000..b4a87dd9a4 --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/Common.h @@ -0,0 +1,28 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" +#include <aidl/android/adpf/ISessionManager.h> +#include <aidl/android/hardware/power/CompositionData.h> +#pragma clang diagnostic pop + +namespace android::adpf { +using namespace ::aidl::android::adpf; +namespace hal = ::aidl::android::hardware::power; +} // namespace android::adpf diff --git a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp index c7d0b2c9ef..ff452723d5 100644 --- a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp +++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.cpp @@ -28,22 +28,19 @@ #include <optional> #include <android-base/properties.h> +#include <android/binder_libbinder.h> #include <common/trace.h> #include <utils/Log.h> #include <utils/Mutex.h> #include <binder/IServiceManager.h> -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" #include <powermanager/PowerHalController.h> #include <powermanager/PowerHintSessionWrapper.h> -#pragma clang diagnostic pop #include <common/FlagManager.h> #include "PowerAdvisor.h" - -namespace hal = aidl::android::hardware::power; +#include "SessionManager.h" namespace android::adpf::impl { @@ -545,6 +542,18 @@ void PowerAdvisor::setTotalFrameTargetWorkDuration(Duration targetDuration) { mTotalFrameTargetDuration = targetDuration; } +std::shared_ptr<SessionManager> PowerAdvisor::getSessionManager() { + return mSessionManager; +} + +sp<IBinder> PowerAdvisor::getOrCreateSessionManagerForBinder(uid_t uid) { + // Flag guards the creation of SessionManager + if (mSessionManager == nullptr && FlagManager::getInstance().adpf_native_session_manager()) { + mSessionManager = ndk::SharedRefBase::make<SessionManager>(uid); + } + return AIBinder_toPlatformBinder(mSessionManager->asBinder().get()); +} + std::vector<DisplayId> PowerAdvisor::getOrderedDisplayIds( std::optional<TimePoint> DisplayTimingData::*sortBy) { std::vector<DisplayId> sortedDisplays; diff --git a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h index 458b46d500..43fc21093f 100644 --- a/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h +++ b/services/surfaceflinger/PowerAdvisor/PowerAdvisor.h @@ -36,6 +36,8 @@ #include <ui/DisplayIdentification.h> #include "../Scheduler/OneShotTimer.h" +#include "SessionManager.h" + using namespace std::chrono_literals; namespace android { @@ -47,6 +49,8 @@ class PowerHintSessionWrapper; namespace adpf { +namespace hal = aidl::android::hardware::power; + class PowerAdvisor { public: virtual ~PowerAdvisor() = default; @@ -102,12 +106,18 @@ public: virtual void setDisplays(std::vector<DisplayId>& displayIds) = 0; // Sets the target duration for the entire pipeline including the gpu virtual void setTotalFrameTargetWorkDuration(Duration targetDuration) = 0; + // Get the session manager, if it exists + virtual std::shared_ptr<SessionManager> getSessionManager() = 0; // --- The following methods may run on threads besides SF main --- // Send a hint about an upcoming increase in the CPU workload virtual void notifyCpuLoadUp() = 0; // Send a hint about the imminent start of a new CPU workload virtual void notifyDisplayUpdateImminentAndCpuReset() = 0; + + // --- The following methods specifically run on binder threads --- + // Retrieve a SessionManager for HintManagerService to call + virtual sp<IBinder> getOrCreateSessionManagerForBinder(uid_t uid) = 0; }; namespace impl { @@ -146,11 +156,15 @@ public: void setCompositeEnd(TimePoint compositeEndTime) override; void setDisplays(std::vector<DisplayId>& displayIds) override; void setTotalFrameTargetWorkDuration(Duration targetDuration) override; + std::shared_ptr<SessionManager> getSessionManager() override; // --- The following methods may run on threads besides SF main --- void notifyCpuLoadUp() override; void notifyDisplayUpdateImminentAndCpuReset() override; + // --- The following methods specifically run on binder threads --- + sp<IBinder> getOrCreateSessionManagerForBinder(uid_t uid) override; + private: friend class PowerAdvisorTest; @@ -323,6 +337,8 @@ private: template <aidl::android::hardware::power::ChannelMessage::ChannelMessageContents::Tag T, class In> bool writeHintSessionMessage(In* elements, size_t count) REQUIRES(mHintSessionMutex); + + std::shared_ptr<SessionManager> mSessionManager; }; } // namespace impl diff --git a/services/surfaceflinger/PowerAdvisor/SessionLayerMap.cpp b/services/surfaceflinger/PowerAdvisor/SessionLayerMap.cpp new file mode 100644 index 0000000000..9f95163e2b --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/SessionLayerMap.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SessionLayerMap.h" +#include <android/binder_libbinder.h> + +namespace android::adpf { + +void SessionLayerMap::notifySessionsDied(std::vector<int32_t>& sessionIds) { + for (int id : sessionIds) { + auto&& iter = mSessions.find(id); + if (iter != mSessions.end()) { + mSessions.erase(iter); + } + } +} + +void SessionLayerMap::notifyLayersDied(std::vector<int32_t>& layers) { + for (auto&& layer : layers) { + auto&& iter = mLayers.find(layer); + if (iter != mLayers.end()) { + mLayers.erase(iter); + } + } +} + +bool SessionLayerMap::bindSessionIDToLayers(int sessionId, const std::vector<int32_t>& layerIds) { + // If there is no association, just drop from map + if (layerIds.empty()) { + mSessions.erase(sessionId); + return false; + } + + // Ensure session exists + if (!mSessions.contains(sessionId)) { + mSessions.emplace(sessionId, MappedType(sessionId, mLayers)); + } + + MappedType& session = mSessions.at(sessionId); + std::set<int32_t> newLinks; + + // For each incoming link + for (auto&& layerId : layerIds) { + auto&& iter = mLayers.find(layerId); + + // If it's not in the map, add it + if (iter == mLayers.end()) { + mLayers.emplace(layerId, MappedType(layerId, mSessions)); + } + + // Make a ref to it in the session's new association map + newLinks.insert(layerId); + } + + session.swapLinks(std::move(newLinks)); + return true; +} + +void SessionLayerMap::getAssociatedSessions(int32_t layerId, std::vector<int32_t>& sessionIdsOut) { + sessionIdsOut.clear(); + auto&& iter = mLayers.find(layerId); + + if (iter == mLayers.end()) { + return; + } + + // Dump the internal association set into this vector + sessionIdsOut.insert(sessionIdsOut.begin(), iter->second.mLinks.begin(), + iter->second.mLinks.end()); +} + +void SessionLayerMap::getCurrentlyRelevantLayers( + std::unordered_set<int32_t>& currentlyRelevantLayers) { + currentlyRelevantLayers.clear(); + for (auto&& layer : mLayers) { + currentlyRelevantLayers.insert(layer.first); + } +} + +} // namespace android::adpf
\ No newline at end of file diff --git a/services/surfaceflinger/PowerAdvisor/SessionLayerMap.h b/services/surfaceflinger/PowerAdvisor/SessionLayerMap.h new file mode 100644 index 0000000000..51808a65fc --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/SessionLayerMap.h @@ -0,0 +1,111 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <log/log.h> +#include <set> +#include <unordered_map> +#include <unordered_set> + +namespace android::adpf { + +class SessionLayerMap { +public: + // Inform the SessionLayerMap about dead sessions + void notifySessionsDied(std::vector<int32_t>& sessionIds); + // Inform the SessionLayerMap about dead layers + void notifyLayersDied(std::vector<int32_t>& layers); + // Associate a session with a specific set of layer ids + bool bindSessionIDToLayers(int sessionId, const std::vector<int32_t>& layerIds); + // Get the set of sessions that are mapped to a specific layer id + void getAssociatedSessions(int32_t layerId, std::vector<int32_t>& sessionIdsOut); + // Get the set of layers that are currently being tracked + void getCurrentlyRelevantLayers(std::unordered_set<int32_t>& currentlyRelevantLayers); + +private: + struct MappedType { + MappedType(int32_t id, std::unordered_map<int32_t, MappedType>& otherList) + : mId(id), mOtherList(otherList) {}; + MappedType() = delete; + ~MappedType() { swapLinks({}); } + + // Replace the set of associated IDs for this mapped type with a different set of IDs, + // updating only associations which have changed between the two sets + void swapLinks(std::set<int32_t>&& incoming) { + auto&& oldIter = mLinks.begin(); + auto&& newIter = incoming.begin(); + + // Dump all outdated values and insert new ones + while (oldIter != mLinks.end() || newIter != incoming.end()) { + // If there is a value in the new set but not the old set + // We should have already ensured what we're linking to exists + if (oldIter == mLinks.end() || (newIter != incoming.end() && *newIter < *oldIter)) { + addRemoteAssociation(*newIter); + ++newIter; + continue; + } + + // If there is a value in the old set but not the new set + if (newIter == incoming.end() || (oldIter != mLinks.end() && *oldIter < *newIter)) { + dropRemoteAssociation(*oldIter); + ++oldIter; + continue; + } + + // If they're the same, skip + if (*oldIter == *newIter) { + ++oldIter; + ++newIter; + continue; + } + } + + mLinks.swap(incoming); + } + + void addRemoteAssociation(int32_t other) { + auto&& iter = mOtherList.find(other); + if (iter != mOtherList.end()) { + iter->second.mLinks.insert(mId); + } else { + ALOGE("Existing entry in SessionLayerMap, link failed"); + } + } + + void dropRemoteAssociation(int32_t other) { + auto&& iter = mOtherList.find(other); + if (iter != mOtherList.end()) { + iter->second.mLinks.erase(mId); + if (iter->second.mLinks.empty()) { + // This only erases them from the map, not from general tracking + mOtherList.erase(iter); + } + } else { + ALOGE("Missing entry in SessionLayerMap, unlinking failed"); + } + } + + int32_t mId; + std::set<int> mLinks; + std::unordered_map<int32_t, MappedType>& mOtherList; + }; + + std::unordered_map<int32_t, MappedType> mSessions; + std::unordered_map<int32_t, MappedType> mLayers; +}; + +} // namespace android::adpf diff --git a/services/surfaceflinger/PowerAdvisor/SessionManager.cpp b/services/surfaceflinger/PowerAdvisor/SessionManager.cpp new file mode 100644 index 0000000000..a855f07914 --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/SessionManager.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PowerAdvisor/SessionManager.h" +#include <android/binder_libbinder.h> +#include <android/binder_status.h> +#include <binder/IPCThreadState.h> +#include "FrontEnd/LayerHandle.h" +#include "Layer.h" +#include "SurfaceFlinger.h" + +namespace android::adpf { + +SessionManager::SessionManager(uid_t uid) : mUid(uid) {} + +ndk::ScopedAStatus SessionManager::associateSessionToLayers( + int32_t sessionId, int32_t ownerUid, const std::vector<::ndk::SpAIBinder>& layerTokens) { + std::scoped_lock lock{mSessionManagerMutex}; + + std::vector<int32_t> layerIds; + + for (auto&& token : layerTokens) { + auto platformToken = AIBinder_toPlatformBinder(token.get()); + + // Get the layer id for it + int32_t layerId = + static_cast<int32_t>(surfaceflinger::LayerHandle::getLayerId(platformToken)); + auto&& iter = mTrackedLayerData.find(layerId); + + // Ensure it is being tracked + if (iter == mTrackedLayerData.end()) { + mTrackedLayerData.emplace(layerId, LayerData{.layerId = layerId}); + } + layerIds.push_back(layerId); + } + + // Register the session then track it + if (mMap.bindSessionIDToLayers(sessionId, layerIds) && + !mTrackedSessionData.contains(sessionId)) { + mTrackedSessionData.emplace(sessionId, + SessionData{.sessionId = sessionId, .uid = ownerUid}); + } + return ndk::ScopedAStatus::ok(); +} + +ndk::ScopedAStatus SessionManager::trackedSessionsDied(const std::vector<int32_t>& sessionIds) { + std::scoped_lock lock{mSessionManagerMutex}; + for (int sessionId : sessionIds) { + mDeadSessions.push_back(sessionId); + mTrackedSessionData.erase(sessionId); + } + + return ndk::ScopedAStatus::ok(); +} + +void SessionManager::updateTrackingState( + const std::vector<std::pair<uint32_t, std::string>>& handles) { + std::scoped_lock lock{mSessionManagerMutex}; + std::vector<int32_t> deadLayers; + for (auto&& handle : handles) { + int32_t handleId = static_cast<int32_t>(handle.first); + auto it = mTrackedLayerData.find(handleId); + if (it != mTrackedLayerData.end()) { + // Track any dead layers to remove from the mapping + mTrackedLayerData.erase(it); + deadLayers.push_back(it->first); + } + } + mMap.notifyLayersDied(deadLayers); + mMap.notifySessionsDied(mDeadSessions); + + mDeadSessions.clear(); + mMap.getCurrentlyRelevantLayers(mCurrentlyRelevantLayers); +} + +bool SessionManager::isLayerRelevant(int32_t layerId) { + return mCurrentlyRelevantLayers.contains(layerId); +} + +} // namespace android::adpf
\ No newline at end of file diff --git a/services/surfaceflinger/PowerAdvisor/SessionManager.h b/services/surfaceflinger/PowerAdvisor/SessionManager.h new file mode 100644 index 0000000000..93a80b55ab --- /dev/null +++ b/services/surfaceflinger/PowerAdvisor/SessionManager.h @@ -0,0 +1,102 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <aidl/android/adpf/BnSessionManager.h> +#include <sys/types.h> + +#include <utils/Thread.h> +#include "Common.h" +#include "SessionLayerMap.h" + +#include <string> + +namespace android { + +class Layer; + +namespace adpf { +namespace impl { + +class PowerAdvisor; + +} + +// Talks to HMS to manage sessions for PowerHAL +class SessionManager : public BnSessionManager { +public: + SessionManager(uid_t uid); + + // ISessionManager binder methods + ndk::ScopedAStatus trackedSessionsDied(const std::vector<int32_t>& in_sessionId) override; + ndk::ScopedAStatus associateSessionToLayers( + int32_t sessionId, int32_t ownerUid, + const std::vector<::ndk::SpAIBinder>& layers) override; + + // Update the lifecycles of any tracked sessions or layers. This is intended to accepts the + // "destroyedHandles" object from updateLayerSnapshots in SF, and should reflect that type + void updateTrackingState(const std::vector<std::pair<uint32_t, std::string>>& handles); + +private: + // Session metadata tracked by the mTrackedSessionData map + struct SessionData { + int32_t sessionId; + int uid; + }; + + // Layer metadata tracked by the mTrackedSessionData map + struct LayerData { + int32_t layerId; + }; + + // Checks if the layer is currently associated with a specific session in the SessionLayerMap + // This helps us know which layers might be included in an update for the HAL + bool isLayerRelevant(int32_t layerId); + + // The UID of whoever created our ISessionManager connection + const uid_t mUid; + + // State owned by the main thread + + // Set of layers that are currently being tracked in the SessionLayerMap. This is used to + // filter out which layers we actually care about during the latching process + std::unordered_set<int32_t> mCurrentlyRelevantLayers; + + // Tracks active associations between sessions and layers. Items in this map can be thought of + // as "active" connections, and any session or layer not in this map will not receive updates or + // be collected in SurfaceFlinger + SessionLayerMap mMap; + + // The list of currently-living layers which have ever been tracked, this is used to persist any + // data we want to track across potential mapping disconnects, and to determine when to send + // death updates + std::unordered_map<int32_t, LayerData> mTrackedLayerData; + + // The list of currently-living sessions which have ever been tracked, this is used to persist + // any data we want to track across mapping disconnects + std::unordered_map<int32_t, SessionData> mTrackedSessionData; + + // State owned by mSessionManagerMutex + + std::mutex mSessionManagerMutex; + + // The list of sessions that have died since we last called updateTrackingState + std::vector<int32_t> mDeadSessions GUARDED_BY(mSessionManagerMutex); +}; + +} // namespace adpf +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 21d3396ebe..d3483b0cb0 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -346,7 +346,6 @@ void RegionSamplingThread::captureSample() { constexpr bool kRegionSampling = true; constexpr bool kGrayscale = false; constexpr bool kIsProtected = false; - constexpr bool kAttachGainmap = false; SurfaceFlinger::RenderAreaBuilderVariant renderAreaBuilder(std::in_place_type<DisplayRenderAreaBuilder>, sampledBounds, @@ -358,7 +357,7 @@ void RegionSamplingThread::captureSample() { mFlinger.getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layers); FenceResult fenceResult = mFlinger.captureScreenshot(renderAreaBuilder, buffer, kRegionSampling, kGrayscale, - kIsProtected, kAttachGainmap, nullptr, displayState, layers) + kIsProtected, nullptr, displayState, layers) .get(); if (fenceResult.ok()) { fenceResult.value()->waitForever(LOG_TAG); diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index a2cdd460ca..3fdddac52a 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -209,7 +209,6 @@ public: ftl::FakeGuard guard(kMainThreadContext); resyncToHardwareVsyncLocked(id, allowToEnable, modePtr); } - void resync() override EXCLUDES(mDisplayLock); void forceNextResync() { mLastResyncTime = 0; } // Passes a vsync sample to VsyncController. Returns true if @@ -471,6 +470,7 @@ private: bool throttleVsync(TimePoint, uid_t) override; // Get frame interval Period getVsyncPeriod(uid_t) override EXCLUDES(mDisplayLock); + void resync() override EXCLUDES(mDisplayLock); void onExpectedPresentTimePosted(TimePoint expectedPresentTime) override EXCLUDES(mDisplayLock); std::unique_ptr<EventThread> mRenderEventThread; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index d7d567c6c3..e05c5bd97c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -37,6 +37,7 @@ #include <android/hardware/configstore/1.1/types.h> #include <android/native_window.h> #include <android/os/IInputFlinger.h> +#include <android_os.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/PermissionCache.h> @@ -126,7 +127,6 @@ #include <gui/SchedulingPolicy.h> #include <gui/SyncScreenCaptureListener.h> #include <ui/DisplayIdentification.h> -#include "ActivePictureUpdater.h" #include "BackgroundExecutor.h" #include "Client.h" #include "ClientCache.h" @@ -742,7 +742,10 @@ void SurfaceFlinger::bootFinished() { mBootFinished = true; FlagManager::getMutableInstance().markBootCompleted(); - ::tracing_perfetto::registerWithPerfetto(); + if (android::os::perfetto_sdk_tracing()) { + ::tracing_perfetto::registerWithPerfetto(); + } + mInitBootPropsFuture.wait(); mRenderEnginePrimeCacheFuture.wait(); @@ -1444,14 +1447,14 @@ status_t SurfaceFlinger::setActiveModeFromBackdoor(const sp<display::DisplayToke return future.get(); } -void SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { +bool SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { SFTRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str()); const auto pendingModeOpt = mDisplayModeController.getPendingMode(displayId); if (!pendingModeOpt) { // There is no pending mode change. This can happen if the active // display changed and the mode change happened on a different display. - return; + return true; } const auto& activeMode = pendingModeOpt->mode; @@ -1466,8 +1469,8 @@ void SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { state.physical->activeMode = activeMode.modePtr.get(); processDisplayChangesLocked(); - // processDisplayChangesLocked will update all necessary components so we're done here. - return; + // The DisplayDevice has been destroyed, so abort the commit for the now dead FrameTargeter. + return false; } mDisplayModeController.finalizeModeChange(displayId, activeMode.modePtr->getId(), @@ -1478,6 +1481,8 @@ void SurfaceFlinger::finalizeDisplayModeChange(PhysicalDisplayId displayId) { if (pendingModeOpt->emitEvent) { mScheduler->onDisplayModeChanged(displayId, activeMode, /*clearContentRequirements*/ true); } + + return true; } void SurfaceFlinger::dropModeRequest(PhysicalDisplayId displayId) { @@ -2659,7 +2664,10 @@ bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId, for (const auto [displayId, _] : frameTargets) { if (mDisplayModeController.isModeSetPending(displayId)) { - finalizeDisplayModeChange(displayId); + if (!finalizeDisplayModeChange(displayId)) { + mScheduler->scheduleFrame(); + return false; + } } } } @@ -2788,12 +2796,43 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays); refreshArgs.outputs.reserve(displays.size()); + // Track layer stacks of physical displays that might be added to CompositionEngine + // output. Layer stacks are not tracked in Display when we iterate through + // frameTargeters. Cross-referencing layer stacks allows us to filter out displays + // by ID with duplicate layer stacks before adding them to CompositionEngine output. + ui::DisplayMap<DisplayId, ui::LayerStack> physicalDisplayLayerStacks; + for (auto& [_, display] : displays) { + const auto id = PhysicalDisplayId::tryCast(display->getId()); + if (id && frameTargeters.contains(*id)) { + physicalDisplayLayerStacks.try_emplace(*id, display->getLayerStack()); + } + } + + // Tracks layer stacks of displays that are added to CompositionEngine output. + ui::DisplayMap<ui::LayerStack, ftl::Unit> outputLayerStacks; + auto isOutputLayerStack = [&outputLayerStacks](DisplayId id, ui::LayerStack layerStack) { + if (FlagManager::getInstance().reject_dupe_layerstacks() && + outputLayerStacks.contains(layerStack)) { + // TODO: remove log and DisplayId from params once reject_dupe_layerstacks flag is + // removed + ALOGD("Existing layer stack ID %d output to another display %" PRIu64 + ", dropping display from outputs", + layerStack.id, id.value); + return true; + } + outputLayerStacks.try_emplace(layerStack); + return false; + }; + // Add outputs for physical displays. for (const auto& [id, targeter] : frameTargeters) { ftl::FakeGuard guard(mStateLock); if (const auto display = getCompositionDisplayLocked(id)) { - refreshArgs.outputs.push_back(display); + const auto layerStack = physicalDisplayLayerStacks.get(id)->get(); + if (!isOutputLayerStack(display->getId(), layerStack)) { + refreshArgs.outputs.push_back(display); + } } refreshArgs.frameTargets.try_emplace(id, &targeter->target()); @@ -2810,7 +2849,9 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( if (!refreshRate.isValid() || mScheduler->isVsyncInPhase(pacesetterTarget.frameBeginTime(), refreshRate)) { - refreshArgs.outputs.push_back(display->getCompositionDisplay()); + if (!isOutputLayerStack(display->getId(), display->getLayerStack())) { + refreshArgs.outputs.push_back(display->getCompositionDisplay()); + } } } } @@ -2914,7 +2955,7 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( layer->setWasClientComposed(compositionResult.lastClientCompositionFence); } if (com_android_graphics_libgui_flags_apply_picture_profiles()) { - mActivePictureUpdater.onLayerComposed(*layer, *layerFE, compositionResult); + mActivePictureTracker.onLayerComposed(*layer, *layerFE, compositionResult); } } @@ -3226,8 +3267,8 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, std::vector<std::pair<std::shared_ptr<compositionengine::Display>, sp<HdrLayerInfoReporter>>> hdrInfoListeners; bool haveNewHdrInfoListeners = false; - sp<gui::IActivePictureListener> activePictureListener; - bool haveNewActivePictureListener = false; + ActivePictureTracker::Listeners activePictureListenersToAdd; + ActivePictureTracker::Listeners activePictureListenersToRemove; { Mutex::Autolock lock(mStateLock); if (mFpsReporter) { @@ -3249,9 +3290,8 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, haveNewHdrInfoListeners = mAddingHDRLayerInfoListener; // grab this with state lock mAddingHDRLayerInfoListener = false; - activePictureListener = mActivePictureListener; - haveNewActivePictureListener = mHaveNewActivePictureListener; - mHaveNewActivePictureListener = false; + std::swap(activePictureListenersToAdd, mActivePictureListenersToAdd); + std::swap(activePictureListenersToRemove, mActivePictureListenersToRemove); } if (haveNewHdrInfoListeners || mHdrLayerInfoChanged) { @@ -3315,14 +3355,10 @@ void SurfaceFlinger::onCompositionPresented(PhysicalDisplayId pacesetterId, mHdrLayerInfoChanged = false; if (com_android_graphics_libgui_flags_apply_picture_profiles()) { - // Track, update and notify changes to active pictures - layers that are undergoing picture - // processing - if (mActivePictureUpdater.updateAndHasChanged() || haveNewActivePictureListener) { - if (activePictureListener) { - activePictureListener->onActivePicturesChanged( - mActivePictureUpdater.getActivePictures()); - } - } + // Track, update and notify changes to active pictures - layers that are undergoing + // picture processing + mActivePictureTracker.updateAndNotifyListeners(activePictureListenersToAdd, + activePictureListenersToRemove); } mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */); @@ -3634,10 +3670,13 @@ std::optional<DisplayModeId> SurfaceFlinger::processHotplugConnect(PhysicalDispl deviceProductInfo = snapshot.deviceProductInfo(); } + // Use the cached port via snapshot because we are updating an existing + // display on reconnect. const auto it = mPhysicalDisplays.try_replace(displayId, display.token(), displayId, - snapshot.connectionType(), std::move(displayModes), - std::move(colorModes), std::move(deviceProductInfo)); + snapshot.port(), snapshot.connectionType(), + std::move(displayModes), std::move(colorModes), + std::move(deviceProductInfo)); auto& state = mCurrentState.displays.editValueFor(it->second.token()); state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId. @@ -3650,7 +3689,7 @@ std::optional<DisplayModeId> SurfaceFlinger::processHotplugConnect(PhysicalDispl const ui::DisplayConnectionType connectionType = getHwComposer().getDisplayConnectionType(displayId); - mPhysicalDisplays.try_emplace(displayId, token, displayId, connectionType, + mPhysicalDisplays.try_emplace(displayId, token, displayId, info.port, connectionType, std::move(displayModes), std::move(colorModes), std::move(info.deviceProductInfo)); @@ -4566,7 +4605,6 @@ void SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule sche SFTRACE_INT("mTransactionFlags", transactionFlags); if (const bool scheduled = transactionFlags & mask; !scheduled) { - mScheduler->resync(); scheduleCommit(frameHint); } else if (frameHint == FrameHint::kActive) { // Even if the next frame is already scheduled, we should reset the idle timer @@ -7149,8 +7187,7 @@ void SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args, displayWeak, options), getLayerSnapshotsFn, reqSize, static_cast<ui::PixelFormat>(captureArgs.pixelFormat), - captureArgs.allowProtected, captureArgs.grayscale, - captureArgs.attachGainmap, captureListener); + captureArgs.allowProtected, captureArgs.grayscale, captureListener); } void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args, @@ -7207,7 +7244,7 @@ void SurfaceFlinger::captureDisplay(DisplayId displayId, const CaptureArgs& args static_cast<ui::Dataspace>(args.dataspace), displayWeak, options), getLayerSnapshotsFn, size, static_cast<ui::PixelFormat>(args.pixelFormat), - kAllowProtected, kGrayscale, args.attachGainmap, captureListener); + kAllowProtected, kGrayscale, captureListener); } ScreenCaptureResults SurfaceFlinger::captureLayersSync(const LayerCaptureArgs& args) { @@ -7318,8 +7355,7 @@ void SurfaceFlinger::captureLayers(const LayerCaptureArgs& args, options), getLayerSnapshotsFn, reqSize, static_cast<ui::PixelFormat>(captureArgs.pixelFormat), - captureArgs.allowProtected, captureArgs.grayscale, - captureArgs.attachGainmap, captureListener); + captureArgs.allowProtected, captureArgs.grayscale, captureListener); } // Creates a Future release fence for a layer and keeps track of it in a list to @@ -7377,7 +7413,7 @@ std::optional<SurfaceFlinger::OutputCompositionState> SurfaceFlinger::getSnapsho void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuilder, GetLayerSnapshotsFunction getLayerSnapshotsFn, ui::Size bufferSize, ui::PixelFormat reqPixelFormat, - bool allowProtected, bool grayscale, bool attachGainmap, + bool allowProtected, bool grayscale, const sp<IScreenCaptureListener>& captureListener) { SFTRACE_CALL(); @@ -7392,6 +7428,10 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil std::vector<std::pair<Layer*, sp<LayerFE>>> layers; auto displayState = getSnapshotsFromMainThread(renderAreaBuilder, getLayerSnapshotsFn, layers); + const bool hasHdrLayer = std::any_of(layers.cbegin(), layers.cend(), [this](const auto& layer) { + return isHdrLayer(*(layer.second->mSnapshot.get())); + }); + const bool supportsProtected = getRenderEngine().supportsProtectedContent(); bool hasProtectedLayer = false; if (allowProtected && supportsProtected) { @@ -7420,9 +7460,51 @@ void SurfaceFlinger::captureScreenCommon(RenderAreaBuilderVariant renderAreaBuil renderengine::impl::ExternalTexture>(buffer, getRenderEngine(), renderengine::impl::ExternalTexture::Usage:: WRITEABLE); - auto futureFence = - captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */, grayscale, - isProtected, attachGainmap, captureListener, displayState, layers); + + std::shared_ptr<renderengine::impl::ExternalTexture> hdrTexture; + std::shared_ptr<renderengine::impl::ExternalTexture> gainmapTexture; + + bool hintForSeamless = std::visit( + [](auto&& arg) { + return arg.options.test(RenderArea::Options::HINT_FOR_SEAMLESS_TRANSITION); + }, + renderAreaBuilder); + if (hasHdrLayer && !hintForSeamless && FlagManager::getInstance().true_hdr_screenshots()) { + const auto hdrBuffer = + getFactory().createGraphicBuffer(buffer->getWidth(), buffer->getHeight(), + HAL_PIXEL_FORMAT_RGBA_FP16, 1 /* layerCount */, + buffer->getUsage(), "screenshot-hdr"); + const auto gainmapBuffer = + getFactory().createGraphicBuffer(buffer->getWidth(), buffer->getHeight(), + buffer->getPixelFormat(), 1 /* layerCount */, + buffer->getUsage(), "screenshot-gainmap"); + + const status_t hdrBufferStatus = hdrBuffer->initCheck(); + const status_t gainmapBufferStatus = gainmapBuffer->initCheck(); + + if (hdrBufferStatus != OK || gainmapBufferStatus != -OK) { + if (hdrBufferStatus != OK) { + ALOGW("%s: Buffer failed to allocate for hdr: %d. Screenshoting SDR instead.", + __func__, hdrBufferStatus); + } else { + ALOGW("%s: Buffer failed to allocate for gainmap: %d. Screenshoting SDR instead.", + __func__, gainmapBufferStatus); + } + } else { + hdrTexture = std::make_shared< + renderengine::impl::ExternalTexture>(hdrBuffer, getRenderEngine(), + renderengine::impl::ExternalTexture:: + Usage::WRITEABLE); + gainmapTexture = std::make_shared< + renderengine::impl::ExternalTexture>(gainmapBuffer, getRenderEngine(), + renderengine::impl::ExternalTexture:: + Usage::WRITEABLE); + } + } + + auto futureFence = captureScreenshot(renderAreaBuilder, texture, false /* regionSampling */, + grayscale, isProtected, captureListener, displayState, + layers, hdrTexture, gainmapTexture); futureFence.get(); } @@ -7465,10 +7547,11 @@ SurfaceFlinger::getDisplayStateFromRenderAreaBuilder(RenderAreaBuilderVariant& r ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( const RenderAreaBuilderVariant& renderAreaBuilder, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, - bool grayscale, bool isProtected, bool attachGainmap, - const sp<IScreenCaptureListener>& captureListener, - std::optional<OutputCompositionState>& displayState, - std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) { + bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener, + const std::optional<OutputCompositionState>& displayState, + const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, + const std::shared_ptr<renderengine::ExternalTexture>& hdrBuffer, + const std::shared_ptr<renderengine::ExternalTexture>& gainmapBuffer) { SFTRACE_CALL(); ScreenCaptureResults captureResults; @@ -7484,74 +7567,40 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( } return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share(); } + float displayBrightnessNits = displayState.value().displayBrightnessNits; float sdrWhitePointNits = displayState.value().sdrWhitePointNits; - ftl::SharedFuture<FenceResult> renderFuture = - renderScreenImpl(renderArea.get(), buffer, regionSampling, grayscale, isProtected, - captureResults, displayState, layers); - - if (captureResults.capturedHdrLayers && attachGainmap && - FlagManager::getInstance().true_hdr_screenshots()) { - sp<GraphicBuffer> hdrBuffer = - getFactory().createGraphicBuffer(buffer->getWidth(), buffer->getHeight(), - HAL_PIXEL_FORMAT_RGBA_FP16, 1 /* layerCount */, - buffer->getUsage(), "screenshot-hdr"); - sp<GraphicBuffer> gainmapBuffer = - getFactory().createGraphicBuffer(buffer->getWidth(), buffer->getHeight(), - buffer->getPixelFormat(), 1 /* layerCount */, - buffer->getUsage(), "screenshot-gainmap"); - - const status_t bufferStatus = hdrBuffer->initCheck(); - const status_t gainmapBufferStatus = gainmapBuffer->initCheck(); - - if (bufferStatus != OK) { - ALOGW("%s: Buffer failed to allocate for hdr: %d. Screenshoting SDR instead.", __func__, - bufferStatus); - } else if (gainmapBufferStatus != OK) { - ALOGW("%s: Buffer failed to allocate for gainmap: %d. Screenshoting SDR instead.", - __func__, gainmapBufferStatus); - } else { - captureResults.optionalGainMap = gainmapBuffer; - const auto hdrTexture = std::make_shared< - renderengine::impl::ExternalTexture>(hdrBuffer, getRenderEngine(), - renderengine::impl::ExternalTexture:: - Usage::WRITEABLE); - const auto gainmapTexture = std::make_shared< - renderengine::impl::ExternalTexture>(gainmapBuffer, getRenderEngine(), - renderengine::impl::ExternalTexture:: - Usage::WRITEABLE); - ScreenCaptureResults unusedResults; - ftl::SharedFuture<FenceResult> hdrRenderFuture = - renderScreenImpl(renderArea.get(), hdrTexture, regionSampling, grayscale, - isProtected, unusedResults, displayState, layers); - - renderFuture = - ftl::Future(std::move(renderFuture)) - .then([&, hdrRenderFuture = std::move(hdrRenderFuture), - displayBrightnessNits, sdrWhitePointNits, - dataspace = captureResults.capturedDataspace, buffer, hdrTexture, - gainmapTexture](FenceResult fenceResult) -> FenceResult { - if (!fenceResult.ok()) { - return fenceResult; - } - - auto hdrFenceResult = hdrRenderFuture.get(); - - if (!hdrFenceResult.ok()) { - return hdrFenceResult; - } + ftl::SharedFuture<FenceResult> renderFuture; + + if (hdrBuffer && gainmapBuffer) { + ftl::SharedFuture<FenceResult> hdrRenderFuture = + renderScreenImpl(renderArea.get(), hdrBuffer, regionSampling, grayscale, + isProtected, captureResults, displayState, layers); + captureResults.buffer = buffer->getBuffer(); + captureResults.optionalGainMap = gainmapBuffer->getBuffer(); + + renderFuture = + ftl::Future(std::move(hdrRenderFuture)) + .then([&, displayBrightnessNits, sdrWhitePointNits, + dataspace = captureResults.capturedDataspace, buffer, hdrBuffer, + gainmapBuffer](FenceResult fenceResult) -> FenceResult { + if (!fenceResult.ok()) { + return fenceResult; + } - return getRenderEngine() - .drawGainmap(buffer, fenceResult.value()->get(), hdrTexture, - hdrFenceResult.value()->get(), - displayBrightnessNits / sdrWhitePointNits, - static_cast<ui::Dataspace>(dataspace), - gainmapTexture) - .get(); - }) - .share(); - }; + return getRenderEngine() + .tonemapAndDrawGainmap(hdrBuffer, fenceResult.value()->get(), + displayBrightnessNits / + sdrWhitePointNits, + static_cast<ui::Dataspace>(dataspace), + buffer, gainmapBuffer) + .get(); + }) + .share(); + } else { + renderFuture = renderScreenImpl(renderArea.get(), buffer, regionSampling, grayscale, + isProtected, captureResults, displayState, layers); } if (captureListener) { @@ -7573,8 +7622,8 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenshot( ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( const RenderArea* renderArea, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults& captureResults, - std::optional<OutputCompositionState>& displayState, - std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) { + const std::optional<OutputCompositionState>& displayState, + const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers) { SFTRACE_CALL(); for (auto& [_, layerFE] : layers) { @@ -7642,9 +7691,8 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( } auto present = [this, buffer = capturedBuffer, dataspace = captureResults.capturedDataspace, - sdrWhitePointNits, displayBrightnessNits, grayscale, isProtected, - layers = std::move(layers), layerStack, regionSampling, - renderArea = std::move(renderArea), renderIntent, + sdrWhitePointNits, displayBrightnessNits, grayscale, isProtected, layers, + layerStack, regionSampling, renderArea = std::move(renderArea), renderIntent, enableLocalTonemapping]() -> FenceResult { std::unique_ptr<compositionengine::CompositionEngine> compositionEngine = mFactory.createCompositionEngine(); @@ -8175,12 +8223,20 @@ void SurfaceFlinger::updateHdcpLevels(hal::HWDisplayId hwcDisplayId, int32_t con })); } -void SurfaceFlinger::setActivePictureListener(const sp<gui::IActivePictureListener>& listener) { - if (com_android_graphics_libgui_flags_apply_picture_profiles()) { - Mutex::Autolock lock(mStateLock); - mActivePictureListener = listener; - mHaveNewActivePictureListener = listener != nullptr; - } +void SurfaceFlinger::addActivePictureListener(const sp<gui::IActivePictureListener>& listener) { + Mutex::Autolock lock(mStateLock); + std::erase_if(mActivePictureListenersToRemove, [listener](const auto& otherListener) { + return IInterface::asBinder(listener) == IInterface::asBinder(otherListener); + }); + mActivePictureListenersToAdd.push_back(listener); +} + +void SurfaceFlinger::removeActivePictureListener(const sp<gui::IActivePictureListener>& listener) { + Mutex::Autolock lock(mStateLock); + std::erase_if(mActivePictureListenersToAdd, [listener](const auto& otherListener) { + return IInterface::asBinder(listener) == IInterface::asBinder(otherListener); + }); + mActivePictureListenersToRemove.push_back(listener); } std::shared_ptr<renderengine::ExternalTexture> SurfaceFlinger::getExternalTextureFromBufferData( @@ -9133,11 +9189,20 @@ binder::Status SurfaceComposerAIDL::removeHdrLayerInfoListener( return binderStatusFromStatusT(status); } -binder::Status SurfaceComposerAIDL::setActivePictureListener( +binder::Status SurfaceComposerAIDL::addActivePictureListener( + const sp<gui::IActivePictureListener>& listener) { + status_t status = checkObservePictureProfilesPermission(); + if (status == OK) { + mFlinger->addActivePictureListener(listener); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::removeActivePictureListener( const sp<gui::IActivePictureListener>& listener) { status_t status = checkObservePictureProfilesPermission(); if (status == OK) { - mFlinger->setActivePictureListener(listener); + mFlinger->removeActivePictureListener(listener); } return binderStatusFromStatusT(status); } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 1e2c08747b..c85c0846c5 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -69,7 +69,7 @@ #include <ui/FenceResult.h> #include <common/FlagManager.h> -#include "ActivePictureUpdater.h" +#include "ActivePictureTracker.h" #include "BackgroundExecutor.h" #include "Display/DisplayModeController.h" #include "Display/PhysicalDisplay.h" @@ -667,7 +667,9 @@ private: void updateHdcpLevels(hal::HWDisplayId hwcDisplayId, int32_t connectedLevel, int32_t maxLevel); - void setActivePictureListener(const sp<gui::IActivePictureListener>& listener); + void addActivePictureListener(const sp<gui::IActivePictureListener>& listener); + + void removeActivePictureListener(const sp<gui::IActivePictureListener>& listener); // IBinder::DeathRecipient overrides: void binderDied(const wp<IBinder>& who) override; @@ -730,7 +732,11 @@ private: Fps maxFps); void initiateDisplayModeChanges() REQUIRES(kMainThreadContext) REQUIRES(mStateLock); - void finalizeDisplayModeChange(PhysicalDisplayId) REQUIRES(kMainThreadContext) + + // Returns whether the commit stage should proceed. The return value is ignored when finalizing + // immediate mode changes, which happen toward the end of the commit stage. + // TODO: b/355427258 - Remove the return value once the `synced_resolution_switch` flag is live. + bool finalizeDisplayModeChange(PhysicalDisplayId) REQUIRES(kMainThreadContext) REQUIRES(mStateLock); void dropModeRequest(PhysicalDisplayId) REQUIRES(kMainThreadContext); @@ -872,7 +878,7 @@ private: void captureScreenCommon(RenderAreaBuilderVariant, GetLayerSnapshotsFunction, ui::Size bufferSize, ui::PixelFormat, bool allowProtected, - bool grayscale, bool attachGainmap, const sp<IScreenCaptureListener>&); + bool grayscale, const sp<IScreenCaptureListener>&); std::optional<OutputCompositionState> getDisplayStateFromRenderAreaBuilder( RenderAreaBuilderVariant& renderAreaBuilder) REQUIRES(kMainThreadContext); @@ -880,16 +886,17 @@ private: ftl::SharedFuture<FenceResult> captureScreenshot( const RenderAreaBuilderVariant& renderAreaBuilder, const std::shared_ptr<renderengine::ExternalTexture>& buffer, bool regionSampling, - bool grayscale, bool isProtected, bool attachGainmap, - const sp<IScreenCaptureListener>& captureListener, - std::optional<OutputCompositionState>& displayState, - std::vector<std::pair<Layer*, sp<LayerFE>>>& layers); + bool grayscale, bool isProtected, const sp<IScreenCaptureListener>& captureListener, + const std::optional<OutputCompositionState>& displayState, + const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers, + const std::shared_ptr<renderengine::ExternalTexture>& hdrBuffer = nullptr, + const std::shared_ptr<renderengine::ExternalTexture>& gainmapBuffer = nullptr); ftl::SharedFuture<FenceResult> renderScreenImpl( const RenderArea*, const std::shared_ptr<renderengine::ExternalTexture>&, bool regionSampling, bool grayscale, bool isProtected, ScreenCaptureResults&, - std::optional<OutputCompositionState>& displayState, - std::vector<std::pair<Layer*, sp<LayerFE>>>& layers); + const std::optional<OutputCompositionState>& displayState, + const std::vector<std::pair<Layer*, sp<LayerFE>>>& layers); void readPersistentProperties(); @@ -1402,9 +1409,9 @@ private: std::unordered_map<DisplayId, sp<HdrLayerInfoReporter>> mHdrLayerInfoListeners GUARDED_BY(mStateLock); - sp<gui::IActivePictureListener> mActivePictureListener GUARDED_BY(mStateLock); - bool mHaveNewActivePictureListener GUARDED_BY(mStateLock); - ActivePictureUpdater mActivePictureUpdater GUARDED_BY(kMainThreadContext); + ActivePictureTracker mActivePictureTracker GUARDED_BY(kMainThreadContext); + ActivePictureTracker::Listeners mActivePictureListenersToAdd GUARDED_BY(mStateLock); + ActivePictureTracker::Listeners mActivePictureListenersToRemove GUARDED_BY(mStateLock); std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint; @@ -1641,8 +1648,8 @@ public: binder::Status flushJankData(int32_t layerId) override; binder::Status removeJankListener(int32_t layerId, const sp<gui::IJankListener>& listener, int64_t afterVsync) override; - binder::Status setActivePictureListener(const sp<gui::IActivePictureListener>& listener); - binder::Status clearActivePictureListener(); + binder::Status addActivePictureListener(const sp<gui::IActivePictureListener>& listener); + binder::Status removeActivePictureListener(const sp<gui::IActivePictureListener>& listener); private: static const constexpr bool kUsePermissionCache = true; diff --git a/services/surfaceflinger/Tracing/tools/Android.bp b/services/surfaceflinger/Tracing/tools/Android.bp index 63c1b37166..d2ffcc0f73 100644 --- a/services/surfaceflinger/Tracing/tools/Android.bp +++ b/services/surfaceflinger/Tracing/tools/Android.bp @@ -27,6 +27,7 @@ cc_binary { defaults: [ "libsurfaceflinger_mocks_defaults", "librenderengine_deps", + "poweradvisor_deps", "surfaceflinger_defaults", "libsurfaceflinger_common_deps", ], diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp index 5e78426c77..e80cd78cbd 100644 --- a/services/surfaceflinger/common/FlagManager.cpp +++ b/services/surfaceflinger/common/FlagManager.cpp @@ -112,60 +112,63 @@ void FlagManager::dump(std::string& result) const { DUMP_LEGACY_SERVER_FLAG(use_skia_tracing); /// Trunk stable server (R/W) flags /// - DUMP_ACONFIG_FLAG(refresh_rate_overlay_on_external_display); DUMP_ACONFIG_FLAG(adpf_gpu_sf); DUMP_ACONFIG_FLAG(adpf_native_session_manager); DUMP_ACONFIG_FLAG(adpf_use_fmq_channel); DUMP_ACONFIG_FLAG(graphite_renderengine_preview_rollout); + DUMP_ACONFIG_FLAG(refresh_rate_overlay_on_external_display); /// Trunk stable readonly flags /// + /// IMPORTANT - please keep alphabetize to reduce merge conflicts + DUMP_ACONFIG_FLAG(add_sf_skipped_frames_to_trace); DUMP_ACONFIG_FLAG(adpf_fmq_sf); + DUMP_ACONFIG_FLAG(allow_n_vsyncs_in_targeter); DUMP_ACONFIG_FLAG(arr_setframerate_gte_enum); - DUMP_ACONFIG_FLAG(connected_display); - DUMP_ACONFIG_FLAG(enable_small_area_detection); - DUMP_ACONFIG_FLAG(stable_edid_ids); - DUMP_ACONFIG_FLAG(frame_rate_category_mrr); - DUMP_ACONFIG_FLAG(misc1); - DUMP_ACONFIG_FLAG(vrr_config); - DUMP_ACONFIG_FLAG(hdcp_level_hal); - DUMP_ACONFIG_FLAG(multithreaded_present); - DUMP_ACONFIG_FLAG(add_sf_skipped_frames_to_trace); - DUMP_ACONFIG_FLAG(use_known_refresh_rate_for_fps_consistency); + DUMP_ACONFIG_FLAG(begone_bright_hlg); DUMP_ACONFIG_FLAG(cache_when_source_crop_layer_only_moved); - DUMP_ACONFIG_FLAG(enable_fro_dependent_features); + DUMP_ACONFIG_FLAG(commit_not_composited); + DUMP_ACONFIG_FLAG(connected_display); + DUMP_ACONFIG_FLAG(connected_display_hdr); + DUMP_ACONFIG_FLAG(correct_dpi_with_display_size); + DUMP_ACONFIG_FLAG(deprecate_frame_tracker); + DUMP_ACONFIG_FLAG(deprecate_vsync_sf); + DUMP_ACONFIG_FLAG(detached_mirror); + DUMP_ACONFIG_FLAG(display_config_error_hal); DUMP_ACONFIG_FLAG(display_protected); + DUMP_ACONFIG_FLAG(dont_skip_on_early_ro); + DUMP_ACONFIG_FLAG(enable_fro_dependent_features); + DUMP_ACONFIG_FLAG(enable_layer_command_batching); + DUMP_ACONFIG_FLAG(enable_small_area_detection); + DUMP_ACONFIG_FLAG(filter_frames_before_trace_starts); + DUMP_ACONFIG_FLAG(flush_buffer_slots_to_uncache); + DUMP_ACONFIG_FLAG(force_compile_graphite_renderengine); DUMP_ACONFIG_FLAG(fp16_client_target); + DUMP_ACONFIG_FLAG(frame_rate_category_mrr); DUMP_ACONFIG_FLAG(game_default_frame_rate); - DUMP_ACONFIG_FLAG(enable_layer_command_batching); - DUMP_ACONFIG_FLAG(vulkan_renderengine); - DUMP_ACONFIG_FLAG(renderable_buffer_usage); - DUMP_ACONFIG_FLAG(vrr_bugfix_24q4); - DUMP_ACONFIG_FLAG(vrr_bugfix_dropped_frame); - DUMP_ACONFIG_FLAG(restore_blur_step); - DUMP_ACONFIG_FLAG(dont_skip_on_early_ro); - DUMP_ACONFIG_FLAG(no_vsyncs_on_screen_off); - DUMP_ACONFIG_FLAG(protected_if_client); - DUMP_ACONFIG_FLAG(idle_screen_refresh_rate_timeout); DUMP_ACONFIG_FLAG(graphite_renderengine); - DUMP_ACONFIG_FLAG(filter_frames_before_trace_starts); + DUMP_ACONFIG_FLAG(hdcp_level_hal); + DUMP_ACONFIG_FLAG(idle_screen_refresh_rate_timeout); DUMP_ACONFIG_FLAG(latch_unsignaled_with_auto_refresh_changed); - DUMP_ACONFIG_FLAG(deprecate_vsync_sf); - DUMP_ACONFIG_FLAG(allow_n_vsyncs_in_targeter); - DUMP_ACONFIG_FLAG(detached_mirror); - DUMP_ACONFIG_FLAG(commit_not_composited); - DUMP_ACONFIG_FLAG(correct_dpi_with_display_size); DUMP_ACONFIG_FLAG(local_tonemap_screenshots); + DUMP_ACONFIG_FLAG(misc1); + DUMP_ACONFIG_FLAG(multithreaded_present); + DUMP_ACONFIG_FLAG(no_vsyncs_on_screen_off); DUMP_ACONFIG_FLAG(override_trusted_overlay); - DUMP_ACONFIG_FLAG(flush_buffer_slots_to_uncache); - DUMP_ACONFIG_FLAG(force_compile_graphite_renderengine); + DUMP_ACONFIG_FLAG(protected_if_client); + DUMP_ACONFIG_FLAG(reject_dupe_layerstacks); + DUMP_ACONFIG_FLAG(renderable_buffer_usage); + DUMP_ACONFIG_FLAG(restore_blur_step); + DUMP_ACONFIG_FLAG(skip_invisible_windows_in_input); + DUMP_ACONFIG_FLAG(stable_edid_ids); DUMP_ACONFIG_FLAG(trace_frame_rate_override); DUMP_ACONFIG_FLAG(true_hdr_screenshots); - DUMP_ACONFIG_FLAG(display_config_error_hal); - DUMP_ACONFIG_FLAG(connected_display_hdr); - DUMP_ACONFIG_FLAG(deprecate_frame_tracker); - DUMP_ACONFIG_FLAG(skip_invisible_windows_in_input); - DUMP_ACONFIG_FLAG(begone_bright_hlg); + DUMP_ACONFIG_FLAG(use_known_refresh_rate_for_fps_consistency); + DUMP_ACONFIG_FLAG(vrr_bugfix_24q4); + DUMP_ACONFIG_FLAG(vrr_bugfix_dropped_frame); + DUMP_ACONFIG_FLAG(vrr_config); + DUMP_ACONFIG_FLAG(vulkan_renderengine); DUMP_ACONFIG_FLAG(window_blur_kawase2); + /// IMPORTANT - please keep alphabetize to reduce merge conflicts #undef DUMP_ACONFIG_FLAG #undef DUMP_LEGACY_SERVER_FLAG @@ -266,6 +269,7 @@ FLAG_MANAGER_ACONFIG_FLAG(deprecate_frame_tracker, ""); FLAG_MANAGER_ACONFIG_FLAG(skip_invisible_windows_in_input, ""); FLAG_MANAGER_ACONFIG_FLAG(begone_bright_hlg, "debug.sf.begone_bright_hlg"); FLAG_MANAGER_ACONFIG_FLAG(window_blur_kawase2, ""); +FLAG_MANAGER_ACONFIG_FLAG(reject_dupe_layerstacks, ""); /// Trunk stable server (R/W) flags /// FLAG_MANAGER_ACONFIG_FLAG(refresh_rate_overlay_on_external_display, "") diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h index d8887f538f..c7f97b4008 100644 --- a/services/surfaceflinger/common/include/common/FlagManager.h +++ b/services/surfaceflinger/common/include/common/FlagManager.h @@ -48,62 +48,65 @@ public: bool use_skia_tracing() const; /// Trunk stable server (R/W) flags /// - bool refresh_rate_overlay_on_external_display() const; bool adpf_gpu_sf() const; - bool adpf_use_fmq_channel() const; bool adpf_native_session_manager() const; + bool adpf_use_fmq_channel() const; bool adpf_use_fmq_channel_fixed() const; bool graphite_renderengine_preview_rollout() const; + bool refresh_rate_overlay_on_external_display() const; /// Trunk stable readonly flags /// - bool arr_setframerate_gte_enum() const; - bool adpf_fmq_sf() const; - bool connected_display() const; - bool frame_rate_category_mrr() const; - bool enable_small_area_detection() const; - bool stable_edid_ids() const; - bool misc1() const; - bool vrr_config() const; - bool hdcp_level_hal() const; - bool multithreaded_present() const; + /// IMPORTANT - please keep alphabetize to reduce merge conflicts bool add_sf_skipped_frames_to_trace() const; - bool use_known_refresh_rate_for_fps_consistency() const; + bool adpf_fmq_sf() const; + bool allow_n_vsyncs_in_targeter() const; + bool arr_setframerate_gte_enum() const; + bool begone_bright_hlg() const; bool cache_when_source_crop_layer_only_moved() const; - bool enable_fro_dependent_features() const; + bool commit_not_composited() const; + bool connected_display() const; + bool connected_display_hdr() const; + bool correct_dpi_with_display_size() const; + bool deprecate_frame_tracker() const; + bool deprecate_vsync_sf() const; + bool detached_mirror() const; + bool display_config_error_hal() const; bool display_protected() const; + bool dont_skip_on_early_ro() const; + bool enable_fro_dependent_features() const; + bool enable_layer_command_batching() const; + bool enable_small_area_detection() const; + bool filter_frames_before_trace_starts() const; + bool flush_buffer_slots_to_uncache() const; + bool force_compile_graphite_renderengine() const; bool fp16_client_target() const; + bool frame_rate_category_mrr() const; bool game_default_frame_rate() const; - bool enable_layer_command_batching() const; - bool vulkan_renderengine() const; - bool vrr_bugfix_24q4() const; - bool vrr_bugfix_dropped_frame() const; - bool renderable_buffer_usage() const; - bool restore_blur_step() const; - bool dont_skip_on_early_ro() const; - bool no_vsyncs_on_screen_off() const; - bool protected_if_client() const; - bool idle_screen_refresh_rate_timeout() const; bool graphite_renderengine() const; - bool filter_frames_before_trace_starts() const; + bool hdcp_level_hal() const; + bool idle_screen_refresh_rate_timeout() const; bool latch_unsignaled_with_auto_refresh_changed() const; - bool deprecate_vsync_sf() const; - bool allow_n_vsyncs_in_targeter() const; - bool detached_mirror() const; - bool commit_not_composited() const; - bool correct_dpi_with_display_size() const; bool local_tonemap_screenshots() const; + bool luts_api() const; + bool misc1() const; + bool multithreaded_present() const; + bool no_vsyncs_on_screen_off() const; bool override_trusted_overlay() const; - bool flush_buffer_slots_to_uncache() const; - bool force_compile_graphite_renderengine() const; + bool protected_if_client() const; + bool reject_dupe_layerstacks() const; + bool renderable_buffer_usage() const; + bool restore_blur_step() const; + bool skip_invisible_windows_in_input() const; + bool stable_edid_ids() const; bool trace_frame_rate_override() const; bool true_hdr_screenshots() const; - bool display_config_error_hal() const; - bool connected_display_hdr() const; - bool deprecate_frame_tracker() const; - bool skip_invisible_windows_in_input() const; - bool begone_bright_hlg() const; - bool luts_api() const; + bool use_known_refresh_rate_for_fps_consistency() const; + bool vrr_bugfix_24q4() const; + bool vrr_bugfix_dropped_frame() const; + bool vrr_config() const; + bool vulkan_renderengine() const; bool window_blur_kawase2() const; + /// IMPORTANT - please keep alphabetize to reduce merge conflicts protected: // overridden for unit tests diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig index bdd826d084..b28d2697c5 100644 --- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig +++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig @@ -217,6 +217,17 @@ flag { } # no_vsyncs_on_screen_off flag { + name: "reject_dupe_layerstacks" + namespace: "window_surfaces" + description: "Reject duplicate layerstacks for displays" + bug: "370358572" + is_fixed_read_only: true + metadata { + purpose: PURPOSE_BUGFIX + } + } # reject_dupe_layerstacks + +flag { name: "single_hop_screenshot" namespace: "window_surfaces" description: "Only access SF main thread once during a screenshot" diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index 4d5c0fd1de..b5f7a74347 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -52,7 +52,7 @@ cc_test { "LayerTypeTransaction_test.cpp", "LayerUpdate_test.cpp", "MirrorLayer_test.cpp", - "MultiDisplayLayerBounds_test.cpp", + "MultiDisplay_test.cpp", "RefreshRateOverlay_test.cpp", "RelativeZ_test.cpp", "ReleaseBufferCallback_test.cpp", diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplay_test.cpp index 65add63165..54bb253526 100644 --- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp +++ b/services/surfaceflinger/tests/MultiDisplay_test.cpp @@ -33,7 +33,7 @@ using android::hardware::graphics::common::V1_1::BufferUsage; ::testing::Environment* const binderEnv = ::testing::AddGlobalTestEnvironment(new BinderEnvironment()); -class MultiDisplayLayerBoundsTest : public LayerTransactionTest { +class MultiDisplayTest : public LayerTransactionTest { protected: virtual void SetUp() { LayerTransactionTest::SetUp(); @@ -105,7 +105,7 @@ protected: Color mExpectedColor = {63, 63, 195, 255}; }; -TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) { +TEST_F(MultiDisplayTest, RenderLayerInVirtualDisplay) { constexpr ui::LayerStack kLayerStack{1u}; createDisplay(mMainDisplayState.layerStackSpaceRect, kLayerStack); createColorLayer(kLayerStack); @@ -124,7 +124,7 @@ TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) { sc->expectColor(Rect(1, 1, 9, 9), {0, 0, 0, 255}); } -TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) { +TEST_F(MultiDisplayTest, RenderLayerInMirroredVirtualDisplay) { // Create a display and set its layer stack to the main display's layer stack so // the contents of the main display are mirrored on to the virtual display. @@ -150,7 +150,7 @@ TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) { sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255}); } -TEST_F(MultiDisplayLayerBoundsTest, RenderLayerWithPromisedFenceInMirroredVirtualDisplay) { +TEST_F(MultiDisplayTest, RenderLayerWithPromisedFenceInMirroredVirtualDisplay) { // Create a display and use a unique layerstack ID for mirrorDisplay() so // the contents of the main display are mirrored on to the virtual display. @@ -181,6 +181,51 @@ TEST_F(MultiDisplayLayerBoundsTest, RenderLayerWithPromisedFenceInMirroredVirtua sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255}); } +#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) +TEST_F(MultiDisplayTest, rejectDuplicateLayerStacks) { + if (!FlagManager::getInstance().reject_dupe_layerstacks()) return; + + // Setup + sp<CpuConsumer> cpuConsumer1 = sp<CpuConsumer>::make(static_cast<size_t>(1)); + cpuConsumer1->setName(String8("consumer 1")); + cpuConsumer1->setDefaultBufferSize(100, 100); + sp<IGraphicBufferProducer> cpuProducer1 = + cpuConsumer1->getSurface()->getIGraphicBufferProducer(); + CpuConsumer::LockedBuffer buffer1; + + sp<CpuConsumer> cpuConsumer2 = sp<CpuConsumer>::make(static_cast<size_t>(1)); + cpuConsumer2->setName(String8("consumer 2")); + cpuConsumer2->setDefaultBufferSize(100, 100); + sp<IGraphicBufferProducer> cpuProducer2 = + cpuConsumer2->getSurface()->getIGraphicBufferProducer(); + CpuConsumer::LockedBuffer buffer2; + + SurfaceComposerClient::Transaction t; + constexpr ui::LayerStack layerStack = {123u}; + createColorLayer(layerStack); + + static const std::string kDisplayName1("VirtualDisplay1 - rejectDuplicateLayerStacks"); + sp<IBinder> virtualDisplay1 = + SurfaceComposerClient::createVirtualDisplay(kDisplayName1, false /*isSecure*/); + + t.setDisplaySurface(virtualDisplay1, cpuProducer1); + t.setDisplayLayerStack(virtualDisplay1, layerStack); + t.apply(true); + + static const std::string kDisplayName2("VirtualDisplay2 - rejectDuplicateLayerStacks"); + sp<IBinder> virtualDisplay2 = + SurfaceComposerClient::createVirtualDisplay(kDisplayName2, false /*isSecure*/); + + t.setDisplaySurface(virtualDisplay2, cpuProducer2); + t.setDisplayLayerStack(virtualDisplay2, layerStack); + t.apply(true); + + // The second consumer will not be able to lock a buffer because + // the duplicate layer stack should be rejected. + ASSERT_EQ(NO_ERROR, cpuConsumer1->lockNextBuffer(&buffer1)); + ASSERT_NE(NO_ERROR, cpuConsumer2->lockNextBuffer(&buffer2)); +} +#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues diff --git a/services/surfaceflinger/tests/unittests/ActivePictureTrackerTest.cpp b/services/surfaceflinger/tests/unittests/ActivePictureTrackerTest.cpp new file mode 100644 index 0000000000..8011309519 --- /dev/null +++ b/services/surfaceflinger/tests/unittests/ActivePictureTrackerTest.cpp @@ -0,0 +1,482 @@ +/* + * Copyright 2024 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +#include <android/gui/ActivePicture.h> +#include <android/gui/IActivePictureListener.h> +#include <compositionengine/mock/CompositionEngine.h> +#include <mock/DisplayHardware/MockComposer.h> +#include <mock/MockLayer.h> +#include <renderengine/mock/RenderEngine.h> + +#include "ActivePictureTracker.h" +#include "LayerFE.h" +#include "TestableSurfaceFlinger.h" + +namespace android { + +using android::compositionengine::LayerFECompositionState; +using android::gui::ActivePicture; +using android::gui::IActivePictureListener; +using android::mock::MockLayer; +using surfaceflinger::frontend::LayerSnapshot; +using testing::_; +using testing::NiceMock; +using testing::Return; +using testing::SizeIs; +using testing::StrictMock; + +class TestableLayerFE : public LayerFE { +public: + TestableLayerFE() : LayerFE("TestableLayerFE"), snapshot(*(new LayerSnapshot)) { + mSnapshot = std::unique_ptr<LayerSnapshot>(&snapshot); + } + + LayerSnapshot& snapshot; +}; + +class MockActivePictureListener : public gui::BnActivePictureListener { +public: + operator ActivePictureTracker::Listeners const() { + return {sp<IActivePictureListener>::fromExisting(this)}; + } + + MOCK_METHOD(binder::Status, onActivePicturesChanged, (const std::vector<ActivePicture>&), + (override)); +}; + +class ActivePictureTrackerTest : public testing::Test { +protected: + const static ActivePictureTracker::Listeners NO_LISTENERS; + + SurfaceFlinger* flinger() { + if (!mFlingerSetup) { + mFlinger.setupMockScheduler(); + mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>()); + mFlinger.setupRenderEngine(std::make_unique<renderengine::mock::RenderEngine>()); + mFlingerSetup = true; + } + return mFlinger.flinger(); + } + + sp<NiceMock<MockLayer>> createMockLayer(int layerId, int ownerUid) { + auto layer = sp<NiceMock<MockLayer>>::make(flinger(), layerId); + EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(ownerUid))); + return layer; + } + + sp<StrictMock<MockActivePictureListener>> createMockListener() { + return sp<StrictMock<MockActivePictureListener>>::make(); + } + + ActivePictureTracker::Listeners mListenersToAdd; + ActivePictureTracker::Listeners mListenersToRemove; + +private: + TestableSurfaceFlinger mFlinger; + bool mFlingerSetup = false; +}; + +const ActivePictureTracker::Listeners ActivePictureTrackerTest::NO_LISTENERS; + +// Hack to workaround initializer lists not working for parcelables because parcelables inherit from +// Parcelable, which has a virtual destructor. +auto UnorderedElementsAre(std::initializer_list<std::tuple<int32_t, int32_t, int64_t>> tuples) { + std::vector<ActivePicture> activePictures; + for (auto tuple : tuples) { + ActivePicture ap; + ap.layerId = std::get<0>(tuple); + ap.ownerUid = std::get<1>(tuple); + ap.pictureProfileId = std::get<2>(tuple); + activePictures.push_back(ap); + } + return testing::UnorderedElementsAreArray(activePictures); +} + +// Parcelables don't define this for matchers, which is unfortunate +void PrintTo(const ActivePicture& activePicture, std::ostream* os) { + *os << activePicture.toString(); +} + +TEST_F(ActivePictureTrackerTest, whenListenerAdded_called) { + ActivePictureTracker tracker; + auto listener = createMockListener(); + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(0))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); +} + +TEST_F(ActivePictureTrackerTest, whenListenerAdded_withListenerAlreadyAdded_notCalled) { + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(0))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + EXPECT_CALL(*listener, onActivePicturesChanged(_)).Times(0); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenListenerAdded_withUncommittedProfile_calledWithNone) { + auto layer = createMockLayer(100, 10); + TestableLayerFE layerFE; + + ActivePictureTracker tracker; + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } + { + auto listener = createMockListener(); + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(0))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenListenerAdded_withCommittedProfile_calledWithActivePicture) { + auto layer = createMockLayer(100, 10); + TestableLayerFE layerFE; + + ActivePictureTracker tracker; + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + auto listener = createMockListener(); + EXPECT_CALL(*listener, onActivePicturesChanged(_)) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 1}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenProfileAdded_calledWithActivePicture) { + auto layer = createMockLayer(100, 10); + TestableLayerFE layerFE; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(0))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 1}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenContinuesUsingProfile_notCalled) { + auto layer = createMockLayer(100, 10); + TestableLayerFE layerFE; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(1))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)).Times(0); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenProfileIsRemoved_calledWithNoActivePictures) { + auto layer = createMockLayer(100, 10); + TestableLayerFE layerFE; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(1))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle::NONE; + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(0))).Times(1); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenProfileIsNotCommitted_calledWithNoActivePictures) { + auto layer = createMockLayer(100, 10); + TestableLayerFE layerFE; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(1))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(0))).Times(1); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenProfileChanges_calledWithDifferentProfile) { + auto layer = createMockLayer(100, 10); + TestableLayerFE layerFE; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(1))) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 1}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(1))) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 2}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenMultipleCommittedProfiles_calledWithMultipleActivePictures) { + auto layer1 = createMockLayer(100, 10); + TestableLayerFE layerFE1; + + auto layer2 = createMockLayer(200, 20); + TestableLayerFE layerFE2; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE2.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(2))) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 1}, {200, 20, 2}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenNonCommittedProfileChanges_notCalled) { + auto layer1 = createMockLayer(100, 10); + TestableLayerFE layerFE1; + + auto layer2 = createMockLayer(200, 20); + TestableLayerFE layerFE2; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(1))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)).Times(0); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenDifferentLayerUsesSameProfile_called) { + auto layer1 = createMockLayer(100, 10); + TestableLayerFE layerFE1; + + auto layer2 = createMockLayer(200, 20); + TestableLayerFE layerFE2; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE2.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 1}, {200, 20, 2}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE2.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 2}, {200, 20, 1}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenSameUidDifferentLayerUsesSameProfile_called) { + auto layer1 = createMockLayer(100, 10); + TestableLayerFE layerFE1; + + auto layer2 = createMockLayer(200, 10); + TestableLayerFE layerFE2; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE2.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 1}, {200, 10, 2}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(2); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE2.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 2}, {200, 10, 1}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +TEST_F(ActivePictureTrackerTest, whenNewLayerUsesSameProfile_called) { + auto layer1 = createMockLayer(100, 10); + TestableLayerFE layerFE1; + + ActivePictureTracker tracker; + auto listener = createMockListener(); + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(SizeIs(1))).Times(1); + tracker.updateAndNotifyListeners(*listener, NO_LISTENERS); + } + + auto layer2 = createMockLayer(200, 10); + TestableLayerFE layerFE2; + { + layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE1.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); + + layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); + layerFE2.onPictureProfileCommitted(); + tracker.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); + + EXPECT_CALL(*listener, onActivePicturesChanged(_)) + .WillOnce([](const std::vector<gui::ActivePicture>& activePictures) { + EXPECT_THAT(activePictures, UnorderedElementsAre({{100, 10, 1}, {200, 10, 1}})); + return binder::Status::ok(); + }); + tracker.updateAndNotifyListeners(NO_LISTENERS, NO_LISTENERS); + } +} + +} // namespace android diff --git a/services/surfaceflinger/tests/unittests/ActivePictureUpdaterTest.cpp b/services/surfaceflinger/tests/unittests/ActivePictureUpdaterTest.cpp deleted file mode 100644 index b926d2f4da..0000000000 --- a/services/surfaceflinger/tests/unittests/ActivePictureUpdaterTest.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright 2024 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <gmock/gmock.h> -#include <gtest/gtest.h> - -#include <android/gui/ActivePicture.h> -#include <android/gui/IActivePictureListener.h> -#include <compositionengine/mock/CompositionEngine.h> -#include <mock/DisplayHardware/MockComposer.h> -#include <mock/MockLayer.h> -#include <renderengine/mock/RenderEngine.h> - -#include "ActivePictureUpdater.h" -#include "LayerFE.h" -#include "TestableSurfaceFlinger.h" - -namespace android { - -using android::compositionengine::LayerFECompositionState; -using android::gui::ActivePicture; -using android::gui::IActivePictureListener; -using android::mock::MockLayer; -using surfaceflinger::frontend::LayerSnapshot; -using testing::_; -using testing::NiceMock; -using testing::Return; - -class TestableLayerFE : public LayerFE { -public: - TestableLayerFE() : LayerFE("TestableLayerFE"), snapshot(*(new LayerSnapshot)) { - mSnapshot = std::unique_ptr<LayerSnapshot>(&snapshot); - } - - LayerSnapshot& snapshot; -}; - -class ActivePictureUpdaterTest : public testing::Test { -protected: - SurfaceFlinger* flinger() { - if (!mFlingerSetup) { - mFlinger.setupMockScheduler(); - mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>()); - mFlinger.setupRenderEngine(std::make_unique<renderengine::mock::RenderEngine>()); - mFlingerSetup = true; - } - return mFlinger.flinger(); - } - -private: - TestableSurfaceFlinger mFlinger; - bool mFlingerSetup = false; -}; - -// Hack to workaround initializer lists not working for parcelables because parcelables inherit from -// Parcelable, which has a virtual destructor. -auto UnorderedElementsAre(std::initializer_list<std::tuple<int32_t, int32_t, int64_t>> tuples) { - std::vector<ActivePicture> activePictures; - for (auto tuple : tuples) { - ActivePicture ap; - ap.layerId = std::get<0>(tuple); - ap.ownerUid = std::get<1>(tuple); - ap.pictureProfileId = std::get<2>(tuple); - activePictures.push_back(ap); - } - return testing::UnorderedElementsAreArray(activePictures); -} - -// Parcelables don't define this for matchers, which is unfortunate -void PrintTo(const ActivePicture& activePicture, std::ostream* os) { - *os << activePicture.toString(); -} - -TEST_F(ActivePictureUpdaterTest, notCalledWithNoProfile) { - sp<NiceMock<MockLayer>> layer = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE; - EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - ActivePictureUpdater updater; - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle::NONE; - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_FALSE(updater.updateAndHasChanged()); - } -} - -TEST_F(ActivePictureUpdaterTest, calledWhenLayerStartsUsingProfile) { - sp<NiceMock<MockLayer>> layer = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE; - EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - ActivePictureUpdater updater; - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle::NONE; - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_FALSE(updater.updateAndHasChanged()); - } - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE.onPictureProfileCommitted(); - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); - } -} - -TEST_F(ActivePictureUpdaterTest, notCalledWhenLayerContinuesUsingProfile) { - sp<NiceMock<MockLayer>> layer = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE; - EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - ActivePictureUpdater updater; - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE.onPictureProfileCommitted(); - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); - } - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE.onPictureProfileCommitted(); - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_FALSE(updater.updateAndHasChanged()); - } -} - -TEST_F(ActivePictureUpdaterTest, calledWhenLayerStopsUsingProfile) { - sp<NiceMock<MockLayer>> layer = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE; - EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - ActivePictureUpdater updater; - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE.onPictureProfileCommitted(); - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); - } - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle::NONE; - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({})); - } -} - -TEST_F(ActivePictureUpdaterTest, calledWhenLayerChangesProfile) { - sp<NiceMock<MockLayer>> layer = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE; - EXPECT_CALL(*layer, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - ActivePictureUpdater updater; - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE.onPictureProfileCommitted(); - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); - } - { - layerFE.snapshot.pictureProfileHandle = PictureProfileHandle(2); - layerFE.onPictureProfileCommitted(); - updater.onLayerComposed(*layer, layerFE, layerFE.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 2}})); - } -} - -TEST_F(ActivePictureUpdaterTest, notCalledWhenUncommittedLayerChangesProfile) { - sp<NiceMock<MockLayer>> layer1 = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE1; - EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - sp<NiceMock<MockLayer>> layer2 = sp<NiceMock<MockLayer>>::make(flinger(), 200); - TestableLayerFE layerFE2; - EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(20))); - - ActivePictureUpdater updater; - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); - updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); - } - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); - updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); - - ASSERT_FALSE(updater.updateAndHasChanged()); - } -} - -TEST_F(ActivePictureUpdaterTest, calledWhenDifferentLayerUsesSameProfile) { - sp<NiceMock<MockLayer>> layer1 = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE1; - EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - sp<NiceMock<MockLayer>> layer2 = sp<NiceMock<MockLayer>>::make(flinger(), 200); - TestableLayerFE layerFE2; - EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(20))); - - ActivePictureUpdater updater; - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); - layerFE2.onPictureProfileCommitted(); - updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), - UnorderedElementsAre({{100, 10, 1}, {200, 20, 2}})); - } - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(2); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE2.onPictureProfileCommitted(); - updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), - UnorderedElementsAre({{100, 10, 2}, {200, 20, 1}})); - } -} - -TEST_F(ActivePictureUpdaterTest, calledWhenSameUidUsesSameProfile) { - sp<NiceMock<MockLayer>> layer1 = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE1; - EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - sp<NiceMock<MockLayer>> layer2 = sp<NiceMock<MockLayer>>::make(flinger(), 200); - TestableLayerFE layerFE2; - EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - ActivePictureUpdater updater; - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(2); - layerFE2.onPictureProfileCommitted(); - updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), - UnorderedElementsAre({{100, 10, 1}, {200, 10, 2}})); - } - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(2); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE2.onPictureProfileCommitted(); - updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), - UnorderedElementsAre({{100, 10, 2}, {200, 10, 1}})); - } -} - -TEST_F(ActivePictureUpdaterTest, calledWhenNewLayerUsesSameProfile) { - sp<NiceMock<MockLayer>> layer1 = sp<NiceMock<MockLayer>>::make(flinger(), 100); - TestableLayerFE layerFE1; - EXPECT_CALL(*layer1, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - ActivePictureUpdater updater; - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), UnorderedElementsAre({{100, 10, 1}})); - } - - sp<NiceMock<MockLayer>> layer2 = sp<NiceMock<MockLayer>>::make(flinger(), 200); - TestableLayerFE layerFE2; - EXPECT_CALL(*layer2, getOwnerUid()).WillRepeatedly(Return(uid_t(10))); - - { - layerFE1.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE1.onPictureProfileCommitted(); - updater.onLayerComposed(*layer1, layerFE1, layerFE1.stealCompositionResult()); - - layerFE2.snapshot.pictureProfileHandle = PictureProfileHandle(1); - layerFE2.onPictureProfileCommitted(); - updater.onLayerComposed(*layer2, layerFE2, layerFE2.stealCompositionResult()); - - ASSERT_TRUE(updater.updateAndHasChanged()); - EXPECT_THAT(updater.getActivePictures(), - UnorderedElementsAre({{100, 10, 1}, {200, 10, 1}})); - } -} - -} // namespace android diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 6af51435c3..42259af7b0 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -103,6 +103,7 @@ cc_defaults { "librenderengine_deps", "libsurfaceflinger_common_test_deps", "libsurfaceflinger_proto_deps", + "poweradvisor_deps", ], static_libs: [ "android.hardware.common-V2-ndk", diff --git a/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h b/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h index b517ff02ad..c858d9a477 100644 --- a/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h +++ b/services/surfaceflinger/tests/unittests/CommitAndCompositeTest.h @@ -54,8 +54,8 @@ struct CommitAndCompositeTest : testing::Test { compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(), std::move(compostionEngineDisplayArgs)); mDisplay = FakeDisplayDeviceInjector(mFlinger, compositionDisplay, - ui::DisplayConnectionType::Internal, HWC_DISPLAY, - kIsPrimary) + ui::DisplayConnectionType::Internal, + DEFAULT_DISPLAY_PORT, HWC_DISPLAY, kIsPrimary) .setDisplaySurface(mDisplaySurface) .setNativeWindow(mNativeWindow) .setPowerMode(hal::PowerMode::ON) @@ -68,7 +68,9 @@ struct CommitAndCompositeTest : testing::Test { using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector; static constexpr hal::HWDisplayId HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID; - static constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u); + static constexpr uint8_t DEFAULT_DISPLAY_PORT = 42u; + static constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = + PhysicalDisplayId::fromPort(DEFAULT_DISPLAY_PORT); static constexpr int DEFAULT_DISPLAY_WIDTH = 1920; static constexpr int DEFAULT_DISPLAY_HEIGHT = 1024; diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index 860ad2e013..71cafbfd64 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -76,7 +76,8 @@ constexpr hal::HWDisplayId HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DIS constexpr hal::HWLayerId HWC_LAYER = 5000; constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0); -constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u); +constexpr uint8_t DEFAULT_DISPLAY_PORT = 42u; +constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(DEFAULT_DISPLAY_PORT); constexpr int DEFAULT_DISPLAY_WIDTH = 1920; constexpr int DEFAULT_DISPLAY_HEIGHT = 1024; @@ -276,7 +277,8 @@ struct BaseDisplayVariant { test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, - kDisplayConnectionType, HWC_DISPLAY, kIsPrimary) + kDisplayConnectionType, DEFAULT_DISPLAY_PORT, HWC_DISPLAY, + kIsPrimary) .setDisplaySurface(test->mDisplaySurface) .setNativeWindow(test->mNativeWindow) .setSecure(Derived::IS_SECURE) diff --git a/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp b/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp index 29a1fab5ff..c6cbe52c4a 100644 --- a/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayModeControllerTest.cpp @@ -71,7 +71,7 @@ public: ASSERT_TRUE(infoOpt); mDisplayId = infoOpt->id; - mDisplaySnapshotOpt.emplace(mDisplayId, ui::DisplayConnectionType::Internal, + mDisplaySnapshotOpt.emplace(mDisplayId, infoOpt->port, ui::DisplayConnectionType::Internal, makeModes(kMode60, kMode90, kMode120), ui::ColorModes{}, std::nullopt); diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h index fa976c8091..6e231aa7f4 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h @@ -231,6 +231,16 @@ struct HwcDisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> { static constexpr std::optional<HWDisplayId> value = PhysicalDisplay::HWC_DISPLAY_ID; }; +template <typename> +struct PortGetter { + static constexpr std::optional<uint8_t> value; +}; + +template <typename PhysicalDisplay> +struct PortGetter<PhysicalDisplayIdType<PhysicalDisplay>> { + static constexpr std::optional<uint8_t> value = PhysicalDisplay::PORT; +}; + // DisplayIdType can be: // 1) PhysicalDisplayIdType<...> for generated ID of physical display backed by HWC. // 2) HalVirtualDisplayIdType<...> for hard-coded ID of virtual display backed by HWC. @@ -241,6 +251,7 @@ struct DisplayVariant { using DISPLAY_ID = DisplayIdGetter<DisplayIdType>; using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>; using HWC_DISPLAY_ID_OPT = HwcDisplayIdGetter<DisplayIdType>; + using PORT = PortGetter<DisplayIdType>; static constexpr int WIDTH = width; static constexpr int HEIGHT = height; @@ -277,6 +288,7 @@ struct DisplayVariant { TestableSurfaceFlinger::FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay, CONNECTION_TYPE::value, + PORT::value, HWC_DISPLAY_ID_OPT::value, static_cast<bool>(PRIMARY)); @@ -558,6 +570,10 @@ using OuterDisplayNonSecureVariant = /*hasIdentificationData=*/true, kNonSecure>, 1080, 2092>; +using ExternalDisplayWithIdentificationVariant = + PhysicalDisplayVariant<SecondaryDisplay<ui::DisplayConnectionType::External, + /*hasIdentificationData=*/true, kNonSecure>, + 1920, 1280>; using ExternalDisplayVariant = PhysicalDisplayVariant<SecondaryDisplay<ui::DisplayConnectionType::External, /*hasIdentificationData=*/false, kSecure>, diff --git a/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h b/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h index 744c53637a..5f7a9f2422 100644 --- a/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h +++ b/services/surfaceflinger/tests/unittests/FakeDisplayInjector.h @@ -24,12 +24,15 @@ namespace android { +static constexpr uint8_t kDefaultPort = 255u; + using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector; using android::adpf::mock::PowerAdvisor; using android::hardware::graphics::composer::hal::HWDisplayId; struct FakeDisplayInjectorArgs { - PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(255u); + PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(kDefaultPort); + uint8_t port = kDefaultPort; HWDisplayId hwcDisplayId = 0; bool isPrimary = true; }; @@ -73,7 +76,7 @@ public: .build()); auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay, - ui::DisplayConnectionType::Internal, + ui::DisplayConnectionType::Internal, args.port, args.hwcDisplayId, args.isPrimary); injector.setNativeWindow(mNativeWindow); diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 8c53eef01a..4d322efe86 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -2021,16 +2021,13 @@ TEST_F(LayerSnapshotTest, contentDirtyWhenParentGeometryChanges) { EXPECT_FALSE(getSnapshot(1)->contentDirty); } TEST_F(LayerSnapshotTest, shouldUpdatePictureProfileHandle) { - if (!com_android_graphics_libgui_flags_apply_picture_profiles()) { - GTEST_SKIP() << "Flag disabled, skipping test"; - } std::vector<TransactionState> transactions; transactions.emplace_back(); transactions.back().states.push_back({}); - transactions.back().states.front().layerId = 1; - transactions.back().states.front().state.layerId = 1; - transactions.back().states.front().state.what = layer_state_t::ePictureProfileHandleChanged; - transactions.back().states.front().state.pictureProfileHandle = PictureProfileHandle(3); + transactions.back().states.back().layerId = 1; + transactions.back().states.back().state.layerId = 1; + transactions.back().states.back().state.what = layer_state_t::ePictureProfileHandleChanged; + transactions.back().states.back().state.pictureProfileHandle = PictureProfileHandle(3); mLifecycleManager.applyTransactions(transactions); EXPECT_EQ(mLifecycleManager.getGlobalChanges(), RequestedLayerState::Changes::Content); @@ -2042,23 +2039,50 @@ TEST_F(LayerSnapshotTest, shouldUpdatePictureProfileHandle) { } TEST_F(LayerSnapshotTest, shouldUpdatePictureProfilePriorityFromAppContentPriority) { - if (!com_android_graphics_libgui_flags_apply_picture_profiles()) { - GTEST_SKIP() << "Flag disabled, skipping test"; + { + std::vector<TransactionState> transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + transactions.back().states.back().layerId = 1; + transactions.back().states.back().state.layerId = 1; + transactions.back().states.back().state.what = layer_state_t::eAppContentPriorityChanged; + transactions.back().states.back().state.appContentPriority = 1; + transactions.back().states.push_back({}); + transactions.back().states.back().layerId = 2; + transactions.back().states.back().state.layerId = 2; + transactions.back().states.back().state.what = layer_state_t::eAppContentPriorityChanged; + transactions.back().states.back().state.appContentPriority = -1; + + mLifecycleManager.applyTransactions(transactions); + EXPECT_EQ(mLifecycleManager.getGlobalChanges(), RequestedLayerState::Changes::Content); + + update(mSnapshotBuilder); + + EXPECT_GT(getSnapshot(1)->pictureProfilePriority, getSnapshot(2)->pictureProfilePriority); + EXPECT_EQ(getSnapshot(1)->pictureProfilePriority - getSnapshot(2)->pictureProfilePriority, + 2); + } + { + std::vector<TransactionState> transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + transactions.back().states.back().layerId = 1; + transactions.back().states.back().state.layerId = 1; + transactions.back().states.back().state.what = layer_state_t::eAppContentPriorityChanged; + transactions.back().states.back().state.appContentPriority = INT_MIN; + transactions.back().states.push_back({}); + transactions.back().states.back().layerId = 2; + transactions.back().states.back().state.layerId = 2; + transactions.back().states.back().state.what = layer_state_t::eAppContentPriorityChanged; + transactions.back().states.back().state.appContentPriority = INT_MAX; + + mLifecycleManager.applyTransactions(transactions); + EXPECT_EQ(mLifecycleManager.getGlobalChanges(), RequestedLayerState::Changes::Content); + + update(mSnapshotBuilder); + + EXPECT_GT(getSnapshot(2)->pictureProfilePriority, getSnapshot(1)->pictureProfilePriority); } - std::vector<TransactionState> transactions; - transactions.emplace_back(); - transactions.back().states.push_back({}); - transactions.back().states.front().layerId = 1; - transactions.back().states.front().state.layerId = 1; - transactions.back().states.front().state.what = layer_state_t::eAppContentPriorityChanged; - transactions.back().states.front().state.appContentPriority = 3; - - mLifecycleManager.applyTransactions(transactions); - EXPECT_EQ(mLifecycleManager.getGlobalChanges(), RequestedLayerState::Changes::Content); - - update(mSnapshotBuilder); - - EXPECT_EQ(getSnapshot(1)->pictureProfilePriority, 3); } } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp index b0dd5c21f8..a506873d4c 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp @@ -126,8 +126,9 @@ public: static constexpr HWDisplayId kInnerDisplayHwcId = PrimaryDisplayVariant::HWC_DISPLAY_ID; static constexpr HWDisplayId kOuterDisplayHwcId = kInnerDisplayHwcId + 1; - - static constexpr PhysicalDisplayId kOuterDisplayId = PhysicalDisplayId::fromPort(254u); + static constexpr uint8_t kOuterDisplayPort = 254u; + static constexpr PhysicalDisplayId kOuterDisplayId = + PhysicalDisplayId::fromPort(kOuterDisplayPort); auto injectOuterDisplay() { // For the inner display, this is handled by setupHwcHotplugCallExpectations. @@ -149,6 +150,7 @@ public: kModeId120); }, {.displayId = kOuterDisplayId, + .port = kOuterDisplayPort, .hwcDisplayId = kOuterDisplayHwcId, .isPrimary = kIsPrimary}); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp index aef467ab9d..4e7a1742fd 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HotplugTest.cpp @@ -59,6 +59,137 @@ TEST_F(HotplugTest, schedulesFrameToCommitDisplayTransaction) { EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded)); } +TEST_F(HotplugTest, createsDisplaySnapshotsForDisplaysWithIdentificationData) { + // Configure a primary display with identification data. + using PrimaryDisplay = InnerDisplayVariant; + PrimaryDisplay::setupHwcHotplugCallExpectations(this); + PrimaryDisplay::setupHwcGetActiveConfigCallExpectations(this); + PrimaryDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED); + + // TODO(b/241286146): Remove this unnecessary call. + EXPECT_CALL(*mComposer, + setVsyncEnabled(PrimaryDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE)) + .WillOnce(Return(Error::NONE)); + + // A single commit should be scheduled. + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame(_)).Times(1); + + mFlinger.configure(); + + // Configure an external display with identification info. + using ExternalDisplay = ExternalDisplayWithIdentificationVariant; + ExternalDisplay::setupHwcHotplugCallExpectations(this); + ExternalDisplay::setupHwcGetActiveConfigCallExpectations(this); + ExternalDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED); + + // TODO(b/241286146): Remove this unnecessary call. + EXPECT_CALL(*mComposer, + setVsyncEnabled(ExternalDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE)) + .WillOnce(Return(Error::NONE)); + + mFlinger.configure(); + + EXPECT_TRUE(hasPhysicalHwcDisplay(PrimaryDisplay::HWC_DISPLAY_ID)); + EXPECT_TRUE(mFlinger.getHwComposer().isConnected(PrimaryDisplay::DISPLAY_ID::get())); + const auto primaryDisplayIdOpt = + mFlinger.getHwComposer().toPhysicalDisplayId(PrimaryDisplay::HWC_DISPLAY_ID); + ASSERT_TRUE(primaryDisplayIdOpt.has_value()); + const auto primaryPhysicalDisplayOpt = + mFlinger.physicalDisplays().get(primaryDisplayIdOpt.value()); + ASSERT_TRUE(primaryPhysicalDisplayOpt.has_value()); + const auto primaryDisplaySnapshotRef = primaryPhysicalDisplayOpt->get().snapshotRef(); + EXPECT_EQ(PrimaryDisplay::DISPLAY_ID::get(), primaryDisplaySnapshotRef.get().displayId()); + EXPECT_EQ(PrimaryDisplay::PORT::value, primaryDisplaySnapshotRef.get().port()); + EXPECT_EQ(PrimaryDisplay::CONNECTION_TYPE::value, + primaryDisplaySnapshotRef.get().connectionType()); + + EXPECT_TRUE(hasPhysicalHwcDisplay(ExternalDisplay::HWC_DISPLAY_ID)); + EXPECT_TRUE(mFlinger.getHwComposer().isConnected(ExternalDisplay::DISPLAY_ID::get())); + const auto externalDisplayIdOpt = + mFlinger.getHwComposer().toPhysicalDisplayId(ExternalDisplay::HWC_DISPLAY_ID); + ASSERT_TRUE(externalDisplayIdOpt.has_value()); + const auto externalPhysicalDisplayOpt = + mFlinger.physicalDisplays().get(externalDisplayIdOpt.value()); + ASSERT_TRUE(externalPhysicalDisplayOpt.has_value()); + const auto externalDisplaySnapshotRef = externalPhysicalDisplayOpt->get().snapshotRef(); + EXPECT_EQ(ExternalDisplay::DISPLAY_ID::get(), externalDisplaySnapshotRef.get().displayId()); + EXPECT_EQ(ExternalDisplay::PORT::value, externalDisplaySnapshotRef.get().port()); + EXPECT_EQ(ExternalDisplay::CONNECTION_TYPE::value, + externalDisplaySnapshotRef.get().connectionType()); +} + +TEST_F(HotplugTest, createsDisplaySnapshotsForDisplaysWithoutIdentificationData) { + // Configure a primary display without identification data. + using PrimaryDisplay = PrimaryDisplayVariant; + PrimaryDisplay::setupHwcHotplugCallExpectations(this); + PrimaryDisplay::setupHwcGetActiveConfigCallExpectations(this); + PrimaryDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED); + + // TODO(b/241286146): Remove this unnecessary call. + EXPECT_CALL(*mComposer, + setVsyncEnabled(PrimaryDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE)) + .WillOnce(Return(Error::NONE)); + + // A single commit should be scheduled. + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame(_)).Times(1); + + mFlinger.configure(); + + // Configure an external display with identification info. + using ExternalDisplay = ExternalDisplayWithIdentificationVariant; + ExternalDisplay::setupHwcHotplugCallExpectations(this); + ExternalDisplay::setupHwcGetActiveConfigCallExpectations(this); + ExternalDisplay::injectPendingHotplugEvent(this, Connection::CONNECTED); + + // TODO(b/241286146): Remove this unnecessary call. + EXPECT_CALL(*mComposer, + setVsyncEnabled(ExternalDisplay::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE)) + .WillOnce(Return(Error::NONE)); + + mFlinger.configure(); + + // Both ID and port are expected to be equal to 0 for primary internal display due to no + // identification data. + constexpr uint8_t primaryInternalDisplayPort = 0u; + constexpr PhysicalDisplayId primaryInternalDisplayId = + PhysicalDisplayId::fromPort(primaryInternalDisplayPort); + EXPECT_TRUE(hasPhysicalHwcDisplay(PrimaryDisplay::HWC_DISPLAY_ID)); + ASSERT_EQ(primaryInternalDisplayId, PrimaryDisplay::DISPLAY_ID::get()); + EXPECT_TRUE(mFlinger.getHwComposer().isConnected(PrimaryDisplay::DISPLAY_ID::get())); + const auto primaryDisplayIdOpt = + mFlinger.getHwComposer().toPhysicalDisplayId(PrimaryDisplay::HWC_DISPLAY_ID); + ASSERT_TRUE(primaryDisplayIdOpt.has_value()); + const auto primaryPhysicalDisplayOpt = + mFlinger.physicalDisplays().get(primaryDisplayIdOpt.value()); + ASSERT_TRUE(primaryPhysicalDisplayOpt.has_value()); + const auto primaryDisplaySnapshotRef = primaryPhysicalDisplayOpt->get().snapshotRef(); + EXPECT_EQ(primaryInternalDisplayId, primaryDisplaySnapshotRef.get().displayId()); + EXPECT_EQ(primaryInternalDisplayPort, primaryDisplaySnapshotRef.get().port()); + EXPECT_EQ(PrimaryDisplay::CONNECTION_TYPE::value, + primaryDisplaySnapshotRef.get().connectionType()); + + // Even though the external display has identification data available, the lack of data for the + // internal display has set of the legacy multi-display mode in SF and therefore the external + // display's identification data will be ignored. + // Both ID and port are expected to be equal to 1 for external internal display. + constexpr uint8_t externalDisplayPort = 1u; + constexpr PhysicalDisplayId externalDisplayId = + PhysicalDisplayId::fromPort(externalDisplayPort); + EXPECT_TRUE(hasPhysicalHwcDisplay(ExternalDisplay::HWC_DISPLAY_ID)); + EXPECT_TRUE(mFlinger.getHwComposer().isConnected(externalDisplayId)); + const auto externalDisplayIdOpt = + mFlinger.getHwComposer().toPhysicalDisplayId(ExternalDisplay::HWC_DISPLAY_ID); + ASSERT_TRUE(externalDisplayIdOpt.has_value()); + const auto externalPhysicalDisplayOpt = + mFlinger.physicalDisplays().get(externalDisplayIdOpt.value()); + ASSERT_TRUE(externalPhysicalDisplayOpt.has_value()); + const auto externalDisplaySnapshotRef = externalPhysicalDisplayOpt->get().snapshotRef(); + EXPECT_EQ(externalDisplayId, externalDisplaySnapshotRef.get().displayId()); + EXPECT_EQ(externalDisplayPort, externalDisplaySnapshotRef.get().port()); + EXPECT_EQ(ExternalDisplay::CONNECTION_TYPE::value, + externalDisplaySnapshotRef.get().connectionType()); +} + TEST_F(HotplugTest, ignoresDuplicateDisconnection) { // Inject a primary display. PrimaryDisplayVariant::injectHwcDisplay(this); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp index 352000ef9a..6951eaf093 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp @@ -239,6 +239,8 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { ASSERT_TRUE(displayId); const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value; ASSERT_TRUE(hwcDisplayId); + const auto port = Case::Display::PORT::value; + ASSERT_TRUE(port); mFlinger.getHwComposer().allocatePhysicalDisplay(*hwcDisplayId, *displayId, std::nullopt); DisplayModePtr activeMode = DisplayMode::Builder(Case::Display::HWC_ACTIVE_CONFIG_ID) .setResolution(Case::Display::RESOLUTION) @@ -258,7 +260,7 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { } const auto it = mFlinger.mutablePhysicalDisplays() - .emplace_or_replace(*displayId, displayToken, *displayId, + .emplace_or_replace(*displayId, displayToken, *displayId, *port, *kConnectionTypeOpt, makeModes(activeMode), std::move(colorModes), std::nullopt) .first; @@ -299,6 +301,13 @@ void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() { mFlinger.mutableDisplayModeController() .getActiveMode(device->getPhysicalId()) .modePtr->getHwcId()); + + EXPECT_EQ(Case::Display::PORT::value, + mFlinger.physicalDisplays() + .get(device->getPhysicalId()) + .transform([](const display::PhysicalDisplay& display) { + return display.snapshot().port(); + })); } } diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 7f0b7a6585..bd1382e851 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -947,11 +947,13 @@ public: FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, std::shared_ptr<compositionengine::Display> display, std::optional<ui::DisplayConnectionType> connectionType, + std::optional<uint8_t> port, std::optional<hal::HWDisplayId> hwcDisplayId, bool isPrimary) : mFlinger(flinger), mCreationArgs(flinger.mFlinger, flinger.mFlinger->getHwComposer(), mDisplayToken, display), mConnectionType(connectionType), + mPort(port), mHwcDisplayId(hwcDisplayId) { mCreationArgs.isPrimary = isPrimary; mCreationArgs.initialPowerMode = hal::PowerMode::ON; @@ -1100,11 +1102,12 @@ public: .hwcDisplayId = *mHwcDisplayId, .activeMode = activeModeOpt->get()}; - const auto it = mFlinger.mutablePhysicalDisplays() - .emplace_or_replace(*physicalId, mDisplayToken, *physicalId, - *mConnectionType, std::move(modes), - ui::ColorModes(), std::nullopt) - .first; + const auto it = + mFlinger.mutablePhysicalDisplays() + .emplace_or_replace(*physicalId, mDisplayToken, *physicalId, *mPort, + *mConnectionType, std::move(modes), + ui::ColorModes(), std::nullopt) + .first; mFlinger.mutableDisplayModeController() .registerDisplay(*physicalId, it->second.snapshot(), @@ -1138,6 +1141,7 @@ public: DisplayModeId mActiveModeId; bool mSchedulerRegistration = true; const std::optional<ui::DisplayConnectionType> mConnectionType; + const std::optional<uint8_t> mPort; const std::optional<hal::HWDisplayId> mHwcDisplayId; }; diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h index 0d5266e113..2bf66ac54e 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h @@ -190,6 +190,9 @@ public: MOCK_METHOD(Error, getMaxLayerPictureProfiles, (Display, int32_t*)); MOCK_METHOD(Error, setDisplayPictureProfileId, (Display, PictureProfileId id)); MOCK_METHOD(Error, setLayerPictureProfileId, (Display, Layer, PictureProfileId id)); + MOCK_METHOD(Error, getLuts, + (Display, const std::vector<sp<GraphicBuffer>>&, + std::vector<aidl::android::hardware::graphics::composer3::Luts>*)); }; } // namespace Hwc2::mock diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h index ec065a773c..4ca6fe073b 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWC2.h @@ -116,6 +116,10 @@ public: MOCK_METHOD(hal::Error, getMaxLayerPictureProfiles, (int32_t*), (override)); MOCK_METHOD(hal::Error, setPictureProfileHandle, (const android::PictureProfileHandle&), (override)); + MOCK_METHOD(hal::Error, getLuts, + (const std::vector<android::sp<android::GraphicBuffer>>&, + std::vector<aidl::android::hardware::graphics::composer3::Luts>*), + (override)); }; class Layer : public HWC2::Layer { diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWComposer.h index 88f83d2e07..7bd85cd59f 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWComposer.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockHWComposer.h @@ -151,6 +151,9 @@ public: MOCK_METHOD(int32_t, getMaxLayerPictureProfiles, (PhysicalDisplayId)); MOCK_METHOD(status_t, setDisplayPictureProfileHandle, (PhysicalDisplayId, const PictureProfileHandle&)); + MOCK_METHOD(status_t, getLuts, + (PhysicalDisplayId, const std::vector<sp<GraphicBuffer>>&, + std::vector<aidl::android::hardware::graphics::composer3::Luts>*)); }; } // namespace android::mock diff --git a/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h index 5c4512a2df..fd55597d7a 100644 --- a/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h +++ b/services/surfaceflinger/tests/unittests/mock/PowerAdvisor/MockPowerAdvisor.h @@ -63,6 +63,8 @@ public: MOCK_METHOD(void, setCompositeEnd, (TimePoint compositeEndTime), (override)); MOCK_METHOD(void, setDisplays, (std::vector<DisplayId> & displayIds), (override)); MOCK_METHOD(void, setTotalFrameTargetWorkDuration, (Duration targetDuration), (override)); + MOCK_METHOD(std::shared_ptr<SessionManager>, getSessionManager, (), (override)); + MOCK_METHOD(sp<IBinder>, getOrCreateSessionManagerForBinder, (uid_t uid), (override)); }; } // namespace android::adpf::mock |