diff options
264 files changed, 9221 insertions, 8505 deletions
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index 5267b0294c..891b1c6b0b 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -181,6 +181,8 @@ on late-init chmod 0666 /sys/kernel/tracing/events/clk/clk_enable/enable chmod 0666 /sys/kernel/debug/tracing/events/clk/clk_set_rate/enable chmod 0666 /sys/kernel/tracing/events/clk/clk_set_rate/enable + chmod 0666 /sys/kernel/debug/tracing/events/printk/console/enable + chmod 0666 /sys/kernel/tracing/events/printk/console/enable # disk chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable diff --git a/data/etc/android.hardware.type.automotive.xml b/data/etc/android.hardware.type.automotive.xml index 113945b0c5..a9b4b0526a 100644 --- a/data/etc/android.hardware.type.automotive.xml +++ b/data/etc/android.hardware.type.automotive.xml @@ -17,6 +17,4 @@ <!-- These features determine that the device running android is a car. --> <permissions> <feature name="android.hardware.type.automotive" /> - <!-- TODO: Revert this after enabling work profiles refer b/170332519 --> - <unavailable-feature name="android.software.managed_users"/> </permissions> diff --git a/include/input/Input.h b/include/input/Input.h index e7d68fc349..e0c9de49bf 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -1059,6 +1059,48 @@ public: uint32_t seq; }; +/* Pointer icon styles. + * Must match the definition in android.view.PointerIcon. + * + * Due to backwards compatibility and public api constraints, this is a duplicate (but type safe) + * definition of PointerIcon.java. + * + * TODO(b/235023317) move this definition to an aidl and statically assign to the below java public + * api values. + * + * WARNING: Keep these definitions in sync with + * frameworks/base/core/java/android/view/PointerIcon.java + */ +enum class PointerIconStyle : int32_t { + TYPE_CUSTOM = -1, + TYPE_NULL = 0, + TYPE_ARROW = 1000, + TYPE_CONTEXT_MENU = 1001, + TYPE_HAND = 1002, + TYPE_HELP = 1003, + TYPE_WAIT = 1004, + TYPE_CELL = 1006, + TYPE_CROSSHAIR = 1007, + TYPE_TEXT = 1008, + TYPE_VERTICAL_TEXT = 1009, + TYPE_ALIAS = 1010, + TYPE_COPY = 1011, + TYPE_NO_DROP = 1012, + TYPE_ALL_SCROLL = 1013, + TYPE_HORIZONTAL_DOUBLE_ARROW = 1014, + TYPE_VERTICAL_DOUBLE_ARROW = 1015, + TYPE_TOP_RIGHT_DOUBLE_ARROW = 1016, + TYPE_TOP_LEFT_DOUBLE_ARROW = 1017, + TYPE_ZOOM_IN = 1018, + TYPE_ZOOM_OUT = 1019, + TYPE_GRAB = 1020, + TYPE_GRABBING = 1021, + + TYPE_SPOT_HOVER = 2000, + TYPE_SPOT_TOUCH = 2001, + TYPE_SPOT_ANCHOR = 2002, +}; + } // namespace android #endif // _LIBINPUT_INPUT_H diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h index 5f9a37d69c..dbc7bfa388 100644 --- a/include/input/InputTransport.h +++ b/include/input/InputTransport.h @@ -452,8 +452,11 @@ private: */ class InputConsumer { public: - /* Creates a consumer associated with an input channel. */ + /* Create a consumer associated with an input channel. */ explicit InputConsumer(const std::shared_ptr<InputChannel>& channel); + /* Create a consumer associated with an input channel, override resampling system property */ + explicit InputConsumer(const std::shared_ptr<InputChannel>& channel, + bool enableTouchResampling); /* Destroys the consumer and releases its input channel. */ ~InputConsumer(); diff --git a/include/input/PropertyMap.h b/include/input/PropertyMap.h index 451918bb46..b1e3f85ed5 100644 --- a/include/input/PropertyMap.h +++ b/include/input/PropertyMap.h @@ -18,10 +18,8 @@ #define _UTILS_PROPERTY_MAP_H #include <android-base/result.h> -#include <utils/Errors.h> -#include <utils/KeyedVector.h> -#include <utils/String8.h> #include <utils/Tokenizer.h> +#include <unordered_map> namespace android { @@ -58,30 +56,27 @@ public: /* Adds a property. * Replaces the property with the same key if it is already present. */ - void addProperty(const String8& key, const String8& value); - - /* Returns true if the property map contains the specified key. */ - bool hasProperty(const String8& key) const; + void addProperty(const std::string& key, const std::string& value); /* Gets the value of a property and parses it. * Returns true and sets outValue if the key was found and its value was parsed successfully. * Otherwise returns false and does not modify outValue. (Also logs a warning.) */ - bool tryGetProperty(const String8& key, String8& outValue) const; - bool tryGetProperty(const String8& key, bool& outValue) const; - bool tryGetProperty(const String8& key, int32_t& outValue) const; - bool tryGetProperty(const String8& key, float& outValue) const; + bool tryGetProperty(const std::string& key, std::string& outValue) const; + bool tryGetProperty(const std::string& key, bool& outValue) const; + bool tryGetProperty(const std::string& key, int32_t& outValue) const; + bool tryGetProperty(const std::string& key, float& outValue) const; /* Adds all values from the specified property map. */ void addAll(const PropertyMap* map); - /* Gets the underlying property map. */ - inline const KeyedVector<String8, String8>& getProperties() const { return mProperties; } - /* Loads a property map from a file. */ static android::base::Result<std::unique_ptr<PropertyMap>> load(const char* filename); private: + /* Returns true if the property map contains the specified key. */ + bool hasProperty(const std::string& key) const; + class Parser { PropertyMap* mMap; Tokenizer* mTokenizer; @@ -95,11 +90,11 @@ private: status_t parseType(); status_t parseKey(); status_t parseKeyProperty(); - status_t parseModifier(const String8& token, int32_t* outMetaState); + status_t parseModifier(const std::string& token, int32_t* outMetaState); status_t parseCharacterLiteral(char16_t* outCharacter); }; - KeyedVector<String8, String8> mProperties; + std::unordered_map<std::string, std::string> mProperties; }; } // namespace android diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp index 441a4a8be4..5e9f5407fd 100644 --- a/libs/binder/Android.bp +++ b/libs/binder/Android.bp @@ -260,10 +260,6 @@ cc_library { }, afdo: true, - - header_abi_checker: { - diff_flags: ["-allow-adding-removing-weak-symbols"], - }, } cc_library_static { @@ -367,9 +363,7 @@ aidl_interface { local_include_dir: "aidl", host_supported: true, srcs: [ - "aidl/android/content/pm/IPackageChangeObserver.aidl", "aidl/android/content/pm/IPackageManagerNative.aidl", - "aidl/android/content/pm/PackageChangeEvent.aidl", "aidl/android/content/pm/IStagedApexObserver.aidl", "aidl/android/content/pm/ApexStagedEvent.aidl", "aidl/android/content/pm/StagedApexInfo.aidl", diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl index 7c99f76ec6..f8a8843309 100644 --- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl +++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl @@ -17,7 +17,6 @@ package android.content.pm; -import android.content.pm.IPackageChangeObserver; import android.content.pm.IStagedApexObserver; import android.content.pm.StagedApexInfo; @@ -92,18 +91,6 @@ interface IPackageManagerNative { */ @utf8InCpp String getModuleMetadataPackageName(); - /* Returns the names of all packages. */ - @utf8InCpp String[] getAllPackages(); - - /** Register an extra package change observer to receive the multi-cast. */ - void registerPackageChangeObserver(in IPackageChangeObserver observer); - - /** - * Unregister an existing package change observer. - * This does nothing if this observer was not already registered. - */ - void unregisterPackageChangeObserver(in IPackageChangeObserver observer); - /** * Returns true if the package has the SHA 256 version of the signing certificate. * @see PackageManager#hasSigningCertificate(String, byte[], int), where type diff --git a/libs/binder/include/binder/IInterface.h b/libs/binder/include/binder/IInterface.h index 9f7e2c87b8..dc572ac953 100644 --- a/libs/binder/include/binder/IInterface.h +++ b/libs/binder/include/binder/IInterface.h @@ -219,80 +219,79 @@ inline IBinder* BpInterface<INTERFACE>::onAsBinder() namespace internal { constexpr const char* const kManualInterfaces[] = { - "android.app.IActivityManager", - "android.app.IUidObserver", - "android.drm.IDrm", - "android.dvr.IVsyncCallback", - "android.dvr.IVsyncService", - "android.gfx.tests.ICallback", - "android.gfx.tests.IIPCTest", - "android.gfx.tests.ISafeInterfaceTest", - "android.graphicsenv.IGpuService", - "android.gui.IConsumerListener", - "android.gui.IGraphicBufferConsumer", - "android.gui.ITransactionComposerListener", - "android.gui.SensorEventConnection", - "android.gui.SensorServer", - "android.hardware.ICamera", - "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", - "android.media.IMediaMetadataRetriever", - "android.media.IMediaMetricsService", - "android.media.IMediaPlayer", - "android.media.IMediaPlayerClient", - "android.media.IMediaPlayerService", - "android.media.IMediaRecorder", - "android.media.IMediaRecorderClient", - "android.media.IMediaResourceMonitor", - "android.media.IMediaSource", - "android.media.IRemoteDisplay", - "android.media.IRemoteDisplayClient", - "android.media.IResourceManagerClient", - "android.media.IResourceManagerService", - "android.os.IComplexTypeInterface", - "android.os.IPermissionController", - "android.os.IPingResponder", - "android.os.IProcessInfoService", - "android.os.ISchedulingPolicyService", - "android.os.IStringConstants", - "android.os.storage.IObbActionListener", - "android.os.storage.IStorageEventListener", - "android.os.storage.IStorageManager", - "android.os.storage.IStorageShutdownObserver", - "android.service.vr.IPersistentVrStateCallbacks", - "android.service.vr.IVrManager", - "android.service.vr.IVrStateCallbacks", - "android.ui.ISurfaceComposer", - "android.ui.ISurfaceComposerClient", - "android.utils.IMemory", - "android.utils.IMemoryHeap", - "com.android.car.procfsinspector.IProcfsInspector", - "com.android.internal.app.IAppOpsCallback", - "com.android.internal.app.IAppOpsService", - "com.android.internal.app.IBatteryStats", - "com.android.internal.os.IResultReceiver", - "com.android.internal.os.IShellCallback", - "drm.IDrmManagerService", - "drm.IDrmServiceListener", - "IAAudioClient", - "IAAudioService", - "VtsFuzzer", - nullptr, + "android.app.IActivityManager", + "android.app.IUidObserver", + "android.drm.IDrm", + "android.dvr.IVsyncCallback", + "android.dvr.IVsyncService", + "android.gfx.tests.ICallback", + "android.gfx.tests.IIPCTest", + "android.gfx.tests.ISafeInterfaceTest", + "android.graphicsenv.IGpuService", + "android.gui.IConsumerListener", + "android.gui.IGraphicBufferConsumer", + "android.gui.ITransactionComposerListener", + "android.gui.SensorEventConnection", + "android.gui.SensorServer", + "android.hardware.ICamera", + "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", + "android.media.IMediaMetadataRetriever", + "android.media.IMediaMetricsService", + "android.media.IMediaPlayer", + "android.media.IMediaPlayerClient", + "android.media.IMediaPlayerService", + "android.media.IMediaRecorder", + "android.media.IMediaRecorderClient", + "android.media.IMediaResourceMonitor", + "android.media.IMediaSource", + "android.media.IRemoteDisplay", + "android.media.IRemoteDisplayClient", + "android.media.IResourceManagerClient", + "android.media.IResourceManagerService", + "android.os.IComplexTypeInterface", + "android.os.IPermissionController", + "android.os.IPingResponder", + "android.os.IProcessInfoService", + "android.os.ISchedulingPolicyService", + "android.os.IStringConstants", + "android.os.storage.IObbActionListener", + "android.os.storage.IStorageEventListener", + "android.os.storage.IStorageManager", + "android.os.storage.IStorageShutdownObserver", + "android.service.vr.IPersistentVrStateCallbacks", + "android.service.vr.IVrManager", + "android.service.vr.IVrStateCallbacks", + "android.ui.ISurfaceComposer", + "android.utils.IMemory", + "android.utils.IMemoryHeap", + "com.android.car.procfsinspector.IProcfsInspector", + "com.android.internal.app.IAppOpsCallback", + "com.android.internal.app.IAppOpsService", + "com.android.internal.app.IBatteryStats", + "com.android.internal.os.IResultReceiver", + "com.android.internal.os.IShellCallback", + "drm.IDrmManagerService", + "drm.IDrmServiceListener", + "IAAudioClient", + "IAAudioService", + "VtsFuzzer", + nullptr, }; constexpr const char* const kDownstreamManualInterfaces[] = { diff --git a/libs/bufferqueueconverter/Android.bp b/libs/bufferqueueconverter/Android.bp index c5d3a3207c..5f145a149d 100644 --- a/libs/bufferqueueconverter/Android.bp +++ b/libs/bufferqueueconverter/Android.bp @@ -22,6 +22,7 @@ cc_library_shared { double_loadable: true, srcs: [ + ":libgui_frame_event_aidl", "BufferQueueConverter.cpp", ], diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp index 7f0cac5d4f..4a0a839948 100644 --- a/libs/graphicsenv/GraphicsEnv.cpp +++ b/libs/graphicsenv/GraphicsEnv.cpp @@ -364,26 +364,61 @@ bool GraphicsEnv::shouldUseAngle() { return (mUseAngle == YES) ? true : false; } +bool GraphicsEnv::angleIsSystemDriver() { + // Make sure we are init'ed + if (mAngleAppName.empty()) { + ALOGV("App name is empty. setAngleInfo() has not been called to enable ANGLE."); + return false; + } + + return (mAngleIsSystemDriver == YES) ? true : false; +} + +bool GraphicsEnv::shouldForceLegacyDriver() { + // Make sure we are init'ed + if (mAngleAppName.empty()) { + ALOGV("App name is empty. setAngleInfo() has not been called to enable ANGLE."); + return false; + } + + return (mAngleIsSystemDriver == YES && mUseAngle == NO) ? true : false; +} + +std::string GraphicsEnv::getLegacySuffix() { + return mLegacyDriverSuffix; +} + void GraphicsEnv::updateUseAngle() { mUseAngle = NO; const char* ANGLE_PREFER_ANGLE = "angle"; + const char* ANGLE_PREFER_LEGACY = "legacy"; + // The following is a deprecated version of "legacy" const char* ANGLE_PREFER_NATIVE = "native"; mUseAngle = NO; if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) { - ALOGV("User set \"Developer Options\" to force the use of ANGLE"); + ALOGI("Using ANGLE, the %s GLES driver for package '%s'", + mAngleIsSystemDriver == YES ? "system" : "optional", mAngleAppName.c_str()); mUseAngle = YES; - } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) { - ALOGV("User set \"Developer Options\" to force the use of Native"); + } else if (mAngleDeveloperOptIn == ANGLE_PREFER_LEGACY || + mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) { + ALOGI("Using the (%s) Legacy GLES driver for package '%s'", + mAngleIsSystemDriver == YES ? "optional" : "system", mAngleAppName.c_str()); } else { ALOGV("User set invalid \"Developer Options\": '%s'", mAngleDeveloperOptIn.c_str()); } } void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName, - const std::string developerOptIn, + const bool angleIsSystemDriver, const std::string developerOptIn, const std::vector<std::string> eglFeatures) { + // Set whether ANGLE is the system driver: + mAngleIsSystemDriver = angleIsSystemDriver ? YES : NO; + + // Note: Given the current logic and lack of the old rules file processing, + // there seems to be little chance that mUseAngle != UNKNOWN. Leave this + // for now, even though it seems outdated. if (mUseAngle != UNKNOWN) { // We've already figured out an answer for this app, so just return. ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", appName.c_str(), @@ -404,6 +439,25 @@ void GraphicsEnv::setAngleInfo(const std::string path, const std::string appName updateUseAngle(); } +void GraphicsEnv::setLegacyDriverInfo(const std::string appName, const bool angleIsSystemDriver, + const std::string legacyDriverName) { + ALOGV("setting legacy app name to '%s'", appName.c_str()); + mAngleAppName = appName; + + // Force the use of the legacy driver instead of ANGLE + const char* ANGLE_PREFER_LEGACY = "legacy"; + mAngleDeveloperOptIn = ANGLE_PREFER_LEGACY; + ALOGV("setting ANGLE application opt-in to 'legacy'"); + + // Set whether ANGLE is the system driver: + mAngleIsSystemDriver = angleIsSystemDriver ? YES : NO; + + mLegacyDriverSuffix = legacyDriverName; + + // Update the current status of whether we should use ANGLE or not + updateUseAngle(); +} + void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths) { if (mLayerPaths.empty()) { mLayerPaths = layerPaths; diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h index 56d1139f57..82a6b6c2c0 100644 --- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h +++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h @@ -91,17 +91,28 @@ public: bool shouldUseAngle(std::string appName); // Check if this app process should use ANGLE. bool shouldUseAngle(); + // If ANGLE is the system GLES driver + bool angleIsSystemDriver(); + // If should use legacy driver instead of a system ANGLE driver + bool shouldForceLegacyDriver(); // Set a search path for loading ANGLE libraries. The path is a list of // directories separated by ':'. A directory can be contained in a zip file // (libraries must be stored uncompressed and page aligned); such elements // in the search path must have a '!' after the zip filename, e.g. // /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a - void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn, + void setAngleInfo(const std::string path, const std::string appName, + const bool angleIsSystemDriver, std::string devOptIn, const std::vector<std::string> eglFeatures); + // Set the state so that the legacy driver will be used, and in case ANGLE + // is the system driver, provide the name of the legacy driver. + void setLegacyDriverInfo(const std::string appName, const bool angleIsSystemDriver, + const std::string legacyDriverName); // Get the ANGLE driver namespace. android_namespace_t* getAngleNamespace(); // Get the app name for ANGLE debug message. std::string& getAngleAppName(); + // Get the legacy driver's suffix name. + std::string getLegacySuffix(); const std::vector<std::string>& getAngleEglFeatures(); @@ -156,6 +167,10 @@ private: std::string mAngleDeveloperOptIn; // ANGLE EGL features; std::vector<std::string> mAngleEglFeatures; + // ANGLE is System Driver flag. + UseAngle mAngleIsSystemDriver = UNKNOWN; + // Legacy driver name to use when ANGLE is the system driver. + std::string mLegacyDriverSuffix; // Use ANGLE flag. UseAngle mUseAngle = UNKNOWN; // Vulkan debug layers libs. diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 5a2b92b0ff..d7bc5002bf 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -120,6 +120,12 @@ filegroup { path: "aidl/", } +filegroup { + name: "libgui_frame_event_aidl", + srcs: ["aidl/android/gui/FrameEvent.aidl"], + path: "aidl/", +} + cc_library_static { name: "libgui_aidl_static", vendor_available: true, @@ -136,16 +142,24 @@ cc_library_static { "include", ], + include_dirs: [ + "frameworks/native/include", + ], + export_shared_lib_headers: [ "libbinder", ], static_libs: [ "libui-types", + "libgui_window_info_static", ], aidl: { export_aidl_headers: true, + include_dirs: [ + "frameworks/native/libs/gui", + ], }, } @@ -179,19 +193,18 @@ cc_library_shared { "BufferHubConsumer.cpp", "BufferHubProducer.cpp", "BufferItemConsumer.cpp", + "CompositorTiming.cpp", "ConsumerBase.cpp", "CpuConsumer.cpp", "DebugEGLImageTracker.cpp", "DisplayEventDispatcher.cpp", "DisplayEventReceiver.cpp", - "FrameTimelineInfo.cpp", "GLConsumer.cpp", "IConsumerListener.cpp", "IGraphicBufferConsumer.cpp", "IGraphicBufferProducer.cpp", "IProducerListener.cpp", "ISurfaceComposer.cpp", - "ISurfaceComposerClient.cpp", "ITransactionCompletedListener.cpp", "LayerDebugInfo.cpp", "LayerMetadata.cpp", @@ -282,10 +295,16 @@ cc_library_static { defaults: ["libgui_bufferqueue-defaults"], srcs: [ + ":libgui_frame_event_aidl", ":inputconstants_aidl", ":libgui_bufferqueue_sources", - ":libgui_aidl", ], + + aidl: { + include_dirs: [ + "frameworks/native/libs/gui", + ], + }, } filegroup { @@ -404,6 +423,7 @@ cc_library_static { ], srcs: [ + ":libgui_frame_event_aidl", "mock/GraphicBufferConsumer.cpp", "mock/GraphicBufferProducer.cpp", ], diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index aba81f60d8..3bf2e195c5 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -33,6 +33,7 @@ #include <utils/Trace.h> #include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <chrono> @@ -158,9 +159,8 @@ BLASTBufferQueue::BLASTBufferQueue(const std::string& name, bool updateDestinati id++; mBufferItemConsumer->setName(String8(consumerName.c_str())); mBufferItemConsumer->setFrameAvailableListener(this); - mBufferItemConsumer->setBufferFreedListener(this); - ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers); + ComposerServiceAIDL::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers); mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers); mCurrentMaxAcquiredBufferCount = mMaxAcquiredBuffers; mNumAcquired = 0; @@ -566,7 +566,7 @@ void BLASTBufferQueue::acquireNextBufferLocked( if (dequeueTime != mDequeueTimestamps.end()) { Parcel p; p.writeInt64(dequeueTime->second); - t->setMetadata(mSurfaceControl, METADATA_DEQUEUE_TIME, p); + t->setMetadata(mSurfaceControl, gui::METADATA_DEQUEUE_TIME, p); mDequeueTimestamps.erase(dequeueTime); } } @@ -599,6 +599,7 @@ Rect BLASTBufferQueue::computeCrop(const BufferItem& item) { } void BLASTBufferQueue::acquireAndReleaseBuffer() { + BBQ_TRACE(); BufferItem bufferItem; status_t status = mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false); @@ -612,6 +613,7 @@ void BLASTBufferQueue::acquireAndReleaseBuffer() { } void BLASTBufferQueue::flushAndWaitForFreeBuffer(std::unique_lock<std::mutex>& lock) { + BBQ_TRACE(); if (!mSyncedFrameNumbers.empty() && mNumFrameAvailable > 0) { // We are waiting on a previous sync's transaction callback so allow another sync // transaction to proceed. @@ -642,8 +644,8 @@ void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) { bool waitForTransactionCallback = !mSyncedFrameNumbers.empty(); { - BBQ_TRACE(); std::unique_lock _lock{mMutex}; + BBQ_TRACE(); const bool syncTransactionSet = mTransactionReadyCallback != nullptr; BQA_LOGV("onFrameAvailable-start syncTransactionSet=%s", boolToString(syncTransactionSet)); @@ -1119,7 +1121,6 @@ void BLASTBufferQueue::abandon() { if (mBufferItemConsumer != nullptr) { mBufferItemConsumer->abandon(); mBufferItemConsumer->setFrameAvailableListener(nullptr); - mBufferItemConsumer->setBufferFreedListener(nullptr); } mBufferItemConsumer = nullptr; mConsumer = nullptr; diff --git a/libs/gui/CompositorTiming.cpp b/libs/gui/CompositorTiming.cpp new file mode 100644 index 0000000000..50f7b252b6 --- /dev/null +++ b/libs/gui/CompositorTiming.cpp @@ -0,0 +1,54 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "CompositorTiming" + +#include <cutils/compiler.h> +#include <gui/CompositorTiming.h> +#include <log/log.h> + +namespace android::gui { + +CompositorTiming::CompositorTiming(nsecs_t vsyncDeadline, nsecs_t vsyncPeriod, nsecs_t vsyncPhase, + nsecs_t presentLatency) { + if (CC_UNLIKELY(vsyncPeriod <= 0)) { + ALOGE("Invalid VSYNC period"); + return; + } + + const nsecs_t idealLatency = [=] { + // Modulo rounds toward 0 not INT64_MIN, so treat signs separately. + if (vsyncPhase < 0) return -vsyncPhase % vsyncPeriod; + + const nsecs_t latency = (vsyncPeriod - vsyncPhase) % vsyncPeriod; + return latency > 0 ? latency : vsyncPeriod; + }(); + + // Snap the latency to a value that removes scheduling jitter from the composite and present + // times, which often have >1ms of jitter. Reducing jitter is important if an app attempts to + // extrapolate something like user input to an accurate present time. Snapping also allows an + // app to precisely calculate vsyncPhase with (presentLatency % interval). + const nsecs_t bias = vsyncPeriod / 2; + const nsecs_t extraVsyncs = (presentLatency - idealLatency + bias) / vsyncPeriod; + const nsecs_t snappedLatency = + extraVsyncs > 0 ? idealLatency + extraVsyncs * vsyncPeriod : idealLatency; + + this->deadline = vsyncDeadline - idealLatency; + this->interval = vsyncPeriod; + this->presentLatency = snappedLatency; +} + +} // namespace android::gui diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp index dfdce20438..501e69ade5 100644 --- a/libs/gui/DisplayEventDispatcher.cpp +++ b/libs/gui/DisplayEventDispatcher.cpp @@ -35,11 +35,14 @@ static const size_t EVENT_BUFFER_SIZE = 100; static constexpr nsecs_t WAITING_FOR_VSYNC_TIMEOUT = ms2ns(300); -DisplayEventDispatcher::DisplayEventDispatcher( - const sp<Looper>& looper, ISurfaceComposer::VsyncSource vsyncSource, - ISurfaceComposer::EventRegistrationFlags eventRegistration) - : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false), - mLastVsyncCount(0), mLastScheduleVsyncTime(0) { +DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper, + gui::ISurfaceComposer::VsyncSource vsyncSource, + EventRegistrationFlags eventRegistration) + : mLooper(looper), + mReceiver(vsyncSource, eventRegistration), + mWaitingForVsync(false), + mLastVsyncCount(0), + mLastScheduleVsyncTime(0) { ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this); } diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index bfb77699c0..c52fb6b7c3 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -19,10 +19,9 @@ #include <utils/Errors.h> #include <gui/DisplayEventReceiver.h> -#include <gui/ISurfaceComposer.h> #include <gui/VsyncEventData.h> -#include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <private/gui/BitTube.h> @@ -32,15 +31,20 @@ namespace android { // --------------------------------------------------------------------------- -DisplayEventReceiver::DisplayEventReceiver( - ISurfaceComposer::VsyncSource vsyncSource, - ISurfaceComposer::EventRegistrationFlags eventRegistration) { - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); +DisplayEventReceiver::DisplayEventReceiver(gui::ISurfaceComposer::VsyncSource vsyncSource, + EventRegistrationFlags eventRegistration) { + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); if (sf != nullptr) { - mEventConnection = sf->createDisplayEventConnection(vsyncSource, eventRegistration); + mEventConnection = nullptr; + binder::Status status = + sf->createDisplayEventConnection(vsyncSource, + static_cast< + gui::ISurfaceComposer::EventRegistration>( + eventRegistration.get()), + &mEventConnection); if (mEventConnection != nullptr) { mDataChannel = std::make_unique<gui::BitTube>(); - const auto status = mEventConnection->stealReceiveChannel(mDataChannel.get()); + status = mEventConnection->stealReceiveChannel(mDataChannel.get()); if (!status.isOk()) { ALOGE("stealReceiveChannel failed: %s", status.toString8().c_str()); mInitError = std::make_optional<status_t>(status.transactionError()); diff --git a/libs/gui/FrameTimelineInfo.cpp b/libs/gui/FrameTimelineInfo.cpp deleted file mode 100644 index 3800b88ab0..0000000000 --- a/libs/gui/FrameTimelineInfo.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "FrameTimelineInfo" - -#include <inttypes.h> - -#include <android/os/IInputConstants.h> -#include <gui/FrameTimelineInfo.h> -#include <gui/LayerState.h> -#include <private/gui/ParcelUtils.h> -#include <utils/Errors.h> - -#include <cmath> - -using android::os::IInputConstants; - -namespace android { - -status_t FrameTimelineInfo::write(Parcel& output) const { - SAFE_PARCEL(output.writeInt64, vsyncId); - SAFE_PARCEL(output.writeInt32, inputEventId); - SAFE_PARCEL(output.writeInt64, startTimeNanos); - return NO_ERROR; -} - -status_t FrameTimelineInfo::read(const Parcel& input) { - SAFE_PARCEL(input.readInt64, &vsyncId); - SAFE_PARCEL(input.readInt32, &inputEventId); - SAFE_PARCEL(input.readInt64, &startTimeNanos); - return NO_ERROR; -} - -void FrameTimelineInfo::merge(const FrameTimelineInfo& other) { - // When merging vsync Ids we take the oldest valid one - if (vsyncId != INVALID_VSYNC_ID && other.vsyncId != INVALID_VSYNC_ID) { - if (other.vsyncId > vsyncId) { - vsyncId = other.vsyncId; - inputEventId = other.inputEventId; - startTimeNanos = other.startTimeNanos; - } - } else if (vsyncId == INVALID_VSYNC_ID) { - vsyncId = other.vsyncId; - inputEventId = other.inputEventId; - startTimeNanos = other.startTimeNanos; - } -} - -void FrameTimelineInfo::clear() { - vsyncId = INVALID_VSYNC_ID; - inputEventId = IInputConstants::INVALID_INPUT_EVENT_ID; - startTimeNanos = 0; -} - -}; // namespace android diff --git a/libs/gui/GLConsumerUtils.cpp b/libs/gui/GLConsumerUtils.cpp index 7a06c3d801..a1c69e7d6d 100644 --- a/libs/gui/GLConsumerUtils.cpp +++ b/libs/gui/GLConsumerUtils.cpp @@ -27,6 +27,13 @@ namespace android { void GLConsumer::computeTransformMatrix(float outTransform[16], const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform, bool filtering) { + computeTransformMatrix(outTransform, buf->getWidth(), buf->getHeight(), buf->getPixelFormat(), + cropRect, transform, filtering); +} + +void GLConsumer::computeTransformMatrix(float outTransform[16], float bufferWidth, + float bufferHeight, PixelFormat pixelFormat, + const Rect& cropRect, uint32_t transform, bool filtering) { // Transform matrices static const mat4 mtxFlipH( -1, 0, 0, 0, @@ -60,8 +67,6 @@ void GLConsumer::computeTransformMatrix(float outTransform[16], if (!cropRect.isEmpty()) { float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f; - float bufferWidth = buf->getWidth(); - float bufferHeight = buf->getHeight(); float shrinkAmount = 0.0f; if (filtering) { // In order to prevent bilinear sampling beyond the edge of the @@ -70,7 +75,7 @@ void GLConsumer::computeTransformMatrix(float outTransform[16], // off each end, but because the chroma channels of YUV420 images // are subsampled we may need to shrink the crop region by a whole // texel on each side. - switch (buf->getPixelFormat()) { + switch (pixelFormat) { case PIXEL_FORMAT_RGBA_8888: case PIXEL_FORMAT_RGBX_8888: case PIXEL_FORMAT_RGBA_FP16: diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 24d39fe86a..af64b3bd32 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -25,8 +25,6 @@ #include <binder/Parcel.h> #include <gui/IGraphicBufferProducer.h> #include <gui/ISurfaceComposer.h> -#include <gui/ISurfaceComposerClient.h> -#include <gui/LayerDebugInfo.h> #include <gui/LayerState.h> #include <private/gui/ParcelUtils.h> #include <stdint.h> @@ -37,7 +35,6 @@ #include <ui/DisplayState.h> #include <ui/DynamicDisplayInfo.h> #include <ui/HdrCapabilities.h> -#include <ui/StaticDisplayInfo.h> #include <utils/Log.h> // --------------------------------------------------------------------------- @@ -63,14 +60,6 @@ public: virtual ~BpSurfaceComposer(); - virtual sp<ISurfaceComposerClient> createConnection() - { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::CREATE_CONNECTION, data, &reply); - return interface_cast<ISurfaceComposerClient>(reply.readStrongBinder()); - } - status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& state, const Vector<DisplayState>& displays, uint32_t flags, @@ -82,7 +71,7 @@ public: Parcel data, reply; data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(frameTimelineInfo.write, data); + frameTimelineInfo.writeToParcel(&data); SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(state.size())); for (const auto& s : state) { @@ -119,905 +108,6 @@ public: data, &reply); } } - - void bootFinished() override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::BOOT_FINISHED, data, &reply); - } - - bool authenticateSurfaceTexture( - const sp<IGraphicBufferProducer>& bufferProducer) const override { - Parcel data, reply; - int err = NO_ERROR; - err = data.writeInterfaceToken( - ISurfaceComposer::getInterfaceDescriptor()); - if (err != NO_ERROR) { - ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error writing " - "interface descriptor: %s (%d)", strerror(-err), -err); - return false; - } - err = data.writeStrongBinder(IInterface::asBinder(bufferProducer)); - if (err != NO_ERROR) { - ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error writing " - "strong binder to parcel: %s (%d)", strerror(-err), -err); - return false; - } - err = remote()->transact(BnSurfaceComposer::AUTHENTICATE_SURFACE, data, - &reply); - if (err != NO_ERROR) { - ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error " - "performing transaction: %s (%d)", strerror(-err), -err); - return false; - } - int32_t result = 0; - err = reply.readInt32(&result); - if (err != NO_ERROR) { - ALOGE("ISurfaceComposer::authenticateSurfaceTexture: error " - "retrieving result: %s (%d)", strerror(-err), -err); - return false; - } - return result != 0; - } - - status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override { - if (!outSupported) { - return UNEXPECTED_NULL; - } - outSupported->clear(); - - Parcel data, reply; - - status_t err = data.writeInterfaceToken( - ISurfaceComposer::getInterfaceDescriptor()); - if (err != NO_ERROR) { - return err; - } - - err = remote()->transact( - BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS, - data, &reply); - if (err != NO_ERROR) { - return err; - } - - int32_t result = 0; - err = reply.readInt32(&result); - if (err != NO_ERROR) { - return err; - } - if (result != NO_ERROR) { - return result; - } - - std::vector<int32_t> supported; - err = reply.readInt32Vector(&supported); - if (err != NO_ERROR) { - return err; - } - - outSupported->reserve(supported.size()); - for (int32_t s : supported) { - outSupported->push_back(static_cast<FrameEvent>(s)); - } - return NO_ERROR; - } - - sp<IDisplayEventConnection> createDisplayEventConnection( - VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) override { - Parcel data, reply; - sp<IDisplayEventConnection> result; - int err = data.writeInterfaceToken( - ISurfaceComposer::getInterfaceDescriptor()); - if (err != NO_ERROR) { - return result; - } - data.writeInt32(static_cast<int32_t>(vsyncSource)); - data.writeUint32(eventRegistration.get()); - err = remote()->transact( - BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION, - data, &reply); - if (err != NO_ERROR) { - ALOGE("ISurfaceComposer::createDisplayEventConnection: error performing " - "transaction: %s (%d)", strerror(-err), -err); - return result; - } - result = interface_cast<IDisplayEventConnection>(reply.readStrongBinder()); - return result; - } - - status_t getStaticDisplayInfo(const sp<IBinder>& display, - ui::StaticDisplayInfo* info) override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeStrongBinder(display); - remote()->transact(BnSurfaceComposer::GET_STATIC_DISPLAY_INFO, data, &reply); - const status_t result = reply.readInt32(); - if (result != NO_ERROR) return result; - return reply.read(*info); - } - - status_t getDynamicDisplayInfo(const sp<IBinder>& display, - ui::DynamicDisplayInfo* info) override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeStrongBinder(display); - remote()->transact(BnSurfaceComposer::GET_DYNAMIC_DISPLAY_INFO, data, &reply); - const status_t result = reply.readInt32(); - if (result != NO_ERROR) return result; - return reply.read(*info); - } - - status_t getDisplayNativePrimaries(const sp<IBinder>& display, - ui::DisplayPrimaries& primaries) override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("getDisplayNativePrimaries failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(display); - if (result != NO_ERROR) { - ALOGE("getDisplayNativePrimaries failed to writeStrongBinder: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::GET_DISPLAY_NATIVE_PRIMARIES, data, &reply); - if (result != NO_ERROR) { - ALOGE("getDisplayNativePrimaries failed to transact: %d", result); - return result; - } - result = reply.readInt32(); - if (result == NO_ERROR) { - memcpy(&primaries, reply.readInplace(sizeof(ui::DisplayPrimaries)), - sizeof(ui::DisplayPrimaries)); - } - return result; - } - - status_t setActiveColorMode(const sp<IBinder>& display, ColorMode colorMode) override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("setActiveColorMode failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(display); - if (result != NO_ERROR) { - ALOGE("setActiveColorMode failed to writeStrongBinder: %d", result); - return result; - } - result = data.writeInt32(static_cast<int32_t>(colorMode)); - if (result != NO_ERROR) { - ALOGE("setActiveColorMode failed to writeInt32: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::SET_ACTIVE_COLOR_MODE, data, &reply); - if (result != NO_ERROR) { - ALOGE("setActiveColorMode failed to transact: %d", result); - return result; - } - return static_cast<status_t>(reply.readInt32()); - } - - status_t setBootDisplayMode(const sp<IBinder>& display, - ui::DisplayModeId displayModeId) override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("setBootDisplayMode failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(display); - if (result != NO_ERROR) { - ALOGE("setBootDisplayMode failed to writeStrongBinder: %d", result); - return result; - } - result = data.writeInt32(displayModeId); - if (result != NO_ERROR) { - ALOGE("setBootDisplayMode failed to writeIint32: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::SET_BOOT_DISPLAY_MODE, data, &reply); - if (result != NO_ERROR) { - ALOGE("setBootDisplayMode failed to transact: %d", result); - } - return result; - } - - status_t clearAnimationFrameStats() override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("clearAnimationFrameStats failed to writeInterfaceToken: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS, data, &reply); - if (result != NO_ERROR) { - ALOGE("clearAnimationFrameStats failed to transact: %d", result); - return result; - } - return reply.readInt32(); - } - - status_t getAnimationFrameStats(FrameStats* outStats) const override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::GET_ANIMATION_FRAME_STATS, data, &reply); - reply.read(*outStats); - return reply.readInt32(); - } - - virtual status_t overrideHdrTypes(const sp<IBinder>& display, - const std::vector<ui::Hdr>& hdrTypes) { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, display); - - std::vector<int32_t> hdrTypesVector; - for (ui::Hdr i : hdrTypes) { - hdrTypesVector.push_back(static_cast<int32_t>(i)); - } - SAFE_PARCEL(data.writeInt32Vector, hdrTypesVector); - - status_t result = remote()->transact(BnSurfaceComposer::OVERRIDE_HDR_TYPES, data, &reply); - if (result != NO_ERROR) { - ALOGE("overrideHdrTypes failed to transact: %d", result); - return result; - } - return result; - } - - status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success) { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeInt32, atomId); - - status_t err = remote()->transact(BnSurfaceComposer::ON_PULL_ATOM, data, &reply); - if (err != NO_ERROR) { - ALOGE("onPullAtom failed to transact: %d", err); - return err; - } - - int32_t size = 0; - SAFE_PARCEL(reply.readInt32, &size); - const void* dataPtr = reply.readInplace(size); - if (dataPtr == nullptr) { - return UNEXPECTED_NULL; - } - pulledData->assign((const char*)dataPtr, size); - SAFE_PARCEL(reply.readBool, success); - return NO_ERROR; - } - - status_t enableVSyncInjections(bool enable) override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("enableVSyncInjections failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeBool(enable); - if (result != NO_ERROR) { - ALOGE("enableVSyncInjections failed to writeBool: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS, data, &reply, - IBinder::FLAG_ONEWAY); - if (result != NO_ERROR) { - ALOGE("enableVSyncInjections failed to transact: %d", result); - return result; - } - return result; - } - - status_t injectVSync(nsecs_t when) override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("injectVSync failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeInt64(when); - if (result != NO_ERROR) { - ALOGE("injectVSync failed to writeInt64: %d", result); - return result; - } - result = remote()->transact(BnSurfaceComposer::INJECT_VSYNC, data, &reply, - IBinder::FLAG_ONEWAY); - if (result != NO_ERROR) { - ALOGE("injectVSync failed to transact: %d", result); - return result; - } - return result; - } - - status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) override { - if (!outLayers) { - return UNEXPECTED_NULL; - } - - Parcel data, reply; - - status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (err != NO_ERROR) { - return err; - } - - err = remote()->transact(BnSurfaceComposer::GET_LAYER_DEBUG_INFO, data, &reply); - if (err != NO_ERROR) { - return err; - } - - int32_t result = 0; - err = reply.readInt32(&result); - if (err != NO_ERROR) { - return err; - } - if (result != NO_ERROR) { - return result; - } - - outLayers->clear(); - return reply.readParcelableVector(outLayers); - } - - status_t getCompositionPreference(ui::Dataspace* defaultDataspace, - ui::PixelFormat* defaultPixelFormat, - ui::Dataspace* wideColorGamutDataspace, - ui::PixelFormat* wideColorGamutPixelFormat) const override { - Parcel data, reply; - status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (error != NO_ERROR) { - return error; - } - error = remote()->transact(BnSurfaceComposer::GET_COMPOSITION_PREFERENCE, data, &reply); - if (error != NO_ERROR) { - return error; - } - error = static_cast<status_t>(reply.readInt32()); - if (error == NO_ERROR) { - *defaultDataspace = static_cast<ui::Dataspace>(reply.readInt32()); - *defaultPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32()); - *wideColorGamutDataspace = static_cast<ui::Dataspace>(reply.readInt32()); - *wideColorGamutPixelFormat = static_cast<ui::PixelFormat>(reply.readInt32()); - } - return error; - } - - status_t getColorManagement(bool* outGetColorManagement) const override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - remote()->transact(BnSurfaceComposer::GET_COLOR_MANAGEMENT, data, &reply); - bool result; - status_t err = reply.readBool(&result); - if (err == NO_ERROR) { - *outGetColorManagement = result; - } - return err; - } - - status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display, - ui::PixelFormat* outFormat, - ui::Dataspace* outDataspace, - uint8_t* outComponentMask) const override { - if (!outFormat || !outDataspace || !outComponentMask) return BAD_VALUE; - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeStrongBinder(display); - - status_t error = - remote()->transact(BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES, - data, &reply); - if (error != NO_ERROR) { - return error; - } - - uint32_t value = 0; - error = reply.readUint32(&value); - if (error != NO_ERROR) { - return error; - } - *outFormat = static_cast<ui::PixelFormat>(value); - - error = reply.readUint32(&value); - if (error != NO_ERROR) { - return error; - } - *outDataspace = static_cast<ui::Dataspace>(value); - - error = reply.readUint32(&value); - if (error != NO_ERROR) { - return error; - } - *outComponentMask = static_cast<uint8_t>(value); - return error; - } - - status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable, - uint8_t componentMask, uint64_t maxFrames) override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeStrongBinder(display); - data.writeBool(enable); - data.writeByte(static_cast<int8_t>(componentMask)); - data.writeUint64(maxFrames); - status_t result = - remote()->transact(BnSurfaceComposer::SET_DISPLAY_CONTENT_SAMPLING_ENABLED, data, - &reply); - return result; - } - - status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames, - uint64_t timestamp, - DisplayedFrameStats* outStats) const override { - if (!outStats) return BAD_VALUE; - - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - data.writeStrongBinder(display); - data.writeUint64(maxFrames); - data.writeUint64(timestamp); - - status_t result = - remote()->transact(BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLE, data, &reply); - - if (result != NO_ERROR) { - return result; - } - - result = reply.readUint64(&outStats->numFrames); - if (result != NO_ERROR) { - return result; - } - - result = reply.readUint64Vector(&outStats->component_0_sample); - if (result != NO_ERROR) { - return result; - } - result = reply.readUint64Vector(&outStats->component_1_sample); - if (result != NO_ERROR) { - return result; - } - result = reply.readUint64Vector(&outStats->component_2_sample); - if (result != NO_ERROR) { - return result; - } - result = reply.readUint64Vector(&outStats->component_3_sample); - return result; - } - - status_t getProtectedContentSupport(bool* outSupported) const override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - status_t error = - remote()->transact(BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT, data, &reply); - if (error != NO_ERROR) { - return error; - } - error = reply.readBool(outSupported); - return error; - } - - status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle, - const sp<IRegionSamplingListener>& listener) override { - Parcel data, reply; - status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (error != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to write interface token"); - return error; - } - error = data.write(samplingArea); - if (error != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to write sampling area"); - return error; - } - error = data.writeStrongBinder(stopLayerHandle); - if (error != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to write stop layer handle"); - return error; - } - error = data.writeStrongBinder(IInterface::asBinder(listener)); - if (error != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to write listener"); - return error; - } - error = remote()->transact(BnSurfaceComposer::ADD_REGION_SAMPLING_LISTENER, data, &reply); - if (error != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to transact"); - } - return error; - } - - status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override { - Parcel data, reply; - status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (error != NO_ERROR) { - ALOGE("removeRegionSamplingListener: Failed to write interface token"); - return error; - } - error = data.writeStrongBinder(IInterface::asBinder(listener)); - if (error != NO_ERROR) { - ALOGE("removeRegionSamplingListener: Failed to write listener"); - return error; - } - error = remote()->transact(BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER, data, - &reply); - if (error != NO_ERROR) { - ALOGE("removeRegionSamplingListener: Failed to transact"); - } - return error; - } - - virtual status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeInt32, taskId); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); - const status_t error = - remote()->transact(BnSurfaceComposer::ADD_FPS_LISTENER, data, &reply); - if (error != OK) { - ALOGE("addFpsListener: Failed to transact"); - } - return error; - } - - virtual status_t removeFpsListener(const sp<gui::IFpsListener>& listener) { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); - - const status_t error = - remote()->transact(BnSurfaceComposer::REMOVE_FPS_LISTENER, data, &reply); - if (error != OK) { - ALOGE("removeFpsListener: Failed to transact"); - } - return error; - } - - virtual status_t addTunnelModeEnabledListener( - const sp<gui::ITunnelModeEnabledListener>& listener) { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); - - const status_t error = - remote()->transact(BnSurfaceComposer::ADD_TUNNEL_MODE_ENABLED_LISTENER, data, - &reply); - if (error != NO_ERROR) { - ALOGE("addTunnelModeEnabledListener: Failed to transact"); - } - return error; - } - - virtual status_t removeTunnelModeEnabledListener( - const sp<gui::ITunnelModeEnabledListener>& listener) { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); - - const status_t error = - remote()->transact(BnSurfaceComposer::REMOVE_TUNNEL_MODE_ENABLED_LISTENER, data, - &reply); - if (error != NO_ERROR) { - ALOGE("removeTunnelModeEnabledListener: Failed to transact"); - } - return error; - } - - status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, - ui::DisplayModeId defaultMode, bool allowGroupSwitching, - float primaryRefreshRateMin, float primaryRefreshRateMax, - float appRequestRefreshRateMin, - float appRequestRefreshRateMax) override { - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(displayToken); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to write display token: %d", result); - return result; - } - result = data.writeInt32(defaultMode); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs failed to write defaultMode: %d", result); - return result; - } - result = data.writeBool(allowGroupSwitching); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs failed to write allowGroupSwitching: %d", result); - return result; - } - result = data.writeFloat(primaryRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs failed to write primaryRefreshRateMin: %d", result); - return result; - } - result = data.writeFloat(primaryRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs failed to write primaryRefreshRateMax: %d", result); - return result; - } - result = data.writeFloat(appRequestRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs failed to write appRequestRefreshRateMin: %d", - result); - return result; - } - result = data.writeFloat(appRequestRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs failed to write appRequestRefreshRateMax: %d", - result); - return result; - } - - result = - remote()->transact(BnSurfaceComposer::SET_DESIRED_DISPLAY_MODE_SPECS, data, &reply); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs failed to transact: %d", result); - return result; - } - return reply.readInt32(); - } - - status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, - ui::DisplayModeId* outDefaultMode, - bool* outAllowGroupSwitching, - float* outPrimaryRefreshRateMin, - float* outPrimaryRefreshRateMax, - float* outAppRequestRefreshRateMin, - float* outAppRequestRefreshRateMax) override { - if (!outDefaultMode || !outAllowGroupSwitching || !outPrimaryRefreshRateMin || - !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || - !outAppRequestRefreshRateMax) { - return BAD_VALUE; - } - Parcel data, reply; - status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to writeInterfaceToken: %d", result); - return result; - } - result = data.writeStrongBinder(displayToken); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to writeStrongBinder: %d", result); - return result; - } - result = - remote()->transact(BnSurfaceComposer::GET_DESIRED_DISPLAY_MODE_SPECS, data, &reply); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to transact: %d", result); - return result; - } - - result = reply.readInt32(outDefaultMode); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to read defaultMode: %d", result); - return result; - } - if (*outDefaultMode < 0) { - ALOGE("%s: defaultMode must be non-negative but it was %d", __func__, *outDefaultMode); - return BAD_VALUE; - } - - result = reply.readBool(outAllowGroupSwitching); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to read allowGroupSwitching: %d", result); - return result; - } - result = reply.readFloat(outPrimaryRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to read primaryRefreshRateMin: %d", result); - return result; - } - result = reply.readFloat(outPrimaryRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to read primaryRefreshRateMax: %d", result); - return result; - } - result = reply.readFloat(outAppRequestRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to read appRequestRefreshRateMin: %d", result); - return result; - } - result = reply.readFloat(outAppRequestRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs failed to read appRequestRefreshRateMax: %d", result); - return result; - } - return reply.readInt32(); - } - - status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, - float lightPosY, float lightPosZ, float lightRadius) override { - Parcel data, reply; - status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (error != NO_ERROR) { - ALOGE("setGlobalShadowSettings: failed to write interface token: %d", error); - return error; - } - - std::vector<float> shadowConfig = {ambientColor.r, ambientColor.g, ambientColor.b, - ambientColor.a, spotColor.r, spotColor.g, - spotColor.b, spotColor.a, lightPosY, - lightPosZ, lightRadius}; - - error = data.writeFloatVector(shadowConfig); - if (error != NO_ERROR) { - ALOGE("setGlobalShadowSettings: failed to write shadowConfig: %d", error); - return error; - } - - error = remote()->transact(BnSurfaceComposer::SET_GLOBAL_SHADOW_SETTINGS, data, &reply, - IBinder::FLAG_ONEWAY); - if (error != NO_ERROR) { - ALOGE("setGlobalShadowSettings: failed to transact: %d", error); - return error; - } - return NO_ERROR; - } - - status_t getDisplayDecorationSupport( - const sp<IBinder>& displayToken, - std::optional<common::DisplayDecorationSupport>* outSupport) const override { - Parcel data, reply; - status_t error = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (error != NO_ERROR) { - ALOGE("getDisplayDecorationSupport: failed to write interface token: %d", error); - return error; - } - error = data.writeStrongBinder(displayToken); - if (error != NO_ERROR) { - ALOGE("getDisplayDecorationSupport: failed to write display token: %d", error); - return error; - } - error = remote()->transact(BnSurfaceComposer::GET_DISPLAY_DECORATION_SUPPORT, data, &reply); - if (error != NO_ERROR) { - ALOGE("getDisplayDecorationSupport: failed to transact: %d", error); - return error; - } - bool support; - error = reply.readBool(&support); - if (error != NO_ERROR) { - ALOGE("getDisplayDecorationSupport: failed to read support: %d", error); - return error; - } - - if (support) { - int32_t format, alphaInterpretation; - error = reply.readInt32(&format); - if (error != NO_ERROR) { - ALOGE("getDisplayDecorationSupport: failed to read format: %d", error); - return error; - } - error = reply.readInt32(&alphaInterpretation); - if (error != NO_ERROR) { - ALOGE("getDisplayDecorationSupport: failed to read alphaInterpretation: %d", error); - return error; - } - outSupport->emplace(); - outSupport->value().format = static_cast<common::PixelFormat>(format); - outSupport->value().alphaInterpretation = - static_cast<common::AlphaInterpretation>(alphaInterpretation); - } else { - outSupport->reset(); - } - return NO_ERROR; - } - - status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, - int8_t compatibility, int8_t changeFrameRateStrategy) override { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(surface)); - SAFE_PARCEL(data.writeFloat, frameRate); - SAFE_PARCEL(data.writeByte, compatibility); - SAFE_PARCEL(data.writeByte, changeFrameRateStrategy); - - status_t err = remote()->transact(BnSurfaceComposer::SET_FRAME_RATE, data, &reply); - if (err != NO_ERROR) { - ALOGE("setFrameRate: failed to transact: %s (%d)", strerror(-err), err); - return err; - } - - return reply.readInt32(); - } - - status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface, - const FrameTimelineInfo& frameTimelineInfo) override { - Parcel data, reply; - status_t err = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - if (err != NO_ERROR) { - ALOGE("%s: failed writing interface token: %s (%d)", __func__, strerror(-err), -err); - return err; - } - - err = data.writeStrongBinder(IInterface::asBinder(surface)); - if (err != NO_ERROR) { - ALOGE("%s: failed writing strong binder: %s (%d)", __func__, strerror(-err), -err); - return err; - } - - SAFE_PARCEL(frameTimelineInfo.write, data); - - err = remote()->transact(BnSurfaceComposer::SET_FRAME_TIMELINE_INFO, data, &reply); - if (err != NO_ERROR) { - ALOGE("%s: failed to transact: %s (%d)", __func__, strerror(-err), err); - return err; - } - - return reply.readInt32(); - } - - status_t addTransactionTraceListener( - const sp<gui::ITransactionTraceListener>& listener) override { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener)); - - return remote()->transact(BnSurfaceComposer::ADD_TRANSACTION_TRACE_LISTENER, data, &reply); - } - - /** - * Get priority of the RenderEngine in surface flinger. - */ - int getGPUContextPriority() override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - status_t err = - remote()->transact(BnSurfaceComposer::GET_GPU_CONTEXT_PRIORITY, data, &reply); - if (err != NO_ERROR) { - ALOGE("getGPUContextPriority failed to read data: %s (%d)", strerror(-err), err); - return 0; - } - return reply.readInt32(); - } - - status_t getMaxAcquiredBufferCount(int* buffers) const override { - Parcel data, reply; - data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); - status_t err = - remote()->transact(BnSurfaceComposer::GET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply); - if (err != NO_ERROR) { - ALOGE("getMaxAcquiredBufferCount failed to read data: %s (%d)", strerror(-err), err); - return err; - } - - return reply.readInt32(buffers); - } - - status_t addWindowInfosListener( - const sp<IWindowInfosListener>& windowInfosListener) const override { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(windowInfosListener)); - return remote()->transact(BnSurfaceComposer::ADD_WINDOW_INFOS_LISTENER, data, &reply); - } - - status_t removeWindowInfosListener( - const sp<IWindowInfosListener>& windowInfosListener) const override { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(windowInfosListener)); - return remote()->transact(BnSurfaceComposer::REMOVE_WINDOW_INFOS_LISTENER, data, &reply); - } - - status_t setOverrideFrameRate(uid_t uid, float frameRate) override { - Parcel data, reply; - SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor()); - SAFE_PARCEL(data.writeUint32, uid); - SAFE_PARCEL(data.writeFloat, frameRate); - - status_t err = remote()->transact(BnSurfaceComposer::SET_OVERRIDE_FRAME_RATE, data, &reply); - if (err != NO_ERROR) { - ALOGE("setOverrideFrameRate: failed to transact %s (%d)", strerror(-err), err); - return err; - } - - return NO_ERROR; - } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -1031,18 +121,12 @@ IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer"); status_t BnSurfaceComposer::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { - switch(code) { - case CREATE_CONNECTION: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> b = IInterface::asBinder(createConnection()); - reply->writeStrongBinder(b); - return NO_ERROR; - } + switch (code) { case SET_TRANSACTION_STATE: { CHECK_INTERFACE(ISurfaceComposer, data, reply); FrameTimelineInfo frameTimelineInfo; - SAFE_PARCEL(frameTimelineInfo.read, data); + frameTimelineInfo.readFromParcel(&data); uint32_t count = 0; SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize()); @@ -1102,642 +186,6 @@ status_t BnSurfaceComposer::onTransact( uncachedBuffer, hasListenerCallbacks, listenerCallbacks, transactionId); } - case BOOT_FINISHED: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - bootFinished(); - return NO_ERROR; - } - case AUTHENTICATE_SURFACE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IGraphicBufferProducer> bufferProducer = - interface_cast<IGraphicBufferProducer>(data.readStrongBinder()); - int32_t result = authenticateSurfaceTexture(bufferProducer) ? 1 : 0; - reply->writeInt32(result); - return NO_ERROR; - } - case GET_SUPPORTED_FRAME_TIMESTAMPS: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - std::vector<FrameEvent> supportedTimestamps; - status_t result = getSupportedFrameTimestamps(&supportedTimestamps); - status_t err = reply->writeInt32(result); - if (err != NO_ERROR) { - return err; - } - if (result != NO_ERROR) { - return result; - } - - std::vector<int32_t> supported; - supported.reserve(supportedTimestamps.size()); - for (FrameEvent s : supportedTimestamps) { - supported.push_back(static_cast<int32_t>(s)); - } - return reply->writeInt32Vector(supported); - } - case CREATE_DISPLAY_EVENT_CONNECTION: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - auto vsyncSource = static_cast<ISurfaceComposer::VsyncSource>(data.readInt32()); - EventRegistrationFlags eventRegistration = - static_cast<EventRegistration>(data.readUint32()); - - sp<IDisplayEventConnection> connection( - createDisplayEventConnection(vsyncSource, eventRegistration)); - reply->writeStrongBinder(IInterface::asBinder(connection)); - return NO_ERROR; - } - case GET_STATIC_DISPLAY_INFO: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - ui::StaticDisplayInfo info; - const sp<IBinder> display = data.readStrongBinder(); - const status_t result = getStaticDisplayInfo(display, &info); - SAFE_PARCEL(reply->writeInt32, result); - if (result != NO_ERROR) return result; - SAFE_PARCEL(reply->write, info); - return NO_ERROR; - } - case GET_DYNAMIC_DISPLAY_INFO: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - ui::DynamicDisplayInfo info; - const sp<IBinder> display = data.readStrongBinder(); - const status_t result = getDynamicDisplayInfo(display, &info); - SAFE_PARCEL(reply->writeInt32, result); - if (result != NO_ERROR) return result; - SAFE_PARCEL(reply->write, info); - return NO_ERROR; - } - case GET_DISPLAY_NATIVE_PRIMARIES: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - ui::DisplayPrimaries primaries; - sp<IBinder> display = nullptr; - - status_t result = data.readStrongBinder(&display); - if (result != NO_ERROR) { - ALOGE("getDisplayNativePrimaries failed to readStrongBinder: %d", result); - return result; - } - - result = getDisplayNativePrimaries(display, primaries); - reply->writeInt32(result); - if (result == NO_ERROR) { - memcpy(reply->writeInplace(sizeof(ui::DisplayPrimaries)), &primaries, - sizeof(ui::DisplayPrimaries)); - } - - return NO_ERROR; - } - case SET_ACTIVE_COLOR_MODE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> display = nullptr; - status_t result = data.readStrongBinder(&display); - if (result != NO_ERROR) { - ALOGE("getActiveColorMode failed to readStrongBinder: %d", result); - return result; - } - int32_t colorModeInt = 0; - result = data.readInt32(&colorModeInt); - if (result != NO_ERROR) { - ALOGE("setActiveColorMode failed to readInt32: %d", result); - return result; - } - result = setActiveColorMode(display, - static_cast<ColorMode>(colorModeInt)); - result = reply->writeInt32(result); - return result; - } - case SET_BOOT_DISPLAY_MODE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> display = nullptr; - status_t result = data.readStrongBinder(&display); - if (result != NO_ERROR) { - ALOGE("setBootDisplayMode failed to readStrongBinder: %d", result); - return result; - } - ui::DisplayModeId displayModeId; - result = data.readInt32(&displayModeId); - if (result != NO_ERROR) { - ALOGE("setBootDisplayMode failed to readInt32: %d", result); - return result; - } - return setBootDisplayMode(display, displayModeId); - } - case CLEAR_ANIMATION_FRAME_STATS: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - status_t result = clearAnimationFrameStats(); - reply->writeInt32(result); - return NO_ERROR; - } - case GET_ANIMATION_FRAME_STATS: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - FrameStats stats; - status_t result = getAnimationFrameStats(&stats); - reply->write(stats); - reply->writeInt32(result); - return NO_ERROR; - } - case ENABLE_VSYNC_INJECTIONS: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - bool enable = false; - status_t result = data.readBool(&enable); - if (result != NO_ERROR) { - ALOGE("enableVSyncInjections failed to readBool: %d", result); - return result; - } - return enableVSyncInjections(enable); - } - case INJECT_VSYNC: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - int64_t when = 0; - status_t result = data.readInt64(&when); - if (result != NO_ERROR) { - ALOGE("enableVSyncInjections failed to readInt64: %d", result); - return result; - } - return injectVSync(when); - } - case GET_LAYER_DEBUG_INFO: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - std::vector<LayerDebugInfo> outLayers; - status_t result = getLayerDebugInfo(&outLayers); - reply->writeInt32(result); - if (result == NO_ERROR) - { - result = reply->writeParcelableVector(outLayers); - } - return result; - } - case GET_COMPOSITION_PREFERENCE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - ui::Dataspace defaultDataspace; - ui::PixelFormat defaultPixelFormat; - ui::Dataspace wideColorGamutDataspace; - ui::PixelFormat wideColorGamutPixelFormat; - status_t error = - getCompositionPreference(&defaultDataspace, &defaultPixelFormat, - &wideColorGamutDataspace, &wideColorGamutPixelFormat); - reply->writeInt32(error); - if (error == NO_ERROR) { - reply->writeInt32(static_cast<int32_t>(defaultDataspace)); - reply->writeInt32(static_cast<int32_t>(defaultPixelFormat)); - reply->writeInt32(static_cast<int32_t>(wideColorGamutDataspace)); - reply->writeInt32(static_cast<int32_t>(wideColorGamutPixelFormat)); - } - return error; - } - case GET_COLOR_MANAGEMENT: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - bool result; - status_t error = getColorManagement(&result); - if (error == NO_ERROR) { - reply->writeBool(result); - } - return error; - } - case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - - sp<IBinder> display = data.readStrongBinder(); - ui::PixelFormat format; - ui::Dataspace dataspace; - uint8_t component = 0; - auto result = - getDisplayedContentSamplingAttributes(display, &format, &dataspace, &component); - if (result == NO_ERROR) { - reply->writeUint32(static_cast<uint32_t>(format)); - reply->writeUint32(static_cast<uint32_t>(dataspace)); - reply->writeUint32(static_cast<uint32_t>(component)); - } - return result; - } - case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - - sp<IBinder> display = nullptr; - bool enable = false; - int8_t componentMask = 0; - uint64_t maxFrames = 0; - status_t result = data.readStrongBinder(&display); - if (result != NO_ERROR) { - ALOGE("setDisplayContentSamplingEnabled failure in reading Display token: %d", - result); - return result; - } - - result = data.readBool(&enable); - if (result != NO_ERROR) { - ALOGE("setDisplayContentSamplingEnabled failure in reading enable: %d", result); - return result; - } - - result = data.readByte(static_cast<int8_t*>(&componentMask)); - if (result != NO_ERROR) { - ALOGE("setDisplayContentSamplingEnabled failure in reading component mask: %d", - result); - return result; - } - - result = data.readUint64(&maxFrames); - if (result != NO_ERROR) { - ALOGE("setDisplayContentSamplingEnabled failure in reading max frames: %d", result); - return result; - } - - return setDisplayContentSamplingEnabled(display, enable, - static_cast<uint8_t>(componentMask), maxFrames); - } - case GET_DISPLAYED_CONTENT_SAMPLE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - - sp<IBinder> display = data.readStrongBinder(); - uint64_t maxFrames = 0; - uint64_t timestamp = 0; - - status_t result = data.readUint64(&maxFrames); - if (result != NO_ERROR) { - ALOGE("getDisplayedContentSample failure in reading max frames: %d", result); - return result; - } - - result = data.readUint64(×tamp); - if (result != NO_ERROR) { - ALOGE("getDisplayedContentSample failure in reading timestamp: %d", result); - return result; - } - - DisplayedFrameStats stats; - result = getDisplayedContentSample(display, maxFrames, timestamp, &stats); - if (result == NO_ERROR) { - reply->writeUint64(stats.numFrames); - reply->writeUint64Vector(stats.component_0_sample); - reply->writeUint64Vector(stats.component_1_sample); - reply->writeUint64Vector(stats.component_2_sample); - reply->writeUint64Vector(stats.component_3_sample); - } - return result; - } - case GET_PROTECTED_CONTENT_SUPPORT: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - bool result; - status_t error = getProtectedContentSupport(&result); - if (error == NO_ERROR) { - reply->writeBool(result); - } - return error; - } - case ADD_REGION_SAMPLING_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - Rect samplingArea; - status_t result = data.read(samplingArea); - if (result != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to read sampling area"); - return result; - } - sp<IBinder> stopLayerHandle; - result = data.readNullableStrongBinder(&stopLayerHandle); - if (result != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to read stop layer handle"); - return result; - } - sp<IRegionSamplingListener> listener; - result = data.readNullableStrongBinder(&listener); - if (result != NO_ERROR) { - ALOGE("addRegionSamplingListener: Failed to read listener"); - return result; - } - return addRegionSamplingListener(samplingArea, stopLayerHandle, listener); - } - case REMOVE_REGION_SAMPLING_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IRegionSamplingListener> listener; - status_t result = data.readNullableStrongBinder(&listener); - if (result != NO_ERROR) { - ALOGE("removeRegionSamplingListener: Failed to read listener"); - return result; - } - return removeRegionSamplingListener(listener); - } - case ADD_FPS_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - int32_t taskId; - status_t result = data.readInt32(&taskId); - if (result != NO_ERROR) { - ALOGE("addFpsListener: Failed to read layer handle"); - return result; - } - sp<gui::IFpsListener> listener; - result = data.readNullableStrongBinder(&listener); - if (result != NO_ERROR) { - ALOGE("addFpsListener: Failed to read listener"); - return result; - } - return addFpsListener(taskId, listener); - } - case REMOVE_FPS_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<gui::IFpsListener> listener; - status_t result = data.readNullableStrongBinder(&listener); - if (result != NO_ERROR) { - ALOGE("removeFpsListener: Failed to read listener"); - return result; - } - return removeFpsListener(listener); - } - case ADD_TUNNEL_MODE_ENABLED_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<gui::ITunnelModeEnabledListener> listener; - status_t result = data.readNullableStrongBinder(&listener); - if (result != NO_ERROR) { - ALOGE("addTunnelModeEnabledListener: Failed to read listener"); - return result; - } - return addTunnelModeEnabledListener(listener); - } - case REMOVE_TUNNEL_MODE_ENABLED_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<gui::ITunnelModeEnabledListener> listener; - status_t result = data.readNullableStrongBinder(&listener); - if (result != NO_ERROR) { - ALOGE("removeTunnelModeEnabledListener: Failed to read listener"); - return result; - } - return removeTunnelModeEnabledListener(listener); - } - case SET_DESIRED_DISPLAY_MODE_SPECS: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> displayToken = data.readStrongBinder(); - ui::DisplayModeId defaultMode; - status_t result = data.readInt32(&defaultMode); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to read defaultMode: %d", result); - return result; - } - if (defaultMode < 0) { - ALOGE("%s: defaultMode must be non-negative but it was %d", __func__, defaultMode); - return BAD_VALUE; - } - bool allowGroupSwitching; - result = data.readBool(&allowGroupSwitching); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to read allowGroupSwitching: %d", result); - return result; - } - float primaryRefreshRateMin; - result = data.readFloat(&primaryRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to read primaryRefreshRateMin: %d", - result); - return result; - } - float primaryRefreshRateMax; - result = data.readFloat(&primaryRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to read primaryRefreshRateMax: %d", - result); - return result; - } - float appRequestRefreshRateMin; - result = data.readFloat(&appRequestRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to read appRequestRefreshRateMin: %d", - result); - return result; - } - float appRequestRefreshRateMax; - result = data.readFloat(&appRequestRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to read appRequestRefreshRateMax: %d", - result); - return result; - } - result = setDesiredDisplayModeSpecs(displayToken, defaultMode, allowGroupSwitching, - primaryRefreshRateMin, primaryRefreshRateMax, - appRequestRefreshRateMin, appRequestRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("setDesiredDisplayModeSpecs: failed to call setDesiredDisplayModeSpecs: " - "%d", - result); - return result; - } - reply->writeInt32(result); - return result; - } - case GET_DESIRED_DISPLAY_MODE_SPECS: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> displayToken = data.readStrongBinder(); - ui::DisplayModeId defaultMode; - bool allowGroupSwitching; - float primaryRefreshRateMin; - float primaryRefreshRateMax; - float appRequestRefreshRateMin; - float appRequestRefreshRateMax; - - status_t result = - getDesiredDisplayModeSpecs(displayToken, &defaultMode, &allowGroupSwitching, - &primaryRefreshRateMin, &primaryRefreshRateMax, - &appRequestRefreshRateMin, - &appRequestRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs: failed to get getDesiredDisplayModeSpecs: " - "%d", - result); - return result; - } - - result = reply->writeInt32(defaultMode); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs: failed to write defaultMode: %d", result); - return result; - } - result = reply->writeBool(allowGroupSwitching); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs: failed to write allowGroupSwitching: %d", - result); - return result; - } - result = reply->writeFloat(primaryRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs: failed to write primaryRefreshRateMin: %d", - result); - return result; - } - result = reply->writeFloat(primaryRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs: failed to write primaryRefreshRateMax: %d", - result); - return result; - } - result = reply->writeFloat(appRequestRefreshRateMin); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs: failed to write appRequestRefreshRateMin: %d", - result); - return result; - } - result = reply->writeFloat(appRequestRefreshRateMax); - if (result != NO_ERROR) { - ALOGE("getDesiredDisplayModeSpecs: failed to write appRequestRefreshRateMax: %d", - result); - return result; - } - reply->writeInt32(result); - return result; - } - case SET_GLOBAL_SHADOW_SETTINGS: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - - std::vector<float> shadowConfig; - status_t error = data.readFloatVector(&shadowConfig); - if (error != NO_ERROR || shadowConfig.size() != 11) { - ALOGE("setGlobalShadowSettings: failed to read shadowConfig: %d", error); - return error; - } - - half4 ambientColor = {shadowConfig[0], shadowConfig[1], shadowConfig[2], - shadowConfig[3]}; - half4 spotColor = {shadowConfig[4], shadowConfig[5], shadowConfig[6], shadowConfig[7]}; - float lightPosY = shadowConfig[8]; - float lightPosZ = shadowConfig[9]; - float lightRadius = shadowConfig[10]; - return setGlobalShadowSettings(ambientColor, spotColor, lightPosY, lightPosZ, - lightRadius); - } - case GET_DISPLAY_DECORATION_SUPPORT: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> displayToken; - SAFE_PARCEL(data.readNullableStrongBinder, &displayToken); - std::optional<common::DisplayDecorationSupport> support; - auto error = getDisplayDecorationSupport(displayToken, &support); - if (error != NO_ERROR) { - ALOGE("getDisplayDecorationSupport failed with error %d", error); - return error; - } - reply->writeBool(support.has_value()); - if (support) { - reply->writeInt32(static_cast<int32_t>(support.value().format)); - reply->writeInt32(static_cast<int32_t>(support.value().alphaInterpretation)); - } - return error; - } - case SET_FRAME_RATE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> binder; - SAFE_PARCEL(data.readStrongBinder, &binder); - - sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(binder); - if (!surface) { - ALOGE("setFrameRate: failed to cast to IGraphicBufferProducer"); - return BAD_VALUE; - } - float frameRate; - SAFE_PARCEL(data.readFloat, &frameRate); - - int8_t compatibility; - SAFE_PARCEL(data.readByte, &compatibility); - - int8_t changeFrameRateStrategy; - SAFE_PARCEL(data.readByte, &changeFrameRateStrategy); - - status_t result = - setFrameRate(surface, frameRate, compatibility, changeFrameRateStrategy); - reply->writeInt32(result); - return NO_ERROR; - } - case SET_FRAME_TIMELINE_INFO: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> binder; - status_t err = data.readStrongBinder(&binder); - if (err != NO_ERROR) { - ALOGE("setFrameTimelineInfo: failed to read strong binder: %s (%d)", strerror(-err), - -err); - return err; - } - sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(binder); - if (!surface) { - ALOGE("setFrameTimelineInfo: failed to cast to IGraphicBufferProducer: %s (%d)", - strerror(-err), -err); - return err; - } - - FrameTimelineInfo frameTimelineInfo; - SAFE_PARCEL(frameTimelineInfo.read, data); - - status_t result = setFrameTimelineInfo(surface, frameTimelineInfo); - reply->writeInt32(result); - return NO_ERROR; - } - case ADD_TRANSACTION_TRACE_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<gui::ITransactionTraceListener> listener; - SAFE_PARCEL(data.readStrongBinder, &listener); - - return addTransactionTraceListener(listener); - } - case GET_GPU_CONTEXT_PRIORITY: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - int priority = getGPUContextPriority(); - SAFE_PARCEL(reply->writeInt32, priority); - return NO_ERROR; - } - case GET_MAX_ACQUIRED_BUFFER_COUNT: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - int buffers = 0; - int err = getMaxAcquiredBufferCount(&buffers); - if (err != NO_ERROR) { - return err; - } - SAFE_PARCEL(reply->writeInt32, buffers); - return NO_ERROR; - } - case OVERRIDE_HDR_TYPES: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IBinder> display = nullptr; - SAFE_PARCEL(data.readStrongBinder, &display); - - std::vector<int32_t> hdrTypes; - SAFE_PARCEL(data.readInt32Vector, &hdrTypes); - - std::vector<ui::Hdr> hdrTypesVector; - for (int i : hdrTypes) { - hdrTypesVector.push_back(static_cast<ui::Hdr>(i)); - } - return overrideHdrTypes(display, hdrTypesVector); - } - case ON_PULL_ATOM: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - int32_t atomId = 0; - SAFE_PARCEL(data.readInt32, &atomId); - - std::string pulledData; - bool success; - status_t err = onPullAtom(atomId, &pulledData, &success); - SAFE_PARCEL(reply->writeByteArray, pulledData.size(), - reinterpret_cast<const uint8_t*>(pulledData.data())); - SAFE_PARCEL(reply->writeBool, success); - return err; - } - case ADD_WINDOW_INFOS_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IWindowInfosListener> listener; - SAFE_PARCEL(data.readStrongBinder, &listener); - - return addWindowInfosListener(listener); - } - case REMOVE_WINDOW_INFOS_LISTENER: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - sp<IWindowInfosListener> listener; - SAFE_PARCEL(data.readStrongBinder, &listener); - - return removeWindowInfosListener(listener); - } - case SET_OVERRIDE_FRAME_RATE: { - CHECK_INTERFACE(ISurfaceComposer, data, reply); - - uid_t uid; - SAFE_PARCEL(data.readUint32, &uid); - - float frameRate; - SAFE_PARCEL(data.readFloat, &frameRate); - - return setOverrideFrameRate(uid, frameRate); - } default: { return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp deleted file mode 100644 index 5e7a7ec67b..0000000000 --- a/libs/gui/ISurfaceComposerClient.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// tag as surfaceflinger -#define LOG_TAG "SurfaceFlinger" - -#include <gui/ISurfaceComposerClient.h> - -#include <gui/IGraphicBufferProducer.h> - -#include <binder/SafeInterface.h> - -#include <ui/FrameStats.h> - -namespace android { - -namespace { // Anonymous - -enum class Tag : uint32_t { - CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION, - CREATE_WITH_SURFACE_PARENT, - CLEAR_LAYER_FRAME_STATS, - GET_LAYER_FRAME_STATS, - MIRROR_SURFACE, - LAST = MIRROR_SURFACE, -}; - -} // Anonymous namespace - -class BpSurfaceComposerClient : public SafeBpInterface<ISurfaceComposerClient> { -public: - explicit BpSurfaceComposerClient(const sp<IBinder>& impl) - : SafeBpInterface<ISurfaceComposerClient>(impl, "BpSurfaceComposerClient") {} - - ~BpSurfaceComposerClient() override; - - status_t createSurface(const String8& name, uint32_t width, uint32_t height, PixelFormat format, - uint32_t flags, const sp<IBinder>& parent, LayerMetadata metadata, - sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, - int32_t* outLayerId, uint32_t* outTransformHint) override { - return callRemote<decltype(&ISurfaceComposerClient::createSurface)>(Tag::CREATE_SURFACE, - name, width, height, - format, flags, parent, - std::move(metadata), - handle, gbp, outLayerId, - outTransformHint); - } - - status_t createWithSurfaceParent(const String8& name, uint32_t width, uint32_t height, - PixelFormat format, uint32_t flags, - const sp<IGraphicBufferProducer>& parent, - LayerMetadata metadata, sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId, - uint32_t* outTransformHint) override { - return callRemote<decltype( - &ISurfaceComposerClient::createWithSurfaceParent)>(Tag::CREATE_WITH_SURFACE_PARENT, - name, width, height, format, - flags, parent, - std::move(metadata), handle, gbp, - outLayerId, outTransformHint); - } - - status_t clearLayerFrameStats(const sp<IBinder>& handle) const override { - return callRemote<decltype( - &ISurfaceComposerClient::clearLayerFrameStats)>(Tag::CLEAR_LAYER_FRAME_STATS, - handle); - } - - status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const override { - return callRemote<decltype( - &ISurfaceComposerClient::getLayerFrameStats)>(Tag::GET_LAYER_FRAME_STATS, handle, - outStats); - } - - status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle, - int32_t* outLayerId) override { - return callRemote<decltype(&ISurfaceComposerClient::mirrorSurface)>(Tag::MIRROR_SURFACE, - mirrorFromHandle, - outHandle, outLayerId); - } -}; - -// Out-of-line virtual method definition to trigger vtable emission in this -// translation unit (see clang warning -Wweak-vtables) -BpSurfaceComposerClient::~BpSurfaceComposerClient() {} - -IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient"); - -// ---------------------------------------------------------------------- - -status_t BnSurfaceComposerClient::onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags) { - if (code < IBinder::FIRST_CALL_TRANSACTION || code > static_cast<uint32_t>(Tag::LAST)) { - return BBinder::onTransact(code, data, reply, flags); - } - auto tag = static_cast<Tag>(code); - switch (tag) { - case Tag::CREATE_SURFACE: - return callLocal(data, reply, &ISurfaceComposerClient::createSurface); - case Tag::CREATE_WITH_SURFACE_PARENT: - return callLocal(data, reply, &ISurfaceComposerClient::createWithSurfaceParent); - case Tag::CLEAR_LAYER_FRAME_STATS: - return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats); - case Tag::GET_LAYER_FRAME_STATS: - return callLocal(data, reply, &ISurfaceComposerClient::getLayerFrameStats); - case Tag::MIRROR_SURFACE: - return callLocal(data, reply, &ISurfaceComposerClient::mirrorSurface); - } -} - -} // namespace android diff --git a/libs/gui/LayerDebugInfo.cpp b/libs/gui/LayerDebugInfo.cpp index ea5fb293a6..15b2221464 100644 --- a/libs/gui/LayerDebugInfo.cpp +++ b/libs/gui/LayerDebugInfo.cpp @@ -27,7 +27,7 @@ using android::base::StringAppendF; #define RETURN_ON_ERROR(X) do {status_t res = (X); if (res != NO_ERROR) return res;} while(false) -namespace android { +namespace android::gui { status_t LayerDebugInfo::writeToParcel(Parcel* parcel) const { RETURN_ON_ERROR(parcel->writeCString(mName.c_str())); @@ -149,4 +149,4 @@ std::string to_string(const LayerDebugInfo& info) { return result; } -} // android +} // namespace android::gui diff --git a/libs/gui/LayerMetadata.cpp b/libs/gui/LayerMetadata.cpp index 189d51a4c1..4e12fd330c 100644 --- a/libs/gui/LayerMetadata.cpp +++ b/libs/gui/LayerMetadata.cpp @@ -23,7 +23,7 @@ using android::base::StringPrintf; -namespace android { +namespace android::gui { LayerMetadata::LayerMetadata() = default; @@ -144,4 +144,4 @@ std::string LayerMetadata::itemToString(uint32_t key, const char* separator) con } } -} // namespace android +} // namespace android::gui diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 502031c8d8..bb660854c8 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -19,10 +19,10 @@ #include <cinttypes> #include <cmath> +#include <android/gui/ISurfaceComposerClient.h> #include <android/native_window.h> #include <binder/Parcel.h> #include <gui/IGraphicBufferProducer.h> -#include <gui/ISurfaceComposerClient.h> #include <gui/LayerState.h> #include <private/gui/ParcelUtils.h> #include <system/window.h> @@ -63,9 +63,11 @@ layer_state_t::layer_state_t() frameRate(0.0f), frameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), changeFrameRateStrategy(ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS), + defaultFrameRateCompatibility(ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT), fixedTransformHint(ui::Transform::ROT_INVALID), autoRefresh(false), isTrustedOverlay(false), + borderEnabled(false), bufferCrop(Rect::INVALID_RECT), destinationFrame(Rect::INVALID_RECT), dropInputMode(gui::DropInputMode::NONE) { @@ -100,7 +102,12 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.write, transparentRegion); SAFE_PARCEL(output.writeUint32, transform); SAFE_PARCEL(output.writeBool, transformToDisplayInverse); - + SAFE_PARCEL(output.writeBool, borderEnabled); + SAFE_PARCEL(output.writeFloat, borderWidth); + SAFE_PARCEL(output.writeFloat, borderColor.r); + SAFE_PARCEL(output.writeFloat, borderColor.g); + SAFE_PARCEL(output.writeFloat, borderColor.b); + SAFE_PARCEL(output.writeFloat, borderColor.a); SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(dataspace)); SAFE_PARCEL(output.write, hdrMetadata); SAFE_PARCEL(output.write, surfaceDamageRegion); @@ -131,6 +138,7 @@ status_t layer_state_t::write(Parcel& output) const SAFE_PARCEL(output.writeFloat, frameRate); SAFE_PARCEL(output.writeByte, frameRateCompatibility); SAFE_PARCEL(output.writeByte, changeFrameRateStrategy); + SAFE_PARCEL(output.writeByte, defaultFrameRateCompatibility); SAFE_PARCEL(output.writeUint32, fixedTransformHint); SAFE_PARCEL(output.writeBool, autoRefresh); SAFE_PARCEL(output.writeBool, dimmingEnabled); @@ -200,6 +208,17 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.read, transparentRegion); SAFE_PARCEL(input.readUint32, &transform); SAFE_PARCEL(input.readBool, &transformToDisplayInverse); + SAFE_PARCEL(input.readBool, &borderEnabled); + SAFE_PARCEL(input.readFloat, &tmpFloat); + borderWidth = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + borderColor.r = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + borderColor.g = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + borderColor.b = tmpFloat; + SAFE_PARCEL(input.readFloat, &tmpFloat); + borderColor.a = tmpFloat; uint32_t tmpUint32 = 0; SAFE_PARCEL(input.readUint32, &tmpUint32); @@ -240,6 +259,7 @@ status_t layer_state_t::read(const Parcel& input) SAFE_PARCEL(input.readFloat, &frameRate); SAFE_PARCEL(input.readByte, &frameRateCompatibility); SAFE_PARCEL(input.readByte, &changeFrameRateStrategy); + SAFE_PARCEL(input.readByte, &defaultFrameRateCompatibility); SAFE_PARCEL(input.readUint32, &tmpUint32); fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32); SAFE_PARCEL(input.readBool, &autoRefresh); @@ -550,6 +570,16 @@ void layer_state_t::merge(const layer_state_t& other) { what |= eShadowRadiusChanged; shadowRadius = other.shadowRadius; } + if (other.what & eRenderBorderChanged) { + what |= eRenderBorderChanged; + borderEnabled = other.borderEnabled; + borderWidth = other.borderWidth; + borderColor = other.borderColor; + } + if (other.what & eDefaultFrameRateCompatibilityChanged) { + what |= eDefaultFrameRateCompatibilityChanged; + defaultFrameRateCompatibility = other.defaultFrameRateCompatibility; + } if (other.what & eFrameRateSelectionPriority) { what |= eFrameRateSelectionPriority; frameRateSelectionPriority = other.frameRateSelectionPriority; @@ -641,29 +671,44 @@ bool InputWindowCommands::merge(const InputWindowCommands& other) { changes |= !other.focusRequests.empty(); focusRequests.insert(focusRequests.end(), std::make_move_iterator(other.focusRequests.begin()), std::make_move_iterator(other.focusRequests.end())); - changes |= other.syncInputWindows && !syncInputWindows; - syncInputWindows |= other.syncInputWindows; + changes |= !other.windowInfosReportedListeners.empty(); + windowInfosReportedListeners.insert(other.windowInfosReportedListeners.begin(), + other.windowInfosReportedListeners.end()); return changes; } bool InputWindowCommands::empty() const { - return focusRequests.empty() && !syncInputWindows; + return focusRequests.empty() && windowInfosReportedListeners.empty(); } void InputWindowCommands::clear() { focusRequests.clear(); - syncInputWindows = false; + windowInfosReportedListeners.clear(); } status_t InputWindowCommands::write(Parcel& output) const { SAFE_PARCEL(output.writeParcelableVector, focusRequests); - SAFE_PARCEL(output.writeBool, syncInputWindows); + + SAFE_PARCEL(output.writeInt32, windowInfosReportedListeners.size()); + for (const auto& listener : windowInfosReportedListeners) { + SAFE_PARCEL(output.writeStrongBinder, listener); + } + return NO_ERROR; } status_t InputWindowCommands::read(const Parcel& input) { SAFE_PARCEL(input.readParcelableVector, &focusRequests); - SAFE_PARCEL(input.readBool, &syncInputWindows); + + int listenerSize = 0; + SAFE_PARCEL_READ_SIZE(input.readInt32, &listenerSize, input.dataSize()); + windowInfosReportedListeners.reserve(listenerSize); + for (int i = 0; i < listenerSize; i++) { + sp<gui::IWindowInfosReportedListener> listener; + SAFE_PARCEL(input.readStrongBinder, &listener); + windowInfosReportedListeners.insert(listener); + } + return NO_ERROR; } diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 54b6d6a549..e8aac2fb6f 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -39,6 +39,7 @@ #include <ui/GraphicBuffer.h> #include <ui/Region.h> +#include <gui/AidlStatusUtil.h> #include <gui/BufferItem.h> #include <gui/IProducerListener.h> @@ -49,6 +50,7 @@ namespace android { +using gui::aidl_utils::statusTFromBinderStatus; using ui::Dataspace; namespace { @@ -182,7 +184,7 @@ status_t Surface::getDisplayRefreshCycleDuration(nsecs_t* outRefreshDuration) { gui::DisplayStatInfo stats; binder::Status status = composerServiceAIDL()->getDisplayStats(nullptr, &stats); if (!status.isOk()) { - return status.transactionError(); + return statusTFromBinderStatus(status); } *outRefreshDuration = stats.vsyncPeriod; @@ -355,7 +357,7 @@ status_t Surface::getWideColorSupport(bool* supported) { *supported = false; binder::Status status = composerServiceAIDL()->isWideColorDisplay(display, supported); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t Surface::getHdrSupport(bool* supported) { @@ -366,12 +368,13 @@ status_t Surface::getHdrSupport(bool* supported) { return NAME_NOT_FOUND; } - ui::DynamicDisplayInfo info; - if (status_t err = composerService()->getDynamicDisplayInfo(display, &info); err != NO_ERROR) { - return err; + gui::DynamicDisplayInfo info; + if (binder::Status status = composerServiceAIDL()->getDynamicDisplayInfo(display, &info); + !status.isOk()) { + return statusTFromBinderStatus(status); } - *supported = !info.hdrCapabilities.getSupportedHdrTypes().empty(); + *supported = !info.hdrCapabilities.supportedHdrTypes.empty(); return NO_ERROR; } @@ -1256,10 +1259,10 @@ void Surface::querySupportedTimestampsLocked() const { mQueriedSupportedTimestamps = true; std::vector<FrameEvent> supportedFrameTimestamps; - status_t err = composerService()->getSupportedFrameTimestamps( - &supportedFrameTimestamps); + binder::Status status = + composerServiceAIDL()->getSupportedFrameTimestamps(&supportedFrameTimestamps); - if (err != NO_ERROR) { + if (!status.isOk()) { return; } @@ -1287,15 +1290,12 @@ int Surface::query(int what, int* value) const { if (err == NO_ERROR) { return NO_ERROR; } - sp<ISurfaceComposer> surfaceComposer = composerService(); + sp<gui::ISurfaceComposer> surfaceComposer = composerServiceAIDL(); if (surfaceComposer == nullptr) { return -EPERM; // likely permissions error } - if (surfaceComposer->authenticateSurfaceTexture(mGraphicBufferProducer)) { - *value = 1; - } else { - *value = 0; - } + // ISurfaceComposer no longer supports authenticateSurfaceTexture + *value = 0; return NO_ERROR; } case NATIVE_WINDOW_CONCRETE_TYPE: @@ -1867,7 +1867,11 @@ int Surface::dispatchSetFrameTimelineInfo(va_list args) { auto startTimeNanos = static_cast<int64_t>(va_arg(args, int64_t)); ALOGV("Surface::%s", __func__); - return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId, startTimeNanos}); + FrameTimelineInfo ftlInfo; + ftlInfo.vsyncId = frameTimelineVsyncId; + ftlInfo.inputEventId = inputEventId; + ftlInfo.startTimeNanos = startTimeNanos; + return setFrameTimelineInfo(ftlInfo); } bool Surface::transformToDisplayInverse() const { @@ -2623,22 +2627,18 @@ void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vector<int32_ mSurfaceListener->onBuffersDiscarded(discardedBufs); } -status_t Surface::setFrameRate(float frameRate, int8_t compatibility, - int8_t changeFrameRateStrategy) { - ATRACE_CALL(); - ALOGV("Surface::setFrameRate"); - - if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, - "Surface::setFrameRate")) { - return BAD_VALUE; - } - - return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility, - changeFrameRateStrategy); +[[deprecated]] status_t Surface::setFrameRate(float /*frameRate*/, int8_t /*compatibility*/, + int8_t /*changeFrameRateStrategy*/) { + ALOGI("Surface::setFrameRate is deprecated, setFrameRate hint is dropped as destination is not " + "SurfaceFlinger"); + // ISurfaceComposer no longer supports setFrameRate, we will return NO_ERROR when the api is + // called to avoid apps crashing, as BAD_VALUE can generate fatal exception in apps. + return NO_ERROR; } -status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) { - return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo); +status_t Surface::setFrameTimelineInfo(const FrameTimelineInfo& /*frameTimelineInfo*/) { + // ISurfaceComposer no longer supports setFrameTimelineInfo + return BAD_VALUE; } sp<IBinder> Surface::getSurfaceControlHandle() const { diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 9358e29030..16dbc922a4 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -19,8 +19,11 @@ #include <stdint.h> #include <sys/types.h> +#include <android/gui/BnWindowInfosReportedListener.h> #include <android/gui/DisplayState.h> +#include <android/gui/ISurfaceComposerClient.h> #include <android/gui/IWindowInfosListener.h> +#include <android/os/IInputConstants.h> #include <utils/Errors.h> #include <utils/Log.h> #include <utils/SortedVector.h> @@ -33,11 +36,11 @@ #include <system/graphics.h> +#include <gui/AidlStatusUtil.h> #include <gui/BufferItemConsumer.h> #include <gui/CpuConsumer.h> #include <gui/IGraphicBufferProducer.h> #include <gui/ISurfaceComposer.h> -#include <gui/ISurfaceComposerClient.h> #include <gui/LayerState.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> @@ -61,6 +64,7 @@ using gui::IRegionSamplingListener; using gui::WindowInfo; using gui::WindowInfoHandle; using gui::WindowInfosListener; +using gui::aidl_utils::statusTFromBinderStatus; using ui::ColorMode; // --------------------------------------------------------------------------- @@ -111,7 +115,6 @@ bool ComposerService::connectLocked() { if (instance.mComposerService == nullptr) { if (ComposerService::getInstance().connectLocked()) { ALOGD("ComposerService reconnected"); - WindowInfosListenerReporter::getInstance()->reconnect(instance.mComposerService); } } return instance.mComposerService; @@ -159,6 +162,7 @@ bool ComposerServiceAIDL::connectLocked() { if (instance.mComposerService == nullptr) { if (ComposerServiceAIDL::getInstance().connectLocked()) { ALOGD("ComposerServiceAIDL reconnected"); + WindowInfosListenerReporter::getInstance()->reconnect(instance.mComposerService); } } return instance.mComposerService; @@ -632,7 +636,8 @@ SurfaceComposerClient::Transaction::Transaction(const Transaction& other) mDesiredPresentTime(other.mDesiredPresentTime), mIsAutoTimestamp(other.mIsAutoTimestamp), mFrameTimelineInfo(other.mFrameTimelineInfo), - mApplyToken(other.mApplyToken) { + mApplyToken(other.mApplyToken), + mWindowInfosReportedEvent(other.mWindowInfosReportedEvent) { mDisplayStates = other.mDisplayStates; mComposerStates = other.mComposerStates; mInputWindowCommands = other.mInputWindowCommands; @@ -657,6 +662,7 @@ SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) { status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) { + const uint64_t transactionId = parcel->readUint64(); const uint32_t forceSynchronous = parcel->readUint32(); const uint32_t transactionNestCount = parcel->readUint32(); const bool animation = parcel->readBool(); @@ -666,7 +672,7 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel const int64_t desiredPresentTime = parcel->readInt64(); const bool isAutoTimestamp = parcel->readBool(); FrameTimelineInfo frameTimelineInfo; - SAFE_PARCEL(frameTimelineInfo.read, *parcel); + frameTimelineInfo.readFromParcel(parcel); sp<IBinder> applyToken; parcel->readNullableStrongBinder(&applyToken); @@ -734,6 +740,7 @@ status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel inputWindowCommands.read(*parcel); // Parsing was successful. Update the object. + mId = transactionId; mForceSynchronous = forceSynchronous; mTransactionNestCount = transactionNestCount; mAnimation = animation; @@ -765,6 +772,7 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const const_cast<SurfaceComposerClient::Transaction*>(this)->cacheBuffers(); + parcel->writeUint64(mId); parcel->writeUint32(mForceSynchronous); parcel->writeUint32(mTransactionNestCount); parcel->writeBool(mAnimation); @@ -773,7 +781,7 @@ status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const parcel->writeBool(mContainsBuffer); parcel->writeInt64(mDesiredPresentTime); parcel->writeBool(mIsAutoTimestamp); - SAFE_PARCEL(mFrameTimelineInfo.write, *parcel); + mFrameTimelineInfo.writeToParcel(parcel); parcel->writeStrongBinder(mApplyToken); parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size())); for (auto const& displayState : mDisplayStates) { @@ -873,8 +881,11 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Tr mEarlyWakeupStart = mEarlyWakeupStart || other.mEarlyWakeupStart; mEarlyWakeupEnd = mEarlyWakeupEnd || other.mEarlyWakeupEnd; mApplyToken = other.mApplyToken; + if (other.mWindowInfosReportedEvent) { + mWindowInfosReportedEvent = std::move(other.mWindowInfosReportedEvent); + } - mFrameTimelineInfo.merge(other.mFrameTimelineInfo); + mergeFrameTimelineInfo(mFrameTimelineInfo, other.mFrameTimelineInfo); other.clear(); return *this; @@ -893,8 +904,9 @@ void SurfaceComposerClient::Transaction::clear() { mEarlyWakeupEnd = false; mDesiredPresentTime = 0; mIsAutoTimestamp = true; - mFrameTimelineInfo.clear(); + clearFrameTimelineInfo(mFrameTimelineInfo); mApplyToken = nullptr; + mWindowInfosReportedEvent = nullptr; } uint64_t SurfaceComposerClient::Transaction::getId() { @@ -1041,6 +1053,10 @@ status_t SurfaceComposerClient::Transaction::apply(bool synchronous, bool oneWay hasListenerCallbacks, listenerCallbacks, mId); mId = generateId(); + if (mWindowInfosReportedEvent && !mWindowInfosReportedEvent->wait()) { + ALOGE("Timed out waiting for window infos to be reported."); + } + // Clear the current states and flags clear(); @@ -1085,7 +1101,7 @@ status_t SurfaceComposerClient::getPrimaryPhysicalDisplayId(PhysicalDisplayId* i if (status.isOk()) { *id = *DisplayId::fromValue<PhysicalDisplayId>(static_cast<uint64_t>(displayId)); } - return status.transactionError(); + return statusTFromBinderStatus(status); } std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() { @@ -1727,8 +1743,25 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFocus return *this; } +class NotifyWindowInfosReported : public gui::BnWindowInfosReportedListener { +public: + NotifyWindowInfosReported( + std::shared_ptr<SurfaceComposerClient::Event> windowInfosReportedEvent) + : mWindowInfosReportedEvent(windowInfosReportedEvent) {} + + binder::Status onWindowInfosReported() { + mWindowInfosReportedEvent->set(); + return binder::Status::ok(); + } + +private: + std::shared_ptr<SurfaceComposerClient::Event> mWindowInfosReportedEvent; +}; + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::syncInputWindows() { - mInputWindowCommands.syncInputWindows = true; + mWindowInfosReportedEvent = std::make_shared<Event>(); + mInputWindowCommands.windowInfosReportedListeners.insert( + sp<NotifyWindowInfosReported>::make(mWindowInfosReportedEvent)); return *this; } @@ -1835,6 +1868,19 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrame return *this; } +SurfaceComposerClient::Transaction& +SurfaceComposerClient::Transaction::setDefaultFrameRateCompatibility(const sp<SurfaceControl>& sc, + int8_t compatibility) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + s->what |= layer_state_t::eDefaultFrameRateCompatibilityChanged; + s->defaultFrameRateCompatibility = compatibility; + return *this; +} + SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixedTransformHint( const sp<SurfaceControl>& sc, int32_t fixedTransformHint) { layer_state_t* s = getLayerState(sc); @@ -1853,7 +1899,7 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFixed SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineInfo( const FrameTimelineInfo& frameTimelineInfo) { - mFrameTimelineInfo.merge(frameTimelineInfo); + mergeFrameTimelineInfo(mFrameTimelineInfo, frameTimelineInfo); return *this; } @@ -1947,6 +1993,23 @@ SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDropI return *this; } +SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::enableBorder( + const sp<SurfaceControl>& sc, bool shouldEnable, float width, const half4& color) { + layer_state_t* s = getLayerState(sc); + if (!s) { + mStatus = BAD_INDEX; + return *this; + } + + s->what |= layer_state_t::eRenderBorderChanged; + s->borderEnabled = shouldEnable; + s->borderWidth = width; + s->borderColor = color; + + registerSurfaceControlForCallback(sc); + return *this; +} + // --------------------------------------------------------------------------- DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) { @@ -2012,6 +2075,31 @@ void SurfaceComposerClient::Transaction::setDisplaySize(const sp<IBinder>& token s.what |= DisplayState::eDisplaySizeChanged; } +// copied from FrameTimelineInfo::merge() +void SurfaceComposerClient::Transaction::mergeFrameTimelineInfo(FrameTimelineInfo& t, + const FrameTimelineInfo& other) { + // When merging vsync Ids we take the oldest valid one + if (t.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID && + other.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) { + if (other.vsyncId > t.vsyncId) { + t.vsyncId = other.vsyncId; + t.inputEventId = other.inputEventId; + t.startTimeNanos = other.startTimeNanos; + } + } else if (t.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) { + t.vsyncId = other.vsyncId; + t.inputEventId = other.inputEventId; + t.startTimeNanos = other.startTimeNanos; + } +} + +// copied from FrameTimelineInfo::clear() +void SurfaceComposerClient::Transaction::clearFrameTimelineInfo(FrameTimelineInfo& t) { + t.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID; + t.inputEventId = os::IInputConstants::INVALID_INPUT_EVENT_ID; + t.startTimeNanos = 0; +} + // --------------------------------------------------------------------------- SurfaceComposerClient::SurfaceComposerClient() : mStatus(NO_INIT) {} @@ -2020,11 +2108,11 @@ SurfaceComposerClient::SurfaceComposerClient(const sp<ISurfaceComposerClient>& c : mStatus(NO_ERROR), mClient(client) {} void SurfaceComposerClient::onFirstRef() { - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); if (sf != nullptr && mStatus == NO_INIT) { sp<ISurfaceComposerClient> conn; - conn = sf->createConnection(); - if (conn != nullptr) { + binder::Status status = sf->createConnection(&conn); + if (status.isOk() && conn != nullptr) { mClient = conn; mStatus = NO_ERROR; } @@ -2062,7 +2150,7 @@ void SurfaceComposerClient::dispose() { } sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name, uint32_t w, uint32_t h, - PixelFormat format, uint32_t flags, + PixelFormat format, int32_t flags, const sp<IBinder>& parentHandle, LayerMetadata metadata, uint32_t* outTransformHint) { @@ -2072,38 +2160,9 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name, uin return s; } -sp<SurfaceControl> SurfaceComposerClient::createWithSurfaceParent(const String8& name, uint32_t w, - uint32_t h, PixelFormat format, - uint32_t flags, Surface* parent, - LayerMetadata metadata, - uint32_t* outTransformHint) { - sp<SurfaceControl> sur; - status_t err = mStatus; - - if (mStatus == NO_ERROR) { - sp<IBinder> handle; - sp<IGraphicBufferProducer> parentGbp = parent->getIGraphicBufferProducer(); - sp<IGraphicBufferProducer> gbp; - - uint32_t transformHint = 0; - int32_t id = -1; - err = mClient->createWithSurfaceParent(name, w, h, format, flags, parentGbp, - std::move(metadata), &handle, &gbp, &id, - &transformHint); - if (outTransformHint) { - *outTransformHint = transformHint; - } - ALOGE_IF(err, "SurfaceComposerClient::createWithSurfaceParent error %s", strerror(-err)); - if (err == NO_ERROR) { - return new SurfaceControl(this, handle, gbp, id, transformHint); - } - } - return nullptr; -} - status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h, PixelFormat format, - sp<SurfaceControl>* outSurface, uint32_t flags, + sp<SurfaceControl>* outSurface, int32_t flags, const sp<IBinder>& parentHandle, LayerMetadata metadata, uint32_t* outTransformHint) { @@ -2111,21 +2170,17 @@ status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32 status_t err = mStatus; if (mStatus == NO_ERROR) { - sp<IBinder> handle; - sp<IGraphicBufferProducer> gbp; - - uint32_t transformHint = 0; - int32_t id = -1; - err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata), - &handle, &gbp, &id, &transformHint); - + gui::CreateSurfaceResult result; + binder::Status status = mClient->createSurface(std::string(name.string()), flags, + parentHandle, std::move(metadata), &result); + err = statusTFromBinderStatus(status); if (outTransformHint) { - *outTransformHint = transformHint; + *outTransformHint = result.transformHint; } ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err)); if (err == NO_ERROR) { - *outSurface = - new SurfaceControl(this, handle, gbp, id, w, h, format, transformHint, flags); + *outSurface = new SurfaceControl(this, result.handle, result.layerId, w, h, format, + result.transformHint, flags); } } return err; @@ -2136,12 +2191,12 @@ sp<SurfaceControl> SurfaceComposerClient::mirrorSurface(SurfaceControl* mirrorFr return nullptr; } - sp<IBinder> handle; sp<IBinder> mirrorFromHandle = mirrorFromSurface->getHandle(); - int32_t layer_id = -1; - status_t err = mClient->mirrorSurface(mirrorFromHandle, &handle, &layer_id); + gui::MirrorSurfaceResult result; + const binder::Status status = mClient->mirrorSurface(mirrorFromHandle, &result); + const status_t err = statusTFromBinderStatus(status); if (err == NO_ERROR) { - return new SurfaceControl(this, handle, nullptr, layer_id, true /* owned */); + return new SurfaceControl(this, result.handle, result.layerId); } return nullptr; } @@ -2150,7 +2205,8 @@ status_t SurfaceComposerClient::clearLayerFrameStats(const sp<IBinder>& token) c if (mStatus != NO_ERROR) { return mStatus; } - return mClient->clearLayerFrameStats(token); + const binder::Status status = mClient->clearLayerFrameStats(token); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getLayerFrameStats(const sp<IBinder>& token, @@ -2158,19 +2214,38 @@ status_t SurfaceComposerClient::getLayerFrameStats(const sp<IBinder>& token, if (mStatus != NO_ERROR) { return mStatus; } - return mClient->getLayerFrameStats(token, outStats); + gui::FrameStats stats; + const binder::Status status = mClient->getLayerFrameStats(token, &stats); + if (status.isOk()) { + outStats->refreshPeriodNano = stats.refreshPeriodNano; + outStats->desiredPresentTimesNano.setCapacity(stats.desiredPresentTimesNano.size()); + for (const auto& t : stats.desiredPresentTimesNano) { + outStats->desiredPresentTimesNano.add(t); + } + outStats->actualPresentTimesNano.setCapacity(stats.actualPresentTimesNano.size()); + for (const auto& t : stats.actualPresentTimesNano) { + outStats->actualPresentTimesNano.add(t); + } + outStats->frameReadyTimesNano.setCapacity(stats.frameReadyTimesNano.size()); + for (const auto& t : stats.frameReadyTimesNano) { + outStats->frameReadyTimesNano.add(t); + } + } + return statusTFromBinderStatus(status); } // ---------------------------------------------------------------------------- status_t SurfaceComposerClient::enableVSyncInjections(bool enable) { - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - return sf->enableVSyncInjections(enable); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); + binder::Status status = sf->enableVSyncInjections(enable); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::injectVSync(nsecs_t when) { - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - return sf->injectVSync(when); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); + binder::Status status = sf->injectVSync(when); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display, @@ -2184,17 +2259,106 @@ status_t SurfaceComposerClient::getDisplayState(const sp<IBinder>& display, state->layerStackSpaceRect = ui::Size(ds.layerStackSpaceRect.width, ds.layerStackSpaceRect.height); } - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getStaticDisplayInfo(const sp<IBinder>& display, - ui::StaticDisplayInfo* info) { - return ComposerService::getComposerService()->getStaticDisplayInfo(display, info); + ui::StaticDisplayInfo* outInfo) { + using Tag = android::gui::DeviceProductInfo::ManufactureOrModelDate::Tag; + gui::StaticDisplayInfo ginfo; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getStaticDisplayInfo(display, &ginfo); + if (status.isOk()) { + // convert gui::StaticDisplayInfo to ui::StaticDisplayInfo + outInfo->connectionType = static_cast<ui::DisplayConnectionType>(ginfo.connectionType); + outInfo->density = ginfo.density; + outInfo->secure = ginfo.secure; + outInfo->installOrientation = static_cast<ui::Rotation>(ginfo.installOrientation); + + DeviceProductInfo info; + std::optional<gui::DeviceProductInfo> dpi = ginfo.deviceProductInfo; + gui::DeviceProductInfo::ManufactureOrModelDate& date = dpi->manufactureOrModelDate; + info.name = dpi->name; + if (dpi->manufacturerPnpId.size() > 0) { + // copid from PnpId = std::array<char, 4> in ui/DeviceProductInfo.h + constexpr int kMaxPnpIdSize = 4; + size_t count = std::max<size_t>(kMaxPnpIdSize, dpi->manufacturerPnpId.size()); + std::copy_n(dpi->manufacturerPnpId.begin(), count, info.manufacturerPnpId.begin()); + } + if (dpi->relativeAddress.size() > 0) { + std::copy(dpi->relativeAddress.begin(), dpi->relativeAddress.end(), + std::back_inserter(info.relativeAddress)); + } + info.productId = dpi->productId; + if (date.getTag() == Tag::modelYear) { + DeviceProductInfo::ModelYear modelYear; + modelYear.year = static_cast<uint32_t>(date.get<Tag::modelYear>().year); + info.manufactureOrModelDate = modelYear; + } else if (date.getTag() == Tag::manufactureYear) { + DeviceProductInfo::ManufactureYear manufactureYear; + manufactureYear.year = date.get<Tag::manufactureYear>().modelYear.year; + info.manufactureOrModelDate = manufactureYear; + } else if (date.getTag() == Tag::manufactureWeekAndYear) { + DeviceProductInfo::ManufactureWeekAndYear weekAndYear; + weekAndYear.year = + date.get<Tag::manufactureWeekAndYear>().manufactureYear.modelYear.year; + weekAndYear.week = date.get<Tag::manufactureWeekAndYear>().week; + info.manufactureOrModelDate = weekAndYear; + } + + outInfo->deviceProductInfo = info; + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDynamicDisplayInfo(const sp<IBinder>& display, - ui::DynamicDisplayInfo* info) { - return ComposerService::getComposerService()->getDynamicDisplayInfo(display, info); + ui::DynamicDisplayInfo* outInfo) { + gui::DynamicDisplayInfo ginfo; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getDynamicDisplayInfo(display, &ginfo); + if (status.isOk()) { + // convert gui::DynamicDisplayInfo to ui::DynamicDisplayInfo + outInfo->supportedDisplayModes.clear(); + outInfo->supportedDisplayModes.reserve(ginfo.supportedDisplayModes.size()); + for (const auto& mode : ginfo.supportedDisplayModes) { + ui::DisplayMode outMode; + outMode.id = mode.id; + outMode.resolution.width = mode.resolution.width; + outMode.resolution.height = mode.resolution.height; + outMode.xDpi = mode.xDpi; + outMode.yDpi = mode.yDpi; + outMode.refreshRate = mode.refreshRate; + outMode.appVsyncOffset = mode.appVsyncOffset; + outMode.sfVsyncOffset = mode.sfVsyncOffset; + outMode.presentationDeadline = mode.presentationDeadline; + outMode.group = mode.group; + outInfo->supportedDisplayModes.push_back(outMode); + } + + outInfo->activeDisplayModeId = ginfo.activeDisplayModeId; + + outInfo->supportedColorModes.clear(); + outInfo->supportedColorModes.reserve(ginfo.supportedColorModes.size()); + for (const auto& cmode : ginfo.supportedColorModes) { + outInfo->supportedColorModes.push_back(static_cast<ui::ColorMode>(cmode)); + } + + outInfo->activeColorMode = static_cast<ui::ColorMode>(ginfo.activeColorMode); + + std::vector<ui::Hdr> types; + types.reserve(ginfo.hdrCapabilities.supportedHdrTypes.size()); + for (const auto& hdr : ginfo.hdrCapabilities.supportedHdrTypes) { + types.push_back(static_cast<ui::Hdr>(hdr)); + } + outInfo->hdrCapabilities = HdrCapabilities(types, ginfo.hdrCapabilities.maxLuminance, + ginfo.hdrCapabilities.maxAverageLuminance, + ginfo.hdrCapabilities.minLuminance); + + outInfo->autoLowLatencyModeSupported = ginfo.autoLowLatencyModeSupported; + outInfo->gameContentTypeSupported = ginfo.gameContentTypeSupported; + outInfo->preferredBootDisplayMode = ginfo.preferredBootDisplayMode; + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getActiveDisplayMode(const sp<IBinder>& display, @@ -2218,10 +2382,13 @@ status_t SurfaceComposerClient::setDesiredDisplayModeSpecs( const sp<IBinder>& displayToken, ui::DisplayModeId defaultMode, bool allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin, float appRequestRefreshRateMax) { - return ComposerService::getComposerService() - ->setDesiredDisplayModeSpecs(displayToken, defaultMode, allowGroupSwitching, - primaryRefreshRateMin, primaryRefreshRateMax, - appRequestRefreshRateMin, appRequestRefreshRateMax); + binder::Status status = + ComposerServiceAIDL::getComposerService() + ->setDesiredDisplayModeSpecs(displayToken, defaultMode, allowGroupSwitching, + primaryRefreshRateMin, primaryRefreshRateMax, + appRequestRefreshRateMin, + appRequestRefreshRateMax); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, @@ -2231,41 +2398,81 @@ status_t SurfaceComposerClient::getDesiredDisplayModeSpecs(const sp<IBinder>& di float* outPrimaryRefreshRateMax, float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) { - return ComposerService::getComposerService() - ->getDesiredDisplayModeSpecs(displayToken, outDefaultMode, outAllowGroupSwitching, - outPrimaryRefreshRateMin, outPrimaryRefreshRateMax, - outAppRequestRefreshRateMin, outAppRequestRefreshRateMax); + if (!outDefaultMode || !outAllowGroupSwitching || !outPrimaryRefreshRateMin || + !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) { + return BAD_VALUE; + } + gui::DisplayModeSpecs specs; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getDesiredDisplayModeSpecs(displayToken, + &specs); + if (status.isOk()) { + *outDefaultMode = specs.defaultMode; + *outAllowGroupSwitching = specs.allowGroupSwitching; + *outPrimaryRefreshRateMin = specs.primaryRefreshRateMin; + *outPrimaryRefreshRateMax = specs.primaryRefreshRateMax; + *outAppRequestRefreshRateMin = specs.appRequestRefreshRateMin; + *outAppRequestRefreshRateMax = specs.appRequestRefreshRateMax; + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDisplayNativePrimaries(const sp<IBinder>& display, ui::DisplayPrimaries& outPrimaries) { - return ComposerService::getComposerService()->getDisplayNativePrimaries(display, outPrimaries); + gui::DisplayPrimaries primaries; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getDisplayNativePrimaries(display, + &primaries); + if (status.isOk()) { + outPrimaries.red.X = primaries.red.X; + outPrimaries.red.Y = primaries.red.Y; + outPrimaries.red.Z = primaries.red.Z; + + outPrimaries.green.X = primaries.green.X; + outPrimaries.green.Y = primaries.green.Y; + outPrimaries.green.Z = primaries.green.Z; + + outPrimaries.blue.X = primaries.blue.X; + outPrimaries.blue.Y = primaries.blue.Y; + outPrimaries.blue.Z = primaries.blue.Z; + + outPrimaries.white.X = primaries.white.X; + outPrimaries.white.Y = primaries.white.Y; + outPrimaries.white.Z = primaries.white.Z; + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setActiveColorMode(const sp<IBinder>& display, ColorMode colorMode) { - return ComposerService::getComposerService()->setActiveColorMode(display, colorMode); + binder::Status status = ComposerServiceAIDL::getComposerService() + ->setActiveColorMode(display, static_cast<int>(colorMode)); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getBootDisplayModeSupport(bool* support) { binder::Status status = ComposerServiceAIDL::getComposerService()->getBootDisplayModeSupport(support); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setBootDisplayMode(const sp<IBinder>& display, ui::DisplayModeId displayModeId) { - return ComposerService::getComposerService()->setBootDisplayMode(display, displayModeId); + binder::Status status = ComposerServiceAIDL::getComposerService() + ->setBootDisplayMode(display, static_cast<int>(displayModeId)); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::clearBootDisplayMode(const sp<IBinder>& display) { binder::Status status = ComposerServiceAIDL::getComposerService()->clearBootDisplayMode(display); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setOverrideFrameRate(uid_t uid, float frameRate) { - return ComposerService::getComposerService()->setOverrideFrameRate(uid, frameRate); + binder::Status status = + ComposerServiceAIDL::getComposerService()->setOverrideFrameRate(uid, frameRate); + return statusTFromBinderStatus(status); } void SurfaceComposerClient::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) { @@ -2284,57 +2491,137 @@ void SurfaceComposerClient::setDisplayPowerMode(const sp<IBinder>& token, status_t SurfaceComposerClient::getCompositionPreference( ui::Dataspace* defaultDataspace, ui::PixelFormat* defaultPixelFormat, ui::Dataspace* wideColorGamutDataspace, ui::PixelFormat* wideColorGamutPixelFormat) { - return ComposerService::getComposerService() - ->getCompositionPreference(defaultDataspace, defaultPixelFormat, - wideColorGamutDataspace, wideColorGamutPixelFormat); + gui::CompositionPreference pref; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getCompositionPreference(&pref); + if (status.isOk()) { + *defaultDataspace = static_cast<ui::Dataspace>(pref.defaultDataspace); + *defaultPixelFormat = static_cast<ui::PixelFormat>(pref.defaultPixelFormat); + *wideColorGamutDataspace = static_cast<ui::Dataspace>(pref.wideColorGamutDataspace); + *wideColorGamutPixelFormat = static_cast<ui::PixelFormat>(pref.wideColorGamutPixelFormat); + } + return statusTFromBinderStatus(status); } bool SurfaceComposerClient::getProtectedContentSupport() { bool supported = false; - ComposerService::getComposerService()->getProtectedContentSupport(&supported); + ComposerServiceAIDL::getComposerService()->getProtectedContentSupport(&supported); return supported; } status_t SurfaceComposerClient::clearAnimationFrameStats() { - return ComposerService::getComposerService()->clearAnimationFrameStats(); + binder::Status status = ComposerServiceAIDL::getComposerService()->clearAnimationFrameStats(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getAnimationFrameStats(FrameStats* outStats) { - return ComposerService::getComposerService()->getAnimationFrameStats(outStats); + gui::FrameStats stats; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getAnimationFrameStats(&stats); + if (status.isOk()) { + outStats->refreshPeriodNano = stats.refreshPeriodNano; + outStats->desiredPresentTimesNano.setCapacity(stats.desiredPresentTimesNano.size()); + for (const auto& t : stats.desiredPresentTimesNano) { + outStats->desiredPresentTimesNano.add(t); + } + outStats->actualPresentTimesNano.setCapacity(stats.actualPresentTimesNano.size()); + for (const auto& t : stats.actualPresentTimesNano) { + outStats->actualPresentTimesNano.add(t); + } + outStats->frameReadyTimesNano.setCapacity(stats.frameReadyTimesNano.size()); + for (const auto& t : stats.frameReadyTimesNano) { + outStats->frameReadyTimesNano.add(t); + } + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::overrideHdrTypes(const sp<IBinder>& display, const std::vector<ui::Hdr>& hdrTypes) { - return ComposerService::getComposerService()->overrideHdrTypes(display, hdrTypes); + std::vector<int32_t> hdrTypesVector; + hdrTypesVector.reserve(hdrTypes.size()); + for (auto t : hdrTypes) { + hdrTypesVector.push_back(static_cast<int32_t>(t)); + } + + binder::Status status = + ComposerServiceAIDL::getComposerService()->overrideHdrTypes(display, hdrTypesVector); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::onPullAtom(const int32_t atomId, std::string* outData, bool* success) { - return ComposerService::getComposerService()->onPullAtom(atomId, outData, success); + gui::PullAtomData pad; + binder::Status status = ComposerServiceAIDL::getComposerService()->onPullAtom(atomId, &pad); + if (status.isOk()) { + outData->assign((const char*)pad.data.data(), pad.data.size()); + *success = pad.success; + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDisplayedContentSamplingAttributes(const sp<IBinder>& display, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, uint8_t* outComponentMask) { - return ComposerService::getComposerService() - ->getDisplayedContentSamplingAttributes(display, outFormat, outDataspace, - outComponentMask); + if (!outFormat || !outDataspace || !outComponentMask) { + return BAD_VALUE; + } + + gui::ContentSamplingAttributes attrs; + binder::Status status = ComposerServiceAIDL::getComposerService() + ->getDisplayedContentSamplingAttributes(display, &attrs); + if (status.isOk()) { + *outFormat = static_cast<ui::PixelFormat>(attrs.format); + *outDataspace = static_cast<ui::Dataspace>(attrs.dataspace); + *outComponentMask = static_cast<uint8_t>(attrs.componentMask); + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable, uint8_t componentMask, uint64_t maxFrames) { - return ComposerService::getComposerService()->setDisplayContentSamplingEnabled(display, enable, - componentMask, - maxFrames); + binder::Status status = + ComposerServiceAIDL::getComposerService() + ->setDisplayContentSamplingEnabled(display, enable, + static_cast<int8_t>(componentMask), + static_cast<int64_t>(maxFrames)); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames, uint64_t timestamp, DisplayedFrameStats* outStats) { - return ComposerService::getComposerService()->getDisplayedContentSample(display, maxFrames, - timestamp, outStats); + if (!outStats) { + return BAD_VALUE; + } + + gui::DisplayedFrameStats stats; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getDisplayedContentSample(display, maxFrames, + timestamp, &stats); + if (status.isOk()) { + // convert gui::DisplayedFrameStats to ui::DisplayedFrameStats + outStats->numFrames = static_cast<uint64_t>(stats.numFrames); + outStats->component_0_sample.reserve(stats.component_0_sample.size()); + for (const auto& s : stats.component_0_sample) { + outStats->component_0_sample.push_back(static_cast<uint64_t>(s)); + } + outStats->component_1_sample.reserve(stats.component_1_sample.size()); + for (const auto& s : stats.component_1_sample) { + outStats->component_1_sample.push_back(static_cast<uint64_t>(s)); + } + outStats->component_2_sample.reserve(stats.component_2_sample.size()); + for (const auto& s : stats.component_2_sample) { + outStats->component_2_sample.push_back(static_cast<uint64_t>(s)); + } + outStats->component_3_sample.reserve(stats.component_3_sample.size()); + for (const auto& s : stats.component_3_sample) { + outStats->component_3_sample.push_back(static_cast<uint64_t>(s)); + } + } + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::isWideColorDisplay(const sp<IBinder>& display, @@ -2342,39 +2629,55 @@ status_t SurfaceComposerClient::isWideColorDisplay(const sp<IBinder>& display, binder::Status status = ComposerServiceAIDL::getComposerService()->isWideColorDisplay(display, outIsWideColorDisplay); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::addRegionSamplingListener( const Rect& samplingArea, const sp<IBinder>& stopLayerHandle, const sp<IRegionSamplingListener>& listener) { - return ComposerService::getComposerService()->addRegionSamplingListener(samplingArea, - stopLayerHandle, - listener); + gui::ARect rect; + rect.left = samplingArea.left; + rect.top = samplingArea.top; + rect.right = samplingArea.right; + rect.bottom = samplingArea.bottom; + binder::Status status = + ComposerServiceAIDL::getComposerService()->addRegionSamplingListener(rect, + stopLayerHandle, + listener); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::removeRegionSamplingListener( const sp<IRegionSamplingListener>& listener) { - return ComposerService::getComposerService()->removeRegionSamplingListener(listener); + binder::Status status = + ComposerServiceAIDL::getComposerService()->removeRegionSamplingListener(listener); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) { - return ComposerService::getComposerService()->addFpsListener(taskId, listener); + binder::Status status = + ComposerServiceAIDL::getComposerService()->addFpsListener(taskId, listener); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::removeFpsListener(const sp<gui::IFpsListener>& listener) { - return ComposerService::getComposerService()->removeFpsListener(listener); + binder::Status status = ComposerServiceAIDL::getComposerService()->removeFpsListener(listener); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::addTunnelModeEnabledListener( const sp<gui::ITunnelModeEnabledListener>& listener) { - return ComposerService::getComposerService()->addTunnelModeEnabledListener(listener); + binder::Status status = + ComposerServiceAIDL::getComposerService()->addTunnelModeEnabledListener(listener); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::removeTunnelModeEnabledListener( const sp<gui::ITunnelModeEnabledListener>& listener) { - return ComposerService::getComposerService()->removeTunnelModeEnabledListener(listener); + binder::Status status = + ComposerServiceAIDL::getComposerService()->removeTunnelModeEnabledListener(listener); + return statusTFromBinderStatus(status); } bool SurfaceComposerClient::getDisplayBrightnessSupport(const sp<IBinder>& displayToken) { @@ -2390,7 +2693,7 @@ status_t SurfaceComposerClient::setDisplayBrightness(const sp<IBinder>& displayT binder::Status status = ComposerServiceAIDL::getComposerService()->setDisplayBrightness(displayToken, brightness); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::addHdrLayerInfoListener( @@ -2398,7 +2701,7 @@ status_t SurfaceComposerClient::addHdrLayerInfoListener( binder::Status status = ComposerServiceAIDL::getComposerService()->addHdrLayerInfoListener(displayToken, listener); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::removeHdrLayerInfoListener( @@ -2406,45 +2709,76 @@ status_t SurfaceComposerClient::removeHdrLayerInfoListener( binder::Status status = ComposerServiceAIDL::getComposerService()->removeHdrLayerInfoListener(displayToken, listener); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::notifyPowerBoost(int32_t boostId) { binder::Status status = ComposerServiceAIDL::getComposerService()->notifyPowerBoost(boostId); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t SurfaceComposerClient::setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, float lightPosY, float lightPosZ, float lightRadius) { - return ComposerService::getComposerService()->setGlobalShadowSettings(ambientColor, spotColor, - lightPosY, lightPosZ, - lightRadius); + gui::Color ambientColorG, spotColorG; + ambientColorG.r = ambientColor.r; + ambientColorG.g = ambientColor.g; + ambientColorG.b = ambientColor.b; + ambientColorG.a = ambientColor.a; + spotColorG.r = spotColor.r; + spotColorG.g = spotColor.g; + spotColorG.b = spotColor.b; + spotColorG.a = spotColor.a; + binder::Status status = + ComposerServiceAIDL::getComposerService()->setGlobalShadowSettings(ambientColorG, + spotColorG, + lightPosY, lightPosZ, + lightRadius); + return statusTFromBinderStatus(status); } std::optional<DisplayDecorationSupport> SurfaceComposerClient::getDisplayDecorationSupport( const sp<IBinder>& displayToken) { + std::optional<gui::DisplayDecorationSupport> gsupport; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getDisplayDecorationSupport(displayToken, + &gsupport); std::optional<DisplayDecorationSupport> support; - ComposerService::getComposerService()->getDisplayDecorationSupport(displayToken, &support); + if (status.isOk() && gsupport.has_value()) { + support->format = static_cast<aidl::android::hardware::graphics::common::PixelFormat>( + gsupport->format); + support->alphaInterpretation = + static_cast<aidl::android::hardware::graphics::common::AlphaInterpretation>( + gsupport->alphaInterpretation); + } return support; } -int SurfaceComposerClient::getGPUContextPriority() { - return ComposerService::getComposerService()->getGPUContextPriority(); +int SurfaceComposerClient::getGpuContextPriority() { + int priority; + binder::Status status = + ComposerServiceAIDL::getComposerService()->getGpuContextPriority(&priority); + if (!status.isOk()) { + status_t err = statusTFromBinderStatus(status); + ALOGE("getGpuContextPriority failed to read data: %s (%d)", strerror(-err), err); + return 0; + } + return priority; } status_t SurfaceComposerClient::addWindowInfosListener( const sp<WindowInfosListener>& windowInfosListener, std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo) { return WindowInfosListenerReporter::getInstance() - ->addWindowInfosListener(windowInfosListener, ComposerService::getComposerService(), + ->addWindowInfosListener(windowInfosListener, ComposerServiceAIDL::getComposerService(), outInitialInfo); } status_t SurfaceComposerClient::removeWindowInfosListener( const sp<WindowInfosListener>& windowInfosListener) { return WindowInfosListenerReporter::getInstance() - ->removeWindowInfosListener(windowInfosListener, ComposerService::getComposerService()); + ->removeWindowInfosListener(windowInfosListener, + ComposerServiceAIDL::getComposerService()); } // ---------------------------------------------------------------------------- @@ -2455,7 +2789,7 @@ status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs, if (s == nullptr) return NO_INIT; binder::Status status = s->captureDisplay(captureArgs, captureListener); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t ScreenshotClient::captureDisplay(DisplayId displayId, @@ -2464,7 +2798,7 @@ status_t ScreenshotClient::captureDisplay(DisplayId displayId, if (s == nullptr) return NO_INIT; binder::Status status = s->captureDisplayById(displayId.value, captureListener); - return status.transactionError(); + return statusTFromBinderStatus(status); } status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs, @@ -2473,7 +2807,7 @@ status_t ScreenshotClient::captureLayers(const LayerCaptureArgs& captureArgs, if (s == nullptr) return NO_INIT; binder::Status status = s->captureLayers(captureArgs, captureListener); - return status.transactionError(); + return statusTFromBinderStatus(status); } // --------------------------------------------------------------------------------- @@ -2515,4 +2849,17 @@ void ReleaseCallbackThread::threadMain() { } } +// --------------------------------------------------------------------------------- + +void SurfaceComposerClient::Event::set() { + std::lock_guard<std::mutex> lock(mMutex); + mComplete = true; + mConditionVariable.notify_all(); +} + +bool SurfaceComposerClient::Event::wait() { + std::unique_lock<std::mutex> lock(mMutex); + return mConditionVariable.wait_for(lock, sTimeout, [this] { return mComplete; }); +} + } // namespace android diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp index 654fb336fe..84257dee9b 100644 --- a/libs/gui/SurfaceControl.cpp +++ b/libs/gui/SurfaceControl.cpp @@ -49,12 +49,10 @@ namespace android { // ============================================================================ SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle, - const sp<IGraphicBufferProducer>& gbp, int32_t layerId, - uint32_t w, uint32_t h, PixelFormat format, uint32_t transform, - uint32_t flags) + int32_t layerId, uint32_t w, uint32_t h, PixelFormat format, + uint32_t transform, uint32_t flags) : mClient(client), mHandle(handle), - mGraphicBufferProducer(gbp), mLayerId(layerId), mTransformHint(transform), mWidth(w), @@ -65,7 +63,6 @@ SurfaceControl::SurfaceControl(const sp<SurfaceComposerClient>& client, const sp SurfaceControl::SurfaceControl(const sp<SurfaceControl>& other) { mClient = other->mClient; mHandle = other->mHandle; - mGraphicBufferProducer = other->mGraphicBufferProducer; mTransformHint = other->mTransformHint; mLayerId = other->mLayerId; mWidth = other->mWidth; @@ -165,11 +162,11 @@ sp<Surface> SurfaceControl::createSurface() void SurfaceControl::updateDefaultBufferSize(uint32_t width, uint32_t height) { Mutex::Autolock _l(mLock); - mWidth = width; mHeight = height; + mWidth = width; + mHeight = height; if (mBbq) { mBbq->update(mBbqChild, width, height, mFormat); } - } sp<IBinder> SurfaceControl::getLayerStateHandle() const @@ -245,9 +242,7 @@ status_t SurfaceControl::readFromParcel(const Parcel& parcel, *outSurfaceControl = new SurfaceControl(new SurfaceComposerClient( interface_cast<ISurfaceComposerClient>(client)), - handle.get(), nullptr, layerId, - width, height, format, - transformHint); + handle.get(), layerId, width, height, format, transformHint); return NO_ERROR; } diff --git a/libs/gui/TransactionTracing.cpp b/libs/gui/TransactionTracing.cpp index eedc3df009..59450fb411 100644 --- a/libs/gui/TransactionTracing.cpp +++ b/libs/gui/TransactionTracing.cpp @@ -15,9 +15,9 @@ */ #include "gui/TransactionTracing.h" -#include "gui/ISurfaceComposer.h" +#include "android/gui/ISurfaceComposer.h" -#include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> namespace android { @@ -32,7 +32,7 @@ sp<TransactionTraceListener> TransactionTraceListener::getInstance() { if (sInstance == nullptr) { sInstance = new TransactionTraceListener; - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); sf->addTransactionTraceListener(sInstance); } @@ -50,4 +50,4 @@ bool TransactionTraceListener::isTracingEnabled() { return mTracingEnabled; } -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp index 4e966d1393..804ce4fac0 100644 --- a/libs/gui/WindowInfo.cpp +++ b/libs/gui/WindowInfo.cpp @@ -76,7 +76,7 @@ bool WindowInfo::operator==(const WindowInfo& info) const { info.inputConfig == inputConfig && info.displayId == displayId && info.replaceTouchableRegionWithCrop == replaceTouchableRegionWithCrop && info.applicationInfo == applicationInfo && info.layoutParamsType == layoutParamsType && - info.layoutParamsFlags == layoutParamsFlags && info.isClone == isClone; + info.layoutParamsFlags == layoutParamsFlags; } status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { @@ -124,8 +124,7 @@ status_t WindowInfo::writeToParcel(android::Parcel* parcel) const { parcel->write(touchableRegion) ?: parcel->writeBool(replaceTouchableRegionWithCrop) ?: parcel->writeStrongBinder(touchableRegionCropHandle.promote()) ?: - parcel->writeStrongBinder(windowToken) ?: - parcel->writeBool(isClone); + parcel->writeStrongBinder(windowToken); // clang-format on return status; } @@ -176,8 +175,7 @@ status_t WindowInfo::readFromParcel(const android::Parcel* parcel) { parcel->read(touchableRegion) ?: parcel->readBool(&replaceTouchableRegionWithCrop) ?: parcel->readNullableStrongBinder(&touchableRegionCropHandleSp) ?: - parcel->readNullableStrongBinder(&windowToken) ?: - parcel->readBool(&isClone); + parcel->readNullableStrongBinder(&windowToken); // clang-format on if (status != OK) { diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp index cfc7dbc463..01e865da6a 100644 --- a/libs/gui/WindowInfosListenerReporter.cpp +++ b/libs/gui/WindowInfosListenerReporter.cpp @@ -14,7 +14,8 @@ * limitations under the License. */ -#include <gui/ISurfaceComposer.h> +#include <android/gui/ISurfaceComposer.h> +#include <gui/AidlStatusUtil.h> #include <gui/WindowInfosListenerReporter.h> namespace android { @@ -23,6 +24,7 @@ using gui::DisplayInfo; using gui::IWindowInfosReportedListener; using gui::WindowInfo; using gui::WindowInfosListener; +using gui::aidl_utils::statusTFromBinderStatus; sp<WindowInfosListenerReporter> WindowInfosListenerReporter::getInstance() { static sp<WindowInfosListenerReporter> sInstance = new WindowInfosListenerReporter; @@ -31,13 +33,14 @@ sp<WindowInfosListenerReporter> WindowInfosListenerReporter::getInstance() { status_t WindowInfosListenerReporter::addWindowInfosListener( const sp<WindowInfosListener>& windowInfosListener, - const sp<ISurfaceComposer>& surfaceComposer, + const sp<gui::ISurfaceComposer>& surfaceComposer, std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo) { status_t status = OK; { std::scoped_lock lock(mListenersMutex); if (mWindowInfosListeners.empty()) { - status = surfaceComposer->addWindowInfosListener(this); + binder::Status s = surfaceComposer->addWindowInfosListener(this); + status = statusTFromBinderStatus(s); } if (status == OK) { @@ -55,12 +58,13 @@ status_t WindowInfosListenerReporter::addWindowInfosListener( status_t WindowInfosListenerReporter::removeWindowInfosListener( const sp<WindowInfosListener>& windowInfosListener, - const sp<ISurfaceComposer>& surfaceComposer) { + const sp<gui::ISurfaceComposer>& surfaceComposer) { status_t status = OK; { std::scoped_lock lock(mListenersMutex); if (mWindowInfosListeners.size() == 1) { - status = surfaceComposer->removeWindowInfosListener(this); + binder::Status s = surfaceComposer->removeWindowInfosListener(this); + status = statusTFromBinderStatus(s); // Clear the last stored state since we're disabling updates and don't want to hold // stale values mLastWindowInfos.clear(); @@ -78,7 +82,8 @@ status_t WindowInfosListenerReporter::removeWindowInfosListener( binder::Status WindowInfosListenerReporter::onWindowInfosChanged( const std::vector<WindowInfo>& windowInfos, const std::vector<DisplayInfo>& displayInfos, const sp<IWindowInfosReportedListener>& windowInfosReportedListener) { - std::unordered_set<sp<WindowInfosListener>, SpHash<WindowInfosListener>> windowInfosListeners; + std::unordered_set<sp<WindowInfosListener>, gui::SpHash<WindowInfosListener>> + windowInfosListeners; { std::scoped_lock lock(mListenersMutex); @@ -101,7 +106,7 @@ binder::Status WindowInfosListenerReporter::onWindowInfosChanged( return binder::Status::ok(); } -void WindowInfosListenerReporter::reconnect(const sp<ISurfaceComposer>& composerService) { +void WindowInfosListenerReporter::reconnect(const sp<gui::ISurfaceComposer>& composerService) { std::scoped_lock lock(mListenersMutex); if (!mWindowInfosListeners.empty()) { composerService->addWindowInfosListener(this); diff --git a/libs/gui/aidl/android/gui/Rect.aidl b/libs/gui/aidl/android/gui/ARect.aidl index 1b13761392..5785907a9c 100644 --- a/libs/gui/aidl/android/gui/Rect.aidl +++ b/libs/gui/aidl/android/gui/ARect.aidl @@ -20,7 +20,7 @@ package android.gui; // TODO(b/221473398): // use hardware/interfaces/graphics/common/aidl/android/hardware/graphics/common/Rect.aidl /** @hide */ -parcelable Rect { +parcelable ARect { /// Minimum X coordinate of the rectangle. int left; diff --git a/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl b/libs/gui/aidl/android/gui/Color.aidl index e30e9072fc..12af066562 100644 --- a/libs/binder/aidl/android/content/pm/PackageChangeEvent.aidl +++ b/libs/gui/aidl/android/gui/Color.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright 2022 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. @@ -14,19 +14,12 @@ * limitations under the License. */ -package android.content.pm; +package android.gui; -/** - * This event is designed for notification to native code listener about - * any changes on a package including update, deletion and etc. - * - * @hide - */ -parcelable PackageChangeEvent { - @utf8InCpp String packageName; - long version; - long lastUpdateTimeMillis; - boolean newInstalled; - boolean dataRemoved; - boolean isDeleted; +/** @hide */ +parcelable Color { + float r; + float g; + float b; + float a; } diff --git a/libs/gui/aidl/android/gui/CompositionPreference.aidl b/libs/gui/aidl/android/gui/CompositionPreference.aidl new file mode 100644 index 0000000000..b615824a7d --- /dev/null +++ b/libs/gui/aidl/android/gui/CompositionPreference.aidl @@ -0,0 +1,25 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +/** @hide */ +parcelable CompositionPreference { + int /*ui::Dataspace*/ defaultDataspace; + int /*ui::PixelFormat*/ defaultPixelFormat; + int /*ui::Dataspace*/ wideColorGamutDataspace; + int /*ui::PixelFormat*/ wideColorGamutPixelFormat; +} diff --git a/libs/gui/aidl/android/gui/ContentSamplingAttributes.aidl b/libs/gui/aidl/android/gui/ContentSamplingAttributes.aidl new file mode 100644 index 0000000000..5d913b1da6 --- /dev/null +++ b/libs/gui/aidl/android/gui/ContentSamplingAttributes.aidl @@ -0,0 +1,24 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +/** @hide */ +parcelable ContentSamplingAttributes { + int /*ui::PixelFormat*/ format; + int /*ui::Dataspace*/ dataspace; + byte componentMask; +} diff --git a/libs/gui/aidl/android/gui/CreateSurfaceResult.aidl b/libs/gui/aidl/android/gui/CreateSurfaceResult.aidl new file mode 100644 index 0000000000..39e49167aa --- /dev/null +++ b/libs/gui/aidl/android/gui/CreateSurfaceResult.aidl @@ -0,0 +1,24 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +/** @hide */ +parcelable CreateSurfaceResult { + IBinder handle; + int layerId; + int transformHint; +} diff --git a/libs/gui/aidl/android/gui/DeviceProductInfo.aidl b/libs/gui/aidl/android/gui/DeviceProductInfo.aidl new file mode 100644 index 0000000000..98404cf0fd --- /dev/null +++ b/libs/gui/aidl/android/gui/DeviceProductInfo.aidl @@ -0,0 +1,58 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +// Product-specific information about the display or the directly connected device on the +// display chain. For example, if the display is transitively connected, this field may contain +// product information about the intermediate device. + +/** @hide */ +parcelable DeviceProductInfo { + parcelable ModelYear { + int year; + } + + parcelable ManufactureYear { + ModelYear modelYear; + } + + parcelable ManufactureWeekAndYear { + ManufactureYear manufactureYear; + + // 1-base week number. Week numbering may not be consistent between manufacturers. + int week; + } + + union ManufactureOrModelDate { + ModelYear modelYear; + ManufactureYear manufactureYear; + ManufactureWeekAndYear manufactureWeekAndYear; + } + + // Display name. + @utf8InCpp String name; + + // NULL-terminated Manufacturer plug and play ID. + byte[] manufacturerPnpId; + + // Manufacturer product ID. + @utf8InCpp String productId; + + ManufactureOrModelDate manufactureOrModelDate; + + byte[] relativeAddress; +} diff --git a/libs/gui/aidl/android/gui/DisplayConnectionType.aidl b/libs/gui/aidl/android/gui/DisplayConnectionType.aidl new file mode 100644 index 0000000000..72c4ede7ac --- /dev/null +++ b/libs/gui/aidl/android/gui/DisplayConnectionType.aidl @@ -0,0 +1,24 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +/** @hide */ +@Backing(type="int") +enum DisplayConnectionType { + Internal = 0, + External = 1 +} diff --git a/libs/input/android/os/BlockUntrustedTouchesMode.aidl b/libs/gui/aidl/android/gui/DisplayDecorationSupport.aidl index 9504e993f8..023049657b 100644 --- a/libs/input/android/os/BlockUntrustedTouchesMode.aidl +++ b/libs/gui/aidl/android/gui/DisplayDecorationSupport.aidl @@ -1,5 +1,5 @@ /** - * Copyright (c) 2020, The Android Open Source Project + * Copyright (c) 2022, 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. @@ -14,22 +14,12 @@ * limitations under the License. */ -package android.os; +package android.gui; - -/** - * Block untrusted touches feature mode. - * - * @hide - */ -@Backing(type="int") -enum BlockUntrustedTouchesMode { - /** Feature is off. */ - DISABLED, - - /** Untrusted touches are flagged but not blocked. */ - PERMISSIVE, - - /** Untrusted touches are blocked. */ - BLOCK +// TODO(b/222607970): +// remove this aidl and use android.hardware.graphics.common.DisplayDecorationSupport +/** @hide */ +parcelable DisplayDecorationSupport { + int format; + int alphaInterpretation; } diff --git a/libs/gui/aidl/android/gui/DisplayMode.aidl b/libs/gui/aidl/android/gui/DisplayMode.aidl new file mode 100644 index 0000000000..3cd77f82d7 --- /dev/null +++ b/libs/gui/aidl/android/gui/DisplayMode.aidl @@ -0,0 +1,36 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +import android.gui.Size; + +// Mode supported by physical display. +// Make sure to sync with libui DisplayMode.h + +/** @hide */ +parcelable DisplayMode { + int id; + Size resolution; + float xDpi = 0.0f; + float yDpi = 0.0f; + + float refreshRate = 0.0f; + long appVsyncOffset = 0; + long sfVsyncOffset = 0; + long presentationDeadline = 0; + int group = -1; +} diff --git a/libs/gui/aidl/android/gui/DisplayModeSpecs.aidl b/libs/gui/aidl/android/gui/DisplayModeSpecs.aidl new file mode 100644 index 0000000000..fb4fcdf8e8 --- /dev/null +++ b/libs/gui/aidl/android/gui/DisplayModeSpecs.aidl @@ -0,0 +1,27 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +/** @hide */ +parcelable DisplayModeSpecs { + int defaultMode; + boolean allowGroupSwitching; + float primaryRefreshRateMin; + float primaryRefreshRateMax; + float appRequestRefreshRateMin; + float appRequestRefreshRateMax; +} diff --git a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl b/libs/gui/aidl/android/gui/DisplayPrimaries.aidl index 6929a6cb49..dbf668c629 100644 --- a/libs/binder/aidl/android/content/pm/IPackageChangeObserver.aidl +++ b/libs/gui/aidl/android/gui/DisplayPrimaries.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright 2022 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. @@ -14,15 +14,20 @@ * limitations under the License. */ -package android.content.pm; +package android.gui; -import android.content.pm.PackageChangeEvent; +// copied from libui ConfigStoreTypes.h -/** - * This is a non-blocking notification when a package has changed. - * - * @hide - */ -oneway interface IPackageChangeObserver { - void onPackageChanged(in PackageChangeEvent event); +/** @hide */ +parcelable DisplayPrimaries { + parcelable CieXyz { + float X; + float Y; + float Z; + } + + CieXyz red; + CieXyz green; + CieXyz blue; + CieXyz white; } diff --git a/libs/gui/aidl/android/gui/DisplayedFrameStats.aidl b/libs/gui/aidl/android/gui/DisplayedFrameStats.aidl new file mode 100644 index 0000000000..f4b6dadc49 --- /dev/null +++ b/libs/gui/aidl/android/gui/DisplayedFrameStats.aidl @@ -0,0 +1,40 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +/** @hide */ +parcelable DisplayedFrameStats { + /* The number of frames represented by this sample. */ + long numFrames = 0; + + /* A histogram counting how many times a pixel of a given value was displayed onscreen for + * FORMAT_COMPONENT_0. The buckets of the histogram are evenly weighted, the number of buckets + * is device specific. eg, for RGBA_8888, if sampleComponent0 is {10, 6, 4, 1} this means that + * 10 red pixels were displayed onscreen in range 0x00->0x3F, 6 red pixels + * were displayed onscreen in range 0x40->0x7F, etc. + */ + long[] component_0_sample; + + /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_1. */ + long[] component_1_sample; + + /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_2. */ + long[] component_2_sample; + + /* The same sample definition as sampleComponent0, but for FORMAT_COMPONENT_3. */ + long[] component_3_sample; +} diff --git a/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl new file mode 100644 index 0000000000..57e6081e27 --- /dev/null +++ b/libs/gui/aidl/android/gui/DynamicDisplayInfo.aidl @@ -0,0 +1,45 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +import android.gui.DisplayMode; +import android.gui.HdrCapabilities; + +// Information about a physical display which may change on hotplug reconnect. +// Make sure to sync with libui DynamicDisplayInfo.h + +/** @hide */ +parcelable DynamicDisplayInfo { + List<DisplayMode> supportedDisplayModes; + + int activeDisplayModeId; + + int[] supportedColorModes; + int activeColorMode; + HdrCapabilities hdrCapabilities; + + // True if the display reports support for HDMI 2.1 Auto Low Latency Mode. + // For more information, see the HDMI 2.1 specification. + boolean autoLowLatencyModeSupported; + + // True if the display reports support for Game Content Type. + // For more information, see the HDMI 1.4 specification. + boolean gameContentTypeSupported; + + // The boot display mode preferred by the implementation. + int preferredBootDisplayMode; +} diff --git a/libs/gui/aidl/android/gui/FrameEvent.aidl b/libs/gui/aidl/android/gui/FrameEvent.aidl new file mode 100644 index 0000000000..aaabdb5b54 --- /dev/null +++ b/libs/gui/aidl/android/gui/FrameEvent.aidl @@ -0,0 +1,35 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +// Identifiers for all the events that may be recorded or reported. + +/** @hide */ +@Backing(type="int") +enum FrameEvent { + POSTED = 0, + REQUESTED_PRESENT = 1, + LATCH = 2, + ACQUIRE = 3, + FIRST_REFRESH_START = 4, + LAST_REFRESH_START = 5, + GPU_COMPOSITION_DONE = 6, + DISPLAY_PRESENT = 7, + DEQUEUE_READY = 8, + RELEASE = 9, + EVENT_COUNT = 10 // Not an actual event. +} diff --git a/libs/gui/aidl/android/gui/FrameStats.aidl b/libs/gui/aidl/android/gui/FrameStats.aidl new file mode 100644 index 0000000000..a145e74b11 --- /dev/null +++ b/libs/gui/aidl/android/gui/FrameStats.aidl @@ -0,0 +1,47 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +// Make sure to sync with libui FrameStats.h + +/** @hide */ +parcelable FrameStats { + /* + * Approximate refresh time, in nanoseconds. + */ + long refreshPeriodNano; + + /* + * The times in nanoseconds for when the frame contents were posted by the producer (e.g. + * the application). They are either explicitly set or defaulted to the time when + * Surface::queueBuffer() was called. + */ + long[] desiredPresentTimesNano; + + /* + * The times in milliseconds for when the frame contents were presented on the screen. + */ + long[] actualPresentTimesNano; + + /* + * The times in nanoseconds for when the frame contents were ready to be presented. Note that + * a frame can be posted and still it contents being rendered asynchronously in GL. In such a + * case these are the times when the frame contents were completely rendered (i.e. their fences + * signaled). + */ + long[] frameReadyTimesNano; +} diff --git a/libs/gui/include/gui/FrameTimelineInfo.h b/libs/gui/aidl/android/gui/FrameTimelineInfo.aidl index 255ce568d2..6ffe466f20 100644 --- a/libs/gui/include/gui/FrameTimelineInfo.h +++ b/libs/gui/aidl/android/gui/FrameTimelineInfo.aidl @@ -1,5 +1,5 @@ /* - * Copyright 2021 The Android Open Source Project + * Copyright 2022 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. @@ -14,36 +14,23 @@ * limitations under the License. */ -#pragma once +package android.gui; -#include <stdint.h> - -#include <binder/Parcel.h> - -namespace android { - -struct FrameTimelineInfo { +/** @hide */ +parcelable FrameTimelineInfo { // Needs to be in sync with android.graphics.FrameInfo.INVALID_VSYNC_ID in java - static constexpr int64_t INVALID_VSYNC_ID = -1; + const long INVALID_VSYNC_ID = -1; // The vsync id that was used to start the transaction - int64_t vsyncId = INVALID_VSYNC_ID; + long vsyncId = INVALID_VSYNC_ID; // The id of the input event that caused this buffer // Default is android::os::IInputConstants::INVALID_INPUT_EVENT_ID = 0 // We copy the value of the input event ID instead of including the header, because libgui // header libraries containing FrameTimelineInfo must be available to vendors, but libinput is // not directly vendor available. - int32_t inputEventId = 0; + int inputEventId = 0; // The current time in nanoseconds the application started to render the frame. - int64_t startTimeNanos = 0; - - status_t write(Parcel& output) const; - status_t read(const Parcel& input); - - void merge(const FrameTimelineInfo& other); - void clear(); -}; - -} // namespace android + long startTimeNanos = 0; +} diff --git a/libs/gui/aidl/android/gui/HdrCapabilities.aidl b/libs/gui/aidl/android/gui/HdrCapabilities.aidl new file mode 100644 index 0000000000..9d06da9f27 --- /dev/null +++ b/libs/gui/aidl/android/gui/HdrCapabilities.aidl @@ -0,0 +1,27 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +// Make sure to sync with libui HdrCapabilities.h + +/** @hide */ +parcelable HdrCapabilities { + int[] supportedHdrTypes; + float maxLuminance; + float maxAverageLuminance; + float minLuminance; +} diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl index b31b37bada..730d758d80 100644 --- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl +++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl @@ -16,39 +16,99 @@ package android.gui; -import android.gui.DisplayCaptureArgs; +import android.gui.Color; +import android.gui.CompositionPreference; +import android.gui.ContentSamplingAttributes; import android.gui.DisplayBrightness; +import android.gui.DisplayCaptureArgs; +import android.gui.DisplayDecorationSupport; +import android.gui.DisplayedFrameStats; +import android.gui.DisplayModeSpecs; +import android.gui.DisplayPrimaries; import android.gui.DisplayState; import android.gui.DisplayStatInfo; +import android.gui.DynamicDisplayInfo; +import android.gui.FrameEvent; +import android.gui.FrameStats; +import android.gui.IDisplayEventConnection; +import android.gui.IFpsListener; import android.gui.IHdrLayerInfoListener; -import android.gui.LayerCaptureArgs; +import android.gui.IRegionSamplingListener; import android.gui.IScreenCaptureListener; +import android.gui.ISurfaceComposerClient; +import android.gui.ITransactionTraceListener; +import android.gui.ITunnelModeEnabledListener; +import android.gui.IWindowInfosListener; +import android.gui.LayerCaptureArgs; +import android.gui.LayerDebugInfo; +import android.gui.PullAtomData; +import android.gui.ARect; +import android.gui.StaticDisplayInfo; /** @hide */ interface ISurfaceComposer { - /* create a virtual display + enum VsyncSource { + eVsyncSourceApp = 0, + eVsyncSourceSurfaceFlinger = 1 + } + + enum EventRegistration { + modeChanged = 1 << 0, + frameRateOverride = 1 << 1, + } + + /** + * Signal that we're done booting. + * Requires ACCESS_SURFACE_FLINGER permission + */ + // Note this must be the 1st method, so IBinder::FIRST_CALL_TRANSACTION + // is assigned, as it is called from Java by ActivityManagerService. + void bootFinished(); + + /** + * Create a display event connection + */ + @nullable IDisplayEventConnection createDisplayEventConnection(VsyncSource vsyncSource, + EventRegistration eventRegistration); + + /** + * Create a connection with SurfaceFlinger. + */ + @nullable ISurfaceComposerClient createConnection(); + + /** + * Create a virtual display * requires ACCESS_SURFACE_FLINGER permission. */ @nullable IBinder createDisplay(@utf8InCpp String displayName, boolean secure); - /* destroy a virtual display + /** + * Destroy a virtual display * requires ACCESS_SURFACE_FLINGER permission. */ void destroyDisplay(IBinder display); - /* get stable IDs for connected physical displays. + /** + * Get stable IDs for connected physical displays. */ long[] getPhysicalDisplayIds(); long getPrimaryPhysicalDisplayId(); - /* get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or a - * DisplayEventReceiver hotplug event. + /** + * Get token for a physical display given its stable ID obtained via getPhysicalDisplayIds or + * a DisplayEventReceiver hotplug event. */ @nullable IBinder getPhysicalDisplayToken(long displayId); - /* set display power mode. depending on the mode, it can either trigger + /** + * Returns the frame timestamps supported by SurfaceFlinger. + */ + FrameEvent[] getSupportedFrameTimestamps(); + + /** + * Set display power mode. depending on the mode, it can either trigger * screen on, off or low power mode and wait for it to complete. * requires ACCESS_SURFACE_FLINGER permission. */ @@ -60,12 +120,31 @@ interface ISurfaceComposer { * video frames */ DisplayStatInfo getDisplayStats(@nullable IBinder display); - /** + /** * Get transactional state of given display. */ DisplayState getDisplayState(IBinder display); /** + * Gets immutable information about given physical display. + */ + StaticDisplayInfo getStaticDisplayInfo(IBinder display); + + /** + * Gets dynamic information about given physical display. + */ + DynamicDisplayInfo getDynamicDisplayInfo(IBinder display); + + DisplayPrimaries getDisplayNativePrimaries(IBinder display); + + void setActiveColorMode(IBinder display, int colorMode); + + /** + * Sets the user-preferred display mode that a device should boot in. + */ + void setBootDisplayMode(IBinder display, int displayModeId); + + /** * Clears the user-preferred display mode. The device should now boot in system preferred * display mode. */ @@ -110,7 +189,9 @@ interface ISurfaceComposer { * match the size of the output buffer. */ void captureDisplay(in DisplayCaptureArgs args, IScreenCaptureListener listener); + void captureDisplayById(long displayId, IScreenCaptureListener listener); + /** * Capture a subtree of the layer hierarchy, potentially ignoring the root node. * This requires READ_FRAME_BUFFER permission. This function will fail if there @@ -118,13 +199,163 @@ interface ISurfaceComposer { */ void captureLayers(in LayerCaptureArgs args, IScreenCaptureListener listener); - /* + /** + * Clears the frame statistics for animations. + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + void clearAnimationFrameStats(); + + /** + * Gets the frame statistics for animations. + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + FrameStats getAnimationFrameStats(); + + /** + * Overrides the supported HDR modes for the given display device. + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + void overrideHdrTypes(IBinder display, in int[] hdrTypes); + + /** + * Pulls surfaceflinger atoms global stats and layer stats to pipe to statsd. + * + * Requires the calling uid be from system server. + */ + PullAtomData onPullAtom(int atomId); + + oneway void enableVSyncInjections(boolean enable); + + oneway void injectVSync(long when); + + /** + * Gets the list of active layers in Z order for debugging purposes + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + List<LayerDebugInfo> getLayerDebugInfo(); + + boolean getColorManagement(); + + /** + * Gets the composition preference of the default data space and default pixel format, + * as well as the wide color gamut data space and wide color gamut pixel format. + * If the wide color gamut data space is V0_SRGB, then it implies that the platform + * has no wide color gamut support. + * + */ + CompositionPreference getCompositionPreference(); + + /** + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + ContentSamplingAttributes getDisplayedContentSamplingAttributes(IBinder display); + + /** + * Turns on the color sampling engine on the display. + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + void setDisplayContentSamplingEnabled(IBinder display, boolean enable, byte componentMask, long maxFrames); + + /** + * Returns statistics on the color profile of the last frame displayed for a given display + * + * Requires the ACCESS_SURFACE_FLINGER permission. + */ + DisplayedFrameStats getDisplayedContentSample(IBinder display, long maxFrames, long timestamp); + + /** + * Gets whether SurfaceFlinger can support protected content in GPU composition. + */ + boolean getProtectedContentSupport(); + + /** * Queries whether the given display is a wide color display. * Requires the ACCESS_SURFACE_FLINGER permission. */ boolean isWideColorDisplay(IBinder token); - /* + /** + * Registers a listener to stream median luma updates from SurfaceFlinger. + * + * The sampling area is bounded by both samplingArea and the given stopLayerHandle + * (i.e., only layers behind the stop layer will be captured and sampled). + * + * Multiple listeners may be provided so long as they have independent listeners. + * If multiple listeners are provided, the effective sampling region for each listener will + * be bounded by whichever stop layer has a lower Z value. + * + * Requires the same permissions as captureLayers and captureScreen. + */ + void addRegionSamplingListener(in ARect samplingArea, @nullable IBinder stopLayerHandle, IRegionSamplingListener listener); + + /** + * Removes a listener that was streaming median luma updates from SurfaceFlinger. + */ + void removeRegionSamplingListener(IRegionSamplingListener listener); + + /** + * Registers a listener that streams fps updates from SurfaceFlinger. + * + * The listener will stream fps updates for the layer tree rooted at the layer denoted by the + * task ID, i.e., the layer must have the task ID as part of its layer metadata with key + * METADATA_TASK_ID. If there is no such layer, then no fps is expected to be reported. + * + * Multiple listeners may be supported. + * + * Requires the READ_FRAME_BUFFER permission. + */ + void addFpsListener(int taskId, IFpsListener listener); + + /** + * Removes a listener that was streaming fps updates from SurfaceFlinger. + */ + void removeFpsListener(IFpsListener listener); + + /** + * Registers a listener to receive tunnel mode enabled updates from SurfaceFlinger. + * + * Requires ACCESS_SURFACE_FLINGER permission. + */ + void addTunnelModeEnabledListener(ITunnelModeEnabledListener listener); + + /** + * Removes a listener that was receiving tunnel mode enabled updates from SurfaceFlinger. + * + * Requires ACCESS_SURFACE_FLINGER permission. + */ + void removeTunnelModeEnabledListener(ITunnelModeEnabledListener listener); + + /** + * Sets the refresh rate boundaries for the display. + * + * The primary refresh rate range represents display manager's general guidance on the display + * modes we'll consider when switching refresh rates. Unless we get an explicit signal from an + * app, we should stay within this range. + * + * The app request refresh rate range allows us to consider more display modes when switching + * refresh rates. Although we should generally stay within the primary range, specific + * considerations, such as layer frame rate settings specified via the setFrameRate() api, may + * cause us to go outside the primary range. We never go outside the app request range. The app + * request range will be greater than or equal to the primary refresh rate range, never smaller. + * + * defaultMode is used to narrow the list of display modes SurfaceFlinger will consider + * switching between. Only modes with a mode group and resolution matching defaultMode + * will be considered for switching. The defaultMode corresponds to an ID of mode in the list + * of supported modes returned from getDynamicDisplayInfo(). + */ + void setDesiredDisplayModeSpecs( + IBinder displayToken, int defaultMode, + boolean allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax, + float appRequestRefreshRateMin, float appRequestRefreshRateMax); + + DisplayModeSpecs getDesiredDisplayModeSpecs(IBinder displayToken); + + /** * Gets whether brightness operations are supported on a display. * * displayToken @@ -138,7 +369,7 @@ interface ISurfaceComposer { */ boolean getDisplayBrightnessSupport(IBinder displayToken); - /* + /** * Sets the brightness of a display. * * displayToken @@ -153,7 +384,7 @@ interface ISurfaceComposer { */ void setDisplayBrightness(IBinder displayToken, in DisplayBrightness brightness); - /* + /** * Adds a listener that receives HDR layer information. This is used in combination * with setDisplayBrightness to adjust the display brightness depending on factors such * as whether or not HDR is in use. @@ -162,7 +393,7 @@ interface ISurfaceComposer { */ void addHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener); - /* + /** * Removes a listener that was added with addHdrLayerInfoListener. * * Returns NO_ERROR upon success, NAME_NOT_FOUND if the display is invalid, and BAD_VALUE if @@ -171,7 +402,7 @@ interface ISurfaceComposer { */ void removeHdrLayerInfoListener(IBinder displayToken, IHdrLayerInfoListener listener); - /* + /** * Sends a power boost to the composer. This function is asynchronous. * * boostId @@ -179,5 +410,78 @@ interface ISurfaceComposer { * * Returns NO_ERROR upon success. */ - void notifyPowerBoost(int boostId); + oneway void notifyPowerBoost(int boostId); + + /* + * Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows + * material design guidelines. + * + * ambientColor + * Color to the ambient shadow. The alpha is premultiplied. + * + * spotColor + * Color to the spot shadow. The alpha is premultiplied. The position of the spot shadow + * depends on the light position. + * + * lightPosY/lightPosZ + * Position of the light used to cast the spot shadow. The X value is always the display + * width / 2. + * + * lightRadius + * Radius of the light casting the shadow. + */ + oneway void setGlobalShadowSettings(in Color ambientColor, in Color spotColor, float lightPosY, float lightPosZ, float lightRadius); + + /** + * Gets whether a display supports DISPLAY_DECORATION layers. + * + * displayToken + * The token of the display. + * outSupport + * An output parameter for whether/how the display supports + * DISPLAY_DECORATION layers. + * + * Returns NO_ERROR upon success. Otherwise, + * NAME_NOT_FOUND if the display is invalid, or + * BAD_VALUE if the output parameter is invalid. + */ + @nullable DisplayDecorationSupport getDisplayDecorationSupport(IBinder displayToken); + + /** + * Set the override frame rate for a specified uid by GameManagerService. + * Passing the frame rate and uid to SurfaceFlinger to update the override mapping + * in the scheduler. + */ + void setOverrideFrameRate(int uid, float frameRate); + + /** + * Adds a TransactionTraceListener to listen for transaction tracing state updates. + */ + void addTransactionTraceListener(ITransactionTraceListener listener); + + /** + * Gets priority of the RenderEngine in SurfaceFlinger. + */ + int getGpuContextPriority(); + + /** + * Gets the number of buffers SurfaceFlinger would need acquire. This number + * would be propagated to the client via MIN_UNDEQUEUED_BUFFERS so that the + * client could allocate enough buffers to match SF expectations of the + * pipeline depth. SurfaceFlinger will make sure that it will give the app at + * least the time configured as the 'appDuration' before trying to latch + * the buffer. + * + * The total buffers needed for a given configuration is basically the + * numbers of vsyncs a single buffer is used across the stack. For the default + * configuration a buffer is held ~1 vsync by the app, ~1 vsync by SurfaceFlinger + * and 1 vsync by the display. The extra buffers are calculated as the + * number of additional buffers on top of the 2 buffers already present + * in MIN_UNDEQUEUED_BUFFERS. + */ + int getMaxAcquiredBufferCount(); + + void addWindowInfosListener(IWindowInfosListener windowInfosListener); + + void removeWindowInfosListener(IWindowInfosListener windowInfosListener); } diff --git a/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl b/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl new file mode 100644 index 0000000000..71933aa6ff --- /dev/null +++ b/libs/gui/aidl/android/gui/ISurfaceComposerClient.aidl @@ -0,0 +1,62 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +import android.gui.CreateSurfaceResult; +import android.gui.FrameStats; +import android.gui.LayerMetadata; +import android.gui.MirrorSurfaceResult; + +/** @hide */ +interface ISurfaceComposerClient { + + // flags for createSurface() + // (keep in sync with SurfaceControl.java) + const int eHidden = 0x00000004; + const int eDestroyBackbuffer = 0x00000020; + const int eSkipScreenshot = 0x00000040; + const int eSecure = 0x00000080; + const int eNonPremultiplied = 0x00000100; + const int eOpaque = 0x00000400; + const int eProtectedByApp = 0x00000800; + const int eProtectedByDRM = 0x00001000; + const int eCursorWindow = 0x00002000; + const int eNoColorFill = 0x00004000; + + const int eFXSurfaceBufferQueue = 0x00000000; + const int eFXSurfaceEffect = 0x00020000; + const int eFXSurfaceBufferState = 0x00040000; + const int eFXSurfaceContainer = 0x00080000; + const int eFXSurfaceMask = 0x000F0000; + + /** + * Requires ACCESS_SURFACE_FLINGER permission + */ + CreateSurfaceResult createSurface(@utf8InCpp String name, int flags, @nullable IBinder parent, in LayerMetadata metadata); + + /** + * Requires ACCESS_SURFACE_FLINGER permission + */ + void clearLayerFrameStats(IBinder handle); + + /** + * Requires ACCESS_SURFACE_FLINGER permission + */ + FrameStats getLayerFrameStats(IBinder handle); + + MirrorSurfaceResult mirrorSurface(IBinder mirrorFromHandle); +} diff --git a/libs/gui/aidl/android/gui/LayerDebugInfo.aidl b/libs/gui/aidl/android/gui/LayerDebugInfo.aidl new file mode 100644 index 0000000000..faca980f3c --- /dev/null +++ b/libs/gui/aidl/android/gui/LayerDebugInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +parcelable LayerDebugInfo cpp_header "gui/LayerDebugInfo.h"; diff --git a/libs/gui/aidl/android/gui/LayerMetadata.aidl b/libs/gui/aidl/android/gui/LayerMetadata.aidl new file mode 100644 index 0000000000..1368ac512f --- /dev/null +++ b/libs/gui/aidl/android/gui/LayerMetadata.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +parcelable LayerMetadata cpp_header "gui/LayerMetadata.h"; diff --git a/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl b/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl new file mode 100644 index 0000000000..9fac3e8644 --- /dev/null +++ b/libs/gui/aidl/android/gui/MirrorSurfaceResult.aidl @@ -0,0 +1,23 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +/** @hide */ +parcelable MirrorSurfaceResult { + IBinder handle; + int layerId; +} diff --git a/libs/gui/aidl/android/gui/PullAtomData.aidl b/libs/gui/aidl/android/gui/PullAtomData.aidl new file mode 100644 index 0000000000..14d33c6d0b --- /dev/null +++ b/libs/gui/aidl/android/gui/PullAtomData.aidl @@ -0,0 +1,23 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +/** @hide */ +parcelable PullAtomData { + @utf8InCpp String data; + boolean success; +} diff --git a/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl b/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl new file mode 100644 index 0000000000..0ccda56ef5 --- /dev/null +++ b/libs/gui/aidl/android/gui/StaticDisplayInfo.aidl @@ -0,0 +1,30 @@ +/* + * Copyright 2022 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. + */ + +package android.gui; + +import android.gui.DisplayConnectionType; +import android.gui.DeviceProductInfo; +import android.gui.Rotation; + +/** @hide */ +parcelable StaticDisplayInfo { + DisplayConnectionType connectionType = DisplayConnectionType.Internal; + float density; + boolean secure; + @nullable DeviceProductInfo deviceProductInfo; + Rotation installOrientation = Rotation.Rotation0; +} diff --git a/libs/gui/fuzzer/Android.bp b/libs/gui/fuzzer/Android.bp new file mode 100644 index 0000000000..f1c529d614 --- /dev/null +++ b/libs/gui/fuzzer/Android.bp @@ -0,0 +1,87 @@ +/* + * Copyright 2021 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. + */ +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_defaults { + name: "libgui_fuzzer_defaults", + static_libs: [ + "android.hidl.token@1.0-utils", + "libbinder_random_parcel", + "libgui_aidl_static", + "libgui_window_info_static", + "libpdx", + "libgmock", + "libgui_mocks", + "libgmock_ndk", + "libgmock_main", + "libgtest_ndk_c++", + "libgmock_main_ndk", + "librenderengine_mocks", + "perfetto_trace_protos", + "libcompositionengine_mocks", + "perfetto_trace_protos", + ], + shared_libs: [ + "android.hardware.configstore@1.0", + "android.hardware.configstore-utils", + "android.hardware.graphics.bufferqueue@1.0", + "android.hardware.graphics.bufferqueue@2.0", + "android.hardware.power-V2-cpp", + "android.hidl.token@1.0", + "libSurfaceFlingerProp", + "libgui", + "libbase", + "liblog", + "libEGL", + "libGLESv2", + "libbinder", + "libcutils", + "libhidlbase", + "libinput", + "libui", + "libutils", + "libnativewindow", + "libvndksupport", + "libbufferhubqueue", + ], + header_libs: [ + "libdvr_headers", + "libui_fuzzableDataspaces_headers", + ], + fuzz_config: { + cc: [ + "android-media-fuzzing-reports@google.com", + ], + componentid: 155276, + }, +} + +cc_fuzz { + name: "libgui_surfaceComposer_fuzzer", + srcs: [ + "libgui_surfaceComposer_fuzzer.cpp", + ], + defaults: [ + "libgui_fuzzer_defaults", + ], +} diff --git a/libs/gui/fuzzer/README.md b/libs/gui/fuzzer/README.md new file mode 100644 index 0000000000..c9e8b653ee --- /dev/null +++ b/libs/gui/fuzzer/README.md @@ -0,0 +1,42 @@ +# Fuzzers for Libgui + +## Table of contents ++ [libgui_surfaceComposer_fuzzer](#SurfaceComposer) + +# <a name="libgui_surfaceComposer_fuzzer"></a> Fuzzer for SurfaceComposer + +SurfaceComposer supports the following parameters: +1. SurfaceWidth (parameter name:`width`) +2. SurfaceHeight (parameter name:`height`) +3. TransactionStateFlags (parameter name:`flags`) +4. TransformHint (parameter name:`outTransformHint`) +5. SurfacePixelFormat (parameter name:`format`) +6. LayerId (parameter name:`outLayerId`) +7. SurfaceComposerTags (parameter name:`surfaceTag`) +8. PowerBoostID (parameter name:`boostId`) +9. VsyncSource (parameter name:`vsyncSource`) +10. EventRegistrationFlags (parameter name:`eventRegistration`) +11. FrameRateCompatibility (parameter name:`frameRateCompatibility`) +12. ChangeFrameRateStrategy (parameter name:`changeFrameRateStrategy`) +13. HdrTypes (parameter name:`hdrTypes`) + +| Parameter| Valid Values| Configured Value| +|------------- |-------------| ----- | +|`surfaceTag` | 0.`BnSurfaceComposer::BOOT_FINISHED`, 1.`BnSurfaceComposer::CREATE_CONNECTION`, 2.`BnSurfaceComposer::GET_STATIC_DISPLAY_INFO`, 3.`BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION`, 4.`BnSurfaceComposer::CREATE_DISPLAY`, 5.`BnSurfaceComposer::DESTROY_DISPLAY`, 6.`BnSurfaceComposer::GET_PHYSICAL_DISPLAY_TOKEN`, 7.`BnSurfaceComposer::SET_TRANSACTION_STATE`, 8.`BnSurfaceComposer::AUTHENTICATE_SURFACE`, 9.`BnSurfaceComposer::GET_SUPPORTED_FRAME_TIMESTAMPS`, 10.`BnSurfaceComposer::GET_DISPLAY_STATE`, 11.`BnSurfaceComposer::CAPTURE_DISPLAY`, 12.`BnSurfaceComposer::CAPTURE_LAYERS`, 13.`BnSurfaceComposer::CLEAR_ANIMATION_FRAME_STATS`, 14.`BnSurfaceComposer::GET_ANIMATION_FRAME_STATS`, 15.`BnSurfaceComposer::SET_POWER_MODE`, 16.`BnSurfaceComposer::GET_DISPLAY_STATS`, 17.`BnSurfaceComposer::SET_ACTIVE_COLOR_MODE`, 18.`BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS`, 19.`BnSurfaceComposer::INJECT_VSYNC`, 20.`BnSurfaceComposer::GET_LAYER_DEBUG_INFO`, 21.`BnSurfaceComposer::GET_COMPOSITION_PREFERENCE`, 22.`BnSurfaceComposer::GET_COLOR_MANAGEMENT`, 23.`BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES`, 24.`BnSurfaceComposer::SET_DISPLAY_CONTENT_SAMPLING_ENABLED`, 25.`BnSurfaceComposer::GET_DISPLAYED_CONTENT_SAMPLE`, 26.`BnSurfaceComposer::GET_PROTECTED_CONTENT_SUPPORT`, 27.`BnSurfaceComposer::IS_WIDE_COLOR_DISPLAY`, 28.`BnSurfaceComposer::GET_DISPLAY_NATIVE_PRIMARIES`, 29.`BnSurfaceComposer::GET_PHYSICAL_DISPLAY_IDS`, 30.`BnSurfaceComposer::ADD_REGION_SAMPLING_LISTENER`, 31.`BnSurfaceComposer::REMOVE_REGION_SAMPLING_LISTENER`, 32.`BnSurfaceComposer::SET_DESIRED_DISPLAY_MODE_SPECS`, 33.`BnSurfaceComposer::GET_DESIRED_DISPLAY_MODE_SPECS`, 34.`BnSurfaceComposer::GET_DISPLAY_BRIGHTNESS_SUPPORT`, 35.`BnSurfaceComposer::SET_DISPLAY_BRIGHTNESS`, 36.`BnSurfaceComposer::CAPTURE_DISPLAY_BY_ID`, 37.`BnSurfaceComposer::NOTIFY_POWER_BOOST`, 38.`BnSurfaceComposer::SET_GLOBAL_SHADOW_SETTINGS`, 39.`BnSurfaceComposer::SET_AUTO_LOW_LATENCY_MODE`, 40.`BnSurfaceComposer::SET_GAME_CONTENT_TYPE`, 41.`BnSurfaceComposer::SET_FRAME_RATE`, 42.`BnSurfaceComposer::ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN`, 43.`BnSurfaceComposer::SET_FRAME_TIMELINE_INFO`, 44.`BnSurfaceComposer::ADD_TRANSACTION_TRACE_LISTENER`, 45.`BnSurfaceComposer::GET_GPU_CONTEXT_PRIORITY`, 46.`BnSurfaceComposer::GET_MAX_ACQUIRED_BUFFER_COUNT`, 47.`BnSurfaceComposer::GET_DYNAMIC_DISPLAY_INFO`, 48.`BnSurfaceComposer::ADD_FPS_LISTENER`, 49.`BnSurfaceComposer::REMOVE_FPS_LISTENER`, 50.`BnSurfaceComposer::OVERRIDE_HDR_TYPES`, 51.`BnSurfaceComposer::ADD_HDR_LAYER_INFO_LISTENER`, 52.`BnSurfaceComposer::REMOVE_HDR_LAYER_INFO_LISTENER`, 53.`BnSurfaceComposer::ON_PULL_ATOM`, 54.`BnSurfaceComposer::ADD_TUNNEL_MODE_ENABLED_LISTENER`, 55.`BnSurfaceComposer::REMOVE_TUNNEL_MODE_ENABLED_LISTENER` | Value obtained from FuzzedDataProvider| +|`boostId`| 0.`hardware::power::Boost::INTERACTION`, 1.`hardware::power::Boost::DISPLAY_UPDATE_IMMINENT`, 2.`hardware::power::Boost::ML_ACC`, 3.`hardware::power::Boost::AUDIO_LAUNCH`, 4.`hardware::power::Boost::CAMERA_LAUNCH`, 5.`hardware::power::Boost::CAMERA_SHOT` |Value obtained from FuzzedDataProvider| +|`vsyncSource`| 0.`ISurfaceComposer::eVsyncSourceApp`, 1.`ISurfaceComposer::eVsyncSourceSurfaceFlinger`, |Value obtained from FuzzedDataProvider| +|`eventRegistration`| 0.`ISurfaceComposer::EventRegistration::modeChanged`, 1.`ISurfaceComposer::EventRegistration::frameRateOverride` |Value obtained from FuzzedDataProvider| +|`frameRateCompatibility`| 0.`ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT`, 1.`ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE` |Value obtained from FuzzedDataProvider| +|`changeFrameRateStrategy`| 0.`ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS`, 1.`ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS` |Value obtained from FuzzedDataProvider| +|`hdrTypes`| 0.`ui::Hdr::DOLBY_VISION`, 1.`ui::Hdr::HDR10`, 2.`ui::Hdr::HLG`, 3.`ui::Hdr::HDR10_PLUS` |Value obtained from FuzzedDataProvider| + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) libgui_surfaceComposer_fuzzer +``` +2. Run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/libgui_surfaceComposer_fuzzer/libgui_surfaceComposer_fuzzer +``` diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h new file mode 100644 index 0000000000..98e2ea3c79 --- /dev/null +++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h @@ -0,0 +1,311 @@ +/* + * Copyright 2021 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 <android/gui/BnRegionSamplingListener.h> +#include <android/gui/BnSurfaceComposer.h> +#include <android/gui/BnSurfaceComposerClient.h> +#include <android/gui/IDisplayEventConnection.h> +#include <android/gui/ISurfaceComposerClient.h> +#include <fuzzer/FuzzedDataProvider.h> +#include <gmock/gmock.h> +#include <gui/BLASTBufferQueue.h> +#include <gui/DisplayEventDispatcher.h> +#include <gui/IGraphicBufferProducer.h> +#include <gui/LayerDebugInfo.h> +#include <gui/LayerState.h> +#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h> +#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h> +#include <ui/fuzzer/FuzzableDataspaces.h> + +namespace android { + +constexpr uint32_t kOrientation[] = { + ui::Transform::ROT_0, ui::Transform::FLIP_H, ui::Transform::FLIP_V, + ui::Transform::ROT_90, ui::Transform::ROT_180, ui::Transform::ROT_270, +}; + +Rect getRect(FuzzedDataProvider* fdp) { + const int32_t left = fdp->ConsumeIntegral<int32_t>(); + const int32_t top = fdp->ConsumeIntegral<int32_t>(); + const int32_t right = fdp->ConsumeIntegral<int32_t>(); + const int32_t bottom = fdp->ConsumeIntegral<int32_t>(); + return Rect(left, top, right, bottom); +} + +gui::DisplayBrightness getBrightness(FuzzedDataProvider* fdp) { + static constexpr float kMinBrightness = 0; + static constexpr float kMaxBrightness = 1; + gui::DisplayBrightness brightness; + brightness.sdrWhitePoint = + fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness); + brightness.sdrWhitePointNits = + fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness); + brightness.displayBrightness = + fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness); + brightness.displayBrightnessNits = + fdp->ConsumeFloatingPointInRange<float>(kMinBrightness, kMaxBrightness); + return brightness; +} + +class FakeBnSurfaceComposer : public gui::BnSurfaceComposer { +public: + MOCK_METHOD(binder::Status, bootFinished, (), (override)); + MOCK_METHOD(binder::Status, createDisplayEventConnection, + (gui::ISurfaceComposer::VsyncSource, gui::ISurfaceComposer::EventRegistration, + sp<gui::IDisplayEventConnection>*), + (override)); + MOCK_METHOD(binder::Status, createConnection, (sp<gui::ISurfaceComposerClient>*), (override)); + MOCK_METHOD(binder::Status, createDisplay, (const std::string&, bool, sp<IBinder>*), + (override)); + MOCK_METHOD(binder::Status, destroyDisplay, (const sp<IBinder>&), (override)); + MOCK_METHOD(binder::Status, getPhysicalDisplayIds, (std::vector<int64_t>*), (override)); + MOCK_METHOD(binder::Status, getPrimaryPhysicalDisplayId, (int64_t*), (override)); + MOCK_METHOD(binder::Status, getPhysicalDisplayToken, (int64_t, sp<IBinder>*), (override)); + MOCK_METHOD(binder::Status, setPowerMode, (const sp<IBinder>&, int), (override)); + MOCK_METHOD(binder::Status, getSupportedFrameTimestamps, (std::vector<FrameEvent>*), + (override)); + MOCK_METHOD(binder::Status, getDisplayStats, (const sp<IBinder>&, gui::DisplayStatInfo*), + (override)); + MOCK_METHOD(binder::Status, getDisplayState, (const sp<IBinder>&, gui::DisplayState*), + (override)); + MOCK_METHOD(binder::Status, getStaticDisplayInfo, (const sp<IBinder>&, gui::StaticDisplayInfo*), + (override)); + MOCK_METHOD(binder::Status, getDynamicDisplayInfo, + (const sp<IBinder>&, gui::DynamicDisplayInfo*), (override)); + MOCK_METHOD(binder::Status, getDisplayNativePrimaries, + (const sp<IBinder>&, gui::DisplayPrimaries*), (override)); + MOCK_METHOD(binder::Status, setActiveColorMode, (const sp<IBinder>&, int), (override)); + MOCK_METHOD(binder::Status, setBootDisplayMode, (const sp<IBinder>&, int), (override)); + MOCK_METHOD(binder::Status, clearBootDisplayMode, (const sp<IBinder>&), (override)); + MOCK_METHOD(binder::Status, getBootDisplayModeSupport, (bool*), (override)); + MOCK_METHOD(binder::Status, setAutoLowLatencyMode, (const sp<IBinder>&, bool), (override)); + MOCK_METHOD(binder::Status, setGameContentType, (const sp<IBinder>&, bool), (override)); + MOCK_METHOD(binder::Status, captureDisplay, + (const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&), (override)); + MOCK_METHOD(binder::Status, captureDisplayById, (int64_t, const sp<IScreenCaptureListener>&), + (override)); + MOCK_METHOD(binder::Status, captureLayers, + (const LayerCaptureArgs&, const sp<IScreenCaptureListener>&), (override)); + MOCK_METHOD(binder::Status, clearAnimationFrameStats, (), (override)); + MOCK_METHOD(binder::Status, getAnimationFrameStats, (gui::FrameStats*), (override)); + MOCK_METHOD(binder::Status, overrideHdrTypes, (const sp<IBinder>&, const std::vector<int32_t>&), + (override)); + MOCK_METHOD(binder::Status, onPullAtom, (int32_t, gui::PullAtomData*), (override)); + MOCK_METHOD(binder::Status, enableVSyncInjections, (bool), (override)); + MOCK_METHOD(binder::Status, injectVSync, (int64_t), (override)); + MOCK_METHOD(binder::Status, getLayerDebugInfo, (std::vector<gui::LayerDebugInfo>*), (override)); + MOCK_METHOD(binder::Status, getColorManagement, (bool*), (override)); + MOCK_METHOD(binder::Status, getCompositionPreference, (gui::CompositionPreference*), + (override)); + MOCK_METHOD(binder::Status, getDisplayedContentSamplingAttributes, + (const sp<IBinder>&, gui::ContentSamplingAttributes*), (override)); + MOCK_METHOD(binder::Status, setDisplayContentSamplingEnabled, + (const sp<IBinder>&, bool, int8_t, int64_t), (override)); + MOCK_METHOD(binder::Status, getDisplayedContentSample, + (const sp<IBinder>&, int64_t, int64_t, gui::DisplayedFrameStats*), (override)); + MOCK_METHOD(binder::Status, getProtectedContentSupport, (bool*), (override)); + MOCK_METHOD(binder::Status, isWideColorDisplay, (const sp<IBinder>&, bool*), (override)); + MOCK_METHOD(binder::Status, addRegionSamplingListener, + (const gui::ARect&, const sp<IBinder>&, const sp<gui::IRegionSamplingListener>&), + (override)); + MOCK_METHOD(binder::Status, removeRegionSamplingListener, + (const sp<gui::IRegionSamplingListener>&), (override)); + MOCK_METHOD(binder::Status, addFpsListener, (int32_t, const sp<gui::IFpsListener>&), + (override)); + MOCK_METHOD(binder::Status, removeFpsListener, (const sp<gui::IFpsListener>&), (override)); + MOCK_METHOD(binder::Status, addTunnelModeEnabledListener, + (const sp<gui::ITunnelModeEnabledListener>&), (override)); + MOCK_METHOD(binder::Status, removeTunnelModeEnabledListener, + (const sp<gui::ITunnelModeEnabledListener>&), (override)); + MOCK_METHOD(binder::Status, setDesiredDisplayModeSpecs, + (const sp<IBinder>&, int32_t, bool, float, float, float, + float appRequestRefreshRateMax), + (override)); + MOCK_METHOD(binder::Status, getDesiredDisplayModeSpecs, + (const sp<IBinder>&, gui::DisplayModeSpecs*), (override)); + MOCK_METHOD(binder::Status, getDisplayBrightnessSupport, (const sp<IBinder>&, bool*), + (override)); + MOCK_METHOD(binder::Status, setDisplayBrightness, + (const sp<IBinder>&, const gui::DisplayBrightness&), (override)); + MOCK_METHOD(binder::Status, addHdrLayerInfoListener, + (const sp<IBinder>&, const sp<gui::IHdrLayerInfoListener>&), (override)); + MOCK_METHOD(binder::Status, removeHdrLayerInfoListener, + (const sp<IBinder>&, const sp<gui::IHdrLayerInfoListener>&), (override)); + MOCK_METHOD(binder::Status, notifyPowerBoost, (int), (override)); + MOCK_METHOD(binder::Status, setGlobalShadowSettings, + (const gui::Color&, const gui::Color&, float, float, float), (override)); + MOCK_METHOD(binder::Status, getDisplayDecorationSupport, + (const sp<IBinder>&, std::optional<gui::DisplayDecorationSupport>*), (override)); + MOCK_METHOD(binder::Status, setOverrideFrameRate, (int32_t, float), (override)); + MOCK_METHOD(binder::Status, addTransactionTraceListener, + (const sp<gui::ITransactionTraceListener>&), (override)); + MOCK_METHOD(binder::Status, getGpuContextPriority, (int32_t*), (override)); + MOCK_METHOD(binder::Status, getMaxAcquiredBufferCount, (int32_t*), (override)); + MOCK_METHOD(binder::Status, addWindowInfosListener, (const sp<gui::IWindowInfosListener>&), + (override)); + MOCK_METHOD(binder::Status, removeWindowInfosListener, (const sp<gui::IWindowInfosListener>&), + (override)); +}; + +class FakeBnSurfaceComposerClient : public gui::BnSurfaceComposerClient { +public: + MOCK_METHOD(binder::Status, createSurface, + (const std::string& name, int32_t flags, const sp<IBinder>& parent, + const gui::LayerMetadata& metadata, gui::CreateSurfaceResult* outResult), + (override)); + + MOCK_METHOD(binder::Status, clearLayerFrameStats, (const sp<IBinder>& handle), (override)); + + MOCK_METHOD(binder::Status, getLayerFrameStats, + (const sp<IBinder>& handle, gui::FrameStats* outStats), (override)); + + MOCK_METHOD(binder::Status, mirrorSurface, + (const sp<IBinder>& mirrorFromHandle, gui::MirrorSurfaceResult* outResult), + (override)); +}; + +class FakeDisplayEventDispatcher : public DisplayEventDispatcher { +public: + FakeDisplayEventDispatcher(const sp<Looper>& looper, + gui::ISurfaceComposer::VsyncSource vsyncSource, + gui::ISurfaceComposer::EventRegistration eventRegistration) + : DisplayEventDispatcher(looper, vsyncSource, eventRegistration){}; + + MOCK_METHOD4(dispatchVsync, void(nsecs_t, PhysicalDisplayId, uint32_t, VsyncEventData)); + MOCK_METHOD3(dispatchHotplug, void(nsecs_t, PhysicalDisplayId, bool)); + MOCK_METHOD4(dispatchModeChanged, void(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t)); + MOCK_METHOD2(dispatchNullEvent, void(nsecs_t, PhysicalDisplayId)); + MOCK_METHOD3(dispatchFrameRateOverrides, + void(nsecs_t, PhysicalDisplayId, std::vector<FrameRateOverride>)); +}; + +} // namespace android + +namespace android::hardware { + +namespace graphics::bufferqueue::V1_0::utils { + +class FakeGraphicBufferProducerV1 : public HGraphicBufferProducer { +public: + FakeGraphicBufferProducerV1() { + ON_CALL(*this, setMaxDequeuedBufferCount).WillByDefault([]() { return 0; }); + ON_CALL(*this, setAsyncMode).WillByDefault([]() { return 0; }); + ON_CALL(*this, detachBuffer).WillByDefault([]() { return 0; }); + ON_CALL(*this, cancelBuffer).WillByDefault([]() { return 0; }); + ON_CALL(*this, disconnect).WillByDefault([]() { return 0; }); + ON_CALL(*this, setSidebandStream).WillByDefault([]() { return 0; }); + ON_CALL(*this, allowAllocation).WillByDefault([]() { return 0; }); + ON_CALL(*this, setGenerationNumber).WillByDefault([]() { return 0; }); + ON_CALL(*this, setSharedBufferMode).WillByDefault([]() { return 0; }); + ON_CALL(*this, setAutoRefresh).WillByDefault([]() { return 0; }); + ON_CALL(*this, setDequeueTimeout).WillByDefault([]() { return 0; }); + ON_CALL(*this, setLegacyBufferDrop).WillByDefault([]() { return 0; }); + }; + MOCK_METHOD2(requestBuffer, Return<void>(int, requestBuffer_cb)); + MOCK_METHOD1(setMaxDequeuedBufferCount, Return<int32_t>(int32_t)); + MOCK_METHOD1(setAsyncMode, Return<int32_t>(bool)); + MOCK_METHOD6(dequeueBuffer, + Return<void>(uint32_t, uint32_t, graphics::common::V1_0::PixelFormat, uint32_t, + bool, dequeueBuffer_cb)); + MOCK_METHOD1(detachBuffer, Return<int32_t>(int)); + MOCK_METHOD1(detachNextBuffer, Return<void>(detachNextBuffer_cb)); + MOCK_METHOD2(attachBuffer, Return<void>(const media::V1_0::AnwBuffer&, attachBuffer_cb)); + MOCK_METHOD3( + queueBuffer, + Return<void>( + int, + const graphics::bufferqueue::V1_0::IGraphicBufferProducer::QueueBufferInput&, + queueBuffer_cb)); + MOCK_METHOD2(cancelBuffer, Return<int32_t>(int, const hidl_handle&)); + MOCK_METHOD2(query, Return<void>(int32_t, query_cb)); + MOCK_METHOD4(connect, + Return<void>(const sp<graphics::bufferqueue::V1_0::IProducerListener>&, int32_t, + bool, connect_cb)); + MOCK_METHOD2(disconnect, + Return<int32_t>( + int, graphics::bufferqueue::V1_0::IGraphicBufferProducer::DisconnectMode)); + MOCK_METHOD1(setSidebandStream, Return<int32_t>(const hidl_handle&)); + MOCK_METHOD4(allocateBuffers, + Return<void>(uint32_t, uint32_t, graphics::common::V1_0::PixelFormat, uint32_t)); + MOCK_METHOD1(allowAllocation, Return<int32_t>(bool)); + MOCK_METHOD1(setGenerationNumber, Return<int32_t>(uint32_t)); + MOCK_METHOD1(getConsumerName, Return<void>(getConsumerName_cb)); + MOCK_METHOD1(setSharedBufferMode, Return<int32_t>(bool)); + MOCK_METHOD1(setAutoRefresh, Return<int32_t>(bool)); + MOCK_METHOD1(setDequeueTimeout, Return<int32_t>(nsecs_t)); + MOCK_METHOD1(setLegacyBufferDrop, Return<int32_t>(bool)); + MOCK_METHOD1(getLastQueuedBuffer, Return<void>(getLastQueuedBuffer_cb)); + MOCK_METHOD1(getFrameTimestamps, Return<void>(getFrameTimestamps_cb)); + MOCK_METHOD1(getUniqueId, Return<void>(getUniqueId_cb)); +}; + +}; // namespace graphics::bufferqueue::V1_0::utils + +namespace graphics::bufferqueue::V2_0::utils { + +class FakeGraphicBufferProducerV2 : public HGraphicBufferProducer { +public: + FakeGraphicBufferProducerV2() { + ON_CALL(*this, setMaxDequeuedBufferCount).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, setAsyncMode).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, detachBuffer).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, cancelBuffer).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, disconnect).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, allocateBuffers).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, allowAllocation).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, setGenerationNumber).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, setDequeueTimeout).WillByDefault([]() { return Status::OK; }); + ON_CALL(*this, getUniqueId).WillByDefault([]() { return 0; }); + }; + MOCK_METHOD2(requestBuffer, Return<void>(int, requestBuffer_cb)); + MOCK_METHOD1(setMaxDequeuedBufferCount, Return<graphics::bufferqueue::V2_0::Status>(int)); + MOCK_METHOD1(setAsyncMode, Return<graphics::bufferqueue::V2_0::Status>(bool)); + MOCK_METHOD2( + dequeueBuffer, + Return<void>( + const graphics::bufferqueue::V2_0::IGraphicBufferProducer::DequeueBufferInput&, + dequeueBuffer_cb)); + MOCK_METHOD1(detachBuffer, Return<graphics::bufferqueue::V2_0::Status>(int)); + MOCK_METHOD1(detachNextBuffer, Return<void>(detachNextBuffer_cb)); + MOCK_METHOD3(attachBuffer, + Return<void>(const graphics::common::V1_2::HardwareBuffer&, uint32_t, + attachBuffer_cb)); + MOCK_METHOD3( + queueBuffer, + Return<void>( + int, + const graphics::bufferqueue::V2_0::IGraphicBufferProducer::QueueBufferInput&, + queueBuffer_cb)); + MOCK_METHOD2(cancelBuffer, + Return<graphics::bufferqueue::V2_0::Status>(int, const hidl_handle&)); + MOCK_METHOD2(query, Return<void>(int32_t, query_cb)); + MOCK_METHOD4(connect, + Return<void>(const sp<graphics::bufferqueue::V2_0::IProducerListener>&, + graphics::bufferqueue::V2_0::ConnectionType, bool, connect_cb)); + MOCK_METHOD1(disconnect, + Return<graphics::bufferqueue::V2_0::Status>( + graphics::bufferqueue::V2_0::ConnectionType)); + MOCK_METHOD4(allocateBuffers, + Return<graphics::bufferqueue::V2_0::Status>(uint32_t, uint32_t, uint32_t, + uint64_t)); + MOCK_METHOD1(allowAllocation, Return<graphics::bufferqueue::V2_0::Status>(bool)); + MOCK_METHOD1(setGenerationNumber, Return<graphics::bufferqueue::V2_0::Status>(uint32_t)); + MOCK_METHOD1(getConsumerName, Return<void>(getConsumerName_cb)); + MOCK_METHOD1(setDequeueTimeout, Return<graphics::bufferqueue::V2_0::Status>(int64_t)); + MOCK_METHOD0(getUniqueId, Return<uint64_t>()); +}; + +}; // namespace graphics::bufferqueue::V2_0::utils +}; // namespace android::hardware diff --git a/libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp new file mode 100644 index 0000000000..6d5427bc9e --- /dev/null +++ b/libs/gui/fuzzer/libgui_surfaceComposer_fuzzer.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2021 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 <fuzzbinder/libbinder_driver.h> +#include <fuzzer/FuzzedDataProvider.h> +#include <libgui_fuzzer_utils.h> + +using namespace android; + +class SurfaceComposerFuzzer { +public: + SurfaceComposerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){}; + void process(); + +private: + FuzzedDataProvider mFdp; +}; + +void SurfaceComposerFuzzer::process() { + sp<FakeBnSurfaceComposer> composer(new FakeBnSurfaceComposer()); + fuzzService(composer.get(), std::move(mFdp)); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + SurfaceComposerFuzzer surfaceComposerFuzzer(data, size); + surfaceComposerFuzzer.process(); + return 0; +} diff --git a/libs/gui/include/gui/AidlStatusUtil.h b/libs/gui/include/gui/AidlStatusUtil.h new file mode 100644 index 0000000000..55be27bf35 --- /dev/null +++ b/libs/gui/include/gui/AidlStatusUtil.h @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2022 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 <binder/Status.h> + +// Extracted from frameworks/av/media/libaudioclient/include/media/AidlConversionUtil.h +namespace android::gui::aidl_utils { + +/** + * Return the equivalent Android status_t from a binder exception code. + * + * Generally one should use statusTFromBinderStatus() instead. + * + * Exception codes can be generated from a remote Java service exception, translate + * them for use on the Native side. + * + * Note: for EX_TRANSACTION_FAILED and EX_SERVICE_SPECIFIC a more detailed error code + * can be found from transactionError() or serviceSpecificErrorCode(). + */ +static inline status_t statusTFromExceptionCode(int32_t exceptionCode) { + using namespace ::android::binder; + switch (exceptionCode) { + case Status::EX_NONE: + return OK; + case Status::EX_SECURITY: // Java SecurityException, rethrows locally in Java + return PERMISSION_DENIED; + case Status::EX_BAD_PARCELABLE: // Java BadParcelableException, rethrows in Java + case Status::EX_ILLEGAL_ARGUMENT: // Java IllegalArgumentException, rethrows in Java + case Status::EX_NULL_POINTER: // Java NullPointerException, rethrows in Java + return BAD_VALUE; + case Status::EX_ILLEGAL_STATE: // Java IllegalStateException, rethrows in Java + case Status::EX_UNSUPPORTED_OPERATION: // Java UnsupportedOperationException, rethrows + return INVALID_OPERATION; + case Status::EX_HAS_REPLY_HEADER: // Native strictmode violation + case Status::EX_PARCELABLE: // Java bootclass loader (not standard exception), rethrows + case Status::EX_NETWORK_MAIN_THREAD: // Java NetworkOnMainThreadException, rethrows + case Status::EX_TRANSACTION_FAILED: // Native - see error code + case Status::EX_SERVICE_SPECIFIC: // Java ServiceSpecificException, + // rethrows in Java with integer error code + return UNKNOWN_ERROR; + } + return UNKNOWN_ERROR; +} + +/** + * Return the equivalent Android status_t from a binder status. + * + * Used to handle errors from a AIDL method declaration + * + * [oneway] void method(type0 param0, ...) + * + * or the following (where return_type is not a status_t) + * + * return_type method(type0 param0, ...) + */ +static inline status_t statusTFromBinderStatus(const ::android::binder::Status &status) { + return status.isOk() ? OK // check OK, + : status.serviceSpecificErrorCode() // service-side error, not standard Java exception + // (fromServiceSpecificError) + ?: status.transactionError() // a native binder transaction error (fromStatusT) + ?: statusTFromExceptionCode(status.exceptionCode()); // a service-side error with a + // standard Java exception (fromExceptionCode) +} + +/** + * Return a binder::Status from native service status. + * + * This is used for methods not returning an explicit status_t, + * where Java callers expect an exception, not an integer return value. + */ +static inline ::android::binder::Status binderStatusFromStatusT( + status_t status, const char *optionalMessage = nullptr) { + const char *const emptyIfNull = optionalMessage == nullptr ? "" : optionalMessage; + // From binder::Status instructions: + // Prefer a generic exception code when possible, then a service specific + // code, and finally a status_t for low level failures or legacy support. + // Exception codes and service specific errors map to nicer exceptions for + // Java clients. + + using namespace ::android::binder; + switch (status) { + case OK: + return Status::ok(); + case PERMISSION_DENIED: // throw SecurityException on Java side + return Status::fromExceptionCode(Status::EX_SECURITY, emptyIfNull); + case BAD_VALUE: // throw IllegalArgumentException on Java side + return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, emptyIfNull); + case INVALID_OPERATION: // throw IllegalStateException on Java side + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, emptyIfNull); + } + + // A service specific error will not show on status.transactionError() so + // be sure to use statusTFromBinderStatus() for reliable error handling. + + // throw a ServiceSpecificException. + return Status::fromServiceSpecificError(status, emptyIfNull); +} + +} // namespace android::gui::aidl_utils diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index 9d287910a5..2ed526096d 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -69,9 +69,7 @@ private: bool mPreviouslyConnected GUARDED_BY(mMutex); }; -class BLASTBufferQueue - : public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener -{ +class BLASTBufferQueue : public ConsumerBase::FrameAvailableListener { public: BLASTBufferQueue(const std::string& name, bool updateDestinationFrame = true); BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface, int width, @@ -83,7 +81,6 @@ public: sp<Surface> getSurface(bool includeSurfaceControlHandle); bool isSameSurfaceControl(const sp<SurfaceControl>& surfaceControl) const; - void onBufferFreed(const wp<GraphicBuffer>&/* graphicBuffer*/) override { /* TODO */ } void onFrameReplaced(const BufferItem& item) override; void onFrameAvailable(const BufferItem& item) override; void onFrameDequeued(const uint64_t) override; diff --git a/libs/gui/include/gui/CompositorTiming.h b/libs/gui/include/gui/CompositorTiming.h new file mode 100644 index 0000000000..cb8ca7a15c --- /dev/null +++ b/libs/gui/include/gui/CompositorTiming.h @@ -0,0 +1,43 @@ +/* + * Copyright 2022 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 <utils/Timers.h> + +namespace android::gui { + +// Expected timing of the next composited frame, based on the timing of the latest frames. +struct CompositorTiming { + static constexpr nsecs_t kDefaultVsyncPeriod = 16'666'667; + + CompositorTiming() = default; + CompositorTiming(nsecs_t vsyncDeadline, nsecs_t vsyncPeriod, nsecs_t vsyncPhase, + nsecs_t presentLatency); + + // Time point when compositing is expected to start. + nsecs_t deadline = 0; + + // Duration between consecutive frames. In other words, the VSYNC period. + nsecs_t interval = kDefaultVsyncPeriod; + + // Duration between composite start and present. For missed frames, the extra latency is rounded + // to a multiple of the VSYNC period, such that the remainder (presentLatency % interval) always + // evaluates to the VSYNC phase offset. + nsecs_t presentLatency = kDefaultVsyncPeriod; +}; + +} // namespace android::gui diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h index a3425395bf..bf3a07b6b5 100644 --- a/libs/gui/include/gui/DisplayEventDispatcher.h +++ b/libs/gui/include/gui/DisplayEventDispatcher.h @@ -23,10 +23,10 @@ using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; class DisplayEventDispatcher : public LooperCallback { public: - explicit DisplayEventDispatcher( - const sp<Looper>& looper, - ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp, - ISurfaceComposer::EventRegistrationFlags eventRegistration = {}); + explicit DisplayEventDispatcher(const sp<Looper>& looper, + gui::ISurfaceComposer::VsyncSource vsyncSource = + gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, + EventRegistrationFlags eventRegistration = {}); status_t initialize(); void dispose(); diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h index cf7a4e5522..0f4907fcb9 100644 --- a/libs/gui/include/gui/DisplayEventReceiver.h +++ b/libs/gui/include/gui/DisplayEventReceiver.h @@ -20,20 +20,26 @@ #include <stdint.h> #include <sys/types.h> +#include <ftl/flags.h> + #include <utils/Errors.h> #include <utils/RefBase.h> #include <utils/Timers.h> +#include <android/gui/ISurfaceComposer.h> #include <binder/IInterface.h> -#include <gui/ISurfaceComposer.h> #include <gui/VsyncEventData.h> +#include <ui/DisplayId.h> + // ---------------------------------------------------------------------------- namespace android { // ---------------------------------------------------------------------------- +using EventRegistrationFlags = ftl::Flags<gui::ISurfaceComposer::EventRegistration>; + using gui::IDisplayEventConnection; using gui::ParcelableVsyncEventData; using gui::VsyncEventData; @@ -111,9 +117,9 @@ public: * To receive ModeChanged and/or FrameRateOverrides events specify this in * the constructor. Other events start being delivered immediately. */ - explicit DisplayEventReceiver( - ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp, - ISurfaceComposer::EventRegistrationFlags eventRegistration = {}); + explicit DisplayEventReceiver(gui::ISurfaceComposer::VsyncSource vsyncSource = + gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, + EventRegistrationFlags eventRegistration = {}); /* * ~DisplayEventReceiver severs the connection with SurfaceFlinger, new events diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h index dd3de58844..c08a9b1b6c 100644 --- a/libs/gui/include/gui/FrameTimestamps.h +++ b/libs/gui/include/gui/FrameTimestamps.h @@ -17,6 +17,9 @@ #ifndef ANDROID_GUI_FRAMETIMESTAMPS_H #define ANDROID_GUI_FRAMETIMESTAMPS_H +#include <android/gui/FrameEvent.h> + +#include <gui/CompositorTiming.h> #include <ui/FenceTime.h> #include <utils/Flattenable.h> #include <utils/StrongPointer.h> @@ -31,22 +34,8 @@ namespace android { struct FrameEvents; class FrameEventHistoryDelta; - -// Identifiers for all the events that may be recorded or reported. -enum class FrameEvent { - POSTED, - REQUESTED_PRESENT, - LATCH, - ACQUIRE, - FIRST_REFRESH_START, - LAST_REFRESH_START, - GPU_COMPOSITION_DONE, - DISPLAY_PRESENT, - DEQUEUE_READY, - RELEASE, - EVENT_COUNT, // Not an actual event. -}; - +using gui::CompositorTiming; +using gui::FrameEvent; // A collection of timestamps corresponding to a single frame. struct FrameEvents { @@ -96,12 +85,6 @@ struct FrameEvents { std::shared_ptr<FenceTime> releaseFence{FenceTime::NO_FENCE}; }; -struct CompositorTiming { - nsecs_t deadline{0}; - nsecs_t interval{16666667}; - nsecs_t presentLatency{16666667}; -}; - // A short history of frames that are synchronized between the consumer and // producer via deltas. class FrameEventHistory { diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h index 2f538ffb86..ba268ab17a 100644 --- a/libs/gui/include/gui/GLConsumer.h +++ b/libs/gui/include/gui/GLConsumer.h @@ -138,6 +138,10 @@ public: const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform, bool filtering); + static void computeTransformMatrix(float outTransform[16], float bufferWidth, + float bufferHeight, PixelFormat pixelFormat, + const Rect& cropRect, uint32_t transform, bool filtering); + // Scale the crop down horizontally or vertically such that it has the // same aspect ratio as the buffer does. static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index a610e940be..1e85131386 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -17,6 +17,7 @@ #pragma once #include <android/gui/DisplayBrightness.h> +#include <android/gui/FrameTimelineInfo.h> #include <android/gui/IDisplayEventConnection.h> #include <android/gui/IFpsListener.h> #include <android/gui/IHdrLayerInfoListener.h> @@ -27,8 +28,6 @@ #include <android/gui/IWindowInfosListener.h> #include <binder/IBinder.h> #include <binder/IInterface.h> -#include <ftl/flags.h> -#include <gui/FrameTimelineInfo.h> #include <gui/ITransactionCompletedListener.h> #include <gui/SpHash.h> #include <math/vec4.h> @@ -61,13 +60,10 @@ struct ComposerState; struct DisplayStatInfo; struct DisplayState; struct InputWindowCommands; -class LayerDebugInfo; class HdrCapabilities; -class IGraphicBufferProducer; -class ISurfaceComposerClient; class Rect; -enum class FrameEvent; +using gui::FrameTimelineInfo; using gui::IDisplayEventConnection; using gui::IRegionSamplingListener; using gui::IScreenCaptureListener; @@ -77,6 +73,7 @@ namespace gui { struct DisplayCaptureArgs; struct LayerCaptureArgs; +class LayerDebugInfo; } // namespace gui @@ -85,7 +82,6 @@ namespace ui { struct DisplayMode; struct DisplayState; struct DynamicDisplayInfo; -struct StaticDisplayInfo; } // namespace ui @@ -97,8 +93,6 @@ class ISurfaceComposer: public IInterface { public: DECLARE_META_INTERFACE(SurfaceComposer) - static constexpr size_t MAX_LAYERS = 4096; - // flags for setTransactionState() enum { eSynchronous = 0x01, @@ -116,28 +110,6 @@ public: eOneWay = 0x20 }; - enum VsyncSource { - eVsyncSourceApp = 0, - eVsyncSourceSurfaceFlinger = 1 - }; - - enum class EventRegistration { - modeChanged = 1 << 0, - frameRateOverride = 1 << 1, - }; - - using EventRegistrationFlags = ftl::Flags<EventRegistration>; - - /* - * Create a connection with SurfaceFlinger. - */ - virtual sp<ISurfaceComposerClient> createConnection() = 0; - - /* return an IDisplayEventConnection */ - virtual sp<IDisplayEventConnection> createDisplayEventConnection( - VsyncSource vsyncSource = eVsyncSourceApp, - EventRegistrationFlags eventRegistration = {}) = 0; - /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */ virtual status_t setTransactionState( const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& state, @@ -145,293 +117,6 @@ public: const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) = 0; - - /* signal that we're done booting. - * Requires ACCESS_SURFACE_FLINGER permission - */ - virtual void bootFinished() = 0; - - /* verify that an IGraphicBufferProducer was created by SurfaceFlinger. - */ - virtual bool authenticateSurfaceTexture( - const sp<IGraphicBufferProducer>& surface) const = 0; - - /* Returns the frame timestamps supported by SurfaceFlinger. - */ - virtual status_t getSupportedFrameTimestamps( - std::vector<FrameEvent>* outSupported) const = 0; - - /** - * Gets immutable information about given physical display. - */ - virtual status_t getStaticDisplayInfo(const sp<IBinder>& display, ui::StaticDisplayInfo*) = 0; - - /** - * Gets dynamic information about given physical display. - */ - virtual status_t getDynamicDisplayInfo(const sp<IBinder>& display, ui::DynamicDisplayInfo*) = 0; - - virtual status_t getDisplayNativePrimaries(const sp<IBinder>& display, - ui::DisplayPrimaries& primaries) = 0; - virtual status_t setActiveColorMode(const sp<IBinder>& display, - ui::ColorMode colorMode) = 0; - - /** - * Sets the user-preferred display mode that a device should boot in. - */ - virtual status_t setBootDisplayMode(const sp<IBinder>& display, ui::DisplayModeId) = 0; - - /* Clears the frame statistics for animations. - * - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t clearAnimationFrameStats() = 0; - - /* Gets the frame statistics for animations. - * - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t getAnimationFrameStats(FrameStats* outStats) const = 0; - - /* Overrides the supported HDR modes for the given display device. - * - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t overrideHdrTypes(const sp<IBinder>& display, - const std::vector<ui::Hdr>& hdrTypes) = 0; - - /* Pulls surfaceflinger atoms global stats and layer stats to pipe to statsd. - * - * Requires the calling uid be from system server. - */ - virtual status_t onPullAtom(const int32_t atomId, std::string* outData, bool* success) = 0; - - virtual status_t enableVSyncInjections(bool enable) = 0; - - virtual status_t injectVSync(nsecs_t when) = 0; - - /* Gets the list of active layers in Z order for debugging purposes - * - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) = 0; - - virtual status_t getColorManagement(bool* outGetColorManagement) const = 0; - - /* Gets the composition preference of the default data space and default pixel format, - * as well as the wide color gamut data space and wide color gamut pixel format. - * If the wide color gamut data space is V0_SRGB, then it implies that the platform - * has no wide color gamut support. - * - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t getCompositionPreference(ui::Dataspace* defaultDataspace, - ui::PixelFormat* defaultPixelFormat, - ui::Dataspace* wideColorGamutDataspace, - ui::PixelFormat* wideColorGamutPixelFormat) const = 0; - /* - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& display, - ui::PixelFormat* outFormat, - ui::Dataspace* outDataspace, - uint8_t* outComponentMask) const = 0; - - /* Turns on the color sampling engine on the display. - * - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable, - uint8_t componentMask, - uint64_t maxFrames) = 0; - - /* Returns statistics on the color profile of the last frame displayed for a given display - * - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t getDisplayedContentSample(const sp<IBinder>& display, uint64_t maxFrames, - uint64_t timestamp, - DisplayedFrameStats* outStats) const = 0; - - /* - * Gets whether SurfaceFlinger can support protected content in GPU composition. - * Requires the ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t getProtectedContentSupport(bool* outSupported) const = 0; - - /* Registers a listener to stream median luma updates from SurfaceFlinger. - * - * The sampling area is bounded by both samplingArea and the given stopLayerHandle - * (i.e., only layers behind the stop layer will be captured and sampled). - * - * Multiple listeners may be provided so long as they have independent listeners. - * If multiple listeners are provided, the effective sampling region for each listener will - * be bounded by whichever stop layer has a lower Z value. - * - * Requires the same permissions as captureLayers and captureScreen. - */ - virtual status_t addRegionSamplingListener(const Rect& samplingArea, - const sp<IBinder>& stopLayerHandle, - const sp<IRegionSamplingListener>& listener) = 0; - - /* - * Removes a listener that was streaming median luma updates from SurfaceFlinger. - */ - virtual status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) = 0; - - /* Registers a listener that streams fps updates from SurfaceFlinger. - * - * The listener will stream fps updates for the layer tree rooted at the layer denoted by the - * task ID, i.e., the layer must have the task ID as part of its layer metadata with key - * METADATA_TASK_ID. If there is no such layer, then no fps is expected to be reported. - * - * Multiple listeners may be supported. - * - * Requires the READ_FRAME_BUFFER permission. - */ - virtual status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) = 0; - /* - * Removes a listener that was streaming fps updates from SurfaceFlinger. - */ - virtual status_t removeFpsListener(const sp<gui::IFpsListener>& listener) = 0; - - /* Registers a listener to receive tunnel mode enabled updates from SurfaceFlinger. - * - * Requires ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t addTunnelModeEnabledListener( - const sp<gui::ITunnelModeEnabledListener>& listener) = 0; - - /* - * Removes a listener that was receiving tunnel mode enabled updates from SurfaceFlinger. - * - * Requires ACCESS_SURFACE_FLINGER permission. - */ - virtual status_t removeTunnelModeEnabledListener( - const sp<gui::ITunnelModeEnabledListener>& listener) = 0; - - /* Sets the refresh rate boundaries for the display. - * - * The primary refresh rate range represents display manager's general guidance on the display - * modes we'll consider when switching refresh rates. Unless we get an explicit signal from an - * app, we should stay within this range. - * - * The app request refresh rate range allows us to consider more display modes when switching - * refresh rates. Although we should generally stay within the primary range, specific - * considerations, such as layer frame rate settings specified via the setFrameRate() api, may - * cause us to go outside the primary range. We never go outside the app request range. The app - * request range will be greater than or equal to the primary refresh rate range, never smaller. - * - * defaultMode is used to narrow the list of display modes SurfaceFlinger will consider - * switching between. Only modes with a mode group and resolution matching defaultMode - * will be considered for switching. The defaultMode corresponds to an ID of mode in the list - * of supported modes returned from getDynamicDisplayInfo(). - */ - virtual status_t setDesiredDisplayModeSpecs( - const sp<IBinder>& displayToken, ui::DisplayModeId defaultMode, - bool allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax, - float appRequestRefreshRateMin, float appRequestRefreshRateMax) = 0; - - virtual status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, - ui::DisplayModeId* outDefaultMode, - bool* outAllowGroupSwitching, - float* outPrimaryRefreshRateMin, - float* outPrimaryRefreshRateMax, - float* outAppRequestRefreshRateMin, - float* outAppRequestRefreshRateMax) = 0; - - /* - * Sets the global configuration for all the shadows drawn by SurfaceFlinger. Shadow follows - * material design guidelines. - * - * ambientColor - * Color to the ambient shadow. The alpha is premultiplied. - * - * spotColor - * Color to the spot shadow. The alpha is premultiplied. The position of the spot shadow - * depends on the light position. - * - * lightPosY/lightPosZ - * Position of the light used to cast the spot shadow. The X value is always the display - * width / 2. - * - * lightRadius - * Radius of the light casting the shadow. - */ - virtual status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, - float lightPosY, float lightPosZ, - float lightRadius) = 0; - - /* - * Gets whether a display supports DISPLAY_DECORATION layers. - * - * displayToken - * The token of the display. - * outSupport - * An output parameter for whether/how the display supports - * DISPLAY_DECORATION layers. - * - * Returns NO_ERROR upon success. Otherwise, - * NAME_NOT_FOUND if the display is invalid, or - * BAD_VALUE if the output parameter is invalid. - */ - virtual status_t getDisplayDecorationSupport( - const sp<IBinder>& displayToken, - std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>* - outSupport) const = 0; - - /* - * Sets the intended frame rate for a surface. See ANativeWindow_setFrameRate() for more info. - */ - virtual status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, - int8_t compatibility, int8_t changeFrameRateStrategy) = 0; - - /* - * Set the override frame rate for a specified uid by GameManagerService. - * Passing the frame rate and uid to SurfaceFlinger to update the override mapping - * in the scheduler. - */ - virtual status_t setOverrideFrameRate(uid_t uid, float frameRate) = 0; - - /* - * Sets the frame timeline vsync info received from choreographer that corresponds to next - * buffer submitted on that surface. - */ - virtual status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface, - const FrameTimelineInfo& frameTimelineInfo) = 0; - - /* - * Adds a TransactionTraceListener to listen for transaction tracing state updates. - */ - virtual status_t addTransactionTraceListener( - const sp<gui::ITransactionTraceListener>& listener) = 0; - - /** - * Gets priority of the RenderEngine in SurfaceFlinger. - */ - virtual int getGPUContextPriority() = 0; - - /** - * Gets the number of buffers SurfaceFlinger would need acquire. This number - * would be propagated to the client via MIN_UNDEQUEUED_BUFFERS so that the - * client could allocate enough buffers to match SF expectations of the - * pipeline depth. SurfaceFlinger will make sure that it will give the app at - * least the time configured as the 'appDuration' before trying to latch - * the buffer. - * - * The total buffers needed for a given configuration is basically the - * numbers of vsyncs a single buffer is used across the stack. For the default - * configuration a buffer is held ~1 vsync by the app, ~1 vsync by SurfaceFlinger - * and 1 vsync by the display. The extra buffers are calculated as the - * number of additional buffers on top of the 2 buffers already present - * in MIN_UNDEQUEUED_BUFFERS. - */ - virtual status_t getMaxAcquiredBufferCount(int* buffers) const = 0; - - virtual status_t addWindowInfosListener( - const sp<gui::IWindowInfosListener>& windowInfosListener) const = 0; - virtual status_t removeWindowInfosListener( - const sp<gui::IWindowInfosListener>& windowInfosListener) const = 0; }; // ---------------------------------------------------------------------------- @@ -442,77 +127,77 @@ public: // Note: BOOT_FINISHED must remain this value, it is called from // Java by ActivityManagerService. BOOT_FINISHED = IBinder::FIRST_CALL_TRANSACTION, - CREATE_CONNECTION, - GET_STATIC_DISPLAY_INFO, - CREATE_DISPLAY_EVENT_CONNECTION, - CREATE_DISPLAY, // Deprecated. Autogenerated by .aidl now. - DESTROY_DISPLAY, // Deprecated. Autogenerated by .aidl now. - GET_PHYSICAL_DISPLAY_TOKEN, // Deprecated. Autogenerated by .aidl now. + CREATE_CONNECTION, // Deprecated. Autogenerated by .aidl now. + GET_STATIC_DISPLAY_INFO, // Deprecated. Autogenerated by .aidl now. + CREATE_DISPLAY_EVENT_CONNECTION, // Deprecated. Autogenerated by .aidl now. + CREATE_DISPLAY, // Deprecated. Autogenerated by .aidl now. + DESTROY_DISPLAY, // Deprecated. Autogenerated by .aidl now. + GET_PHYSICAL_DISPLAY_TOKEN, // Deprecated. Autogenerated by .aidl now. SET_TRANSACTION_STATE, - AUTHENTICATE_SURFACE, - GET_SUPPORTED_FRAME_TIMESTAMPS, - GET_DISPLAY_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. - GET_ACTIVE_DISPLAY_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. + AUTHENTICATE_SURFACE, // Deprecated. Autogenerated by .aidl now. + GET_SUPPORTED_FRAME_TIMESTAMPS, // Deprecated. Autogenerated by .aidl now. + GET_DISPLAY_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. + GET_ACTIVE_DISPLAY_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. GET_DISPLAY_STATE, - CAPTURE_DISPLAY, // Deprecated. Autogenerated by .aidl now. - CAPTURE_LAYERS, // Deprecated. Autogenerated by .aidl now. - CLEAR_ANIMATION_FRAME_STATS, - GET_ANIMATION_FRAME_STATS, - SET_POWER_MODE, // Deprecated. Autogenerated by .aidl now. + CAPTURE_DISPLAY, // Deprecated. Autogenerated by .aidl now. + CAPTURE_LAYERS, // Deprecated. Autogenerated by .aidl now. + CLEAR_ANIMATION_FRAME_STATS, // Deprecated. Autogenerated by .aidl now. + GET_ANIMATION_FRAME_STATS, // Deprecated. Autogenerated by .aidl now. + SET_POWER_MODE, // Deprecated. Autogenerated by .aidl now. GET_DISPLAY_STATS, - GET_HDR_CAPABILITIES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. - GET_DISPLAY_COLOR_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. - GET_ACTIVE_COLOR_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. - SET_ACTIVE_COLOR_MODE, - ENABLE_VSYNC_INJECTIONS, - INJECT_VSYNC, - GET_LAYER_DEBUG_INFO, - GET_COMPOSITION_PREFERENCE, - GET_COLOR_MANAGEMENT, - GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES, - SET_DISPLAY_CONTENT_SAMPLING_ENABLED, + GET_HDR_CAPABILITIES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. + GET_DISPLAY_COLOR_MODES, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. + GET_ACTIVE_COLOR_MODE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. + SET_ACTIVE_COLOR_MODE, // Deprecated. Autogenerated by .aidl now. + ENABLE_VSYNC_INJECTIONS, // Deprecated. Autogenerated by .aidl now. + INJECT_VSYNC, // Deprecated. Autogenerated by .aidl now. + GET_LAYER_DEBUG_INFO, // Deprecated. Autogenerated by .aidl now. + GET_COMPOSITION_PREFERENCE, // Deprecated. Autogenerated by .aidl now. + GET_COLOR_MANAGEMENT, // Deprecated. Autogenerated by .aidl now. + GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES, // Deprecated. Autogenerated by .aidl now. + SET_DISPLAY_CONTENT_SAMPLING_ENABLED, // Deprecated. Autogenerated by .aidl now. GET_DISPLAYED_CONTENT_SAMPLE, - GET_PROTECTED_CONTENT_SUPPORT, - IS_WIDE_COLOR_DISPLAY, // Deprecated. Autogenerated by .aidl now. - GET_DISPLAY_NATIVE_PRIMARIES, - GET_PHYSICAL_DISPLAY_IDS, // Deprecated. Autogenerated by .aidl now. - ADD_REGION_SAMPLING_LISTENER, - REMOVE_REGION_SAMPLING_LISTENER, - SET_DESIRED_DISPLAY_MODE_SPECS, - GET_DESIRED_DISPLAY_MODE_SPECS, - GET_DISPLAY_BRIGHTNESS_SUPPORT, // Deprecated. Autogenerated by .aidl now. - SET_DISPLAY_BRIGHTNESS, // Deprecated. Autogenerated by .aidl now. - CAPTURE_DISPLAY_BY_ID, // Deprecated. Autogenerated by .aidl now. - NOTIFY_POWER_BOOST, // Deprecated. Autogenerated by .aidl now. + GET_PROTECTED_CONTENT_SUPPORT, // Deprecated. Autogenerated by .aidl now. + IS_WIDE_COLOR_DISPLAY, // Deprecated. Autogenerated by .aidl now. + GET_DISPLAY_NATIVE_PRIMARIES, // Deprecated. Autogenerated by .aidl now. + GET_PHYSICAL_DISPLAY_IDS, // Deprecated. Autogenerated by .aidl now. + ADD_REGION_SAMPLING_LISTENER, // Deprecated. Autogenerated by .aidl now. + REMOVE_REGION_SAMPLING_LISTENER, // Deprecated. Autogenerated by .aidl now. + SET_DESIRED_DISPLAY_MODE_SPECS, // Deprecated. Autogenerated by .aidl now. + GET_DESIRED_DISPLAY_MODE_SPECS, // Deprecated. Autogenerated by .aidl now. + GET_DISPLAY_BRIGHTNESS_SUPPORT, // Deprecated. Autogenerated by .aidl now. + SET_DISPLAY_BRIGHTNESS, // Deprecated. Autogenerated by .aidl now. + CAPTURE_DISPLAY_BY_ID, // Deprecated. Autogenerated by .aidl now. + NOTIFY_POWER_BOOST, // Deprecated. Autogenerated by .aidl now. SET_GLOBAL_SHADOW_SETTINGS, GET_AUTO_LOW_LATENCY_MODE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. SET_AUTO_LOW_LATENCY_MODE, // Deprecated. Autogenerated by .aidl now. GET_GAME_CONTENT_TYPE_SUPPORT, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. SET_GAME_CONTENT_TYPE, // Deprecated. Use GET_DYNAMIC_DISPLAY_INFO instead. - SET_FRAME_RATE, + SET_FRAME_RATE, // Deprecated. Autogenerated by .aidl now. // Deprecated. Use DisplayManager.setShouldAlwaysRespectAppRequestedMode(true); ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN, - SET_FRAME_TIMELINE_INFO, - ADD_TRANSACTION_TRACE_LISTENER, + SET_FRAME_TIMELINE_INFO, // Deprecated. Autogenerated by .aidl now. + ADD_TRANSACTION_TRACE_LISTENER, // Deprecated. Autogenerated by .aidl now. GET_GPU_CONTEXT_PRIORITY, GET_MAX_ACQUIRED_BUFFER_COUNT, - GET_DYNAMIC_DISPLAY_INFO, - ADD_FPS_LISTENER, - REMOVE_FPS_LISTENER, - OVERRIDE_HDR_TYPES, - ADD_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now. - REMOVE_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now. - ON_PULL_ATOM, - ADD_TUNNEL_MODE_ENABLED_LISTENER, - REMOVE_TUNNEL_MODE_ENABLED_LISTENER, - ADD_WINDOW_INFOS_LISTENER, - REMOVE_WINDOW_INFOS_LISTENER, - GET_PRIMARY_PHYSICAL_DISPLAY_ID, // Deprecated. Autogenerated by .aidl now. + GET_DYNAMIC_DISPLAY_INFO, // Deprecated. Autogenerated by .aidl now. + ADD_FPS_LISTENER, // Deprecated. Autogenerated by .aidl now. + REMOVE_FPS_LISTENER, // Deprecated. Autogenerated by .aidl now. + OVERRIDE_HDR_TYPES, // Deprecated. Autogenerated by .aidl now. + ADD_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now. + REMOVE_HDR_LAYER_INFO_LISTENER, // Deprecated. Autogenerated by .aidl now. + ON_PULL_ATOM, // Deprecated. Autogenerated by .aidl now. + ADD_TUNNEL_MODE_ENABLED_LISTENER, // Deprecated. Autogenerated by .aidl now. + REMOVE_TUNNEL_MODE_ENABLED_LISTENER, // Deprecated. Autogenerated by .aidl now. + ADD_WINDOW_INFOS_LISTENER, // Deprecated. Autogenerated by .aidl now. + REMOVE_WINDOW_INFOS_LISTENER, // Deprecated. Autogenerated by .aidl now. + GET_PRIMARY_PHYSICAL_DISPLAY_ID, // Deprecated. Autogenerated by .aidl now. GET_DISPLAY_DECORATION_SUPPORT, GET_BOOT_DISPLAY_MODE_SUPPORT, // Deprecated. Autogenerated by .aidl now. - SET_BOOT_DISPLAY_MODE, - CLEAR_BOOT_DISPLAY_MODE, // Deprecated. Autogenerated by .aidl now. - SET_OVERRIDE_FRAME_RATE, + SET_BOOT_DISPLAY_MODE, // Deprecated. Autogenerated by .aidl now. + CLEAR_BOOT_DISPLAY_MODE, // Deprecated. Autogenerated by .aidl now. + SET_OVERRIDE_FRAME_RATE, // Deprecated. Autogenerated by .aidl now. // Always append new enum to the end. }; diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h deleted file mode 100644 index 9e9e191480..0000000000 --- a/libs/gui/include/gui/ISurfaceComposerClient.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <binder/IInterface.h> -#include <binder/SafeInterface.h> -#include <gui/LayerMetadata.h> -#include <ui/PixelFormat.h> - -#include <unordered_map> - -namespace android { - -class FrameStats; -class IGraphicBufferProducer; - -class ISurfaceComposerClient : public IInterface { -public: - DECLARE_META_INTERFACE(SurfaceComposerClient) - - // flags for createSurface() - enum { // (keep in sync with SurfaceControl.java) - eHidden = 0x00000004, - eDestroyBackbuffer = 0x00000020, - eSkipScreenshot = 0x00000040, - eSecure = 0x00000080, - eNonPremultiplied = 0x00000100, - eOpaque = 0x00000400, - eProtectedByApp = 0x00000800, - eProtectedByDRM = 0x00001000, - eCursorWindow = 0x00002000, - eNoColorFill = 0x00004000, - - eFXSurfaceBufferQueue = 0x00000000, - eFXSurfaceEffect = 0x00020000, - eFXSurfaceBufferState = 0x00040000, - eFXSurfaceContainer = 0x00080000, - eFXSurfaceMask = 0x000F0000, - }; - - // TODO(b/172002646): Clean up the Surface Creation Arguments - /* - * Requires ACCESS_SURFACE_FLINGER permission - */ - virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags, const sp<IBinder>& parent, - LayerMetadata metadata, sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId, - uint32_t* outTransformHint) = 0; - - /* - * Requires ACCESS_SURFACE_FLINGER permission - */ - virtual status_t createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h, - PixelFormat format, uint32_t flags, - const sp<IGraphicBufferProducer>& parent, - LayerMetadata metadata, sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId, - uint32_t* outTransformHint) = 0; - - /* - * Requires ACCESS_SURFACE_FLINGER permission - */ - virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const = 0; - - /* - * Requires ACCESS_SURFACE_FLINGER permission - */ - virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0; - - virtual status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle, - int32_t* outLayerId) = 0; -}; - -class BnSurfaceComposerClient : public SafeBnInterface<ISurfaceComposerClient> { -public: - BnSurfaceComposerClient() - : SafeBnInterface<ISurfaceComposerClient>("BnSurfaceComposerClient") {} - - status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override; -}; - -} // namespace android diff --git a/libs/gui/include/gui/LayerDebugInfo.h b/libs/gui/include/gui/LayerDebugInfo.h index af834d78df..dbb80e583c 100644 --- a/libs/gui/include/gui/LayerDebugInfo.h +++ b/libs/gui/include/gui/LayerDebugInfo.h @@ -25,7 +25,7 @@ #include <string> #include <math/vec4.h> -namespace android { +namespace android::gui { /* Class for transporting debug info from SurfaceFlinger to authorized * recipients. The class is intended to be a data container. There are @@ -52,7 +52,7 @@ public: uint32_t mZ = 0 ; int32_t mWidth = -1; int32_t mHeight = -1; - Rect mCrop = Rect::INVALID_RECT; + android::Rect mCrop = android::Rect::INVALID_RECT; half4 mColor = half4(1.0_hf, 1.0_hf, 1.0_hf, 0.0_hf); uint32_t mFlags = 0; PixelFormat mPixelFormat = PIXEL_FORMAT_NONE; @@ -71,4 +71,4 @@ public: std::string to_string(const LayerDebugInfo& info); -} // namespace android +} // namespace android::gui diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h index 27f4d379e9..5af598956b 100644 --- a/libs/gui/include/gui/LayerMetadata.h +++ b/libs/gui/include/gui/LayerMetadata.h @@ -20,7 +20,7 @@ #include <unordered_map> -namespace android { +namespace android::gui { enum { METADATA_OWNER_UID = 1, @@ -69,4 +69,13 @@ enum class GameMode : int32_t { ftl_last = Battery }; -} // namespace android +} // namespace android::gui + +using android::gui::METADATA_ACCESSIBILITY_ID; +using android::gui::METADATA_DEQUEUE_TIME; +using android::gui::METADATA_GAME_MODE; +using android::gui::METADATA_MOUSE_CURSOR; +using android::gui::METADATA_OWNER_PID; +using android::gui::METADATA_OWNER_UID; +using android::gui::METADATA_TASK_ID; +using android::gui::METADATA_WINDOW_TYPE; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 0a9b75a7f1..f3701e8522 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -21,6 +21,7 @@ #include <stdint.h> #include <sys/types.h> +#include <android/gui/IWindowInfosReportedListener.h> #include <android/native_window.h> #include <gui/IGraphicBufferProducer.h> #include <gui/ITransactionCompletedListener.h> @@ -51,7 +52,9 @@ namespace android { class Parcel; -class ISurfaceComposerClient; + +using gui::ISurfaceComposerClient; +using gui::LayerMetadata; struct client_cache_t { wp<IBinder> token = nullptr; @@ -153,7 +156,7 @@ struct layer_state_t { eLayerStackChanged = 0x00000080, eDimmingEnabledChanged = 0x00000400, eShadowRadiusChanged = 0x00000800, - /* unused 0x00001000, */ + eRenderBorderChanged = 0x00001000, eBufferCropChanged = 0x00002000, eRelativeLayerChanged = 0x00004000, eReparent = 0x00008000, @@ -163,7 +166,7 @@ struct layer_state_t { eTransformToDisplayInverseChanged = 0x00080000, eCropChanged = 0x00100000, eBufferChanged = 0x00200000, - /* unused 0x00400000, */ + eDefaultFrameRateCompatibilityChanged = 0x00400000, eDataspaceChanged = 0x00800000, eHdrMetadataChanged = 0x01000000, eSurfaceDamageRegionChanged = 0x02000000, @@ -273,6 +276,9 @@ struct layer_state_t { int8_t frameRateCompatibility; int8_t changeFrameRateStrategy; + // Default frame rate compatibility used to set the layer refresh rate votetype. + int8_t defaultFrameRateCompatibility; + // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that // the graphic producers should receive a transform hint as if the @@ -291,6 +297,11 @@ struct layer_state_t { // should be trusted for input occlusion detection purposes bool isTrustedOverlay; + // Flag to indicate if border needs to be enabled on the layer + bool borderEnabled; + float borderWidth; + half4 borderColor; + // Stretch effect to be applied to this layer StretchEffect stretchEffect; @@ -352,7 +363,9 @@ struct DisplayState { struct InputWindowCommands { std::vector<gui::FocusRequest> focusRequests; - bool syncInputWindows{false}; + std::unordered_set<sp<gui::IWindowInfosReportedListener>, + SpHash<gui::IWindowInfosReportedListener>> + windowInfosReportedListeners; // Merges the passed in commands and returns true if there were any changes. bool merge(const InputWindowCommands& other); diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index ab9ebaa882..267c28fde2 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -17,8 +17,8 @@ #ifndef ANDROID_GUI_SURFACE_H #define ANDROID_GUI_SURFACE_H +#include <android/gui/FrameTimelineInfo.h> #include <gui/BufferQueueDefs.h> -#include <gui/FrameTimelineInfo.h> #include <gui/HdrMetadata.h> #include <gui/IGraphicBufferProducer.h> #include <gui/IProducerListener.h> @@ -41,6 +41,8 @@ class ISurfaceComposer; class ISurfaceComposer; +using gui::FrameTimelineInfo; + /* This is the same as ProducerListener except that onBuffersDiscarded is * called with a vector of graphic buffers instead of buffer slots. */ diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index b598b43403..24399ffbf0 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -38,6 +38,9 @@ #include <ui/GraphicTypes.h> #include <ui/PixelFormat.h> #include <ui/Rotation.h> +#include <ui/StaticDisplayInfo.h> + +#include <android/gui/ISurfaceComposerClient.h> #include <gui/CpuConsumer.h> #include <gui/ISurfaceComposer.h> @@ -52,14 +55,15 @@ namespace android { class HdrCapabilities; -class ISurfaceComposerClient; class IGraphicBufferProducer; class ITunnelModeEnabledListener; class Region; using gui::DisplayCaptureArgs; using gui::IRegionSamplingListener; +using gui::ISurfaceComposerClient; using gui::LayerCaptureArgs; +using gui::LayerMetadata; struct SurfaceControlStats { SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime, @@ -215,7 +219,7 @@ public: /** * Gets the context priority of surface flinger's render engine. */ - static int getGPUContextPriority(); + static int getGpuContextPriority(); /** * Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is @@ -311,7 +315,7 @@ public: uint32_t w, // width in pixel uint32_t h, // height in pixel PixelFormat format, // pixel-format desired - uint32_t flags = 0, // usage flags + int32_t flags = 0, // usage flags const sp<IBinder>& parentHandle = nullptr, // parentHandle LayerMetadata metadata = LayerMetadata(), // metadata uint32_t* outTransformHint = nullptr); @@ -321,21 +325,11 @@ public: uint32_t h, // height in pixel PixelFormat format, // pixel-format desired sp<SurfaceControl>* outSurface, - uint32_t flags = 0, // usage flags + int32_t flags = 0, // usage flags const sp<IBinder>& parentHandle = nullptr, // parentHandle LayerMetadata metadata = LayerMetadata(), // metadata uint32_t* outTransformHint = nullptr); - //! Create a surface - sp<SurfaceControl> createWithSurfaceParent(const String8& name, // name of the surface - uint32_t w, // width in pixel - uint32_t h, // height in pixel - PixelFormat format, // pixel-format desired - uint32_t flags = 0, // usage flags - Surface* parent = nullptr, // parent - LayerMetadata metadata = LayerMetadata(), // metadata - uint32_t* outTransformHint = nullptr); - // Creates a mirrored hierarchy for the mirrorFromSurface. This returns a SurfaceControl // which is a parent of the root of the mirrored hierarchy. // @@ -393,9 +387,27 @@ public: std::unordered_set<sp<SurfaceControl>, SCHash> surfaceControls; }; + // TODO(b/222421815) this class should be removed when + // SurfaceComposerClient::Transaction::syncInputWindows is removed and replaced with a method + // for adding callbacks to InputWindowCommands. + class Event { + private: + static constexpr std::chrono::seconds sTimeout{5}; + + bool mComplete = false; + std::condition_variable mConditionVariable; + std::mutex mMutex; + + public: + void set(); + bool wait(); + }; + class Transaction : public Parcelable { private: void releaseBufferIfOverwriting(const layer_state_t& state); + static void mergeFrameTimelineInfo(FrameTimelineInfo& t, const FrameTimelineInfo& other); + static void clearFrameTimelineInfo(FrameTimelineInfo& t); protected: std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> mComposerStates; @@ -440,6 +452,8 @@ public: InputWindowCommands mInputWindowCommands; int mStatus = NO_ERROR; + std::shared_ptr<Event> mWindowInfosReportedEvent = nullptr; + layer_state_t* getLayerState(const sp<SurfaceControl>& sc); DisplayState& getDisplayState(const sp<IBinder>& token); @@ -587,6 +601,9 @@ public: Transaction& setFrameRate(const sp<SurfaceControl>& sc, float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy); + Transaction& setDefaultFrameRateCompatibility(const sp<SurfaceControl>& sc, + int8_t compatibility); + // Set by window manager indicating the layer and all its children are // in a different orientation than the display. The hint suggests that // the graphic producers should receive a transform hint as if the @@ -633,6 +650,9 @@ public: const Rect& destinationFrame); Transaction& setDropInputMode(const sp<SurfaceControl>& sc, gui::DropInputMode mode); + Transaction& enableBorder(const sp<SurfaceControl>& sc, bool shouldEnable, float width, + const half4& color); + status_t setDisplaySurface(const sp<IBinder>& token, const sp<IGraphicBufferProducer>& bufferProducer); diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h index b72cf8390e..e4a1350643 100644 --- a/libs/gui/include/gui/SurfaceControl.h +++ b/libs/gui/include/gui/SurfaceControl.h @@ -24,11 +24,12 @@ #include <utils/RefBase.h> #include <utils/threads.h> +#include <android/gui/ISurfaceComposerClient.h> + #include <ui/FrameStats.h> #include <ui/PixelFormat.h> #include <ui/Region.h> -#include <gui/ISurfaceComposerClient.h> #include <math/vec3.h> namespace android { @@ -93,8 +94,7 @@ public: explicit SurfaceControl(const sp<SurfaceControl>& other); SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle, - const sp<IGraphicBufferProducer>& gbp, int32_t layerId, - uint32_t width = 0, uint32_t height = 0, PixelFormat format = 0, + int32_t layerId, uint32_t width = 0, uint32_t height = 0, PixelFormat format = 0, uint32_t transformHint = 0, uint32_t flags = 0); sp<SurfaceControl> getParentingLayer(); @@ -115,8 +115,7 @@ private: status_t validate() const; sp<SurfaceComposerClient> mClient; - sp<IBinder> mHandle; - sp<IGraphicBufferProducer> mGraphicBufferProducer; + sp<IBinder> mHandle; mutable Mutex mLock; mutable sp<Surface> mSurfaceData; mutable sp<BLASTBufferQueue> mBbq; diff --git a/libs/gui/include/gui/TraceUtils.h b/libs/gui/include/gui/TraceUtils.h index e5d268445c..00096158e7 100644 --- a/libs/gui/include/gui/TraceUtils.h +++ b/libs/gui/include/gui/TraceUtils.h @@ -27,6 +27,8 @@ #define ATRACE_FORMAT_BEGIN(fmt, ...) TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__) +#define ATRACE_FORMAT_INSTANT(fmt, ...) TraceUtils::intantFormat(fmt, ##__VA_ARGS__) + namespace android { class TraceUtils { @@ -50,6 +52,20 @@ public: ATRACE_BEGIN(buf); } + static void intantFormat(const char* fmt, ...) { + if (CC_LIKELY(!ATRACE_ENABLED())) return; + + const int BUFFER_SIZE = 256; + va_list ap; + char buf[BUFFER_SIZE]; + + va_start(ap, fmt); + vsnprintf(buf, BUFFER_SIZE, fmt, ap); + va_end(ap); + + ATRACE_INSTANT(buf); + } + }; // class TraceUtils } /* namespace android */ diff --git a/libs/gui/include/gui/VsyncEventData.h b/libs/gui/include/gui/VsyncEventData.h index 8e99539fe9..dfdae214d2 100644 --- a/libs/gui/include/gui/VsyncEventData.h +++ b/libs/gui/include/gui/VsyncEventData.h @@ -16,7 +16,7 @@ #pragma once -#include <gui/FrameTimelineInfo.h> +#include <android/gui/FrameTimelineInfo.h> #include <array> diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h index 169f7f022b..ac74c8a91f 100644 --- a/libs/gui/include/gui/WindowInfo.h +++ b/libs/gui/include/gui/WindowInfo.h @@ -171,6 +171,8 @@ struct WindowInfo : public Parcelable { static_cast<uint32_t>(os::InputConfig::SPY), INTERCEPTS_STYLUS = static_cast<uint32_t>(os::InputConfig::INTERCEPTS_STYLUS), + CLONE = + static_cast<uint32_t>(os::InputConfig::CLONE), // clang-format on }; @@ -236,8 +238,6 @@ struct WindowInfo : public Parcelable { void setInputConfig(ftl::Flags<InputConfig> config, bool value); - bool isClone = false; - void addTouchableRegion(const Rect& region); bool touchableRegionContainsPoint(int32_t x, int32_t y) const; diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h index 3b4aed442e..2754442a95 100644 --- a/libs/gui/include/gui/WindowInfosListenerReporter.h +++ b/libs/gui/include/gui/WindowInfosListenerReporter.h @@ -17,15 +17,14 @@ #pragma once #include <android/gui/BnWindowInfosListener.h> +#include <android/gui/ISurfaceComposer.h> #include <android/gui/IWindowInfosReportedListener.h> #include <binder/IBinder.h> -#include <gui/ISurfaceComposer.h> #include <gui/SpHash.h> #include <gui/WindowInfosListener.h> #include <unordered_set> namespace android { -class ISurfaceComposer; class WindowInfosListenerReporter : public gui::BnWindowInfosListener { public: @@ -33,17 +32,17 @@ public: binder::Status onWindowInfosChanged(const std::vector<gui::WindowInfo>&, const std::vector<gui::DisplayInfo>&, const sp<gui::IWindowInfosReportedListener>&) override; - status_t addWindowInfosListener( - const sp<gui::WindowInfosListener>& windowInfosListener, const sp<ISurfaceComposer>&, + const sp<gui::WindowInfosListener>& windowInfosListener, + const sp<gui::ISurfaceComposer>&, std::pair<std::vector<gui::WindowInfo>, std::vector<gui::DisplayInfo>>* outInitialInfo); status_t removeWindowInfosListener(const sp<gui::WindowInfosListener>& windowInfosListener, - const sp<ISurfaceComposer>& surfaceComposer); - void reconnect(const sp<ISurfaceComposer>&); + const sp<gui::ISurfaceComposer>& surfaceComposer); + void reconnect(const sp<gui::ISurfaceComposer>&); private: std::mutex mListenersMutex; - std::unordered_set<sp<gui::WindowInfosListener>, SpHash<gui::WindowInfosListener>> + std::unordered_set<sp<gui::WindowInfosListener>, gui::SpHash<gui::WindowInfosListener>> mWindowInfosListeners GUARDED_BY(mListenersMutex); std::vector<gui::WindowInfo> mLastWindowInfos GUARDED_BY(mListenersMutex); diff --git a/libs/gui/include/private/gui/ComposerServiceAIDL.h b/libs/gui/include/private/gui/ComposerServiceAIDL.h index 9a96976c0f..296358329b 100644 --- a/libs/gui/include/private/gui/ComposerServiceAIDL.h +++ b/libs/gui/include/private/gui/ComposerServiceAIDL.h @@ -20,6 +20,7 @@ #include <sys/types.h> #include <android/gui/ISurfaceComposer.h> +#include <ui/DisplayId.h> #include <utils/Singleton.h> #include <utils/StrongPointer.h> diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index fc68ad27c5..7b37b25a61 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -24,6 +24,7 @@ cc_test { "BLASTBufferQueue_test.cpp", "BufferItemConsumer_test.cpp", "BufferQueue_test.cpp", + "CompositorTiming_test.cpp", "CpuConsumer_test.cpp", "EndToEndNativeInputTest.cpp", "DisplayInfo_test.cpp", diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp index b993289e6a..3e563b2aa2 100644 --- a/libs/gui/tests/BLASTBufferQueue_test.cpp +++ b/libs/gui/tests/BLASTBufferQueue_test.cpp @@ -19,6 +19,7 @@ #include <gui/BLASTBufferQueue.h> #include <android/hardware/graphics/common/1.2/types.h> +#include <gui/AidlStatusUtil.h> #include <gui/BufferQueueCore.h> #include <gui/BufferQueueProducer.h> #include <gui/FrameTimestamps.h> @@ -305,8 +306,9 @@ protected: const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); binder::Status status = sf->captureDisplay(captureArgs, captureListener); - if (status.transactionError() != NO_ERROR) { - return status.transactionError(); + status_t err = gui::aidl_utils::statusTFromBinderStatus(status); + if (err != NO_ERROR) { + return err; } captureResults = captureListener->waitForResults(); return captureResults.result; @@ -1146,6 +1148,7 @@ TEST_F(BLASTBufferQueueTest, SyncNextTransactionDropBuffer) { ASSERT_EQ(NO_ERROR, captureDisplay(mCaptureArgs, mCaptureResults)); ASSERT_NO_FATAL_FAILURE( checkScreenCapture(r, g, b, {0, 0, (int32_t)mDisplayWidth, (int32_t)mDisplayHeight})); + sync.apply(); } // This test will currently fail because the old surfacecontrol will steal the last presented buffer diff --git a/libs/gui/tests/CompositorTiming_test.cpp b/libs/gui/tests/CompositorTiming_test.cpp new file mode 100644 index 0000000000..d8bb21d582 --- /dev/null +++ b/libs/gui/tests/CompositorTiming_test.cpp @@ -0,0 +1,61 @@ +/* + * Copyright 2022 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 <gtest/gtest.h> +#include <gui/CompositorTiming.h> + +namespace android::test { +namespace { + +constexpr nsecs_t kMillisecond = 1'000'000; +constexpr nsecs_t kVsyncPeriod = 8'333'333; +constexpr nsecs_t kVsyncPhase = -2'166'667; +constexpr nsecs_t kIdealLatency = -kVsyncPhase; + +} // namespace + +TEST(CompositorTimingTest, InvalidVsyncPeriod) { + const nsecs_t vsyncDeadline = systemTime(); + constexpr nsecs_t kInvalidVsyncPeriod = -1; + + const gui::CompositorTiming timing(vsyncDeadline, kInvalidVsyncPeriod, kVsyncPhase, + kIdealLatency); + + EXPECT_EQ(timing.deadline, 0); + EXPECT_EQ(timing.interval, gui::CompositorTiming::kDefaultVsyncPeriod); + EXPECT_EQ(timing.presentLatency, gui::CompositorTiming::kDefaultVsyncPeriod); +} + +TEST(CompositorTimingTest, PresentLatencySnapping) { + for (nsecs_t presentDelay = 0, compositeTime = systemTime(); presentDelay < 10 * kVsyncPeriod; + presentDelay += kMillisecond, compositeTime += kVsyncPeriod) { + const nsecs_t presentLatency = kIdealLatency + presentDelay; + const nsecs_t vsyncDeadline = compositeTime + presentLatency + kVsyncPeriod; + + const gui::CompositorTiming timing(vsyncDeadline, kVsyncPeriod, kVsyncPhase, + presentLatency); + + EXPECT_EQ(timing.deadline, compositeTime + presentDelay + kVsyncPeriod); + EXPECT_EQ(timing.interval, kVsyncPeriod); + + // The presentDelay should be rounded to a multiple of the VSYNC period, such that the + // remainder (presentLatency % interval) always evaluates to the VSYNC phase offset. + EXPECT_GE(timing.presentLatency, kIdealLatency); + EXPECT_EQ(timing.presentLatency % timing.interval, kIdealLatency); + } +} + +} // namespace android::test diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp index c9106bed4c..b18b544257 100644 --- a/libs/gui/tests/RegionSampling_test.cpp +++ b/libs/gui/tests/RegionSampling_test.cpp @@ -19,14 +19,16 @@ #include <android/gui/BnRegionSamplingListener.h> #include <binder/ProcessState.h> +#include <gui/AidlStatusUtil.h> #include <gui/DisplayEventReceiver.h> #include <gui/ISurfaceComposer.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> -#include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <utils/Looper.h> using namespace std::chrono_literals; +using android::gui::aidl_utils::statusTFromBinderStatus; namespace android::test { @@ -242,24 +244,33 @@ protected: }; TEST_F(RegionSamplingTest, invalidLayerHandle_doesNotCrash) { - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); sp<Listener> listener = new Listener(); - const Rect sampleArea{100, 100, 200, 200}; + gui::ARect sampleArea; + sampleArea.left = 100; + sampleArea.top = 100; + sampleArea.right = 200; + sampleArea.bottom = 200; // Passing in composer service as the layer handle should not crash, we'll // treat it as a layer that no longer exists and silently allow sampling to // occur. - status_t status = composer->addRegionSamplingListener(sampleArea, - IInterface::asBinder(composer), listener); - ASSERT_EQ(NO_ERROR, status); + binder::Status status = + composer->addRegionSamplingListener(sampleArea, IInterface::asBinder(composer), + listener); + ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status)); composer->removeRegionSamplingListener(listener); } TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) { fill_render(rgba_green); - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); sp<Listener> listener = new Listener(); - const Rect sampleArea{100, 100, 200, 200}; + gui::ARect sampleArea; + sampleArea.left = 100; + sampleArea.top = 100; + sampleArea.right = 200; + sampleArea.bottom = 200; composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; @@ -271,9 +282,13 @@ TEST_F(RegionSamplingTest, DISABLED_CollectsLuma) { TEST_F(RegionSamplingTest, DISABLED_CollectsChangingLuma) { fill_render(rgba_green); - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); sp<Listener> listener = new Listener(); - const Rect sampleArea{100, 100, 200, 200}; + gui::ARect sampleArea; + sampleArea.left = 100; + sampleArea.top = 100; + sampleArea.right = 200; + sampleArea.bottom = 200; composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; @@ -291,13 +306,21 @@ TEST_F(RegionSamplingTest, DISABLED_CollectsChangingLuma) { TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) { fill_render(rgba_green); - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); sp<Listener> greenListener = new Listener(); - const Rect greenSampleArea{100, 100, 200, 200}; + gui::ARect greenSampleArea; + greenSampleArea.left = 100; + greenSampleArea.top = 100; + greenSampleArea.right = 200; + greenSampleArea.bottom = 200; composer->addRegionSamplingListener(greenSampleArea, mTopLayer->getHandle(), greenListener); sp<Listener> grayListener = new Listener(); - const Rect graySampleArea{500, 100, 600, 200}; + gui::ARect graySampleArea; + graySampleArea.left = 500; + graySampleArea.top = 100; + graySampleArea.right = 600; + graySampleArea.bottom = 200; composer->addRegionSamplingListener(graySampleArea, mTopLayer->getHandle(), grayListener); EXPECT_TRUE(grayListener->wait_event(300ms)) @@ -312,29 +335,49 @@ TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromTwoRegions) { } TEST_F(RegionSamplingTest, DISABLED_TestIfInvalidInputParameters) { - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); sp<Listener> listener = new Listener(); - const Rect sampleArea{100, 100, 200, 200}; + + gui::ARect invalidRect; + invalidRect.left = Rect::INVALID_RECT.left; + invalidRect.top = Rect::INVALID_RECT.top; + invalidRect.right = Rect::INVALID_RECT.right; + invalidRect.bottom = Rect::INVALID_RECT.bottom; + + gui::ARect sampleArea; + sampleArea.left = 100; + sampleArea.top = 100; + sampleArea.right = 200; + sampleArea.bottom = 200; // Invalid input sampleArea EXPECT_EQ(BAD_VALUE, - composer->addRegionSamplingListener(Rect::INVALID_RECT, mTopLayer->getHandle(), - listener)); + statusTFromBinderStatus(composer->addRegionSamplingListener(invalidRect, + mTopLayer->getHandle(), + listener))); listener->reset(); // Invalid input binder - EXPECT_EQ(NO_ERROR, composer->addRegionSamplingListener(sampleArea, NULL, listener)); + EXPECT_EQ(NO_ERROR, + statusTFromBinderStatus( + composer->addRegionSamplingListener(sampleArea, NULL, listener))); // Invalid input listener EXPECT_EQ(BAD_VALUE, - composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), NULL)); - EXPECT_EQ(BAD_VALUE, composer->removeRegionSamplingListener(NULL)); + statusTFromBinderStatus(composer->addRegionSamplingListener(sampleArea, + mTopLayer->getHandle(), + NULL))); + EXPECT_EQ(BAD_VALUE, statusTFromBinderStatus(composer->removeRegionSamplingListener(NULL))); // remove the listener composer->removeRegionSamplingListener(listener); } TEST_F(RegionSamplingTest, DISABLED_TestCallbackAfterRemoveListener) { fill_render(rgba_green); - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); sp<Listener> listener = new Listener(); - const Rect sampleArea{100, 100, 200, 200}; + gui::ARect sampleArea; + sampleArea.left = 100; + sampleArea.top = 100; + sampleArea.right = 200; + sampleArea.bottom = 200; composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); fill_render(rgba_green); @@ -349,13 +392,18 @@ TEST_F(RegionSamplingTest, DISABLED_TestCallbackAfterRemoveListener) { } TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromMovingLayer) { - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); sp<Listener> listener = new Listener(); Rect sampleArea{100, 100, 200, 200}; + gui::ARect sampleAreaA; + sampleAreaA.left = sampleArea.left; + sampleAreaA.top = sampleArea.top; + sampleAreaA.right = sampleArea.right; + sampleAreaA.bottom = sampleArea.bottom; // Test: listener in (100, 100). See layer before move, no layer after move. fill_render(rgba_blue); - composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + composer->addRegionSamplingListener(sampleAreaA, mTopLayer->getHandle(), listener); EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; EXPECT_NEAR(listener->luma(), luma_blue, error_margin); listener->reset(); @@ -367,7 +415,11 @@ TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromMovingLayer) { // Test: listener offset to (600, 600). No layer before move, see layer after move. fill_render(rgba_green); sampleArea.offsetTo(600, 600); - composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener); + sampleAreaA.left = sampleArea.left; + sampleAreaA.top = sampleArea.top; + sampleAreaA.right = sampleArea.right; + sampleAreaA.bottom = sampleArea.bottom; + composer->addRegionSamplingListener(sampleAreaA, mTopLayer->getHandle(), listener); EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received"; EXPECT_NEAR(listener->luma(), luma_gray, error_margin); listener->reset(); diff --git a/libs/gui/tests/SamplingDemo.cpp b/libs/gui/tests/SamplingDemo.cpp index a083a228a6..f98437b4f8 100644 --- a/libs/gui/tests/SamplingDemo.cpp +++ b/libs/gui/tests/SamplingDemo.cpp @@ -26,7 +26,7 @@ #include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> #include <gui/SurfaceControl.h> -#include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <utils/Trace.h> using namespace std::chrono_literals; @@ -121,10 +121,22 @@ int main(int, const char**) { const Rect backButtonArea{200, 1606, 248, 1654}; sp<android::Button> backButton = new android::Button("BackButton", backButtonArea); - sp<ISurfaceComposer> composer = ComposerService::getComposerService(); - composer->addRegionSamplingListener(homeButtonArea, homeButton->getStopLayerHandle(), + gui::ARect homeButtonAreaA; + homeButtonAreaA.left = 490; + homeButtonAreaA.top = 1606; + homeButtonAreaA.right = 590; + homeButtonAreaA.bottom = 1654; + + gui::ARect backButtonAreaA; + backButtonAreaA.left = 200; + backButtonAreaA.top = 1606; + backButtonAreaA.right = 248; + backButtonAreaA.bottom = 1654; + + sp<gui::ISurfaceComposer> composer = ComposerServiceAIDL::getComposerService(); + composer->addRegionSamplingListener(homeButtonAreaA, homeButton->getStopLayerHandle(), homeButton); - composer->addRegionSamplingListener(backButtonArea, backButton->getStopLayerHandle(), + composer->addRegionSamplingListener(backButtonAreaA, backButton->getStopLayerHandle(), backButton); ProcessState::self()->startThreadPool(); diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index 065cd7a5c7..391a0aa7d4 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -24,6 +24,7 @@ #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <binder/ProcessState.h> #include <configstore/Utils.h> +#include <gui/AidlStatusUtil.h> #include <gui/BufferItemConsumer.h> #include <gui/IProducerListener.h> #include <gui/ISurfaceComposer.h> @@ -212,8 +213,9 @@ protected: const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); binder::Status status = sf->captureDisplay(captureArgs, captureListener); - if (status.transactionError() != NO_ERROR) { - return status.transactionError(); + status_t err = gui::aidl_utils::statusTFromBinderStatus(status); + if (err != NO_ERROR) { + return err; } captureResults = captureListener->waitForResults(); return captureResults.result; @@ -690,11 +692,6 @@ public: mSupportsPresent = supportsPresent; } - sp<ISurfaceComposerClient> createConnection() override { return nullptr; } - sp<IDisplayEventConnection> createDisplayEventConnection( - ISurfaceComposer::VsyncSource, ISurfaceComposer::EventRegistrationFlags) override { - return nullptr; - } status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/, const Vector<ComposerState>& /*state*/, const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/, @@ -708,260 +705,236 @@ public: return NO_ERROR; } - void bootFinished() override {} - bool authenticateSurfaceTexture( - const sp<IGraphicBufferProducer>& /*surface*/) const override { - return false; - } +protected: + IBinder* onAsBinder() override { return nullptr; } - status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) - const override { - *outSupported = { - FrameEvent::REQUESTED_PRESENT, - FrameEvent::ACQUIRE, - FrameEvent::LATCH, - FrameEvent::FIRST_REFRESH_START, - FrameEvent::LAST_REFRESH_START, - FrameEvent::GPU_COMPOSITION_DONE, - FrameEvent::DEQUEUE_READY, - FrameEvent::RELEASE - }; - if (mSupportsPresent) { - outSupported->push_back( - FrameEvent::DISPLAY_PRESENT); - } - return NO_ERROR; - } +private: + bool mSupportsPresent{true}; +}; - status_t getStaticDisplayInfo(const sp<IBinder>& /*display*/, ui::StaticDisplayInfo*) override { - return NO_ERROR; - } - status_t getDynamicDisplayInfo(const sp<IBinder>& /*display*/, - ui::DynamicDisplayInfo*) override { - return NO_ERROR; - } - status_t getDisplayNativePrimaries(const sp<IBinder>& /*display*/, - ui::DisplayPrimaries& /*primaries*/) override { - return NO_ERROR; - } - status_t setActiveColorMode(const sp<IBinder>& /*display*/, ColorMode /*colorMode*/) override { - return NO_ERROR; - } - status_t setBootDisplayMode(const sp<IBinder>& /*display*/, ui::DisplayModeId /*id*/) override { - return NO_ERROR; +class FakeSurfaceComposerAIDL : public gui::ISurfaceComposer { +public: + ~FakeSurfaceComposerAIDL() override {} + + void setSupportsPresent(bool supportsPresent) { mSupportsPresent = supportsPresent; } + + binder::Status bootFinished() override { return binder::Status::ok(); } + + binder::Status createDisplayEventConnection( + VsyncSource /*vsyncSource*/, EventRegistration /*eventRegistration*/, + sp<gui::IDisplayEventConnection>* outConnection) override { + *outConnection = nullptr; + return binder::Status::ok(); } - status_t clearAnimationFrameStats() override { return NO_ERROR; } - status_t getAnimationFrameStats(FrameStats* /*outStats*/) const override { - return NO_ERROR; + binder::Status createConnection(sp<gui::ISurfaceComposerClient>* outClient) override { + *outClient = nullptr; + return binder::Status::ok(); } - status_t overrideHdrTypes(const sp<IBinder>& /*display*/, - const std::vector<ui::Hdr>& /*hdrTypes*/) override { - return NO_ERROR; + + binder::Status createDisplay(const std::string& /*displayName*/, bool /*secure*/, + sp<IBinder>* /*outDisplay*/) override { + return binder::Status::ok(); } - status_t onPullAtom(const int32_t /*atomId*/, std::string* /*outData*/, - bool* /*success*/) override { - return NO_ERROR; + + binder::Status destroyDisplay(const sp<IBinder>& /*display*/) override { + return binder::Status::ok(); } - status_t enableVSyncInjections(bool /*enable*/) override { - return NO_ERROR; + + binder::Status getPhysicalDisplayIds(std::vector<int64_t>* /*outDisplayIds*/) override { + return binder::Status::ok(); } - status_t injectVSync(nsecs_t /*when*/) override { return NO_ERROR; } - status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* /*layers*/) override { - return NO_ERROR; + + binder::Status getPrimaryPhysicalDisplayId(int64_t* /*outDisplayId*/) override { + return binder::Status::ok(); } - status_t getCompositionPreference( - ui::Dataspace* /*outDefaultDataspace*/, ui::PixelFormat* /*outDefaultPixelFormat*/, - ui::Dataspace* /*outWideColorGamutDataspace*/, - ui::PixelFormat* /*outWideColorGamutPixelFormat*/) const override { - return NO_ERROR; + + binder::Status getPhysicalDisplayToken(int64_t /*displayId*/, + sp<IBinder>* /*outDisplay*/) override { + return binder::Status::ok(); } - status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& /*display*/, - ui::PixelFormat* /*outFormat*/, - ui::Dataspace* /*outDataspace*/, - uint8_t* /*outComponentMask*/) const override { - return NO_ERROR; + + binder::Status setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override { + return binder::Status::ok(); } - status_t setDisplayContentSamplingEnabled(const sp<IBinder>& /*display*/, bool /*enable*/, - uint8_t /*componentMask*/, - uint64_t /*maxFrames*/) override { - return NO_ERROR; + + binder::Status getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) override { + *outSupported = {FrameEvent::REQUESTED_PRESENT, + FrameEvent::ACQUIRE, + FrameEvent::LATCH, + FrameEvent::FIRST_REFRESH_START, + FrameEvent::LAST_REFRESH_START, + FrameEvent::GPU_COMPOSITION_DONE, + FrameEvent::DEQUEUE_READY, + FrameEvent::RELEASE}; + if (mSupportsPresent) { + outSupported->push_back(FrameEvent::DISPLAY_PRESENT); + } + return binder::Status::ok(); } - status_t getDisplayedContentSample(const sp<IBinder>& /*display*/, uint64_t /*maxFrames*/, - uint64_t /*timestamp*/, - DisplayedFrameStats* /*outStats*/) const override { - return NO_ERROR; + + binder::Status getDisplayStats(const sp<IBinder>& /*display*/, + gui::DisplayStatInfo* /*outStatInfo*/) override { + return binder::Status::ok(); } - status_t getColorManagement(bool* /*outGetColorManagement*/) const override { return NO_ERROR; } - status_t getProtectedContentSupport(bool* /*outSupported*/) const override { return NO_ERROR; } + binder::Status getDisplayState(const sp<IBinder>& /*display*/, + gui::DisplayState* /*outState*/) override { + return binder::Status::ok(); + } - status_t addRegionSamplingListener(const Rect& /*samplingArea*/, - const sp<IBinder>& /*stopLayerHandle*/, - const sp<IRegionSamplingListener>& /*listener*/) override { - return NO_ERROR; + binder::Status getStaticDisplayInfo(const sp<IBinder>& /*display*/, + gui::StaticDisplayInfo* /*outInfo*/) override { + return binder::Status::ok(); } - status_t removeRegionSamplingListener( - const sp<IRegionSamplingListener>& /*listener*/) override { - return NO_ERROR; + + binder::Status getDynamicDisplayInfo(const sp<IBinder>& /*display*/, + gui::DynamicDisplayInfo* /*outInfo*/) override { + return binder::Status::ok(); } - status_t addFpsListener(int32_t /*taskId*/, const sp<gui::IFpsListener>& /*listener*/) { - return NO_ERROR; + + binder::Status getDisplayNativePrimaries(const sp<IBinder>& /*display*/, + gui::DisplayPrimaries* /*outPrimaries*/) override { + return binder::Status::ok(); } - status_t removeFpsListener(const sp<gui::IFpsListener>& /*listener*/) { return NO_ERROR; } - status_t addTunnelModeEnabledListener(const sp<gui::ITunnelModeEnabledListener>& /*listener*/) { - return NO_ERROR; + binder::Status setActiveColorMode(const sp<IBinder>& /*display*/, int /*colorMode*/) override { + return binder::Status::ok(); } - status_t removeTunnelModeEnabledListener( - const sp<gui::ITunnelModeEnabledListener>& /*listener*/) { - return NO_ERROR; + binder::Status setBootDisplayMode(const sp<IBinder>& /*display*/, + int /*displayModeId*/) override { + return binder::Status::ok(); } - status_t setDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/, - ui::DisplayModeId /*defaultMode*/, - bool /*allowGroupSwitching*/, - float /*primaryRefreshRateMin*/, - float /*primaryRefreshRateMax*/, - float /*appRequestRefreshRateMin*/, - float /*appRequestRefreshRateMax*/) { - return NO_ERROR; + binder::Status clearBootDisplayMode(const sp<IBinder>& /*display*/) override { + return binder::Status::ok(); } - status_t getDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/, - ui::DisplayModeId* /*outDefaultMode*/, - bool* /*outAllowGroupSwitching*/, - float* /*outPrimaryRefreshRateMin*/, - float* /*outPrimaryRefreshRateMax*/, - float* /*outAppRequestRefreshRateMin*/, - float* /*outAppRequestRefreshRateMax*/) override { - return NO_ERROR; - }; - status_t setGlobalShadowSettings(const half4& /*ambientColor*/, const half4& /*spotColor*/, - float /*lightPosY*/, float /*lightPosZ*/, - float /*lightRadius*/) override { - return NO_ERROR; + binder::Status getBootDisplayModeSupport(bool* /*outMode*/) override { + return binder::Status::ok(); } - status_t getDisplayDecorationSupport( - const sp<IBinder>& /*displayToken*/, - std::optional<DisplayDecorationSupport>* /*outSupport*/) const override { - return NO_ERROR; + binder::Status setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override { + return binder::Status::ok(); } - status_t setFrameRate(const sp<IGraphicBufferProducer>& /*surface*/, float /*frameRate*/, - int8_t /*compatibility*/, int8_t /*changeFrameRateStrategy*/) override { - return NO_ERROR; + binder::Status setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override { + return binder::Status::ok(); } - status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& /*surface*/, - const FrameTimelineInfo& /*frameTimelineInfo*/) override { - return NO_ERROR; + binder::Status captureDisplay(const DisplayCaptureArgs&, + const sp<IScreenCaptureListener>&) override { + return binder::Status::ok(); } - status_t addTransactionTraceListener( - const sp<gui::ITransactionTraceListener>& /*listener*/) override { - return NO_ERROR; + binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override { + return binder::Status::ok(); } - int getGPUContextPriority() override { return 0; }; + binder::Status captureLayers(const LayerCaptureArgs&, + const sp<IScreenCaptureListener>&) override { + return binder::Status::ok(); + } - status_t getMaxAcquiredBufferCount(int* /*buffers*/) const override { return NO_ERROR; } + binder::Status clearAnimationFrameStats() override { return binder::Status::ok(); } - status_t addWindowInfosListener( - const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) const override { - return NO_ERROR; + binder::Status getAnimationFrameStats(gui::FrameStats* /*outStats*/) override { + return binder::Status::ok(); } - status_t removeWindowInfosListener( - const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) const override { - return NO_ERROR; + binder::Status overrideHdrTypes(const sp<IBinder>& /*display*/, + const std::vector<int32_t>& /*hdrTypes*/) override { + return binder::Status::ok(); } - status_t setOverrideFrameRate(uid_t /*uid*/, float /*frameRate*/) override { return NO_ERROR; } - -protected: - IBinder* onAsBinder() override { return nullptr; } - -private: - bool mSupportsPresent{true}; -}; + binder::Status onPullAtom(int32_t /*atomId*/, gui::PullAtomData* /*outPullData*/) override { + return binder::Status::ok(); + } -class FakeSurfaceComposerAIDL : public gui::ISurfaceComposer { -public: - ~FakeSurfaceComposerAIDL() override {} + binder::Status enableVSyncInjections(bool /*enable*/) override { return binder::Status::ok(); } - void setSupportsPresent(bool supportsPresent) { mSupportsPresent = supportsPresent; } + binder::Status injectVSync(int64_t /*when*/) override { return binder::Status::ok(); } - binder::Status createDisplay(const std::string& /*displayName*/, bool /*secure*/, - sp<IBinder>* /*outDisplay*/) override { + binder::Status getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* /*outLayers*/) override { return binder::Status::ok(); } - binder::Status destroyDisplay(const sp<IBinder>& /*display*/) override { + binder::Status getColorManagement(bool* /*outGetColorManagement*/) override { return binder::Status::ok(); } - binder::Status getPhysicalDisplayIds(std::vector<int64_t>* /*outDisplayIds*/) override { + binder::Status getCompositionPreference(gui::CompositionPreference* /*outPref*/) override { return binder::Status::ok(); } - binder::Status getPrimaryPhysicalDisplayId(int64_t* /*outDisplayId*/) override { + binder::Status getDisplayedContentSamplingAttributes( + const sp<IBinder>& /*display*/, gui::ContentSamplingAttributes* /*outAttrs*/) override { return binder::Status::ok(); } - binder::Status getPhysicalDisplayToken(int64_t /*displayId*/, - sp<IBinder>* /*outDisplay*/) override { + binder::Status setDisplayContentSamplingEnabled(const sp<IBinder>& /*display*/, bool /*enable*/, + int8_t /*componentMask*/, + int64_t /*maxFrames*/) override { return binder::Status::ok(); } - binder::Status setPowerMode(const sp<IBinder>& /*display*/, int /*mode*/) override { + binder::Status getProtectedContentSupport(bool* /*outSupporte*/) override { return binder::Status::ok(); } - binder::Status getDisplayStats(const sp<IBinder>& /*display*/, - gui::DisplayStatInfo* /*outStatInfo*/) override { + binder::Status getDisplayedContentSample(const sp<IBinder>& /*display*/, int64_t /*maxFrames*/, + int64_t /*timestamp*/, + gui::DisplayedFrameStats* /*outStats*/) override { return binder::Status::ok(); } - binder::Status getDisplayState(const sp<IBinder>& /*display*/, - gui::DisplayState* /*outState*/) override { + binder::Status isWideColorDisplay(const sp<IBinder>& /*token*/, + bool* /*outIsWideColorDisplay*/) override { return binder::Status::ok(); } - binder::Status clearBootDisplayMode(const sp<IBinder>& /*display*/) override { + binder::Status addRegionSamplingListener( + const gui::ARect& /*samplingArea*/, const sp<IBinder>& /*stopLayerHandle*/, + const sp<gui::IRegionSamplingListener>& /*listener*/) override { return binder::Status::ok(); } - binder::Status getBootDisplayModeSupport(bool* /*outMode*/) override { + binder::Status removeRegionSamplingListener( + const sp<gui::IRegionSamplingListener>& /*listener*/) override { return binder::Status::ok(); } - binder::Status setAutoLowLatencyMode(const sp<IBinder>& /*display*/, bool /*on*/) override { + binder::Status addFpsListener(int32_t /*taskId*/, + const sp<gui::IFpsListener>& /*listener*/) override { return binder::Status::ok(); } - binder::Status setGameContentType(const sp<IBinder>& /*display*/, bool /*on*/) override { + binder::Status removeFpsListener(const sp<gui::IFpsListener>& /*listener*/) override { return binder::Status::ok(); } - binder::Status captureDisplay(const DisplayCaptureArgs&, - const sp<IScreenCaptureListener>&) override { + binder::Status addTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& /*listener*/) override { return binder::Status::ok(); } - binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override { + binder::Status removeTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& /*listener*/) override { return binder::Status::ok(); } - binder::Status captureLayers(const LayerCaptureArgs&, - const sp<IScreenCaptureListener>&) override { + binder::Status setDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/, + int32_t /*defaultMode*/, bool /*allowGroupSwitching*/, + float /*primaryRefreshRateMin*/, + float /*primaryRefreshRateMax*/, + float /*appRequestRefreshRateMin*/, + float /*appRequestRefreshRateMax*/) override { return binder::Status::ok(); } - binder::Status isWideColorDisplay(const sp<IBinder>& /*token*/, - bool* /*outIsWideColorDisplay*/) override { + binder::Status getDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/, + gui::DisplayModeSpecs* /*outSpecs*/) override { return binder::Status::ok(); } @@ -989,6 +962,45 @@ public: binder::Status notifyPowerBoost(int /*boostId*/) override { return binder::Status::ok(); } + binder::Status setGlobalShadowSettings(const gui::Color& /*ambientColor*/, + const gui::Color& /*spotColor*/, float /*lightPosY*/, + float /*lightPosZ*/, float /*lightRadius*/) override { + return binder::Status::ok(); + } + + binder::Status getDisplayDecorationSupport( + const sp<IBinder>& /*displayToken*/, + std::optional<gui::DisplayDecorationSupport>* /*outSupport*/) override { + return binder::Status::ok(); + } + + binder::Status setOverrideFrameRate(int32_t /*uid*/, float /*frameRate*/) override { + return binder::Status::ok(); + } + + binder::Status addTransactionTraceListener( + const sp<gui::ITransactionTraceListener>& /*listener*/) override { + return binder::Status::ok(); + } + + binder::Status getGpuContextPriority(int32_t* /*outPriority*/) override { + return binder::Status::ok(); + } + + binder::Status getMaxAcquiredBufferCount(int32_t* /*buffers*/) override { + return binder::Status::ok(); + } + + binder::Status addWindowInfosListener( + const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) override { + return binder::Status::ok(); + } + + binder::Status removeWindowInfosListener( + const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) override { + return binder::Status::ok(); + } + protected: IBinder* onAsBinder() override { return nullptr; } @@ -1034,10 +1046,10 @@ protected: class TestSurface : public Surface { public: - TestSurface(const sp<IGraphicBufferProducer>& bufferProducer, - FenceToFenceTimeMap* fenceMap) - : Surface(bufferProducer), - mFakeSurfaceComposer(new FakeSurfaceComposer) { + TestSurface(const sp<IGraphicBufferProducer>& bufferProducer, FenceToFenceTimeMap* fenceMap) + : Surface(bufferProducer), + mFakeSurfaceComposer(new FakeSurfaceComposer), + mFakeSurfaceComposerAIDL(new FakeSurfaceComposerAIDL) { mFakeFrameEventHistory = new FakeProducerFrameEventHistory(fenceMap); mFrameEventHistory.reset(mFakeFrameEventHistory); } @@ -1048,6 +1060,10 @@ public: return mFakeSurfaceComposer; } + sp<gui::ISurfaceComposer> composerServiceAIDL() const override { + return mFakeSurfaceComposerAIDL; + } + nsecs_t now() const override { return mNow; } @@ -1058,6 +1074,7 @@ public: public: sp<FakeSurfaceComposer> mFakeSurfaceComposer; + sp<FakeSurfaceComposerAIDL> mFakeSurfaceComposerAIDL; nsecs_t mNow = 0; // mFrameEventHistory owns the instance of FakeProducerFrameEventHistory, @@ -1070,20 +1087,30 @@ class GetFrameTimestampsTest : public ::testing::Test { protected: struct FenceAndFenceTime { explicit FenceAndFenceTime(FenceToFenceTimeMap& fenceMap) - : mFence(new Fence), - mFenceTime(fenceMap.createFenceTimeForTest(mFence)) {} - sp<Fence> mFence { nullptr }; - std::shared_ptr<FenceTime> mFenceTime { nullptr }; + : mFenceTime(fenceMap.createFenceTimeForTest(mFence)) {} + + sp<Fence> mFence = sp<Fence>::make(); + std::shared_ptr<FenceTime> mFenceTime; }; + static CompositorTiming makeCompositorTiming(nsecs_t deadline = 1'000'000'000, + nsecs_t interval = 16'666'667, + nsecs_t presentLatency = 50'000'000) { + CompositorTiming timing; + timing.deadline = deadline; + timing.interval = interval; + timing.presentLatency = presentLatency; + return timing; + } + struct RefreshEvents { RefreshEvents(FenceToFenceTimeMap& fenceMap, nsecs_t refreshStart) - : mFenceMap(fenceMap), - kCompositorTiming( - {refreshStart, refreshStart + 1, refreshStart + 2 }), - kStartTime(refreshStart + 3), - kGpuCompositionDoneTime(refreshStart + 4), - kPresentTime(refreshStart + 5) {} + : mFenceMap(fenceMap), + kCompositorTiming( + makeCompositorTiming(refreshStart, refreshStart + 1, refreshStart + 2)), + kStartTime(refreshStart + 3), + kGpuCompositionDoneTime(refreshStart + 4), + kPresentTime(refreshStart + 5) {} void signalPostCompositeFences() { mFenceMap.signalAllForTest( @@ -1093,8 +1120,8 @@ protected: FenceToFenceTimeMap& mFenceMap; - FenceAndFenceTime mGpuCompositionDone { mFenceMap }; - FenceAndFenceTime mPresent { mFenceMap }; + FenceAndFenceTime mGpuCompositionDone{mFenceMap}; + FenceAndFenceTime mPresent{mFenceMap}; const CompositorTiming kCompositorTiming; @@ -1360,11 +1387,7 @@ TEST_F(GetFrameTimestampsTest, DefaultDisabled) { // This test verifies that the frame timestamps are retrieved if explicitly // enabled via native_window_enable_frame_timestamps. TEST_F(GetFrameTimestampsTest, EnabledSimple) { - CompositorTiming initialCompositorTiming { - 1000000000, // 1s deadline - 16666667, // 16ms interval - 50000000, // 50ms present latency - }; + const CompositorTiming initialCompositorTiming = makeCompositorTiming(); mCfeh->initializeCompositorTiming(initialCompositorTiming); enableFrameTimestamps(); @@ -1424,6 +1447,7 @@ TEST_F(GetFrameTimestampsTest, EnabledSimple) { TEST_F(GetFrameTimestampsTest, QueryPresentSupported) { bool displayPresentSupported = true; mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported); + mSurface->mFakeSurfaceComposerAIDL->setSupportsPresent(displayPresentSupported); // Verify supported bits are forwarded. int supportsPresent = -1; @@ -1435,6 +1459,7 @@ TEST_F(GetFrameTimestampsTest, QueryPresentSupported) { TEST_F(GetFrameTimestampsTest, QueryPresentNotSupported) { bool displayPresentSupported = false; mSurface->mFakeSurfaceComposer->setSupportsPresent(displayPresentSupported); + mSurface->mFakeSurfaceComposerAIDL->setSupportsPresent(displayPresentSupported); // Verify supported bits are forwarded. int supportsPresent = -1; @@ -1501,11 +1526,7 @@ TEST_F(GetFrameTimestampsTest, SnapToNextTickOverflow) { // This verifies the compositor timing is updated by refresh events // and piggy backed on a queue, dequeue, and enabling of timestamps.. TEST_F(GetFrameTimestampsTest, CompositorTimingUpdatesBasic) { - CompositorTiming initialCompositorTiming { - 1000000000, // 1s deadline - 16666667, // 16ms interval - 50000000, // 50ms present latency - }; + const CompositorTiming initialCompositorTiming = makeCompositorTiming(); mCfeh->initializeCompositorTiming(initialCompositorTiming); enableFrameTimestamps(); @@ -1586,11 +1607,7 @@ TEST_F(GetFrameTimestampsTest, CompositorTimingUpdatesBasic) { // This verifies the compositor deadline properly snaps to the the next // deadline based on the current time. TEST_F(GetFrameTimestampsTest, CompositorTimingDeadlineSnaps) { - CompositorTiming initialCompositorTiming { - 1000000000, // 1s deadline - 16666667, // 16ms interval - 50000000, // 50ms present latency - }; + const CompositorTiming initialCompositorTiming = makeCompositorTiming(); mCfeh->initializeCompositorTiming(initialCompositorTiming); enableFrameTimestamps(); @@ -2012,6 +2029,7 @@ TEST_F(GetFrameTimestampsTest, NoReleaseNoSync) { TEST_F(GetFrameTimestampsTest, PresentUnsupportedNoSync) { enableFrameTimestamps(); mSurface->mFakeSurfaceComposer->setSupportsPresent(false); + mSurface->mFakeSurfaceComposerAIDL->setSupportsPresent(false); // Dequeue and queue frame 1. const uint64_t fId1 = getNextFrameId(); diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp index 99658ccd4b..c51b244c50 100644 --- a/libs/gui/tests/WindowInfo_test.cpp +++ b/libs/gui/tests/WindowInfo_test.cpp @@ -71,7 +71,6 @@ TEST(WindowInfo, Parcelling) { i.applicationInfo.name = "ApplicationFooBar"; i.applicationInfo.token = new BBinder(); i.applicationInfo.dispatchingTimeoutMillis = 0x12345678ABCD; - i.isClone = true; Parcel p; i.writeToParcel(&p); @@ -102,7 +101,6 @@ TEST(WindowInfo, Parcelling) { ASSERT_EQ(i.replaceTouchableRegionWithCrop, i2.replaceTouchableRegionWithCrop); ASSERT_EQ(i.touchableRegionCropHandle, i2.touchableRegionCropHandle); ASSERT_EQ(i.applicationInfo, i2.applicationInfo); - ASSERT_EQ(i.isClone, i2.isClone); } TEST(InputApplicationInfo, Parcelling) { diff --git a/libs/input/Android.bp b/libs/input/Android.bp index b2fec7917b..5030d60da2 100644 --- a/libs/input/Android.bp +++ b/libs/input/Android.bp @@ -26,7 +26,6 @@ package { filegroup { name: "inputconstants_aidl", srcs: [ - "android/os/BlockUntrustedTouchesMode.aidl", "android/os/IInputConstants.aidl", "android/os/InputEventInjectionResult.aidl", "android/os/InputEventInjectionSync.aidl", diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 61950522ff..8d8433b973 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -51,7 +51,7 @@ static const nsecs_t NANOS_PER_MS = 1000000; // Latency added during resampling. A few milliseconds doesn't hurt much but // reduces the impact of mispredicted touch positions. -static const nsecs_t RESAMPLE_LATENCY = 5 * NANOS_PER_MS; +const std::chrono::duration RESAMPLE_LATENCY = 5ms; // Minimum time difference between consecutive samples before attempting to resample. static const nsecs_t RESAMPLE_MIN_DELTA = 2 * NANOS_PER_MS; @@ -721,7 +721,11 @@ android::base::Result<InputPublisher::ConsumerResponse> InputPublisher::receiveC // --- InputConsumer --- InputConsumer::InputConsumer(const std::shared_ptr<InputChannel>& channel) - : mResampleTouch(isTouchResamplingEnabled()), mChannel(channel), mMsgDeferred(false) {} + : InputConsumer(channel, isTouchResamplingEnabled()) {} + +InputConsumer::InputConsumer(const std::shared_ptr<InputChannel>& channel, + bool enableTouchResampling) + : mResampleTouch(enableTouchResampling), mChannel(channel), mMsgDeferred(false) {} InputConsumer::~InputConsumer() { } @@ -751,7 +755,10 @@ status_t InputConsumer::consume(InputEventFactoryInterface* factory, bool consum // Receive a fresh message. status_t result = mChannel->receiveMessage(&mMsg); if (result == OK) { - mConsumeTimes.emplace(mMsg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC)); + const auto [_, inserted] = + mConsumeTimes.emplace(mMsg.header.seq, systemTime(SYSTEM_TIME_MONOTONIC)); + LOG_ALWAYS_FATAL_IF(!inserted, "Already have a consume time for seq=%" PRIu32, + mMsg.header.seq); } if (result) { // Consume the next batched event unless batches are being held for later. @@ -918,7 +925,7 @@ status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory, nsecs_t sampleTime = frameTime; if (mResampleTouch) { - sampleTime -= RESAMPLE_LATENCY; + sampleTime -= std::chrono::nanoseconds(RESAMPLE_LATENCY).count(); } ssize_t split = findSampleNoLaterThan(batch, sampleTime); if (split < 0) { @@ -1166,6 +1173,11 @@ void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, return; } + if (current->eventTime == sampleTime) { + // Prevents having 2 events with identical times and coordinates. + return; + } + // Resample touch coordinates. History oldLastResample; oldLastResample.initializeFrom(touchState.lastResample); diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp index c3f5151fd1..3f8467d818 100644 --- a/libs/input/Keyboard.cpp +++ b/libs/input/Keyboard.cpp @@ -49,25 +49,23 @@ status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier, const PropertyMap* deviceConfiguration) { // Use the configured key layout if available. if (deviceConfiguration) { - String8 keyLayoutName; - if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), - keyLayoutName)) { + std::string keyLayoutName; + if (deviceConfiguration->tryGetProperty("keyboard.layout", keyLayoutName)) { status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " - "it was not found.", - deviceIdentifier.name.c_str(), keyLayoutName.string()); + "it was not found.", + deviceIdentifier.name.c_str(), keyLayoutName.c_str()); } } - String8 keyCharacterMapName; - if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), - keyCharacterMapName)) { + std::string keyCharacterMapName; + if (deviceConfiguration->tryGetProperty("keyboard.characterMap", keyCharacterMapName)) { status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str()); if (status == NAME_NOT_FOUND) { ALOGE("Configuration for keyboard device '%s' requested keyboard character " - "map '%s' but it was not found.", - deviceIdentifier.name.c_str(), keyCharacterMapName.string()); + "map '%s' but it was not found.", + deviceIdentifier.name.c_str(), keyCharacterMapName.c_str()); } } @@ -165,7 +163,7 @@ bool isKeyboardSpecialFunction(const PropertyMap* config) { return false; } bool isSpecialFunction = false; - config->tryGetProperty(String8("keyboard.specialFunction"), isSpecialFunction); + config->tryGetProperty("keyboard.specialFunction", isSpecialFunction); return isSpecialFunction; } @@ -180,8 +178,7 @@ bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, if (deviceConfiguration) { bool builtIn = false; - if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn) - && builtIn) { + if (deviceConfiguration->tryGetProperty("keyboard.builtIn", builtIn) && builtIn) { return true; } } diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp index a842166761..662e568ac0 100644 --- a/libs/input/PropertyMap.cpp +++ b/libs/input/PropertyMap.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "PropertyMap" #include <input/PropertyMap.h> +#include <log/log.h> // Enables debug output for the parser. #define DEBUG_PARSER 0 @@ -39,25 +40,25 @@ void PropertyMap::clear() { mProperties.clear(); } -void PropertyMap::addProperty(const String8& key, const String8& value) { - mProperties.add(key, value); +void PropertyMap::addProperty(const std::string& key, const std::string& value) { + mProperties.emplace(key, value); } -bool PropertyMap::hasProperty(const String8& key) const { - return mProperties.indexOfKey(key) >= 0; +bool PropertyMap::hasProperty(const std::string& key) const { + return mProperties.find(key) != mProperties.end(); } -bool PropertyMap::tryGetProperty(const String8& key, String8& outValue) const { - ssize_t index = mProperties.indexOfKey(key); - if (index < 0) { +bool PropertyMap::tryGetProperty(const std::string& key, std::string& outValue) const { + auto it = mProperties.find(key); + if (it == mProperties.end()) { return false; } - outValue = mProperties.valueAt(index); + outValue = it->second; return true; } -bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const { +bool PropertyMap::tryGetProperty(const std::string& key, bool& outValue) const { int32_t intValue; if (!tryGetProperty(key, intValue)) { return false; @@ -67,34 +68,34 @@ bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const { return true; } -bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const { - String8 stringValue; +bool PropertyMap::tryGetProperty(const std::string& key, int32_t& outValue) const { + std::string stringValue; if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) { return false; } char* end; - int value = strtol(stringValue.string(), &end, 10); + int value = strtol(stringValue.c_str(), &end, 10); if (*end != '\0') { - ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.string(), - stringValue.string()); + ALOGW("Property key '%s' has invalid value '%s'. Expected an integer.", key.c_str(), + stringValue.c_str()); return false; } outValue = value; return true; } -bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const { - String8 stringValue; +bool PropertyMap::tryGetProperty(const std::string& key, float& outValue) const { + std::string stringValue; if (!tryGetProperty(key, stringValue) || stringValue.length() == 0) { return false; } char* end; - float value = strtof(stringValue.string(), &end); + float value = strtof(stringValue.c_str(), &end); if (*end != '\0') { - ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", key.string(), - stringValue.string()); + ALOGW("Property key '%s' has invalid value '%s'. Expected a float.", key.c_str(), + stringValue.c_str()); return false; } outValue = value; @@ -102,8 +103,8 @@ bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const { } void PropertyMap::addAll(const PropertyMap* map) { - for (size_t i = 0; i < map->mProperties.size(); i++) { - mProperties.add(map->mProperties.keyAt(i), map->mProperties.valueAt(i)); + for (const auto& [key, value] : map->mProperties) { + mProperties.emplace(key, value); } } @@ -184,13 +185,13 @@ status_t PropertyMap::Parser::parse() { return BAD_VALUE; } - if (mMap->hasProperty(keyToken)) { + if (mMap->hasProperty(keyToken.string())) { ALOGE("%s: Duplicate property value for key '%s'.", mTokenizer->getLocation().string(), keyToken.string()); return BAD_VALUE; } - mMap->addProperty(keyToken, valueToken); + mMap->addProperty(keyToken.string(), valueToken.string()); } mTokenizer->nextLine(); diff --git a/libs/input/PropertyMap_fuzz.cpp b/libs/input/PropertyMap_fuzz.cpp index afb97a1d47..d985dc1748 100755 --- a/libs/input/PropertyMap_fuzz.cpp +++ b/libs/input/PropertyMap_fuzz.cpp @@ -17,32 +17,22 @@ #include "android-base/file.h" #include "fuzzer/FuzzedDataProvider.h" #include "input/PropertyMap.h" -#include "utils/String8.h" static constexpr int MAX_FILE_SIZE = 256; static constexpr int MAX_STR_LEN = 2048; static constexpr int MAX_OPERATIONS = 1000; -static const std::vector<std::function<void(FuzzedDataProvider*, android::PropertyMap)>> +static const std::vector<std::function<void(FuzzedDataProvider*, android::PropertyMap&)>> operations = { - [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void { - propertyMap.getProperties(); - }, - [](FuzzedDataProvider*, android::PropertyMap propertyMap) -> void { + [](FuzzedDataProvider*, android::PropertyMap& propertyMap) -> void { propertyMap.clear(); }, - [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { - std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); - android::String8 key = android::String8(keyStr.c_str()); - propertyMap.hasProperty(key); - }, - [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { - std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); - android::String8 key = android::String8(keyStr.c_str()); - android::String8 out; + [](FuzzedDataProvider* dataProvider, android::PropertyMap& propertyMap) -> void { + std::string key = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); + std::string out; propertyMap.tryGetProperty(key, out); }, - [](FuzzedDataProvider* dataProvider, android::PropertyMap /*unused*/) -> void { + [](FuzzedDataProvider* dataProvider, android::PropertyMap& /*unused*/) -> void { TemporaryFile tf; // Generate file contents std::string contents = dataProvider->ConsumeRandomLengthString(MAX_FILE_SIZE); @@ -54,17 +44,15 @@ static const std::vector<std::function<void(FuzzedDataProvider*, android::Proper } android::PropertyMap::load(tf.path); }, - [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void { - std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); - std::string valStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); - android::String8 key = android::String8(keyStr.c_str()); - android::String8 val = android::String8(valStr.c_str()); + [](FuzzedDataProvider* dataProvider, android::PropertyMap& propertyMap) -> void { + std::string key = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); + std::string val = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN); propertyMap.addProperty(key, val); }, }; extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FuzzedDataProvider dataProvider(data, size); - android::PropertyMap propertyMap = android::PropertyMap(); + android::PropertyMap propertyMap; int opsRun = 0; while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) { diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp index 7f427f2364..76aaf61da7 100644 --- a/libs/input/VelocityTracker.cpp +++ b/libs/input/VelocityTracker.cpp @@ -27,6 +27,8 @@ #include <utils/BitSet.h> #include <utils/Timers.h> +using std::literals::chrono_literals::operator""ms; + namespace android { /** @@ -57,8 +59,14 @@ static const nsecs_t NANOS_PER_MS = 1000000; // Some input devices do not send ACTION_MOVE events in the case where a pointer has // stopped. We need to detect this case so that we can accurately predict the // velocity after the pointer starts moving again. -static const nsecs_t ASSUME_POINTER_STOPPED_TIME = 40 * NANOS_PER_MS; +static const std::chrono::duration ASSUME_POINTER_STOPPED_TIME = 40ms; +static std::string toString(std::chrono::nanoseconds t) { + std::stringstream stream; + stream.precision(1); + stream << std::fixed << std::chrono::duration<float, std::milli>(t).count() << " ms"; + return stream.str(); +} static float vectorDot(const float* a, const float* b, uint32_t m) { float r = 0; @@ -146,18 +154,14 @@ std::unique_ptr<VelocityTrackerStrategy> VelocityTracker::createStrategy( VelocityTracker::Strategy strategy) { switch (strategy) { case VelocityTracker::Strategy::IMPULSE: - if (DEBUG_STRATEGY) { - ALOGI("Initializing impulse strategy"); - } + ALOGI_IF(DEBUG_STRATEGY, "Initializing impulse strategy"); return std::make_unique<ImpulseVelocityTrackerStrategy>(); case VelocityTracker::Strategy::LSQ1: return std::make_unique<LeastSquaresVelocityTrackerStrategy>(1); case VelocityTracker::Strategy::LSQ2: - if (DEBUG_STRATEGY && !DEBUG_IMPULSE) { - ALOGI("Initializing lsq2 strategy"); - } + ALOGI_IF(DEBUG_STRATEGY && !DEBUG_IMPULSE, "Initializing lsq2 strategy"); return std::make_unique<LeastSquaresVelocityTrackerStrategy>(2); case VelocityTracker::Strategy::LSQ3: @@ -221,12 +225,11 @@ void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, idBits.clearLastMarkedBit(); } - if ((mCurrentPointerIdBits.value & idBits.value) - && eventTime >= mLastEventTime + ASSUME_POINTER_STOPPED_TIME) { - if (DEBUG_VELOCITY) { - ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.", - (eventTime - mLastEventTime) * 0.000001f); - } + if ((mCurrentPointerIdBits.value & idBits.value) && + std::chrono::nanoseconds(eventTime - mLastEventTime) > ASSUME_POINTER_STOPPED_TIME) { + ALOGD_IF(DEBUG_VELOCITY, "VelocityTracker: stopped for %s, clearing state.", + toString(std::chrono::nanoseconds(eventTime - mLastEventTime)).c_str()); + // We have not received any movements for too long. Assume that all pointers // have stopped. mStrategy->clear(); @@ -281,8 +284,18 @@ void VelocityTracker::addMovement(const MotionEvent* event) { case AMOTION_EVENT_ACTION_MOVE: case AMOTION_EVENT_ACTION_HOVER_MOVE: break; - default: - // Ignore all other actions because they do not convey any new information about + case AMOTION_EVENT_ACTION_POINTER_UP: + case AMOTION_EVENT_ACTION_UP: { + std::chrono::nanoseconds delaySinceLastEvent(event->getEventTime() - mLastEventTime); + if (delaySinceLastEvent > ASSUME_POINTER_STOPPED_TIME) { + ALOGD_IF(DEBUG_VELOCITY, + "VelocityTracker: stopped for %s, clearing state upon pointer liftoff.", + toString(delaySinceLastEvent).c_str()); + // We have not received any movements for too long. Assume that all pointers + // have stopped. + mStrategy->clear(); + } + // These actions because they do not convey any new information about // pointer movement. We also want to preserve the last known velocity of the pointers. // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position // of the pointers that went up. ACTION_POINTER_UP does include the new position of @@ -292,6 +305,10 @@ void VelocityTracker::addMovement(const MotionEvent* event) { // before adding the movement. return; } + default: + // Ignore all other actions. + return; + } size_t pointerCount = event->getPointerCount(); if (pointerCount > MAX_POINTERS) { @@ -438,10 +455,10 @@ void LeastSquaresVelocityTrackerStrategy::addMovement( static bool solveLeastSquares(const std::vector<float>& x, const std::vector<float>& y, const std::vector<float>& w, uint32_t n, float* outB, float* outDet) { const size_t m = x.size(); - if (DEBUG_STRATEGY) { - ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n), - vectorToString(x).c_str(), vectorToString(y).c_str(), vectorToString(w).c_str()); - } + + ALOGD_IF(DEBUG_STRATEGY, "solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n), + vectorToString(x).c_str(), vectorToString(y).c_str(), vectorToString(w).c_str()); + LOG_ALWAYS_FATAL_IF(m != y.size() || m != w.size(), "Mismatched vector sizes"); // Expand the X vector to a matrix A, pre-multiplied by the weights. @@ -452,9 +469,9 @@ static bool solveLeastSquares(const std::vector<float>& x, const std::vector<flo a[i][h] = a[i - 1][h] * x[h]; } } - if (DEBUG_STRATEGY) { - ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str()); - } + + ALOGD_IF(DEBUG_STRATEGY, " - a=%s", + matrixToString(&a[0][0], m, n, false /*rowMajor*/).c_str()); // Apply the Gram-Schmidt process to A to obtain its QR decomposition. float q[n][m]; // orthonormal basis, column-major order @@ -473,9 +490,7 @@ static bool solveLeastSquares(const std::vector<float>& x, const std::vector<flo float norm = vectorNorm(&q[j][0], m); if (norm < 0.000001f) { // vectors are linearly dependent or zero so no solution - if (DEBUG_STRATEGY) { - ALOGD(" - no solution, norm=%f", norm); - } + ALOGD_IF(DEBUG_STRATEGY, " - no solution, norm=%f", norm); return false; } @@ -518,9 +533,8 @@ static bool solveLeastSquares(const std::vector<float>& x, const std::vector<flo } outB[i] /= r[i][i]; } - if (DEBUG_STRATEGY) { - ALOGD(" - b=%s", vectorToString(outB, n).c_str()); - } + + ALOGD_IF(DEBUG_STRATEGY, " - b=%s", vectorToString(outB, n).c_str()); // Calculate the coefficient of determination as 1 - (SSerr / SStot) where // SSerr is the residual sum of squares (variance of the error), @@ -546,11 +560,11 @@ static bool solveLeastSquares(const std::vector<float>& x, const std::vector<flo sstot += w[h] * w[h] * var * var; } *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1; - if (DEBUG_STRATEGY) { - ALOGD(" - sserr=%f", sserr); - ALOGD(" - sstot=%f", sstot); - ALOGD(" - det=%f", *outDet); - } + + ALOGD_IF(DEBUG_STRATEGY, " - sserr=%f", sserr); + ALOGD_IF(DEBUG_STRATEGY, " - sstot=%f", sstot); + ALOGD_IF(DEBUG_STRATEGY, " - det=%f", *outDet); + return true; } @@ -673,11 +687,11 @@ bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id, outEstimator->time = newestMovement.eventTime; outEstimator->degree = degree; outEstimator->confidence = xdet * ydet; - if (DEBUG_STRATEGY) { - ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f", - int(outEstimator->degree), vectorToString(outEstimator->xCoeff, n).c_str(), - vectorToString(outEstimator->yCoeff, n).c_str(), outEstimator->confidence); - } + + ALOGD_IF(DEBUG_STRATEGY, "estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f", + int(outEstimator->degree), vectorToString(outEstimator->xCoeff, n).c_str(), + vectorToString(outEstimator->yCoeff, n).c_str(), outEstimator->confidence); + return true; } } @@ -1185,9 +1199,10 @@ bool ImpulseVelocityTrackerStrategy::getEstimator(uint32_t id, outEstimator->time = newestMovement.eventTime; outEstimator->degree = 2; // similar results to 2nd degree fit outEstimator->confidence = 1; - if (DEBUG_STRATEGY) { - ALOGD("velocity: (%.1f, %.1f)", outEstimator->xCoeff[1], outEstimator->yCoeff[1]); - } + + ALOGD_IF(DEBUG_STRATEGY, "velocity: (%.1f, %.1f)", outEstimator->xCoeff[1], + outEstimator->yCoeff[1]); + if (DEBUG_IMPULSE) { // TODO(b/134179997): delete this block once the switch to 'impulse' is complete. // Calculate the lsq2 velocity for the same inputs to allow runtime comparisons diff --git a/libs/input/android/os/InputConfig.aidl b/libs/input/android/os/InputConfig.aidl index 6d1b3967f7..4e644fff06 100644 --- a/libs/input/android/os/InputConfig.aidl +++ b/libs/input/android/os/InputConfig.aidl @@ -144,4 +144,10 @@ enum InputConfig { * It is not valid to set this configuration if {@link #TRUSTED_OVERLAY} is not set. */ INTERCEPTS_STYLUS = 1 << 15, + + /** + * The window is a clone of another window. This may be treated differently since there's + * likely a duplicate window with the same client token, but different bounds. + */ + CLONE = 1 << 16, } diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp index d947cd99e8..c53811a92d 100644 --- a/libs/input/tests/Android.bp +++ b/libs/input/tests/Android.bp @@ -16,6 +16,7 @@ cc_test { "InputDevice_test.cpp", "InputEvent_test.cpp", "InputPublisherAndConsumer_test.cpp", + "TouchResampling_test.cpp", "TouchVideoFrame_test.cpp", "VelocityTracker_test.cpp", "VerifiedInputEvent_test.cpp", diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp index 05bc0bcbe8..70e4fda662 100644 --- a/libs/input/tests/InputPublisherAndConsumer_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp @@ -16,17 +16,10 @@ #include "TestHelpers.h" -#include <unistd.h> -#include <sys/mman.h> -#include <time.h> - #include <attestation/HmacKeyManager.h> -#include <cutils/ashmem.h> #include <gtest/gtest.h> #include <gui/constants.h> #include <input/InputTransport.h> -#include <utils/StopWatch.h> -#include <utils/Timers.h> using android::base::Result; diff --git a/libs/input/tests/TouchResampling_test.cpp b/libs/input/tests/TouchResampling_test.cpp new file mode 100644 index 0000000000..c09a8e9358 --- /dev/null +++ b/libs/input/tests/TouchResampling_test.cpp @@ -0,0 +1,562 @@ +/* + * Copyright (C) 2022 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 "TestHelpers.h" + +#include <chrono> +#include <vector> + +#include <attestation/HmacKeyManager.h> +#include <gtest/gtest.h> +#include <input/InputTransport.h> + +using namespace std::chrono_literals; + +namespace android { + +struct Pointer { + int32_t id; + float x; + float y; +}; + +struct InputEventEntry { + std::chrono::nanoseconds eventTime; + std::vector<Pointer> pointers; + int32_t action; +}; + +class TouchResamplingTest : public testing::Test { +protected: + std::unique_ptr<InputPublisher> mPublisher; + std::unique_ptr<InputConsumer> mConsumer; + PreallocatedInputEventFactory mEventFactory; + + uint32_t mSeq = 1; + + void SetUp() override { + std::unique_ptr<InputChannel> serverChannel, clientChannel; + status_t result = + InputChannel::openInputChannelPair("channel name", serverChannel, clientChannel); + ASSERT_EQ(OK, result); + + mPublisher = std::make_unique<InputPublisher>(std::move(serverChannel)); + mConsumer = std::make_unique<InputConsumer>(std::move(clientChannel), + true /* enableTouchResampling */); + } + + status_t publishSimpleMotionEventWithCoords(int32_t action, nsecs_t eventTime, + const std::vector<PointerProperties>& properties, + const std::vector<PointerCoords>& coords); + void publishSimpleMotionEvent(int32_t action, nsecs_t eventTime, + const std::vector<Pointer>& pointers); + void publishInputEventEntries(const std::vector<InputEventEntry>& entries); + void consumeInputEventEntries(const std::vector<InputEventEntry>& entries, + std::chrono::nanoseconds frameTime); + void receiveResponseUntilSequence(uint32_t seq); +}; + +status_t TouchResamplingTest::publishSimpleMotionEventWithCoords( + int32_t action, nsecs_t eventTime, const std::vector<PointerProperties>& properties, + const std::vector<PointerCoords>& coords) { + const ui::Transform identityTransform; + const nsecs_t downTime = 0; + + if (action == AMOTION_EVENT_ACTION_DOWN && eventTime != 0) { + ADD_FAILURE() << "Downtime should be equal to 0 (hardcoded for convenience)"; + } + return mPublisher->publishMotionEvent(mSeq++, InputEvent::nextId(), 1 /*deviceId*/, + AINPUT_SOURCE_TOUCHSCREEN, 0 /*displayId*/, INVALID_HMAC, + action, 0 /*actionButton*/, 0 /*flags*/, 0 /*edgeFlags*/, + AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE, + identityTransform, 0 /*xPrecision*/, 0 /*yPrecision*/, + AMOTION_EVENT_INVALID_CURSOR_POSITION, + AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, + downTime, eventTime, properties.size(), properties.data(), + coords.data()); +} + +void TouchResamplingTest::publishSimpleMotionEvent(int32_t action, nsecs_t eventTime, + const std::vector<Pointer>& pointers) { + std::vector<PointerProperties> properties; + std::vector<PointerCoords> coords; + + for (const Pointer& pointer : pointers) { + properties.push_back({}); + properties.back().clear(); + properties.back().id = pointer.id; + properties.back().toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; + + coords.push_back({}); + coords.back().clear(); + coords.back().setAxisValue(AMOTION_EVENT_AXIS_X, pointer.x); + coords.back().setAxisValue(AMOTION_EVENT_AXIS_Y, pointer.y); + } + + status_t result = publishSimpleMotionEventWithCoords(action, eventTime, properties, coords); + ASSERT_EQ(OK, result); +} + +/** + * Each entry is published separately, one entry at a time. As a result, action is used here + * on a per-entry basis. + */ +void TouchResamplingTest::publishInputEventEntries(const std::vector<InputEventEntry>& entries) { + for (const InputEventEntry& entry : entries) { + publishSimpleMotionEvent(entry.action, entry.eventTime.count(), entry.pointers); + } +} + +/** + * Inside the publisher, read responses repeatedly until the desired sequence number is returned. + * + * Sometimes, when you call 'sendFinishedSignal', you would be finishing a batch which is comprised + * of several input events. As a result, consumer will generate multiple 'finish' signals on your + * behalf. + * + * In this function, we call 'receiveConsumerResponse' in a loop until the desired sequence number + * is returned. + */ +void TouchResamplingTest::receiveResponseUntilSequence(uint32_t seq) { + size_t consumedEvents = 0; + while (consumedEvents < 100) { + android::base::Result<InputPublisher::ConsumerResponse> response = + mPublisher->receiveConsumerResponse(); + ASSERT_TRUE(response.ok()); + ASSERT_TRUE(std::holds_alternative<InputPublisher::Finished>(*response)); + const InputPublisher::Finished& finish = std::get<InputPublisher::Finished>(*response); + ASSERT_TRUE(finish.handled) + << "publisher receiveFinishedSignal should have set handled to consumer's reply"; + if (finish.seq == seq) { + return; + } + consumedEvents++; + } + FAIL() << "Got " << consumedEvents << "events, but still no event with seq=" << seq; +} + +/** + * All entries are compared against a single MotionEvent, but the same data structure + * InputEventEntry is used here for simpler code. As a result, the entire array of InputEventEntry + * must contain identical values for the action field. + */ +void TouchResamplingTest::consumeInputEventEntries(const std::vector<InputEventEntry>& entries, + std::chrono::nanoseconds frameTime) { + ASSERT_GE(entries.size(), 1U) << "Must have at least 1 InputEventEntry to compare against"; + + uint32_t consumeSeq; + InputEvent* event; + + status_t status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, frameTime.count(), + &consumeSeq, &event); + ASSERT_EQ(OK, status); + MotionEvent* motionEvent = static_cast<MotionEvent*>(event); + + ASSERT_EQ(entries.size() - 1, motionEvent->getHistorySize()); + for (size_t i = 0; i < entries.size(); i++) { // most recent sample is last + SCOPED_TRACE(i); + const InputEventEntry& entry = entries[i]; + ASSERT_EQ(entry.action, motionEvent->getAction()); + ASSERT_EQ(entry.eventTime.count(), motionEvent->getHistoricalEventTime(i)); + ASSERT_EQ(entry.pointers.size(), motionEvent->getPointerCount()); + + for (size_t p = 0; p < motionEvent->getPointerCount(); p++) { + SCOPED_TRACE(p); + // The pointers can be in any order, both in MotionEvent as well as InputEventEntry + ssize_t motionEventPointerIndex = motionEvent->findPointerIndex(entry.pointers[p].id); + ASSERT_GE(motionEventPointerIndex, 0) << "Pointer must be present in MotionEvent"; + ASSERT_EQ(entry.pointers[p].x, + motionEvent->getHistoricalAxisValue(AMOTION_EVENT_AXIS_X, + motionEventPointerIndex, i)); + ASSERT_EQ(entry.pointers[p].x, + motionEvent->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_X, + motionEventPointerIndex, i)); + ASSERT_EQ(entry.pointers[p].y, + motionEvent->getHistoricalAxisValue(AMOTION_EVENT_AXIS_Y, + motionEventPointerIndex, i)); + ASSERT_EQ(entry.pointers[p].y, + motionEvent->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, + motionEventPointerIndex, i)); + } + } + + status = mConsumer->sendFinishedSignal(consumeSeq, true); + ASSERT_EQ(OK, status); + + receiveResponseUntilSequence(consumeSeq); +} + +/** + * Timeline + * ---------+------------------+------------------+--------+-----------------+---------------------- + * 0 ms 10 ms 20 ms 25 ms 35 ms + * ACTION_DOWN ACTION_MOVE ACTION_MOVE ^ ^ + * | | + * resampled value | + * frameTime + * Typically, the prediction is made for time frameTime - RESAMPLE_LATENCY, or 30 ms in this case + * However, that would be 10 ms later than the last real sample (which came in at 20 ms). + * Therefore, the resampling should happen at 20 ms + RESAMPLE_MAX_PREDICTION = 28 ms. + * In this situation, though, resample time is further limited by taking half of the difference + * between the last two real events, which would put this time at: + * 20 ms + (20 ms - 10 ms) / 2 = 25 ms. + */ +TEST_F(TouchResamplingTest, EventIsResampled) { + std::chrono::nanoseconds frameTime; + std::vector<InputEventEntry> entries, expectedEntries; + + // Initial ACTION_DOWN should be separate, because the first consume event will only return + // InputEvent with a single action. + entries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + publishInputEventEntries(entries); + frameTime = 5ms; + expectedEntries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y + entries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 35ms; + expectedEntries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {25ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value + }; + consumeInputEventEntries(expectedEntries, frameTime); +} + +/** + * Same as above test, but use pointer id=1 instead of 0 to make sure that system does not + * have these hardcoded. + */ +TEST_F(TouchResamplingTest, EventIsResampledWithDifferentId) { + std::chrono::nanoseconds frameTime; + std::vector<InputEventEntry> entries, expectedEntries; + + // Initial ACTION_DOWN should be separate, because the first consume event will only return + // InputEvent with a single action. + entries = { + // id x y + {0ms, {{1, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + publishInputEventEntries(entries); + frameTime = 5ms; + expectedEntries = { + // id x y + {0ms, {{1, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y + entries = { + // id x y + {10ms, {{1, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{1, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 35ms; + expectedEntries = { + // id x y + {10ms, {{1, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{1, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {25ms, {{1, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value + }; + consumeInputEventEntries(expectedEntries, frameTime); +} + +/** + * Event should not be resampled when sample time is equal to event time. + */ +TEST_F(TouchResamplingTest, SampleTimeEqualsEventTime) { + std::chrono::nanoseconds frameTime; + std::vector<InputEventEntry> entries, expectedEntries; + + // Initial ACTION_DOWN should be separate, because the first consume event will only return + // InputEvent with a single action. + entries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + publishInputEventEntries(entries); + frameTime = 5ms; + expectedEntries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y + entries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 20ms + 5ms /*RESAMPLE_LATENCY*/; + expectedEntries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + // no resampled event because the time of resample falls exactly on the existing event + }; + consumeInputEventEntries(expectedEntries, frameTime); +} + +/** + * Once we send a resampled value to the app, we should continue to "lie" if the pointer + * does not move. So, if the pointer keeps the same coordinates, resampled value should continue + * to be used. + */ +TEST_F(TouchResamplingTest, ResampledValueIsUsedForIdenticalCoordinates) { + std::chrono::nanoseconds frameTime; + std::vector<InputEventEntry> entries, expectedEntries; + + // Initial ACTION_DOWN should be separate, because the first consume event will only return + // InputEvent with a single action. + entries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + publishInputEventEntries(entries); + frameTime = 5ms; + expectedEntries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y + entries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 35ms; + expectedEntries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {25ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Coordinate value 30 has been resampled to 35. When a new event comes in with value 30 again, + // the system should still report 35. + entries = { + // id x y + {40ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 45ms + 5ms /*RESAMPLE_LATENCY*/; + expectedEntries = { + // id x y + {40ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // original event, rewritten + {45ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled event, rewritten + }; + consumeInputEventEntries(expectedEntries, frameTime); +} + +TEST_F(TouchResamplingTest, OldEventReceivedAfterResampleOccurs) { + std::chrono::nanoseconds frameTime; + std::vector<InputEventEntry> entries, expectedEntries; + + // Initial ACTION_DOWN should be separate, because the first consume event will only return + // InputEvent with a single action. + entries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + publishInputEventEntries(entries); + frameTime = 5ms; + expectedEntries = { + // id x y + {0ms, {{0, 10, 20}}, AMOTION_EVENT_ACTION_DOWN}, + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Two ACTION_MOVE events 10 ms apart that move in X direction and stay still in Y + entries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 35ms; + expectedEntries = { + // id x y + {10ms, {{0, 20, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {20ms, {{0, 30, 30}}, AMOTION_EVENT_ACTION_MOVE}, + {25ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value + }; + consumeInputEventEntries(expectedEntries, frameTime); + // Above, the resampled event is at 25ms rather than at 30 ms = 35ms - RESAMPLE_LATENCY + // because we are further bound by how far we can extrapolate by the "last time delta". + // That's 50% of (20 ms - 10ms) => 5ms. So we can't predict more than 5 ms into the future + // from the event at 20ms, which is why the resampled event is at t = 25 ms. + + // We resampled the event to 25 ms. Now, an older 'real' event comes in. + entries = { + // id x y + {24ms, {{0, 40, 30}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 50ms; + expectedEntries = { + // id x y + {24ms, {{0, 35, 30}}, AMOTION_EVENT_ACTION_MOVE}, // original event, rewritten + {26ms, {{0, 45, 30}}, AMOTION_EVENT_ACTION_MOVE}, // resampled event, rewritten + }; + consumeInputEventEntries(expectedEntries, frameTime); +} + +TEST_F(TouchResamplingTest, TwoPointersAreResampledIndependently) { + std::chrono::nanoseconds frameTime; + std::vector<InputEventEntry> entries, expectedEntries; + + // full action for when a pointer with id=1 appears (some other pointer must already be present) + constexpr int32_t actionPointer1Down = + AMOTION_EVENT_ACTION_POINTER_DOWN + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + + // full action for when a pointer with id=0 disappears (some other pointer must still remain) + constexpr int32_t actionPointer0Up = + AMOTION_EVENT_ACTION_POINTER_UP + (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + + // Initial ACTION_DOWN should be separate, because the first consume event will only return + // InputEvent with a single action. + entries = { + // id x y + {0ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_DOWN}, + }; + publishInputEventEntries(entries); + frameTime = 5ms; + expectedEntries = { + // id x y + {0ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_DOWN}, + }; + consumeInputEventEntries(expectedEntries, frameTime); + + entries = { + // id x y + {10ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 10ms + 5ms /*RESAMPLE_LATENCY*/; + expectedEntries = { + // id x y + {10ms, {{0, 100, 100}}, AMOTION_EVENT_ACTION_MOVE}, + // no resampled value because frameTime - RESAMPLE_LATENCY == eventTime + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Second pointer id=1 appears + entries = { + // id x y + {15ms, {{0, 100, 100}, {1, 500, 500}}, actionPointer1Down}, + }; + publishInputEventEntries(entries); + frameTime = 20ms + 5ms /*RESAMPLE_LATENCY*/; + expectedEntries = { + // id x y + {15ms, {{0, 100, 100}, {1, 500, 500}}, actionPointer1Down}, + // no resampled value because frameTime - RESAMPLE_LATENCY == eventTime + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Both pointers move + entries = { + // id x y + {30ms, {{0, 100, 100}, {1, 500, 500}}, AMOTION_EVENT_ACTION_MOVE}, + {40ms, {{0, 120, 120}, {1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 45ms + 5ms /*RESAMPLE_LATENCY*/; + expectedEntries = { + // id x y + {30ms, {{0, 100, 100}, {1, 500, 500}}, AMOTION_EVENT_ACTION_MOVE}, + {40ms, {{0, 120, 120}, {1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE}, + {45ms, {{0, 130, 130}, {1, 650, 650}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Both pointers move again + entries = { + // id x y + {60ms, {{0, 120, 120}, {1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE}, + {70ms, {{0, 130, 130}, {1, 700, 700}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 75ms + 5ms /*RESAMPLE_LATENCY*/; + /** + * The sample at t = 60, pointer id 0 is not equal to 120, because this value of 120 was + * received twice, and resampled to 130. So if we already reported it as "130", we continue + * to report it as such. Similar with pointer id 1. + */ + expectedEntries = { + {60ms, + {{0, 130, 130}, // not 120! because it matches previous real event + {1, 650, 650}}, + AMOTION_EVENT_ACTION_MOVE}, + {70ms, {{0, 130, 130}, {1, 700, 700}}, AMOTION_EVENT_ACTION_MOVE}, + {75ms, {{0, 135, 135}, {1, 750, 750}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // First pointer id=0 leaves the screen + entries = { + // id x y + {80ms, {{1, 600, 600}}, actionPointer0Up}, + }; + publishInputEventEntries(entries); + frameTime = 90ms; + expectedEntries = { + // id x y + {80ms, {{1, 600, 600}}, actionPointer0Up}, + // no resampled event for ACTION_POINTER_UP + }; + consumeInputEventEntries(expectedEntries, frameTime); + + // Remaining pointer id=1 is still present, but doesn't move + entries = { + // id x y + {90ms, {{1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE}, + }; + publishInputEventEntries(entries); + frameTime = 100ms; + expectedEntries = { + // id x y + {90ms, {{1, 600, 600}}, AMOTION_EVENT_ACTION_MOVE}, + /** + * The latest event with ACTION_MOVE was at t = 70, coord = 700. + * Use that value for resampling here: (600 - 700) / (90 - 70) * 5 + 600 + */ + {95ms, {{1, 575, 575}}, AMOTION_EVENT_ACTION_MOVE}, // resampled value + }; + consumeInputEventEntries(expectedEntries, frameTime); +} + +} // namespace android diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp index a87b1873f0..4a445de3ac 100644 --- a/libs/input/tests/VelocityTracker_test.cpp +++ b/libs/input/tests/VelocityTracker_test.cpp @@ -26,7 +26,9 @@ #include <gui/constants.h> #include <input/VelocityTracker.h> -using namespace std::chrono_literals; +using std::literals::chrono_literals::operator""ms; +using std::literals::chrono_literals::operator""ns; +using std::literals::chrono_literals::operator""us; using android::base::StringPrintf; namespace android { @@ -149,8 +151,7 @@ static std::vector<MotionEvent> createMotionEventStream( if (i == 0) { action = AMOTION_EVENT_ACTION_DOWN; EXPECT_EQ(1U, pointerCount) << "First event should only have 1 pointer"; - } else if (i == motions.size() - 1) { - EXPECT_EQ(1U, pointerCount) << "Last event should only have 1 pointer"; + } else if ((i == motions.size() - 1) && pointerCount == 1) { action = AMOTION_EVENT_ACTION_UP; } else { const MotionEventEntry& previousEntry = motions[i-1]; @@ -195,7 +196,7 @@ static std::vector<MotionEvent> createMotionEventStream( static void computeAndCheckVelocity(const VelocityTracker::Strategy strategy, const std::vector<MotionEventEntry>& motions, int32_t axis, - float targetVelocity) { + float targetVelocity, uint32_t pointerId = DEFAULT_POINTER_ID) { VelocityTracker vt(strategy); float Vx, Vy; @@ -204,7 +205,7 @@ static void computeAndCheckVelocity(const VelocityTracker::Strategy strategy, vt.addMovement(&event); } - vt.getVelocity(DEFAULT_POINTER_ID, &Vx, &Vy); + vt.getVelocity(pointerId, &Vx, &Vy); switch (axis) { case AMOTION_EVENT_AXIS_X: @@ -846,13 +847,71 @@ TEST_F(VelocityTrackerTest, LeastSquaresVelocityTrackerStrategyEstimator_ThreeFi // Velocity should actually be zero, but we expect 0.016 here instead. // This is close enough to zero, and is likely caused by division by a very small number. - computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, -0.016); - computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y, -0.016); + computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0); + computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_Y, 0); computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0); computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_Y, 0); } /** + * ================= Pointer liftoff =============================================================== + */ + +/** + * The last movement of a pointer is always ACTION_POINTER_UP or ACTION_UP. If there's a short delay + * between the last ACTION_MOVE and the next ACTION_POINTER_UP or ACTION_UP, velocity should not be + * affected by the liftoff. + */ +TEST_F(VelocityTrackerTest, ShortDelayBeforeActionUp) { + std::vector<MotionEventEntry> motions = { + {0ms, {{10, 0}}}, {10ms, {{20, 0}}}, {20ms, {{30, 0}}}, {30ms, {{30, 0}}}, // ACTION_UP + }; + computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, + 1000); + computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 1000); +} + +/** + * The last movement of a single pointer is ACTION_UP. If there's a long delay between the last + * ACTION_MOVE and the final ACTION_UP, velocity should be reported as zero because the pointer + * should be assumed to have stopped. + */ +TEST_F(VelocityTrackerTest, LongDelayBeforeActionUp) { + std::vector<MotionEventEntry> motions = { + {0ms, {{10, 0}}}, + {10ms, {{20, 0}}}, + {20ms, {{30, 0}}}, + {3000ms, {{30, 0}}}, // ACTION_UP + }; + computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0); + computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0); +} + +/** + * The last movement of a pointer is always ACTION_POINTER_UP or ACTION_UP. If there's a long delay + * before ACTION_POINTER_UP event, the movement should be assumed to have stopped. + * The final velocity should be reported as zero for all pointers. + */ +TEST_F(VelocityTrackerTest, LongDelayBeforeActionPointerUp) { + std::vector<MotionEventEntry> motions = { + {0ms, {{10, 0}}}, + {10ms, {{20, 0}, {100, 0}}}, + {20ms, {{30, 0}, {200, 0}}}, + {30ms, {{30, 0}, {300, 0}}}, + {40ms, {{30, 0}, {400, 0}}}, + {3000ms, {{30, 0}}}, // ACTION_POINTER_UP + }; + computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0, + /*pointerId*/ 0); + computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0, + /*pointerId*/ 0); + computeAndCheckVelocity(VelocityTracker::Strategy::IMPULSE, motions, AMOTION_EVENT_AXIS_X, 0, + /*pointerId*/ 1); + computeAndCheckVelocity(VelocityTracker::Strategy::LSQ2, motions, AMOTION_EVENT_AXIS_X, 0, + /*pointerId*/ 1); +} + +/** * ================== Tests for least squares fitting ============================================== * * Special care must be taken when constructing tests for LeastSquaresVelocityTrackerStrategy diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp index 8240b08085..539cbaa341 100644 --- a/libs/nativedisplay/AChoreographer.cpp +++ b/libs/nativedisplay/AChoreographer.cpp @@ -18,8 +18,8 @@ //#define LOG_NDEBUG 0 #include <android-base/thread_annotations.h> +#include <android/gui/ISurfaceComposer.h> #include <gui/DisplayEventDispatcher.h> -#include <gui/ISurfaceComposer.h> #include <jni.h> #include <private/android/choreographer.h> #include <utils/Looper.h> @@ -198,7 +198,7 @@ Choreographer* Choreographer::getForThread() { } Choreographer::Choreographer(const sp<Looper>& looper) - : DisplayEventDispatcher(looper, ISurfaceComposer::VsyncSource::eVsyncSourceApp), + : DisplayEventDispatcher(looper, gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp), mLooper(looper), mThreadId(std::this_thread::get_id()) { std::lock_guard<std::mutex> _l(gChoreographers.lock); diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp index 4659b96b11..8d8a2bc244 100644 --- a/libs/nativedisplay/Android.bp +++ b/libs/nativedisplay/Android.bp @@ -53,6 +53,7 @@ cc_library_shared { version_script: "libnativedisplay.map.txt", srcs: [ + ":libgui_frame_event_aidl", "AChoreographer.cpp", "ADisplay.cpp", "surfacetexture/surface_texture.cpp", diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp index 4a1784ea0b..f3009dd3d8 100644 --- a/libs/nativewindow/AHardwareBuffer.cpp +++ b/libs/nativewindow/AHardwareBuffer.cpp @@ -357,12 +357,12 @@ int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** out return INVALID_OPERATION; } - GraphicBuffer* gBuffer = new GraphicBuffer(); + sp<GraphicBuffer> gBuffer(new GraphicBuffer()); status_t err = gBuffer->unflatten(data, dataLen, fdData, fdCount); if (err != NO_ERROR) { return err; } - *outBuffer = AHardwareBuffer_from_GraphicBuffer(gBuffer); + *outBuffer = AHardwareBuffer_from_GraphicBuffer(gBuffer.get()); // Ensure the buffer has a positive ref-count. AHardwareBuffer_acquire(*outBuffer); diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index 18a4b2d3e8..731f989658 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -176,8 +176,8 @@ int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpa static_cast<int>(HAL_DATASPACE_BT2020_HLG)); static_assert(static_cast<int>(ADATASPACE_BT2020_ITU_HLG) == static_cast<int>(HAL_DATASPACE_BT2020_ITU_HLG)); - static_assert(static_cast<int>(DEPTH) == static_cast<int>(HAL_DATASPACE_DEPTH)); - static_assert(static_cast<int>(DYNAMIC_DEPTH) == static_cast<int>(HAL_DATASPACE_DYNAMIC_DEPTH)); + static_assert(static_cast<int>(ADATASPACE_DEPTH) == static_cast<int>(HAL_DATASPACE_DEPTH)); + static_assert(static_cast<int>(ADATASPACE_DYNAMIC_DEPTH) == static_cast<int>(HAL_DATASPACE_DYNAMIC_DEPTH)); if (!window || !query(window, NATIVE_WINDOW_IS_VALID) || !isDataSpaceValid(window, dataSpace)) { @@ -193,6 +193,13 @@ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) { return query(window, NATIVE_WINDOW_DATASPACE); } +int32_t ANativeWindow_getBuffersDefaultDataSpace(ANativeWindow* window) { + if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) { + return -EINVAL; + } + return query(window, NATIVE_WINDOW_DEFAULT_DATASPACE); +} + int32_t ANativeWindow_setFrameRate(ANativeWindow* window, float frameRate, int8_t compatibility) { return ANativeWindow_setFrameRateWithChangeStrategy(window, frameRate, compatibility, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS); diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h index 771844f4fe..ad4cc4a229 100644 --- a/libs/nativewindow/include/android/data_space.h +++ b/libs/nativewindow/include/android/data_space.h @@ -548,14 +548,14 @@ enum ADataSpace { * * This value is valid with formats HAL_PIXEL_FORMAT_Y16 and HAL_PIXEL_FORMAT_BLOB. */ - DEPTH = 4096, + ADATASPACE_DEPTH = 4096, /** * ISO 16684-1:2011(E) Dynamic Depth: * * Embedded depth metadata following the dynamic depth specification. */ - DYNAMIC_DEPTH = 4098 + ADATASPACE_DYNAMIC_DEPTH = 4098 }; __END_DECLS diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index f0e1c4d749..20f4b52caa 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -227,6 +227,16 @@ int32_t ANativeWindow_setBuffersDataSpace(ANativeWindow* window, int32_t dataSpa */ int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) __INTRODUCED_IN(28); +/** + * Get the default dataspace of the buffers in window as set by the consumer. + * + * Available since API level 34. + * + * \return the dataspace of buffers in window, ADATASPACE_UNKNOWN is returned if + * dataspace is unknown, or -EINVAL if window is invalid. + */ +int32_t ANativeWindow_getBuffersDefaultDataSpace(ANativeWindow* window) __INTRODUCED_IN(34); + /** Compatibility value for ANativeWindow_setFrameRate. */ enum ANativeWindow_FrameRateCompatibility { /** diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h index a54af1fa62..79f49e1786 100644 --- a/libs/nativewindow/include/system/window.h +++ b/libs/nativewindow/include/system/window.h @@ -1034,6 +1034,11 @@ enum { * This surface is ignored while choosing the refresh rate. */ ANATIVEWINDOW_FRAME_RATE_NO_VOTE, + + /** + * This surface will vote for the minimum refresh rate. + */ + ANATIVEWINDOW_FRAME_RATE_MIN }; static inline int native_window_set_frame_rate(struct ANativeWindow* window, float frameRate, diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index 988132cd1c..f8c9e4a55f 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -21,6 +21,7 @@ LIBNATIVEWINDOW { ANativeWindow_cancelBuffer; # llndk ANativeWindow_dequeueBuffer; # llndk ANativeWindow_getBuffersDataSpace; # introduced=28 + ANativeWindow_getBuffersDefaultDataSpace; # introduced=34 ANativeWindow_getFormat; ANativeWindow_getHeight; ANativeWindow_getLastDequeueDuration; # apex # introduced=30 diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp index 22dd86698b..6dc01b916e 100644 --- a/libs/renderengine/gl/GLESRenderEngine.cpp +++ b/libs/renderengine/gl/GLESRenderEngine.cpp @@ -921,7 +921,8 @@ void GLESRenderEngine::handleRoundedCorners(const DisplaySettings& display, // Finally, we cut the layer into 3 parts, with top and bottom parts having rounded corners // and the middle part without rounded corners. - const int32_t radius = ceil(layer.geometry.roundedCornersRadius); + const int32_t radius = ceil( + (layer.geometry.roundedCornersRadius.x + layer.geometry.roundedCornersRadius.y) / 2.0); const Rect topRect(bounds.left, bounds.top, bounds.right, bounds.top + radius); setScissor(topRect); drawMesh(mesh); @@ -1266,23 +1267,24 @@ void GLESRenderEngine::drawLayersInternal( const half3 solidColor = layer.source.solidColor; const half4 color = half4(solidColor.r, solidColor.g, solidColor.b, layer.alpha); + const float radius = + (layer.geometry.roundedCornersRadius.x + layer.geometry.roundedCornersRadius.y) / + 2.0f; // Buffer sources will have a black solid color ignored in the shader, // so in that scenario the solid color passed here is arbitrary. - setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, - layer.geometry.roundedCornersRadius); + setupLayerBlending(usePremultipliedAlpha, isOpaque, disableTexture, color, radius); if (layer.disableBlending) { glDisable(GL_BLEND); } setSourceDataSpace(layer.sourceDataspace); if (layer.shadow.length > 0.0f) { - handleShadow(layer.geometry.boundaries, layer.geometry.roundedCornersRadius, - layer.shadow); + handleShadow(layer.geometry.boundaries, radius, layer.shadow); } // We only want to do a special handling for rounded corners when having rounded corners // is the only reason it needs to turn on blending, otherwise, we handle it like the // usual way since it needs to turn on blending anyway. - else if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) { + else if (radius > 0.0 && color.a >= 1.0f && isOpaque) { handleRoundedCorners(display, layer, mesh); } else { drawMesh(mesh); diff --git a/libs/renderengine/include/renderengine/BorderRenderInfo.h b/libs/renderengine/include/renderengine/BorderRenderInfo.h new file mode 100644 index 0000000000..0ee6661f33 --- /dev/null +++ b/libs/renderengine/include/renderengine/BorderRenderInfo.h @@ -0,0 +1,36 @@ +/* + * Copyright 2022 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 <math/mat4.h> +#include <ui/Region.h> + +namespace android { +namespace renderengine { + +struct BorderRenderInfo { + float width = 0; + half4 color; + Region combinedRegion; + + bool operator==(const BorderRenderInfo& rhs) const { + return (width == rhs.width && color == rhs.color && + combinedRegion.hasSameRects(rhs.combinedRegion)); + } +}; + +} // namespace renderengine +} // namespace android
\ No newline at end of file diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h index 59ef991eec..25fe9f2d8e 100644 --- a/libs/renderengine/include/renderengine/DisplaySettings.h +++ b/libs/renderengine/include/renderengine/DisplaySettings.h @@ -22,6 +22,7 @@ #include <math/mat4.h> #include <renderengine/PrintMatrix.h> +#include <renderengine/BorderRenderInfo.h> #include <ui/GraphicTypes.h> #include <ui/Rect.h> #include <ui/Region.h> @@ -79,6 +80,8 @@ struct DisplaySettings { // Configures the rendering intent of the output display. This is used for tonemapping. aidl::android::hardware::graphics::composer3::RenderIntent renderIntent = aidl::android::hardware::graphics::composer3::RenderIntent::TONE_MAP_COLORIMETRIC; + + std::vector<renderengine::BorderRenderInfo> borderInfoList; }; static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& rhs) { @@ -90,7 +93,8 @@ static inline bool operator==(const DisplaySettings& lhs, const DisplaySettings& lhs.deviceHandlesColorTransform == rhs.deviceHandlesColorTransform && lhs.orientation == rhs.orientation && lhs.targetLuminanceNits == rhs.targetLuminanceNits && - lhs.dimmingStage == rhs.dimmingStage && lhs.renderIntent == rhs.renderIntent; + lhs.dimmingStage == rhs.dimmingStage && lhs.renderIntent == rhs.renderIntent && + lhs.borderInfoList == rhs.borderInfoList; } static const char* orientation_to_string(uint32_t orientation) { diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h index 154e5269f0..b3a617c04b 100644 --- a/libs/renderengine/include/renderengine/LayerSettings.h +++ b/libs/renderengine/include/renderengine/LayerSettings.h @@ -87,7 +87,7 @@ struct Geometry { // rectangle to figure out how to apply the radius for this layer. The crop rectangle will be // in local layer coordinate space, so we have to take the layer transform into account when // walking up the tree. - float roundedCornersRadius = 0.0; + vec2 roundedCornersRadius = vec2(0.0f, 0.0f); // Rectangle within which corners will be rounded. FloatRect roundedCornersCrop = FloatRect(); @@ -258,7 +258,8 @@ static inline void PrintTo(const Geometry& settings, ::std::ostream* os) { PrintTo(settings.boundaries, os); *os << "\n .positionTransform = "; PrintMatrix(settings.positionTransform, os); - *os << "\n .roundedCornersRadius = " << settings.roundedCornersRadius; + *os << "\n .roundedCornersRadiusX = " << settings.roundedCornersRadius.x; + *os << "\n .roundedCornersRadiusY = " << settings.roundedCornersRadius.y; *os << "\n .roundedCornersCrop = "; PrintTo(settings.roundedCornersCrop, os); *os << "\n}"; diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp index f3064f3c69..c39f0a97fd 100644 --- a/libs/renderengine/skia/Cache.cpp +++ b/libs/renderengine/skia/Cache.cpp @@ -66,7 +66,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin Geometry{ .boundaries = rect, .roundedCornersCrop = rect, - .roundedCornersRadius = 50.f, + .roundedCornersRadius = {50.f, 50.f}, }, // drawShadow ignores alpha .shadow = @@ -87,7 +87,7 @@ static void drawShadowLayers(SkiaRenderEngine* renderengine, const DisplaySettin Geometry{ .boundaries = smallerRect, .roundedCornersCrop = rect, - .roundedCornersRadius = 50.f, + .roundedCornersRadius = {50.f, 50.f}, }, .source = PixelSource{ @@ -148,7 +148,7 @@ static void drawImageLayers(SkiaRenderEngine* renderengine, const DisplaySetting // In reduced shader mode, all non-zero round rect radii get the same code path. for (float roundedCornersRadius : {0.0f, 50.0f}) { // roundedCornersCrop is always set, but the radius triggers the behavior - layer.geometry.roundedCornersRadius = roundedCornersRadius; + layer.geometry.roundedCornersRadius = {roundedCornersRadius, roundedCornersRadius}; for (bool isOpaque : {true, false}) { layer.source.buffer.isOpaque = isOpaque; for (auto alpha : {half(.2f), half(1.0f)}) { @@ -181,7 +181,7 @@ static void drawSolidLayers(SkiaRenderEngine* renderengine, const DisplaySetting for (auto transform : {mat4(), kScaleAndTranslate}) { layer.geometry.positionTransform = transform; for (float roundedCornersRadius : {0.0f, 50.f}) { - layer.geometry.roundedCornersRadius = roundedCornersRadius; + layer.geometry.roundedCornersRadius = {roundedCornersRadius, roundedCornersRadius}; auto layers = std::vector<LayerSettings>{layer}; renderengine->drawLayers(display, layers, dstTexture, kUseFrameBufferCache, base::unique_fd()); @@ -238,7 +238,7 @@ static void drawClippedLayers(SkiaRenderEngine* renderengine, const DisplaySetti .geometry = Geometry{ .boundaries = rect, - .roundedCornersRadius = 27, // larger than the 20 above. + .roundedCornersRadius = {27.f, 27.f}, .roundedCornersCrop = FloatRect(0, 0, displayRect.width(), displayRect.height()), }, @@ -275,9 +275,9 @@ static void drawPIPImageLayer(SkiaRenderEngine* renderengine, const DisplaySetti // larger than the layer bounds. .positionTransform = kFlip, .boundaries = rect, - .roundedCornersRadius = 94.2551, - .roundedCornersCrop = FloatRect( - -93.75, 0, displayRect.width() + 93.75, displayRect.height()), + .roundedCornersRadius = {94.2551f, 94.2551f}, + .roundedCornersCrop = FloatRect(-93.75, 0, displayRect.width() + 93.75, + displayRect.height()), }, .source = PixelSource{.buffer = Buffer{ @@ -307,10 +307,11 @@ static void drawHolePunchLayer(SkiaRenderEngine* renderengine, const DisplaySett // the boundaries have to be smaller than the rounded crop so that // clipRRect is used instead of drawRRect .boundaries = small, - .roundedCornersRadius = 50.f, + .roundedCornersRadius = {50.f, 50.f}, .roundedCornersCrop = rect, }, - .source = PixelSource{ + .source = + PixelSource{ .solidColor = half3(0.f, 0.f, 0.f), }, .sourceDataspace = kDestDataSpace, diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index 97271cb32d..a0bba593e3 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -24,16 +24,35 @@ #include <EGL/egl.h> #include <EGL/eglext.h> #include <GrContextOptions.h> +#include <SkBlendMode.h> #include <SkCanvas.h> +#include <SkColor.h> #include <SkColorFilter.h> #include <SkColorMatrix.h> #include <SkColorSpace.h> +#include <SkData.h> #include <SkGraphics.h> #include <SkImage.h> #include <SkImageFilters.h> +#include <SkImageInfo.h> +#include <SkM44.h> +#include <SkMatrix.h> +#include <SkPaint.h> +#include <SkPath.h> +#include <SkPoint.h> +#include <SkPoint3.h> +#include <SkRect.h> +#include <SkRefCnt.h> #include <SkRegion.h> +#include <SkRRect.h> +#include <SkRuntimeEffect.h> +#include <SkSamplingOptions.h> +#include <SkScalar.h> +#include <SkShader.h> #include <SkShadowUtils.h> +#include <SkString.h> #include <SkSurface.h> +#include <SkTileMode.h> #include <android-base/stringprintf.h> #include <gl/GrGLInterface.h> #include <gui/TraceUtils.h> @@ -52,8 +71,6 @@ #include "../gl/GLExtensions.h" #include "Cache.h" #include "ColorSpaces.h" -#include "SkBlendMode.h" -#include "SkImageInfo.h" #include "filters/BlurFilter.h" #include "filters/GaussianBlurFilter.h" #include "filters/KawaseBlurFilter.h" @@ -311,7 +328,7 @@ SkiaGLRenderEngine::SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGL mProtectedPlaceholderSurface(protectedPlaceholder), mDefaultPixelFormat(static_cast<PixelFormat>(args.pixelFormat)), mUseColorManagement(args.useColorManagement) { - sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface()); + sk_sp<const GrGLInterface> glInterface = GrGLMakeNativeInterface(); LOG_ALWAYS_FATAL_IF(!glInterface.get()); GrContextOptions options; @@ -762,15 +779,9 @@ void SkiaGLRenderEngine::drawLayersInternal( const DisplaySettings& display, const std::vector<LayerSettings>& layers, const std::shared_ptr<ExternalTexture>& buffer, const bool /*useFramebufferCache*/, base::unique_fd&& bufferFence) { - ATRACE_NAME("SkiaGL::drawLayers"); + ATRACE_NAME("SkiaGL::drawLayersInternal"); std::lock_guard<std::mutex> lock(mRenderingMutex); - if (layers.empty()) { - ALOGV("Drawing empty layer stack"); - resultPromise->set_value({NO_ERROR, base::unique_fd()}); - return; - } - if (buffer == nullptr) { ALOGE("No output buffer provided. Aborting GPU composition."); resultPromise->set_value({BAD_VALUE, base::unique_fd()}); @@ -1228,6 +1239,26 @@ void SkiaGLRenderEngine::drawLayersInternal( activeSurface->flush(); } } + for (const auto& borderRenderInfo : display.borderInfoList) { + SkPaint p; + p.setColor(SkColor4f{borderRenderInfo.color.r, borderRenderInfo.color.g, + borderRenderInfo.color.b, borderRenderInfo.color.a}); + p.setAntiAlias(true); + p.setStyle(SkPaint::kStroke_Style); + p.setStrokeWidth(borderRenderInfo.width); + SkRegion sk_region; + SkPath path; + + // Construct a final SkRegion using Regions + for (const auto& r : borderRenderInfo.combinedRegion) { + sk_region.op({r.left, r.top, r.right, r.bottom}, SkRegion::kUnion_Op); + } + + sk_region.getBoundaryPath(&path); + canvas->drawPath(path, p); + path.close(); + } + surfaceAutoSaveRestore.restore(); mCapture->endCapture(); { @@ -1276,7 +1307,7 @@ inline SkRect SkiaGLRenderEngine::getSkRect(const Rect& rect) { * produce the insected roundRect. If false, the returned state of the radii param is undefined. */ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, - const SkRect& insetCrop, float cornerRadius, + const SkRect& insetCrop, const vec2& cornerRadius, SkVector radii[4]) { const bool leftEqual = bounds.fLeft == crop.fLeft; const bool topEqual = bounds.fTop == crop.fTop; @@ -1288,8 +1319,8 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, // In particular the round rect implementation will scale the value of all corner radii // if the sum of the radius along any edge is greater than the length of that edge. // See https://www.w3.org/TR/css-backgrounds-3/#corner-overlap - const bool requiredWidth = bounds.width() > (cornerRadius * 2); - const bool requiredHeight = bounds.height() > (cornerRadius * 2); + const bool requiredWidth = bounds.width() > (cornerRadius.x * 2); + const bool requiredHeight = bounds.height() > (cornerRadius.y * 2); if (!requiredWidth || !requiredHeight) { return false; } @@ -1298,7 +1329,7 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, // contained within the cropped shape and does not need rounded. // compute the UpperLeft corner radius if (leftEqual && topEqual) { - radii[0].set(cornerRadius, cornerRadius); + radii[0].set(cornerRadius.x, cornerRadius.y); } else if ((leftEqual && bounds.fTop >= insetCrop.fTop) || (topEqual && bounds.fLeft >= insetCrop.fLeft)) { radii[0].set(0, 0); @@ -1307,7 +1338,7 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, } // compute the UpperRight corner radius if (rightEqual && topEqual) { - radii[1].set(cornerRadius, cornerRadius); + radii[1].set(cornerRadius.x, cornerRadius.y); } else if ((rightEqual && bounds.fTop >= insetCrop.fTop) || (topEqual && bounds.fRight <= insetCrop.fRight)) { radii[1].set(0, 0); @@ -1316,7 +1347,7 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, } // compute the BottomRight corner radius if (rightEqual && bottomEqual) { - radii[2].set(cornerRadius, cornerRadius); + radii[2].set(cornerRadius.x, cornerRadius.y); } else if ((rightEqual && bounds.fBottom <= insetCrop.fBottom) || (bottomEqual && bounds.fRight <= insetCrop.fRight)) { radii[2].set(0, 0); @@ -1325,7 +1356,7 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, } // compute the BottomLeft corner radius if (leftEqual && bottomEqual) { - radii[3].set(cornerRadius, cornerRadius); + radii[3].set(cornerRadius.x, cornerRadius.y); } else if ((leftEqual && bounds.fBottom <= insetCrop.fBottom) || (bottomEqual && bounds.fLeft >= insetCrop.fLeft)) { radii[3].set(0, 0); @@ -1338,22 +1369,22 @@ static bool intersectionIsRoundRect(const SkRect& bounds, const SkRect& crop, inline std::pair<SkRRect, SkRRect> SkiaGLRenderEngine::getBoundsAndClip(const FloatRect& boundsRect, const FloatRect& cropRect, - const float cornerRadius) { + const vec2& cornerRadius) { const SkRect bounds = getSkRect(boundsRect); const SkRect crop = getSkRect(cropRect); SkRRect clip; - if (cornerRadius > 0) { + if (cornerRadius.x > 0 && cornerRadius.y > 0) { // it the crop and the bounds are equivalent or there is no crop then we don't need a clip if (bounds == crop || crop.isEmpty()) { - return {SkRRect::MakeRectXY(bounds, cornerRadius, cornerRadius), clip}; + return {SkRRect::MakeRectXY(bounds, cornerRadius.x, cornerRadius.y), clip}; } // This makes an effort to speed up common, simple bounds + clip combinations by // converting them to a single RRect draw. It is possible there are other cases // that can be converted. if (crop.contains(bounds)) { - const auto insetCrop = crop.makeInset(cornerRadius, cornerRadius); + const auto insetCrop = crop.makeInset(cornerRadius.x, cornerRadius.y); if (insetCrop.contains(bounds)) { return {SkRRect::MakeRect(bounds), clip}; // clip is empty - no rounding required } @@ -1367,7 +1398,7 @@ inline std::pair<SkRRect, SkRRect> SkiaGLRenderEngine::getBoundsAndClip(const Fl } // we didn't hit any of our fast paths so set the clip to the cropRect - clip.setRectXY(crop, cornerRadius, cornerRadius); + clip.setRectXY(crop, cornerRadius.x, cornerRadius.y); } // if we hit this point then we either don't have rounded corners or we are going to rely diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h index 5ef9944b14..34f18c1fde 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.h +++ b/libs/renderengine/skia/SkiaGLRenderEngine.h @@ -41,6 +41,10 @@ #include "filters/LinearEffect.h" #include "filters/StretchShaderFactory.h" +class SkData; + +struct SkPoint3; + namespace android { namespace renderengine { namespace skia { @@ -90,7 +94,8 @@ private: inline SkRect getSkRect(const FloatRect& layer); inline SkRect getSkRect(const Rect& layer); inline std::pair<SkRRect, SkRRect> getBoundsAndClip(const FloatRect& bounds, - const FloatRect& crop, float cornerRadius); + const FloatRect& crop, + const vec2& cornerRadius); inline bool layerHasBlur(const LayerSettings& layer, bool colorTransformModifiesAlpha); inline SkColor getSkColor(const vec4& color); inline SkM44 getSkM44(const mat4& matrix); diff --git a/libs/renderengine/skia/debug/SkiaCapture.cpp b/libs/renderengine/skia/debug/SkiaCapture.cpp index 856fff4b01..b21b01cc1b 100644 --- a/libs/renderengine/skia/debug/SkiaCapture.cpp +++ b/libs/renderengine/skia/debug/SkiaCapture.cpp @@ -27,6 +27,9 @@ #include <utils/Trace.h> #include "CommonPool.h" +#include "SkCanvas.h" +#include "SkRect.h" +#include "SkTypeface.h" #include "src/utils/SkMultiPictureDocument.h" namespace android { diff --git a/libs/renderengine/skia/debug/SkiaCapture.h b/libs/renderengine/skia/debug/SkiaCapture.h index f1946290ca..d65a579916 100644 --- a/libs/renderengine/skia/debug/SkiaCapture.h +++ b/libs/renderengine/skia/debug/SkiaCapture.h @@ -19,13 +19,15 @@ #include <SkDocument.h> #include <SkNWayCanvas.h> #include <SkPictureRecorder.h> +#include <SkRefCnt.h> +#include <SkStream.h> #include <SkSurface.h> +#include "tools/SkSharingProc.h" #include <chrono> #include <mutex> #include "CaptureTimer.h" -#include "tools/SkSharingProc.h" namespace android { namespace renderengine { diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp index 63cc02b7ea..2557ac9770 100644 --- a/libs/renderengine/skia/filters/BlurFilter.cpp +++ b/libs/renderengine/skia/filters/BlurFilter.cpp @@ -17,7 +17,6 @@ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include "BlurFilter.h" #include <SkCanvas.h> -#include <SkData.h> #include <SkPaint.h> #include <SkRRect.h> #include <SkRuntimeEffect.h> diff --git a/libs/renderengine/skia/filters/GaussianBlurFilter.cpp b/libs/renderengine/skia/filters/GaussianBlurFilter.cpp index 55867a95cc..f3b6ab9885 100644 --- a/libs/renderengine/skia/filters/GaussianBlurFilter.cpp +++ b/libs/renderengine/skia/filters/GaussianBlurFilter.cpp @@ -18,7 +18,6 @@ #include "GaussianBlurFilter.h" #include <SkCanvas.h> -#include <SkData.h> #include <SkPaint.h> #include <SkRRect.h> #include <SkRuntimeEffect.h> diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp index bfde06fd9a..e370c39a94 100644 --- a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp +++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp @@ -18,7 +18,6 @@ #include "KawaseBlurFilter.h" #include <SkCanvas.h> -#include <SkData.h> #include <SkPaint.h> #include <SkRRect.h> #include <SkRuntimeEffect.h> diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp index 7c70a748b5..f2897308af 100644 --- a/libs/renderengine/tests/RenderEngineTest.cpp +++ b/libs/renderengine/tests/RenderEngineTest.cpp @@ -444,7 +444,9 @@ public: const ubyte4& backgroundColor) { const Rect casterRect(castingLayer.geometry.boundaries); Region casterRegion = Region(casterRect); - const float casterCornerRadius = castingLayer.geometry.roundedCornersRadius; + const float casterCornerRadius = (castingLayer.geometry.roundedCornersRadius.x + + castingLayer.geometry.roundedCornersRadius.y) / + 2.0; if (casterCornerRadius > 0.0f) { // ignore the corners if a corner radius is set Rect cornerRect(casterCornerRadius, casterCornerRadius); @@ -1129,7 +1131,7 @@ void RenderEngineTest::fillRedBufferWithRoundedCorners() { renderengine::LayerSettings layer; layer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; layer.geometry.boundaries = fullscreenRect().toFloatRect(); - layer.geometry.roundedCornersRadius = 5.0f; + layer.geometry.roundedCornersRadius = {5.0f, 5.0f}; layer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect(); SourceVariant::fillColor(layer, 1.0f, 0.0f, 0.0f, this); layer.alpha = 1.0f; @@ -1606,6 +1608,36 @@ TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) { drawEmptyLayers(); } +TEST_P(RenderEngineTest, drawLayers_fillRedBufferAndEmptyBuffer) { + const auto& renderEngineFactory = GetParam(); + if (renderEngineFactory->type() == renderengine::RenderEngine::RenderEngineType::GLES) { + // GLES-specific test + return; + } + + initializeRenderEngine(); + renderengine::DisplaySettings settings; + settings.physicalDisplay = fullscreenRect(); + settings.clip = fullscreenRect(); + settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; + + // add a red layer + renderengine::LayerSettings layerOne{ + .geometry.boundaries = fullscreenRect().toFloatRect(), + .source.solidColor = half3(1.0f, 0.0f, 0.0f), + .alpha = 1.f, + }; + + std::vector<renderengine::LayerSettings> layersFirst{layerOne}; + invokeDraw(settings, layersFirst); + expectBufferColor(fullscreenRect(), 255, 0, 0, 255); + + // re-draw with an empty layer above it, and we get a transparent black one + std::vector<renderengine::LayerSettings> layersSecond; + invokeDraw(settings, layersSecond); + expectBufferColor(fullscreenRect(), 0, 0, 0, 0); +} + TEST_P(RenderEngineTest, drawLayers_withoutBuffers_withColorTransform) { initializeRenderEngine(); @@ -2131,7 +2163,7 @@ TEST_P(RenderEngineTest, drawLayers_fillShadow_casterWithRoundedCorner) { casterBounds.offsetBy(shadowLength + 1, shadowLength + 1); renderengine::LayerSettings castingLayer; castingLayer.geometry.boundaries = casterBounds.toFloatRect(); - castingLayer.geometry.roundedCornersRadius = 3.0f; + castingLayer.geometry.roundedCornersRadius = {3.0f, 3.0f}; castingLayer.geometry.roundedCornersCrop = casterBounds.toFloatRect(); castingLayer.alpha = 1.0f; renderengine::ShadowSettings settings = @@ -2219,7 +2251,8 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; redLayer.geometry.boundaries = fullscreenRect().toFloatRect(); - redLayer.geometry.roundedCornersRadius = 5.0f; + redLayer.geometry.roundedCornersRadius = {5.0f, 5.0f}; + redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect(); // Red background. redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); @@ -2231,7 +2264,7 @@ TEST_P(RenderEngineTest, testRoundedCornersCrop) { renderengine::LayerSettings greenLayer; greenLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; greenLayer.geometry.boundaries = fullscreenRect().toFloatRect(); - greenLayer.geometry.roundedCornersRadius = 5.0f; + greenLayer.geometry.roundedCornersRadius = {5.0f, 5.0f}; // Bottom right corner is not going to be rounded. greenLayer.geometry.roundedCornersCrop = Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3, DEFAULT_DISPLAY_HEIGHT, @@ -2268,7 +2301,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCrop) { renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; redLayer.geometry.boundaries = fullscreenRect().toFloatRect(); - redLayer.geometry.roundedCornersRadius = 5.0f; + redLayer.geometry.roundedCornersRadius = {5.0f, 5.0f}; redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect(); // Red background. redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); @@ -2313,7 +2346,7 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) { renderengine::LayerSettings redLayer; redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; redLayer.geometry.boundaries = FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, 32); - redLayer.geometry.roundedCornersRadius = 64; + redLayer.geometry.roundedCornersRadius = {64.0f, 64.0f}; redLayer.geometry.roundedCornersCrop = FloatRect(0, 0, DEFAULT_DISPLAY_WIDTH, 128); // Red background. redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); @@ -2334,6 +2367,49 @@ TEST_P(RenderEngineTest, testRoundedCornersParentCropSmallBounds) { expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH / 2, 31), 255, 0, 0, 255); } +TEST_P(RenderEngineTest, testRoundedCornersXY) { + if (GetParam()->type() != renderengine::RenderEngine::RenderEngineType::SKIA_GL) { + GTEST_SKIP(); + } + + initializeRenderEngine(); + + renderengine::DisplaySettings settings; + settings.physicalDisplay = fullscreenRect(); + settings.clip = fullscreenRect(); + settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR; + + std::vector<renderengine::LayerSettings> layers; + + renderengine::LayerSettings redLayer; + redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR; + redLayer.geometry.boundaries = fullscreenRect().toFloatRect(); + redLayer.geometry.roundedCornersRadius = {5.0f, 20.0f}; + redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect(); + // Red background. + redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f); + redLayer.alpha = 1.0f; + + layers.push_back(redLayer); + + invokeDraw(settings, layers); + + // Due to roundedCornersRadius, the corners are untouched. + expectBufferColor(Point(0, 0), 0, 0, 0, 0); + expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, 0), 0, 0, 0, 0); + expectBufferColor(Point(0, DEFAULT_DISPLAY_HEIGHT - 1), 0, 0, 0, 0); + expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 1), 0, 0, 0, 0); + + // Y-axis draws a larger radius, check that its untouched as well + expectBufferColor(Point(0, DEFAULT_DISPLAY_HEIGHT - 5), 0, 0, 0, 0); + expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 5), 0, 0, 0, 0); + expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH - 1, 5), 0, 0, 0, 0); + expectBufferColor(Point(0, 5), 0, 0, 0, 0); + + // middle should be red + expectBufferColor(Point(DEFAULT_DISPLAY_WIDTH / 2, DEFAULT_DISPLAY_HEIGHT / 2), 255, 0, 0, 255); +} + TEST_P(RenderEngineTest, testClear) { initializeRenderEngine(); @@ -2411,6 +2487,55 @@ TEST_P(RenderEngineTest, testDisableBlendingBuffer) { expectBufferColor(rect, 0, 128, 0, 128); } +TEST_P(RenderEngineTest, testBorder) { + if (GetParam()->type() != renderengine::RenderEngine::RenderEngineType::SKIA_GL) { + GTEST_SKIP(); + } + + if (!GetParam()->useColorManagement()) { + GTEST_SKIP(); + } + + initializeRenderEngine(); + + const ui::Dataspace dataspace = ui::Dataspace::V0_SRGB; + + const auto displayRect = Rect(1080, 2280); + renderengine::DisplaySettings display{ + .physicalDisplay = displayRect, + .clip = displayRect, + .outputDataspace = dataspace, + }; + display.borderInfoList.clear(); + renderengine::BorderRenderInfo info; + info.combinedRegion = Region(Rect(99, 99, 199, 199)); + info.width = 20.0f; + info.color = half4{1.0f, 128.0f / 255.0f, 0.0f, 1.0f}; + display.borderInfoList.emplace_back(info); + + const auto greenBuffer = allocateAndFillSourceBuffer(1, 1, ubyte4(0, 255, 0, 255)); + const renderengine::LayerSettings greenLayer{ + .geometry.boundaries = FloatRect(0.f, 0.f, 1.f, 1.f), + .source = + renderengine::PixelSource{ + .buffer = + renderengine::Buffer{ + .buffer = greenBuffer, + .usePremultipliedAlpha = true, + }, + }, + .alpha = 1.0f, + .sourceDataspace = dataspace, + .whitePointNits = 200.f, + }; + + std::vector<renderengine::LayerSettings> layers; + layers.emplace_back(greenLayer); + invokeDraw(display, layers); + + expectBufferColor(Rect(99, 99, 101, 101), 255, 128, 0, 255, 1); +} + TEST_P(RenderEngineTest, testDimming) { if (GetParam()->type() == renderengine::RenderEngine::RenderEngineType::GLES) { GTEST_SKIP(); diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp index 0f771a9070..ca8adfa445 100644 --- a/libs/ui/Android.bp +++ b/libs/ui/Android.bp @@ -127,7 +127,6 @@ cc_library_shared { "DebugUtils.cpp", "DeviceProductInfo.cpp", "DisplayIdentification.cpp", - "DisplayMode.cpp", "DynamicDisplayInfo.cpp", "Fence.cpp", "FenceTime.cpp", @@ -139,11 +138,9 @@ cc_library_shared { "GraphicBuffer.cpp", "GraphicBufferAllocator.cpp", "GraphicBufferMapper.cpp", - "HdrCapabilities.cpp", "PixelFormat.cpp", "PublicFormat.cpp", "StaticAsserts.cpp", - "StaticDisplayInfo.cpp", ], include_dirs: [ @@ -241,10 +238,6 @@ cc_library_shared { ], afdo: true, - - header_abi_checker: { - diff_flags: ["-allow-adding-removing-weak-symbols"], - }, } cc_library_headers { diff --git a/libs/ui/DeviceProductInfo.cpp b/libs/ui/DeviceProductInfo.cpp index 04d9d3c989..33060126ff 100644 --- a/libs/ui/DeviceProductInfo.cpp +++ b/libs/ui/DeviceProductInfo.cpp @@ -17,7 +17,6 @@ #include <ui/DeviceProductInfo.h> #include <android-base/stringprintf.h> -#include <ui/FlattenableHelpers.h> #include <utils/Log.h> #define RETURN_IF_ERROR(op) \ @@ -27,35 +26,6 @@ namespace android { using base::StringAppendF; -size_t DeviceProductInfo::getFlattenedSize() const { - return FlattenableHelpers::getFlattenedSize(name) + - FlattenableHelpers::getFlattenedSize(manufacturerPnpId) + - FlattenableHelpers::getFlattenedSize(productId) + - FlattenableHelpers::getFlattenedSize(manufactureOrModelDate) + - FlattenableHelpers::getFlattenedSize(relativeAddress); -} - -status_t DeviceProductInfo::flatten(void* buffer, size_t size) const { - if (size < getFlattenedSize()) { - return NO_MEMORY; - } - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, name)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, manufacturerPnpId)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, productId)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, manufactureOrModelDate)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, relativeAddress)); - return OK; -} - -status_t DeviceProductInfo::unflatten(void const* buffer, size_t size) { - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &name)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &manufacturerPnpId)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &productId)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &manufactureOrModelDate)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &relativeAddress)); - return OK; -} - void DeviceProductInfo::dump(std::string& result) const { StringAppendF(&result, "{name=\"%s\", ", name.c_str()); StringAppendF(&result, "manufacturerPnpId=%s, ", manufacturerPnpId.data()); diff --git a/libs/ui/DisplayMode.cpp b/libs/ui/DisplayMode.cpp deleted file mode 100644 index cf05dbfb05..0000000000 --- a/libs/ui/DisplayMode.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <ui/DisplayMode.h> - -#include <cstdint> - -#include <ui/FlattenableHelpers.h> - -#define RETURN_IF_ERROR(op) \ - if (const status_t status = (op); status != OK) return status; - -namespace android::ui { - -size_t DisplayMode::getFlattenedSize() const { - return FlattenableHelpers::getFlattenedSize(id) + - FlattenableHelpers::getFlattenedSize(resolution) + - FlattenableHelpers::getFlattenedSize(xDpi) + - FlattenableHelpers::getFlattenedSize(yDpi) + - FlattenableHelpers::getFlattenedSize(refreshRate) + - FlattenableHelpers::getFlattenedSize(appVsyncOffset) + - FlattenableHelpers::getFlattenedSize(sfVsyncOffset) + - FlattenableHelpers::getFlattenedSize(presentationDeadline) + - FlattenableHelpers::getFlattenedSize(group); -} - -status_t DisplayMode::flatten(void* buffer, size_t size) const { - if (size < getFlattenedSize()) { - return NO_MEMORY; - } - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, id)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, resolution)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, xDpi)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, yDpi)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, refreshRate)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, appVsyncOffset)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, sfVsyncOffset)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, presentationDeadline)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, group)); - return OK; -} - -status_t DisplayMode::unflatten(const void* buffer, size_t size) { - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &id)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &resolution)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &xDpi)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &yDpi)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &refreshRate)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &appVsyncOffset)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &sfVsyncOffset)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &presentationDeadline)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &group)); - return OK; -} - -} // namespace android::ui diff --git a/libs/ui/DynamicDisplayInfo.cpp b/libs/ui/DynamicDisplayInfo.cpp index 78ba9965b6..f5feea925d 100644 --- a/libs/ui/DynamicDisplayInfo.cpp +++ b/libs/ui/DynamicDisplayInfo.cpp @@ -18,11 +18,6 @@ #include <cstdint> -#include <ui/FlattenableHelpers.h> - -#define RETURN_IF_ERROR(op) \ - if (const status_t status = (op); status != OK) return status; - namespace android::ui { std::optional<ui::DisplayMode> DynamicDisplayInfo::getActiveDisplayMode() const { @@ -34,42 +29,4 @@ std::optional<ui::DisplayMode> DynamicDisplayInfo::getActiveDisplayMode() const return {}; } -size_t DynamicDisplayInfo::getFlattenedSize() const { - return FlattenableHelpers::getFlattenedSize(supportedDisplayModes) + - FlattenableHelpers::getFlattenedSize(activeDisplayModeId) + - FlattenableHelpers::getFlattenedSize(supportedColorModes) + - FlattenableHelpers::getFlattenedSize(activeColorMode) + - FlattenableHelpers::getFlattenedSize(hdrCapabilities) + - FlattenableHelpers::getFlattenedSize(autoLowLatencyModeSupported) + - FlattenableHelpers::getFlattenedSize(gameContentTypeSupported) + - FlattenableHelpers::getFlattenedSize(preferredBootDisplayMode); -} - -status_t DynamicDisplayInfo::flatten(void* buffer, size_t size) const { - if (size < getFlattenedSize()) { - return NO_MEMORY; - } - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, supportedDisplayModes)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, activeDisplayModeId)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, supportedColorModes)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, activeColorMode)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, hdrCapabilities)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, autoLowLatencyModeSupported)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, gameContentTypeSupported)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, preferredBootDisplayMode)); - return OK; -} - -status_t DynamicDisplayInfo::unflatten(const void* buffer, size_t size) { - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &supportedDisplayModes)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &activeDisplayModeId)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &supportedColorModes)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &activeColorMode)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &hdrCapabilities)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &autoLowLatencyModeSupported)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &gameContentTypeSupported)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &preferredBootDisplayMode)); - return OK; -} - } // namespace android::ui diff --git a/libs/ui/HdrCapabilities.cpp b/libs/ui/HdrCapabilities.cpp deleted file mode 100644 index aec2fac780..0000000000 --- a/libs/ui/HdrCapabilities.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <ui/HdrCapabilities.h> - -namespace android { - -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wundefined-reinterpret-cast" -#endif - -size_t HdrCapabilities::getFlattenedSize() const { - return sizeof(mMaxLuminance) + - sizeof(mMaxAverageLuminance) + - sizeof(mMinLuminance) + - sizeof(int32_t) + - mSupportedHdrTypes.size() * sizeof(ui::Hdr); -} - -status_t HdrCapabilities::flatten(void* buffer, size_t size) const { - - if (size < getFlattenedSize()) { - return NO_MEMORY; - } - - int32_t* const buf = static_cast<int32_t*>(buffer); - reinterpret_cast<float&>(buf[0]) = mMaxLuminance; - reinterpret_cast<float&>(buf[1]) = mMaxAverageLuminance; - reinterpret_cast<float&>(buf[2]) = mMinLuminance; - buf[3] = static_cast<int32_t>(mSupportedHdrTypes.size()); - for (size_t i = 0, c = mSupportedHdrTypes.size(); i < c; ++i) { - buf[4 + i] = static_cast<int32_t>(mSupportedHdrTypes[i]); - } - return NO_ERROR; -} - -status_t HdrCapabilities::unflatten(void const* buffer, size_t size) { - - size_t minSize = sizeof(mMaxLuminance) + - sizeof(mMaxAverageLuminance) + - sizeof(mMinLuminance) + - sizeof(int32_t); - - if (size < minSize) { - return NO_MEMORY; - } - - int32_t const * const buf = static_cast<int32_t const *>(buffer); - const size_t itemCount = size_t(buf[3]); - - // check the buffer is large enough - if (size < minSize + itemCount * sizeof(int32_t)) { - return BAD_VALUE; - } - - mMaxLuminance = reinterpret_cast<float const&>(buf[0]); - mMaxAverageLuminance = reinterpret_cast<float const&>(buf[1]); - mMinLuminance = reinterpret_cast<float const&>(buf[2]); - if (itemCount) { - mSupportedHdrTypes.resize(itemCount); - for (size_t i = 0; i < itemCount; ++i) { - mSupportedHdrTypes[i] = static_cast<ui::Hdr>(buf[4 + i]); - } - } - return NO_ERROR; -} - -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - -} // namespace android diff --git a/libs/ui/StaticDisplayInfo.cpp b/libs/ui/StaticDisplayInfo.cpp deleted file mode 100644 index 03d15e4694..0000000000 --- a/libs/ui/StaticDisplayInfo.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <ui/StaticDisplayInfo.h> - -#include <cstdint> - -#include <ui/FlattenableHelpers.h> - -#define RETURN_IF_ERROR(op) \ - if (const status_t status = (op); status != OK) return status; - -namespace android::ui { - -size_t StaticDisplayInfo::getFlattenedSize() const { - return FlattenableHelpers::getFlattenedSize(connectionType) + - FlattenableHelpers::getFlattenedSize(density) + - FlattenableHelpers::getFlattenedSize(secure) + - FlattenableHelpers::getFlattenedSize(deviceProductInfo) + - FlattenableHelpers::getFlattenedSize(installOrientation); -} - -status_t StaticDisplayInfo::flatten(void* buffer, size_t size) const { - if (size < getFlattenedSize()) { - return NO_MEMORY; - } - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, connectionType)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, density)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, secure)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, deviceProductInfo)); - RETURN_IF_ERROR(FlattenableHelpers::flatten(&buffer, &size, installOrientation)); - return OK; -} - -status_t StaticDisplayInfo::unflatten(void const* buffer, size_t size) { - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &connectionType)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &density)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &secure)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &deviceProductInfo)); - RETURN_IF_ERROR(FlattenableHelpers::unflatten(&buffer, &size, &installOrientation)); - return OK; -} - -} // namespace android::ui diff --git a/libs/ui/include/ui/DeviceProductInfo.h b/libs/ui/include/ui/DeviceProductInfo.h index 807a5d96a3..879e46fbdc 100644 --- a/libs/ui/include/ui/DeviceProductInfo.h +++ b/libs/ui/include/ui/DeviceProductInfo.h @@ -24,8 +24,6 @@ #include <variant> #include <vector> -#include <utils/Flattenable.h> - namespace android { // NUL-terminated plug and play ID. @@ -34,7 +32,7 @@ using PnpId = std::array<char, 4>; // Product-specific information about the display or the directly connected device on the // display chain. For example, if the display is transitively connected, this field may contain // product information about the intermediate device. -struct DeviceProductInfo : LightFlattenable<DeviceProductInfo> { +struct DeviceProductInfo { struct ModelYear { uint32_t year; }; @@ -64,11 +62,6 @@ struct DeviceProductInfo : LightFlattenable<DeviceProductInfo> { // For example, for HDMI connected device this will be the physical address. std::vector<uint8_t> relativeAddress; - bool isFixedSize() const { return false; } - size_t getFlattenedSize() const; - status_t flatten(void* buffer, size_t size) const; - status_t unflatten(void const* buffer, size_t size); - void dump(std::string& result) const; }; diff --git a/libs/ui/include/ui/DisplayMode.h b/libs/ui/include/ui/DisplayMode.h index 56f68e7bb2..a2791a6d44 100644 --- a/libs/ui/include/ui/DisplayMode.h +++ b/libs/ui/include/ui/DisplayMode.h @@ -29,7 +29,7 @@ namespace android::ui { using DisplayModeId = int32_t; // Mode supported by physical display. -struct DisplayMode : LightFlattenable<DisplayMode> { +struct DisplayMode { DisplayModeId id; ui::Size resolution; float xDpi = 0; @@ -40,11 +40,6 @@ struct DisplayMode : LightFlattenable<DisplayMode> { nsecs_t sfVsyncOffset = 0; nsecs_t presentationDeadline = 0; int32_t group = -1; - - bool isFixedSize() const { return false; } - size_t getFlattenedSize() const; - status_t flatten(void* buffer, size_t size) const; - status_t unflatten(const void* buffer, size_t size); }; } // namespace android::ui diff --git a/libs/ui/include/ui/DynamicDisplayInfo.h b/libs/ui/include/ui/DynamicDisplayInfo.h index ce75a65214..8c9fe4c311 100644 --- a/libs/ui/include/ui/DynamicDisplayInfo.h +++ b/libs/ui/include/ui/DynamicDisplayInfo.h @@ -24,12 +24,11 @@ #include <ui/GraphicTypes.h> #include <ui/HdrCapabilities.h> -#include <utils/Flattenable.h> namespace android::ui { // Information about a physical display which may change on hotplug reconnect. -struct DynamicDisplayInfo : LightFlattenable<DynamicDisplayInfo> { +struct DynamicDisplayInfo { std::vector<ui::DisplayMode> supportedDisplayModes; // This struct is going to be serialized over binder, so @@ -53,11 +52,6 @@ struct DynamicDisplayInfo : LightFlattenable<DynamicDisplayInfo> { ui::DisplayModeId preferredBootDisplayMode; std::optional<ui::DisplayMode> getActiveDisplayMode() const; - - bool isFixedSize() const { return false; } - size_t getFlattenedSize() const; - status_t flatten(void* buffer, size_t size) const; - status_t unflatten(const void* buffer, size_t size); }; } // namespace android::ui diff --git a/libs/ui/include/ui/HdrCapabilities.h b/libs/ui/include/ui/HdrCapabilities.h index 813addeca6..ae54223585 100644 --- a/libs/ui/include/ui/HdrCapabilities.h +++ b/libs/ui/include/ui/HdrCapabilities.h @@ -22,12 +22,10 @@ #include <vector> #include <ui/GraphicTypes.h> -#include <utils/Flattenable.h> namespace android { -class HdrCapabilities : public LightFlattenable<HdrCapabilities> -{ +class HdrCapabilities { public: HdrCapabilities(const std::vector<ui::Hdr>& types, float maxLuminance, float maxAverageLuminance, float minLuminance) @@ -49,12 +47,6 @@ public: float getDesiredMaxAverageLuminance() const { return mMaxAverageLuminance; } float getDesiredMinLuminance() const { return mMinLuminance; } - // Flattenable protocol - bool isFixedSize() const { return false; } - size_t getFlattenedSize() const; - status_t flatten(void* buffer, size_t size) const; - status_t unflatten(void const* buffer, size_t size); - private: std::vector<ui::Hdr> mSupportedHdrTypes; float mMaxLuminance; diff --git a/libs/ui/include/ui/StaticDisplayInfo.h b/libs/ui/include/ui/StaticDisplayInfo.h index cc7c869b3b..566e4172a1 100644 --- a/libs/ui/include/ui/StaticDisplayInfo.h +++ b/libs/ui/include/ui/StaticDisplayInfo.h @@ -20,24 +20,18 @@ #include <ui/DeviceProductInfo.h> #include <ui/Rotation.h> -#include <utils/Flattenable.h> namespace android::ui { enum class DisplayConnectionType { Internal, External }; // Immutable information about physical display. -struct StaticDisplayInfo : LightFlattenable<StaticDisplayInfo> { +struct StaticDisplayInfo { DisplayConnectionType connectionType = DisplayConnectionType::Internal; float density = 0.f; bool secure = false; std::optional<DeviceProductInfo> deviceProductInfo; Rotation installOrientation = ROTATION_0; - - bool isFixedSize() const { return false; } - size_t getFlattenedSize() const; - status_t flatten(void* buffer, size_t size) const; - status_t unflatten(void const* buffer, size_t size); }; } // namespace android::ui diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp index 76fd7f0f3f..dd14bcfb55 100644 --- a/opengl/libs/EGL/Loader.cpp +++ b/opengl/libs/EGL/Loader.cpp @@ -207,7 +207,8 @@ void* Loader::open(egl_connection_t* cnx) ATRACE_CALL(); const nsecs_t openTime = systemTime(); - if (should_unload_system_driver(cnx)) { + if (!android::GraphicsEnv::getInstance().angleIsSystemDriver() && + should_unload_system_driver(cnx)) { unload_system_driver(cnx); } @@ -216,8 +217,13 @@ void* Loader::open(egl_connection_t* cnx) return cnx->dso; } - // Firstly, try to load ANGLE driver. - driver_t* hnd = attempt_to_load_angle(cnx); + // Firstly, try to load ANGLE driver, unless we know that we shouldn't. + bool shouldForceLegacyDriver = android::GraphicsEnv::getInstance().shouldForceLegacyDriver(); + driver_t* hnd = nullptr; + if (!shouldForceLegacyDriver) { + hnd = attempt_to_load_angle(cnx); + } + if (!hnd) { // Secondly, try to load from driver apk. hnd = attempt_to_load_updated_driver(cnx); @@ -230,21 +236,29 @@ void* Loader::open(egl_connection_t* cnx) LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s", android::GraphicsEnv::getInstance().getDriverPath().c_str()); } - // Finally, try to load system driver, start by searching for the library name appended by - // the system properties of the GLES userspace driver in both locations. - // i.e.: - // libGLES_${prop}.so, or: - // libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so - for (auto key : HAL_SUBNAME_KEY_PROPERTIES) { - auto prop = base::GetProperty(key, ""); - if (prop.empty()) { - continue; - } - hnd = attempt_to_load_system_driver(cnx, prop.c_str(), true); - if (hnd) { - break; - } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) { - failToLoadFromDriverSuffixProperty = true; + // Finally, try to load system driver. If ANGLE is the system driver + // (i.e. we are forcing the legacy system driver instead of ANGLE), use + // the driver suffix that was passed down from above. + if (shouldForceLegacyDriver) { + std::string suffix = android::GraphicsEnv::getInstance().getLegacySuffix(); + hnd = attempt_to_load_system_driver(cnx, suffix.c_str(), true); + } else { + // Start by searching for the library name appended by the system + // properties of the GLES userspace driver in both locations. + // i.e.: + // libGLES_${prop}.so, or: + // libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so + for (auto key : HAL_SUBNAME_KEY_PROPERTIES) { + auto prop = base::GetProperty(key, ""); + if (prop.empty()) { + continue; + } + hnd = attempt_to_load_system_driver(cnx, prop.c_str(), true); + if (hnd) { + break; + } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) { + failToLoadFromDriverSuffixProperty = true; + } } } } diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp index 8ce2f35d7b..21695c354d 100644 --- a/services/inputflinger/InputClassifier.cpp +++ b/services/inputflinger/InputClassifier.cpp @@ -331,20 +331,9 @@ void MotionClassifier::reset(const NotifyDeviceResetArgs& args) { enqueueEvent(std::make_unique<NotifyDeviceResetArgs>(args)); } -const char* MotionClassifier::getServiceStatus() REQUIRES(mLock) { - if (!mService) { - return "null"; - } - - if (AIBinder_ping(mService->asBinder().get()) == STATUS_OK) { - return "running"; - } - return "not responding"; -} - void MotionClassifier::dump(std::string& dump) { std::scoped_lock lock(mLock); - dump += StringPrintf(INDENT2 "mService status: %s\n", getServiceStatus()); + dump += StringPrintf(INDENT2 "mService connected: %s\n", mService ? "true" : "false"); dump += StringPrintf(INDENT2 "mEvents: %zu element(s) (max=%zu)\n", mEvents.size(), MAX_EVENTS); dump += INDENT2 "mClassifications, mLastDownTimes:\n"; @@ -365,6 +354,18 @@ void MotionClassifier::dump(std::string& dump) { } } +void MotionClassifier::monitor() { + std::scoped_lock lock(mLock); + if (mService) { + // Ping the HAL service to ensure it is alive and not blocked. + const binder_status_t status = AIBinder_ping(mService->asBinder().get()); + if (status != STATUS_OK) { + ALOGW("IInputProcessor HAL is not responding; binder ping result: %s", + AStatus_getDescription(AStatus_fromStatus(status))); + } + } +} + // --- InputClassifier --- InputClassifier::InputClassifier(InputListenerInterface& listener) : mQueuedListener(listener) {} @@ -504,6 +505,7 @@ void InputClassifier::dump(std::string& dump) { void InputClassifier::monitor() { std::scoped_lock lock(mLock); + if (mMotionClassifier) mMotionClassifier->monitor(); } InputClassifier::~InputClassifier() { diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h index 56cf760256..9b31a3c33d 100644 --- a/services/inputflinger/InputClassifier.h +++ b/services/inputflinger/InputClassifier.h @@ -78,9 +78,14 @@ public: virtual void reset(const NotifyDeviceResetArgs& args) = 0; /** - * Dump the state of the motion classifier + * Dump the state of the motion classifier. */ virtual void dump(std::string& dump) = 0; + + /** + * Called by the heartbeat to ensure the HAL is still processing normally. + */ + virtual void monitor() = 0; }; /** @@ -96,7 +101,7 @@ public: */ virtual void dump(std::string& dump) = 0; - /* Called by the heatbeat to ensures that the classifier has not deadlocked. */ + /** Called by the heartbeat to ensure that the classifier has not deadlocked. */ virtual void monitor() = 0; InputClassifierInterface() { } @@ -155,13 +160,14 @@ public: virtual void reset(const NotifyDeviceResetArgs& args) override; virtual void dump(std::string& dump) override; + virtual void monitor() override; private: friend class MotionClassifierTest; // to create MotionClassifier with a test HAL implementation explicit MotionClassifier( std::shared_ptr<aidl::android::hardware::input::processor::IInputProcessor> service); - // The events that need to be sent to the HAL. + /** The events that need to be sent to the HAL. */ BlockingQueue<ClassifierEvent> mEvents; /** * Add an event to the queue mEvents. diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING index b4b617e188..f673a287c4 100644 --- a/services/inputflinger/TEST_MAPPING +++ b/services/inputflinger/TEST_MAPPING @@ -45,6 +45,101 @@ ] }, { + "name": "CtsWidgetTestCases", + "options": [ + { + "include-filter": "android.widget.cts.NumberPickerTest" + } + ] + }, + { + "name": "FrameworksCoreTests", + "options": [ + { + "include-filter": "android.view.VerifiedKeyEventTest", + "include-filter": "android.view.VerifiedMotionEventTest" + } + ] + }, + { + "name": "FrameworksServicesTests", + "options": [ + { + "include-filter": "com.android.server.input" + } + ] + }, + { + "name": "CtsSecurityTestCases", + "options": [ + { + "include-filter": "android.security.cts.MotionEventTest" + } + ] + }, + { + "name": "CtsSecurityBulletinHostTestCases", + "options": [ + { + "include-filter": "android.security.cts.Poc19_03#testPocBug_115739809" + } + ] + } + ], + "hwasan-postsubmit": [ + { + "name": "CtsWindowManagerDeviceTestCases", + "options": [ + { + "include-filter": "android.server.wm.WindowInputTests" + } + ] + }, + { + "name": "libinput_tests" + }, + { + "name": "inputflinger_tests" + }, + { + "name": "libpalmrejection_test" + }, + { + "name": "InputTests" + }, + { + "name": "libinputservice_test" + }, + { + "name": "CtsHardwareTestCases", + "options": [ + { + "include-filter": "android.hardware.input.cts.tests" + } + ] + }, + { + "name": "CtsInputTestCases" + }, + { + "name": "CtsViewTestCases", + "options": [ + { + "include-filter": "android.view.cts.MotionEventTest", + "include-filter": "android.view.cts.PointerCaptureTest", + "include-filter": "android.view.cts.VerifyInputEventTest" + } + ] + }, + { + "name": "CtsWidgetTestCases", + "options": [ + { + "include-filter": "android.widget.cts.NumberPickerTest" + } + ] + }, + { "name": "FrameworksCoreTests", "options": [ { diff --git a/services/inputflinger/UnwantedInteractionBlocker.cpp b/services/inputflinger/UnwantedInteractionBlocker.cpp index f57ff33d50..a8e495f235 100644 --- a/services/inputflinger/UnwantedInteractionBlocker.cpp +++ b/services/inputflinger/UnwantedInteractionBlocker.cpp @@ -29,6 +29,14 @@ using android::base::StringPrintf; +/** + * This type is declared here to ensure consistency between the instantiated type (used in the + * constructor via std::make_unique) and the cast-to type (used in PalmRejector::dump() with + * static_cast). Due to the lack of rtti support, dynamic_cast is not available, so this can't be + * checked at runtime to avoid undefined behaviour. + */ +using PalmFilterImplementation = ::ui::NeuralStylusPalmDetectionFilter; + namespace android { // Category (=namespace) name for the input settings that are applied at boot time @@ -81,21 +89,6 @@ static int getLinuxToolType(int32_t toolType) { return MT_TOOL_FINGER; } -static std::string dumpDeviceInfo(const AndroidPalmFilterDeviceInfo& info) { - std::string out; - out += StringPrintf("max_x = %.2f\n", info.max_x); - out += StringPrintf("max_y = %.2f\n", info.max_y); - out += StringPrintf("x_res = %.2f\n", info.x_res); - out += StringPrintf("y_res = %.2f\n", info.y_res); - out += StringPrintf("major_radius_res = %.2f\n", info.major_radius_res); - out += StringPrintf("minor_radius_res = %.2f\n", info.minor_radius_res); - out += StringPrintf("minor_radius_supported = %s\n", - info.minor_radius_supported ? "true" : "false"); - out += StringPrintf("touch_major_res = %" PRId32 "\n", info.touch_major_res); - out += StringPrintf("touch_minor_res = %" PRId32 "\n", info.touch_minor_res); - return out; -} - static int32_t getActionUpForPointerId(const NotifyMotionArgs& args, int32_t pointerId) { for (size_t i = 0; i < args.pointerCount; i++) { if (pointerId == args.pointerProperties[i].id) { @@ -128,15 +121,6 @@ static int32_t resolveActionForPointer(uint8_t pointerIndex, int32_t action) { return AMOTION_EVENT_ACTION_MOVE; } -std::string toString(const ::ui::InProgressTouchEvdev& touch) { - return StringPrintf("x=%.1f, y=%.1f, tracking_id=%i, slot=%zu," - " pressure=%.1f, major=%i, minor=%i, " - "tool_type=%i, altered=%s, was_touching=%s, touching=%s", - touch.x, touch.y, touch.tracking_id, touch.slot, touch.pressure, - touch.major, touch.minor, touch.tool_type, toString(touch.altered), - toString(touch.was_touching), toString(touch.touching)); -} - /** * Remove the data for the provided pointers from the args. The pointers are identified by their * pointerId, not by the index inside the array. @@ -428,9 +412,10 @@ void UnwantedInteractionBlocker::dump(std::string& dump) { dump += "UnwantedInteractionBlocker:\n"; dump += " mPreferStylusOverTouchBlocker:\n"; dump += addLinePrefix(mPreferStylusOverTouchBlocker.dump(), " "); - dump += StringPrintf(" mEnablePalmRejection: %s\n", toString(mEnablePalmRejection)); + dump += StringPrintf(" mEnablePalmRejection: %s\n", + std::to_string(mEnablePalmRejection).c_str()); dump += StringPrintf(" isPalmRejectionEnabled (flag value): %s\n", - toString(isPalmRejectionEnabled())); + std::to_string(isPalmRejectionEnabled()).c_str()); dump += mPalmRejectors.empty() ? " mPalmRejectors: None\n" : " mPalmRejectors:\n"; for (const auto& [deviceId, palmRejector] : mPalmRejectors) { dump += StringPrintf(" deviceId = %" PRId32 ":\n", deviceId); @@ -512,6 +497,15 @@ std::string SlotState::dump() const { return out; } +class AndroidPalmRejectionModel : public ::ui::OneDeviceTrainNeuralStylusPalmDetectionFilterModel { +public: + AndroidPalmRejectionModel() + : ::ui::OneDeviceTrainNeuralStylusPalmDetectionFilterModel(/*default version*/ "", + std::vector<float>()) { + config_.resample_period = ::ui::kResamplePeriod; + } +}; + PalmRejector::PalmRejector(const AndroidPalmFilterDeviceInfo& info, std::unique_ptr<::ui::PalmDetectionFilter> filter) : mSharedPalmState(std::make_unique<::ui::SharedPalmDetectionFilterState>()), @@ -523,11 +517,9 @@ PalmRejector::PalmRejector(const AndroidPalmFilterDeviceInfo& info, return; } std::unique_ptr<::ui::NeuralStylusPalmDetectionFilterModel> model = - std::make_unique<::ui::OneDeviceTrainNeuralStylusPalmDetectionFilterModel>( - std::vector<float>()); - mPalmDetectionFilter = - std::make_unique<::ui::NeuralStylusPalmDetectionFilter>(mDeviceInfo, std::move(model), - mSharedPalmState.get()); + std::make_unique<AndroidPalmRejectionModel>(); + mPalmDetectionFilter = std::make_unique<PalmFilterImplementation>(mDeviceInfo, std::move(model), + mSharedPalmState.get()); } std::vector<::ui::InProgressTouchEvdev> getTouches(const NotifyMotionArgs& args, @@ -648,12 +640,13 @@ std::vector<NotifyMotionArgs> PalmRejector::processMotion(const NotifyMotionArgs LOG_ALWAYS_FATAL_IF(checkArgs.action == ACTION_UNKNOWN, "%s", checkArgs.dump().c_str()); } - if (mSuppressedPointerIds != oldSuppressedIds) { - if (argsWithoutUnwantedPointers.size() != 1 || - argsWithoutUnwantedPointers[0].pointerCount != args.pointerCount) { - ALOGI("Palm detected, removing pointer ids %s from %s", - dumpSet(mSuppressedPointerIds).c_str(), args.dump().c_str()); - } + // Only log if new pointers are getting rejected. That means mSuppressedPointerIds is not a + // subset of oldSuppressedIds. + if (!std::includes(oldSuppressedIds.begin(), oldSuppressedIds.end(), + mSuppressedPointerIds.begin(), mSuppressedPointerIds.end())) { + ALOGI("Palm detected, removing pointer ids %s after %" PRId64 "ms from %s", + dumpSet(mSuppressedPointerIds).c_str(), ns2ms(args.eventTime - args.downTime), + args.dump().c_str()); } return argsWithoutUnwantedPointers; @@ -666,11 +659,21 @@ const AndroidPalmFilterDeviceInfo& PalmRejector::getPalmFilterDeviceInfo() { std::string PalmRejector::dump() const { std::string out; out += "mDeviceInfo:\n"; - out += addLinePrefix(dumpDeviceInfo(mDeviceInfo), " "); + std::stringstream deviceInfo; + deviceInfo << mDeviceInfo << ", touch_major_res=" << mDeviceInfo.touch_major_res + << ", touch_minor_res=" << mDeviceInfo.touch_minor_res << "\n"; + out += addLinePrefix(deviceInfo.str(), " "); out += "mSlotState:\n"; out += addLinePrefix(mSlotState.dump(), " "); out += "mSuppressedPointerIds: "; out += dumpSet(mSuppressedPointerIds) + "\n"; + std::stringstream state; + state << *mSharedPalmState; + out += "mSharedPalmState: " + state.str() + "\n"; + std::stringstream filter; + filter << static_cast<const PalmFilterImplementation&>(*mPalmDetectionFilter); + out += "mPalmDetectionFilter:\n"; + out += addLinePrefix(filter.str(), " ") + "\n"; return out; } diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp index a2e60c4e6f..c9ea068334 100644 --- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp @@ -82,8 +82,6 @@ private: void notifyVibratorState(int32_t deviceId, bool isOn) override {} - void notifyUntrustedTouch(const std::string& obscuringPackage) override {} - void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override { *outConfig = mConfig; } @@ -114,6 +112,8 @@ private: void notifyDropWindow(const sp<IBinder>&, float x, float y) override {} + bool isPerDisplayTouchModeEnabled() override { return false; } + InputDispatcherConfiguration mConfig; }; diff --git a/services/inputflinger/dispatcher/CancelationOptions.h b/services/inputflinger/dispatcher/CancelationOptions.h index 99e2108dbf..fec5f83638 100644 --- a/services/inputflinger/dispatcher/CancelationOptions.h +++ b/services/inputflinger/dispatcher/CancelationOptions.h @@ -17,9 +17,11 @@ #ifndef _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H #define _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H +#include <utils/BitSet.h> #include <optional> -namespace android::inputdispatcher { +namespace android { +namespace inputdispatcher { /* Specifies which events are to be canceled and why. */ struct CancelationOptions { @@ -45,9 +47,13 @@ struct CancelationOptions { // The specific display id of events to cancel, or nullopt to cancel events on any display. std::optional<int32_t> displayId = std::nullopt; + // The specific pointers to cancel, or nullopt to cancel all pointer events + std::optional<BitSet32> pointerIds = std::nullopt; + CancelationOptions(Mode mode, const char* reason) : mode(mode), reason(reason) {} }; -} // namespace android::inputdispatcher +} // namespace inputdispatcher +} // namespace android #endif // _UI_INPUT_INPUTDISPATCHER_CANCELLATIONOPTIONS_H diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp index a02b3e8779..4da846bcf8 100644 --- a/services/inputflinger/dispatcher/FocusResolver.cpp +++ b/services/inputflinger/dispatcher/FocusResolver.cpp @@ -13,24 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -#define LOG_TAG "FocusResolver" +#define LOG_TAG "InputDispatcher" #define ATRACE_TAG ATRACE_TAG_INPUT #define INDENT " " #define INDENT2 " " -// Log debug messages about input focus tracking. -static constexpr bool DEBUG_FOCUS = false; - #include <inttypes.h> #include <android-base/stringprintf.h> #include <binder/Binder.h> #include <ftl/enum.h> #include <gui/WindowInfo.h> -#include <log/log.h> +#include "DebugConfig.h" #include "FocusResolver.h" using android::gui::FocusRequest; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 5e9427ad87..bd55216a6b 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -56,7 +56,6 @@ using android::gui::FocusRequest; using android::gui::TouchOcclusionMode; using android::gui::WindowInfo; using android::gui::WindowInfoHandle; -using android::os::BlockUntrustedTouchesMode; using android::os::IInputConstants; using android::os::InputEventInjectionResult; using android::os::InputEventInjectionSync; @@ -554,7 +553,8 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mWindowTokenWithPointerCapture(nullptr), mStaleEventTimeout(staleEventTimeout), mLatencyAggregator(), - mLatencyTracker(&mLatencyAggregator) { + mLatencyTracker(&mLatencyAggregator), + kPerDisplayTouchModeEnabled(mPolicy->isPerDisplayTouchModeEnabled()) { mLooper = new Looper(false); mReporter = createInputReporter(); @@ -1658,6 +1658,13 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr< InputEventInjectionResult injectionResult; if (isPointerEvent) { // Pointer event. (eg. touchscreen) + + if (mDragState && + (entry->action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_POINTER_DOWN) { + // If drag and drop ongoing and pointer down occur: pilfer drag window pointers + pilferPointersLocked(mDragState->dragWindow->getToken()); + } + injectionResult = findTouchedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime, &conflictingPointerActions); @@ -1866,6 +1873,17 @@ bool InputDispatcher::shouldWaitToSendKeyLocked(nsecs_t currentTime, return false; } +static std::optional<nsecs_t> getDownTime(const EventEntry& eventEntry) { + if (eventEntry.type == EventEntry::Type::KEY) { + const KeyEntry& keyEntry = static_cast<const KeyEntry&>(eventEntry); + return keyEntry.downTime; + } else if (eventEntry.type == EventEntry::Type::MOTION) { + const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry); + return motionEntry.downTime; + } + return std::nullopt; +} + InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( nsecs_t currentTime, const EventEntry& entry, std::vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) { @@ -1955,7 +1973,7 @@ InputEventInjectionResult InputDispatcher::findFocusedWindowTargetsLocked( // Success! Output targets. addWindowTargetLocked(focusedWindowHandle, InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, - BitSet32(0), inputTargets); + BitSet32(0), getDownTime(entry), inputTargets); // Done. return InputEventInjectionResult::SUCCEEDED; @@ -2152,23 +2170,17 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( } // Drop events that can't be trusted due to occlusion - if (mBlockUntrustedTouchesMode != BlockUntrustedTouchesMode::DISABLED) { - TouchOcclusionInfo occlusionInfo = - computeTouchOcclusionInfoLocked(windowHandle, x, y); - if (!isTouchTrustedLocked(occlusionInfo)) { - if (DEBUG_TOUCH_OCCLUSION) { - ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y); - for (const auto& log : occlusionInfo.debugInfo) { - ALOGD("%s", log.c_str()); - } - } - sendUntrustedTouchCommandLocked(occlusionInfo.obscuringPackage); - if (mBlockUntrustedTouchesMode == BlockUntrustedTouchesMode::BLOCK) { - ALOGW("Dropping untrusted touch event due to %s/%d", - occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid); - continue; + TouchOcclusionInfo occlusionInfo = computeTouchOcclusionInfoLocked(windowHandle, x, y); + if (!isTouchTrustedLocked(occlusionInfo)) { + if (DEBUG_TOUCH_OCCLUSION) { + ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y); + for (const auto& log : occlusionInfo.debugInfo) { + ALOGD("%s", log.c_str()); } } + ALOGW("Dropping untrusted touch event due to %s/%d", + occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid); + continue; } // Drop touch events if requested by input feature @@ -2200,8 +2212,18 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( pointerIds.markBit(pointerId); } - tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds); + tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds, + entry.eventTime); } + + // If any existing window is pilfering pointers from newly added window, remove it + BitSet32 canceledPointers = BitSet32(0); + for (const TouchedWindow& window : tempTouchState.windows) { + if (window.isPilferingPointers) { + canceledPointers |= window.pointerIds; + } + } + tempTouchState.cancelPointersForNonPilferingWindows(canceledPointers); } else { /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ @@ -2278,7 +2300,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( if (isSplit) { pointerIds.markBit(entry.pointerProperties[0].id); } - tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); + tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds, + entry.eventTime); } } } @@ -2395,7 +2418,7 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( InputTarget:: FLAG_WINDOW_IS_PARTIALLY_OBSCURED | InputTarget::FLAG_DISPATCH_AS_IS, - BitSet32(0)); + BitSet32(0), entry.eventTime); } } } @@ -2406,7 +2429,8 @@ InputEventInjectionResult InputDispatcher::findTouchedWindowTargetsLocked( for (const TouchedWindow& touchedWindow : tempTouchState.windows) { addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, - touchedWindow.pointerIds, inputTargets); + touchedWindow.pointerIds, touchedWindow.firstDownTimeInTarget, + inputTargets); } // Drop the outside or hover touch windows since we will not care about them @@ -2591,6 +2615,7 @@ void InputDispatcher::addDragEventLocked(const MotionEntry& entry) { void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHandle, int32_t targetFlags, BitSet32 pointerIds, + std::optional<nsecs_t> firstDownTimeInTarget, std::vector<InputTarget>& inputTargets) { std::vector<InputTarget>::iterator it = std::find_if(inputTargets.begin(), inputTargets.end(), @@ -2612,6 +2637,7 @@ void InputDispatcher::addWindowTargetLocked(const sp<WindowInfoHandle>& windowHa inputTarget.inputChannel = inputChannel; inputTarget.flags = targetFlags; inputTarget.globalScaleFactor = windowInfo->globalScaleFactor; + inputTarget.firstDownTimeInTarget = firstDownTimeInTarget; const auto& displayInfoIt = mDisplayInfos.find(windowInfo->displayId); if (displayInfoIt != mDisplayInfos.end()) { inputTarget.displayTransform = displayInfoIt->second.transform; @@ -2637,6 +2663,8 @@ void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& InputTarget target; target.inputChannel = monitor.inputChannel; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; + // target.firstDownTimeInTarget is not set for global monitors. It is only required in split + // touch and global monitoring works as intended even without setting firstDownTimeInTarget if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) { target.displayTransform = it->second.transform; } @@ -2921,8 +2949,12 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry); if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) { + LOG_ALWAYS_FATAL_IF(!inputTarget.firstDownTimeInTarget.has_value(), + "Splitting motion events requires a down time to be set for the " + "target"); std::unique_ptr<MotionEntry> splitMotionEntry = - splitMotionEvent(originalMotionEntry, inputTarget.pointerIds); + splitMotionEvent(originalMotionEntry, inputTarget.pointerIds, + inputTarget.firstDownTimeInTarget.value()); if (!splitMotionEntry) { return; // split event was dropped } @@ -3678,15 +3710,13 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( } void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( - const sp<Connection>& connection) { + const nsecs_t downTime, const sp<Connection>& connection) { if (connection->status == Connection::Status::BROKEN) { return; } - nsecs_t currentTime = now(); - std::vector<std::unique_ptr<EventEntry>> downEvents = - connection->inputState.synthesizePointerDownEvents(currentTime); + connection->inputState.synthesizePointerDownEvents(downTime); if (downEvents.empty()) { return; @@ -3734,11 +3764,11 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( InputTarget::FLAG_DISPATCH_AS_IS); } - startDispatchCycleLocked(currentTime, connection); + startDispatchCycleLocked(downTime, connection); } std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent( - const MotionEntry& originalMotionEntry, BitSet32 pointerIds) { + const MotionEntry& originalMotionEntry, BitSet32 pointerIds, nsecs_t splitDownTime) { ALOG_ASSERT(pointerIds.value != 0); uint32_t splitPointerIndexMap[MAX_POINTERS]; @@ -3806,6 +3836,13 @@ std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent( } } + if (action == AMOTION_EVENT_ACTION_DOWN) { + LOG_ALWAYS_FATAL_IF(splitDownTime != originalMotionEntry.eventTime, + "Split motion event has mismatching downTime and eventTime for " + "ACTION_DOWN, motionEntry=%s, splitDownTime=%" PRId64 "ms", + originalMotionEntry.getDescription().c_str(), ns2ms(splitDownTime)); + } + int32_t newId = mIdGenerator.nextId(); if (ATRACE_ENABLED()) { std::string message = StringPrintf("Split MotionEvent(id=0x%" PRIx32 @@ -3826,9 +3863,9 @@ std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent( originalMotionEntry.xPrecision, originalMotionEntry.yPrecision, originalMotionEntry.xCursorPosition, - originalMotionEntry.yCursorPosition, - originalMotionEntry.downTime, splitPointerCount, - splitPointerProperties, splitPointerCoords); + originalMotionEntry.yCursorPosition, splitDownTime, + splitPointerCount, splitPointerProperties, + splitPointerCoords); if (originalMotionEntry.injectionState) { splitMotionEntry->injectionState = originalMotionEntry.injectionState; @@ -4951,8 +4988,8 @@ void InputDispatcher::setInputFilterEnabled(bool enabled) { mLooper->wake(); } -bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, - bool hasPermission) { +bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission, + int32_t displayId) { bool needWake = false; { std::scoped_lock lock(mLock); @@ -4961,8 +4998,9 @@ bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, } if (DEBUG_TOUCH_MODE) { ALOGD("Request to change touch mode from %s to %s (calling pid=%d, uid=%d, " - "hasPermission=%s)", - toString(mInTouchMode), toString(inTouchMode), pid, uid, toString(hasPermission)); + "hasPermission=%s, target displayId=%d, perDisplayTouchModeEnabled=%s)", + toString(mInTouchMode), toString(inTouchMode), pid, uid, toString(hasPermission), + displayId, toString(kPerDisplayTouchModeEnabled)); } if (!hasPermission) { if (!focusedWindowIsOwnedByLocked(pid, uid) && @@ -4974,7 +5012,7 @@ bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, } } - // TODO(b/198499018): Store touch mode per display. + // TODO(b/198499018): Store touch mode per display (kPerDisplayTouchModeEnabled) mInTouchMode = inTouchMode; auto entry = std::make_unique<TouchModeEntry>(mIdGenerator.nextId(), now(), inTouchMode); @@ -5015,11 +5053,6 @@ void InputDispatcher::setMaximumObscuringOpacityForTouch(float opacity) { mMaximumObscuringOpacityForTouch = opacity; } -void InputDispatcher::setBlockUntrustedTouchesMode(BlockUntrustedTouchesMode mode) { - std::scoped_lock lock(mLock); - mBlockUntrustedTouchesMode = mode; -} - std::pair<TouchState*, TouchedWindow*> InputDispatcher::findTouchStateAndWindowLocked( const sp<IBinder>& token) { for (auto& [displayId, state] : mTouchStatesByDisplay) { @@ -5070,12 +5103,13 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< state->removeWindowByToken(fromToken); // Add new window. + nsecs_t downTimeInTarget = now(); int32_t newTargetFlags = oldTargetFlags & (InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS); if (canReceiveForegroundTouches(*toWindowHandle->getInfo())) { newTargetFlags |= InputTarget::FLAG_FOREGROUND; } - state->addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds); + state->addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds, downTimeInTarget); // Store the dragging window. if (isDragDrop) { @@ -5099,7 +5133,7 @@ bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp< options(CancelationOptions::CANCEL_POINTER_EVENTS, "transferring touch focus from this window to another window"); synthesizeCancelationEventsForConnectionLocked(fromConnection, options); - synthesizePointerDownEventsForConnectionLocked(toConnection); + synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection); } if (DEBUG_FOCUS) { @@ -5249,10 +5283,12 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += INDENT3 "Windows:\n"; for (size_t i = 0; i < state.windows.size(); i++) { const TouchedWindow& touchedWindow = state.windows[i]; - dump += StringPrintf(INDENT4 - "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", + dump += StringPrintf(INDENT4 "%zu: name='%s', pointerIds=0x%0x, " + "targetFlags=0x%x, firstDownTimeInTarget=%" PRId64 + "ms\n", i, touchedWindow.windowHandle->getName().c_str(), - touchedWindow.pointerIds.value, touchedWindow.targetFlags); + touchedWindow.pointerIds.value, touchedWindow.targetFlags, + ns2ms(touchedWindow.firstDownTimeInTarget.value_or(0))); } } else { dump += INDENT3 "Windows: <none>\n"; @@ -5578,7 +5614,10 @@ void InputDispatcher::removeMonitorChannelLocked(const sp<IBinder>& connectionTo status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { std::scoped_lock _l(mLock); + return pilferPointersLocked(token); +} +status_t InputDispatcher::pilferPointersLocked(const sp<IBinder>& token) { const std::shared_ptr<InputChannel> requestingChannel = getInputChannelLocked(token); if (!requestingChannel) { ALOGW("Attempted to pilfer pointers from an un-registered channel or invalid token"); @@ -5593,16 +5632,20 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { } TouchState& state = *statePtr; - + TouchedWindow& window = *windowPtr; // Send cancel events to all the input channels we're stealing from. CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, "input channel stole pointer stream"); options.deviceId = state.deviceId; options.displayId = state.displayId; + if (state.split) { + // If split pointers then selectively cancel pointers otherwise cancel all pointers + options.pointerIds = window.pointerIds; + } std::string canceledWindows; - for (const TouchedWindow& window : state.windows) { + for (const TouchedWindow& w : state.windows) { const std::shared_ptr<InputChannel> channel = - getInputChannelLocked(window.windowHandle->getToken()); + getInputChannelLocked(w.windowHandle->getToken()); if (channel != nullptr && channel->getConnectionToken() != token) { synthesizeCancelationEventsForInputChannelLocked(channel, options); canceledWindows += canceledWindows.empty() ? "[" : ", "; @@ -5614,8 +5657,14 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { canceledWindows.c_str()); // Prevent the gesture from being sent to any other windows. - state.filterWindowsExcept(token); - state.preventNewTargets = true; + // This only blocks relevant pointers to be sent to other windows + window.isPilferingPointers = true; + + if (state.split) { + state.cancelPointersForWindowsExcept(window.pointerIds, token); + } else { + state.filterWindowsExcept(token); + } return OK; } @@ -5787,14 +5836,6 @@ void InputDispatcher::sendDropWindowCommandLocked(const sp<IBinder>& token, floa postCommandLocked(std::move(command)); } -void InputDispatcher::sendUntrustedTouchCommandLocked(const std::string& obscuringPackage) { - auto command = [this, obscuringPackage]() REQUIRES(mLock) { - scoped_unlock unlock(mLock); - mPolicy->notifyUntrustedTouch(obscuringPackage); - }; - postCommandLocked(std::move(command)); -} - void InputDispatcher::onAnrLocked(const sp<Connection>& connection) { if (connection == nullptr) { LOG_ALWAYS_FATAL("Caller must check for nullness"); diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h index ed89ed0b0f..be619ae4c2 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.h +++ b/services/inputflinger/dispatcher/InputDispatcher.h @@ -119,9 +119,9 @@ public: void setFocusedDisplay(int32_t displayId) override; void setInputDispatchMode(bool enabled, bool frozen) override; void setInputFilterEnabled(bool enabled) override; - bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) override; + bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission, + int32_t displayId) override; void setMaximumObscuringOpacityForTouch(float opacity) override; - void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) override; bool transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken, bool isDragDrop = false) override; @@ -256,6 +256,8 @@ private: void removeConnectionLocked(const sp<Connection>& connection) REQUIRES(mLock); + status_t pilferPointersLocked(const sp<IBinder>& token) REQUIRES(mLock); + template <typename T> struct StrongPointerHash { std::size_t operator()(const sp<T>& b) const { return std::hash<T*>{}(b.get()); } @@ -344,7 +346,6 @@ private: bool mInputFilterEnabled GUARDED_BY(mLock); bool mInTouchMode GUARDED_BY(mLock); float mMaximumObscuringOpacityForTouch GUARDED_BY(mLock); - android::os::BlockUntrustedTouchesMode mBlockUntrustedTouchesMode GUARDED_BY(mLock); class DispatcherWindowListener : public gui::WindowInfosListener { public: @@ -550,6 +551,7 @@ private: void addWindowTargetLocked(const sp<android::gui::WindowInfoHandle>& windowHandle, int32_t targetFlags, BitSet32 pointerIds, + std::optional<nsecs_t> firstDownTimeInTarget, std::vector<InputTarget>& inputTargets) REQUIRES(mLock); void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId) REQUIRES(mLock); @@ -621,12 +623,14 @@ private: const CancelationOptions& options) REQUIRES(mLock); - void synthesizePointerDownEventsForConnectionLocked(const sp<Connection>& connection) + void synthesizePointerDownEventsForConnectionLocked(const nsecs_t downTime, + const sp<Connection>& connection) REQUIRES(mLock); - // Splitting motion events across windows. + // Splitting motion events across windows. When splitting motion event for a target, + // splitDownTime refers to the time of first 'down' event on that particular target std::unique_ptr<MotionEntry> splitMotionEvent(const MotionEntry& originalMotionEntry, - BitSet32 pointerIds); + BitSet32 pointerIds, nsecs_t splitDownTime); // Reset and drop everything the dispatcher is doing. void resetAndDropEverythingLocked(const char* reason) REQUIRES(mLock); @@ -652,7 +656,6 @@ private: void sendFocusChangedCommandLocked(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) REQUIRES(mLock); void sendDropWindowCommandLocked(const sp<IBinder>& token, float x, float y) REQUIRES(mLock); - void sendUntrustedTouchCommandLocked(const std::string& obscuringPackage) REQUIRES(mLock); void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock); void onAnrLocked(std::shared_ptr<InputApplicationHandle> application) REQUIRES(mLock); void updateLastAnrStateLocked(const sp<android::gui::WindowInfoHandle>& window, @@ -683,6 +686,9 @@ private: bool focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock); bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock); + // Per display touch mode enabled + const bool kPerDisplayTouchModeEnabled; + sp<InputReporterInterface> mReporter; }; diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp index f46a8bce7e..047c628e67 100644 --- a/services/inputflinger/dispatcher/InputState.cpp +++ b/services/inputflinger/dispatcher/InputState.cpp @@ -286,19 +286,30 @@ std::vector<std::unique_ptr<EventEntry>> InputState::synthesizeCancelationEvents for (const MotionMemento& memento : mMotionMementos) { if (shouldCancelMotion(memento, options)) { - const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT - : AMOTION_EVENT_ACTION_CANCEL; - events.push_back( - std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime, - memento.deviceId, memento.source, - memento.displayId, memento.policyFlags, action, - 0 /*actionButton*/, memento.flags, AMETA_NONE, - 0 /*buttonState*/, MotionClassification::NONE, - AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, - memento.yPrecision, memento.xCursorPosition, - memento.yCursorPosition, memento.downTime, - memento.pointerCount, memento.pointerProperties, - memento.pointerCoords)); + if (options.pointerIds == std::nullopt) { + const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT + : AMOTION_EVENT_ACTION_CANCEL; + events.push_back( + std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime, + memento.deviceId, memento.source, + memento.displayId, memento.policyFlags, + action, 0 /*actionButton*/, memento.flags, + AMETA_NONE, 0 /*buttonState*/, + MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, + memento.xPrecision, memento.yPrecision, + memento.xCursorPosition, + memento.yCursorPosition, memento.downTime, + memento.pointerCount, + memento.pointerProperties, + memento.pointerCoords)); + } else { + std::vector<std::unique_ptr<MotionEntry>> pointerCancelEvents = + synthesizeCancelationEventsForPointers(memento, options.pointerIds.value(), + currentTime); + events.insert(events.end(), std::make_move_iterator(pointerCancelEvents.begin()), + std::make_move_iterator(pointerCancelEvents.end())); + } } } return events; @@ -359,6 +370,73 @@ std::vector<std::unique_ptr<EventEntry>> InputState::synthesizePointerDownEvents return events; } +std::vector<std::unique_ptr<MotionEntry>> InputState::synthesizeCancelationEventsForPointers( + const MotionMemento& memento, const BitSet32 pointerIds, nsecs_t currentTime) { + std::vector<std::unique_ptr<MotionEntry>> events; + std::vector<uint32_t> canceledPointerIndices; + std::vector<PointerProperties> pointerProperties(MAX_POINTERS); + std::vector<PointerCoords> pointerCoords(MAX_POINTERS); + for (uint32_t pointerIdx = 0; pointerIdx < memento.pointerCount; pointerIdx++) { + uint32_t pointerId = uint32_t(memento.pointerProperties[pointerIdx].id); + pointerProperties[pointerIdx].copyFrom(memento.pointerProperties[pointerIdx]); + pointerCoords[pointerIdx].copyFrom(memento.pointerCoords[pointerIdx]); + if (pointerIds.hasBit(pointerId)) { + canceledPointerIndices.push_back(pointerIdx); + } + } + + if (canceledPointerIndices.size() == memento.pointerCount) { + const int32_t action = + memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT : AMOTION_EVENT_ACTION_CANCEL; + events.push_back( + std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime, memento.deviceId, + memento.source, memento.displayId, + memento.policyFlags, action, 0 /*actionButton*/, + memento.flags, AMETA_NONE, 0 /*buttonState*/, + MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, + memento.yPrecision, memento.xCursorPosition, + memento.yCursorPosition, memento.downTime, + memento.pointerCount, memento.pointerProperties, + memento.pointerCoords)); + } else { + // If we aren't canceling all pointers, we need to generated ACTION_POINTER_UP with + // FLAG_CANCELED for each of the canceled pointers. For each event, we must remove the + // previously canceled pointers from PointerProperties and PointerCoords, and update + // pointerCount appropriately. For convenience, sort the canceled pointer indices so that we + // can just slide the remaining pointers to the beginning of the array when a pointer is + // canceled. + std::sort(canceledPointerIndices.begin(), canceledPointerIndices.end(), + std::greater<uint32_t>()); + + uint32_t pointerCount = memento.pointerCount; + for (const uint32_t pointerIdx : canceledPointerIndices) { + const int32_t action = pointerCount == 1 ? AMOTION_EVENT_ACTION_CANCEL + : AMOTION_EVENT_ACTION_POINTER_UP | + (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); + events.push_back( + std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime, + memento.deviceId, memento.source, + memento.displayId, memento.policyFlags, action, + 0 /*actionButton*/, + memento.flags | AMOTION_EVENT_FLAG_CANCELED, + AMETA_NONE, 0 /*buttonState*/, + MotionClassification::NONE, + AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision, + memento.yPrecision, memento.xCursorPosition, + memento.yCursorPosition, memento.downTime, + pointerCount, pointerProperties.data(), + pointerCoords.data())); + + // Cleanup pointer information + pointerProperties.erase(pointerProperties.begin() + pointerIdx); + pointerCoords.erase(pointerCoords.begin() + pointerIdx); + pointerCount--; + } + } + return events; +} + void InputState::clear() { mKeyMementos.clear(); mMotionMementos.clear(); diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h index 74ae21f76a..77a6db19bc 100644 --- a/services/inputflinger/dispatcher/InputState.h +++ b/services/inputflinger/dispatcher/InputState.h @@ -22,7 +22,8 @@ #include <utils/Timers.h> -namespace android::inputdispatcher { +namespace android { +namespace inputdispatcher { static constexpr int32_t INVALID_POINTER_INDEX = -1; @@ -125,8 +126,13 @@ private: static bool shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options); static bool shouldCancelMotion(const MotionMemento& memento, const CancelationOptions& options); + + // Synthesizes pointer cancel events for a particular set of pointers. + std::vector<std::unique_ptr<MotionEntry>> synthesizeCancelationEventsForPointers( + const MotionMemento& memento, const BitSet32 pointerIds, nsecs_t currentTime); }; -} // namespace android::inputdispatcher +} // namespace inputdispatcher +} // namespace android #endif // _UI_INPUT_INPUTDISPATCHER_INPUTSTATE_H diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h index 0725389ed6..ac20dab205 100644 --- a/services/inputflinger/dispatcher/InputTarget.h +++ b/services/inputflinger/dispatcher/InputTarget.h @@ -106,6 +106,9 @@ struct InputTarget { // The subset of pointer ids to include in motion events dispatched to this input target // if FLAG_SPLIT is set. BitSet32 pointerIds; + // Event time for the first motion event (ACTION_DOWN) dispatched to this input target if + // FLAG_SPLIT is set. + std::optional<nsecs_t> firstDownTimeInTarget; // The data is stored by the pointerId. Use the bit position of pointerIds to look up // Transform per pointerId. ui::Transform pointerTransforms[MAX_POINTERS]; diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index 61e78ccbe4..cf0c38af33 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -30,7 +30,7 @@ void TouchState::reset() { } void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, int32_t targetFlags, - BitSet32 pointerIds) { + BitSet32 pointerIds, std::optional<nsecs_t> eventTime) { if (targetFlags & InputTarget::FLAG_SPLIT) { split = true; } @@ -42,17 +42,22 @@ void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle, int if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS; } + // For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have + // downTime set initially. Need to update existing window when an pointer is down for + // the window. touchedWindow.pointerIds.value |= pointerIds.value; + if (!touchedWindow.firstDownTimeInTarget.has_value()) { + touchedWindow.firstDownTimeInTarget = eventTime; + } return; } } - if (preventNewTargets) return; // Don't add new TouchedWindows. - TouchedWindow touchedWindow; touchedWindow.windowHandle = windowHandle; touchedWindow.targetFlags = targetFlags; touchedWindow.pointerIds = pointerIds; + touchedWindow.firstDownTimeInTarget = eventTime; windows.push_back(touchedWindow); } @@ -79,6 +84,27 @@ void TouchState::filterNonAsIsTouchWindows() { } } +void TouchState::cancelPointersForWindowsExcept(const BitSet32 pointerIds, + const sp<IBinder>& token) { + if (pointerIds.isEmpty()) return; + std::for_each(windows.begin(), windows.end(), [&pointerIds, &token](TouchedWindow& w) { + if (w.windowHandle->getToken() != token) { + w.pointerIds &= BitSet32(~pointerIds.value); + } + }); + std::erase_if(windows, [](const TouchedWindow& w) { return w.pointerIds.isEmpty(); }); +} + +void TouchState::cancelPointersForNonPilferingWindows(const BitSet32 pointerIds) { + if (pointerIds.isEmpty()) return; + std::for_each(windows.begin(), windows.end(), [&pointerIds](TouchedWindow& w) { + if (!w.isPilferingPointers) { + w.pointerIds &= BitSet32(~pointerIds.value); + } + }); + std::erase_if(windows, [](const TouchedWindow& w) { return w.pointerIds.isEmpty(); }); +} + void TouchState::filterWindowsExcept(const sp<IBinder>& token) { std::erase_if(windows, [&token](const TouchedWindow& w) { return w.windowHandle->getToken() != token; }); diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 9efb2808c5..1fb51e161d 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -31,7 +31,6 @@ namespace inputdispatcher { struct TouchState { bool down = false; bool split = false; - bool preventNewTargets = false; // id of the device that is currently down, others are rejected int32_t deviceId = -1; @@ -48,10 +47,18 @@ struct TouchState { void reset(); void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle, - int32_t targetFlags, BitSet32 pointerIds); + int32_t targetFlags, BitSet32 pointerIds, + std::optional<nsecs_t> eventTime = std::nullopt); void removeWindowByToken(const sp<IBinder>& token); void filterNonAsIsTouchWindows(); void filterWindowsExcept(const sp<IBinder>& token); + + // Cancel pointers for current set of windows except the window with particular binder token. + void cancelPointersForWindowsExcept(const BitSet32 pointerIds, const sp<IBinder>& token); + // Cancel pointers for current set of non-pilfering windows i.e. windows with isPilferingWindow + // set to false. + void cancelPointersForNonPilferingWindows(const BitSet32 pointerIds); + sp<android::gui::WindowInfoHandle> getFirstForegroundWindowHandle() const; bool isSlippery() const; sp<android::gui::WindowInfoHandle> getWallpaperWindow() const; diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h index 4c31ec3acd..0962d0cc2c 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.h +++ b/services/inputflinger/dispatcher/TouchedWindow.h @@ -30,6 +30,10 @@ struct TouchedWindow { sp<gui::WindowInfoHandle> windowHandle; int32_t targetFlags; BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set + bool isPilferingPointers = false; + // Time at which the first action down occurred on this window. + // NOTE: This is not initialized in case of HOVER entry/exit and DISPATCH_AS_OUTSIDE scenario. + std::optional<nsecs_t> firstDownTimeInTarget; }; } // namespace inputdispatcher diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h index 67fed8b4f1..32b3ddbdeb 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h @@ -20,7 +20,7 @@ #include <InputListener.h> #include <android-base/result.h> #include <android/gui/FocusRequest.h> -#include <android/os/BlockUntrustedTouchesMode.h> + #include <android/os/InputEventInjectionResult.h> #include <android/os/InputEventInjectionSync.h> #include <gui/InputApplication.h> @@ -132,7 +132,8 @@ public: * * Returns true when changing touch mode state. */ - virtual bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) = 0; + virtual bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission, + int32_t displayId) = 0; /** * Sets the maximum allowed obscuring opacity by UID to propagate touches. @@ -142,13 +143,6 @@ public: */ virtual void setMaximumObscuringOpacityForTouch(float opacity) = 0; - /** - * Sets the mode of the block untrusted touches feature. - * - * TODO(b/169067926): Clean-up feature modes. - */ - virtual void setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode mode) = 0; - /* Transfers touch focus from one window to another window. * * Returns true on success. False if the window did not actually have touch focus. diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h index 575b3d7059..7c299b2608 100644 --- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h +++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h @@ -75,9 +75,6 @@ public: InputDeviceSensorAccuracy accuracy) = 0; virtual void notifyVibratorState(int32_t deviceId, bool isOn) = 0; - /* Notifies the system that an untrusted touch occurred. */ - virtual void notifyUntrustedTouch(const std::string& obscuringPackage) = 0; - /* Gets the input dispatcher configuration. */ virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0; @@ -140,6 +137,9 @@ public: /* Notifies the policy that the drag window has moved over to another window */ virtual void notifyDropWindow(const sp<IBinder>& token, float x, float y) = 0; + + /* If touch mode is enabled per display or global */ + virtual bool isPerDisplayTouchModeEnabled() = 0; }; } // namespace android diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp index 2ebdbcfcc4..97d57e4bd0 100644 --- a/services/inputflinger/host/InputDriver.cpp +++ b/services/inputflinger/host/InputDriver.cpp @@ -240,19 +240,16 @@ input_property_map_t* InputDriver::inputGetDevicePropertyMap(input_device_identi return nullptr; } -input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map, - const char* key) { - String8 keyString(key); +input_property_t* InputDriver::inputGetDeviceProperty(input_property_map_t* map, const char* key) { if (map != nullptr) { - if (map->propertyMap->hasProperty(keyString)) { - auto prop = new input_property_t(); - if (!map->propertyMap->tryGetProperty(keyString, prop->value)) { - delete prop; - return nullptr; - } - prop->key = keyString; - return prop; + std::string value; + auto prop = std::make_unique<input_property_t>(); + if (!map->propertyMap->tryGetProperty(key, value)) { + return nullptr; } + prop->key = key; + prop->value = value.c_str(); + return prop.release(); } return nullptr; } diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h index 41ecef365d..77c9142131 100644 --- a/services/inputflinger/include/InputReaderBase.h +++ b/services/inputflinger/include/InputReaderBase.h @@ -95,7 +95,7 @@ public: /* Determine whether physical keys exist for the given framework-domain key codes. */ virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0; + const std::vector<int32_t>& keyCodes, uint8_t* outFlags) = 0; /* Requests that a reconfiguration of all input devices. * The changes flag is a bitfield that indicates what has changed and whether diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp index 669d2e1833..a17d2c0fab 100644 --- a/services/inputflinger/reader/EventHub.cpp +++ b/services/inputflinger/reader/EventHub.cpp @@ -502,7 +502,7 @@ status_t EventHub::Device::loadKeyMapLocked() { bool EventHub::Device::isExternalDeviceLocked() { if (configuration) { bool value; - if (configuration->tryGetProperty(String8("device.internal"), value)) { + if (configuration->tryGetProperty("device.internal", value)) { return !value; } } @@ -512,7 +512,7 @@ bool EventHub::Device::isExternalDeviceLocked() { bool EventHub::Device::deviceHasMicLocked() { if (configuration) { bool value; - if (configuration->tryGetProperty(String8("audio.mic"), value)) { + if (configuration->tryGetProperty("audio.mic", value)) { return value; } } @@ -687,6 +687,7 @@ EventHub::EventHub(void) LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno)); mINotifyFd = inotify_init1(IN_CLOEXEC); + LOG_ALWAYS_FATAL_IF(mINotifyFd < 0, "Could not create inotify instance: %s", strerror(errno)); std::error_code errorCode; bool isDeviceInotifyAdded = false; @@ -952,20 +953,20 @@ status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* return -1; } -bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, +bool EventHub::markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes, uint8_t* outFlags) const { std::scoped_lock _l(mLock); Device* device = getDeviceLocked(deviceId); if (device != nullptr && device->keyMap.haveKeyLayout()) { - for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) { + for (size_t codeIndex = 0; codeIndex < keyCodes.size(); codeIndex++) { std::vector<int32_t> scanCodes = device->keyMap.keyLayoutMap->findScanCodesForKey(keyCodes[codeIndex]); // check the possible scan codes identified by the layout map against the // map of codes actually emitted by the driver - for (size_t sc = 0; sc < scanCodes.size(); sc++) { - if (device->keyBitmask.test(scanCodes[sc])) { + for (const int32_t scanCode : scanCodes) { + if (device->keyBitmask.test(scanCode)) { outFlags[codeIndex] = 1; break; } @@ -1723,7 +1724,10 @@ size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSiz // before closing the devices. if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) { mPendingINotify = false; - readNotifyLocked(); + const auto res = readNotifyLocked(); + if (!res.ok()) { + ALOGW("Failed to read from inotify: %s", res.error().message().c_str()); + } deviceChanged = true; } @@ -2072,10 +2076,9 @@ void EventHub::openDeviceLocked(const std::string& devicePath) { } // See if this is a rotary encoder type device. - String8 deviceType = String8(); - if (device->configuration && - device->configuration->tryGetProperty(String8("device.type"), deviceType)) { - if (!deviceType.compare(String8("rotaryEncoder"))) { + std::string deviceType; + if (device->configuration && device->configuration->tryGetProperty("device.type", deviceType)) { + if (deviceType == "rotaryEncoder") { device->classes |= InputDeviceClass::ROTARY_ENCODER; } } @@ -2413,53 +2416,56 @@ void EventHub::closeDeviceLocked(Device& device) { mDevices.erase(device.id); } -status_t EventHub::readNotifyLocked() { - int res; - char event_buf[512]; - int event_size; - int event_pos = 0; - struct inotify_event* event; +base::Result<void> EventHub::readNotifyLocked() { + static constexpr auto EVENT_SIZE = static_cast<ssize_t>(sizeof(inotify_event)); + uint8_t eventBuffer[512]; + ssize_t sizeRead; ALOGV("EventHub::readNotify nfd: %d\n", mINotifyFd); - res = read(mINotifyFd, event_buf, sizeof(event_buf)); - if (res < (int)sizeof(*event)) { - if (errno == EINTR) return 0; - ALOGW("could not get event, %s\n", strerror(errno)); - return -1; - } - - while (res >= (int)sizeof(*event)) { - event = (struct inotify_event*)(event_buf + event_pos); - if (event->len) { - if (event->wd == mDeviceInputWd) { - std::string filename = std::string(DEVICE_INPUT_PATH) + "/" + event->name; - if (event->mask & IN_CREATE) { - openDeviceLocked(filename); - } else { - ALOGI("Removing device '%s' due to inotify event\n", filename.c_str()); - closeDeviceByPathLocked(filename); - } - } else if (event->wd == mDeviceWd) { - if (isV4lTouchNode(event->name)) { - std::string filename = std::string(DEVICE_PATH) + "/" + event->name; - if (event->mask & IN_CREATE) { - openVideoDeviceLocked(filename); - } else { - ALOGI("Removing video device '%s' due to inotify event", filename.c_str()); - closeVideoDeviceByPathLocked(filename); - } - } else if (strcmp(event->name, "input") == 0 && event->mask & IN_CREATE) { - addDeviceInputInotify(); - } + do { + sizeRead = read(mINotifyFd, eventBuffer, sizeof(eventBuffer)); + } while (sizeRead < 0 && errno == EINTR); + + if (sizeRead < EVENT_SIZE) return Errorf("could not get event, %s", strerror(errno)); + + for (ssize_t eventPos = 0; sizeRead >= EVENT_SIZE;) { + const inotify_event* event; + event = (const inotify_event*)(eventBuffer + eventPos); + if (event->len == 0) continue; + + handleNotifyEventLocked(*event); + + const ssize_t eventSize = EVENT_SIZE + event->len; + sizeRead -= eventSize; + eventPos += eventSize; + } + return {}; +} + +void EventHub::handleNotifyEventLocked(const inotify_event& event) { + if (event.wd == mDeviceInputWd) { + std::string filename = std::string(DEVICE_INPUT_PATH) + "/" + event.name; + if (event.mask & IN_CREATE) { + openDeviceLocked(filename); + } else { + ALOGI("Removing device '%s' due to inotify event\n", filename.c_str()); + closeDeviceByPathLocked(filename); + } + } else if (event.wd == mDeviceWd) { + if (isV4lTouchNode(event.name)) { + std::string filename = std::string(DEVICE_PATH) + "/" + event.name; + if (event.mask & IN_CREATE) { + openVideoDeviceLocked(filename); } else { - LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event->wd); + ALOGI("Removing video device '%s' due to inotify event", filename.c_str()); + closeVideoDeviceByPathLocked(filename); } + } else if (strcmp(event.name, "input") == 0 && event.mask & IN_CREATE) { + addDeviceInputInotify(); } - event_size = sizeof(*event) + event->len; - res -= event_size; - event_pos += event_size; + } else { + LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event.wd); } - return 0; } status_t EventHub::scanDirLocked(const std::string& dirname) { diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp index ba5083bec3..b67777fc0a 100644 --- a/services/inputflinger/reader/InputDevice.cpp +++ b/services/inputflinger/reader/InputDevice.cpp @@ -465,12 +465,12 @@ int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc ge return result; } -bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { +bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes, + uint8_t* outFlags) { bool result = false; - for_each_mapper([&result, sourceMask, numCodes, keyCodes, outFlags](InputMapper& mapper) { + for_each_mapper([&result, sourceMask, keyCodes, outFlags](InputMapper& mapper) { if (sourcesMatchMask(mapper.getSources(), sourceMask)) { - result |= mapper.markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); + result |= mapper.markSupportedKeyCodes(sourceMask, keyCodes, outFlags); } }); return result; diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp index 9c5a129213..79901f03e4 100644 --- a/services/inputflinger/reader/InputReader.cpp +++ b/services/inputflinger/reader/InputReader.cpp @@ -561,28 +561,28 @@ void InputReader::toggleCapsLockState(int32_t deviceId) { device->updateMetaState(AKEYCODE_CAPS_LOCK); } -bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { +bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, + const std::vector<int32_t>& keyCodes, uint8_t* outFlags) { std::scoped_lock _l(mLock); - memset(outFlags, 0, numCodes); - return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags); + memset(outFlags, 0, keyCodes.size()); + return markSupportedKeyCodesLocked(deviceId, sourceMask, keyCodes, outFlags); } bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, + const std::vector<int32_t>& keyCodes, uint8_t* outFlags) { bool result = false; if (deviceId >= 0) { InputDevice* device = findInputDeviceLocked(deviceId); if (device && !device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); + result = device->markSupportedKeyCodes(sourceMask, keyCodes, outFlags); } } else { for (auto& devicePair : mDevices) { std::shared_ptr<InputDevice>& device = devicePair.second; if (!device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result |= device->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); + result |= device->markSupportedKeyCodes(sourceMask, keyCodes, outFlags); } } } diff --git a/services/inputflinger/reader/Macros.h b/services/inputflinger/reader/Macros.h index d8376894f6..1bbf38676a 100644 --- a/services/inputflinger/reader/Macros.h +++ b/services/inputflinger/reader/Macros.h @@ -20,27 +20,65 @@ #define LOG_TAG "InputReader" //#define LOG_NDEBUG 0 +#include <log/log.h> +#include <log/log_event_list.h> -// Log debug messages for each raw event received from the EventHub. -static constexpr bool DEBUG_RAW_EVENTS = false; +namespace android { +/** + * Log debug messages for each raw event received from the EventHub. + * Enable this via "adb shell setprop log.tag.InputReaderRawEvents DEBUG" (requires restart) + */ +const bool DEBUG_RAW_EVENTS = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "RawEvents", ANDROID_LOG_INFO); -// Log debug messages about virtual key processing. -static constexpr bool DEBUG_VIRTUAL_KEYS = false; +/** + * Log debug messages about virtual key processing. + * Enable this via "adb shell setprop log.tag.InputReaderVirtualKeys DEBUG" (requires restart) + */ +const bool DEBUG_VIRTUAL_KEYS = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "VirtualKeys", ANDROID_LOG_INFO); -// Log debug messages about pointers. -static constexpr bool DEBUG_POINTERS = false; +/** + * Log debug messages about pointers. + * Enable this via "adb shell setprop log.tag.InputReaderPointers DEBUG" (requires restart) + */ +const bool DEBUG_POINTERS = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Pointers", ANDROID_LOG_INFO); -// Log debug messages about pointer assignment calculations. -static constexpr bool DEBUG_POINTER_ASSIGNMENT = false; +/** + * Log debug messages about pointer assignment calculations. + * Enable this via "adb shell setprop log.tag.InputReaderPointerAssignment DEBUG" (requires restart) + */ +const bool DEBUG_POINTER_ASSIGNMENT = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "PointerAssignment", ANDROID_LOG_INFO); +/** + * Log debug messages about gesture detection. + * Enable this via "adb shell setprop log.tag.InputReaderGestures DEBUG" (requires restart) + */ +const bool DEBUG_GESTURES = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Gestures", ANDROID_LOG_INFO); -// Log debug messages about gesture detection. -static constexpr bool DEBUG_GESTURES = false; +/** + * Log debug messages about the vibrator. + * Enable this via "adb shell setprop log.tag.InputReaderVibrator DEBUG" (requires restart) + */ +const bool DEBUG_VIBRATOR = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "Vibrator", ANDROID_LOG_INFO); -// Log debug messages about the vibrator. -static constexpr bool DEBUG_VIBRATOR = false; +/** + * Log debug messages about fusing stylus data. + * Enable this via "adb shell setprop log.tag.InputReaderStylusFusion DEBUG" (requires restart) + */ +const bool DEBUG_STYLUS_FUSION = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "StylusFusion", ANDROID_LOG_INFO); -// Log debug messages about fusing stylus data. -static constexpr bool DEBUG_STYLUS_FUSION = false; +/** + * Log detailed debug messages about input device lights. + * Enable this via "adb shell setprop log.tag.InputReaderLightDetails DEBUG" (requires restart) + */ +const bool DEBUG_LIGHT_DETAILS = + __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG "LightDetails", ANDROID_LOG_INFO); +} // namespace android #define INDENT " " #define INDENT2 " " diff --git a/services/inputflinger/reader/controller/PeripheralController.cpp b/services/inputflinger/reader/controller/PeripheralController.cpp index a6934960c9..76731749f1 100644 --- a/services/inputflinger/reader/controller/PeripheralController.cpp +++ b/services/inputflinger/reader/controller/PeripheralController.cpp @@ -22,9 +22,6 @@ #include "../Macros.h" #include "PeripheralController.h" -// Log detailed debug messages about input device lights. -static constexpr bool DEBUG_LIGHT_DETAILS = false; - namespace android { static inline int32_t getAlpha(int32_t color) { diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h index 130c55639b..79188aa2c0 100644 --- a/services/inputflinger/reader/include/EventHub.h +++ b/services/inputflinger/reader/include/EventHub.h @@ -36,7 +36,6 @@ #include <sys/epoll.h> #include <utils/BitSet.h> #include <utils/Errors.h> -#include <utils/KeyedVector.h> #include <utils/List.h> #include <utils/Log.h> #include <utils/Mutex.h> @@ -44,6 +43,8 @@ #include "TouchVideoDevice.h" #include "VibrationElement.h" +struct inotify_event; + namespace android { /* Number of colors : {red, green, blue} */ @@ -311,7 +312,7 @@ public: /* * Examine key input devices for specific framework keycode support */ - virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, + virtual bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes, uint8_t* outFlags) const = 0; virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0; @@ -488,7 +489,7 @@ public: status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const override final; - bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, + bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes, uint8_t* outFlags) const override final; size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) override final; @@ -648,7 +649,8 @@ private: status_t scanDirLocked(const std::string& dirname) REQUIRES(mLock); status_t scanVideoDirLocked(const std::string& dirname) REQUIRES(mLock); void scanDevicesLocked() REQUIRES(mLock); - status_t readNotifyLocked() REQUIRES(mLock); + base::Result<void> readNotifyLocked() REQUIRES(mLock); + void handleNotifyEventLocked(const inotify_event&) REQUIRES(mLock); Device* getDeviceByDescriptorLocked(const std::string& descriptor) const REQUIRES(mLock); Device* getDeviceLocked(int32_t deviceId) const REQUIRES(mLock); diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h index 728020eadc..51872ac095 100644 --- a/services/inputflinger/reader/include/InputDevice.h +++ b/services/inputflinger/reader/include/InputDevice.h @@ -88,7 +88,7 @@ public: int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); int32_t getKeyCodeForKeyLocation(int32_t locationKeyCode) const; - bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, + bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes, uint8_t* outFlags); void vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token); void cancelVibrate(int32_t token); @@ -324,9 +324,9 @@ public: inline status_t getAbsoluteAxisValue(int32_t code, int32_t* outValue) const { return mEventHub->getAbsoluteAxisValue(mId, code, outValue); } - inline bool markSupportedKeyCodes(size_t numCodes, const int32_t* keyCodes, + inline bool markSupportedKeyCodes(const std::vector<int32_t>& keyCodes, uint8_t* outFlags) const { - return mEventHub->markSupportedKeyCodes(mId, numCodes, keyCodes, outFlags); + return mEventHub->markSupportedKeyCodes(mId, keyCodes, outFlags); } inline bool hasScanCode(int32_t scanCode) const { return mEventHub->hasScanCode(mId, scanCode); diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h index daeaa1dbe3..ae41e01f7e 100644 --- a/services/inputflinger/reader/include/InputReader.h +++ b/services/inputflinger/reader/include/InputReader.h @@ -73,7 +73,7 @@ public: void toggleCapsLockState(int32_t deviceId) override; - bool hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, + bool hasKeys(int32_t deviceId, uint32_t sourceMask, const std::vector<int32_t>& keyCodes, uint8_t* outFlags) override; void requestRefreshConfiguration(uint32_t changes) override; @@ -237,8 +237,9 @@ private: typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code); int32_t getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) REQUIRES(mLock); - bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) REQUIRES(mLock); + bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, + const std::vector<int32_t>& keyCodes, uint8_t* outFlags) + REQUIRES(mLock); // find an InputDevice from an InputDevice id InputDevice* findInputDeviceLocked(int32_t deviceId) const REQUIRES(mLock); diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp index 91dc61923b..baa6007d2c 100644 --- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp @@ -225,18 +225,17 @@ void CursorInputMapper::configure(nsecs_t when, const InputReaderConfiguration* void CursorInputMapper::configureParameters() { mParameters.mode = Parameters::Mode::POINTER; - String8 cursorModeString; - if (getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.mode"), - cursorModeString)) { + std::string cursorModeString; + if (getDeviceContext().getConfiguration().tryGetProperty("cursor.mode", cursorModeString)) { if (cursorModeString == "navigation") { mParameters.mode = Parameters::Mode::NAVIGATION; } else if (cursorModeString != "pointer" && cursorModeString != "default") { - ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string()); + ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.c_str()); } } mParameters.orientationAware = false; - getDeviceContext().getConfiguration().tryGetProperty(String8("cursor.orientationAware"), + getDeviceContext().getConfiguration().tryGetProperty("cursor.orientationAware", mParameters.orientationAware); mParameters.hasAssociatedDisplay = false; diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp index 7b185e029c..75cebf3ddb 100644 --- a/services/inputflinger/reader/mapper/InputMapper.cpp +++ b/services/inputflinger/reader/mapper/InputMapper.cpp @@ -55,8 +55,8 @@ int32_t InputMapper::getKeyCodeForKeyLocation(int32_t locationKeyCode) const { return AKEYCODE_UNKNOWN; } -bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { +bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes, + uint8_t* outFlags) { return false; } diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h index fce6409b3f..7858728b6e 100644 --- a/services/inputflinger/reader/mapper/InputMapper.h +++ b/services/inputflinger/reader/mapper/InputMapper.h @@ -64,8 +64,8 @@ public: virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); virtual int32_t getKeyCodeForKeyLocation(int32_t locationKeyCode) const; - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); + virtual bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes, + uint8_t* outFlags); virtual void vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token); virtual void cancelVibrate(int32_t token); virtual bool isVibrating(); diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp index 2ac81781fa..6a406d21de 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp @@ -160,7 +160,7 @@ void KeyboardInputMapper::configure(nsecs_t when, const InputReaderConfiguration static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const* property) { int32_t mapped = 0; - if (config.tryGetProperty(String8(property), mapped) && mapped > 0) { + if (config.tryGetProperty(property, mapped) && mapped > 0) { for (size_t i = 0; i < stemKeyRotationMapSize; i++) { if (stemKeyRotationMap[i][0] == keyCode) { stemKeyRotationMap[i][1] = mapped; @@ -173,7 +173,7 @@ static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const* p void KeyboardInputMapper::configureParameters() { mParameters.orientationAware = false; const PropertyMap& config = getDeviceContext().getConfiguration(); - config.tryGetProperty(String8("keyboard.orientationAware"), mParameters.orientationAware); + config.tryGetProperty("keyboard.orientationAware", mParameters.orientationAware); if (mParameters.orientationAware) { mapStemKey(AKEYCODE_STEM_PRIMARY, config, "keyboard.rotated.stem_primary"); @@ -183,10 +183,10 @@ void KeyboardInputMapper::configureParameters() { } mParameters.handlesKeyRepeat = false; - config.tryGetProperty(String8("keyboard.handlesKeyRepeat"), mParameters.handlesKeyRepeat); + config.tryGetProperty("keyboard.handlesKeyRepeat", mParameters.handlesKeyRepeat); mParameters.doNotWakeByDefault = false; - config.tryGetProperty(String8("keyboard.doNotWakeByDefault"), mParameters.doNotWakeByDefault); + config.tryGetProperty("keyboard.doNotWakeByDefault", mParameters.doNotWakeByDefault); } void KeyboardInputMapper::dumpParameters(std::string& dump) { @@ -379,9 +379,10 @@ int32_t KeyboardInputMapper::getKeyCodeForKeyLocation(int32_t locationKeyCode) c return getDeviceContext().getKeyCodeForKeyLocation(locationKeyCode); } -bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - return getDeviceContext().markSupportedKeyCodes(numCodes, keyCodes, outFlags); +bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, + const std::vector<int32_t>& keyCodes, + uint8_t* outFlags) { + return getDeviceContext().markSupportedKeyCodes(keyCodes, outFlags); } int32_t KeyboardInputMapper::getMetaState() { @@ -433,13 +434,12 @@ void KeyboardInputMapper::updateLedState(bool reset) { mMetaState |= getContext()->getLedMetaState(); constexpr int32_t META_NUM = 3; - const std::array<int32_t, META_NUM> keyCodes = {AKEYCODE_CAPS_LOCK, AKEYCODE_NUM_LOCK, - AKEYCODE_SCROLL_LOCK}; + const std::vector<int32_t> keyCodes{AKEYCODE_CAPS_LOCK, AKEYCODE_NUM_LOCK, + AKEYCODE_SCROLL_LOCK}; const std::array<int32_t, META_NUM> metaCodes = {AMETA_CAPS_LOCK_ON, AMETA_NUM_LOCK_ON, AMETA_SCROLL_LOCK_ON}; std::array<uint8_t, META_NUM> flags = {0, 0, 0}; - bool hasKeyLayout = - getDeviceContext().markSupportedKeyCodes(META_NUM, keyCodes.data(), flags.data()); + bool hasKeyLayout = getDeviceContext().markSupportedKeyCodes(keyCodes, flags.data()); // If the device doesn't have the physical meta key it shouldn't generate the corresponding // meta state. if (hasKeyLayout) { diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h index 378769639e..0a55def33f 100644 --- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h +++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h @@ -36,8 +36,8 @@ public: virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override; virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override; - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) override; + virtual bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes, + uint8_t* outFlags) override; virtual int32_t getKeyCodeForKeyLocation(int32_t locationKeyCode) const override; virtual int32_t getMetaState() override; diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp index 41a8426e42..8f5dc9bfd5 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp @@ -31,23 +31,15 @@ static constexpr size_t MAX_SLOTS = 32; MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() : mCurrentSlot(-1), - mSlots(nullptr), - mSlotCount(0), mUsingSlotsProtocol(false), mHaveStylus(false) {} -MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() { - delete[] mSlots; -} - void MultiTouchMotionAccumulator::configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol) { - mSlotCount = slotCount; mUsingSlotsProtocol = usingSlotsProtocol; mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE); - delete[] mSlots; - mSlots = new Slot[slotCount]; + mSlots = std::vector<Slot>(slotCount); } void MultiTouchMotionAccumulator::reset(InputDeviceContext& deviceContext) { @@ -76,10 +68,8 @@ void MultiTouchMotionAccumulator::reset(InputDeviceContext& deviceContext) { } void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) { - if (mSlots) { - for (size_t i = 0; i < mSlotCount; i++) { - mSlots[i].clear(); - } + for (Slot& slot : mSlots) { + slot.clear(); } mCurrentSlot = initialSlot; } @@ -96,68 +86,68 @@ void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { mCurrentSlot = 0; } - if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) { + if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlots.size()) { if (DEBUG_POINTERS) { if (newSlot) { ALOGW("MultiTouch device emitted invalid slot index %d but it " "should be between 0 and %zd; ignoring this slot.", - mCurrentSlot, mSlotCount - 1); + mCurrentSlot, mSlots.size() - 1); } } } else { - Slot* slot = &mSlots[mCurrentSlot]; + Slot& slot = mSlots[mCurrentSlot]; // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while // updating the slot. if (!mUsingSlotsProtocol) { - slot->mInUse = true; + slot.mInUse = true; } switch (rawEvent->code) { case ABS_MT_POSITION_X: - slot->mAbsMTPositionX = rawEvent->value; - warnIfNotInUse(*rawEvent, *slot); + slot.mAbsMTPositionX = rawEvent->value; + warnIfNotInUse(*rawEvent, slot); break; case ABS_MT_POSITION_Y: - slot->mAbsMTPositionY = rawEvent->value; - warnIfNotInUse(*rawEvent, *slot); + slot.mAbsMTPositionY = rawEvent->value; + warnIfNotInUse(*rawEvent, slot); break; case ABS_MT_TOUCH_MAJOR: - slot->mAbsMTTouchMajor = rawEvent->value; + slot.mAbsMTTouchMajor = rawEvent->value; break; case ABS_MT_TOUCH_MINOR: - slot->mAbsMTTouchMinor = rawEvent->value; - slot->mHaveAbsMTTouchMinor = true; + slot.mAbsMTTouchMinor = rawEvent->value; + slot.mHaveAbsMTTouchMinor = true; break; case ABS_MT_WIDTH_MAJOR: - slot->mAbsMTWidthMajor = rawEvent->value; + slot.mAbsMTWidthMajor = rawEvent->value; break; case ABS_MT_WIDTH_MINOR: - slot->mAbsMTWidthMinor = rawEvent->value; - slot->mHaveAbsMTWidthMinor = true; + slot.mAbsMTWidthMinor = rawEvent->value; + slot.mHaveAbsMTWidthMinor = true; break; case ABS_MT_ORIENTATION: - slot->mAbsMTOrientation = rawEvent->value; + slot.mAbsMTOrientation = rawEvent->value; break; case ABS_MT_TRACKING_ID: if (mUsingSlotsProtocol && rawEvent->value < 0) { // The slot is no longer in use but it retains its previous contents, // which may be reused for subsequent touches. - slot->mInUse = false; + slot.mInUse = false; } else { - slot->mInUse = true; - slot->mAbsMTTrackingId = rawEvent->value; + slot.mInUse = true; + slot.mAbsMTTrackingId = rawEvent->value; } break; case ABS_MT_PRESSURE: - slot->mAbsMTPressure = rawEvent->value; + slot.mAbsMTPressure = rawEvent->value; break; case ABS_MT_DISTANCE: - slot->mAbsMTDistance = rawEvent->value; + slot.mAbsMTDistance = rawEvent->value; break; case ABS_MT_TOOL_TYPE: - slot->mAbsMTToolType = rawEvent->value; - slot->mHaveAbsMTToolType = true; + slot.mAbsMTToolType = rawEvent->value; + slot.mHaveAbsMTToolType = true; break; } } @@ -186,28 +176,6 @@ void MultiTouchMotionAccumulator::warnIfNotInUse(const RawEvent& event, const Sl // --- MultiTouchMotionAccumulator::Slot --- -MultiTouchMotionAccumulator::Slot::Slot() { - clear(); -} - -void MultiTouchMotionAccumulator::Slot::clear() { - mInUse = false; - mHaveAbsMTTouchMinor = false; - mHaveAbsMTWidthMinor = false; - mHaveAbsMTToolType = false; - mAbsMTPositionX = 0; - mAbsMTPositionY = 0; - mAbsMTTouchMajor = 0; - mAbsMTTouchMinor = 0; - mAbsMTWidthMajor = 0; - mAbsMTWidthMinor = 0; - mAbsMTOrientation = 0; - mAbsMTTrackingId = -1; - mAbsMTPressure = 0; - mAbsMTDistance = 0; - mAbsMTToolType = 0; -} - int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { if (mHaveAbsMTToolType) { switch (mAbsMTToolType) { @@ -264,14 +232,14 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { mHavePointerIds = true; for (size_t inIndex = 0; inIndex < inCount; inIndex++) { - const MultiTouchMotionAccumulator::Slot* inSlot = + const MultiTouchMotionAccumulator::Slot& inSlot = mMultiTouchMotionAccumulator.getSlot(inIndex); - if (!inSlot->isInUse()) { + if (!inSlot.isInUse()) { continue; } - if (inSlot->getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) { - std::optional<int32_t> id = getActiveBitId(*inSlot); + if (inSlot.getToolType() == AMOTION_EVENT_TOOL_TYPE_PALM) { + std::optional<int32_t> id = getActiveBitId(inSlot); if (id) { outState->rawPointerData.canceledIdBits.markBit(id.value()); } @@ -292,19 +260,19 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { } RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount]; - outPointer.x = inSlot->getX(); - outPointer.y = inSlot->getY(); - outPointer.pressure = inSlot->getPressure(); - outPointer.touchMajor = inSlot->getTouchMajor(); - outPointer.touchMinor = inSlot->getTouchMinor(); - outPointer.toolMajor = inSlot->getToolMajor(); - outPointer.toolMinor = inSlot->getToolMinor(); - outPointer.orientation = inSlot->getOrientation(); - outPointer.distance = inSlot->getDistance(); + outPointer.x = inSlot.getX(); + outPointer.y = inSlot.getY(); + outPointer.pressure = inSlot.getPressure(); + outPointer.touchMajor = inSlot.getTouchMajor(); + outPointer.touchMinor = inSlot.getTouchMinor(); + outPointer.toolMajor = inSlot.getToolMajor(); + outPointer.toolMinor = inSlot.getToolMinor(); + outPointer.orientation = inSlot.getOrientation(); + outPointer.distance = inSlot.getDistance(); outPointer.tiltX = 0; outPointer.tiltY = 0; - outPointer.toolType = inSlot->getToolType(); + outPointer.toolType = inSlot.getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { outPointer.toolType = mTouchButtonAccumulator.getToolType(); if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { @@ -318,12 +286,12 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && (mTouchButtonAccumulator.isHovering() || - (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0)); + (mRawPointerAxes.pressure.valid && inSlot.getPressure() <= 0)); outPointer.isHovering = isHovering; // Assign pointer id using tracking id if available. if (mHavePointerIds) { - int32_t trackingId = inSlot->getTrackingId(); + int32_t trackingId = inSlot.getTrackingId(); int32_t id = -1; if (trackingId >= 0) { for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) { diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h index b7c3457285..fe8af5d818 100644 --- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h +++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h @@ -46,29 +46,27 @@ public: private: friend class MultiTouchMotionAccumulator; - bool mInUse; - bool mHaveAbsMTTouchMinor; - bool mHaveAbsMTWidthMinor; - bool mHaveAbsMTToolType; - - int32_t mAbsMTPositionX; - int32_t mAbsMTPositionY; - int32_t mAbsMTTouchMajor; - int32_t mAbsMTTouchMinor; - int32_t mAbsMTWidthMajor; - int32_t mAbsMTWidthMinor; - int32_t mAbsMTOrientation; - int32_t mAbsMTTrackingId; - int32_t mAbsMTPressure; - int32_t mAbsMTDistance; - int32_t mAbsMTToolType; - - Slot(); - void clear(); + bool mInUse = false; + bool mHaveAbsMTTouchMinor = false; + bool mHaveAbsMTWidthMinor = false; + bool mHaveAbsMTToolType = false; + + int32_t mAbsMTPositionX = 0; + int32_t mAbsMTPositionY = 0; + int32_t mAbsMTTouchMajor = 0; + int32_t mAbsMTTouchMinor = 0; + int32_t mAbsMTWidthMajor = 0; + int32_t mAbsMTWidthMinor = 0; + int32_t mAbsMTOrientation = 0; + int32_t mAbsMTTrackingId = -1; + int32_t mAbsMTPressure = 0; + int32_t mAbsMTDistance = 0; + int32_t mAbsMTToolType = 0; + + void clear() { *this = Slot(); } }; MultiTouchMotionAccumulator(); - ~MultiTouchMotionAccumulator(); void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol); void reset(InputDeviceContext& deviceContext); @@ -76,13 +74,15 @@ public: void finishSync(); bool hasStylus() const; - inline size_t getSlotCount() const { return mSlotCount; } - inline const Slot* getSlot(size_t index) const { return &mSlots[index]; } + inline size_t getSlotCount() const { return mSlots.size(); } + inline const Slot& getSlot(size_t index) const { + LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index); + return mSlots[index]; + } private: int32_t mCurrentSlot; - Slot* mSlots; - size_t mSlotCount; + std::vector<Slot> mSlots; bool mUsingSlotsProtocol; bool mHaveStylus; diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp index eca25f6e6a..05973f783c 100644 --- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp +++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp @@ -40,10 +40,10 @@ void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo* info) { if (mRotaryEncoderScrollAccumulator.haveRelativeVWheel()) { float res = 0.0f; - if (!getDeviceContext().getConfiguration().tryGetProperty(String8("device.res"), res)) { + if (!getDeviceContext().getConfiguration().tryGetProperty("device.res", res)) { ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n"); } - if (!getDeviceContext().getConfiguration().tryGetProperty(String8("device.scalingFactor"), + if (!getDeviceContext().getConfiguration().tryGetProperty("device.scalingFactor", mScalingFactor)) { ALOGW("Rotary Encoder device configuration file didn't specify scaling factor," "default to 1.0!\n"); diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp index b01c2bc13f..573f99cf87 100644 --- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp +++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp @@ -64,7 +64,7 @@ uint32_t SensorInputMapper::getSources() const { template <typename T> bool SensorInputMapper::tryGetProperty(std::string keyName, T& outValue) { const auto& config = getDeviceContext().getConfiguration(); - return config.tryGetProperty(String8(keyName.c_str()), outValue); + return config.tryGetProperty(keyName, outValue); } void SensorInputMapper::parseSensorConfiguration(InputDeviceSensorType sensorType, int32_t absCode, diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index 2acbb0a034..c1111f2e48 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -42,6 +42,8 @@ static constexpr nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20); // data. static constexpr nsecs_t STYLUS_DATA_LATENCY = ms2ns(10); +// Minimum width between two pointers to determine a gesture as freeform gesture in mm +static const float MIN_FREEFORM_GESTURE_WIDTH_IN_MILLIMETER = 30; // --- Static Definitions --- template <typename T> @@ -204,30 +206,30 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { y.fuzz, y.resolution); } - if (mOrientedRanges.haveSize) { - info->addMotionRange(mOrientedRanges.size); + if (mOrientedRanges.size) { + info->addMotionRange(*mOrientedRanges.size); } - if (mOrientedRanges.haveTouchSize) { - info->addMotionRange(mOrientedRanges.touchMajor); - info->addMotionRange(mOrientedRanges.touchMinor); + if (mOrientedRanges.touchMajor) { + info->addMotionRange(*mOrientedRanges.touchMajor); + info->addMotionRange(*mOrientedRanges.touchMinor); } - if (mOrientedRanges.haveToolSize) { - info->addMotionRange(mOrientedRanges.toolMajor); - info->addMotionRange(mOrientedRanges.toolMinor); + if (mOrientedRanges.toolMajor) { + info->addMotionRange(*mOrientedRanges.toolMajor); + info->addMotionRange(*mOrientedRanges.toolMinor); } - if (mOrientedRanges.haveOrientation) { - info->addMotionRange(mOrientedRanges.orientation); + if (mOrientedRanges.orientation) { + info->addMotionRange(*mOrientedRanges.orientation); } - if (mOrientedRanges.haveDistance) { - info->addMotionRange(mOrientedRanges.distance); + if (mOrientedRanges.distance) { + info->addMotionRange(*mOrientedRanges.distance); } - if (mOrientedRanges.haveTilt) { - info->addMotionRange(mOrientedRanges.tilt); + if (mOrientedRanges.tilt) { + info->addMotionRange(*mOrientedRanges.tilt); } if (mCursorScrollAccumulator.haveRelativeVWheel()) { @@ -415,15 +417,15 @@ void TouchInputMapper::configureParameters() { ? Parameters::GestureMode::SINGLE_TOUCH : Parameters::GestureMode::MULTI_TOUCH; - String8 gestureModeString; - if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.gestureMode"), + std::string gestureModeString; + if (getDeviceContext().getConfiguration().tryGetProperty("touch.gestureMode", gestureModeString)) { if (gestureModeString == "single-touch") { mParameters.gestureMode = Parameters::GestureMode::SINGLE_TOUCH; } else if (gestureModeString == "multi-touch") { mParameters.gestureMode = Parameters::GestureMode::MULTI_TOUCH; } else if (gestureModeString != "default") { - ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string()); + ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.c_str()); } } @@ -445,8 +447,8 @@ void TouchInputMapper::configureParameters() { mParameters.hasButtonUnderPad = getDeviceContext().hasInputProperty(INPUT_PROP_BUTTONPAD); - String8 deviceTypeString; - if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.deviceType"), + std::string deviceTypeString; + if (getDeviceContext().getConfiguration().tryGetProperty("touch.deviceType", deviceTypeString)) { if (deviceTypeString == "touchScreen") { mParameters.deviceType = Parameters::DeviceType::TOUCH_SCREEN; @@ -457,17 +459,17 @@ void TouchInputMapper::configureParameters() { } else if (deviceTypeString == "pointer") { mParameters.deviceType = Parameters::DeviceType::POINTER; } else if (deviceTypeString != "default") { - ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); + ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.c_str()); } } mParameters.orientationAware = mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN; - getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientationAware"), + getDeviceContext().getConfiguration().tryGetProperty("touch.orientationAware", mParameters.orientationAware); mParameters.orientation = Parameters::Orientation::ORIENTATION_0; - String8 orientationString; - if (getDeviceContext().getConfiguration().tryGetProperty(String8("touch.orientation"), + std::string orientationString; + if (getDeviceContext().getConfiguration().tryGetProperty("touch.orientation", orientationString)) { if (mParameters.deviceType != Parameters::DeviceType::TOUCH_SCREEN) { ALOGW("The configuration 'touch.orientation' is only supported for touchscreens."); @@ -478,7 +480,7 @@ void TouchInputMapper::configureParameters() { } else if (orientationString == "ORIENTATION_270") { mParameters.orientation = Parameters::Orientation::ORIENTATION_270; } else if (orientationString != "ORIENTATION_0") { - ALOGW("Invalid value for touch.orientation: '%s'", orientationString.string()); + ALOGW("Invalid value for touch.orientation: '%s'", orientationString.c_str()); } } @@ -490,8 +492,8 @@ void TouchInputMapper::configureParameters() { mParameters.hasAssociatedDisplay = true; if (mParameters.deviceType == Parameters::DeviceType::TOUCH_SCREEN) { mParameters.associatedDisplayIsExternal = getDeviceContext().isExternal(); - String8 uniqueDisplayId; - getDeviceContext().getConfiguration().tryGetProperty(String8("touch.displayId"), + std::string uniqueDisplayId; + getDeviceContext().getConfiguration().tryGetProperty("touch.displayId", uniqueDisplayId); mParameters.uniqueDisplayId = uniqueDisplayId.c_str(); } @@ -504,7 +506,7 @@ void TouchInputMapper::configureParameters() { // Normally we don't do this for internal touch screens to prevent them from waking // up in your pocket but you can enable it using the input device configuration. mParameters.wake = getDeviceContext().isExternal(); - getDeviceContext().getConfiguration().tryGetProperty(String8("touch.wake"), mParameters.wake); + getDeviceContext().getConfiguration().tryGetProperty("touch.wake", mParameters.wake); } void TouchInputMapper::dumpParameters(std::string& dump) { @@ -639,57 +641,58 @@ void TouchInputMapper::initializeSizeRanges() { mSizeScale = 0.0f; } - mOrientedRanges.haveTouchSize = true; - mOrientedRanges.haveToolSize = true; - mOrientedRanges.haveSize = true; + mOrientedRanges.touchMajor = InputDeviceInfo::MotionRange{ + .axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR, + .source = mSource, + .min = 0, + .max = diagonalSize, + .flat = 0, + .fuzz = 0, + .resolution = 0, + }; - mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR; - mOrientedRanges.touchMajor.source = mSource; - mOrientedRanges.touchMajor.min = 0; - mOrientedRanges.touchMajor.max = diagonalSize; - mOrientedRanges.touchMajor.flat = 0; - mOrientedRanges.touchMajor.fuzz = 0; - mOrientedRanges.touchMajor.resolution = 0; if (mRawPointerAxes.touchMajor.valid) { mRawPointerAxes.touchMajor.resolution = clampResolution("touchMajor", mRawPointerAxes.touchMajor.resolution); - mOrientedRanges.touchMajor.resolution = mRawPointerAxes.touchMajor.resolution; + mOrientedRanges.touchMajor->resolution = mRawPointerAxes.touchMajor.resolution; } mOrientedRanges.touchMinor = mOrientedRanges.touchMajor; - mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; + mOrientedRanges.touchMinor->axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; if (mRawPointerAxes.touchMinor.valid) { mRawPointerAxes.touchMinor.resolution = clampResolution("touchMinor", mRawPointerAxes.touchMinor.resolution); - mOrientedRanges.touchMinor.resolution = mRawPointerAxes.touchMinor.resolution; - } - - mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR; - mOrientedRanges.toolMajor.source = mSource; - mOrientedRanges.toolMajor.min = 0; - mOrientedRanges.toolMajor.max = diagonalSize; - mOrientedRanges.toolMajor.flat = 0; - mOrientedRanges.toolMajor.fuzz = 0; - mOrientedRanges.toolMajor.resolution = 0; + mOrientedRanges.touchMinor->resolution = mRawPointerAxes.touchMinor.resolution; + } + + mOrientedRanges.toolMajor = InputDeviceInfo::MotionRange{ + .axis = AMOTION_EVENT_AXIS_TOOL_MAJOR, + .source = mSource, + .min = 0, + .max = diagonalSize, + .flat = 0, + .fuzz = 0, + .resolution = 0, + }; if (mRawPointerAxes.toolMajor.valid) { mRawPointerAxes.toolMajor.resolution = clampResolution("toolMajor", mRawPointerAxes.toolMajor.resolution); - mOrientedRanges.toolMajor.resolution = mRawPointerAxes.toolMajor.resolution; + mOrientedRanges.toolMajor->resolution = mRawPointerAxes.toolMajor.resolution; } mOrientedRanges.toolMinor = mOrientedRanges.toolMajor; - mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR; + mOrientedRanges.toolMinor->axis = AMOTION_EVENT_AXIS_TOOL_MINOR; if (mRawPointerAxes.toolMinor.valid) { mRawPointerAxes.toolMinor.resolution = clampResolution("toolMinor", mRawPointerAxes.toolMinor.resolution); - mOrientedRanges.toolMinor.resolution = mRawPointerAxes.toolMinor.resolution; + mOrientedRanges.toolMinor->resolution = mRawPointerAxes.toolMinor.resolution; } if (mCalibration.sizeCalibration == Calibration::SizeCalibration::GEOMETRIC) { - mOrientedRanges.touchMajor.resolution *= mGeometricScale; - mOrientedRanges.touchMinor.resolution *= mGeometricScale; - mOrientedRanges.toolMajor.resolution *= mGeometricScale; - mOrientedRanges.toolMinor.resolution *= mGeometricScale; + mOrientedRanges.touchMajor->resolution *= mGeometricScale; + mOrientedRanges.touchMinor->resolution *= mGeometricScale; + mOrientedRanges.toolMajor->resolution *= mGeometricScale; + mOrientedRanges.toolMinor->resolution *= mGeometricScale; } else { // Support for other calibrations can be added here. ALOGW("%s calibration is not supported for size ranges at the moment. " @@ -697,13 +700,15 @@ void TouchInputMapper::initializeSizeRanges() { ftl::enum_string(mCalibration.sizeCalibration).c_str()); } - mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE; - mOrientedRanges.size.source = mSource; - mOrientedRanges.size.min = 0; - mOrientedRanges.size.max = 1.0; - mOrientedRanges.size.flat = 0; - mOrientedRanges.size.fuzz = 0; - mOrientedRanges.size.resolution = 0; + mOrientedRanges.size = InputDeviceInfo::MotionRange{ + .axis = AMOTION_EVENT_AXIS_SIZE, + .source = mSource, + .min = 0, + .max = 1.0, + .flat = 0, + .fuzz = 0, + .resolution = 0, + }; } void TouchInputMapper::initializeOrientedRanges() { @@ -730,21 +735,23 @@ void TouchInputMapper::initializeOrientedRanges() { float pressureMax = 1.0; if (mCalibration.pressureCalibration == Calibration::PressureCalibration::PHYSICAL || mCalibration.pressureCalibration == Calibration::PressureCalibration::AMPLITUDE) { - if (mCalibration.havePressureScale) { - mPressureScale = mCalibration.pressureScale; + if (mCalibration.pressureScale) { + mPressureScale = *mCalibration.pressureScale; pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue; } else if (mRawPointerAxes.pressure.valid && mRawPointerAxes.pressure.maxValue != 0) { mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; } } - mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; - mOrientedRanges.pressure.source = mSource; - mOrientedRanges.pressure.min = 0; - mOrientedRanges.pressure.max = pressureMax; - mOrientedRanges.pressure.flat = 0; - mOrientedRanges.pressure.fuzz = 0; - mOrientedRanges.pressure.resolution = 0; + mOrientedRanges.pressure = InputDeviceInfo::MotionRange{ + .axis = AMOTION_EVENT_AXIS_PRESSURE, + .source = mSource, + .min = 0, + .max = pressureMax, + .flat = 0, + .fuzz = 0, + .resolution = 0, + }; // Tilt mTiltXCenter = 0; @@ -765,29 +772,30 @@ void TouchInputMapper::initializeOrientedRanges() { mTiltYScale = 1.0 / mRawPointerAxes.tiltY.resolution; } - mOrientedRanges.haveTilt = true; - - mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT; - mOrientedRanges.tilt.source = mSource; - mOrientedRanges.tilt.min = 0; - mOrientedRanges.tilt.max = M_PI_2; - mOrientedRanges.tilt.flat = 0; - mOrientedRanges.tilt.fuzz = 0; - mOrientedRanges.tilt.resolution = 0; + mOrientedRanges.tilt = InputDeviceInfo::MotionRange{ + .axis = AMOTION_EVENT_AXIS_TILT, + .source = mSource, + .min = 0, + .max = M_PI_2, + .flat = 0, + .fuzz = 0, + .resolution = 0, + }; } // Orientation mOrientationScale = 0; if (mHaveTilt) { - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI; - mOrientedRanges.orientation.max = M_PI; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; + mOrientedRanges.orientation = InputDeviceInfo::MotionRange{ + .axis = AMOTION_EVENT_AXIS_ORIENTATION, + .source = mSource, + .min = -M_PI, + .max = M_PI, + .flat = 0, + .fuzz = 0, + .resolution = 0, + }; + } else if (mCalibration.orientationCalibration != Calibration::OrientationCalibration::NONE) { if (mCalibration.orientationCalibration == Calibration::OrientationCalibration::INTERPOLATED) { @@ -802,37 +810,34 @@ void TouchInputMapper::initializeOrientedRanges() { } } - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI_2; - mOrientedRanges.orientation.max = M_PI_2; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; + mOrientedRanges.orientation = InputDeviceInfo::MotionRange{ + .axis = AMOTION_EVENT_AXIS_ORIENTATION, + .source = mSource, + .min = -M_PI_2, + .max = M_PI_2, + .flat = 0, + .fuzz = 0, + .resolution = 0, + }; } // Distance mDistanceScale = 0; if (mCalibration.distanceCalibration != Calibration::DistanceCalibration::NONE) { if (mCalibration.distanceCalibration == Calibration::DistanceCalibration::SCALED) { - if (mCalibration.haveDistanceScale) { - mDistanceScale = mCalibration.distanceScale; - } else { - mDistanceScale = 1.0f; - } + mDistanceScale = mCalibration.distanceScale.value_or(1.0f); } - mOrientedRanges.haveDistance = true; + mOrientedRanges.distance = InputDeviceInfo::MotionRange{ - mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE; - mOrientedRanges.distance.source = mSource; - mOrientedRanges.distance.min = mRawPointerAxes.distance.minValue * mDistanceScale; - mOrientedRanges.distance.max = mRawPointerAxes.distance.maxValue * mDistanceScale; - mOrientedRanges.distance.flat = 0; - mOrientedRanges.distance.fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale; - mOrientedRanges.distance.resolution = 0; + .axis = AMOTION_EVENT_AXIS_DISTANCE, + .source = mSource, + .min = mRawPointerAxes.distance.minValue * mDistanceScale, + .max = mRawPointerAxes.distance.maxValue * mDistanceScale, + .flat = 0, + .fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale, + .resolution = 0, + }; } // Compute oriented precision, scales and ranges. @@ -936,6 +941,11 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) // Raw width and height in the natural orientation. const int32_t rawWidth = mRawPointerAxes.getRawWidth(); const int32_t rawHeight = mRawPointerAxes.getRawHeight(); + const int32_t rawXResolution = mRawPointerAxes.x.resolution; + const int32_t rawYResolution = mRawPointerAxes.y.resolution; + // Calculate the mean resolution when both x and y resolution are set, otherwise set it to 0. + const float rawMeanResolution = + (rawXResolution > 0 && rawYResolution > 0) ? (rawXResolution + rawYResolution) / 2 : 0; const bool viewportChanged = mViewport != *newViewport; bool skipViewportUpdate = false; @@ -1094,10 +1104,14 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) mConfig.pointerGestureZoomSpeedRatio * displayDiagonal / rawDiagonal; mPointerYZoomScale = mPointerXZoomScale; - // Max width between pointers to detect a swipe gesture is more than some fraction - // of the diagonal axis of the touch pad. Touches that are wider than this are - // translated into freeform gestures. - mPointerGestureMaxSwipeWidth = mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal; + // Calculate the min freeform gesture width. It will be 0 when the resolution of any + // axis is non positive value. + const float minFreeformGestureWidth = + rawMeanResolution * MIN_FREEFORM_GESTURE_WIDTH_IN_MILLIMETER; + + mPointerGestureMaxSwipeWidth = + std::max(mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal, + minFreeformGestureWidth); // Abort current pointer usages because the state has changed. const nsecs_t readTime = when; // synthetic event @@ -1192,8 +1206,8 @@ void TouchInputMapper::parseCalibration() { // Size out.sizeCalibration = Calibration::SizeCalibration::DEFAULT; - String8 sizeCalibrationString; - if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) { + std::string sizeCalibrationString; + if (in.tryGetProperty("touch.size.calibration", sizeCalibrationString)) { if (sizeCalibrationString == "none") { out.sizeCalibration = Calibration::SizeCalibration::NONE; } else if (sizeCalibrationString == "geometric") { @@ -1205,18 +1219,28 @@ void TouchInputMapper::parseCalibration() { } else if (sizeCalibrationString == "area") { out.sizeCalibration = Calibration::SizeCalibration::AREA; } else if (sizeCalibrationString != "default") { - ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.string()); + ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.c_str()); } } - out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"), out.sizeScale); - out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"), out.sizeBias); - out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), out.sizeIsSummed); + float sizeScale; + + if (in.tryGetProperty("touch.size.scale", sizeScale)) { + out.sizeScale = sizeScale; + } + float sizeBias; + if (in.tryGetProperty("touch.size.bias", sizeBias)) { + out.sizeBias = sizeBias; + } + bool sizeIsSummed; + if (in.tryGetProperty("touch.size.isSummed", sizeIsSummed)) { + out.sizeIsSummed = sizeIsSummed; + } // Pressure out.pressureCalibration = Calibration::PressureCalibration::DEFAULT; - String8 pressureCalibrationString; - if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) { + std::string pressureCalibrationString; + if (in.tryGetProperty("touch.pressure.calibration", pressureCalibrationString)) { if (pressureCalibrationString == "none") { out.pressureCalibration = Calibration::PressureCalibration::NONE; } else if (pressureCalibrationString == "physical") { @@ -1225,16 +1249,19 @@ void TouchInputMapper::parseCalibration() { out.pressureCalibration = Calibration::PressureCalibration::AMPLITUDE; } else if (pressureCalibrationString != "default") { ALOGW("Invalid value for touch.pressure.calibration: '%s'", - pressureCalibrationString.string()); + pressureCalibrationString.c_str()); } } - out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), out.pressureScale); + float pressureScale; + if (in.tryGetProperty("touch.pressure.scale", pressureScale)) { + out.pressureScale = pressureScale; + } // Orientation out.orientationCalibration = Calibration::OrientationCalibration::DEFAULT; - String8 orientationCalibrationString; - if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) { + std::string orientationCalibrationString; + if (in.tryGetProperty("touch.orientation.calibration", orientationCalibrationString)) { if (orientationCalibrationString == "none") { out.orientationCalibration = Calibration::OrientationCalibration::NONE; } else if (orientationCalibrationString == "interpolated") { @@ -1243,36 +1270,39 @@ void TouchInputMapper::parseCalibration() { out.orientationCalibration = Calibration::OrientationCalibration::VECTOR; } else if (orientationCalibrationString != "default") { ALOGW("Invalid value for touch.orientation.calibration: '%s'", - orientationCalibrationString.string()); + orientationCalibrationString.c_str()); } } // Distance out.distanceCalibration = Calibration::DistanceCalibration::DEFAULT; - String8 distanceCalibrationString; - if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) { + std::string distanceCalibrationString; + if (in.tryGetProperty("touch.distance.calibration", distanceCalibrationString)) { if (distanceCalibrationString == "none") { out.distanceCalibration = Calibration::DistanceCalibration::NONE; } else if (distanceCalibrationString == "scaled") { out.distanceCalibration = Calibration::DistanceCalibration::SCALED; } else if (distanceCalibrationString != "default") { ALOGW("Invalid value for touch.distance.calibration: '%s'", - distanceCalibrationString.string()); + distanceCalibrationString.c_str()); } } - out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), out.distanceScale); + float distanceScale; + if (in.tryGetProperty("touch.distance.scale", distanceScale)) { + out.distanceScale = distanceScale; + } out.coverageCalibration = Calibration::CoverageCalibration::DEFAULT; - String8 coverageCalibrationString; - if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) { + std::string coverageCalibrationString; + if (in.tryGetProperty("touch.coverage.calibration", coverageCalibrationString)) { if (coverageCalibrationString == "none") { out.coverageCalibration = Calibration::CoverageCalibration::NONE; } else if (coverageCalibrationString == "box") { out.coverageCalibration = Calibration::CoverageCalibration::BOX; } else if (coverageCalibrationString != "default") { ALOGW("Invalid value for touch.coverage.calibration: '%s'", - coverageCalibrationString.string()); + coverageCalibrationString.c_str()); } } } @@ -1326,17 +1356,17 @@ void TouchInputMapper::dumpCalibration(std::string& dump) { dump += INDENT4 "touch.size.calibration: "; dump += ftl::enum_string(mCalibration.sizeCalibration) + "\n"; - if (mCalibration.haveSizeScale) { - dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n", mCalibration.sizeScale); + if (mCalibration.sizeScale) { + dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n", *mCalibration.sizeScale); } - if (mCalibration.haveSizeBias) { - dump += StringPrintf(INDENT4 "touch.size.bias: %0.3f\n", mCalibration.sizeBias); + if (mCalibration.sizeBias) { + dump += StringPrintf(INDENT4 "touch.size.bias: %0.3f\n", *mCalibration.sizeBias); } - if (mCalibration.haveSizeIsSummed) { + if (mCalibration.sizeIsSummed) { dump += StringPrintf(INDENT4 "touch.size.isSummed: %s\n", - toString(mCalibration.sizeIsSummed)); + toString(*mCalibration.sizeIsSummed)); } // Pressure @@ -1354,8 +1384,8 @@ void TouchInputMapper::dumpCalibration(std::string& dump) { ALOG_ASSERT(false); } - if (mCalibration.havePressureScale) { - dump += StringPrintf(INDENT4 "touch.pressure.scale: %0.3f\n", mCalibration.pressureScale); + if (mCalibration.pressureScale) { + dump += StringPrintf(INDENT4 "touch.pressure.scale: %0.3f\n", *mCalibration.pressureScale); } // Orientation @@ -1385,8 +1415,8 @@ void TouchInputMapper::dumpCalibration(std::string& dump) { ALOG_ASSERT(false); } - if (mCalibration.haveDistanceScale) { - dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n", mCalibration.distanceScale); + if (mCalibration.distanceScale) { + dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n", *mCalibration.distanceScale); } switch (mCalibration.coverageCalibration) { @@ -2175,7 +2205,7 @@ void TouchInputMapper::cookPointerData() { size = 0; } - if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { + if (mCalibration.sizeIsSummed && *mCalibration.sizeIsSummed) { uint32_t touchingCount = mCurrentRawState.rawPointerData.touchingIdBits.count(); if (touchingCount > 1) { touchMajor /= touchingCount; @@ -2201,13 +2231,16 @@ void TouchInputMapper::cookPointerData() { toolMinor = toolMajor; } - mCalibration.applySizeScaleAndBias(&touchMajor); - mCalibration.applySizeScaleAndBias(&touchMinor); - mCalibration.applySizeScaleAndBias(&toolMajor); - mCalibration.applySizeScaleAndBias(&toolMinor); + mCalibration.applySizeScaleAndBias(touchMajor); + mCalibration.applySizeScaleAndBias(touchMinor); + mCalibration.applySizeScaleAndBias(toolMajor); + mCalibration.applySizeScaleAndBias(toolMinor); size *= mSizeScale; break; - default: + case Calibration::SizeCalibration::DEFAULT: + LOG_ALWAYS_FATAL("Resolution should not be 'DEFAULT' at this point"); + break; + case Calibration::SizeCalibration::NONE: touchMajor = 0; touchMinor = 0; toolMajor = 0; @@ -2304,10 +2337,9 @@ void TouchInputMapper::cookPointerData() { bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale; top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale; orientation -= M_PI_2; - if (mOrientedRanges.haveOrientation && - orientation < mOrientedRanges.orientation.min) { + if (mOrientedRanges.orientation && orientation < mOrientedRanges.orientation->min) { orientation += - (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); + (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min); } break; case DISPLAY_ORIENTATION_180: @@ -2316,10 +2348,9 @@ void TouchInputMapper::cookPointerData() { bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale; top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale; orientation -= M_PI; - if (mOrientedRanges.haveOrientation && - orientation < mOrientedRanges.orientation.min) { + if (mOrientedRanges.orientation && orientation < mOrientedRanges.orientation->min) { orientation += - (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); + (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min); } break; case DISPLAY_ORIENTATION_270: @@ -2328,10 +2359,9 @@ void TouchInputMapper::cookPointerData() { bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale; top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale; orientation += M_PI_2; - if (mOrientedRanges.haveOrientation && - orientation > mOrientedRanges.orientation.max) { + if (mOrientedRanges.orientation && orientation > mOrientedRanges.orientation->max) { orientation -= - (mOrientedRanges.orientation.max - mOrientedRanges.orientation.min); + (mOrientedRanges.orientation->max - mOrientedRanges.orientation->min); } break; default: @@ -4025,10 +4055,11 @@ int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode return AKEY_STATE_UNKNOWN; } -bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { +bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, + const std::vector<int32_t>& keyCodes, + uint8_t* outFlags) { for (const VirtualKey& virtualKey : mVirtualKeys) { - for (size_t i = 0; i < numCodes; i++) { + for (size_t i = 0; i < keyCodes.size(); i++) { if (virtualKey.keyCode == keyCodes[i]) { outFlags[i] = 1; } diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index c948f565d9..3cb11aa04e 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -147,7 +147,7 @@ public: int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override; int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override; - bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes, + bool markSupportedKeyCodes(uint32_t sourceMask, const std::vector<int32_t>& keyCodes, uint8_t* outFlags) override; void cancelTouch(nsecs_t when, nsecs_t readTime) override; @@ -248,12 +248,9 @@ protected: SizeCalibration sizeCalibration; - bool haveSizeScale; - float sizeScale; - bool haveSizeBias; - float sizeBias; - bool haveSizeIsSummed; - bool sizeIsSummed; + std::optional<float> sizeScale; + std::optional<float> sizeBias; + std::optional<bool> sizeIsSummed; // Pressure enum class PressureCalibration { @@ -264,8 +261,7 @@ protected: }; PressureCalibration pressureCalibration; - bool havePressureScale; - float pressureScale; + std::optional<float> pressureScale; // Orientation enum class OrientationCalibration { @@ -285,8 +281,7 @@ protected: }; DistanceCalibration distanceCalibration; - bool haveDistanceScale; - float distanceScale; + std::optional<float> distanceScale; enum class CoverageCalibration { DEFAULT, @@ -296,15 +291,15 @@ protected: CoverageCalibration coverageCalibration; - inline void applySizeScaleAndBias(float* outSize) const { - if (haveSizeScale) { - *outSize *= sizeScale; + inline void applySizeScaleAndBias(float& outSize) const { + if (sizeScale) { + outSize *= *sizeScale; } - if (haveSizeBias) { - *outSize += sizeBias; + if (sizeBias) { + outSize += *sizeBias; } - if (*outSize < 0) { - *outSize = 0; + if (outSize < 0) { + outSize = 0; } } } mCalibration; @@ -475,35 +470,29 @@ private: InputDeviceInfo::MotionRange y; InputDeviceInfo::MotionRange pressure; - bool haveSize; - InputDeviceInfo::MotionRange size; + std::optional<InputDeviceInfo::MotionRange> size; - bool haveTouchSize; - InputDeviceInfo::MotionRange touchMajor; - InputDeviceInfo::MotionRange touchMinor; + std::optional<InputDeviceInfo::MotionRange> touchMajor; + std::optional<InputDeviceInfo::MotionRange> touchMinor; - bool haveToolSize; - InputDeviceInfo::MotionRange toolMajor; - InputDeviceInfo::MotionRange toolMinor; + std::optional<InputDeviceInfo::MotionRange> toolMajor; + std::optional<InputDeviceInfo::MotionRange> toolMinor; - bool haveOrientation; - InputDeviceInfo::MotionRange orientation; + std::optional<InputDeviceInfo::MotionRange> orientation; - bool haveDistance; - InputDeviceInfo::MotionRange distance; + std::optional<InputDeviceInfo::MotionRange> distance; - bool haveTilt; - InputDeviceInfo::MotionRange tilt; - - OrientedRanges() { clear(); } + std::optional<InputDeviceInfo::MotionRange> tilt; void clear() { - haveSize = false; - haveTouchSize = false; - haveToolSize = false; - haveOrientation = false; - haveDistance = false; - haveTilt = false; + size = std::nullopt; + touchMajor = std::nullopt; + touchMinor = std::nullopt; + toolMajor = std::nullopt; + toolMinor = std::nullopt; + orientation = std::nullopt; + distance = std::nullopt; + tilt = std::nullopt; } } mOrientedRanges; @@ -527,7 +516,9 @@ private: float mPointerXZoomScale; float mPointerYZoomScale; - // The maximum swipe width. + // The maximum swipe width between pointers to detect a swipe gesture + // in the number of pixels.Touches that are wider than this are translated + // into freeform gestures. float mPointerGestureMaxSwipeWidth; struct PointerDistanceHeapElement { diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index df4307101f..8a2dea5f4e 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -58,6 +58,8 @@ static constexpr int32_t POINTER_1_DOWN = AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); static constexpr int32_t POINTER_2_DOWN = AMOTION_EVENT_ACTION_POINTER_DOWN | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); +static constexpr int32_t POINTER_3_DOWN = + AMOTION_EVENT_ACTION_POINTER_DOWN | (3 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); static constexpr int32_t POINTER_1_UP = AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); @@ -412,7 +414,6 @@ private: void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) override {} - void notifyUntrustedTouch(const std::string& obscuringPackage) override {} void notifySensorEvent(int32_t deviceId, InputDeviceSensorType sensorType, InputDeviceSensorAccuracy accuracy, nsecs_t timestamp, const std::vector<float>& values) override {} @@ -499,6 +500,11 @@ private: verify(*mFilteredEvent); mFilteredEvent = nullptr; } + + bool isPerDisplayTouchModeEnabled() { + // TODO(b/198499018): Make this a regular property once per display touch mode is enabled + return false; + } }; // --- InputDispatcherTest --- @@ -1942,6 +1948,77 @@ TEST_F(InputDispatcherTest, SplitWorksWhenNonTouchableWindowIsTouched) { window2->consumeMotionDown(); } +/** + * When splitting touch events the downTime should be adjusted such that the downTime corresponds + * to the event time of the first ACTION_DOWN sent to the particular window. + */ +TEST_F(InputDispatcherTest, SplitTouchesSendCorrectActionDownTime) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> window1 = + new FakeWindowHandle(application, mDispatcher, "Window1", DISPLAY_ID); + window1->setTouchableRegion(Region{{0, 0, 100, 100}}); + sp<FakeWindowHandle> window2 = + new FakeWindowHandle(application, mDispatcher, "Window2", DISPLAY_ID); + window2->setTouchableRegion(Region{{100, 0, 200, 100}}); + + mDispatcher->setInputWindows({{DISPLAY_ID, {window1, window2}}}); + + NotifyMotionArgs args; + // Touch down on the first window + mDispatcher->notifyMotion(&(args = generateTouchArgs(AMOTION_EVENT_ACTION_DOWN, {{50, 50}}))); + + mDispatcher->waitForIdle(); + InputEvent* inputEvent1 = window1->consume(); + window2->assertNoEvents(); + MotionEvent& motionEvent1 = static_cast<MotionEvent&>(*inputEvent1); + nsecs_t downTimeForWindow1 = motionEvent1.getDownTime(); + ASSERT_EQ(motionEvent1.getDownTime(), motionEvent1.getEventTime()); + + // Now touch down on the window with another pointer + mDispatcher->notifyMotion(&(args = generateTouchArgs(POINTER_1_DOWN, {{50, 50}, {150, 50}}))); + mDispatcher->waitForIdle(); + InputEvent* inputEvent2 = window2->consume(); + MotionEvent& motionEvent2 = static_cast<MotionEvent&>(*inputEvent2); + nsecs_t downTimeForWindow2 = motionEvent2.getDownTime(); + ASSERT_NE(downTimeForWindow1, downTimeForWindow2); + ASSERT_EQ(motionEvent2.getDownTime(), motionEvent2.getEventTime()); + + // Now move the pointer on the second window + mDispatcher->notifyMotion( + &(args = generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{50, 50}, {151, 51}}))); + mDispatcher->waitForIdle(); + InputEvent* inputEvent3 = window2->consume(); + MotionEvent& motionEvent3 = static_cast<MotionEvent&>(*inputEvent3); + ASSERT_EQ(motionEvent3.getDownTime(), downTimeForWindow2); + + // Now add new touch down on the second window + mDispatcher->notifyMotion( + &(args = generateTouchArgs(POINTER_2_DOWN, {{50, 50}, {151, 51}, {150, 50}}))); + mDispatcher->waitForIdle(); + InputEvent* inputEvent4 = window2->consume(); + MotionEvent& motionEvent4 = static_cast<MotionEvent&>(*inputEvent4); + ASSERT_EQ(motionEvent4.getDownTime(), downTimeForWindow2); + + // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line + window1->consumeMotionMove(); + window1->assertNoEvents(); + + // Now move the pointer on the first window + mDispatcher->notifyMotion( + &(args = generateTouchArgs(AMOTION_EVENT_ACTION_MOVE, {{51, 51}, {151, 51}}))); + mDispatcher->waitForIdle(); + InputEvent* inputEvent5 = window1->consume(); + MotionEvent& motionEvent5 = static_cast<MotionEvent&>(*inputEvent5); + ASSERT_EQ(motionEvent5.getDownTime(), downTimeForWindow1); + + mDispatcher->notifyMotion(&( + args = generateTouchArgs(POINTER_3_DOWN, {{51, 51}, {151, 51}, {150, 50}, {50, 50}}))); + mDispatcher->waitForIdle(); + InputEvent* inputEvent6 = window1->consume(); + MotionEvent& motionEvent6 = static_cast<MotionEvent&>(*inputEvent6); + ASSERT_EQ(motionEvent6.getDownTime(), downTimeForWindow1); +} + TEST_F(InputDispatcherTest, HoverMoveEnterMouseClickAndHoverMoveExit) { std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); sp<FakeWindowHandle> windowLeft = @@ -3221,7 +3298,7 @@ TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) { SCOPED_TRACE("Disable touch mode"); mDispatcher->setInTouchMode(false, windowInfo.ownerPid, windowInfo.ownerUid, - /* hasPermission */ true); + true /*hasPermission*/, ADISPLAY_ID_DEFAULT); window->consumeTouchModeEvent(false); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -3235,7 +3312,7 @@ TEST_F(InputDispatcherTest, TouchModeState_IsSentToApps) { SCOPED_TRACE("Enable touch mode again"); mDispatcher->setInTouchMode(true, windowInfo.ownerPid, windowInfo.ownerUid, - /* hasPermission */ true); + true /*hasPermission*/, ADISPLAY_ID_DEFAULT); window->consumeTouchModeEvent(true); window->setFocusable(true); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}}); @@ -5715,7 +5792,6 @@ protected: virtual void SetUp() override { InputDispatcherTest::SetUp(); mTouchWindow = getWindow(TOUCHED_APP_UID, "Touched"); - mDispatcher->setBlockUntrustedTouchesMode(android::os::BlockUntrustedTouchesMode::BLOCK); mDispatcher->setMaximumObscuringOpacityForTouch(MAXIMUM_OBSCURING_OPACITY); } @@ -6096,6 +6172,7 @@ protected: sp<FakeWindowHandle> mWindow; sp<FakeWindowHandle> mSecondWindow; sp<FakeWindowHandle> mDragWindow; + sp<FakeWindowHandle> mSpyWindow; void SetUp() override { InputDispatcherTest::SetUp(); @@ -6106,8 +6183,13 @@ protected: mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT); mSecondWindow->setFrame(Rect(100, 0, 200, 100)); + mSpyWindow = new FakeWindowHandle(mApp, mDispatcher, "SpyWindow", ADISPLAY_ID_DEFAULT); + mSpyWindow->setSpy(true); + mSpyWindow->setTrustedOverlay(true); + mSpyWindow->setFrame(Rect(0, 0, 200, 100)); + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mSpyWindow, mWindow, mSecondWindow}}}); } void injectDown() { @@ -6118,6 +6200,8 @@ protected: // Window should receive motion event. mWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); + // Spy window should also receive motion event + mSpyWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT); } // Start performing drag, we will create a drag window and transfer touch to it. @@ -6130,8 +6214,9 @@ protected: // The drag window covers the entire display mDragWindow = new FakeWindowHandle(mApp, mDispatcher, "DragWindow", ADISPLAY_ID_DEFAULT); + mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}}); mDispatcher->setInputWindows( - {{ADISPLAY_ID_DEFAULT, {mDragWindow, mWindow, mSecondWindow}}}); + {{ADISPLAY_ID_DEFAULT, {mDragWindow, mSpyWindow, mWindow, mSecondWindow}}}); // Transfer touch focus to the drag window bool transferred = @@ -6209,6 +6294,30 @@ TEST_F(InputDispatcherDragTests, DragEnterAndDragExit) { mSecondWindow->assertNoEvents(); } +TEST_F(InputDispatcherDragTests, DragEnterAndPointerDownPilfersPointers) { + performDrag(); + + // No cancel event after drag start + mSpyWindow->assertNoEvents(); + + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(60).y(60)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + // Receives cancel for first pointer after next pointer down + mSpyWindow->consumeMotionCancel(); + mSpyWindow->consumeMotionDown(); + + mSpyWindow->assertNoEvents(); +} + TEST_F(InputDispatcherDragTests, DragAndDrop) { performDrag(); @@ -6611,14 +6720,15 @@ protected: // Set initial touch mode to InputDispatcher::kDefaultInTouchMode. if (mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, WINDOW_PID, - WINDOW_UID, /* hasPermission */ true)) { + WINDOW_UID, true /*hasPermission*/, ADISPLAY_ID_DEFAULT)) { mWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode); mSecondWindow->consumeTouchModeEvent(InputDispatcher::kDefaultInTouchMode); } } void changeAndVerifyTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission) { - ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission)); + ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission, + ADISPLAY_ID_DEFAULT)); mWindow->consumeTouchModeEvent(inTouchMode); mSecondWindow->consumeTouchModeEvent(inTouchMode); } @@ -6627,7 +6737,7 @@ protected: TEST_F(InputDispatcherTouchModeChangedTests, FocusedWindowCanChangeTouchMode) { const WindowInfo& windowInfo = *mWindow->getInfo(); changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid, - windowInfo.ownerUid, /* hasPermission */ false); + windowInfo.ownerUid, false /*hasPermission*/); } TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) { @@ -6636,7 +6746,8 @@ TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTo int32_t ownerUid = windowInfo.ownerUid; mWindow->setOwnerInfo(/* pid */ -1, /* uid */ -1); ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid, - ownerUid, /* hasPermission */ false)); + ownerUid, false /*hasPermission*/, + ADISPLAY_ID_DEFAULT)); mWindow->assertNoEvents(); mSecondWindow->assertNoEvents(); } @@ -6647,14 +6758,14 @@ TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnP int32_t ownerUid = windowInfo.ownerUid; mWindow->setOwnerInfo(/* pid */ -1, /* uid */ -1); changeAndVerifyTouchMode(!InputDispatcher::kDefaultInTouchMode, ownerPid, ownerUid, - /* hasPermission */ true); + true /*hasPermission*/); } TEST_F(InputDispatcherTouchModeChangedTests, EventIsNotGeneratedIfNotChangingTouchMode) { const WindowInfo& windowInfo = *mWindow->getInfo(); ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid, windowInfo.ownerUid, - /* hasPermission */ true)); + true /*hasPermission*/, ADISPLAY_ID_DEFAULT)); mWindow->assertNoEvents(); mSecondWindow->assertNoEvents(); } @@ -6673,7 +6784,7 @@ TEST_F(InputDispatcherTouchModeChangedTests, CanChangeTouchModeWhenOwningLastInt const WindowInfo& windowInfo = *mWindow->getInfo(); ASSERT_TRUE(mDispatcher->setInTouchMode(!InputDispatcher::kDefaultInTouchMode, windowInfo.ownerPid, windowInfo.ownerUid, - /* hasPermission= */ false)); + false /*hasPermission*/, ADISPLAY_ID_DEFAULT)); } class InputDispatcherSpyWindowTest : public InputDispatcherTest { @@ -6862,10 +6973,146 @@ TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) { } /** - * A spy window can pilfer pointers. When this happens, touch gestures that are currently sent to - * any other windows - including other spy windows - will also be cancelled. + * Even when a spy window spans over multiple foreground windows, the spy should receive all + * pointers that are down within its bounds. + */ +TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { + auto windowLeft = createForeground(); + windowLeft->setFrame({0, 0, 100, 200}); + auto windowRight = createForeground(); + windowRight->setFrame({100, 0, 200, 200}); + auto spy = createSpy(); + spy->setFrame({0, 0, 200, 200}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, windowLeft, windowRight}}}); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + windowLeft->consumeMotionDown(); + spy->consumeMotionDown(); + + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer( + PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + windowRight->consumeMotionDown(); + spy->consumeMotionPointerDown(1 /*pointerIndex*/); +} + +/** + * When the first pointer lands outside the spy window and the second pointer lands inside it, the + * the spy should receive the second pointer with ACTION_DOWN. + */ +TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { + auto window = createForeground(); + window->setFrame({0, 0, 200, 200}); + auto spyRight = createSpy(); + spyRight->setFrame({100, 0, 200, 200}); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyRight, window}}}); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {50, 50})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionDown(); + spyRight->assertNoEvents(); + + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer( + PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionPointerDown(1 /*pointerIndex*/); + spyRight->consumeMotionDown(); +} + +/** + * The spy window should not be able to affect whether or not touches are split. Only the foreground + * windows should be allowed to control split touch. + */ +TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { + // This spy window prevents touch splitting. However, we still expect to split touches + // because a foreground window has not disabled splitting. + auto spy = createSpy(); + spy->setPreventSplitting(true); + + auto window = createForeground(); + window->setFrame(Rect(0, 0, 100, 100)); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + + // First finger down, no window touched. + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, + {100, 200})) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); + window->assertNoEvents(); + + // Second finger down on window, the window should receive touch down. + const MotionEvent secondFingerDownEvent = + MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(100) + .y(200)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + + window->consumeMotionDown(ADISPLAY_ID_DEFAULT); + spy->consumeMotionPointerDown(1 /* pointerIndex */); +} + +/** + * A spy window will usually be implemented as an un-focusable window. Verify that these windows + * do not receive key events. + */ +TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) { + auto spy = createSpy(); + spy->setFocusable(false); + + auto window = createForeground(); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + setFocusedWindow(window); + window->consumeFocusEvent(true); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) + << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeKeyDown(ADISPLAY_ID_NONE); + + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) + << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeKeyUp(ADISPLAY_ID_NONE); + + spy->assertNoEvents(); +} + +using InputDispatcherPilferPointersTest = InputDispatcherSpyWindowTest; + +/** + * A spy window can pilfer pointers. When this happens, touch gestures used by the spy window that + * are currently sent to any other windows - including other spy windows - will also be cancelled. */ -TEST_F(InputDispatcherSpyWindowTest, PilferPointers) { +TEST_F(InputDispatcherPilferPointersTest, PilferPointers) { auto window = createForeground(); auto spy1 = createSpy(); auto spy2 = createSpy(); @@ -6898,7 +7145,7 @@ TEST_F(InputDispatcherSpyWindowTest, PilferPointers) { * A spy window can pilfer pointers for a gesture even after the foreground window has been removed * in the middle of the gesture. */ -TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) { +TEST_F(InputDispatcherPilferPointersTest, CanPilferAfterWindowIsRemovedMidStream) { auto window = createForeground(); auto spy = createSpy(); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); @@ -6923,7 +7170,7 @@ TEST_F(InputDispatcherSpyWindowTest, CanPilferAfterWindowIsRemovedMidStream) { * After a spy window pilfers pointers, new pointers that go down in its bounds should be sent to * the spy, but not to any other windows. */ -TEST_F(InputDispatcherSpyWindowTest, ContinuesToReceiveGestureAfterPilfer) { +TEST_F(InputDispatcherPilferPointersTest, ContinuesToReceiveGestureAfterPilfer) { auto spy = createSpy(); auto window = createForeground(); @@ -6979,136 +7226,154 @@ TEST_F(InputDispatcherSpyWindowTest, ContinuesToReceiveGestureAfterPilfer) { } /** - * Even when a spy window spans over multiple foreground windows, the spy should receive all - * pointers that are down within its bounds. + * After a spy window pilfers pointers, only the pointers used by the spy should be canceled */ -TEST_F(InputDispatcherSpyWindowTest, ReceivesMultiplePointers) { - auto windowLeft = createForeground(); - windowLeft->setFrame({0, 0, 100, 200}); - auto windowRight = createForeground(); - windowRight->setFrame({100, 0, 200, 200}); +TEST_F(InputDispatcherPilferPointersTest, PartiallyPilferRequiredPointers) { auto spy = createSpy(); - spy->setFrame({0, 0, 200, 200}); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, windowLeft, windowRight}}}); + spy->setFrame(Rect(0, 0, 100, 100)); + auto window = createForeground(); + window->setFrame(Rect(0, 0, 200, 200)); + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + + // First finger down on the window only ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {50, 50})) + {150, 150})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - windowLeft->consumeMotionDown(); - spy->consumeMotionDown(); + window->consumeMotionDown(); + // Second finger down on the spy and window const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) - .pointer( - PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(150) + .y(150)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - windowRight->consumeMotionDown(); - spy->consumeMotionPointerDown(1 /*pointerIndex*/); + spy->consumeMotionDown(); + window->consumeMotionPointerDown(1); + + // Third finger down on the spy and window + const MotionEvent thirdFingerDownEvent = + MotionEventBuilder(POINTER_2_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) + .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(150) + .y(150)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) + .pointer(PointerBuilder(/* id */ 2, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .build(); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(mDispatcher, thirdFingerDownEvent, INJECT_EVENT_TIMEOUT, + InputEventInjectionSync::WAIT_FOR_RESULT)) + << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + spy->consumeMotionPointerDown(1); + window->consumeMotionPointerDown(2); + + // Spy window pilfers the pointers. + EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); + window->consumeMotionPointerUp(/* idx */ 2, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED); + window->consumeMotionPointerUp(/* idx */ 1, ADISPLAY_ID_DEFAULT, AMOTION_EVENT_FLAG_CANCELED); + + spy->assertNoEvents(); + window->assertNoEvents(); } /** - * When the first pointer lands outside the spy window and the second pointer lands inside it, the - * the spy should receive the second pointer with ACTION_DOWN. + * After a spy window pilfers pointers, all pilfered pointers that have already been dispatched to + * other windows should be canceled. If this results in the cancellation of all pointers for some + * window, then that window should receive ACTION_CANCEL. */ -TEST_F(InputDispatcherSpyWindowTest, ReceivesSecondPointerAsDown) { +TEST_F(InputDispatcherPilferPointersTest, PilferAllRequiredPointers) { + auto spy = createSpy(); + spy->setFrame(Rect(0, 0, 100, 100)); auto window = createForeground(); - window->setFrame({0, 0, 200, 200}); - auto spyRight = createSpy(); - spyRight->setFrame({100, 0, 200, 200}); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spyRight, window}}}); + window->setFrame(Rect(0, 0, 200, 200)); + + mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); + // First finger down on both spy and window ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {50, 50})) + {10, 10})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; window->consumeMotionDown(); - spyRight->assertNoEvents(); + spy->consumeMotionDown(); + // Second finger down on the spy and window const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) + .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) - .pointer( - PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(150).y(50)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeMotionPointerDown(1 /*pointerIndex*/); - spyRight->consumeMotionDown(); + spy->consumeMotionPointerDown(1); + window->consumeMotionPointerDown(1); + + // Spy window pilfers the pointers. + EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); + window->consumeMotionCancel(); + + spy->assertNoEvents(); + window->assertNoEvents(); } /** - * The spy window should not be able to affect whether or not touches are split. Only the foreground - * windows should be allowed to control split touch. + * After a spy window pilfers pointers, new pointers that are not touching the spy window can still + * be sent to other windows */ -TEST_F(InputDispatcherSpyWindowTest, SplitIfNoForegroundWindowTouched) { - // This spy window prevents touch splitting. However, we still expect to split touches - // because a foreground window has not disabled splitting. +TEST_F(InputDispatcherPilferPointersTest, CanReceivePointersAfterPilfer) { auto spy = createSpy(); - spy->setPreventSplitting(true); - + spy->setFrame(Rect(0, 0, 100, 100)); auto window = createForeground(); - window->setFrame(Rect(0, 0, 100, 100)); + window->setFrame(Rect(0, 0, 200, 200)); mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); - // First finger down, no window touched. + // First finger down on both window and spy ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, - {100, 200})) + {10, 10})) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; - spy->consumeMotionDown(ADISPLAY_ID_DEFAULT); - window->assertNoEvents(); + window->consumeMotionDown(); + spy->consumeMotionDown(); - // Second finger down on window, the window should receive touch down. + // Spy window pilfers the pointers. + EXPECT_EQ(OK, mDispatcher->pilferPointers(spy->getToken())); + window->consumeMotionCancel(); + + // Second finger down on the window only const MotionEvent secondFingerDownEvent = MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN) .displayId(ADISPLAY_ID_DEFAULT) .eventTime(systemTime(SYSTEM_TIME_MONOTONIC)) - .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER) - .x(100) - .y(200)) - .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER).x(50).y(50)) + .pointer(PointerBuilder(/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER).x(10).y(10)) + .pointer(PointerBuilder(/* id */ 1, AMOTION_EVENT_TOOL_TYPE_FINGER) + .x(150) + .y(150)) .build(); ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT, InputEventInjectionSync::WAIT_FOR_RESULT)) << "Inject motion event should return InputEventInjectionResult::SUCCEEDED"; + window->consumeMotionDown(); + window->assertNoEvents(); - window->consumeMotionDown(ADISPLAY_ID_DEFAULT); - spy->consumeMotionPointerDown(1 /* pointerIndex */); -} - -/** - * A spy window will usually be implemented as an un-focusable window. Verify that these windows - * do not receive key events. - */ -TEST_F(InputDispatcherSpyWindowTest, UnfocusableSpyDoesNotReceiveKeyEvents) { - auto spy = createSpy(); - spy->setFocusable(false); - - auto window = createForeground(); - mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}}); - setFocusedWindow(window); - window->consumeFocusEvent(true); - - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyDown(mDispatcher)) - << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeKeyDown(ADISPLAY_ID_NONE); - - ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, injectKeyUp(mDispatcher)) - << "Inject key event should return InputEventInjectionResult::SUCCEEDED"; - window->consumeKeyUp(ADISPLAY_ID_NONE); - + // TODO(b/232530217): do not send the unnecessary MOVE event and delete the next line + spy->consumeMotionMove(); spy->assertNoEvents(); } diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 0b8eb26a03..67fcc40c94 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -373,8 +373,12 @@ public: mConfig.defaultPointerDisplayId = pointerDisplayId; } + void setPointerGestureEnabled(bool enabled) { mConfig.pointerGesturesEnabled = enabled; } + float getPointerGestureMovementSpeedRatio() { return mConfig.pointerGestureMovementSpeedRatio; } + float getPointerGestureZoomSpeedRatio() { return mConfig.pointerGestureZoomSpeedRatio; } + void setVelocityControlParams(const VelocityControlParameters& params) { mConfig.pointerVelocityControlParameters = params; mConfig.wheelVelocityControlParameters = params; @@ -546,7 +550,7 @@ public: enqueueEvent(ARBITRARY_TIME, READ_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0); } - void addConfigurationProperty(int32_t deviceId, const String8& key, const String8& value) { + void addConfigurationProperty(int32_t deviceId, const char* key, const char* value) { Device* device = getDevice(deviceId); device->configuration.addProperty(key, value); } @@ -887,13 +891,13 @@ private: } // Return true if the device has non-empty key layout. - bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, + bool markSupportedKeyCodes(int32_t deviceId, const std::vector<int32_t>& keyCodes, uint8_t* outFlags) const override { bool result = false; Device* device = getDevice(deviceId); if (device) { result = device->keysByScanCode.size() > 0 || device->keysByUsageCode.size() > 0; - for (size_t i = 0; i < numCodes; i++) { + for (size_t i = 0; i < keyCodes.size(); i++) { for (size_t j = 0; j < device->keysByScanCode.size(); j++) { if (keyCodes[i] == device->keysByScanCode.valueAt(j).keyCode) { outFlags[i] = 1; @@ -1209,9 +1213,9 @@ private: } // Return true if the device has non-empty key layout. - bool markSupportedKeyCodes(uint32_t, size_t numCodes, const int32_t* keyCodes, + bool markSupportedKeyCodes(uint32_t, const std::vector<int32_t>& keyCodes, uint8_t* outFlags) override { - for (size_t i = 0; i < numCodes; i++) { + for (size_t i = 0; i < keyCodes.size(); i++) { for (size_t j = 0; j < mSupportedKeyCodes.size(); j++) { if (keyCodes[i] == mSupportedKeyCodes[j]) { outFlags[i] = 1; @@ -1855,34 +1859,37 @@ TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) { mapper.addSupportedKeyCode(AKEYCODE_A); mapper.addSupportedKeyCode(AKEYCODE_B); - const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 }; + const std::vector<int32_t> keyCodes{AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2}; uint8_t flags[4] = { 0, 0, 0, 1 }; - ASSERT_FALSE(mReader->hasKeys(0, AINPUT_SOURCE_ANY, 4, keyCodes, flags)) + ASSERT_FALSE(mReader->hasKeys(0, AINPUT_SOURCE_ANY, keyCodes, flags)) << "Should return false when device id is >= 0 but unknown."; ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); flags[3] = 1; - ASSERT_FALSE(mReader->hasKeys(deviceId, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) + ASSERT_FALSE(mReader->hasKeys(deviceId, AINPUT_SOURCE_TRACKBALL, keyCodes, flags)) << "Should return false when device id is valid but the sources are not supported by " "the device."; ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); flags[3] = 1; - ASSERT_TRUE(mReader->hasKeys(deviceId, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, + ASSERT_TRUE(mReader->hasKeys(deviceId, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, keyCodes, flags)) << "Should return value provided by mapper when device id is valid and the device " "supports some of the sources."; ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]); flags[3] = 1; - ASSERT_FALSE(mReader->hasKeys(-1, AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should return false when the device id is < 0 but the sources are not supported by any device."; + ASSERT_FALSE(mReader->hasKeys(-1, AINPUT_SOURCE_TRACKBALL, keyCodes, flags)) + << "Should return false when the device id is < 0 but the sources are not supported by " + "any device."; ASSERT_TRUE(!flags[0] && !flags[1] && !flags[2] && !flags[3]); flags[3] = 1; - ASSERT_TRUE(mReader->hasKeys(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) - << "Should return value provided by mapper when device id is < 0 and one of the devices supports some of the sources."; + ASSERT_TRUE( + mReader->hasKeys(-1, AINPUT_SOURCE_KEYBOARD | AINPUT_SOURCE_TRACKBALL, keyCodes, flags)) + << "Should return value provided by mapper when device id is < 0 and one of the " + "devices supports some of the sources."; ASSERT_TRUE(flags[0] && flags[1] && !flags[2] && !flags[3]); } @@ -2718,9 +2725,9 @@ TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { ASSERT_EQ(AKEY_STATE_UNKNOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 0)) << "Ignored device should return unknown switch state."; - const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; + const std::vector<int32_t> keyCodes{AKEYCODE_A, AKEYCODE_B}; uint8_t flags[2] = { 0, 1 }; - ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 2, keyCodes, flags)) + ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, keyCodes, flags)) << "Ignored device should never mark any key codes."; ASSERT_EQ(0, flags[0]) << "Flag for unsupported key should be unchanged."; ASSERT_EQ(1, flags[1]) << "Flag for unsupported key should be unchanged."; @@ -2728,7 +2735,7 @@ TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) { TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRequestsToMappers) { // Configuration. - mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, String8("key"), String8("value")); + mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, "key", "value"); FakeInputMapper& mapper1 = mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, AINPUT_SOURCE_KEYBOARD); @@ -2749,10 +2756,10 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe InputReaderConfiguration config; mDevice->configure(ARBITRARY_TIME, &config, 0); - String8 propertyValue; - ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty(String8("key"), propertyValue)) + std::string propertyValue; + ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty("key", propertyValue)) << "Device should have read configuration during configuration phase."; - ASSERT_STREQ("value", propertyValue.string()); + ASSERT_EQ("value", propertyValue); ASSERT_NO_FATAL_FAILURE(mapper1.assertConfigureWasCalled()); ASSERT_NO_FATAL_FAILURE(mapper2.assertConfigureWasCalled()); @@ -2795,16 +2802,16 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe ASSERT_EQ(AKEY_STATE_DOWN, mDevice->getSwitchState(AINPUT_SOURCE_KEYBOARD, 4)) << "Should query mapper when source is supported."; - const int32_t keyCodes[4] = { AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2 }; + const std::vector<int32_t> keyCodes{AKEYCODE_A, AKEYCODE_B, AKEYCODE_1, AKEYCODE_2}; uint8_t flags[4] = { 0, 0, 0, 1 }; - ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_TRACKBALL, 4, keyCodes, flags)) + ASSERT_FALSE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_TRACKBALL, keyCodes, flags)) << "Should do nothing when source is unsupported."; ASSERT_EQ(0, flags[0]) << "Flag should be unchanged when source is unsupported."; ASSERT_EQ(0, flags[1]) << "Flag should be unchanged when source is unsupported."; ASSERT_EQ(0, flags[2]) << "Flag should be unchanged when source is unsupported."; ASSERT_EQ(1, flags[3]) << "Flag should be unchanged when source is unsupported."; - ASSERT_TRUE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, 4, keyCodes, flags)) + ASSERT_TRUE(mDevice->markSupportedKeyCodes(AINPUT_SOURCE_KEYBOARD, keyCodes, flags)) << "Should query mapper when source is supported."; ASSERT_EQ(1, flags[0]) << "Flag for supported key should be set."; ASSERT_EQ(1, flags[1]) << "Flag for supported key should be set."; @@ -2950,7 +2957,7 @@ protected: } void addConfigurationProperty(const char* key, const char* value) { - mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, String8(key), String8(value)); + mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, key, value); } void configureDevice(uint32_t changes) { @@ -3726,9 +3733,8 @@ TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) { mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0); - const int32_t keyCodes[2] = { AKEYCODE_A, AKEYCODE_B }; uint8_t flags[2] = { 0, 0 }; - ASSERT_TRUE(mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, 1, keyCodes, flags)); + ASSERT_TRUE(mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, {AKEYCODE_A, AKEYCODE_B}, flags)); ASSERT_TRUE(flags[0]); ASSERT_FALSE(flags[1]); } @@ -5405,9 +5411,9 @@ TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) { prepareVirtualKeys(); SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); - const int32_t keys[2] = { AKEYCODE_HOME, AKEYCODE_A }; uint8_t flags[2] = { 0, 0 }; - ASSERT_TRUE(mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, 2, keys, flags)); + ASSERT_TRUE( + mapper.markSupportedKeyCodes(AINPUT_SOURCE_ANY, {AKEYCODE_HOME, AKEYCODE_A}, flags)); ASSERT_TRUE(flags[0]); ASSERT_FALSE(flags[1]); } @@ -9462,6 +9468,258 @@ TEST_F(MultiTouchInputMapperTest, WhenCapturedAndNotCaptured_GetSources) { ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources()); } +class MultiTouchPointerModeTest : public MultiTouchInputMapperTest { +protected: + float mPointerMovementScale; + float mPointerXZoomScale; + void preparePointerMode(int xAxisResolution, int yAxisResolution) { + addConfigurationProperty("touch.deviceType", "pointer"); + std::shared_ptr<FakePointerController> fakePointerController = + std::make_shared<FakePointerController>(); + fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1); + fakePointerController->setPosition(0, 0); + fakePointerController->setButtonState(0); + prepareDisplay(DISPLAY_ORIENTATION_0); + + prepareAxes(POSITION); + prepareAbsoluteAxisResolution(xAxisResolution, yAxisResolution); + // In order to enable swipe and freeform gesture in pointer mode, pointer capture + // needs to be disabled, and the pointer gesture needs to be enabled. + mFakePolicy->setPointerCapture(false); + mFakePolicy->setPointerGestureEnabled(true); + mFakePolicy->setPointerController(fakePointerController); + + float rawDiagonal = hypotf(RAW_X_MAX - RAW_X_MIN, RAW_Y_MAX - RAW_Y_MIN); + float displayDiagonal = hypotf(DISPLAY_WIDTH, DISPLAY_HEIGHT); + mPointerMovementScale = + mFakePolicy->getPointerGestureMovementSpeedRatio() * displayDiagonal / rawDiagonal; + mPointerXZoomScale = + mFakePolicy->getPointerGestureZoomSpeedRatio() * displayDiagonal / rawDiagonal; + } + + void prepareAbsoluteAxisResolution(int xAxisResolution, int yAxisResolution) { + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX, + /*flat*/ 0, + /*fuzz*/ 0, /*resolution*/ xAxisResolution); + mFakeEventHub->addAbsoluteAxis(EVENTHUB_ID, ABS_MT_POSITION_Y, RAW_Y_MIN, RAW_Y_MAX, + /*flat*/ 0, + /*fuzz*/ 0, /*resolution*/ yAxisResolution); + } +}; + +/** + * Two fingers down on a pointer mode touch pad. The width + * of the two finger is larger than 1/4 of the touch pack diagnal length. However, it + * is smaller than the fixed min physical length 30mm. Two fingers' distance must + * be greater than the both value to be freeform gesture, so that after two + * fingers start to move downwards, the gesture should be swipe. + */ +TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthSwipe) { + // The min freeform gesture width is 25units/mm x 30mm = 750 + // which is greater than fraction of the diagnal length of the touchpad (349). + // Thus, MaxSwipWidth is 750. + preparePointerMode(25 /*xResolution*/, 25 /*yResolution*/); + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + NotifyMotionArgs motionArgs; + + // Two fingers down at once. + // The two fingers are 450 units apart, expects the current gesture to be PRESS + // Pointer's initial position is used the [0,0] coordinate. + int32_t x1 = 100, y1 = 125, x2 = 550, y2 = 125; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_NO_FATAL_FAILURE( + assertPointerCoords(motionArgs.pointerCoords[0], 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)); + + // It should be recognized as a SWIPE gesture when two fingers start to move down, + // that there should be 1 pointer. + int32_t movingDistance = 200; + y1 += movingDistance; + y2 += movingDistance; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 0, + movingDistance * mPointerMovementScale, 1, 0, 0, 0, + 0, 0, 0, 0)); +} + +/** + * Two fingers down on a pointer mode touch pad. The width of the two finger is larger + * than the minimum freeform gesture width, 30mm. However, it is smaller than 1/4 of + * the touch pack diagnal length. Two fingers' distance must be greater than the both + * value to be freeform gesture, so that after two fingers start to move downwards, + * the gesture should be swipe. + */ +TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthLowResolutionSwipe) { + // The min freeform gesture width is 5units/mm x 30mm = 150 + // which is greater than fraction of the diagnal length of the touchpad (349). + // Thus, MaxSwipWidth is the fraction of the diagnal length, 349. + preparePointerMode(5 /*xResolution*/, 5 /*yResolution*/); + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + NotifyMotionArgs motionArgs; + + // Two fingers down at once. + // The two fingers are 250 units apart, expects the current gesture to be PRESS + // Pointer's initial position is used the [0,0] coordinate. + int32_t x1 = 100, y1 = 125, x2 = 350, y2 = 125; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_NO_FATAL_FAILURE( + assertPointerCoords(motionArgs.pointerCoords[0], 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)); + + // It should be recognized as a SWIPE gesture when two fingers start to move down, + // and there should be 1 pointer. + int32_t movingDistance = 200; + y1 += movingDistance; + y2 += movingDistance; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + // New coordinate is the scaled relative coordinate from the initial coordinate. + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], 0, + movingDistance * mPointerMovementScale, 1, 0, 0, 0, + 0, 0, 0, 0)); +} + +/** + * Touch the touch pad with two fingers with a distance wider than the minimum freeform + * gesture width and 1/4 of the diagnal length of the touchpad. Expect to receive + * freeform gestures after two fingers start to move downwards. + */ +TEST_F(MultiTouchPointerModeTest, PointerGestureMaxSwipeWidthFreeform) { + preparePointerMode(25 /*xResolution*/, 25 /*yResolution*/); + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + + NotifyMotionArgs motionArgs; + + // Two fingers down at once. Wider than the max swipe width. + // The gesture is expected to be PRESS, then transformed to FREEFORM + int32_t x1 = 100, y1 = 125, x2 = 900, y2 = 125; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + // One pointer for PRESS, and its coordinate is used as the origin for pointer coordinates. + ASSERT_NO_FATAL_FAILURE( + assertPointerCoords(motionArgs.pointerCoords[0], 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)); + + int32_t movingDistance = 200; + + // Move two fingers down, expect a cancel event because gesture is changing to freeform, + // then two down events for two pointers. + y1 += movingDistance; + y2 += movingDistance; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + // The previous PRESS gesture is cancelled, because it is transformed to freeform + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, motionArgs.action); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(1U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_EQ(2U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_POINTER_DOWN, motionArgs.action & AMOTION_EVENT_ACTION_MASK); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + // Two pointers' scaled relative coordinates from their initial centroid. + // Initial y coordinates are 0 as y1 and y2 have the same value. + float cookedX1 = (x1 - x2) / 2 * mPointerXZoomScale; + float cookedX2 = (x2 - x1) / 2 * mPointerXZoomScale; + // When pointers move, the new coordinates equal to the initial coordinates plus + // scaled moving distance. + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], cookedX1, + movingDistance * mPointerMovementScale, 1, 0, 0, 0, + 0, 0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], cookedX2, + movingDistance * mPointerMovementScale, 1, 0, 0, 0, + 0, 0, 0, 0)); + + // Move two fingers down again, expect one MOVE motion event. + y1 += movingDistance; + y2 += movingDistance; + + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, x1, y1); + processMTSync(mapper); + processId(mapper, SECOND_TRACKING_ID); + processPosition(mapper, x2, y2); + processMTSync(mapper); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(2U, motionArgs.pointerCount); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[0], cookedX1, + movingDistance * 2 * mPointerMovementScale, 1, 0, 0, + 0, 0, 0, 0, 0)); + ASSERT_NO_FATAL_FAILURE(assertPointerCoords(motionArgs.pointerCoords[1], cookedX2, + movingDistance * 2 * mPointerMovementScale, 1, 0, 0, + 0, 0, 0, 0, 0)); +} + // --- JoystickInputMapperTest --- class JoystickInputMapperTest : public InputMapperTest { diff --git a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp index 0062f426d7..8af387174a 100644 --- a/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp +++ b/services/inputflinger/tests/UnwantedInteractionBlocker_test.cpp @@ -47,6 +47,10 @@ constexpr int MOVE = AMOTION_EVENT_ACTION_MOVE; constexpr int UP = AMOTION_EVENT_ACTION_UP; constexpr int CANCEL = AMOTION_EVENT_ACTION_CANCEL; +static nsecs_t toNs(std::chrono::nanoseconds duration) { + return duration.count(); +} + struct PointerData { float x; float y; @@ -384,7 +388,7 @@ TEST(GetTouchesTest, ConvertDownEvent) { expected.reported_tool_type = ::ui::EventPointerType::kTouch; expected.stylus_button = false; - ASSERT_EQ(expected, touches[0]) << toString(touches[0]); + ASSERT_EQ(expected, touches[0]) << touches[0]; } // --- UnwantedInteractionBlockerTest --- @@ -630,41 +634,41 @@ TEST_F(PalmRejectorTestDeathTest, InconsistentEventCausesACrash) { */ TEST_F(PalmRejectorTest, TwoPointersAreCanceled) { std::vector<NotifyMotionArgs> argsList; - constexpr nsecs_t downTime = 255955749837000; + const nsecs_t downTime = toNs(0ms); mPalmRejector->processMotion( generateMotionArgs(downTime, downTime, DOWN, {{1342.0, 613.0, 79.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955759313000, MOVE, {{1406.0, 650.0, 52.0}})); + generateMotionArgs(downTime, toNs(8ms), MOVE, {{1406.0, 650.0, 52.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955766361000, MOVE, {{1429.0, 672.0, 46.0}})); + generateMotionArgs(downTime, toNs(16ms), MOVE, {{1429.0, 672.0, 46.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955775989000, MOVE, {{1417.0, 685.0, 41.0}})); + generateMotionArgs(downTime, toNs(24ms), MOVE, {{1417.0, 685.0, 41.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955775989000, POINTER_1_DOWN, + generateMotionArgs(downTime, toNs(32ms), POINTER_1_DOWN, {{1417.0, 685.0, 41.0}, {1062.0, 697.0, 10.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955783039000, MOVE, + generateMotionArgs(downTime, toNs(40ms), MOVE, {{1414.0, 702.0, 41.0}, {1059.0, 731.0, 12.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955792536000, MOVE, + generateMotionArgs(downTime, toNs(48ms), MOVE, {{1415.0, 719.0, 44.0}, {1060.0, 760.0, 11.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955799474000, MOVE, + generateMotionArgs(downTime, toNs(56ms), MOVE, {{1421.0, 733.0, 42.0}, {1065.0, 769.0, 13.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955809177000, MOVE, + generateMotionArgs(downTime, toNs(64ms), MOVE, {{1426.0, 742.0, 43.0}, {1068.0, 771.0, 13.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955816131000, MOVE, + generateMotionArgs(downTime, toNs(72ms), MOVE, {{1430.0, 748.0, 45.0}, {1069.0, 772.0, 13.0}})); argsList = mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955825907000, MOVE, + generateMotionArgs(downTime, toNs(80ms), MOVE, {{1432.0, 750.0, 44.0}, {1069.0, 772.0, 13.0}})); ASSERT_EQ(1u, argsList.size()); ASSERT_EQ(0 /* No FLAG_CANCELED */, argsList[0].flags); argsList = mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955832736000, MOVE, + generateMotionArgs(downTime, toNs(88ms), MOVE, {{1433.0, 751.0, 44.0}, {1070.0, 771.0, 13.0}})); ASSERT_EQ(2u, argsList.size()); ASSERT_EQ(POINTER_0_UP, argsList[0].action); @@ -674,94 +678,94 @@ TEST_F(PalmRejectorTest, TwoPointersAreCanceled) { ASSERT_EQ(0, argsList[1].flags); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955842432000, MOVE, + generateMotionArgs(downTime, toNs(96ms), MOVE, {{1433.0, 751.0, 42.0}, {1071.0, 770.0, 13.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955849380000, MOVE, + generateMotionArgs(downTime, toNs(104ms), MOVE, {{1433.0, 751.0, 45.0}, {1072.0, 769.0, 13.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955859046000, MOVE, + generateMotionArgs(downTime, toNs(112ms), MOVE, {{1433.0, 751.0, 43.0}, {1072.0, 768.0, 13.0}})); argsList = mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955869823000, MOVE, + generateMotionArgs(downTime, toNs(120ms), MOVE, {{1433.0, 751.0, 45.0}, {1072.0, 767.0, 13.0}})); ASSERT_EQ(1u, argsList.size()); ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, argsList[0].action); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955875641000, MOVE, + generateMotionArgs(downTime, toNs(128ms), MOVE, {{1433.0, 751.0, 43.0}, {1072.0, 766.0, 13.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955882693000, MOVE, + generateMotionArgs(downTime, toNs(136ms), MOVE, {{1433.0, 750.0, 44.0}, {1072.0, 765.0, 13.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955892324000, MOVE, + generateMotionArgs(downTime, toNs(144ms), MOVE, {{1433.0, 750.0, 42.0}, {1072.0, 763.0, 14.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955899425000, MOVE, + generateMotionArgs(downTime, toNs(152ms), MOVE, {{1434.0, 750.0, 44.0}, {1073.0, 761.0, 14.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955909400000, MOVE, + generateMotionArgs(downTime, toNs(160ms), MOVE, {{1435.0, 750.0, 43.0}, {1073.0, 759.0, 15.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955915885000, MOVE, + generateMotionArgs(downTime, toNs(168ms), MOVE, {{1436.0, 750.0, 45.0}, {1074.0, 757.0, 15.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955925607000, MOVE, + generateMotionArgs(downTime, toNs(176ms), MOVE, {{1436.0, 750.0, 44.0}, {1074.0, 755.0, 15.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955932580000, MOVE, + generateMotionArgs(downTime, toNs(184ms), MOVE, {{1436.0, 750.0, 45.0}, {1074.0, 753.0, 15.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955942231000, MOVE, + generateMotionArgs(downTime, toNs(192ms), MOVE, {{1436.0, 749.0, 44.0}, {1074.0, 751.0, 15.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955949204000, MOVE, + generateMotionArgs(downTime, toNs(200ms), MOVE, {{1435.0, 748.0, 45.0}, {1074.0, 749.0, 15.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955959103000, MOVE, + generateMotionArgs(downTime, toNs(208ms), MOVE, {{1434.0, 746.0, 44.0}, {1074.0, 747.0, 14.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955965884000, MOVE, + generateMotionArgs(downTime, toNs(216ms), MOVE, {{1433.0, 744.0, 44.0}, {1075.0, 745.0, 14.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955975649000, MOVE, + generateMotionArgs(downTime, toNs(224ms), MOVE, {{1431.0, 741.0, 43.0}, {1075.0, 742.0, 13.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955982537000, MOVE, + generateMotionArgs(downTime, toNs(232ms), MOVE, {{1428.0, 738.0, 43.0}, {1076.0, 739.0, 12.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955992284000, MOVE, + generateMotionArgs(downTime, toNs(240ms), MOVE, {{1400.0, 726.0, 54.0}, {1076.0, 739.0, 13.0}})); argsList = mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955999348000, POINTER_1_UP, + generateMotionArgs(downTime, toNs(248ms), POINTER_1_UP, {{1362.0, 716.0, 55.0}, {1076.0, 739.0, 13.0}})); ASSERT_TRUE(argsList.empty()); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255955999348000, MOVE, {{1362.0, 716.0, 55.0}})); + generateMotionArgs(downTime, toNs(256ms), MOVE, {{1362.0, 716.0, 55.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255956008885000, MOVE, {{1347.0, 707.0, 54.0}})); + generateMotionArgs(downTime, toNs(264ms), MOVE, {{1347.0, 707.0, 54.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255956015791000, MOVE, {{1340.0, 698.0, 54.0}})); + generateMotionArgs(downTime, toNs(272ms), MOVE, {{1340.0, 698.0, 54.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255956025804000, MOVE, {{1338.0, 694.0, 55.0}})); + generateMotionArgs(downTime, toNs(280ms), MOVE, {{1338.0, 694.0, 55.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255956032314000, MOVE, {{1336.0, 690.0, 53.0}})); + generateMotionArgs(downTime, toNs(288ms), MOVE, {{1336.0, 690.0, 53.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255956042329000, MOVE, {{1334.0, 685.0, 47.0}})); + generateMotionArgs(downTime, toNs(296ms), MOVE, {{1334.0, 685.0, 47.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255956048979000, MOVE, {{1333.0, 679.0, 46.0}})); + generateMotionArgs(downTime, toNs(304ms), MOVE, {{1333.0, 679.0, 46.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255956058813000, MOVE, {{1332.0, 672.0, 45.0}})); + generateMotionArgs(downTime, toNs(312ms), MOVE, {{1332.0, 672.0, 45.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255956065592000, MOVE, {{1333.0, 666.0, 40.0}})); + generateMotionArgs(downTime, toNs(320ms), MOVE, {{1333.0, 666.0, 40.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255956075276000, MOVE, {{1336.0, 661.0, 24.0}})); + generateMotionArgs(downTime, toNs(328ms), MOVE, {{1336.0, 661.0, 24.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255956082198000, MOVE, {{1338.0, 656.0, 16.0}})); + generateMotionArgs(downTime, toNs(336ms), MOVE, {{1338.0, 656.0, 16.0}})); mPalmRejector->processMotion( - generateMotionArgs(downTime, 255956092059000, MOVE, {{1341.0, 649.0, 1.0}})); + generateMotionArgs(downTime, toNs(344ms), MOVE, {{1341.0, 649.0, 1.0}})); argsList = mPalmRejector->processMotion( - generateMotionArgs(downTime, 255956098764000, UP, {{1341.0, 649.0, 1.0}})); + generateMotionArgs(downTime, toNs(352ms), UP, {{1341.0, 649.0, 1.0}})); ASSERT_TRUE(argsList.empty()); } diff --git a/services/stats/Android.bp b/services/stats/Android.bp index 7fea6161ff..7d358e1bd2 100644 --- a/services/stats/Android.bp +++ b/services/stats/Android.bp @@ -13,10 +13,13 @@ cc_library_shared { "StatsAidl.cpp", "StatsHal.cpp", ], - cflags: ["-Wall", "-Werror"], + cflags: [ + "-Wall", + "-Werror", + ], shared_libs: [ "android.frameworks.stats@1.0", - "android.frameworks.stats-V1-ndk", + "android.frameworks.stats-V2-ndk", "libbinder_ndk", "libhidlbase", "liblog", @@ -29,10 +32,12 @@ cc_library_shared { ], export_shared_lib_headers: [ "android.frameworks.stats@1.0", - "android.frameworks.stats-V1-ndk", + "android.frameworks.stats-V2-ndk", ], local_include_dirs: [ "include/stats", ], - vintf_fragments: ["android.frameworks.stats@1.0-service.xml"] + vintf_fragments: [ + "android.frameworks.stats-service.xml", + ], } diff --git a/services/stats/StatsAidl.cpp b/services/stats/StatsAidl.cpp index a3b68f1dab..8d6a9bdb5a 100644 --- a/services/stats/StatsAidl.cpp +++ b/services/stats/StatsAidl.cpp @@ -62,6 +62,10 @@ ndk::ScopedAStatus StatsHal::reportVendorAtom(const VendorAtom& vendorAtom) { AStatsEvent_writeString(event, atomValue.get<VendorAtomValue::stringValue>().c_str()); break; + case VendorAtomValue::boolValue: + AStatsEvent_writeBool(event, + atomValue.get<VendorAtomValue::boolValue>()); + break; } } AStatsEvent_build(event); diff --git a/services/stats/android.frameworks.stats@1.0-service.xml b/services/stats/android.frameworks.stats-service.xml index c564b7be53..7e2635e406 100644 --- a/services/stats/android.frameworks.stats@1.0-service.xml +++ b/services/stats/android.frameworks.stats-service.xml @@ -11,7 +11,7 @@ <hal format="aidl"> <name>android.frameworks.stats</name> - <version>1</version> + <version>2</version> <fqname>IStats/default</fqname> </hal> </manifest> diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index cbb95f963c..f1457bfffe 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -141,9 +141,6 @@ filegroup { name: "libsurfaceflinger_sources", srcs: [ "BackgroundExecutor.cpp", - "BufferLayer.cpp", - "BufferLayerConsumer.cpp", - "BufferQueueLayer.cpp", "BufferStateLayer.cpp", "ClientCache.cpp", "Client.cpp", @@ -169,10 +166,8 @@ filegroup { "WindowInfosListenerInvoker.cpp", "Layer.cpp", "LayerProtoHelper.cpp", - "LayerRejecter.cpp", "LayerRenderArea.cpp", "LayerVector.cpp", - "MonitoredProducer.cpp", "NativeWindowSurface.cpp", "RefreshRateOverlay.cpp", "RegionSamplingThread.cpp", diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp deleted file mode 100644 index d9c89cd821..0000000000 --- a/services/surfaceflinger/BufferLayer.cpp +++ /dev/null @@ -1,814 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - -//#define LOG_NDEBUG 0 -#undef LOG_TAG -#define LOG_TAG "BufferLayer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS - -#include "BufferLayer.h" - -#include <compositionengine/CompositionEngine.h> -#include <compositionengine/LayerFECompositionState.h> -#include <compositionengine/OutputLayer.h> -#include <compositionengine/impl/OutputLayerCompositionState.h> -#include <cutils/compiler.h> -#include <cutils/native_handle.h> -#include <cutils/properties.h> -#include <gui/BufferItem.h> -#include <gui/BufferQueue.h> -#include <gui/GLConsumer.h> -#include <gui/LayerDebugInfo.h> -#include <gui/Surface.h> -#include <renderengine/RenderEngine.h> -#include <ui/DebugUtils.h> -#include <utils/Errors.h> -#include <utils/Log.h> -#include <utils/NativeHandle.h> -#include <utils/StopWatch.h> -#include <utils/Trace.h> - -#include <cmath> -#include <cstdlib> -#include <mutex> -#include <sstream> - -#include "Colorizer.h" -#include "DisplayDevice.h" -#include "FrameTracer/FrameTracer.h" -#include "LayerRejecter.h" -#include "TimeStats/TimeStats.h" - -namespace android { - -using gui::WindowInfo; - -static constexpr float defaultMaxLuminance = 1000.0; - -BufferLayer::BufferLayer(const LayerCreationArgs& args) - : Layer(args), - mTextureName(args.textureName), - mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()} { - ALOGV("Creating Layer %s", getDebugName()); - - mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied); - - mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow; - mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp; -} - -BufferLayer::~BufferLayer() { - if (!isClone()) { - // The original layer and the clone layer share the same texture. Therefore, only one of - // the layers, in this case the original layer, needs to handle the deletion. The original - // layer and the clone should be removed at the same time so there shouldn't be any issue - // with the clone layer trying to use the deleted texture. - mFlinger->deleteTextureAsync(mTextureName); - } - const int32_t layerId = getSequence(); - mFlinger->mTimeStats->onDestroy(layerId); - mFlinger->mFrameTracer->onDestroy(layerId); -} - -void BufferLayer::useSurfaceDamage() { - if (mFlinger->mForceFullDamage) { - surfaceDamageRegion = Region::INVALID_REGION; - } else { - surfaceDamageRegion = mBufferInfo.mSurfaceDamage; - } -} - -void BufferLayer::useEmptyDamage() { - surfaceDamageRegion.clear(); -} - -bool BufferLayer::isOpaque(const Layer::State& s) const { - // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the - // layer's opaque flag. - if ((mSidebandStream == nullptr) && (mBufferInfo.mBuffer == nullptr)) { - return false; - } - - // if the layer has the opaque flag, then we're always opaque, - // otherwise we use the current buffer's format. - return ((s.flags & layer_state_t::eLayerOpaque) != 0) || getOpacityForFormat(getPixelFormat()); -} - -bool BufferLayer::canReceiveInput() const { - return !isHiddenByPolicy() && (mBufferInfo.mBuffer == nullptr || getAlpha() > 0.0f); -} - -bool BufferLayer::isVisible() const { - return !isHiddenByPolicy() && getAlpha() > 0.0f && - (mBufferInfo.mBuffer != nullptr || mSidebandStream != nullptr); -} - -bool BufferLayer::isFixedSize() const { - return getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE; -} - -bool BufferLayer::usesSourceCrop() const { - return true; -} - -static constexpr mat4 inverseOrientation(uint32_t transform) { - const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); - const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1); - const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); - mat4 tr; - - if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { - tr = tr * rot90; - } - if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { - tr = tr * flipH; - } - if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { - tr = tr * flipV; - } - return inverse(tr); -} - -std::optional<compositionengine::LayerFE::LayerSettings> BufferLayer::prepareClientComposition( - compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { - ATRACE_CALL(); - - std::optional<compositionengine::LayerFE::LayerSettings> result = - Layer::prepareClientComposition(targetSettings); - if (!result) { - return result; - } - - if (CC_UNLIKELY(mBufferInfo.mBuffer == 0) && mSidebandStream != nullptr) { - // For surfaceview of tv sideband, there is no activeBuffer - // in bufferqueue, we need return LayerSettings. - return result; - } - const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) || - ((isSecure() || isProtected()) && !targetSettings.isSecure); - const bool bufferCanBeUsedAsHwTexture = - mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; - compositionengine::LayerFE::LayerSettings& layer = *result; - if (blackOutLayer || !bufferCanBeUsedAsHwTexture) { - ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable", - mName.c_str()); - prepareClearClientComposition(layer, true /* blackout */); - return layer; - } - - const State& s(getDrawingState()); - layer.source.buffer.buffer = mBufferInfo.mBuffer; - layer.source.buffer.isOpaque = isOpaque(s); - layer.source.buffer.fence = mBufferInfo.mFence; - layer.source.buffer.textureName = mTextureName; - layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha(); - layer.source.buffer.isY410BT2020 = isHdrY410(); - bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086; - bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3; - float maxLuminance = 0.f; - if (hasSmpte2086 && hasCta861_3) { - maxLuminance = std::min(mBufferInfo.mHdrMetadata.smpte2086.maxLuminance, - mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel); - } else if (hasSmpte2086) { - maxLuminance = mBufferInfo.mHdrMetadata.smpte2086.maxLuminance; - } else if (hasCta861_3) { - maxLuminance = mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel; - } else { - switch (layer.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) { - case HAL_DATASPACE_TRANSFER_ST2084: - case HAL_DATASPACE_TRANSFER_HLG: - // Behavior-match previous releases for HDR content - maxLuminance = defaultMaxLuminance; - break; - } - } - layer.source.buffer.maxLuminanceNits = maxLuminance; - layer.frameNumber = mCurrentFrameNumber; - layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0; - - const bool useFiltering = - targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering(); - - // Query the texture matrix given our current filtering mode. - float textureMatrix[16]; - getDrawingTransformMatrix(useFiltering, textureMatrix); - - if (getTransformToDisplayInverse()) { - /* - * the code below applies the primary display's inverse transform to - * the texture transform - */ - uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags(); - mat4 tr = inverseOrientation(transform); - - /** - * TODO(b/36727915): This is basically a hack. - * - * Ensure that regardless of the parent transformation, - * this buffer is always transformed from native display - * orientation to display orientation. For example, in the case - * of a camera where the buffer remains in native orientation, - * we want the pixels to always be upright. - */ - sp<Layer> p = mDrawingParent.promote(); - if (p != nullptr) { - const auto parentTransform = p->getTransform(); - tr = tr * inverseOrientation(parentTransform.getOrientation()); - } - - // and finally apply it to the original texture matrix - const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr); - memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix)); - } - - const Rect win{getBounds()}; - float bufferWidth = getBufferSize(s).getWidth(); - float bufferHeight = getBufferSize(s).getHeight(); - - // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has - // been set and there is no parent layer bounds. In that case, the scale is meaningless so - // ignore them. - if (!getBufferSize(s).isValid()) { - bufferWidth = float(win.right) - float(win.left); - bufferHeight = float(win.bottom) - float(win.top); - } - - const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight; - const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth; - const float translateY = float(win.top) / bufferHeight; - const float translateX = float(win.left) / bufferWidth; - - // Flip y-coordinates because GLConsumer expects OpenGL convention. - mat4 tr = mat4::translate(vec4(.5, .5, 0, 1)) * mat4::scale(vec4(1, -1, 1, 1)) * - mat4::translate(vec4(-.5, -.5, 0, 1)) * - mat4::translate(vec4(translateX, translateY, 0, 1)) * - mat4::scale(vec4(scaleWidth, scaleHeight, 1.0, 1.0)); - - layer.source.buffer.useTextureFiltering = useFiltering; - layer.source.buffer.textureTransform = mat4(static_cast<const float*>(textureMatrix)) * tr; - - return layer; -} - -bool BufferLayer::isHdrY410() const { - // pixel format is HDR Y410 masquerading as RGBA_1010102 - return (mBufferInfo.mDataspace == ui::Dataspace::BT2020_ITU_PQ && - mBufferInfo.mApi == NATIVE_WINDOW_API_MEDIA && - mBufferInfo.mPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102); -} - -sp<compositionengine::LayerFE> BufferLayer::getCompositionEngineLayerFE() const { - return asLayerFE(); -} - -compositionengine::LayerFECompositionState* BufferLayer::editCompositionState() { - return mCompositionState.get(); -} - -const compositionengine::LayerFECompositionState* BufferLayer::getCompositionState() const { - return mCompositionState.get(); -} - -void BufferLayer::preparePerFrameCompositionState() { - Layer::preparePerFrameCompositionState(); - - // Sideband layers - auto* compositionState = editCompositionState(); - if (compositionState->sidebandStream.get() && !compositionState->sidebandStreamHasFrame) { - compositionState->compositionType = - aidl::android::hardware::graphics::composer3::Composition::SIDEBAND; - return; - } else if ((mDrawingState.flags & layer_state_t::eLayerIsDisplayDecoration) != 0) { - compositionState->compositionType = - aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION; - } else { - // Normal buffer layers - compositionState->hdrMetadata = mBufferInfo.mHdrMetadata; - compositionState->compositionType = mPotentialCursor - ? aidl::android::hardware::graphics::composer3::Composition::CURSOR - : aidl::android::hardware::graphics::composer3::Composition::DEVICE; - } - - compositionState->buffer = getBuffer(); - compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) - ? 0 - : mBufferInfo.mBufferSlot; - compositionState->acquireFence = mBufferInfo.mFence; - compositionState->frameNumber = mBufferInfo.mFrameNumber; - compositionState->sidebandStreamHasFrame = false; -} - -bool BufferLayer::onPreComposition(nsecs_t) { - return hasReadyFrame(); -} -namespace { -TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) { - using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility; - using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness; - const auto frameRateCompatibility = [frameRate] { - switch (frameRate.type) { - case Layer::FrameRateCompatibility::Default: - return FrameRateCompatibility::Default; - case Layer::FrameRateCompatibility::ExactOrMultiple: - return FrameRateCompatibility::ExactOrMultiple; - default: - return FrameRateCompatibility::Undefined; - } - }(); - - const auto seamlessness = [frameRate] { - switch (frameRate.seamlessness) { - case scheduler::Seamlessness::OnlySeamless: - return Seamlessness::ShouldBeSeamless; - case scheduler::Seamlessness::SeamedAndSeamless: - return Seamlessness::NotRequired; - default: - return Seamlessness::Undefined; - } - }(); - - return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(), - .frameRateCompatibility = frameRateCompatibility, - .seamlessness = seamlessness}; -} -} // namespace - -void BufferLayer::onPostComposition(const DisplayDevice* display, - const std::shared_ptr<FenceTime>& glDoneFence, - const std::shared_ptr<FenceTime>& presentFence, - const CompositorTiming& compositorTiming) { - // mFrameLatencyNeeded is true when a new frame was latched for the - // composition. - if (!mBufferInfo.mFrameLatencyNeeded) return; - - // Update mFrameEventHistory. - finalizeFrameEventHistory(glDoneFence, compositorTiming); - - // Update mFrameTracker. - nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime; - mFrameTracker.setDesiredPresentTime(desiredPresentTime); - - const int32_t layerId = getSequence(); - mFlinger->mTimeStats->setDesiredTime(layerId, mCurrentFrameNumber, desiredPresentTime); - - const auto outputLayer = findOutputLayerForDisplay(display); - if (outputLayer && outputLayer->requiresClientComposition()) { - nsecs_t clientCompositionTimestamp = outputLayer->getState().clientCompositionTimestamp; - mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, - clientCompositionTimestamp, - FrameTracer::FrameEvent::FALLBACK_COMPOSITION); - // Update the SurfaceFrames in the drawing state - if (mDrawingState.bufferSurfaceFrameTX) { - mDrawingState.bufferSurfaceFrameTX->setGpuComposition(); - } - for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) { - surfaceFrame->setGpuComposition(); - } - } - - std::shared_ptr<FenceTime> frameReadyFence = mBufferInfo.mFenceTime; - if (frameReadyFence->isValid()) { - mFrameTracker.setFrameReadyFence(std::move(frameReadyFence)); - } else { - // There was no fence for this frame, so assume that it was ready - // to be presented at the desired present time. - mFrameTracker.setFrameReadyTime(desiredPresentTime); - } - - if (display) { - const Fps refreshRate = display->refreshRateConfigs().getActiveMode()->getFps(); - const std::optional<Fps> renderRate = - mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); - - const auto vote = frameRateToSetFrameRateVotePayload(mDrawingState.frameRate); - const auto gameMode = getGameMode(); - - if (presentFence->isValid()) { - mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence, - refreshRate, renderRate, vote, gameMode); - mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber, - presentFence, - FrameTracer::FrameEvent::PRESENT_FENCE); - mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence)); - } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId()); - displayId && mFlinger->getHwComposer().isConnected(*displayId)) { - // The HWC doesn't support present fences, so use the refresh - // timestamp instead. - const nsecs_t actualPresentTime = display->getRefreshTimestamp(); - mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime, - refreshRate, renderRate, vote, gameMode); - mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), - mCurrentFrameNumber, actualPresentTime, - FrameTracer::FrameEvent::PRESENT_FENCE); - mFrameTracker.setActualPresentTime(actualPresentTime); - } - } - - mFrameTracker.advanceFrame(); - mBufferInfo.mFrameLatencyNeeded = false; -} - -void BufferLayer::gatherBufferInfo() { - mBufferInfo.mPixelFormat = - !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getPixelFormat(); - mBufferInfo.mFrameLatencyNeeded = true; -} - -bool BufferLayer::shouldPresentNow(nsecs_t expectedPresentTime) const { - // If this is not a valid vsync for the layer's uid, return and try again later - const bool isVsyncValidForUid = - mFlinger->mScheduler->isVsyncValid(expectedPresentTime, mOwnerUid); - if (!isVsyncValidForUid) { - ATRACE_NAME("!isVsyncValidForUid"); - return false; - } - - // AutoRefresh layers and sideband streams should always be presented - if (getSidebandStreamChanged() || getAutoRefresh()) { - return true; - } - - // If this layer doesn't have a frame is shouldn't be presented - if (!hasFrameUpdate()) { - return false; - } - - // Defer to the derived class to decide whether the next buffer is due for - // presentation. - return isBufferDue(expectedPresentTime); -} - -bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, - nsecs_t expectedPresentTime) { - ATRACE_CALL(); - - bool refreshRequired = latchSidebandStream(recomputeVisibleRegions); - - if (refreshRequired) { - return refreshRequired; - } - - // If the head buffer's acquire fence hasn't signaled yet, return and - // try again later - if (!fenceHasSignaled()) { - ATRACE_NAME("!fenceHasSignaled()"); - mFlinger->onLayerUpdate(); - return false; - } - - // Capture the old state of the layer for comparisons later - const State& s(getDrawingState()); - const bool oldOpacity = isOpaque(s); - - BufferInfo oldBufferInfo = mBufferInfo; - - status_t err = updateTexImage(recomputeVisibleRegions, latchTime, expectedPresentTime); - if (err != NO_ERROR) { - return false; - } - - err = updateActiveBuffer(); - if (err != NO_ERROR) { - return false; - } - - err = updateFrameNumber(); - if (err != NO_ERROR) { - return false; - } - - gatherBufferInfo(); - - if (oldBufferInfo.mBuffer == nullptr) { - // the first time we receive a buffer, we need to trigger a - // geometry invalidation. - recomputeVisibleRegions = true; - } - - if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) || - (mBufferInfo.mTransform != oldBufferInfo.mTransform) || - (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) || - (mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) { - recomputeVisibleRegions = true; - } - - if (oldBufferInfo.mBuffer != nullptr) { - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); - if (bufWidth != oldBufferInfo.mBuffer->getWidth() || - bufHeight != oldBufferInfo.mBuffer->getHeight()) { - recomputeVisibleRegions = true; - } - } - - if (oldOpacity != isOpaque(s)) { - recomputeVisibleRegions = true; - } - - return true; -} - -bool BufferLayer::hasReadyFrame() const { - return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh(); -} - -uint32_t BufferLayer::getEffectiveScalingMode() const { - return mBufferInfo.mScaleMode; -} - -bool BufferLayer::isProtected() const { - return (mBufferInfo.mBuffer != nullptr) && - (mBufferInfo.mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED); -} - -// As documented in libhardware header, formats in the range -// 0x100 - 0x1FF are specific to the HAL implementation, and -// are known to have no alpha channel -// TODO: move definition for device-specific range into -// hardware.h, instead of using hard-coded values here. -#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF) - -bool BufferLayer::getOpacityForFormat(PixelFormat format) { - if (HARDWARE_IS_DEVICE_FORMAT(format)) { - return true; - } - switch (format) { - case PIXEL_FORMAT_RGBA_8888: - case PIXEL_FORMAT_BGRA_8888: - case PIXEL_FORMAT_RGBA_FP16: - case PIXEL_FORMAT_RGBA_1010102: - case PIXEL_FORMAT_R_8: - return false; - } - // in all other case, we have no blending (also for unknown formats) - return true; -} - -bool BufferLayer::needsFiltering(const DisplayDevice* display) const { - const auto outputLayer = findOutputLayerForDisplay(display); - if (outputLayer == nullptr) { - return false; - } - - // We need filtering if the sourceCrop rectangle size does not match the - // displayframe rectangle size (not a 1:1 render) - const auto& compositionState = outputLayer->getState(); - const auto displayFrame = compositionState.displayFrame; - const auto sourceCrop = compositionState.sourceCrop; - return sourceCrop.getHeight() != displayFrame.getHeight() || - sourceCrop.getWidth() != displayFrame.getWidth(); -} - -bool BufferLayer::needsFilteringForScreenshots(const DisplayDevice* display, - const ui::Transform& inverseParentTransform) const { - const auto outputLayer = findOutputLayerForDisplay(display); - if (outputLayer == nullptr) { - return false; - } - - // We need filtering if the sourceCrop rectangle size does not match the - // viewport rectangle size (not a 1:1 render) - const auto& compositionState = outputLayer->getState(); - const ui::Transform& displayTransform = display->getTransform(); - const ui::Transform inverseTransform = inverseParentTransform * displayTransform.inverse(); - // Undo the transformation of the displayFrame so that we're back into - // layer-stack space. - const Rect frame = inverseTransform.transform(compositionState.displayFrame); - const FloatRect sourceCrop = compositionState.sourceCrop; - - int32_t frameHeight = frame.getHeight(); - int32_t frameWidth = frame.getWidth(); - // If the display transform had a rotational component then undo the - // rotation so that the orientation matches the source crop. - if (displayTransform.getOrientation() & ui::Transform::ROT_90) { - std::swap(frameHeight, frameWidth); - } - return sourceCrop.getHeight() != frameHeight || sourceCrop.getWidth() != frameWidth; -} - -Rect BufferLayer::getBufferSize(const State& s) const { - // If we have a sideband stream, or we are scaling the buffer then return the layer size since - // we cannot determine the buffer size. - if ((s.sidebandStream != nullptr) || - (getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE)) { - return Rect(getActiveWidth(s), getActiveHeight(s)); - } - - if (mBufferInfo.mBuffer == nullptr) { - return Rect::INVALID_RECT; - } - - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); - - // Undo any transformations on the buffer and return the result. - if (mBufferInfo.mTransform & ui::Transform::ROT_90) { - std::swap(bufWidth, bufHeight); - } - - if (getTransformToDisplayInverse()) { - uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); - if (invTransform & ui::Transform::ROT_90) { - std::swap(bufWidth, bufHeight); - } - } - - return Rect(bufWidth, bufHeight); -} - -FloatRect BufferLayer::computeSourceBounds(const FloatRect& parentBounds) const { - const State& s(getDrawingState()); - - // If we have a sideband stream, or we are scaling the buffer then return the layer size since - // we cannot determine the buffer size. - if ((s.sidebandStream != nullptr) || - (getEffectiveScalingMode() != NATIVE_WINDOW_SCALING_MODE_FREEZE)) { - return FloatRect(0, 0, getActiveWidth(s), getActiveHeight(s)); - } - - if (mBufferInfo.mBuffer == nullptr) { - return parentBounds; - } - - uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); - uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); - - // Undo any transformations on the buffer and return the result. - if (mBufferInfo.mTransform & ui::Transform::ROT_90) { - std::swap(bufWidth, bufHeight); - } - - if (getTransformToDisplayInverse()) { - uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); - if (invTransform & ui::Transform::ROT_90) { - std::swap(bufWidth, bufHeight); - } - } - - return FloatRect(0, 0, bufWidth, bufHeight); -} - -void BufferLayer::latchAndReleaseBuffer() { - if (hasReadyFrame()) { - bool ignored = false; - latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */); - } - releasePendingBuffer(systemTime()); -} - -PixelFormat BufferLayer::getPixelFormat() const { - return mBufferInfo.mPixelFormat; -} - -bool BufferLayer::getTransformToDisplayInverse() const { - return mBufferInfo.mTransformToDisplayInverse; -} - -Rect BufferLayer::getBufferCrop() const { - // this is the crop rectangle that applies to the buffer - // itself (as opposed to the window) - if (!mBufferInfo.mCrop.isEmpty()) { - // if the buffer crop is defined, we use that - return mBufferInfo.mCrop; - } else if (mBufferInfo.mBuffer != nullptr) { - // otherwise we use the whole buffer - return mBufferInfo.mBuffer->getBounds(); - } else { - // if we don't have a buffer yet, we use an empty/invalid crop - return Rect(); - } -} - -uint32_t BufferLayer::getBufferTransform() const { - return mBufferInfo.mTransform; -} - -ui::Dataspace BufferLayer::getDataSpace() const { - return mBufferInfo.mDataspace; -} - -ui::Dataspace BufferLayer::translateDataspace(ui::Dataspace dataspace) { - ui::Dataspace updatedDataspace = dataspace; - // translate legacy dataspaces to modern dataspaces - switch (dataspace) { - case ui::Dataspace::SRGB: - updatedDataspace = ui::Dataspace::V0_SRGB; - break; - case ui::Dataspace::SRGB_LINEAR: - updatedDataspace = ui::Dataspace::V0_SRGB_LINEAR; - break; - case ui::Dataspace::JFIF: - updatedDataspace = ui::Dataspace::V0_JFIF; - break; - case ui::Dataspace::BT601_625: - updatedDataspace = ui::Dataspace::V0_BT601_625; - break; - case ui::Dataspace::BT601_525: - updatedDataspace = ui::Dataspace::V0_BT601_525; - break; - case ui::Dataspace::BT709: - updatedDataspace = ui::Dataspace::V0_BT709; - break; - default: - break; - } - - return updatedDataspace; -} - -sp<GraphicBuffer> BufferLayer::getBuffer() const { - return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr; -} - -void BufferLayer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) { - GLConsumer::computeTransformMatrix(outMatrix, - mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() - : nullptr, - mBufferInfo.mCrop, mBufferInfo.mTransform, filteringEnabled); -} - -void BufferLayer::setInitialValuesForClone(const sp<Layer>& clonedFrom) { - Layer::setInitialValuesForClone(clonedFrom); - - sp<BufferLayer> bufferClonedFrom = static_cast<BufferLayer*>(clonedFrom.get()); - mPremultipliedAlpha = bufferClonedFrom->mPremultipliedAlpha; - mPotentialCursor = bufferClonedFrom->mPotentialCursor; - mProtectedByApp = bufferClonedFrom->mProtectedByApp; - - updateCloneBufferInfo(); -} - -void BufferLayer::updateCloneBufferInfo() { - if (!isClone() || !isClonedFromAlive()) { - return; - } - - sp<BufferLayer> clonedFrom = static_cast<BufferLayer*>(getClonedFrom().get()); - mBufferInfo = clonedFrom->mBufferInfo; - mSidebandStream = clonedFrom->mSidebandStream; - surfaceDamageRegion = clonedFrom->surfaceDamageRegion; - mCurrentFrameNumber = clonedFrom->mCurrentFrameNumber.load(); - mPreviousFrameNumber = clonedFrom->mPreviousFrameNumber; - - // After buffer info is updated, the drawingState from the real layer needs to be copied into - // the cloned. This is because some properties of drawingState can change when latchBuffer is - // called. However, copying the drawingState would also overwrite the cloned layer's relatives - // and touchableRegionCrop. Therefore, temporarily store the relatives so they can be set in - // the cloned drawingState again. - wp<Layer> tmpZOrderRelativeOf = mDrawingState.zOrderRelativeOf; - SortedVector<wp<Layer>> tmpZOrderRelatives = mDrawingState.zOrderRelatives; - wp<Layer> tmpTouchableRegionCrop = mDrawingState.touchableRegionCrop; - WindowInfo tmpInputInfo = mDrawingState.inputInfo; - - cloneDrawingState(clonedFrom.get()); - - mDrawingState.touchableRegionCrop = tmpTouchableRegionCrop; - mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf; - mDrawingState.zOrderRelatives = tmpZOrderRelatives; - mDrawingState.inputInfo = tmpInputInfo; -} - -void BufferLayer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) { - mTransformHint = getFixedTransformHint(); - if (mTransformHint == ui::Transform::ROT_INVALID) { - mTransformHint = displayTransformHint; - } -} - -bool BufferLayer::bufferNeedsFiltering() const { - return isFixedSize(); -} - -const std::shared_ptr<renderengine::ExternalTexture>& BufferLayer::getExternalTexture() const { - return mBufferInfo.mBuffer; -} - -} // namespace android - -#if defined(__gl_h_) -#error "don't include gl/gl.h in this file" -#endif - -#if defined(__gl2_h_) -#error "don't include gl2/gl2.h in this file" -#endif - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h deleted file mode 100644 index 4c70eb58bf..0000000000 --- a/services/surfaceflinger/BufferLayer.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (C) 2017 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 <sys/types.h> -#include <cstdint> -#include <list> - -#include <gui/ISurfaceComposerClient.h> -#include <gui/LayerState.h> -#include <renderengine/Image.h> -#include <renderengine/Mesh.h> -#include <renderengine/Texture.h> -#include <system/window.h> // For NATIVE_WINDOW_SCALING_MODE_FREEZE -#include <ui/FrameStats.h> -#include <ui/GraphicBuffer.h> -#include <ui/PixelFormat.h> -#include <ui/Region.h> -#include <utils/RefBase.h> -#include <utils/String8.h> -#include <utils/Timers.h> - -#include "BufferLayerConsumer.h" -#include "Client.h" -#include "DisplayHardware/HWComposer.h" -#include "FrameTimeline.h" -#include "FrameTracker.h" -#include "Layer.h" -#include "LayerVector.h" -#include "MonitoredProducer.h" -#include "SurfaceFlinger.h" - -namespace android { - -class BufferLayer : public Layer { -public: - explicit BufferLayer(const LayerCreationArgs& args); - virtual ~BufferLayer() override; - - // Implements Layer. - sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const override; - compositionengine::LayerFECompositionState* editCompositionState() override; - - // If we have received a new buffer this frame, we will pass its surface - // damage down to hardware composer. Otherwise, we must send a region with - // one empty rect. - void useSurfaceDamage() override; - void useEmptyDamage() override; - - bool isOpaque(const Layer::State& s) const override; - bool canReceiveInput() const override; - - // isVisible - true if this layer is visible, false otherwise - bool isVisible() const override; - - // isProtected - true if the layer may contain protected content in the - // GRALLOC_USAGE_PROTECTED sense. - bool isProtected() const override; - - // isFixedSize - true if content has a fixed size - bool isFixedSize() const override; - - bool usesSourceCrop() const override; - - bool isHdrY410() const override; - - void onPostComposition(const DisplayDevice*, const std::shared_ptr<FenceTime>& glDoneFence, - const std::shared_ptr<FenceTime>& presentFence, - const CompositorTiming&) override; - - // latchBuffer - called each time the screen is redrawn and returns whether - // the visible regions need to be recomputed (this is a fairly heavy - // operation, so this should be set only if needed). Typically this is used - // to figure out if the content or size of a surface has changed. - bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, - nsecs_t expectedPresentTime) override; - bool hasReadyFrame() const override; - - // Returns the current scaling mode - uint32_t getEffectiveScalingMode() const override; - - // Calls latchBuffer if the buffer has a frame queued and then releases the buffer. - // This is used if the buffer is just latched and releases to free up the buffer - // and will not be shown on screen. - // Should only be called on the main thread. - void latchAndReleaseBuffer() override; - - bool getTransformToDisplayInverse() const override; - - Rect getBufferCrop() const override; - - uint32_t getBufferTransform() const override; - - ui::Dataspace getDataSpace() const override; - - sp<GraphicBuffer> getBuffer() const override; - const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const override; - - ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; } - - // Returns true if the transformed buffer size does not match the layer size and we need - // to apply filtering. - virtual bool bufferNeedsFiltering() const; - -protected: - struct BufferInfo { - nsecs_t mDesiredPresentTime; - std::shared_ptr<FenceTime> mFenceTime; - sp<Fence> mFence; - uint32_t mTransform{0}; - ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN}; - Rect mCrop; - uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE}; - Region mSurfaceDamage; - HdrMetadata mHdrMetadata; - int mApi; - PixelFormat mPixelFormat{PIXEL_FORMAT_NONE}; - bool mTransformToDisplayInverse{false}; - - std::shared_ptr<renderengine::ExternalTexture> mBuffer; - uint64_t mFrameNumber; - int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT}; - - bool mFrameLatencyNeeded{false}; - }; - - BufferInfo mBufferInfo; - virtual void gatherBufferInfo() = 0; - - std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition( - compositionengine::LayerFE::ClientCompositionTargetSettings&) override; - - /* - * compositionengine::LayerFE overrides - */ - const compositionengine::LayerFECompositionState* getCompositionState() const override; - bool onPreComposition(nsecs_t) override; - void preparePerFrameCompositionState() override; - - static bool getOpacityForFormat(PixelFormat format); - - // from graphics API - const uint32_t mTextureName; - ui::Dataspace translateDataspace(ui::Dataspace dataspace); - void setInitialValuesForClone(const sp<Layer>& clonedFrom); - void updateCloneBufferInfo() override; - uint64_t mPreviousFrameNumber = 0; - - void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override; - - // Transform hint provided to the producer. This must be accessed holding - // the mStateLock. - ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0; - - bool getAutoRefresh() const { return mDrawingState.autoRefresh; } - bool getSidebandStreamChanged() const { return mSidebandStreamChanged; } - - // Returns true if the next buffer should be presented at the expected present time - bool shouldPresentNow(nsecs_t expectedPresentTime) const; - - // Returns true if the next buffer should be presented at the expected present time, - // overridden by BufferStateLayer and BufferQueueLayer for implementation - // specific logic - virtual bool isBufferDue(nsecs_t /*expectedPresentTime*/) const = 0; - - std::atomic<bool> mSidebandStreamChanged{false}; - -private: - virtual bool fenceHasSignaled() const = 0; - virtual bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const = 0; - - // Latch sideband stream and returns true if the dirty region should be updated. - virtual bool latchSidebandStream(bool& recomputeVisibleRegions) = 0; - - virtual bool hasFrameUpdate() const = 0; - - virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, - nsecs_t expectedPresentTime) = 0; - - virtual status_t updateActiveBuffer() = 0; - virtual status_t updateFrameNumber() = 0; - - // We generate InputWindowHandles for all non-cursor buffered layers regardless of whether they - // have an InputChannel. This is to enable the InputDispatcher to do PID based occlusion - // detection. - bool needsInputInfo() const override { return !mPotentialCursor; } - - // Returns true if this layer requires filtering - bool needsFiltering(const DisplayDevice*) const override; - bool needsFilteringForScreenshots(const DisplayDevice*, - const ui::Transform& inverseParentTransform) const override; - - // BufferStateLayers can return Rect::INVALID_RECT if the layer does not have a display frame - // and its parent layer is not bounded - Rect getBufferSize(const State& s) const override; - - PixelFormat getPixelFormat() const; - - // Computes the transform matrix using the setFilteringEnabled to determine whether the - // transform matrix should be computed for use with bilinear filtering. - void getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]); - - std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState; - - FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; -}; - -} // namespace android diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp deleted file mode 100644 index 7361a4fdef..0000000000 --- a/services/surfaceflinger/BufferLayerConsumer.cpp +++ /dev/null @@ -1,500 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - -#undef LOG_TAG -#define LOG_TAG "BufferLayerConsumer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#include "BufferLayerConsumer.h" -#include "Layer.h" -#include "Scheduler/VsyncController.h" - -#include <inttypes.h> - -#include <cutils/compiler.h> - -#include <hardware/hardware.h> - -#include <math/mat4.h> - -#include <gui/BufferItem.h> -#include <gui/GLConsumer.h> -#include <gui/ISurfaceComposer.h> -#include <gui/SurfaceComposerClient.h> -#include <private/gui/ComposerService.h> -#include <renderengine/RenderEngine.h> -#include <renderengine/impl/ExternalTexture.h> -#include <utils/Log.h> -#include <utils/String8.h> -#include <utils/Trace.h> - -namespace android { - -// Macros for including the BufferLayerConsumer name in log messages -#define BLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) -#define BLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) -//#define BLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__) -#define BLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) -#define BLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) - -static const mat4 mtxIdentity; - -BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, - renderengine::RenderEngine& engine, uint32_t tex, - Layer* layer) - : ConsumerBase(bq, false), - mCurrentCrop(Rect::EMPTY_RECT), - mCurrentTransform(0), - mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mCurrentFence(Fence::NO_FENCE), - mCurrentTimestamp(0), - mCurrentDataSpace(ui::Dataspace::UNKNOWN), - mCurrentFrameNumber(0), - mCurrentTransformToDisplayInverse(false), - mCurrentSurfaceDamage(), - mCurrentApi(0), - mDefaultWidth(1), - mDefaultHeight(1), - mFilteringEnabled(true), - mRE(engine), - mTexName(tex), - mLayer(layer), - mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) { - BLC_LOGV("BufferLayerConsumer"); - - memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); - - mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); -} - -status_t BufferLayerConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - BLC_LOGE("setDefaultBufferSize: BufferLayerConsumer is abandoned!"); - return NO_INIT; - } - mDefaultWidth = w; - mDefaultHeight = h; - return mConsumer->setDefaultBufferSize(w, h); -} - -void BufferLayerConsumer::setContentsChangedListener(const wp<ContentsChangedListener>& listener) { - setFrameAvailableListener(listener); - Mutex::Autolock lock(mMutex); - mContentsChangedListener = listener; -} - -status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime, - bool* autoRefresh, bool* queuedBuffer, - uint64_t maxFrameNumber) { - ATRACE_CALL(); - BLC_LOGV("updateTexImage"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - BLC_LOGE("updateTexImage: BufferLayerConsumer is abandoned!"); - return NO_INIT; - } - - BufferItem item; - - // Acquire the next buffer. - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - status_t err = acquireBufferLocked(&item, expectedPresentTime, maxFrameNumber); - if (err != NO_ERROR) { - if (err == BufferQueue::NO_BUFFER_AVAILABLE) { - err = NO_ERROR; - } else if (err == BufferQueue::PRESENT_LATER) { - // return the error, without logging - } else { - BLC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err); - } - return err; - } - - if (autoRefresh) { - *autoRefresh = item.mAutoRefresh; - } - - if (queuedBuffer) { - *queuedBuffer = item.mQueuedBuffer; - } - - // We call the rejecter here, in case the caller has a reason to - // not accept this buffer. This is used by SurfaceFlinger to - // reject buffers which have the wrong size - int slot = item.mSlot; - if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) { - releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer); - return BUFFER_REJECTED; - } - - // Release the previous buffer. - err = updateAndReleaseLocked(item, &mPendingRelease); - if (err != NO_ERROR) { - return err; - } - return err; -} - -void BufferLayerConsumer::setReleaseFence(const sp<Fence>& fence) { - if (!fence->isValid()) { - return; - } - - auto slot = mPendingRelease.isPending ? mPendingRelease.currentTexture : mCurrentTexture; - if (slot == BufferQueue::INVALID_BUFFER_SLOT) { - return; - } - - auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer - : mCurrentTextureBuffer->getBuffer(); - auto err = addReleaseFence(slot, buffer, fence); - if (err != OK) { - BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err); - } -} - -bool BufferLayerConsumer::releasePendingBuffer() { - if (!mPendingRelease.isPending) { - BLC_LOGV("Pending buffer already released"); - return false; - } - BLC_LOGV("Releasing pending buffer"); - Mutex::Autolock lock(mMutex); - status_t result = - releaseBufferLocked(mPendingRelease.currentTexture, mPendingRelease.graphicBuffer); - if (result < NO_ERROR) { - BLC_LOGE("releasePendingBuffer failed: %s (%d)", strerror(-result), result); - } - mPendingRelease = PendingRelease(); - return true; -} - -sp<Fence> BufferLayerConsumer::getPrevFinalReleaseFence() const { - Mutex::Autolock lock(mMutex); - return ConsumerBase::mPrevFinalReleaseFence; -} - -status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen, - uint64_t maxFrameNumber) { - status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber); - if (err != NO_ERROR) { - return err; - } - - // If item->mGraphicBuffer is not null, this buffer has not been acquired - // before, so we need to clean up old references. - if (item->mGraphicBuffer != nullptr) { - std::lock_guard<std::mutex> lock(mImagesMutex); - if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->getBuffer() == nullptr || - mImages[item->mSlot]->getBuffer()->getId() != item->mGraphicBuffer->getId()) { - mImages[item->mSlot] = std::make_shared< - renderengine::impl::ExternalTexture>(item->mGraphicBuffer, mRE, - renderengine::impl::ExternalTexture:: - Usage::READABLE); - } - } - - return NO_ERROR; -} - -status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item, - PendingRelease* pendingRelease) { - status_t err = NO_ERROR; - - int slot = item.mSlot; - - BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture, - (mCurrentTextureBuffer != nullptr && mCurrentTextureBuffer->getBuffer() != nullptr) - ? mCurrentTextureBuffer->getBuffer()->handle - : 0, - slot, mSlots[slot].mGraphicBuffer->handle); - - // Hang onto the pointer so that it isn't freed in the call to - // releaseBufferLocked() if we're in shared buffer mode and both buffers are - // the same. - - std::shared_ptr<renderengine::ExternalTexture> nextTextureBuffer; - { - std::lock_guard<std::mutex> lock(mImagesMutex); - nextTextureBuffer = mImages[slot]; - } - - // release old buffer - if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { - if (pendingRelease == nullptr) { - status_t status = - releaseBufferLocked(mCurrentTexture, mCurrentTextureBuffer->getBuffer()); - if (status < NO_ERROR) { - BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status), - status); - err = status; - // keep going, with error raised [?] - } - } else { - pendingRelease->currentTexture = mCurrentTexture; - pendingRelease->graphicBuffer = mCurrentTextureBuffer->getBuffer(); - pendingRelease->isPending = true; - } - } - - // Update the BufferLayerConsumer state. - mCurrentTexture = slot; - mCurrentTextureBuffer = nextTextureBuffer; - mCurrentCrop = item.mCrop; - mCurrentTransform = item.mTransform; - mCurrentScalingMode = item.mScalingMode; - mCurrentTimestamp = item.mTimestamp; - mCurrentDataSpace = static_cast<ui::Dataspace>(item.mDataSpace); - mCurrentHdrMetadata = item.mHdrMetadata; - mCurrentFence = item.mFence; - mCurrentFenceTime = item.mFenceTime; - mCurrentFrameNumber = item.mFrameNumber; - mCurrentTransformToDisplayInverse = item.mTransformToDisplayInverse; - mCurrentSurfaceDamage = item.mSurfaceDamage; - mCurrentApi = item.mApi; - - computeCurrentTransformMatrixLocked(); - - return err; -} - -void BufferLayerConsumer::getTransformMatrix(float mtx[16]) { - Mutex::Autolock lock(mMutex); - memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); -} - -void BufferLayerConsumer::setFilteringEnabled(bool enabled) { - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - BLC_LOGE("setFilteringEnabled: BufferLayerConsumer is abandoned!"); - return; - } - bool needsRecompute = mFilteringEnabled != enabled; - mFilteringEnabled = enabled; - - if (needsRecompute && mCurrentTextureBuffer == nullptr) { - BLC_LOGD("setFilteringEnabled called with mCurrentTextureBuffer == nullptr"); - } - - if (needsRecompute && mCurrentTextureBuffer != nullptr) { - computeCurrentTransformMatrixLocked(); - } -} - -void BufferLayerConsumer::computeCurrentTransformMatrixLocked() { - BLC_LOGV("computeCurrentTransformMatrixLocked"); - if (mCurrentTextureBuffer == nullptr || mCurrentTextureBuffer->getBuffer() == nullptr) { - BLC_LOGD("computeCurrentTransformMatrixLocked: " - "mCurrentTextureBuffer is nullptr"); - } - GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, - mCurrentTextureBuffer == nullptr - ? nullptr - : mCurrentTextureBuffer->getBuffer(), - getCurrentCropLocked(), mCurrentTransform, - mFilteringEnabled); -} - -nsecs_t BufferLayerConsumer::getTimestamp() { - BLC_LOGV("getTimestamp"); - Mutex::Autolock lock(mMutex); - return mCurrentTimestamp; -} - -ui::Dataspace BufferLayerConsumer::getCurrentDataSpace() { - BLC_LOGV("getCurrentDataSpace"); - Mutex::Autolock lock(mMutex); - return mCurrentDataSpace; -} - -const HdrMetadata& BufferLayerConsumer::getCurrentHdrMetadata() const { - BLC_LOGV("getCurrentHdrMetadata"); - Mutex::Autolock lock(mMutex); - return mCurrentHdrMetadata; -} - -uint64_t BufferLayerConsumer::getFrameNumber() { - BLC_LOGV("getFrameNumber"); - Mutex::Autolock lock(mMutex); - return mCurrentFrameNumber; -} - -bool BufferLayerConsumer::getTransformToDisplayInverse() const { - Mutex::Autolock lock(mMutex); - return mCurrentTransformToDisplayInverse; -} - -const Region& BufferLayerConsumer::getSurfaceDamage() const { - return mCurrentSurfaceDamage; -} - -void BufferLayerConsumer::mergeSurfaceDamage(const Region& damage) { - if (damage.bounds() == Rect::INVALID_RECT || - mCurrentSurfaceDamage.bounds() == Rect::INVALID_RECT) { - mCurrentSurfaceDamage = Region::INVALID_REGION; - } else { - mCurrentSurfaceDamage |= damage; - } -} - -int BufferLayerConsumer::getCurrentApi() const { - Mutex::Autolock lock(mMutex); - return mCurrentApi; -} - -std::shared_ptr<renderengine::ExternalTexture> BufferLayerConsumer::getCurrentBuffer( - int* outSlot, sp<Fence>* outFence) const { - Mutex::Autolock lock(mMutex); - - if (outSlot != nullptr) { - *outSlot = mCurrentTexture; - } - - if (outFence != nullptr) { - *outFence = mCurrentFence; - } - - return mCurrentTextureBuffer == nullptr ? nullptr : mCurrentTextureBuffer; -} - -Rect BufferLayerConsumer::getCurrentCrop() const { - Mutex::Autolock lock(mMutex); - return getCurrentCropLocked(); -} - -Rect BufferLayerConsumer::getCurrentCropLocked() const { - uint32_t width = mDefaultWidth; - uint32_t height = mDefaultHeight; - // If the buffer comes with a rotated bit for 90 (or 270) degrees, switch width/height in order - // to scale and crop correctly. - if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) { - width = mDefaultHeight; - height = mDefaultWidth; - } - - return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) - ? GLConsumer::scaleDownCrop(mCurrentCrop, width, height) - : mCurrentCrop; -} - -uint32_t BufferLayerConsumer::getCurrentTransform() const { - Mutex::Autolock lock(mMutex); - return mCurrentTransform; -} - -uint32_t BufferLayerConsumer::getCurrentScalingMode() const { - Mutex::Autolock lock(mMutex); - return mCurrentScalingMode; -} - -sp<Fence> BufferLayerConsumer::getCurrentFence() const { - Mutex::Autolock lock(mMutex); - return mCurrentFence; -} - -std::shared_ptr<FenceTime> BufferLayerConsumer::getCurrentFenceTime() const { - Mutex::Autolock lock(mMutex); - return mCurrentFenceTime; -} - -void BufferLayerConsumer::freeBufferLocked(int slotIndex) { - BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); - std::lock_guard<std::mutex> lock(mImagesMutex); - if (slotIndex == mCurrentTexture) { - mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; - } - mImages[slotIndex] = nullptr; - ConsumerBase::freeBufferLocked(slotIndex); -} - -void BufferLayerConsumer::onDisconnect() { - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - // Nothing to do if we're already abandoned. - return; - } - - mLayer->onDisconnect(); -} - -void BufferLayerConsumer::onSidebandStreamChanged() { - [[maybe_unused]] FrameAvailableListener* unsafeFrameAvailableListener = nullptr; - { - Mutex::Autolock lock(mFrameAvailableMutex); - unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get(); - } - sp<ContentsChangedListener> listener; - { // scope for the lock - Mutex::Autolock lock(mMutex); - ALOG_ASSERT(unsafeFrameAvailableListener == mContentsChangedListener.unsafe_get()); - listener = mContentsChangedListener.promote(); - } - - if (listener != nullptr) { - listener->onSidebandStreamChanged(); - } -} - -void BufferLayerConsumer::onBufferAvailable(const BufferItem& item) { - if (item.mGraphicBuffer != nullptr && item.mSlot != BufferQueue::INVALID_BUFFER_SLOT) { - std::lock_guard<std::mutex> lock(mImagesMutex); - const std::shared_ptr<renderengine::ExternalTexture>& oldImage = mImages[item.mSlot]; - if (oldImage == nullptr || oldImage->getBuffer() == nullptr || - oldImage->getBuffer()->getId() != item.mGraphicBuffer->getId()) { - mImages[item.mSlot] = std::make_shared< - renderengine::impl::ExternalTexture>(item.mGraphicBuffer, mRE, - renderengine::impl::ExternalTexture:: - Usage::READABLE); - } - } -} - -void BufferLayerConsumer::abandonLocked() { - BLC_LOGV("abandonLocked"); - mCurrentTextureBuffer = nullptr; - for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - std::lock_guard<std::mutex> lock(mImagesMutex); - mImages[i] = nullptr; - } - ConsumerBase::abandonLocked(); -} - -status_t BufferLayerConsumer::setConsumerUsageBits(uint64_t usage) { - return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS); -} - -void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const { - result.appendFormat("%smTexName=%d mCurrentTexture=%d\n" - "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n", - prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left, - mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom, - mCurrentTransform); - - ConsumerBase::dumpLocked(result, prefix); -} -}; // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h deleted file mode 100644 index 23ad2a3f91..0000000000 --- a/services/surfaceflinger/BufferLayerConsumer.h +++ /dev/null @@ -1,354 +0,0 @@ -/* - * Copyright (C) 2010 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. - */ - -#ifndef ANDROID_BUFFERLAYERCONSUMER_H -#define ANDROID_BUFFERLAYERCONSUMER_H - -#include <android-base/thread_annotations.h> -#include <gui/BufferQueueDefs.h> -#include <gui/ConsumerBase.h> -#include <gui/HdrMetadata.h> -#include <renderengine/ExternalTexture.h> -#include <ui/FenceTime.h> -#include <ui/GraphicBuffer.h> -#include <ui/GraphicTypes.h> -#include <ui/Region.h> -#include <utils/String8.h> -#include <utils/Vector.h> -#include <utils/threads.h> - -namespace android { -// ---------------------------------------------------------------------------- - -class Layer; -class String8; - -namespace renderengine { -class RenderEngine; -} // namespace renderengine - -/* - * BufferLayerConsumer consumes buffers of graphics data from a BufferQueue, - * and makes them available to RenderEngine as a texture. - * - * A typical usage pattern is to call updateTexImage() when a new frame is - * desired. If a new frame is available, the frame is latched. If not, the - * previous contents are retained. The texture is attached and updated after - * bindTextureImage() is called. - * - * All calls to updateTexImage must be made with RenderEngine being current. - * The texture is attached to the TEXTURE_EXTERNAL texture target. - */ -class BufferLayerConsumer : public ConsumerBase { -public: - static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8; - - class BufferRejecter { - friend class BufferLayerConsumer; - virtual bool reject(const sp<GraphicBuffer>& buf, const BufferItem& item) = 0; - - protected: - virtual ~BufferRejecter() {} - }; - - struct ContentsChangedListener : public FrameAvailableListener { - virtual void onSidebandStreamChanged() = 0; - }; - - // BufferLayerConsumer constructs a new BufferLayerConsumer object. The - // tex parameter indicates the name of the RenderEngine texture to which - // images are to be streamed. - BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, renderengine::RenderEngine& engine, - uint32_t tex, Layer* layer); - - // Sets the contents changed listener. This should be used instead of - // ConsumerBase::setFrameAvailableListener(). - void setContentsChangedListener(const wp<ContentsChangedListener>& listener); - - // updateTexImage acquires the most recently queued buffer, and sets the - // image contents of the target texture to it. - // - // This call may only be made while RenderEngine is current. - // - // This calls doFenceWait to ensure proper synchronization unless native - // fence is supported. - // - // Unlike the GLConsumer version, this version takes a functor that may be - // used to reject the newly acquired buffer. It also does not bind the - // RenderEngine texture until bindTextureImage is called. - status_t updateTexImage(BufferRejecter* rejecter, nsecs_t expectedPresentTime, - bool* autoRefresh, bool* queuedBuffer, uint64_t maxFrameNumber); - - // setReleaseFence stores a fence that will signal when the current buffer - // is no longer being read. This fence will be returned to the producer - // when the current buffer is released by updateTexImage(). Multiple - // fences can be set for a given buffer; they will be merged into a single - // union fence. - void setReleaseFence(const sp<Fence>& fence); - - bool releasePendingBuffer(); - - sp<Fence> getPrevFinalReleaseFence() const; - - // See GLConsumer::getTransformMatrix. - void getTransformMatrix(float mtx[16]); - - // getTimestamp retrieves the timestamp associated with the texture image - // set by the most recent call to updateTexImage. - // - // The timestamp is in nanoseconds, and is monotonically increasing. Its - // other semantics (zero point, etc) are source-dependent and should be - // documented by the source. - int64_t getTimestamp(); - - // getDataSpace retrieves the DataSpace associated with the texture image - // set by the most recent call to updateTexImage. - ui::Dataspace getCurrentDataSpace(); - - // getCurrentHdrMetadata retrieves the HDR metadata associated with the - // texture image set by the most recent call to updateTexImage. - const HdrMetadata& getCurrentHdrMetadata() const; - - // getFrameNumber retrieves the frame number associated with the texture - // image set by the most recent call to updateTexImage. - // - // The frame number is an incrementing counter set to 0 at the creation of - // the BufferQueue associated with this consumer. - uint64_t getFrameNumber(); - - bool getTransformToDisplayInverse() const; - - // must be called from SF main thread - const Region& getSurfaceDamage() const; - - // Merge the given damage region into the current damage region value. - void mergeSurfaceDamage(const Region& damage); - - // getCurrentApi retrieves the API which queues the current buffer. - int getCurrentApi() const; - - // See GLConsumer::setDefaultBufferSize. - status_t setDefaultBufferSize(uint32_t width, uint32_t height); - - // setFilteringEnabled sets whether the transform matrix should be computed - // for use with bilinear filtering. - void setFilteringEnabled(bool enabled); - - // getCurrentBuffer returns the buffer associated with the current image. - // When outSlot is not nullptr, the current buffer slot index is also - // returned. Simiarly, when outFence is not nullptr, the current output - // fence is returned. - std::shared_ptr<renderengine::ExternalTexture> getCurrentBuffer( - int* outSlot = nullptr, sp<Fence>* outFence = nullptr) const; - - // getCurrentCrop returns the cropping rectangle of the current buffer. - Rect getCurrentCrop() const; - - // getCurrentTransform returns the transform of the current buffer. - uint32_t getCurrentTransform() const; - - // getCurrentScalingMode returns the scaling mode of the current buffer. - uint32_t getCurrentScalingMode() const; - - // getCurrentFence returns the fence indicating when the current buffer is - // ready to be read from. - sp<Fence> getCurrentFence() const; - - // getCurrentFence returns the FenceTime indicating when the current - // buffer is ready to be read from. - std::shared_ptr<FenceTime> getCurrentFenceTime() const; - - // setConsumerUsageBits overrides the ConsumerBase method to OR - // DEFAULT_USAGE_FLAGS to usage. - status_t setConsumerUsageBits(uint64_t usage); - void onBufferAvailable(const BufferItem& item) EXCLUDES(mImagesMutex); - -protected: - // abandonLocked overrides the ConsumerBase method to clear - // mCurrentTextureImage in addition to the ConsumerBase behavior. - virtual void abandonLocked() EXCLUDES(mImagesMutex); - - // dumpLocked overrides the ConsumerBase method to dump BufferLayerConsumer- - // specific info in addition to the ConsumerBase behavior. - virtual void dumpLocked(String8& result, const char* prefix) const; - - // See ConsumerBase::acquireBufferLocked - virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen, - uint64_t maxFrameNumber = 0) override - EXCLUDES(mImagesMutex); - - bool canUseImageCrop(const Rect& crop) const; - - struct PendingRelease { - PendingRelease() : isPending(false), currentTexture(-1), graphicBuffer() {} - - bool isPending; - int currentTexture; - sp<GraphicBuffer> graphicBuffer; - }; - - // This releases the buffer in the slot referenced by mCurrentTexture, - // then updates state to refer to the BufferItem, which must be a - // newly-acquired buffer. If pendingRelease is not null, the parameters - // which would have been passed to releaseBufferLocked upon the successful - // completion of the method will instead be returned to the caller, so that - // it may call releaseBufferLocked itself later. - status_t updateAndReleaseLocked(const BufferItem& item, - PendingRelease* pendingRelease = nullptr) - EXCLUDES(mImagesMutex); - -private: - // Utility class for managing GraphicBuffer references into renderengine - class Image { - public: - Image(const sp<GraphicBuffer>& graphicBuffer, renderengine::RenderEngine& engine); - virtual ~Image(); - const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; } - - private: - // mGraphicBuffer is the buffer that was used to create this image. - sp<GraphicBuffer> mGraphicBuffer; - // Back-reference into renderengine to initiate cleanup. - renderengine::RenderEngine& mRE; - DISALLOW_COPY_AND_ASSIGN(Image); - }; - - // freeBufferLocked frees up the given buffer slot. If the slot has been - // initialized this will release the reference to the GraphicBuffer in - // that slot. Otherwise it has no effect. - // - // This method must be called with mMutex locked. - virtual void freeBufferLocked(int slotIndex) EXCLUDES(mImagesMutex); - - // IConsumerListener interface - void onDisconnect() override; - void onSidebandStreamChanged() override; - void addAndGetFrameTimestamps(const NewFrameEventsEntry*, FrameEventHistoryDelta*) override {} - - // computeCurrentTransformMatrixLocked computes the transform matrix for the - // current texture. It uses mCurrentTransform and the current GraphicBuffer - // to compute this matrix and stores it in mCurrentTransformMatrix. - // mCurrentTextureImage must not be nullptr. - void computeCurrentTransformMatrixLocked(); - - // getCurrentCropLocked returns the cropping rectangle of the current buffer. - Rect getCurrentCropLocked() const; - - // The default consumer usage flags that BufferLayerConsumer always sets on its - // BufferQueue instance; these will be OR:d with any additional flags passed - // from the BufferLayerConsumer user. In particular, BufferLayerConsumer will always - // consume buffers as hardware textures. - static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE; - - // mCurrentTextureBuffer is the buffer containing the current texture. It's - // possible that this buffer is not associated with any buffer slot, so we - // must track it separately in order to support the getCurrentBuffer method. - std::shared_ptr<renderengine::ExternalTexture> mCurrentTextureBuffer; - - // mCurrentCrop is the crop rectangle that applies to the current texture. - // It gets set each time updateTexImage is called. - Rect mCurrentCrop; - - // mCurrentTransform is the transform identifier for the current texture. It - // gets set each time updateTexImage is called. - uint32_t mCurrentTransform; - - // mCurrentScalingMode is the scaling mode for the current texture. It gets - // set each time updateTexImage is called. - uint32_t mCurrentScalingMode; - - // mCurrentFence is the fence received from BufferQueue in updateTexImage. - sp<Fence> mCurrentFence; - - // The FenceTime wrapper around mCurrentFence. - std::shared_ptr<FenceTime> mCurrentFenceTime{FenceTime::NO_FENCE}; - - // mCurrentTransformMatrix is the transform matrix for the current texture. - // It gets computed by computeTransformMatrix each time updateTexImage is - // called. - float mCurrentTransformMatrix[16]; - - // mCurrentTimestamp is the timestamp for the current texture. It - // gets set each time updateTexImage is called. - int64_t mCurrentTimestamp; - - // mCurrentDataSpace is the dataspace for the current texture. It - // gets set each time updateTexImage is called. - ui::Dataspace mCurrentDataSpace; - - // mCurrentHdrMetadata is the HDR metadata for the current texture. It - // gets set each time updateTexImage is called. - HdrMetadata mCurrentHdrMetadata; - - // mCurrentFrameNumber is the frame counter for the current texture. - // It gets set each time updateTexImage is called. - uint64_t mCurrentFrameNumber; - - // Indicates this buffer must be transformed by the inverse transform of the screen - // it is displayed onto. This is applied after BufferLayerConsumer::mCurrentTransform. - // This must be set/read from SurfaceFlinger's main thread. - bool mCurrentTransformToDisplayInverse; - - // The portion of this surface that has changed since the previous frame - Region mCurrentSurfaceDamage; - - int mCurrentApi; - - uint32_t mDefaultWidth, mDefaultHeight; - - // mFilteringEnabled indicates whether the transform matrix is computed for - // use with bilinear filtering. It defaults to true and is changed by - // setFilteringEnabled(). - bool mFilteringEnabled; - - renderengine::RenderEngine& mRE; - - // mTexName is the name of the RenderEngine texture to which streamed - // images will be bound when bindTexImage is called. It is set at - // construction time. - const uint32_t mTexName; - - // The layer for this BufferLayerConsumer. Always check mAbandoned before accessing. - Layer* mLayer GUARDED_BY(mMutex); - - wp<ContentsChangedListener> mContentsChangedListener; - - // mCurrentTexture is the buffer slot index of the buffer that is currently - // bound to the RenderEngine texture. It is initialized to INVALID_BUFFER_SLOT, - // indicating that no buffer slot is currently bound to the texture. Note, - // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean - // that no buffer is bound to the texture. A call to setBufferCount will - // reset mCurrentTexture to INVALID_BUFFER_SLOT. - int mCurrentTexture; - - // Shadow buffer cache for cleaning up renderengine references. - std::shared_ptr<renderengine::ExternalTexture> - mImages[BufferQueueDefs::NUM_BUFFER_SLOTS] GUARDED_BY(mImagesMutex); - - // Separate mutex guarding the shadow buffer cache. - // mImagesMutex can be manipulated with binder threads (e.g. onBuffersAllocated) - // which is contentious enough that we can't just use mMutex. - mutable std::mutex mImagesMutex; - - // A release that is pending on the receipt of a new release fence from - // presentDisplay - PendingRelease mPendingRelease; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_BUFFERLAYERCONSUMER_H diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp deleted file mode 100644 index bee4de32a6..0000000000 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ /dev/null @@ -1,575 +0,0 @@ -/* - * Copyright (C) 2018 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. - */ - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - -#undef LOG_TAG -#define LOG_TAG "BufferQueueLayer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include "BufferQueueLayer.h" - -#include <compositionengine/LayerFECompositionState.h> -#include <gui/BufferQueueConsumer.h> -#include <system/window.h> - -#include "LayerRejecter.h" -#include "SurfaceInterceptor.h" - -#include "FrameTracer/FrameTracer.h" -#include "Scheduler/LayerHistory.h" -#include "TimeStats/TimeStats.h" - -namespace android { -using PresentState = frametimeline::SurfaceFrame::PresentState; - -BufferQueueLayer::BufferQueueLayer(const LayerCreationArgs& args) : BufferLayer(args) {} - -BufferQueueLayer::~BufferQueueLayer() { - mContentsChangedListener->abandon(); - mConsumer->abandon(); -} - -// ----------------------------------------------------------------------- -// Interface implementation for Layer -// ----------------------------------------------------------------------- - -void BufferQueueLayer::onLayerDisplayed(ftl::SharedFuture<FenceResult> futureFenceResult) { - const sp<Fence> releaseFence = futureFenceResult.get().value_or(Fence::NO_FENCE); - mConsumer->setReleaseFence(releaseFence); - - // Prevent tracing the same release multiple times. - if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) { - mFlinger->mFrameTracer->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber, - std::make_shared<FenceTime>(releaseFence), - FrameTracer::FrameEvent::RELEASE_FENCE); - mPreviousReleasedFrameNumber = mPreviousFrameNumber; - } -} - -void BufferQueueLayer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) { - BufferLayer::setTransformHint(displayTransformHint); - mConsumer->setTransformHint(mTransformHint); -} - -void BufferQueueLayer::releasePendingBuffer(nsecs_t) { - if (!mConsumer->releasePendingBuffer()) { - return; - } -} - -void BufferQueueLayer::setDefaultBufferSize(uint32_t w, uint32_t h) { - mConsumer->setDefaultBufferSize(w, h); -} - -int32_t BufferQueueLayer::getQueuedFrameCount() const { - return mQueuedFrames; -} - -bool BufferQueueLayer::isBufferDue(nsecs_t expectedPresentTime) const { - Mutex::Autolock lock(mQueueItemLock); - - const int64_t addedTime = mQueueItems[0].item.mTimestamp; - - // Ignore timestamps more than a second in the future - const bool isPlausible = addedTime < (expectedPresentTime + s2ns(1)); - ALOGW_IF(!isPlausible, - "[%s] Timestamp %" PRId64 " seems implausible " - "relative to expectedPresent %" PRId64, - getDebugName(), addedTime, expectedPresentTime); - - if (!isPlausible) { - mFlinger->mTimeStats->incrementBadDesiredPresent(getSequence()); - } - - const bool isDue = addedTime < expectedPresentTime; - return isDue || !isPlausible; -} - -// ----------------------------------------------------------------------- -// Interface implementation for BufferLayer -// ----------------------------------------------------------------------- - -bool BufferQueueLayer::fenceHasSignaled() const { - Mutex::Autolock lock(mQueueItemLock); - - if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { - return true; - } - - if (!hasFrameUpdate()) { - return true; - } - - if (mQueueItems[0].item.mIsDroppable) { - // Even though this buffer's fence may not have signaled yet, it could - // be replaced by another buffer before it has a chance to, which means - // that it's possible to get into a situation where a buffer is never - // able to be latched. To avoid this, grab this buffer anyway. - return true; - } - const bool fenceSignaled = - mQueueItems[0].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; - if (!fenceSignaled) { - mFlinger->mTimeStats->incrementLatchSkipped(getSequence(), - TimeStats::LatchSkipReason::LateAcquire); - } - - return fenceSignaled; -} - -bool BufferQueueLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const { - Mutex::Autolock lock(mQueueItemLock); - - if (!hasFrameUpdate() || isRemovedFromCurrentState()) { - return true; - } - - return mQueueItems[0].item.mTimestamp <= expectedPresentTime; -} - -bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) { - // We need to update the sideband stream if the layer has both a buffer and a sideband stream. - editCompositionState()->sidebandStreamHasFrame = hasFrameUpdate() && mSidebandStream.get(); - - bool sidebandStreamChanged = true; - if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) { - // mSidebandStreamChanged was changed to false - mSidebandStream = mConsumer->getSidebandStream(); - auto* layerCompositionState = editCompositionState(); - layerCompositionState->sidebandStream = mSidebandStream; - if (layerCompositionState->sidebandStream != nullptr) { - setTransactionFlags(eTransactionNeeded); - mFlinger->setTransactionFlags(eTraversalNeeded); - } - recomputeVisibleRegions = true; - - return true; - } - return false; -} - -bool BufferQueueLayer::hasFrameUpdate() const { - return mQueuedFrames > 0; -} - -status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, - nsecs_t expectedPresentTime) { - // This boolean is used to make sure that SurfaceFlinger's shadow copy - // of the buffer queue isn't modified when the buffer queue is returning - // BufferItem's that weren't actually queued. This can happen in shared - // buffer mode. - bool queuedBuffer = false; - const int32_t layerId = getSequence(); - LayerRejecter r(mDrawingState, getDrawingState(), recomputeVisibleRegions, - getProducerStickyTransform() != 0, mName, - getTransformToDisplayInverse()); - - if (isRemovedFromCurrentState()) { - expectedPresentTime = 0; - } - - // updateTexImage() below might drop the some buffers at the head of the queue if there is a - // buffer behind them which is timely to be presented. However this buffer may not be signaled - // yet. The code below makes sure that this wouldn't happen by setting maxFrameNumber to the - // last buffer that was signaled. - uint64_t lastSignaledFrameNumber = mLastFrameNumberReceived; - { - Mutex::Autolock lock(mQueueItemLock); - for (size_t i = 0; i < mQueueItems.size(); i++) { - bool fenceSignaled = - mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING; - if (!fenceSignaled) { - break; - } - lastSignaledFrameNumber = mQueueItems[i].item.mFrameNumber; - } - } - const uint64_t maxFrameNumberToAcquire = - std::min(mLastFrameNumberReceived.load(), lastSignaledFrameNumber); - - bool autoRefresh; - status_t updateResult = mConsumer->updateTexImage(&r, expectedPresentTime, &autoRefresh, - &queuedBuffer, maxFrameNumberToAcquire); - mDrawingState.autoRefresh = autoRefresh; - if (updateResult == BufferQueue::PRESENT_LATER) { - // Producer doesn't want buffer to be displayed yet. Signal a - // layer update so we check again at the next opportunity. - mFlinger->onLayerUpdate(); - return BAD_VALUE; - } else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) { - // If the buffer has been rejected, remove it from the shadow queue - // and return early - if (queuedBuffer) { - Mutex::Autolock lock(mQueueItemLock); - if (mQueuedFrames > 0) { - mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage); - mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber); - if (mQueueItems[0].surfaceFrame) { - addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame); - } - mQueueItems.erase(mQueueItems.begin()); - mQueuedFrames--; - } - } - return BAD_VALUE; - } else if (updateResult != NO_ERROR || mUpdateTexImageFailed) { - // This can occur if something goes wrong when trying to create the - // EGLImage for this buffer. If this happens, the buffer has already - // been released, so we need to clean up the queue and bug out - // early. - if (queuedBuffer) { - Mutex::Autolock lock(mQueueItemLock); - for (auto& [item, surfaceFrame] : mQueueItems) { - if (surfaceFrame) { - addSurfaceFrameDroppedForBuffer(surfaceFrame); - } - } - mQueueItems.clear(); - mQueuedFrames = 0; - mFlinger->mTimeStats->onDestroy(layerId); - mFlinger->mFrameTracer->onDestroy(layerId); - } - - // Once we have hit this state, the shadow queue may no longer - // correctly reflect the incoming BufferQueue's contents, so even if - // updateTexImage starts working, the only safe course of action is - // to continue to ignore updates. - mUpdateTexImageFailed = true; - - return BAD_VALUE; - } - - bool more_frames_pending = false; - if (queuedBuffer) { - // Autolock scope - auto currentFrameNumber = mConsumer->getFrameNumber(); - - Mutex::Autolock lock(mQueueItemLock); - - // Remove any stale buffers that have been dropped during - // updateTexImage - while (mQueuedFrames > 0 && mQueueItems[0].item.mFrameNumber != currentFrameNumber) { - mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage); - mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber); - if (mQueueItems[0].surfaceFrame) { - addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame); - } - mQueueItems.erase(mQueueItems.begin()); - mQueuedFrames--; - } - - uint64_t bufferID = mQueueItems[0].item.mGraphicBuffer->getId(); - mFlinger->mTimeStats->setLatchTime(layerId, currentFrameNumber, latchTime); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferID, currentFrameNumber, latchTime, - FrameTracer::FrameEvent::LATCH); - - if (mQueueItems[0].surfaceFrame) { - addSurfaceFramePresentedForBuffer(mQueueItems[0].surfaceFrame, - mQueueItems[0].item.mFenceTime->getSignalTime(), - latchTime); - } - mQueueItems.erase(mQueueItems.begin()); - more_frames_pending = (mQueuedFrames.fetch_sub(1) > 1); - } - - // Decrement the queued-frames count. Signal another event if we - // have more frames pending. - if ((queuedBuffer && more_frames_pending) || mDrawingState.autoRefresh) { - mFlinger->onLayerUpdate(); - } - - return NO_ERROR; -} - -status_t BufferQueueLayer::updateActiveBuffer() { - // update the active buffer - mPreviousBufferId = getCurrentBufferId(); - mBufferInfo.mBuffer = - mConsumer->getCurrentBuffer(&mBufferInfo.mBufferSlot, &mBufferInfo.mFence); - - if (mBufferInfo.mBuffer == nullptr) { - // this can only happen if the very first buffer was rejected. - return BAD_VALUE; - } - return NO_ERROR; -} - -status_t BufferQueueLayer::updateFrameNumber() { - mPreviousFrameNumber = mCurrentFrameNumber; - mCurrentFrameNumber = mConsumer->getFrameNumber(); - return NO_ERROR; -} - -void BufferQueueLayer::setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) { - mFrameTimelineInfo = frameTimelineInfo; -} - -// ----------------------------------------------------------------------- -// Interface implementation for BufferLayerConsumer::ContentsChangedListener -// ----------------------------------------------------------------------- - -void BufferQueueLayer::onFrameDequeued(const uint64_t bufferId) { - const int32_t layerId = getSequence(); - mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str()); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, FrameTracer::UNSPECIFIED_FRAME_NUMBER, - systemTime(), FrameTracer::FrameEvent::DEQUEUE); -} - -void BufferQueueLayer::onFrameDetached(const uint64_t bufferId) { - const int32_t layerId = getSequence(); - mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str()); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, FrameTracer::UNSPECIFIED_FRAME_NUMBER, - systemTime(), FrameTracer::FrameEvent::DETACH); -} - -void BufferQueueLayer::onFrameCancelled(const uint64_t bufferId) { - const int32_t layerId = getSequence(); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, FrameTracer::UNSPECIFIED_FRAME_NUMBER, - systemTime(), FrameTracer::FrameEvent::CANCEL); -} - -void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { - const int32_t layerId = getSequence(); - const uint64_t bufferId = item.mGraphicBuffer->getId(); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, item.mFrameNumber, systemTime(), - FrameTracer::FrameEvent::QUEUE); - mFlinger->mFrameTracer->traceFence(layerId, bufferId, item.mFrameNumber, - std::make_shared<FenceTime>(item.mFence), - FrameTracer::FrameEvent::ACQUIRE_FENCE); - - ATRACE_CALL(); - // Add this buffer from our internal queue tracker - { // Autolock scope - const nsecs_t presentTime = item.mIsAutoTimestamp ? 0 : item.mTimestamp; - - using LayerUpdateType = scheduler::LayerHistory::LayerUpdateType; - mFlinger->mScheduler->recordLayerHistory(this, presentTime, LayerUpdateType::Buffer); - - Mutex::Autolock lock(mQueueItemLock); - // Reset the frame number tracker when we receive the first buffer after - // a frame number reset - if (item.mFrameNumber == 1) { - mLastFrameNumberReceived = 0; - } - - // Ensure that callbacks are handled in order - while (item.mFrameNumber != mLastFrameNumberReceived + 1) { - status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500)); - if (result != NO_ERROR) { - ALOGE("[%s] Timed out waiting on callback", getDebugName()); - break; - } - } - - auto surfaceFrame = createSurfaceFrameForBuffer(mFrameTimelineInfo, systemTime(), mName); - - mQueueItems.push_back({item, surfaceFrame}); - mQueuedFrames++; - - // Wake up any pending callbacks - mLastFrameNumberReceived = item.mFrameNumber; - mQueueItemCondition.broadcast(); - } - - mFlinger->mInterceptor->saveBufferUpdate(layerId, item.mGraphicBuffer->getWidth(), - item.mGraphicBuffer->getHeight(), item.mFrameNumber); - - mFlinger->onLayerUpdate(); - mConsumer->onBufferAvailable(item); -} - -void BufferQueueLayer::onFrameReplaced(const BufferItem& item) { - ATRACE_CALL(); - { // Autolock scope - Mutex::Autolock lock(mQueueItemLock); - - // Ensure that callbacks are handled in order - while (item.mFrameNumber != mLastFrameNumberReceived + 1) { - status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500)); - if (result != NO_ERROR) { - ALOGE("[%s] Timed out waiting on callback", getDebugName()); - break; - } - } - - if (!hasFrameUpdate()) { - ALOGE("Can't replace a frame on an empty queue"); - return; - } - - auto surfaceFrame = createSurfaceFrameForBuffer(mFrameTimelineInfo, systemTime(), mName); - mQueueItems[mQueueItems.size() - 1].item = item; - mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame); - - // Wake up any pending callbacks - mLastFrameNumberReceived = item.mFrameNumber; - mQueueItemCondition.broadcast(); - } - - const int32_t layerId = getSequence(); - const uint64_t bufferId = item.mGraphicBuffer->getId(); - mFlinger->mFrameTracer->traceTimestamp(layerId, bufferId, item.mFrameNumber, systemTime(), - FrameTracer::FrameEvent::QUEUE); - mFlinger->mFrameTracer->traceFence(layerId, bufferId, item.mFrameNumber, - std::make_shared<FenceTime>(item.mFence), - FrameTracer::FrameEvent::ACQUIRE_FENCE); - mConsumer->onBufferAvailable(item); -} - -void BufferQueueLayer::onSidebandStreamChanged() { - bool sidebandStreamChanged = false; - if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, true)) { - // mSidebandStreamChanged was changed to true - mFlinger->onLayerUpdate(); - } -} - -// ----------------------------------------------------------------------- - -void BufferQueueLayer::onFirstRef() { - BufferLayer::onFirstRef(); - - // Creates a custom BufferQueue for SurfaceFlingerConsumer to use - sp<IGraphicBufferProducer> producer; - sp<IGraphicBufferConsumer> consumer; - mFlinger->getFactory().createBufferQueue(&producer, &consumer, true); - mProducer = mFlinger->getFactory().createMonitoredProducer(producer, mFlinger, this); - mConsumer = - mFlinger->getFactory().createBufferLayerConsumer(consumer, mFlinger->getRenderEngine(), - mTextureName, this); - mConsumer->setConsumerUsageBits(getEffectiveUsage(0)); - - mContentsChangedListener = new ContentsChangedListener(this); - mConsumer->setContentsChangedListener(mContentsChangedListener); - mConsumer->setName(String8(mName.data(), mName.size())); - - mProducer->setMaxDequeuedBufferCount(2); -} - -status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) { - // never allow a surface larger than what our underlying GL implementation - // can handle. - if (mFlinger->exceedsMaxRenderTargetSize(w, h)) { - ALOGE("dimensions too large %" PRIu32 " x %" PRIu32, w, h); - return BAD_VALUE; - } - - setDefaultBufferSize(w, h); - mConsumer->setDefaultBufferFormat(format); - mConsumer->setConsumerUsageBits(getEffectiveUsage(0)); - - return NO_ERROR; -} - -sp<IGraphicBufferProducer> BufferQueueLayer::getProducer() const { - return mProducer; -} - -uint32_t BufferQueueLayer::getProducerStickyTransform() const { - int producerStickyTransform = 0; - int ret = mProducer->query(NATIVE_WINDOW_STICKY_TRANSFORM, &producerStickyTransform); - if (ret != OK) { - ALOGW("%s: Error %s (%d) while querying window sticky transform.", __FUNCTION__, - strerror(-ret), ret); - return 0; - } - return static_cast<uint32_t>(producerStickyTransform); -} - -void BufferQueueLayer::gatherBufferInfo() { - BufferLayer::gatherBufferInfo(); - - mBufferInfo.mDesiredPresentTime = mConsumer->getTimestamp(); - mBufferInfo.mFenceTime = mConsumer->getCurrentFenceTime(); - mBufferInfo.mFence = mConsumer->getCurrentFence(); - mBufferInfo.mTransform = mConsumer->getCurrentTransform(); - mBufferInfo.mDataspace = translateDataspace(mConsumer->getCurrentDataSpace()); - mBufferInfo.mCrop = mConsumer->getCurrentCrop(); - mBufferInfo.mScaleMode = mConsumer->getCurrentScalingMode(); - mBufferInfo.mSurfaceDamage = mConsumer->getSurfaceDamage(); - mBufferInfo.mHdrMetadata = mConsumer->getCurrentHdrMetadata(); - mBufferInfo.mApi = mConsumer->getCurrentApi(); - mBufferInfo.mTransformToDisplayInverse = mConsumer->getTransformToDisplayInverse(); -} - -sp<Layer> BufferQueueLayer::createClone() { - LayerCreationArgs args(mFlinger.get(), nullptr, mName + " (Mirror)", 0, LayerMetadata()); - args.textureName = mTextureName; - sp<BufferQueueLayer> layer = mFlinger->getFactory().createBufferQueueLayer(args); - layer->setInitialValuesForClone(this); - - return layer; -} - -// ----------------------------------------------------------------------- -// Interface implementation for BufferLayerConsumer::ContentsChangedListener -// ----------------------------------------------------------------------- - -void BufferQueueLayer::ContentsChangedListener::onFrameAvailable(const BufferItem& item) { - Mutex::Autolock lock(mMutex); - if (mBufferQueueLayer != nullptr) { - mBufferQueueLayer->onFrameAvailable(item); - } -} - -void BufferQueueLayer::ContentsChangedListener::onFrameReplaced(const BufferItem& item) { - Mutex::Autolock lock(mMutex); - if (mBufferQueueLayer != nullptr) { - mBufferQueueLayer->onFrameReplaced(item); - } -} - -void BufferQueueLayer::ContentsChangedListener::onSidebandStreamChanged() { - Mutex::Autolock lock(mMutex); - if (mBufferQueueLayer != nullptr) { - mBufferQueueLayer->onSidebandStreamChanged(); - } -} - -void BufferQueueLayer::ContentsChangedListener::onFrameDequeued(const uint64_t bufferId) { - Mutex::Autolock lock(mMutex); - if (mBufferQueueLayer != nullptr) { - mBufferQueueLayer->onFrameDequeued(bufferId); - } -} - -void BufferQueueLayer::ContentsChangedListener::onFrameDetached(const uint64_t bufferId) { - Mutex::Autolock lock(mMutex); - if (mBufferQueueLayer != nullptr) { - mBufferQueueLayer->onFrameDetached(bufferId); - } -} - -void BufferQueueLayer::ContentsChangedListener::onFrameCancelled(const uint64_t bufferId) { - Mutex::Autolock lock(mMutex); - if (mBufferQueueLayer != nullptr) { - mBufferQueueLayer->onFrameCancelled(bufferId); - } -} - -void BufferQueueLayer::ContentsChangedListener::abandon() { - Mutex::Autolock lock(mMutex); - mBufferQueueLayer = nullptr; -} - -// ----------------------------------------------------------------------- - -} // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h deleted file mode 100644 index e1c80d581d..0000000000 --- a/services/surfaceflinger/BufferQueueLayer.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (C) 2018 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 "BufferLayer.h" - -#include <utils/String8.h> - -namespace android { - -namespace frametimeline { -class SurfaceFrame; -} - -/* - * A new BufferQueue and a new BufferLayerConsumer are created when the - * BufferLayer is first referenced. - * - * This also implements onFrameAvailable(), which notifies SurfaceFlinger - * that new data has arrived. - */ -class BufferQueueLayer : public BufferLayer { -public: - // Only call while mStateLock is held - explicit BufferQueueLayer(const LayerCreationArgs&); - ~BufferQueueLayer() override; - - // Implements Layer. - const char* getType() const override { return "BufferQueueLayer"; } - - void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override; - - // If a buffer was replaced this frame, release the former buffer - void releasePendingBuffer(nsecs_t dequeueReadyTime) override; - - void setDefaultBufferSize(uint32_t w, uint32_t h) override; - - int32_t getQueuedFrameCount() const override; - - // Returns true if the next buffer should be presented at the expected present time - bool isBufferDue(nsecs_t expectedPresentTime) const override; - - // Implements BufferLayer. - bool fenceHasSignaled() const override; - bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override; - - status_t setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format); - sp<IGraphicBufferProducer> getProducer() const; - - void setSizeForTest(uint32_t w, uint32_t h) { - mDrawingState.active_legacy.w = w; - mDrawingState.active_legacy.h = h; - } - -protected: - void gatherBufferInfo() override; - - // ----------------------------------------------------------------------- - // Interface implementation for BufferLayerConsumer::ContentsChangedListener - // ----------------------------------------------------------------------- - class ContentsChangedListener : public BufferLayerConsumer::ContentsChangedListener { - public: - ContentsChangedListener(BufferQueueLayer* bufferQueueLayer) - : mBufferQueueLayer(bufferQueueLayer) {} - void abandon(); - - protected: - void onFrameAvailable(const BufferItem& item) override; - void onFrameReplaced(const BufferItem& item) override; - void onSidebandStreamChanged() override; - void onFrameDequeued(const uint64_t bufferId) override; - void onFrameDetached(const uint64_t bufferId) override; - void onFrameCancelled(const uint64_t bufferId) override; - - private: - BufferQueueLayer* mBufferQueueLayer = nullptr; - Mutex mMutex; - }; - -private: - - bool latchSidebandStream(bool& recomputeVisibleRegions) override; - void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override; - - bool hasFrameUpdate() const override; - - status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, - nsecs_t expectedPresentTime) override; - - status_t updateActiveBuffer() override; - status_t updateFrameNumber() override; - void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& frameTimelineInfo) override; - - sp<Layer> createClone() override; - - void onFirstRef() override; - - void onFrameAvailable(const BufferItem& item); - void onFrameReplaced(const BufferItem& item); - void onSidebandStreamChanged(); - void onFrameDequeued(const uint64_t bufferId); - void onFrameDetached(const uint64_t bufferId); - void onFrameCancelled(const uint64_t bufferId); - - // Temporary - Used only for LEGACY camera mode. - uint32_t getProducerStickyTransform() const; - - sp<BufferLayerConsumer> mConsumer; - sp<IGraphicBufferProducer> mProducer; - - bool mUpdateTexImageFailed{false}; - - uint64_t mPreviousBufferId = 0; - uint64_t mPreviousReleasedFrameNumber = 0; - - // Local copy of the queued contents of the incoming BufferQueue - mutable Mutex mQueueItemLock; - Condition mQueueItemCondition; - - struct BufferData { - BufferData(BufferItem item, std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) - : item(item), surfaceFrame(surfaceFrame) {} - BufferItem item; - std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame; - }; - std::vector<BufferData> mQueueItems; - std::atomic<uint64_t> mLastFrameNumberReceived{0}; - - // thread-safe - std::atomic<int32_t> mQueuedFrames{0}; - - sp<ContentsChangedListener> mContentsChangedListener; - - // The last vsync info received on this layer. This will be used when we get - // a buffer to correlate the buffer with the vsync id. Can only be accessed - // with the SF state lock held. - FrameTimelineInfo mFrameTimelineInfo; -}; - -} // namespace android diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 3875f151cb..59e2d18d88 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -24,37 +24,82 @@ #include <limits> #include <FrameTimeline/FrameTimeline.h> +#include <compositionengine/CompositionEngine.h> #include <compositionengine/LayerFECompositionState.h> #include <gui/BufferQueue.h> #include <private/gui/SyncFeatures.h> #include <renderengine/Image.h> #include "TunnelModeEnabledReporter.h" +#include <gui/TraceUtils.h> #include "EffectLayer.h" #include "FrameTracer/FrameTracer.h" #include "TimeStats/TimeStats.h" #define EARLY_RELEASE_ENABLED false +#include <compositionengine/LayerFECompositionState.h> +#include <compositionengine/OutputLayer.h> +#include <compositionengine/impl/OutputLayerCompositionState.h> +#include <cutils/compiler.h> +#include <cutils/native_handle.h> +#include <cutils/properties.h> +#include <gui/BufferItem.h> +#include <gui/BufferQueue.h> +#include <gui/GLConsumer.h> +#include <gui/LayerDebugInfo.h> +#include <gui/Surface.h> +#include <renderengine/RenderEngine.h> +#include <ui/DebugUtils.h> +#include <utils/Errors.h> +#include <utils/Log.h> +#include <utils/NativeHandle.h> +#include <utils/StopWatch.h> +#include <utils/Trace.h> + +#include <cmath> +#include <cstdlib> +#include <mutex> +#include <sstream> + +#include "Colorizer.h" +#include "DisplayDevice.h" +#include "FrameTracer/FrameTracer.h" +#include "TimeStats/TimeStats.h" + namespace android { using PresentState = frametimeline::SurfaceFrame::PresentState; -namespace { -void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, - const sp<GraphicBuffer>& buffer, uint64_t framenumber, - const sp<Fence>& releaseFence, - uint32_t currentMaxAcquiredBufferCount) { +using gui::WindowInfo; +void BufferStateLayer::callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, + const sp<GraphicBuffer>& buffer, + uint64_t framenumber, + const sp<Fence>& releaseFence, + uint32_t currentMaxAcquiredBufferCount) { if (!listener) { return; } + ATRACE_FORMAT_INSTANT("callReleaseBufferCallback %s - %" PRIu64, getDebugName(), framenumber); listener->onReleaseBuffer({buffer->getId(), framenumber}, releaseFence ? releaseFence : Fence::NO_FENCE, currentMaxAcquiredBufferCount); } + +namespace { +static constexpr float defaultMaxLuminance = 1000.0; } // namespace BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args) - : BufferLayer(args), mHwcSlotGenerator(new HwcSlotGenerator()) { + : Layer(args), + mTextureName(args.textureName), + mCompositionState{mFlinger->getCompositionEngine().createLayerFECompositionState()}, + mHwcSlotGenerator(new HwcSlotGenerator()) { + ALOGV("Creating Layer %s", getDebugName()); + + mPremultipliedAlpha = !(args.flags & ISurfaceComposerClient::eNonPremultiplied); + + mPotentialCursor = args.flags & ISurfaceComposerClient::eCursorWindow; + mProtectedByApp = args.flags & ISurfaceComposerClient::eProtectedByApp; mDrawingState.dataspace = ui::Dataspace::V0_SRGB; } @@ -70,6 +115,16 @@ BufferStateLayer::~BufferStateLayer() { mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate( mOwnerUid)); } + if (!isClone()) { + // The original layer and the clone layer share the same texture. Therefore, only one of + // the layers, in this case the original layer, needs to handle the deletion. The original + // layer and the clone should be removed at the same time so there shouldn't be any issue + // with the clone layer trying to use the deleted texture. + mFlinger->deleteTextureAsync(mTextureName); + } + const int32_t layerId = getSequence(); + mFlinger->mTimeStats->onDestroy(layerId); + mFlinger->mFrameTracer->onDestroy(layerId); } // ----------------------------------------------------------------------- @@ -145,6 +200,8 @@ void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) { handle->dequeueReadyTime = dequeueReadyTime; handle->currentMaxAcquiredBufferCount = mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mOwnerUid); + ATRACE_FORMAT_INSTANT("releasePendingBuffer %s - %" PRIu64, getDebugName(), + handle->previousReleaseCallbackId.framenumber); } for (auto& handle : mDrawingState.callbackHandles) { @@ -569,10 +626,6 @@ FloatRect BufferStateLayer::computeSourceBounds(const FloatRect& parentBounds) c } // ----------------------------------------------------------------------- - -// ----------------------------------------------------------------------- -// Interface implementation for BufferLayer -// ----------------------------------------------------------------------- bool BufferStateLayer::fenceHasSignaled() const { if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { return true; @@ -600,7 +653,7 @@ bool BufferStateLayer::onPreComposition(nsecs_t refreshStartTime) { for (const auto& handle : mDrawingState.callbackHandles) { handle->refreshStartTime = refreshStartTime; } - return BufferLayer::onPreComposition(refreshStartTime); + return hasReadyFrame(); } void BufferStateLayer::setAutoRefresh(bool autoRefresh) { @@ -785,7 +838,9 @@ void BufferStateLayer::HwcSlotGenerator::eraseBufferLocked(const client_cache_t& } void BufferStateLayer::gatherBufferInfo() { - BufferLayer::gatherBufferInfo(); + mBufferInfo.mPixelFormat = + !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->getPixelFormat(); + mBufferInfo.mFrameLatencyNeeded = true; const State& s(getDrawingState()); mBufferInfo.mDesiredPresentTime = s.desiredPresentTime; @@ -853,7 +908,15 @@ bool BufferStateLayer::bufferNeedsFiltering() const { } const Rect layerSize{getBounds()}; - return layerSize.width() != bufferWidth || layerSize.height() != bufferHeight; + int32_t layerWidth = layerSize.getWidth(); + int32_t layerHeight = layerSize.getHeight(); + + // Align the layer orientation with the buffer before comparism + if (mTransformHint & ui::Transform::ROT_90) { + std::swap(layerWidth, layerHeight); + } + + return layerWidth != bufferWidth || layerHeight != bufferHeight; } void BufferStateLayer::decrementPendingBufferCount() { @@ -1082,4 +1145,619 @@ bool BufferStateLayer::simpleBufferUpdate(const layer_state_t& s) const { return true; } +void BufferStateLayer::useSurfaceDamage() { + if (mFlinger->mForceFullDamage) { + surfaceDamageRegion = Region::INVALID_REGION; + } else { + surfaceDamageRegion = mBufferInfo.mSurfaceDamage; + } +} + +void BufferStateLayer::useEmptyDamage() { + surfaceDamageRegion.clear(); +} + +bool BufferStateLayer::isOpaque(const Layer::State& s) const { + // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the + // layer's opaque flag. + if ((mSidebandStream == nullptr) && (mBufferInfo.mBuffer == nullptr)) { + return false; + } + + // if the layer has the opaque flag, then we're always opaque, + // otherwise we use the current buffer's format. + return ((s.flags & layer_state_t::eLayerOpaque) != 0) || getOpacityForFormat(getPixelFormat()); +} + +bool BufferStateLayer::canReceiveInput() const { + return !isHiddenByPolicy() && (mBufferInfo.mBuffer == nullptr || getAlpha() > 0.0f); +} + +bool BufferStateLayer::isVisible() const { + return !isHiddenByPolicy() && getAlpha() > 0.0f && + (mBufferInfo.mBuffer != nullptr || mSidebandStream != nullptr); +} + +bool BufferStateLayer::isFixedSize() const { + return true; +} + +bool BufferStateLayer::usesSourceCrop() const { + return true; +} + +static constexpr mat4 inverseOrientation(uint32_t transform) { + const mat4 flipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); + const mat4 flipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1); + const mat4 rot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); + mat4 tr; + + if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { + tr = tr * rot90; + } + if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { + tr = tr * flipH; + } + if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { + tr = tr * flipV; + } + return inverse(tr); +} + +std::optional<compositionengine::LayerFE::LayerSettings> BufferStateLayer::prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) { + ATRACE_CALL(); + + std::optional<compositionengine::LayerFE::LayerSettings> result = + Layer::prepareClientComposition(targetSettings); + if (!result) { + return result; + } + + if (CC_UNLIKELY(mBufferInfo.mBuffer == 0) && mSidebandStream != nullptr) { + // For surfaceview of tv sideband, there is no activeBuffer + // in bufferqueue, we need return LayerSettings. + return result; + } + const bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) || + ((isSecure() || isProtected()) && !targetSettings.isSecure); + const bool bufferCanBeUsedAsHwTexture = + mBufferInfo.mBuffer->getUsage() & GraphicBuffer::USAGE_HW_TEXTURE; + compositionengine::LayerFE::LayerSettings& layer = *result; + if (blackOutLayer || !bufferCanBeUsedAsHwTexture) { + ALOGE_IF(!bufferCanBeUsedAsHwTexture, "%s is blacked out as buffer is not gpu readable", + mName.c_str()); + prepareClearClientComposition(layer, true /* blackout */); + return layer; + } + + const State& s(getDrawingState()); + layer.source.buffer.buffer = mBufferInfo.mBuffer; + layer.source.buffer.isOpaque = isOpaque(s); + layer.source.buffer.fence = mBufferInfo.mFence; + layer.source.buffer.textureName = mTextureName; + layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha(); + layer.source.buffer.isY410BT2020 = isHdrY410(); + bool hasSmpte2086 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::SMPTE2086; + bool hasCta861_3 = mBufferInfo.mHdrMetadata.validTypes & HdrMetadata::CTA861_3; + float maxLuminance = 0.f; + if (hasSmpte2086 && hasCta861_3) { + maxLuminance = std::min(mBufferInfo.mHdrMetadata.smpte2086.maxLuminance, + mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel); + } else if (hasSmpte2086) { + maxLuminance = mBufferInfo.mHdrMetadata.smpte2086.maxLuminance; + } else if (hasCta861_3) { + maxLuminance = mBufferInfo.mHdrMetadata.cta8613.maxContentLightLevel; + } else { + switch (layer.sourceDataspace & HAL_DATASPACE_TRANSFER_MASK) { + case HAL_DATASPACE_TRANSFER_ST2084: + case HAL_DATASPACE_TRANSFER_HLG: + // Behavior-match previous releases for HDR content + maxLuminance = defaultMaxLuminance; + break; + } + } + layer.source.buffer.maxLuminanceNits = maxLuminance; + layer.frameNumber = mCurrentFrameNumber; + layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0; + + const bool useFiltering = + targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering(); + + // Query the texture matrix given our current filtering mode. + float textureMatrix[16]; + getDrawingTransformMatrix(useFiltering, textureMatrix); + + if (getTransformToDisplayInverse()) { + /* + * the code below applies the primary display's inverse transform to + * the texture transform + */ + uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags(); + mat4 tr = inverseOrientation(transform); + + /** + * TODO(b/36727915): This is basically a hack. + * + * Ensure that regardless of the parent transformation, + * this buffer is always transformed from native display + * orientation to display orientation. For example, in the case + * of a camera where the buffer remains in native orientation, + * we want the pixels to always be upright. + */ + sp<Layer> p = mDrawingParent.promote(); + if (p != nullptr) { + const auto parentTransform = p->getTransform(); + tr = tr * inverseOrientation(parentTransform.getOrientation()); + } + + // and finally apply it to the original texture matrix + const mat4 texTransform(mat4(static_cast<const float*>(textureMatrix)) * tr); + memcpy(textureMatrix, texTransform.asArray(), sizeof(textureMatrix)); + } + + const Rect win{getBounds()}; + float bufferWidth = getBufferSize(s).getWidth(); + float bufferHeight = getBufferSize(s).getHeight(); + + // BufferStateLayers can have a "buffer size" of [0, 0, -1, -1] when no display frame has + // been set and there is no parent layer bounds. In that case, the scale is meaningless so + // ignore them. + if (!getBufferSize(s).isValid()) { + bufferWidth = float(win.right) - float(win.left); + bufferHeight = float(win.bottom) - float(win.top); + } + + const float scaleHeight = (float(win.bottom) - float(win.top)) / bufferHeight; + const float scaleWidth = (float(win.right) - float(win.left)) / bufferWidth; + const float translateY = float(win.top) / bufferHeight; + const float translateX = float(win.left) / bufferWidth; + + // Flip y-coordinates because GLConsumer expects OpenGL convention. + mat4 tr = mat4::translate(vec4(.5f, .5f, 0.f, 1.f)) * mat4::scale(vec4(1.f, -1.f, 1.f, 1.f)) * + mat4::translate(vec4(-.5f, -.5f, 0.f, 1.f)) * + mat4::translate(vec4(translateX, translateY, 0.f, 1.f)) * + mat4::scale(vec4(scaleWidth, scaleHeight, 1.0f, 1.0f)); + + layer.source.buffer.useTextureFiltering = useFiltering; + layer.source.buffer.textureTransform = mat4(static_cast<const float*>(textureMatrix)) * tr; + + return layer; +} + +bool BufferStateLayer::isHdrY410() const { + // pixel format is HDR Y410 masquerading as RGBA_1010102 + return (mBufferInfo.mDataspace == ui::Dataspace::BT2020_ITU_PQ && + mBufferInfo.mApi == NATIVE_WINDOW_API_MEDIA && + mBufferInfo.mPixelFormat == HAL_PIXEL_FORMAT_RGBA_1010102); +} + +sp<compositionengine::LayerFE> BufferStateLayer::getCompositionEngineLayerFE() const { + return asLayerFE(); +} + +compositionengine::LayerFECompositionState* BufferStateLayer::editCompositionState() { + return mCompositionState.get(); +} + +const compositionengine::LayerFECompositionState* BufferStateLayer::getCompositionState() const { + return mCompositionState.get(); +} + +void BufferStateLayer::preparePerFrameCompositionState() { + Layer::preparePerFrameCompositionState(); + + // Sideband layers + auto* compositionState = editCompositionState(); + if (compositionState->sidebandStream.get() && !compositionState->sidebandStreamHasFrame) { + compositionState->compositionType = + aidl::android::hardware::graphics::composer3::Composition::SIDEBAND; + return; + } else if ((mDrawingState.flags & layer_state_t::eLayerIsDisplayDecoration) != 0) { + compositionState->compositionType = + aidl::android::hardware::graphics::composer3::Composition::DISPLAY_DECORATION; + } else { + // Normal buffer layers + compositionState->hdrMetadata = mBufferInfo.mHdrMetadata; + compositionState->compositionType = mPotentialCursor + ? aidl::android::hardware::graphics::composer3::Composition::CURSOR + : aidl::android::hardware::graphics::composer3::Composition::DEVICE; + } + + compositionState->buffer = getBuffer(); + compositionState->bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) + ? 0 + : mBufferInfo.mBufferSlot; + compositionState->acquireFence = mBufferInfo.mFence; + compositionState->frameNumber = mBufferInfo.mFrameNumber; + compositionState->sidebandStreamHasFrame = false; +} + +namespace { +TimeStats::SetFrameRateVote frameRateToSetFrameRateVotePayload(Layer::FrameRate frameRate) { + using FrameRateCompatibility = TimeStats::SetFrameRateVote::FrameRateCompatibility; + using Seamlessness = TimeStats::SetFrameRateVote::Seamlessness; + const auto frameRateCompatibility = [frameRate] { + switch (frameRate.type) { + case Layer::FrameRateCompatibility::Default: + return FrameRateCompatibility::Default; + case Layer::FrameRateCompatibility::ExactOrMultiple: + return FrameRateCompatibility::ExactOrMultiple; + default: + return FrameRateCompatibility::Undefined; + } + }(); + + const auto seamlessness = [frameRate] { + switch (frameRate.seamlessness) { + case scheduler::Seamlessness::OnlySeamless: + return Seamlessness::ShouldBeSeamless; + case scheduler::Seamlessness::SeamedAndSeamless: + return Seamlessness::NotRequired; + default: + return Seamlessness::Undefined; + } + }(); + + return TimeStats::SetFrameRateVote{.frameRate = frameRate.rate.getValue(), + .frameRateCompatibility = frameRateCompatibility, + .seamlessness = seamlessness}; +} +} // namespace + +void BufferStateLayer::onPostComposition(const DisplayDevice* display, + const std::shared_ptr<FenceTime>& glDoneFence, + const std::shared_ptr<FenceTime>& presentFence, + const CompositorTiming& compositorTiming) { + // mFrameLatencyNeeded is true when a new frame was latched for the + // composition. + if (!mBufferInfo.mFrameLatencyNeeded) return; + + // Update mFrameEventHistory. + finalizeFrameEventHistory(glDoneFence, compositorTiming); + + // Update mFrameTracker. + nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime; + mFrameTracker.setDesiredPresentTime(desiredPresentTime); + + const int32_t layerId = getSequence(); + mFlinger->mTimeStats->setDesiredTime(layerId, mCurrentFrameNumber, desiredPresentTime); + + const auto outputLayer = findOutputLayerForDisplay(display); + if (outputLayer && outputLayer->requiresClientComposition()) { + nsecs_t clientCompositionTimestamp = outputLayer->getState().clientCompositionTimestamp; + mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber, + clientCompositionTimestamp, + FrameTracer::FrameEvent::FALLBACK_COMPOSITION); + // Update the SurfaceFrames in the drawing state + if (mDrawingState.bufferSurfaceFrameTX) { + mDrawingState.bufferSurfaceFrameTX->setGpuComposition(); + } + for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) { + surfaceFrame->setGpuComposition(); + } + } + + std::shared_ptr<FenceTime> frameReadyFence = mBufferInfo.mFenceTime; + if (frameReadyFence->isValid()) { + mFrameTracker.setFrameReadyFence(std::move(frameReadyFence)); + } else { + // There was no fence for this frame, so assume that it was ready + // to be presented at the desired present time. + mFrameTracker.setFrameReadyTime(desiredPresentTime); + } + + if (display) { + const Fps refreshRate = display->refreshRateConfigs().getActiveMode()->getFps(); + const std::optional<Fps> renderRate = + mFlinger->mScheduler->getFrameRateOverride(getOwnerUid()); + + const auto vote = frameRateToSetFrameRateVotePayload(mDrawingState.frameRate); + const auto gameMode = getGameMode(); + + if (presentFence->isValid()) { + mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence, + refreshRate, renderRate, vote, gameMode); + mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber, + presentFence, + FrameTracer::FrameEvent::PRESENT_FENCE); + mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence)); + } else if (const auto displayId = PhysicalDisplayId::tryCast(display->getId()); + displayId && mFlinger->getHwComposer().isConnected(*displayId)) { + // The HWC doesn't support present fences, so use the refresh + // timestamp instead. + const nsecs_t actualPresentTime = display->getRefreshTimestamp(); + mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime, + refreshRate, renderRate, vote, gameMode); + mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), + mCurrentFrameNumber, actualPresentTime, + FrameTracer::FrameEvent::PRESENT_FENCE); + mFrameTracker.setActualPresentTime(actualPresentTime); + } + } + + mFrameTracker.advanceFrame(); + mBufferInfo.mFrameLatencyNeeded = false; +} + +bool BufferStateLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, + nsecs_t expectedPresentTime) { + ATRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(), + getDrawingState().frameNumber); + + bool refreshRequired = latchSidebandStream(recomputeVisibleRegions); + + if (refreshRequired) { + return refreshRequired; + } + + // If the head buffer's acquire fence hasn't signaled yet, return and + // try again later + if (!fenceHasSignaled()) { + ATRACE_NAME("!fenceHasSignaled()"); + mFlinger->onLayerUpdate(); + return false; + } + + // Capture the old state of the layer for comparisons later + const State& s(getDrawingState()); + const bool oldOpacity = isOpaque(s); + + BufferInfo oldBufferInfo = mBufferInfo; + + status_t err = updateTexImage(recomputeVisibleRegions, latchTime, expectedPresentTime); + if (err != NO_ERROR) { + return false; + } + + err = updateActiveBuffer(); + if (err != NO_ERROR) { + return false; + } + + err = updateFrameNumber(); + if (err != NO_ERROR) { + return false; + } + + gatherBufferInfo(); + + if (oldBufferInfo.mBuffer == nullptr) { + // the first time we receive a buffer, we need to trigger a + // geometry invalidation. + recomputeVisibleRegions = true; + } + + if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) || + (mBufferInfo.mTransform != oldBufferInfo.mTransform) || + (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) || + (mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) { + recomputeVisibleRegions = true; + } + + if (oldBufferInfo.mBuffer != nullptr) { + uint32_t bufWidth = mBufferInfo.mBuffer->getWidth(); + uint32_t bufHeight = mBufferInfo.mBuffer->getHeight(); + if (bufWidth != oldBufferInfo.mBuffer->getWidth() || + bufHeight != oldBufferInfo.mBuffer->getHeight()) { + recomputeVisibleRegions = true; + } + } + + if (oldOpacity != isOpaque(s)) { + recomputeVisibleRegions = true; + } + + return true; +} + +bool BufferStateLayer::hasReadyFrame() const { + return hasFrameUpdate() || getSidebandStreamChanged() || getAutoRefresh(); +} + +bool BufferStateLayer::isProtected() const { + return (mBufferInfo.mBuffer != nullptr) && + (mBufferInfo.mBuffer->getUsage() & GRALLOC_USAGE_PROTECTED); +} + +// As documented in libhardware header, formats in the range +// 0x100 - 0x1FF are specific to the HAL implementation, and +// are known to have no alpha channel +// TODO: move definition for device-specific range into +// hardware.h, instead of using hard-coded values here. +#define HARDWARE_IS_DEVICE_FORMAT(f) ((f) >= 0x100 && (f) <= 0x1FF) + +bool BufferStateLayer::getOpacityForFormat(PixelFormat format) { + if (HARDWARE_IS_DEVICE_FORMAT(format)) { + return true; + } + switch (format) { + case PIXEL_FORMAT_RGBA_8888: + case PIXEL_FORMAT_BGRA_8888: + case PIXEL_FORMAT_RGBA_FP16: + case PIXEL_FORMAT_RGBA_1010102: + case PIXEL_FORMAT_R_8: + return false; + } + // in all other case, we have no blending (also for unknown formats) + return true; +} + +bool BufferStateLayer::needsFiltering(const DisplayDevice* display) const { + const auto outputLayer = findOutputLayerForDisplay(display); + if (outputLayer == nullptr) { + return false; + } + + // We need filtering if the sourceCrop rectangle size does not match the + // displayframe rectangle size (not a 1:1 render) + const auto& compositionState = outputLayer->getState(); + const auto displayFrame = compositionState.displayFrame; + const auto sourceCrop = compositionState.sourceCrop; + return sourceCrop.getHeight() != displayFrame.getHeight() || + sourceCrop.getWidth() != displayFrame.getWidth(); +} + +bool BufferStateLayer::needsFilteringForScreenshots( + const DisplayDevice* display, const ui::Transform& inverseParentTransform) const { + const auto outputLayer = findOutputLayerForDisplay(display); + if (outputLayer == nullptr) { + return false; + } + + // We need filtering if the sourceCrop rectangle size does not match the + // viewport rectangle size (not a 1:1 render) + const auto& compositionState = outputLayer->getState(); + const ui::Transform& displayTransform = display->getTransform(); + const ui::Transform inverseTransform = inverseParentTransform * displayTransform.inverse(); + // Undo the transformation of the displayFrame so that we're back into + // layer-stack space. + const Rect frame = inverseTransform.transform(compositionState.displayFrame); + const FloatRect sourceCrop = compositionState.sourceCrop; + + int32_t frameHeight = frame.getHeight(); + int32_t frameWidth = frame.getWidth(); + // If the display transform had a rotational component then undo the + // rotation so that the orientation matches the source crop. + if (displayTransform.getOrientation() & ui::Transform::ROT_90) { + std::swap(frameHeight, frameWidth); + } + return sourceCrop.getHeight() != frameHeight || sourceCrop.getWidth() != frameWidth; +} + +void BufferStateLayer::latchAndReleaseBuffer() { + if (hasReadyFrame()) { + bool ignored = false; + latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */); + } + releasePendingBuffer(systemTime()); +} + +PixelFormat BufferStateLayer::getPixelFormat() const { + return mBufferInfo.mPixelFormat; +} + +bool BufferStateLayer::getTransformToDisplayInverse() const { + return mBufferInfo.mTransformToDisplayInverse; +} + +Rect BufferStateLayer::getBufferCrop() const { + // this is the crop rectangle that applies to the buffer + // itself (as opposed to the window) + if (!mBufferInfo.mCrop.isEmpty()) { + // if the buffer crop is defined, we use that + return mBufferInfo.mCrop; + } else if (mBufferInfo.mBuffer != nullptr) { + // otherwise we use the whole buffer + return mBufferInfo.mBuffer->getBounds(); + } else { + // if we don't have a buffer yet, we use an empty/invalid crop + return Rect(); + } +} + +uint32_t BufferStateLayer::getBufferTransform() const { + return mBufferInfo.mTransform; +} + +ui::Dataspace BufferStateLayer::getDataSpace() const { + return mBufferInfo.mDataspace; +} + +ui::Dataspace BufferStateLayer::translateDataspace(ui::Dataspace dataspace) { + ui::Dataspace updatedDataspace = dataspace; + // translate legacy dataspaces to modern dataspaces + switch (dataspace) { + case ui::Dataspace::SRGB: + updatedDataspace = ui::Dataspace::V0_SRGB; + break; + case ui::Dataspace::SRGB_LINEAR: + updatedDataspace = ui::Dataspace::V0_SRGB_LINEAR; + break; + case ui::Dataspace::JFIF: + updatedDataspace = ui::Dataspace::V0_JFIF; + break; + case ui::Dataspace::BT601_625: + updatedDataspace = ui::Dataspace::V0_BT601_625; + break; + case ui::Dataspace::BT601_525: + updatedDataspace = ui::Dataspace::V0_BT601_525; + break; + case ui::Dataspace::BT709: + updatedDataspace = ui::Dataspace::V0_BT709; + break; + default: + break; + } + + return updatedDataspace; +} + +sp<GraphicBuffer> BufferStateLayer::getBuffer() const { + return mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getBuffer() : nullptr; +} + +void BufferStateLayer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) { + sp<GraphicBuffer> buffer = getBuffer(); + if (!buffer) { + ALOGE("Buffer should not be null!"); + return; + } + GLConsumer::computeTransformMatrix(outMatrix, buffer->getWidth(), buffer->getHeight(), + buffer->getPixelFormat(), mBufferInfo.mCrop, + mBufferInfo.mTransform, filteringEnabled); +} + +void BufferStateLayer::setInitialValuesForClone(const sp<Layer>& clonedFrom) { + Layer::setInitialValuesForClone(clonedFrom); + + sp<BufferStateLayer> bufferClonedFrom = static_cast<BufferStateLayer*>(clonedFrom.get()); + mPremultipliedAlpha = bufferClonedFrom->mPremultipliedAlpha; + mPotentialCursor = bufferClonedFrom->mPotentialCursor; + mProtectedByApp = bufferClonedFrom->mProtectedByApp; + + updateCloneBufferInfo(); +} + +void BufferStateLayer::updateCloneBufferInfo() { + if (!isClone() || !isClonedFromAlive()) { + return; + } + + sp<BufferStateLayer> clonedFrom = static_cast<BufferStateLayer*>(getClonedFrom().get()); + mBufferInfo = clonedFrom->mBufferInfo; + mSidebandStream = clonedFrom->mSidebandStream; + surfaceDamageRegion = clonedFrom->surfaceDamageRegion; + mCurrentFrameNumber = clonedFrom->mCurrentFrameNumber.load(); + mPreviousFrameNumber = clonedFrom->mPreviousFrameNumber; + + // After buffer info is updated, the drawingState from the real layer needs to be copied into + // the cloned. This is because some properties of drawingState can change when latchBuffer is + // called. However, copying the drawingState would also overwrite the cloned layer's relatives + // and touchableRegionCrop. Therefore, temporarily store the relatives so they can be set in + // the cloned drawingState again. + wp<Layer> tmpZOrderRelativeOf = mDrawingState.zOrderRelativeOf; + SortedVector<wp<Layer>> tmpZOrderRelatives = mDrawingState.zOrderRelatives; + wp<Layer> tmpTouchableRegionCrop = mDrawingState.touchableRegionCrop; + WindowInfo tmpInputInfo = mDrawingState.inputInfo; + + cloneDrawingState(clonedFrom.get()); + + mDrawingState.touchableRegionCrop = tmpTouchableRegionCrop; + mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf; + mDrawingState.zOrderRelatives = tmpZOrderRelatives; + mDrawingState.inputInfo = tmpInputInfo; +} + +void BufferStateLayer::setTransformHint(ui::Transform::RotationFlags displayTransformHint) { + mTransformHint = getFixedTransformHint(); + if (mTransformHint == ui::Transform::ROT_INVALID) { + mTransformHint = displayTransformHint; + } +} + +const std::shared_ptr<renderengine::ExternalTexture>& BufferStateLayer::getExternalTexture() const { + return mBufferInfo.mBuffer; +} + } // namespace android diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 3f0dbe4039..df7ae611b8 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -16,27 +16,106 @@ #pragma once -#include "BufferLayer.h" -#include "Layer.h" +#include <sys/types.h> +#include <cstdint> +#include <list> +#include <stack> +#include <android/gui/ISurfaceComposerClient.h> +#include <gui/LayerState.h> #include <renderengine/Image.h> +#include <renderengine/Mesh.h> #include <renderengine/RenderEngine.h> -#include <system/window.h> +#include <renderengine/Texture.h> +#include <system/window.h> // For NATIVE_WINDOW_SCALING_MODE_FREEZE +#include <ui/FrameStats.h> +#include <ui/GraphicBuffer.h> +#include <ui/PixelFormat.h> +#include <ui/Region.h> +#include <utils/RefBase.h> #include <utils/String8.h> +#include <utils/Timers.h> -#include <stack> +#include "Client.h" +#include "DisplayHardware/HWComposer.h" +#include "FrameTimeline.h" +#include "FrameTracker.h" +#include "Layer.h" +#include "LayerVector.h" +#include "SurfaceFlinger.h" namespace android { class SlotGenerationTest; -class BufferStateLayer : public BufferLayer { +class BufferStateLayer : public Layer { public: explicit BufferStateLayer(const LayerCreationArgs&); ~BufferStateLayer() override; // Implements Layer. + sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const override; + compositionengine::LayerFECompositionState* editCompositionState() override; + + // If we have received a new buffer this frame, we will pass its surface + // damage down to hardware composer. Otherwise, we must send a region with + // one empty rect. + void useSurfaceDamage() override; + void useEmptyDamage() override; + + bool isOpaque(const Layer::State& s) const override; + bool canReceiveInput() const override; + + // isVisible - true if this layer is visible, false otherwise + bool isVisible() const override; + + // isProtected - true if the layer may contain protected content in the + // GRALLOC_USAGE_PROTECTED sense. + bool isProtected() const override; + + // isFixedSize - true if content has a fixed size + bool isFixedSize() const override; + + bool usesSourceCrop() const override; + + bool isHdrY410() const override; + + void onPostComposition(const DisplayDevice*, const std::shared_ptr<FenceTime>& glDoneFence, + const std::shared_ptr<FenceTime>& presentFence, + const CompositorTiming&) override; + + // latchBuffer - called each time the screen is redrawn and returns whether + // the visible regions need to be recomputed (this is a fairly heavy + // operation, so this should be set only if needed). Typically this is used + // to figure out if the content or size of a surface has changed. + bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime, + nsecs_t expectedPresentTime) override; + bool hasReadyFrame() const override; + + // Returns the current scaling mode + uint32_t getEffectiveScalingMode() const override; + + // Calls latchBuffer if the buffer has a frame queued and then releases the buffer. + // This is used if the buffer is just latched and releases to free up the buffer + // and will not be shown on screen. + // Should only be called on the main thread. + void latchAndReleaseBuffer() override; + + bool getTransformToDisplayInverse() const override; + + Rect getBufferCrop() const override; + + uint32_t getBufferTransform() const override; + + ui::Dataspace getDataSpace() const override; + + sp<GraphicBuffer> getBuffer() const override; + const std::shared_ptr<renderengine::ExternalTexture>& getExternalTexture() const override; + + ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; } + + // Implements Layer. const char* getType() const override { return "BufferStateLayer"; } void onLayerDisplayed(ftl::SharedFuture<FenceResult>) override; @@ -46,7 +125,10 @@ public: void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence, const CompositorTiming& compositorTiming) override; - bool isBufferDue(nsecs_t /*expectedPresentTime*/) const override { return true; } + // Returns true if the next buffer should be presented at the expected present time, + // overridden by BufferStateLayer and BufferQueueLayer for implementation + // specific logic + bool isBufferDue(nsecs_t /*expectedPresentTime*/) const { return true; } Region getActiveTransparentRegion(const Layer::State& s) const override { return s.transparentRegionHint; @@ -73,6 +155,8 @@ public: bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; } bool setTransparentRegionHint(const Region& transparent) override; + // BufferStateLayers can return Rect::INVALID_RECT if the layer does not have a display frame + // and its parent layer is not bounded Rect getBufferSize(const State& s) const override; FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; void setAutoRefresh(bool autoRefresh) override; @@ -81,48 +165,114 @@ public: bool setDestinationFrame(const Rect& destinationFrame) override; bool updateGeometry() override; - // ----------------------------------------------------------------------- - - // ----------------------------------------------------------------------- - // Interface implementation for BufferLayer - // ----------------------------------------------------------------------- - bool fenceHasSignaled() const override; - bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override; - bool onPreComposition(nsecs_t refreshStartTime) override; - uint32_t getEffectiveScalingMode() const override; + bool fenceHasSignaled() const; + bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const; + bool onPreComposition(nsecs_t) override; // See mPendingBufferTransactions void decrementPendingBufferCount(); std::atomic<int32_t>* getPendingBufferCounter() override { return &mPendingBufferTransactions; } std::string getPendingBufferCounterName() override { return mBlastTransactionName; } + // Returns true if the next buffer should be presented at the expected present time bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const override { return true; } protected: - void gatherBufferInfo() override; + void gatherBufferInfo(); void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame); ui::Transform getInputTransform() const override; Rect getInputBounds() const override; + struct BufferInfo { + nsecs_t mDesiredPresentTime; + std::shared_ptr<FenceTime> mFenceTime; + sp<Fence> mFence; + uint32_t mTransform{0}; + ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN}; + Rect mCrop; + uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE}; + Region mSurfaceDamage; + HdrMetadata mHdrMetadata; + int mApi; + PixelFormat mPixelFormat{PIXEL_FORMAT_NONE}; + bool mTransformToDisplayInverse{false}; + + std::shared_ptr<renderengine::ExternalTexture> mBuffer; + uint64_t mFrameNumber; + int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT}; + + bool mFrameLatencyNeeded{false}; + }; + + BufferInfo mBufferInfo; + + std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition( + compositionengine::LayerFE::ClientCompositionTargetSettings&) override; + + /* + * compositionengine::LayerFE overrides + */ + const compositionengine::LayerFECompositionState* getCompositionState() const override; + void preparePerFrameCompositionState() override; + + static bool getOpacityForFormat(PixelFormat format); + + // from graphics API + const uint32_t mTextureName; + ui::Dataspace translateDataspace(ui::Dataspace dataspace); + void setInitialValuesForClone(const sp<Layer>& clonedFrom); + void updateCloneBufferInfo() override; + uint64_t mPreviousFrameNumber = 0; + + void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override; + + // Transform hint provided to the producer. This must be accessed holding + // the mStateLock. + ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0; + + bool getAutoRefresh() const { return mDrawingState.autoRefresh; } + bool getSidebandStreamChanged() const { return mSidebandStreamChanged; } + + std::atomic<bool> mSidebandStreamChanged{false}; + private: friend class SlotGenerationTest; friend class TransactionFrameTracerTest; friend class TransactionSurfaceFrameTest; + // We generate InputWindowHandles for all non-cursor buffered layers regardless of whether they + // have an InputChannel. This is to enable the InputDispatcher to do PID based occlusion + // detection. + bool needsInputInfo() const override { return !mPotentialCursor; } + + // Returns true if this layer requires filtering + bool needsFiltering(const DisplayDevice*) const override; + bool needsFilteringForScreenshots(const DisplayDevice*, + const ui::Transform& inverseParentTransform) const override; + + PixelFormat getPixelFormat() const; + + // Computes the transform matrix using the setFilteringEnabled to determine whether the + // transform matrix should be computed for use with bilinear filtering. + void getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]); + + std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState; + inline void tracePendingBufferCount(int32_t pendingBuffers); bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime, nsecs_t requestedPresentTime); - bool latchSidebandStream(bool& recomputeVisibleRegions) override; + // Latch sideband stream and returns true if the dirty region should be updated. + bool latchSidebandStream(bool& recomputeVisibleRegions); - bool hasFrameUpdate() const override; + bool hasFrameUpdate() const; status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime, - nsecs_t expectedPresentTime) override; + nsecs_t expectedPresentTime); - status_t updateActiveBuffer() override; - status_t updateFrameNumber() override; + status_t updateActiveBuffer(); + status_t updateFrameNumber(); sp<Layer> createClone() override; @@ -131,10 +281,17 @@ private: bool willPresentCurrentTransaction() const; - bool bufferNeedsFiltering() const override; + // Returns true if the transformed buffer size does not match the layer size and we need + // to apply filtering. + bool bufferNeedsFiltering() const; bool simpleBufferUpdate(const layer_state_t& s) const override; + void callReleaseBufferCallback(const sp<ITransactionCompletedListener>& listener, + const sp<GraphicBuffer>& buffer, uint64_t framenumber, + const sp<Fence>& releaseFence, + uint32_t currentMaxAcquiredBufferCount); + ReleaseCallbackId mPreviousReleaseCallbackId = ReleaseCallbackId::INVALID_ID; uint64_t mPreviousReleasedFrameNumber = 0; diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index 6d7b732b36..b27055d57a 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -21,12 +21,16 @@ #include <private/android_filesystem_config.h> +#include <gui/AidlStatusUtil.h> + #include "Client.h" #include "Layer.h" #include "SurfaceFlinger.h" namespace android { +using gui::aidl_utils::binderStatusFromStatusT; + // --------------------------------------------------------------------------- const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER"); @@ -72,52 +76,74 @@ sp<Layer> Client::getLayerUser(const sp<IBinder>& handle) const return lbc; } -status_t Client::createSurface(const String8& name, uint32_t /* w */, uint32_t /* h */, - PixelFormat /* format */, uint32_t flags, - const sp<IBinder>& parentHandle, LayerMetadata metadata, - sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* /* gbp */, - int32_t* outLayerId, uint32_t* outTransformHint) { +binder::Status Client::createSurface(const std::string& name, int32_t flags, + const sp<IBinder>& parent, const gui::LayerMetadata& metadata, + gui::CreateSurfaceResult* outResult) { // We rely on createLayer to check permissions. - LayerCreationArgs args(mFlinger.get(), this, name.c_str(), flags, std::move(metadata)); - return mFlinger->createLayer(args, outHandle, parentHandle, outLayerId, nullptr, - outTransformHint); -} - -status_t Client::createWithSurfaceParent(const String8& /* name */, uint32_t /* w */, - uint32_t /* h */, PixelFormat /* format */, - uint32_t /* flags */, - const sp<IGraphicBufferProducer>& /* parent */, - LayerMetadata /* metadata */, sp<IBinder>* /* handle */, - sp<IGraphicBufferProducer>* /* gbp */, - int32_t* /* outLayerId */, - uint32_t* /* outTransformHint */) { - // This api does not make sense with blast since SF no longer tracks IGBP. This api should be - // removed. - return BAD_VALUE; -} - -status_t Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle, - int32_t* outLayerId) { - LayerCreationArgs args(mFlinger.get(), this, "MirrorRoot", 0 /* flags */, LayerMetadata()); - return mFlinger->mirrorLayer(args, mirrorFromHandle, outHandle, outLayerId); + sp<IBinder> handle; + int32_t layerId; + uint32_t transformHint; + LayerCreationArgs args(mFlinger.get(), this, name.c_str(), static_cast<uint32_t>(flags), + std::move(metadata)); + const status_t status = + mFlinger->createLayer(args, &handle, parent, &layerId, nullptr, &transformHint); + if (status == NO_ERROR) { + outResult->handle = handle; + outResult->layerId = layerId; + outResult->transformHint = static_cast<int32_t>(transformHint); + } + return binderStatusFromStatusT(status); } -status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const { +binder::Status Client::clearLayerFrameStats(const sp<IBinder>& handle) { + status_t status; sp<Layer> layer = getLayerUser(handle); if (layer == nullptr) { - return NAME_NOT_FOUND; + status = NAME_NOT_FOUND; + } else { + layer->clearFrameStats(); + status = NO_ERROR; } - layer->clearFrameStats(); - return NO_ERROR; + return binderStatusFromStatusT(status); } -status_t Client::getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const { +binder::Status Client::getLayerFrameStats(const sp<IBinder>& handle, gui::FrameStats* outStats) { + status_t status; sp<Layer> layer = getLayerUser(handle); if (layer == nullptr) { - return NAME_NOT_FOUND; + status = NAME_NOT_FOUND; + } else { + FrameStats stats; + layer->getFrameStats(&stats); + outStats->refreshPeriodNano = stats.refreshPeriodNano; + outStats->desiredPresentTimesNano.reserve(stats.desiredPresentTimesNano.size()); + for (const auto& t : stats.desiredPresentTimesNano) { + outStats->desiredPresentTimesNano.push_back(t); + } + outStats->actualPresentTimesNano.reserve(stats.actualPresentTimesNano.size()); + for (const auto& t : stats.actualPresentTimesNano) { + outStats->actualPresentTimesNano.push_back(t); + } + outStats->frameReadyTimesNano.reserve(stats.frameReadyTimesNano.size()); + for (const auto& t : stats.frameReadyTimesNano) { + outStats->frameReadyTimesNano.push_back(t); + } + status = NO_ERROR; } - layer->getFrameStats(outStats); - return NO_ERROR; + return binderStatusFromStatusT(status); +} + +binder::Status Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle, + gui::MirrorSurfaceResult* outResult) { + sp<IBinder> handle; + int32_t layerId; + LayerCreationArgs args(mFlinger.get(), this, "MirrorRoot", 0 /* flags */, gui::LayerMetadata()); + status_t status = mFlinger->mirrorLayer(args, mirrorFromHandle, &handle, &layerId); + if (status == NO_ERROR) { + outResult->handle = handle; + outResult->layerId = layerId; + } + return binderStatusFromStatusT(status); } // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h index 15cd763822..4720d5c43d 100644 --- a/services/surfaceflinger/Client.h +++ b/services/surfaceflinger/Client.h @@ -24,15 +24,14 @@ #include <utils/KeyedVector.h> #include <utils/Mutex.h> -#include <gui/ISurfaceComposerClient.h> +#include <android/gui/BnSurfaceComposerClient.h> namespace android { class Layer; class SurfaceFlinger; -class Client : public BnSurfaceComposerClient -{ +class Client : public gui::BnSurfaceComposerClient { public: explicit Client(const sp<SurfaceFlinger>& flinger); ~Client() = default; @@ -47,25 +46,18 @@ public: private: // ISurfaceComposerClient interface - virtual status_t createSurface(const String8& name, uint32_t w, uint32_t h, PixelFormat format, - uint32_t flags, const sp<IBinder>& parent, - LayerMetadata metadata, sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId, - uint32_t* outTransformHint = nullptr); - virtual status_t createWithSurfaceParent(const String8& name, uint32_t w, uint32_t h, - PixelFormat format, uint32_t flags, - const sp<IGraphicBufferProducer>& parent, - LayerMetadata metadata, sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp, int32_t* outLayerId, - uint32_t* outTransformHint = nullptr); + binder::Status createSurface(const std::string& name, int32_t flags, const sp<IBinder>& parent, + const gui::LayerMetadata& metadata, + gui::CreateSurfaceResult* outResult) override; - status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* handle, - int32_t* outLayerId); + binder::Status clearLayerFrameStats(const sp<IBinder>& handle) override; - virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const; + binder::Status getLayerFrameStats(const sp<IBinder>& handle, + gui::FrameStats* outStats) override; - virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const; + binder::Status mirrorSurface(const sp<IBinder>& mirrorFromHandle, + gui::MirrorSurfaceResult* outResult) override; // constant sp<SurfaceFlinger> mFlinger; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h index f201751d59..f861fc97e4 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h @@ -32,6 +32,11 @@ namespace android::compositionengine { using Layers = std::vector<sp<compositionengine::LayerFE>>; using Outputs = std::vector<std::shared_ptr<compositionengine::Output>>; +struct BorderRenderInfo { + float width = 0; + half4 color; + std::vector<int32_t> layerIds; +}; /** * A parameter object for refreshing a set of outputs */ @@ -90,6 +95,8 @@ struct CompositionRefreshArgs { // If set, a frame has been scheduled for that time. std::optional<std::chrono::steady_clock::time_point> scheduledFrameTime; + + std::vector<BorderRenderInfo> borderInfoList; }; } // namespace android::compositionengine diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h index df721cdc89..fc8dd8be94 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h @@ -154,6 +154,7 @@ protected: private: void dirtyEntireOutput(); + void updateCompositionStateForBorder(const compositionengine::CompositionRefreshArgs&); compositionengine::OutputLayer* findLayerRequestingBackgroundComposition() const; void finishPrepareFrame(); ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 7709b967b6..c29165210d 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -33,6 +33,7 @@ #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" #include <compositionengine/ProjectionSpace.h> +#include <renderengine/BorderRenderInfo.h> #include <ui/LayerStack.h> #include <ui/Rect.h> #include <ui/Region.h> @@ -164,6 +165,8 @@ struct OutputCompositionState { bool treat170mAsSrgb = false; + std::vector<renderengine::BorderRenderInfo> borderInfoList; + uint64_t lastOutputLayerHash = 0; uint64_t outputLayerHash = 0; diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index aa0b152db0..aea6798662 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -754,6 +754,44 @@ void Output::updateCompositionState(const compositionengine::CompositionRefreshA forceClientComposition = false; } } + + updateCompositionStateForBorder(refreshArgs); +} + +void Output::updateCompositionStateForBorder( + const compositionengine::CompositionRefreshArgs& refreshArgs) { + std::unordered_map<int32_t, const Region*> layerVisibleRegionMap; + // Store a map of layerId to their computed visible region. + for (auto* layer : getOutputLayersOrderedByZ()) { + int layerId = (layer->getLayerFE()).getSequence(); + layerVisibleRegionMap[layerId] = &((layer->getState()).visibleRegion); + } + OutputCompositionState& outputCompositionState = editState(); + outputCompositionState.borderInfoList.clear(); + bool clientComposeTopLayer = false; + for (const auto& borderInfo : refreshArgs.borderInfoList) { + renderengine::BorderRenderInfo info; + for (const auto& id : borderInfo.layerIds) { + info.combinedRegion.orSelf(*(layerVisibleRegionMap[id])); + } + + if (!info.combinedRegion.isEmpty()) { + info.width = borderInfo.width; + info.color = borderInfo.color; + outputCompositionState.borderInfoList.emplace_back(std::move(info)); + clientComposeTopLayer = true; + } + } + + // In this situation we must client compose the top layer instead of using hwc + // because we want to draw the border above all else. + // This could potentially cause a bit of a performance regression if the top + // layer would have been rendered using hwc originally. + // TODO(b/227656283): Measure system's performance before enabling the border feature + if (clientComposeTopLayer) { + auto topLayer = getOutputLayerOrderedByZByIndex(getOutputLayerCount() - 1); + (topLayer->editState()).forceClientComposition = true; + } } void Output::planComposition() { @@ -1220,6 +1258,13 @@ std::optional<base::unique_fd> Output::composeSurfaces( // Compute the global color transform matrix. clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix; + for (auto& info : outputState.borderInfoList) { + renderengine::BorderRenderInfo borderInfo; + borderInfo.width = info.width; + borderInfo.color = info.color; + borderInfo.combinedRegion = info.combinedRegion; + clientCompositionDisplay.borderInfoList.emplace_back(std::move(borderInfo)); + } clientCompositionDisplay.deviceHandlesColorTransform = outputState.usesDeviceComposition || getSkipColorTransform(); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index 948c0c90bf..c512a1e97f 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -62,14 +62,18 @@ void OutputCompositionState::dump(std::string& out) const { dumpVal(out, "sdrWhitePointNits", sdrWhitePointNits); dumpVal(out, "clientTargetBrightness", clientTargetBrightness); dumpVal(out, "displayBrightness", displayBrightness); - out.append("\n "); dumpVal(out, "compositionStrategyPredictionState", ftl::enum_string(strategyPrediction)); + out.append("\n "); out.append("\n "); dumpVal(out, "treate170mAsSrgb", treat170mAsSrgb); - out += '\n'; + out.append("\n"); + for (const auto& borderRenderInfo : borderInfoList) { + dumpVal(out, "borderRegion", borderRenderInfo.combinedRegion); + } + out.append("\n"); } } // namespace android::compositionengine::impl diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h index 24aef9b73c..486eaf8f03 100644 --- a/services/surfaceflinger/DisplayHardware/HWC2.h +++ b/services/surfaceflinger/DisplayHardware/HWC2.h @@ -88,7 +88,7 @@ public: virtual hal::HWDisplayId getId() const = 0; virtual bool isConnected() const = 0; - virtual void setConnected(bool connected) = 0; // For use by Device only + virtual void setConnected(bool connected) = 0; // For use by HWComposer only virtual bool hasCapability( aidl::android::hardware::graphics::composer3::DisplayCapability) const = 0; virtual bool isVsyncPeriodSwitchSupported() const = 0; @@ -253,7 +253,7 @@ public: // Other Display methods hal::HWDisplayId getId() const override { return mId; } bool isConnected() const override { return mIsConnected; } - void setConnected(bool connected) override; // For use by Device only + void setConnected(bool connected) override; bool hasCapability(aidl::android::hardware::graphics::composer3::DisplayCapability) const override EXCLUDES(mDisplayCapabilitiesMutex); bool isVsyncPeriodSwitchSupported() const override; @@ -271,7 +271,7 @@ private: // Member variables - // These are references to data owned by HWC2::Device, which will outlive + // These are references to data owned by HWComposer, which will outlive // this HWC2::Display, so these references are guaranteed to be valid for // the lifetime of this object. android::Hwc2::Composer& mComposer; @@ -383,7 +383,7 @@ public: hal::Error setBlockingRegion(const android::Region& region) override; private: - // These are references to data owned by HWC2::Device, which will outlive + // These are references to data owned by HWComposer, which will outlive // this HWC2::Layer, so these references are guaranteed to be valid for // the lifetime of this object. android::Hwc2::Composer& mComposer; diff --git a/services/surfaceflinger/FpsReporter.cpp b/services/surfaceflinger/FpsReporter.cpp index e12835f0f6..c89c9ffcd4 100644 --- a/services/surfaceflinger/FpsReporter.cpp +++ b/services/surfaceflinger/FpsReporter.cpp @@ -56,8 +56,8 @@ void FpsReporter::dispatchLayerFps() { mFlinger.mCurrentState.traverse([&](Layer* layer) { auto& currentState = layer->getDrawingState(); - if (currentState.metadata.has(METADATA_TASK_ID)) { - int32_t taskId = currentState.metadata.getInt32(METADATA_TASK_ID, 0); + if (currentState.metadata.has(gui::METADATA_TASK_ID)) { + int32_t taskId = currentState.metadata.getInt32(gui::METADATA_TASK_ID, 0); if (seenTasks.count(taskId) == 0) { // localListeners is expected to be tiny for (TrackedListener& listener : localListeners) { diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp index 66beff2953..3e69b5c67a 100644 --- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp @@ -289,7 +289,7 @@ nsecs_t getMinTime(PredictionState predictionState, TimelineItem predictions, minTime = std::min(minTime, actuals.endTime); } if (actuals.presentTime != 0) { - minTime = std::min(minTime, actuals.endTime); + minTime = std::min(minTime, actuals.presentTime); } return minTime; } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 38662bdaff..ba3cb51f39 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -62,7 +62,6 @@ #include <mutex> #include <sstream> -#include "BufferLayer.h" #include "Colorizer.h" #include "DisplayDevice.h" #include "DisplayHardware/HWComposer.h" @@ -70,8 +69,6 @@ #include "FrameTimeline.h" #include "FrameTracer/FrameTracer.h" #include "LayerProtoHelper.h" -#include "LayerRejecter.h" -#include "MonitoredProducer.h" #include "SurfaceFlinger.h" #include "TimeStats/TimeStats.h" #include "TunnelModeEnabledReporter.h" @@ -86,6 +83,8 @@ constexpr int kDumpTableRowLength = 159; using namespace ftl::flag_operators; using base::StringAppendF; +using gui::GameMode; +using gui::LayerMetadata; using gui::WindowInfo; using PresentState = frametimeline::SurfaceFrame::PresentState; @@ -97,8 +96,10 @@ Layer::Layer(const LayerCreationArgs& args) mFlinger(args.flinger), mName(base::StringPrintf("%s#%d", args.name.c_str(), sequence)), mClientRef(args.client), - mWindowType(static_cast<WindowInfo::Type>(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0))), - mLayerCreationFlags(args.flags) { + mWindowType(static_cast<WindowInfo::Type>( + args.metadata.getInt32(gui::METADATA_WINDOW_TYPE, 0))), + mLayerCreationFlags(args.flags), + mBorderEnabled(false) { uint32_t layerFlags = 0; if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden; if (args.flags & ISurfaceComposerClient::eOpaque) layerFlags |= layer_state_t::eLayerOpaque; @@ -144,6 +145,7 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.isTrustedOverlay = false; mDrawingState.dropInputMode = gui::DropInputMode::NONE; mDrawingState.dimmingEnabled = true; + mDrawingState.defaultFrameRateCompatibility = FrameRateCompatibility::Default; if (args.flags & ISurfaceComposerClient::eNoColorFill) { // Set an invalid color so there is no color fill. @@ -151,17 +153,17 @@ Layer::Layer(const LayerCreationArgs& args) mDrawingState.color.g = -1.0_hf; mDrawingState.color.b = -1.0_hf; } - CompositorTiming compositorTiming; - args.flinger->getCompositorTiming(&compositorTiming); - mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval); + + mFrameTracker.setDisplayRefreshPeriod( + args.flinger->mScheduler->getVsyncPeriodFromRefreshRateConfigs()); mCallingPid = args.callingPid; mCallingUid = args.callingUid; if (mCallingUid == AID_GRAPHICS || mCallingUid == AID_SYSTEM) { // If the system didn't send an ownerUid, use the callingUid for the ownerUid. - mOwnerUid = args.metadata.getInt32(METADATA_OWNER_UID, mCallingUid); - mOwnerPid = args.metadata.getInt32(METADATA_OWNER_PID, mCallingPid); + mOwnerUid = args.metadata.getInt32(gui::METADATA_OWNER_UID, mCallingUid); + mOwnerPid = args.metadata.getInt32(gui::METADATA_OWNER_PID, mCallingPid); } else { // A create layer request from a non system request cannot specify the owner uid mOwnerUid = mCallingUid; @@ -405,7 +407,7 @@ void Layer::prepareBasicGeometryCompositionState() { const auto& drawingState{getDrawingState()}; const auto alpha = static_cast<float>(getAlpha()); const bool opaque = isOpaque(drawingState); - const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f; + const bool usesRoundedCorners = hasRoundedCorners(); auto blendMode = Hwc2::IComposerClient::BlendMode::NONE; if (!opaque || alpha != 1.0f) { @@ -481,7 +483,7 @@ void Layer::preparePerFrameCompositionState() { compositionState->hasProtectedContent = isProtected(); compositionState->dimmingEnabled = isDimmingEnabled(); - const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f; + const bool usesRoundedCorners = hasRoundedCorners(); compositionState->isOpaque = isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf; @@ -720,7 +722,7 @@ uint32_t Layer::doTransaction(uint32_t flags) { if (s.sequence != mLastCommittedTxSequence) { // invalidate and recompute the visible regions if needed - mLastCommittedTxSequence = s.sequence; + mLastCommittedTxSequence = s.sequence; flags |= eVisibleRegion; this->contentDirty = true; @@ -728,6 +730,10 @@ uint32_t Layer::doTransaction(uint32_t flags) { mNeedsFiltering = getActiveTransform(s).needsBilinearFiltering(); } + if (!mPotentialCursor && (flags & Layer::eVisibleRegion)) { + mFlinger->mUpdateInputInfo = true; + } + commitTransaction(mDrawingState); return flags; @@ -878,7 +884,7 @@ bool Layer::setTrustedOverlay(bool isTrustedOverlay) { if (mDrawingState.isTrustedOverlay == isTrustedOverlay) return false; mDrawingState.isTrustedOverlay = isTrustedOverlay; mDrawingState.modified = true; - mFlinger->mInputInfoChanged = true; + mFlinger->mUpdateInputInfo = true; setTransactionFlags(eTransactionNeeded); return true; } @@ -975,6 +981,13 @@ bool Layer::setBackgroundBlurRadius(int backgroundBlurRadius) { return true; } bool Layer::setMatrix(const layer_state_t::matrix22_t& matrix) { + if (matrix.dsdx == mDrawingState.transform.dsdx() && + matrix.dtdy == mDrawingState.transform.dtdy() && + matrix.dtdx == mDrawingState.transform.dtdx() && + matrix.dsdy == mDrawingState.transform.dsdy()) { + return false; + } + ui::Transform t; t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy); @@ -1086,6 +1099,19 @@ int32_t Layer::getFrameRateSelectionPriority() const { return Layer::PRIORITY_UNSET; } +bool Layer::setDefaultFrameRateCompatibility(FrameRateCompatibility compatibility) { + if (mDrawingState.defaultFrameRateCompatibility == compatibility) return false; + mDrawingState.defaultFrameRateCompatibility = compatibility; + mDrawingState.modified = true; + mFlinger->mScheduler->setDefaultFrameRateCompatibility(this); + setTransactionFlags(eTransactionNeeded); + return true; +} + +scheduler::LayerInfo::FrameRateCompatibility Layer::getDefaultFrameRateCompatibility() const { + return mDrawingState.defaultFrameRateCompatibility; +} + bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) { return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE; }; @@ -1150,6 +1176,28 @@ StretchEffect Layer::getStretchEffect() const { return StretchEffect{}; } +bool Layer::enableBorder(bool shouldEnable, float width, const half4& color) { + if (mBorderEnabled == shouldEnable && mBorderWidth == width && mBorderColor == color) { + return false; + } + mBorderEnabled = shouldEnable; + mBorderWidth = width; + mBorderColor = color; + return true; +} + +bool Layer::isBorderEnabled() { + return mBorderEnabled; +} + +float Layer::getBorderWidth() { + return mBorderWidth; +} + +const half4& Layer::getBorderColor() { + return mBorderColor; +} + bool Layer::propagateFrameRateForLayerTree(FrameRate parentFrameRate, bool* transactionNeeded) { // The frame rate for layer tree is this layer's frame rate if present, or the parent frame rate const auto frameRate = [&] { @@ -1398,10 +1446,10 @@ void Layer::updateTransformHint(ui::Transform::RotationFlags transformHint) { // ---------------------------------------------------------------------------- // TODO(marissaw): add new layer state info to layer debugging -LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const { +gui::LayerDebugInfo Layer::getLayerDebugInfo(const DisplayDevice* display) const { using namespace std::string_literals; - LayerDebugInfo info; + gui::LayerDebugInfo info; const State& ds = getDrawingState(); info.mName = getName(); sp<Layer> parent = mDrawingParent.promote(); @@ -1550,8 +1598,9 @@ size_t Layer::getChildrenCount() const { void Layer::setGameModeForTree(GameMode gameMode) { const auto& currentState = getDrawingState(); - if (currentState.metadata.has(METADATA_GAME_MODE)) { - gameMode = static_cast<GameMode>(currentState.metadata.getInt32(METADATA_GAME_MODE, 0)); + if (currentState.metadata.has(gui::METADATA_GAME_MODE)) { + gameMode = + static_cast<GameMode>(currentState.metadata.getInt32(gui::METADATA_GAME_MODE, 0)); } setGameMode(gameMode); for (const sp<Layer>& child : mCurrentChildren) { @@ -1916,27 +1965,22 @@ Layer::RoundedCornerState Layer::getRoundedCornerState() const { const auto& parent = mDrawingParent.promote(); if (parent != nullptr) { parentSettings = parent->getRoundedCornerState(); - if (parentSettings.radius > 0) { + if (parentSettings.hasRoundedCorners()) { ui::Transform t = getActiveTransform(getDrawingState()); t = t.inverse(); parentSettings.cropRect = t.transform(parentSettings.cropRect); - // The rounded corners shader only accepts 1 corner radius for performance reasons, - // but a transform matrix can define horizontal and vertical scales. - // Let's take the average between both of them and pass into the shader, practically we - // never do this type of transformation on windows anyway. - auto scaleX = sqrtf(t[0][0] * t[0][0] + t[0][1] * t[0][1]); - auto scaleY = sqrtf(t[1][0] * t[1][0] + t[1][1] * t[1][1]); - parentSettings.radius *= (scaleX + scaleY) / 2.0f; + parentSettings.radius.x *= t.getScaleX(); + parentSettings.radius.y *= t.getScaleY(); } } // Get layer settings Rect layerCropRect = getCroppedBufferSize(getDrawingState()); - const float radius = getDrawingState().cornerRadius; + const vec2 radius(getDrawingState().cornerRadius, getDrawingState().cornerRadius); RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius); - const bool layerSettingsValid = layerSettings.radius > 0 && layerCropRect.isValid(); + const bool layerSettingsValid = layerSettings.hasRoundedCorners() && layerCropRect.isValid(); - if (layerSettingsValid && parentSettings.radius > 0) { + if (layerSettingsValid && parentSettings.hasRoundedCorners()) { // If the parent and the layer have rounded corner settings, use the parent settings if the // parent crop is entirely inside the layer crop. // This has limitations and cause rendering artifacts. See b/200300845 for correct fix. @@ -1950,7 +1994,7 @@ Layer::RoundedCornerState Layer::getRoundedCornerState() const { } } else if (layerSettingsValid) { return layerSettings; - } else if (parentSettings.radius > 0) { + } else if (parentSettings.hasRoundedCorners()) { return parentSettings; } return {}; @@ -2026,7 +2070,7 @@ void Layer::setInputInfo(const WindowInfo& info) { mDrawingState.inputInfo = info; mDrawingState.touchableRegionCrop = fromHandle(info.touchableRegionCropHandle.promote()); mDrawingState.modified = true; - mFlinger->mInputInfoChanged = true; + mFlinger->mUpdateInputInfo = true; setTransactionFlags(eTransactionNeeded); } @@ -2071,7 +2115,8 @@ void Layer::writeToProtoDrawingState(LayerProto* layerInfo) { layerInfo->set_effective_scaling_mode(getEffectiveScalingMode()); layerInfo->set_requested_corner_radius(getDrawingState().cornerRadius); - layerInfo->set_corner_radius(getRoundedCornerState().radius); + layerInfo->set_corner_radius( + (getRoundedCornerState().radius.x + getRoundedCornerState().radius.y) / 2.0); layerInfo->set_background_blur_radius(getBackgroundBlurRadius()); layerInfo->set_is_trusted_overlay(isTrustedOverlay()); LayerProtoHelper::writeToProtoDeprecated(transform, layerInfo->mutable_transform()); @@ -2425,7 +2470,7 @@ WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform, bool disp // If the layer is a clone, we need to crop the input region to cloned root to prevent // touches from going outside the cloned area. if (isClone()) { - info.isClone = true; + info.inputConfig |= WindowInfo::InputConfig::CLONE; if (const sp<Layer> clonedRoot = getClonedRoot()) { const Rect rect = displayTransform.transform(Rect{clonedRoot->mScreenBounds}); info.touchableRegion = info.touchableRegion.intersect(rect); @@ -2605,6 +2650,8 @@ Layer::FrameRateCompatibility Layer::FrameRate::convertCompatibility(int8_t comp return FrameRateCompatibility::ExactOrMultiple; case ANATIVEWINDOW_FRAME_RATE_EXACT: return FrameRateCompatibility::Exact; + case ANATIVEWINDOW_FRAME_RATE_MIN: + return FrameRateCompatibility::Min; case ANATIVEWINDOW_FRAME_RATE_NO_VOTE: return FrameRateCompatibility::NoVote; default: diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 24abad9b45..b809c8a192 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -17,8 +17,8 @@ #pragma once #include <android/gui/DropInputMode.h> +#include <android/gui/ISurfaceComposerClient.h> #include <gui/BufferQueue.h> -#include <gui/ISurfaceComposerClient.h> #include <gui/LayerState.h> #include <gui/WindowInfo.h> #include <layerproto/LayerProtoHeader.h> @@ -53,7 +53,6 @@ #include "DisplayHardware/HWComposer.h" #include "FrameTracker.h" #include "LayerVector.h" -#include "MonitoredProducer.h" #include "RenderArea.h" #include "Scheduler/LayerInfo.h" #include "SurfaceFlinger.h" @@ -69,13 +68,16 @@ class Colorizer; class DisplayDevice; class GraphicBuffer; class SurfaceFlinger; -class LayerDebugInfo; namespace compositionengine { class OutputLayer; struct LayerFECompositionState; } +namespace gui { +class LayerDebugInfo; +} + namespace impl { class SurfaceInterceptor; } @@ -134,13 +136,14 @@ public: struct RoundedCornerState { RoundedCornerState() = default; - RoundedCornerState(FloatRect cropRect, float radius) + RoundedCornerState(const FloatRect& cropRect, const vec2& radius) : cropRect(cropRect), radius(radius) {} // Rounded rectangle in local layer coordinate space. FloatRect cropRect = FloatRect(); // Radius of the rounded rectangle. - float radius = 0.0f; + vec2 radius; + bool hasRoundedCorners() const { return radius.x > 0.0f && radius.y > 0.0f; } }; using FrameRate = scheduler::LayerInfo::FrameRate; @@ -232,6 +235,9 @@ public: // Priority of the layer assigned by Window Manager. int32_t frameRateSelectionPriority; + // Default frame rate compatibility used to set the layer refresh rate votetype. + FrameRateCompatibility defaultFrameRateCompatibility; + FrameRate frameRate; // The combined frame rate of parents / children of this layer @@ -435,6 +441,7 @@ public: virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace); virtual bool setColorSpaceAgnostic(const bool agnostic); virtual bool setDimmingEnabled(const bool dimmingEnabled); + virtual bool setDefaultFrameRateCompatibility(FrameRateCompatibility compatibility); virtual bool setFrameRateSelectionPriority(int32_t priority); virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint); virtual void setAutoRefresh(bool /* autoRefresh */) {} @@ -443,6 +450,9 @@ public: // If the variable is not set on the layer, it traverses up the tree to inherit the frame // rate priority from its parent. virtual int32_t getFrameRateSelectionPriority() const; + // + virtual FrameRateCompatibility getDefaultFrameRateCompatibility() const; + // virtual ui::Dataspace getDataSpace() const { return ui::Dataspace::UNKNOWN; } virtual sp<compositionengine::LayerFE> getCompositionEngineLayerFE() const; @@ -596,7 +606,7 @@ public: // corner crop does not intersect with its own rounded corner crop. virtual RoundedCornerState getRoundedCornerState() const; - bool hasRoundedCorners() const override { return getRoundedCornerState().radius > .0f; } + bool hasRoundedCorners() const override { return getRoundedCornerState().hasRoundedCorners(); } virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; } /** @@ -735,7 +745,7 @@ public: inline const State& getDrawingState() const { return mDrawingState; } inline State& getDrawingState() { return mDrawingState; } - LayerDebugInfo getLayerDebugInfo(const DisplayDevice*) const; + gui::LayerDebugInfo getLayerDebugInfo(const DisplayDevice*) const; void miniDump(std::string& result, const DisplayDevice&) const; void dumpFrameStats(std::string& result) const; @@ -885,6 +895,10 @@ public: bool setStretchEffect(const StretchEffect& effect); StretchEffect getStretchEffect() const; + bool enableBorder(bool shouldEnable, float width, const half4& color); + bool isBorderEnabled(); + float getBorderWidth(); + const half4& getBorderColor(); virtual bool setBufferCrop(const Rect& /* bufferCrop */) { return false; } virtual bool setDestinationFrame(const Rect& /* destinationFrame */) { return false; } @@ -1126,7 +1140,12 @@ private: bool mIsAtRoot = false; uint32_t mLayerCreationFlags; + bool findInHierarchy(const sp<Layer>&); + + bool mBorderEnabled = false; + float mBorderWidth; + half4 mBorderColor; }; std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate); diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp deleted file mode 100644 index 1c0263ba0b..0000000000 --- a/services/surfaceflinger/LayerRejecter.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2011 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. - */ - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - -#include "LayerRejecter.h" - -#include <gui/BufferItem.h> -#include <system/window.h> - -#define DEBUG_RESIZE 0 - -namespace android { - -LayerRejecter::LayerRejecter(Layer::State& front, Layer::State& current, - bool& recomputeVisibleRegions, bool stickySet, const std::string& name, - bool transformToDisplayInverse) - : mFront(front), - mCurrent(current), - mRecomputeVisibleRegions(recomputeVisibleRegions), - mStickyTransformSet(stickySet), - mName(name), - mTransformToDisplayInverse(transformToDisplayInverse) {} - -bool LayerRejecter::reject(const sp<GraphicBuffer>& buf, const BufferItem& item) { - if (buf == nullptr) { - return false; - } - - uint32_t bufWidth = buf->getWidth(); - uint32_t bufHeight = buf->getHeight(); - - // check that we received a buffer of the right size - // (Take the buffer's orientation into account) - if (item.mTransform & ui::Transform::ROT_90) { - std::swap(bufWidth, bufHeight); - } - - if (mTransformToDisplayInverse) { - uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags(); - if (invTransform & ui::Transform::ROT_90) { - std::swap(bufWidth, bufHeight); - } - } - - int actualScalingMode = item.mScalingMode; - bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE; - if (mFront.active_legacy != mFront.requested_legacy) { - if (isFixedSize || - (bufWidth == mFront.requested_legacy.w && bufHeight == mFront.requested_legacy.h)) { - // Here we pretend the transaction happened by updating the - // current and drawing states. Drawing state is only accessed - // in this thread, no need to have it locked - mFront.active_legacy = mFront.requested_legacy; - - // We also need to update the current state so that - // we don't end-up overwriting the drawing state with - // this stale current state during the next transaction - // - // NOTE: We don't need to hold the transaction lock here - // because State::active_legacy is only accessed from this thread. - mCurrent.active_legacy = mFront.active_legacy; - mCurrent.modified = true; - - // recompute visible region - mRecomputeVisibleRegions = true; - - if (mFront.crop != mFront.requestedCrop) { - mFront.crop = mFront.requestedCrop; - mCurrent.crop = mFront.requestedCrop; - mRecomputeVisibleRegions = true; - } - } - - ALOGD_IF(DEBUG_RESIZE, - "[%s] latchBuffer/reject: buffer (%ux%u, tr=%02x), scalingMode=%d\n" - " drawing={ active_legacy ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} " - "(%4d,%4d) " - "}\n" - " requested_legacy={ wh={%4u,%4u} }}\n", - mName.c_str(), bufWidth, bufHeight, item.mTransform, item.mScalingMode, - mFront.active_legacy.w, mFront.active_legacy.h, mFront.crop.left, mFront.crop.top, - mFront.crop.right, mFront.crop.bottom, mFront.crop.getWidth(), - mFront.crop.getHeight(), mFront.requested_legacy.w, mFront.requested_legacy.h); - } - - if (!isFixedSize && !mStickyTransformSet) { - if (mFront.active_legacy.w != bufWidth || mFront.active_legacy.h != bufHeight) { - // reject this buffer - ALOGE("[%s] rejecting buffer: " - "bufWidth=%d, bufHeight=%d, front.active_legacy.{w=%d, h=%d}", - mName.c_str(), bufWidth, bufHeight, mFront.active_legacy.w, - mFront.active_legacy.h); - return true; - } - } - - // if the transparent region has changed (this test is - // conservative, but that's fine, worst case we're doing - // a bit of extra work), we latch the new one and we - // trigger a visible-region recompute. - // - // We latch the transparent region here, instead of above where we latch - // the rest of the geometry because it is only content but not necessarily - // resize dependent. - if (!mFront.activeTransparentRegion_legacy.hasSameRects( - mFront.requestedTransparentRegion_legacy)) { - mFront.activeTransparentRegion_legacy = mFront.requestedTransparentRegion_legacy; - - // We also need to update the current state so that - // we don't end-up overwriting the drawing state with - // this stale current state during the next transaction - // - // NOTE: We don't need to hold the transaction lock here - // because State::active_legacy is only accessed from this thread. - mCurrent.activeTransparentRegion_legacy = mFront.activeTransparentRegion_legacy; - - // recompute visible region - mRecomputeVisibleRegions = true; - } - - return false; -} - -} // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h deleted file mode 100644 index 4981f451d9..0000000000 --- a/services/surfaceflinger/LayerRejecter.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Layer.h" -#include "BufferLayerConsumer.h" - -namespace android { - -class LayerRejecter : public BufferLayerConsumer::BufferRejecter { -public: - LayerRejecter(Layer::State& front, Layer::State& current, bool& recomputeVisibleRegions, - bool stickySet, const std::string& name, - bool transformToDisplayInverse); - - virtual bool reject(const sp<GraphicBuffer>&, const BufferItem&); - -private: - Layer::State& mFront; - Layer::State& mCurrent; - bool& mRecomputeVisibleRegions; - const bool mStickyTransformSet; - const std::string& mName; - const bool mTransformToDisplayInverse; -}; - -} // namespace android diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp deleted file mode 100644 index df76f50112..0000000000 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2014 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. - */ - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wconversion" - -#include "MonitoredProducer.h" -#include "Layer.h" -#include "SurfaceFlinger.h" - -#include "Scheduler/MessageQueue.h" - -namespace android { - -MonitoredProducer::MonitoredProducer(const sp<IGraphicBufferProducer>& producer, - const sp<SurfaceFlinger>& flinger, - const wp<Layer>& layer) : - mProducer(producer), - mFlinger(flinger), - mLayer(layer) {} - -MonitoredProducer::~MonitoredProducer() {} - -status_t MonitoredProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) { - return mProducer->requestBuffer(slot, buf); -} - -status_t MonitoredProducer::setMaxDequeuedBufferCount( - int maxDequeuedBuffers) { - return mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers); -} - -status_t MonitoredProducer::setAsyncMode(bool async) { - return mProducer->setAsyncMode(async); -} - -status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, - PixelFormat format, uint64_t usage, - uint64_t* outBufferAge, - FrameEventHistoryDelta* outTimestamps) { - return mProducer->dequeueBuffer(slot, fence, w, h, format, usage, outBufferAge, outTimestamps); -} - -status_t MonitoredProducer::detachBuffer(int slot) { - return mProducer->detachBuffer(slot); -} - -status_t MonitoredProducer::detachNextBuffer(sp<GraphicBuffer>* outBuffer, - sp<Fence>* outFence) { - return mProducer->detachNextBuffer(outBuffer, outFence); -} - -status_t MonitoredProducer::attachBuffer(int* outSlot, - const sp<GraphicBuffer>& buffer) { - return mProducer->attachBuffer(outSlot, buffer); -} - -status_t MonitoredProducer::queueBuffer(int slot, const QueueBufferInput& input, - QueueBufferOutput* output) { - return mProducer->queueBuffer(slot, input, output); -} - -status_t MonitoredProducer::cancelBuffer(int slot, const sp<Fence>& fence) { - return mProducer->cancelBuffer(slot, fence); -} - -int MonitoredProducer::query(int what, int* value) { - return mProducer->query(what, value); -} - -status_t MonitoredProducer::connect(const sp<IProducerListener>& listener, - int api, bool producerControlledByApp, QueueBufferOutput* output) { - return mProducer->connect(listener, api, producerControlledByApp, output); -} - -status_t MonitoredProducer::disconnect(int api, DisconnectMode mode) { - return mProducer->disconnect(api, mode); -} - -status_t MonitoredProducer::setSidebandStream(const sp<NativeHandle>& stream) { - return mProducer->setSidebandStream(stream); -} - -void MonitoredProducer::allocateBuffers(uint32_t width, uint32_t height, - PixelFormat format, uint64_t usage) { - mProducer->allocateBuffers(width, height, format, usage); -} - -status_t MonitoredProducer::allowAllocation(bool allow) { - return mProducer->allowAllocation(allow); -} - -status_t MonitoredProducer::setGenerationNumber(uint32_t generationNumber) { - return mProducer->setGenerationNumber(generationNumber); -} - -String8 MonitoredProducer::getConsumerName() const { - return mProducer->getConsumerName(); -} - -status_t MonitoredProducer::setSharedBufferMode(bool sharedBufferMode) { - return mProducer->setSharedBufferMode(sharedBufferMode); -} - -status_t MonitoredProducer::setAutoRefresh(bool autoRefresh) { - return mProducer->setAutoRefresh(autoRefresh); -} - -status_t MonitoredProducer::setDequeueTimeout(nsecs_t timeout) { - return mProducer->setDequeueTimeout(timeout); -} - -status_t MonitoredProducer::setLegacyBufferDrop(bool drop) { - return mProducer->setLegacyBufferDrop(drop); -} - -status_t MonitoredProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, - sp<Fence>* outFence, float outTransformMatrix[16]) { - return mProducer->getLastQueuedBuffer(outBuffer, outFence, - outTransformMatrix); -} - -status_t MonitoredProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, - Rect* outRect, uint32_t* outTransform) { - return mProducer->getLastQueuedBuffer(outBuffer, outFence, outRect, outTransform); -} - -void MonitoredProducer::getFrameTimestamps(FrameEventHistoryDelta* outDelta) { - mProducer->getFrameTimestamps(outDelta); -} - -status_t MonitoredProducer::getUniqueId(uint64_t* outId) const { - return mProducer->getUniqueId(outId); -} - -status_t MonitoredProducer::getConsumerUsage(uint64_t* outUsage) const { - return mProducer->getConsumerUsage(outUsage); -} - -status_t MonitoredProducer::setAutoPrerotation(bool autoPrerotation) { - return mProducer->setAutoPrerotation(autoPrerotation); -} - -IBinder* MonitoredProducer::onAsBinder() { - return this; -} - -sp<Layer> MonitoredProducer::getLayer() const { - return mLayer.promote(); -} - -// --------------------------------------------------------------------------- -}; // namespace android - -// TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h deleted file mode 100644 index 3778277fd3..0000000000 --- a/services/surfaceflinger/MonitoredProducer.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2014 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. - */ - -#ifndef ANDROID_MONITORED_PRODUCER_H -#define ANDROID_MONITORED_PRODUCER_H - -#include <gui/IGraphicBufferProducer.h> - -namespace android { - -class IProducerListener; -class NativeHandle; -class SurfaceFlinger; -class Layer; - -// MonitoredProducer wraps an IGraphicBufferProducer so that SurfaceFlinger will -// be notified upon its destruction -class MonitoredProducer : public BnGraphicBufferProducer { -public: - MonitoredProducer(const sp<IGraphicBufferProducer>& producer, - const sp<SurfaceFlinger>& flinger, - const wp<Layer>& layer); - virtual ~MonitoredProducer(); - - // From IGraphicBufferProducer - virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf); - virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers); - virtual status_t setAsyncMode(bool async); - virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, uint32_t w, uint32_t h, - PixelFormat format, uint64_t usage, uint64_t* outBufferAge, - FrameEventHistoryDelta* outTimestamps); - virtual status_t detachBuffer(int slot); - virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer, - sp<Fence>* outFence); - virtual status_t attachBuffer(int* outSlot, - const sp<GraphicBuffer>& buffer); - virtual status_t queueBuffer(int slot, const QueueBufferInput& input, - QueueBufferOutput* output); - virtual status_t cancelBuffer(int slot, const sp<Fence>& fence); - virtual int query(int what, int* value); - virtual status_t connect(const sp<IProducerListener>& token, int api, - bool producerControlledByApp, QueueBufferOutput* output); - virtual status_t disconnect(int api, DisconnectMode mode); - virtual status_t setSidebandStream(const sp<NativeHandle>& stream); - virtual void allocateBuffers(uint32_t width, uint32_t height, - PixelFormat format, uint64_t usage); - virtual status_t allowAllocation(bool allow); - virtual status_t setGenerationNumber(uint32_t generationNumber); - virtual String8 getConsumerName() const override; - virtual status_t setDequeueTimeout(nsecs_t timeout) override; - virtual status_t setLegacyBufferDrop(bool drop) override; - virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, - sp<Fence>* outFence, float outTransformMatrix[16]) override; - virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, - Rect* outRect, uint32_t* outTransform) override; - virtual IBinder* onAsBinder(); - virtual status_t setSharedBufferMode(bool sharedBufferMode) override; - virtual status_t setAutoRefresh(bool autoRefresh) override; - virtual void getFrameTimestamps(FrameEventHistoryDelta *outDelta) override; - virtual status_t getUniqueId(uint64_t* outId) const override; - virtual status_t getConsumerUsage(uint64_t* outUsage) const override; - virtual status_t setAutoPrerotation(bool autoPrerotation) override; - - // The Layer which created this producer, and on which queued Buffer's will be displayed. - sp<Layer> getLayer() const; - -private: - sp<IGraphicBufferProducer> mProducer; - sp<SurfaceFlinger> mFlinger; - // The Layer which created this producer, and on which queued Buffer's will be displayed. - wp<Layer> mLayer; -}; - -}; // namespace android - -#endif // ANDROID_MONITORED_PRODUCER_H diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index 639ba5a3f1..d152ab2544 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -157,9 +157,9 @@ DisplayEventReceiver::Event makeFrameRateOverrideFlushEvent(PhysicalDisplayId di } // namespace -EventThreadConnection::EventThreadConnection( - EventThread* eventThread, uid_t callingUid, ResyncCallback resyncCallback, - ISurfaceComposer::EventRegistrationFlags eventRegistration) +EventThreadConnection::EventThreadConnection(EventThread* eventThread, uid_t callingUid, + ResyncCallback resyncCallback, + EventRegistrationFlags eventRegistration) : resyncCallback(std::move(resyncCallback)), mOwnerUid(callingUid), mEventRegistration(eventRegistration), @@ -288,8 +288,7 @@ void EventThread::setDuration(std::chrono::nanoseconds workDuration, } sp<EventThreadConnection> EventThread::createEventConnection( - ResyncCallback resyncCallback, - ISurfaceComposer::EventRegistrationFlags eventRegistration) const { + ResyncCallback resyncCallback, EventRegistrationFlags eventRegistration) const { return new EventThreadConnection(const_cast<EventThread*>(this), IPCThreadState::self()->getCallingUid(), std::move(resyncCallback), eventRegistration); @@ -553,7 +552,7 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: { return connection->mEventRegistration.test( - ISurfaceComposer::EventRegistration::modeChanged); + gui::ISurfaceComposer::EventRegistration::modeChanged); } case DisplayEventReceiver::DISPLAY_EVENT_VSYNC: @@ -586,7 +585,7 @@ bool EventThread::shouldConsumeEvent(const DisplayEventReceiver::Event& event, [[fallthrough]]; case DisplayEventReceiver::DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH: return connection->mEventRegistration.test( - ISurfaceComposer::EventRegistration::frameRateOverride); + gui::ISurfaceComposer::EventRegistration::frameRateOverride); default: return false; diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index adb96fd462..d85d140fc0 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -92,7 +92,7 @@ public: class EventThreadConnection : public gui::BnDisplayEventConnection { public: EventThreadConnection(EventThread*, uid_t callingUid, ResyncCallback, - ISurfaceComposer::EventRegistrationFlags eventRegistration = {}); + EventRegistrationFlags eventRegistration = {}); virtual ~EventThreadConnection(); virtual status_t postEvent(const DisplayEventReceiver::Event& event); @@ -107,7 +107,7 @@ public: VSyncRequest vsyncRequest = VSyncRequest::None; const uid_t mOwnerUid; - const ISurfaceComposer::EventRegistrationFlags mEventRegistration; + const EventRegistrationFlags mEventRegistration; private: virtual void onFirstRef(); @@ -123,8 +123,7 @@ public: virtual ~EventThread(); virtual sp<EventThreadConnection> createEventConnection( - ResyncCallback, - ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) const = 0; + ResyncCallback, EventRegistrationFlags eventRegistration = {}) const = 0; // called before the screen is turned off from main thread virtual void onScreenReleased() = 0; @@ -171,8 +170,7 @@ public: ~EventThread(); sp<EventThreadConnection> createEventConnection( - ResyncCallback, - ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) const override; + ResyncCallback, EventRegistrationFlags eventRegistration = {}) const override; status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override; void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override; diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index 5f64efa3d1..ae111c3d45 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -72,6 +72,20 @@ void trace(const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) { ALOGD("%s: %s @ %d Hz", __FUNCTION__, info.getName().c_str(), fps); } + +LayerHistory::LayerVoteType getVoteType(LayerInfo::FrameRateCompatibility compatibility, + bool contentDetectionEnabled) { + LayerHistory::LayerVoteType voteType; + if (!contentDetectionEnabled || compatibility == LayerInfo::FrameRateCompatibility::NoVote) { + voteType = LayerHistory::LayerVoteType::NoVote; + } else if (compatibility == LayerInfo::FrameRateCompatibility::Min) { + voteType = LayerHistory::LayerVoteType::Min; + } else { + voteType = LayerHistory::LayerVoteType::Heuristic; + } + return voteType; +} + } // namespace LayerHistory::LayerHistory() @@ -81,10 +95,12 @@ LayerHistory::LayerHistory() LayerHistory::~LayerHistory() = default; -void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) { +void LayerHistory::registerLayer(Layer* layer, bool contentDetectionEnabled) { std::lock_guard lock(mLock); LOG_ALWAYS_FATAL_IF(findLayer(layer->getSequence()).first != LayerStatus::NotFound, "%s already registered", layer->getName().c_str()); + LayerVoteType type = + getVoteType(layer->getDefaultFrameRateCompatibility(), contentDetectionEnabled); auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type); // The layer can be placed on either map, it is assumed that partitionLayers() will be called @@ -132,6 +148,22 @@ void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now, } } +void LayerHistory::setDefaultFrameRateCompatibility(Layer* layer, bool contentDetectionEnabled) { + std::lock_guard lock(mLock); + auto id = layer->getSequence(); + + auto [found, layerPair] = findLayer(id); + if (found == LayerStatus::NotFound) { + // Offscreen layer + ALOGV("%s: %s not registered", __func__, layer->getName().c_str()); + return; + } + + const auto& info = layerPair->second; + info->setDefaultLayerVote( + getVoteType(layer->getDefaultFrameRateCompatibility(), contentDetectionEnabled)); +} + auto LayerHistory::summarize(const RefreshRateConfigs& configs, nsecs_t now) -> Summary { Summary summary; @@ -203,6 +235,8 @@ void LayerHistory::partitionLayers(nsecs_t now) { switch (frameRate.type) { case Layer::FrameRateCompatibility::Default: return LayerVoteType::ExplicitDefault; + case Layer::FrameRateCompatibility::Min: + return LayerVoteType::Min; case Layer::FrameRateCompatibility::ExactOrMultiple: return LayerVoteType::ExplicitExactOrMultiple; case Layer::FrameRateCompatibility::NoVote: diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index 7b6096f7f3..12bec8dfc1 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -45,7 +45,7 @@ public: ~LayerHistory(); // Layers are unregistered when the weak reference expires. - void registerLayer(Layer*, LayerVoteType type); + void registerLayer(Layer*, bool contentDetectionEnabled); // Sets the display size. Client is responsible for synchronization. void setDisplayArea(uint32_t displayArea) { mDisplayArea = displayArea; } @@ -63,6 +63,10 @@ public: // Marks the layer as active, and records the given state to its history. void record(Layer*, nsecs_t presentTime, nsecs_t now, LayerUpdateType updateType); + // Updates the default frame rate compatibility which takes effect when the app + // does not set a preference for refresh rate. + void setDefaultFrameRateCompatibility(Layer*, bool contentDetectionEnabled); + using Summary = std::vector<RefreshRateConfigs::LayerRequirement>; // Rebuilds sets of active/inactive layers, and accumulates stats for active layers. diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index 8a3b0b97e4..28cb24a64f 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -74,6 +74,8 @@ public: enum class FrameRateCompatibility { Default, // Layer didn't specify any specific handling strategy + Min, // Layer needs the minimum frame rate. + Exact, // Layer needs the exact frame rate. ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 727cb0817e..a3d4e8d0db 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -28,7 +28,6 @@ #include <ftl/fake_guard.h> #include <gui/WindowInfo.h> #include <system/window.h> -#include <ui/DisplayStatInfo.h> #include <utils/Timers.h> #include <utils/Trace.h> @@ -172,8 +171,7 @@ impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const { return [this](uid_t uid) { const Fps refreshRate = holdRefreshRateConfigs()->getActiveMode()->getFps(); - const auto currentPeriod = - mVsyncSchedule->getTracker().currentPeriod() ?: refreshRate.getPeriodNsecs(); + const nsecs_t currentPeriod = mVsyncSchedule->period().ns() ?: refreshRate.getPeriodNsecs(); const auto frameRate = getFrameRateOverride(uid); if (!frameRate.has_value()) { @@ -214,12 +212,12 @@ ConnectionHandle Scheduler::createConnection(std::unique_ptr<EventThread> eventT } sp<EventThreadConnection> Scheduler::createConnectionInternal( - EventThread* eventThread, ISurfaceComposer::EventRegistrationFlags eventRegistration) { + EventThread* eventThread, EventRegistrationFlags eventRegistration) { return eventThread->createEventConnection([&] { resync(); }, eventRegistration); } sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection( - ConnectionHandle handle, ISurfaceComposer::EventRegistrationFlags eventRegistration) { + ConnectionHandle handle, EventRegistrationFlags eventRegistration) { std::lock_guard<std::mutex> lock(mConnectionsLock); RETURN_IF_INVALID_HANDLE(handle, nullptr); return createConnectionInternal(mConnections[handle].thread.get(), eventRegistration); @@ -361,12 +359,6 @@ void Scheduler::setDuration(ConnectionHandle handle, std::chrono::nanoseconds wo thread->setDuration(workDuration, readyDuration); } -DisplayStatInfo Scheduler::getDisplayStatInfo(nsecs_t now) { - const auto vsyncTime = mVsyncSchedule->getTracker().nextAnticipatedVSyncTimeFrom(now); - const auto vsyncPeriod = mVsyncSchedule->getTracker().currentPeriod(); - return DisplayStatInfo{.vsyncTime = vsyncTime, .vsyncPeriod = vsyncPeriod}; -} - ConnectionHandle Scheduler::enableVSyncInjection(bool enable) { if (mInjectVSyncs == enable) { return {}; @@ -497,24 +489,10 @@ void Scheduler::addPresentFence(std::shared_ptr<FenceTime> fence) { } void Scheduler::registerLayer(Layer* layer) { - using WindowType = gui::WindowInfo::Type; - - scheduler::LayerHistory::LayerVoteType voteType; - - if (!mFeatures.test(Feature::kContentDetection) || - layer->getWindowType() == WindowType::STATUS_BAR) { - voteType = scheduler::LayerHistory::LayerVoteType::NoVote; - } else if (layer->getWindowType() == WindowType::WALLPAPER) { - // Running Wallpaper at Min is considered as part of content detection. - voteType = scheduler::LayerHistory::LayerVoteType::Min; - } else { - voteType = scheduler::LayerHistory::LayerVoteType::Heuristic; - } - // If the content detection feature is off, we still keep the layer history, // since we use it for other features (like Frame Rate API), so layers // still need to be registered. - mLayerHistory.registerLayer(layer, voteType); + mLayerHistory.registerLayer(layer, mFeatures.test(Feature::kContentDetection)); } void Scheduler::deregisterLayer(Layer* layer) { @@ -535,6 +513,11 @@ void Scheduler::setModeChangePending(bool pending) { mLayerHistory.setModeChangePending(pending); } +void Scheduler::setDefaultFrameRateCompatibility(Layer* layer) { + mLayerHistory.setDefaultFrameRateCompatibility(layer, + mFeatures.test(Feature::kContentDetection)); +} + void Scheduler::chooseRefreshRateForContent() { const auto configs = holdRefreshRateConfigs(); if (!configs->canSwitch()) return; @@ -776,11 +759,4 @@ void Scheduler::setPreferredRefreshRateForUid(FrameRateOverride frameRateOverrid mFrameRateOverrideMappings.setPreferredRefreshRateForUid(frameRateOverride); } -std::chrono::steady_clock::time_point Scheduler::getPreviousVsyncFrom( - nsecs_t expectedPresentTime) const { - const auto presentTime = std::chrono::nanoseconds(expectedPresentTime); - const auto vsyncPeriod = std::chrono::nanoseconds(mVsyncSchedule->getTracker().currentPeriod()); - return std::chrono::steady_clock::time_point(presentTime - vsyncPeriod); -} - } // namespace android::scheduler diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index a8043bf94c..f800eeb8ee 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -33,6 +33,7 @@ #pragma clang diagnostic pop // ignored "-Wconversion -Wextra" #include <scheduler/Features.h> +#include <scheduler/Time.h> #include "EventThread.h" #include "FrameRateOverrideMappings.h" @@ -131,7 +132,7 @@ public: impl::EventThread::InterceptVSyncsCallback); sp<IDisplayEventConnection> createDisplayEventConnection( - ConnectionHandle, ISurfaceComposer::EventRegistrationFlags eventRegistration = {}); + ConnectionHandle, EventRegistrationFlags eventRegistration = {}); sp<EventThreadConnection> getEventConnection(ConnectionHandle); @@ -148,8 +149,6 @@ public: void setDuration(ConnectionHandle, std::chrono::nanoseconds workDuration, std::chrono::nanoseconds readyDuration); - DisplayStatInfo getDisplayStatInfo(nsecs_t now); - // Returns injector handle if injection has toggled, or an invalid handle otherwise. ConnectionHandle enableVSyncInjection(bool enable); // Returns false if injection is disabled. @@ -176,6 +175,7 @@ public: void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType) EXCLUDES(mRefreshRateConfigsLock); void setModeChangePending(bool pending); + void setDefaultFrameRateCompatibility(Layer*); void deregisterLayer(Layer*); // Detects content using layer history, and selects a matching refresh rate. @@ -188,14 +188,12 @@ public: void setDisplayPowerMode(hal::PowerMode powerMode); - VSyncDispatch& getVsyncDispatch() { return mVsyncSchedule->getDispatch(); } + VsyncSchedule& getVsyncSchedule() { return *mVsyncSchedule; } // Returns true if a given vsync timestamp is considered valid vsync // for a given uid bool isVsyncValid(nsecs_t expectedVsyncTimestamp, uid_t uid) const; - std::chrono::steady_clock::time_point getPreviousVsyncFrom(nsecs_t expectedPresentTime) const; - void dump(std::string&) const; void dump(ConnectionHandle, std::string&) const; void dumpVsync(std::string&) const; @@ -248,7 +246,7 @@ private: // Create a connection on the given EventThread. ConnectionHandle createConnection(std::unique_ptr<EventThread>); sp<EventThreadConnection> createConnectionInternal( - EventThread*, ISurfaceComposer::EventRegistrationFlags eventRegistration = {}); + EventThread*, EventRegistrationFlags eventRegistration = {}); // Update feature state machine to given state when corresponding timer resets or expires. void kernelIdleTimerCallback(TimerState) EXCLUDES(mRefreshRateConfigsLock); diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp index 3a918a1660..95bc31f239 100644 --- a/services/surfaceflinger/Scheduler/VsyncSchedule.cpp +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.cpp @@ -68,6 +68,14 @@ VsyncSchedule::VsyncSchedule(TrackerPtr tracker, DispatchPtr dispatch, Controlle VsyncSchedule::VsyncSchedule(VsyncSchedule&&) = default; VsyncSchedule::~VsyncSchedule() = default; +Period VsyncSchedule::period() const { + return Period::fromNs(mTracker->currentPeriod()); +} + +TimePoint VsyncSchedule::vsyncDeadlineAfter(TimePoint timePoint) const { + return TimePoint::fromNs(mTracker->nextAnticipatedVSyncTimeFrom(timePoint.ns())); +} + void VsyncSchedule::dump(std::string& out) const { out.append("VsyncController:\n"); mController->dump(out); diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h index 0d9b114875..8c17409b02 100644 --- a/services/surfaceflinger/Scheduler/VsyncSchedule.h +++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h @@ -20,6 +20,7 @@ #include <string> #include <scheduler/Features.h> +#include <scheduler/Time.h> namespace android::scheduler { @@ -38,6 +39,9 @@ public: VsyncSchedule(VsyncSchedule&&); ~VsyncSchedule(); + Period period() const; + TimePoint vsyncDeadlineAfter(TimePoint) const; + // TODO(b/185535769): Hide behind API. const VsyncTracker& getTracker() const { return *mTracker; } VsyncTracker& getTracker() { return *mTracker; } diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Time.h b/services/surfaceflinger/Scheduler/include/scheduler/Time.h new file mode 100644 index 0000000000..6fa548e5a7 --- /dev/null +++ b/services/surfaceflinger/Scheduler/include/scheduler/Time.h @@ -0,0 +1,67 @@ +/* + * Copyright 2022 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 <chrono> + +#include <utils/Timers.h> + +namespace android { +namespace scheduler { + +// TODO(b/185535769): Pull Clock.h to libscheduler to reuse this. +using SchedulerClock = std::chrono::high_resolution_clock; +static_assert(SchedulerClock::is_steady); + +} // namespace scheduler + +struct Duration; + +struct TimePoint : scheduler::SchedulerClock::time_point { + explicit TimePoint(const Duration&); + + // Implicit conversion from std::chrono counterpart. + constexpr TimePoint(scheduler::SchedulerClock::time_point p) + : scheduler::SchedulerClock::time_point(p) {} + + static TimePoint fromNs(nsecs_t); + + nsecs_t ns() const; +}; + +struct Duration : TimePoint::duration { + // Implicit conversion from std::chrono counterpart. + constexpr Duration(TimePoint::duration d) : TimePoint::duration(d) {} + + static Duration fromNs(nsecs_t ns) { return {std::chrono::nanoseconds(ns)}; } + + nsecs_t ns() const { return std::chrono::nanoseconds(*this).count(); } +}; + +using Period = Duration; + +inline TimePoint::TimePoint(const Duration& d) : scheduler::SchedulerClock::time_point(d) {} + +inline TimePoint TimePoint::fromNs(nsecs_t ns) { + return TimePoint(Duration::fromNs(ns)); +} + +inline nsecs_t TimePoint::ns() const { + return Duration(time_since_epoch()).ns(); +} + +} // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 6e74eef068..3874371b53 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -30,6 +30,7 @@ #include <android-base/strings.h> #include <android/configuration.h> #include <android/gui/IDisplayEventConnection.h> +#include <android/gui/StaticDisplayInfo.h> #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h> #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> #include <android/hardware/configstore/1.1/types.h> @@ -55,6 +56,7 @@ #include <ftl/fake_guard.h> #include <ftl/future.h> #include <ftl/small_map.h> +#include <gui/AidlStatusUtil.h> #include <gui/BufferQueue.h> #include <gui/DebugEGLImageTracker.h> #include <gui/IProducerListener.h> @@ -103,8 +105,6 @@ #include <ui/DisplayIdentification.h> #include "BackgroundExecutor.h" -#include "BufferLayer.h" -#include "BufferQueueLayer.h" #include "BufferStateLayer.h" #include "Client.h" #include "Colorizer.h" @@ -128,7 +128,6 @@ #include "LayerProtoHelper.h" #include "LayerRenderArea.h" #include "LayerVector.h" -#include "MonitoredProducer.h" #include "MutexUtils.h" #include "NativeWindowSurface.h" #include "RefreshRateOverlay.h" @@ -154,6 +153,10 @@ #define NO_THREAD_SAFETY_ANALYSIS \ _Pragma("GCC error \"Prefer <ftl/fake_guard.h> or MutexUtils.h helpers.\"") +// To enable layer borders in the system, change the below flag to true. +#undef DOES_CONTAIN_BORDER +#define DOES_CONTAIN_BORDER false + namespace android { using namespace std::string_literals; @@ -170,9 +173,12 @@ using CompositionStrategyPredictionState = android::compositionengine::impl:: using base::StringAppendF; using gui::DisplayInfo; +using gui::GameMode; using gui::IDisplayEventConnection; using gui::IWindowInfosListener; +using gui::LayerMetadata; using gui::WindowInfo; +using gui::aidl_utils::binderStatusFromStatusT; using ui::ColorMode; using ui::Dataspace; using ui::DisplayPrimaries; @@ -273,6 +279,8 @@ const String16 sInternalSystemWindow("android.permission.INTERNAL_SYSTEM_WINDOW" const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled"; +static const int MAX_TRACING_MEMORY = 1024 * 1024 * 1024; // 1GB + // --------------------------------------------------------------------------- int64_t SurfaceFlinger::dispSyncPresentTimeOffset; bool SurfaceFlinger::useHwcForRgbToYuv; @@ -331,7 +339,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag) mInternalDisplayDensity(getDensityFromProperty("ro.sf.lcd_density", true)), mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)), mPowerAdvisor(std::make_unique<Hwc2::impl::PowerAdvisor>(*this)), - mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make(*this)) { + mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make()) { ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str()); } @@ -402,7 +410,7 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI property_get("ro.sf.blurs_are_expensive", value, "0"); mBlursAreExpensive = atoi(value); - const size_t defaultListSize = ISurfaceComposer::MAX_LAYERS; + const size_t defaultListSize = MAX_LAYERS; auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize)); mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize; mGraphicBufferProducerListSizeLogThreshold = @@ -483,11 +491,6 @@ void SurfaceFlinger::run() { mScheduler->run(); } -sp<ISurfaceComposerClient> SurfaceFlinger::createConnection() { - const sp<Client> client = new Client(this); - return client->initCheck() == NO_ERROR ? client : nullptr; -} - sp<IBinder> SurfaceFlinger::createDisplay(const String8& displayName, bool secure) { // onTransact already checks for some permissions, but adding an additional check here. // This is to ensure that only system and graphics can request to create a secure @@ -881,17 +884,6 @@ void SurfaceFlinger::startBootAnim() { // ---------------------------------------------------------------------------- -bool SurfaceFlinger::authenticateSurfaceTexture( - const sp<IGraphicBufferProducer>& bufferProducer) const { - Mutex::Autolock _l(mStateLock); - return authenticateSurfaceTextureLocked(bufferProducer); -} - -bool SurfaceFlinger::authenticateSurfaceTextureLocked( - const sp<IGraphicBufferProducer>& /* bufferProducer */) const { - return false; -} - status_t SurfaceFlinger::getSupportedFrameTimestamps( std::vector<FrameEvent>* outSupported) const { *outSupported = { @@ -1061,12 +1053,14 @@ status_t SurfaceFlinger::getDynamicDisplayInfo(const sp<IBinder>& displayToken, return NO_ERROR; } -status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* stats) { - if (!stats) { +status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* outStats) { + if (!outStats) { return BAD_VALUE; } - *stats = mScheduler->getDisplayStatInfo(systemTime()); + const auto& schedule = mScheduler->getVsyncSchedule(); + outStats->vsyncTime = schedule.vsyncDeadlineAfter(scheduler::SchedulerClock::now()).ns(); + outStats->vsyncPeriod = schedule.period().ns(); return NO_ERROR; } @@ -1575,15 +1569,13 @@ status_t SurfaceFlinger::enableVSyncInjections(bool enable) { status_t SurfaceFlinger::injectVSync(nsecs_t when) { Mutex::Autolock lock(mStateLock); - const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(when); - const auto expectedPresent = calculateExpectedPresentTime(stats); - return mScheduler->injectVSync(when, /*expectedVSyncTime=*/expectedPresent, - /*deadlineTimestamp=*/expectedPresent) - ? NO_ERROR - : BAD_VALUE; + const nsecs_t expectedPresentTime = calculateExpectedPresentTime(when).ns(); + const nsecs_t deadlineTimestamp = expectedPresentTime; + return mScheduler->injectVSync(when, expectedPresentTime, deadlineTimestamp) ? NO_ERROR + : BAD_VALUE; } -status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) { +status_t SurfaceFlinger::getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) { outLayers->clear(); auto future = mScheduler->schedule([=] { const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()); @@ -1815,10 +1807,11 @@ status_t SurfaceFlinger::getDisplayDecorationSupport( // ---------------------------------------------------------------------------- sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection( - ISurfaceComposer::VsyncSource vsyncSource, - ISurfaceComposer::EventRegistrationFlags eventRegistration) { + gui::ISurfaceComposer::VsyncSource vsyncSource, EventRegistrationFlags eventRegistration) { const auto& handle = - vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle; + vsyncSource == gui::ISurfaceComposer::VsyncSource::eVsyncSourceSurfaceFlinger + ? mSfConnectionHandle + : mAppConnectionHandle; return mScheduler->createDisplayEventConnection(handle, eventRegistration); } @@ -1891,11 +1884,6 @@ void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t t } } -void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { - std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock); - *compositorTiming = getBE().mCompositorTiming; -} - void SurfaceFlinger::onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) { const bool connected = connection == hal::Connection::CONNECTED; @@ -1956,18 +1944,15 @@ void SurfaceFlinger::setVsyncEnabled(bool enabled) { })); } -SurfaceFlinger::FenceWithFenceTime SurfaceFlinger::previousFrameFence() { - const auto now = systemTime(); - const auto vsyncPeriod = mScheduler->getDisplayStatInfo(now).vsyncPeriod; - const bool expectedPresentTimeIsTheNextVsync = mExpectedPresentTime - now <= vsyncPeriod; - return expectedPresentTimeIsTheNextVsync ? mPreviousPresentFences[0] - : mPreviousPresentFences[1]; +auto SurfaceFlinger::getPreviousPresentFence(nsecs_t frameTime, Period vsyncPeriod) + -> const FenceTimePtr& { + const bool isTwoVsyncsAhead = mExpectedPresentTime - frameTime > vsyncPeriod.ns(); + const size_t i = static_cast<size_t>(isTwoVsyncsAhead); + return mPreviousPresentFences[i].fenceTime; } -bool SurfaceFlinger::previousFramePending(int graceTimeMs) { +bool SurfaceFlinger::isFencePending(const FenceTimePtr& fence, int graceTimeMs) { ATRACE_CALL(); - const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime; - if (fence == FenceTime::NO_FENCE) { return false; } @@ -1978,37 +1963,32 @@ bool SurfaceFlinger::previousFramePending(int graceTimeMs) { return status == -ETIME; } -nsecs_t SurfaceFlinger::previousFramePresentTime() { - const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime; +TimePoint SurfaceFlinger::calculateExpectedPresentTime(nsecs_t frameTime) const { + const auto& schedule = mScheduler->getVsyncSchedule(); - if (fence == FenceTime::NO_FENCE) { - return Fence::SIGNAL_TIME_INVALID; + const TimePoint vsyncDeadline = schedule.vsyncDeadlineAfter(TimePoint::fromNs(frameTime)); + if (mVsyncModulator->getVsyncConfig().sfOffset > 0) { + return vsyncDeadline; } - return fence->getSignalTime(); -} - -nsecs_t SurfaceFlinger::calculateExpectedPresentTime(DisplayStatInfo stats) const { - // Inflate the expected present time if we're targetting the next vsync. - return mVsyncModulator->getVsyncConfig().sfOffset > 0 ? stats.vsyncTime - : stats.vsyncTime + stats.vsyncPeriod; + // Inflate the expected present time if we're targeting the next vsync. + return vsyncDeadline + schedule.period(); } bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVsyncTime) FTL_FAKE_GUARD(kMainThreadContext) { - // calculate the expected present time once and use the cached - // value throughout this frame to make sure all layers are - // seeing this same value. - if (expectedVsyncTime >= frameTime) { - mExpectedPresentTime = expectedVsyncTime; - } else { - const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(frameTime); - mExpectedPresentTime = calculateExpectedPresentTime(stats); - } - + // The expectedVsyncTime, which was predicted when this frame was scheduled, is normally in the + // future relative to frameTime, but may not be for delayed frames. Adjust mExpectedPresentTime + // accordingly, but not mScheduledPresentTime. const nsecs_t lastScheduledPresentTime = mScheduledPresentTime; mScheduledPresentTime = expectedVsyncTime; + // Calculate the expected present time once and use the cached value throughout this frame to + // make sure all layers are seeing this same value. + mExpectedPresentTime = expectedVsyncTime >= frameTime + ? expectedVsyncTime + : calculateExpectedPresentTime(frameTime).ns(); + const auto vsyncIn = [&] { if (!ATRACE_ENABLED()) return 0.f; return (mExpectedPresentTime - systemTime()) / 1e6f; @@ -2016,6 +1996,9 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, vsyncId, vsyncIn, mExpectedPresentTime == expectedVsyncTime ? "" : " (adjusted)"); + const Period vsyncPeriod = mScheduler->getVsyncSchedule().period(); + const FenceTimePtr& previousPresentFence = getPreviousPresentFence(frameTime, vsyncPeriod); + // When Backpressure propagation is enabled we want to give a small grace period // for the present fence to fire instead of just giving up on this frame to handle cases // where present fence is just about to get signaled. @@ -2024,7 +2007,8 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected // Pending frames may trigger backpressure propagation. const TracedOrdinal<bool> framePending = {"PrevFramePending", - previousFramePending(graceTimeForPresentFenceMs)}; + isFencePending(previousPresentFence, + graceTimeForPresentFenceMs)}; // Frame missed counts for metrics tracking. // A frame is missed if the prior frame is still pending. If no longer pending, @@ -2034,9 +2018,8 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected // Add some slop to correct for drift. This should generally be // smaller than a typical frame duration, but should not be so small // that it reports reasonable drift as a missed frame. - const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(systemTime()); - const nsecs_t frameMissedSlop = stats.vsyncPeriod / 2; - const nsecs_t previousPresentTime = previousFramePresentTime(); + const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2; + const nsecs_t previousPresentTime = previousPresentFence->getSignalTime(); const TracedOrdinal<bool> frameMissed = {"PrevFrameMissed", framePending || (previousPresentTime >= 0 && @@ -2060,6 +2043,11 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected mGpuFrameMissedCount++; } + if (mTracingEnabledChanged) { + mLayerTracingEnabled = mLayerTracing.isEnabled(); + mTracingEnabledChanged = false; + } + // If we are in the middle of a mode change and the fence hasn't // fired yet just wait for the next commit. if (mSetActiveModePending) { @@ -2108,11 +2096,6 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected } } - if (mTracingEnabledChanged) { - mLayerTracingEnabled = mLayerTracing.isEnabled(); - mTracingEnabledChanged = false; - } - if (mRefreshRateOverlaySpinner) { Mutex::Autolock lock(mStateLock); if (const auto display = getDefaultDisplayDeviceLocked()) { @@ -2123,11 +2106,11 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected // Composite if transactions were committed, or if requested by HWC. bool mustComposite = mMustComposite.exchange(false); { - mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(stats.vsyncPeriod)); + mFrameTimeline->setSfWakeUp(vsyncId, frameTime, Fps::fromPeriodNsecs(vsyncPeriod.ns())); bool needsTraversal = false; if (clearTransactionFlags(eTransactionFlushNeeded)) { - needsTraversal |= commitCreatedLayers(); + needsTraversal |= commitCreatedLayers(vsyncId); needsTraversal |= flushTransactionQueues(vsyncId); } @@ -2172,8 +2155,9 @@ bool SurfaceFlinger::commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expected if (mLayerTracingEnabled && !mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) { // This will block and tracing should only be enabled for debugging. - mLayerTracing.notify(mVisibleRegionsDirty, frameTime); + mLayerTracing.notify(mVisibleRegionsDirty, frameTime, vsyncId); } + mLastCommittedVsyncId = vsyncId; persistDisplayBrightness(mustComposite); @@ -2197,6 +2181,22 @@ void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) if (auto layerFE = layer->getCompositionEngineLayerFE()) refreshArgs.layers.push_back(layerFE); }); + + if (DOES_CONTAIN_BORDER) { + refreshArgs.borderInfoList.clear(); + mDrawingState.traverse([&refreshArgs](Layer* layer) { + if (layer->isBorderEnabled()) { + compositionengine::BorderRenderInfo info; + info.width = layer->getBorderWidth(); + info.color = layer->getBorderColor(); + layer->traverse(LayerVector::StateSet::Drawing, [&info](Layer* ilayer) { + info.layerIds.push_back(ilayer->getSequence()); + }); + refreshArgs.borderInfoList.emplace_back(std::move(info)); + } + }); + } + refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size()); for (auto layer : mLayersWithQueuedFrames) { if (auto layerFE = layer->getCompositionEngineLayerFE()) @@ -2227,7 +2227,9 @@ void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) } const auto expectedPresentTime = mExpectedPresentTime.load(); - const auto prevVsyncTime = mScheduler->getPreviousVsyncFrom(expectedPresentTime); + const auto prevVsyncTime = + TimePoint::fromNs(expectedPresentTime) - mScheduler->getVsyncSchedule().period(); + const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration; refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration; refreshArgs.previousPresentFence = mPreviousPresentFences[0].fenceTime; @@ -2284,7 +2286,7 @@ void SurfaceFlinger::composite(nsecs_t frameTime, int64_t vsyncId) mLayersWithQueuedFrames.clear(); if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) { // This will block and should only be used for debugging. - mLayerTracing.notify(mVisibleRegionsDirty, frameTime); + mLayerTracing.notify(mVisibleRegionsDirty, frameTime, vsyncId); } mVisibleRegionsWereDirtyThisFrame = mVisibleRegionsDirty; // Cache value for use in post-comp @@ -2314,11 +2316,11 @@ void SurfaceFlinger::updateLayerGeometry() { mLayersPendingRefresh.clear(); } -void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime, - std::shared_ptr<FenceTime>& presentFenceTime) { +nsecs_t SurfaceFlinger::trackPresentLatency(nsecs_t compositeTime, + std::shared_ptr<FenceTime> presentFenceTime) { // Update queue of past composite+present times and determine the // most recently known composite to present latency. - getBE().mCompositePresentTimes.push({compositeTime, presentFenceTime}); + getBE().mCompositePresentTimes.push({compositeTime, std::move(presentFenceTime)}); nsecs_t compositeToPresentLatency = -1; while (!getBE().mCompositePresentTimes.empty()) { SurfaceFlingerBE::CompositePresentTime& cpt = getBE().mCompositePresentTimes.front(); @@ -2337,41 +2339,7 @@ void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_ getBE().mCompositePresentTimes.pop(); } - setCompositorTimingSnapped(stats, compositeToPresentLatency); -} - -void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats, - nsecs_t compositeToPresentLatency) { - // Avoid division by 0 by defaulting to 60Hz - const auto vsyncPeriod = stats.vsyncPeriod ?: (60_Hz).getPeriodNsecs(); - - // Integer division and modulo round toward 0 not -inf, so we need to - // treat negative and positive offsets differently. - nsecs_t idealLatency = (mVsyncConfiguration->getCurrentConfigs().late.sfOffset > 0) - ? (vsyncPeriod - - (mVsyncConfiguration->getCurrentConfigs().late.sfOffset % vsyncPeriod)) - : ((-mVsyncConfiguration->getCurrentConfigs().late.sfOffset) % vsyncPeriod); - - // Just in case mVsyncConfiguration->getCurrentConfigs().late.sf == -vsyncInterval. - if (idealLatency <= 0) { - idealLatency = vsyncPeriod; - } - - // Snap the latency to a value that removes scheduling jitter from the - // composition and present times, which often have >1ms of jitter. - // Reducing jitter is important if an app attempts to extrapolate - // something (such as user input) to an accurate diasplay time. - // Snapping also allows an app to precisely calculate - // mVsyncConfiguration->getCurrentConfigs().late.sf with (presentLatency % interval). - const nsecs_t bias = vsyncPeriod / 2; - const int64_t extraVsyncs = ((compositeToPresentLatency - idealLatency + bias) / vsyncPeriod); - const nsecs_t snappedCompositeToPresentLatency = - (extraVsyncs > 0) ? idealLatency + (extraVsyncs * vsyncPeriod) : idealLatency; - - std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock); - getBE().mCompositorTiming.deadline = stats.vsyncTime - idealLatency; - getBE().mCompositorTiming.interval = vsyncPeriod; - getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency; + return compositeToPresentLatency; } bool SurfaceFlinger::isHdrLayer(Layer* layer) const { @@ -2458,18 +2426,20 @@ void SurfaceFlinger::postComposition() { mFrameTimeline->setSfPresent(/* sfPresentTime */ now, mPreviousPresentFences[0].fenceTime, glCompositionDoneFenceTime); - const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now); - // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might // be sampled a little later than when we started doing work for this frame, - // but that should be okay since updateCompositorTiming has snapping logic. - updateCompositorTiming(stats, mCompositionEngine->getLastFrameRefreshTimestamp(), - mPreviousPresentFences[0].fenceTime); - CompositorTiming compositorTiming; - { - std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock); - compositorTiming = getBE().mCompositorTiming; - } + // but that should be okay since CompositorTiming has snapping logic. + const nsecs_t compositeTime = mCompositionEngine->getLastFrameRefreshTimestamp(); + const nsecs_t presentLatency = + trackPresentLatency(compositeTime, mPreviousPresentFences[0].fenceTime); + + const auto& schedule = mScheduler->getVsyncSchedule(); + const TimePoint vsyncDeadline = schedule.vsyncDeadlineAfter(TimePoint::fromNs(now)); + const Period vsyncPeriod = schedule.period(); + const nsecs_t vsyncPhase = mVsyncConfiguration->getCurrentConfigs().late.sfOffset; + + const CompositorTiming compositorTiming(vsyncDeadline.ns(), vsyncPeriod.ns(), vsyncPhase, + presentLatency); for (const auto& layer: mLayersWithQueuedFrames) { layer->onPostComposition(display, glCompositionDoneFenceTime, @@ -2581,7 +2551,7 @@ void SurfaceFlinger::postComposition() { mHasPoweredOff = false; } else { nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime; - size_t numPeriods = static_cast<size_t>(elapsedTime / stats.vsyncPeriod); + const size_t numPeriods = static_cast<size_t>(elapsedTime / vsyncPeriod.ns()); if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) { getBE().mFrameBuckets[numPeriods] += elapsedTime; } else { @@ -3103,6 +3073,7 @@ void SurfaceFlinger::processDisplayChangesLocked() { const KeyedVector<wp<IBinder>, DisplayDeviceState>& draw(mDrawingState.displays); if (!curr.isIdenticalTo(draw)) { mVisibleRegionsDirty = true; + mUpdateInputInfo = true; // find the displays that were removed // (ie: in drawing state but not in current state) @@ -3147,6 +3118,7 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { if (mSomeChildrenChanged) { mVisibleRegionsDirty = true; mSomeChildrenChanged = false; + mUpdateInputInfo = true; } // Update transform hint. @@ -3188,7 +3160,7 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { } } - if (!hintDisplay) { + if (!hintDisplay && mDisplays.size() > 0) { // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to // redraw after transform hint changes. See bug 8508397. @@ -3198,7 +3170,11 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { hintDisplay = getDefaultDisplayDeviceLocked(); } - layer->updateTransformHint(hintDisplay->getTransformHint()); + if (hintDisplay) { + layer->updateTransformHint(hintDisplay->getTransformHint()); + } else { + ALOGW("Ignoring transform hint update for %s", layer->getDebugName()); + } }); } @@ -3206,6 +3182,7 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { mLayersAdded = false; // Layers have been added. mVisibleRegionsDirty = true; + mUpdateInputInfo = true; } // some layers might have been removed, so @@ -3213,6 +3190,7 @@ void SurfaceFlinger::commitTransactionsLocked(uint32_t transactionFlags) { if (mLayersRemoved) { mLayersRemoved = false; mVisibleRegionsDirty = true; + mUpdateInputInfo = true; mDrawingState.traverseInZOrder([&](Layer* layer) { if (mLayersPendingRemoval.indexOf(layer) >= 0) { // this layer is not visible anymore @@ -3237,14 +3215,14 @@ void SurfaceFlinger::updateInputFlinger() { std::vector<WindowInfo> windowInfos; std::vector<DisplayInfo> displayInfos; bool updateWindowInfo = false; - if (mVisibleRegionsDirty || mInputInfoChanged) { - mInputInfoChanged = false; + if (mUpdateInputInfo) { + mUpdateInputInfo = false; updateWindowInfo = true; buildWindowInfos(windowInfos, displayInfos); - } - if (!updateWindowInfo && mInputWindowCommands.empty()) { + } else if (mInputWindowCommands.empty()) { return; } + BackgroundExecutor::getInstance().sendCallbacks({[updateWindowInfo, windowInfos = std::move(windowInfos), displayInfos = std::move(displayInfos), @@ -3253,12 +3231,17 @@ void SurfaceFlinger::updateInputFlinger() { inputFlinger = mInputFlinger, this]() { ATRACE_NAME("BackgroundExecutor::updateInputFlinger"); if (updateWindowInfo) { - mWindowInfosListenerInvoker->windowInfosChanged(windowInfos, displayInfos, - inputWindowCommands.syncInputWindows); - } else if (inputWindowCommands.syncInputWindows) { - // If the caller requested to sync input windows, but there are no - // changes to input windows, notify immediately. - windowInfosReported(); + mWindowInfosListenerInvoker + ->windowInfosChanged(windowInfos, displayInfos, + inputWindowCommands.windowInfosReportedListeners); + } else { + // If there are listeners but no changes to input windows, call the listeners + // immediately. + for (const auto& listener : inputWindowCommands.windowInfosReportedListeners) { + if (IInterface::asBinder(listener)->isBinderAlive()) { + listener->onWindowInfosReported(); + } + } } for (const auto& focusRequest : inputWindowCommands.focusRequests) { inputFlinger->setFocusedWindow(focusRequest); @@ -3445,8 +3428,8 @@ void SurfaceFlinger::initScheduler(const sp<DisplayDevice>& display) { mInterceptor->saveVSyncEvent(timestamp); }); - mScheduler->initVsync(mScheduler->getVsyncDispatch(), *mFrameTimeline->getTokenManager(), - configs.late.sfWorkDuration); + mScheduler->initVsync(mScheduler->getVsyncSchedule().getDispatch(), + *mFrameTimeline->getTokenManager(), configs.late.sfWorkDuration); mRegionSamplingThread = new RegionSamplingThread(*this, RegionSamplingThread::EnvironmentTimingTunables()); @@ -3638,9 +3621,9 @@ bool SurfaceFlinger::latchBuffers() { status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle, const sp<Layer>& layer, const wp<Layer>& parent, bool addToRoot, uint32_t* outTransformHint) { - if (mNumLayers >= ISurfaceComposer::MAX_LAYERS) { + if (mNumLayers >= MAX_LAYERS) { ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(), - ISurfaceComposer::MAX_LAYERS); + MAX_LAYERS); static_cast<void>(mScheduler->schedule([=] { ALOGE("Dumping random sampling of on-screen layers: "); mDrawingState.traverse([&](Layer *layer) { @@ -3916,10 +3899,10 @@ bool SurfaceFlinger::transactionFlushNeeded() { bool SurfaceFlinger::frameIsEarly(nsecs_t expectedPresentTime, int64_t vsyncId) const { // The amount of time SF can delay a frame if it is considered early based // on the VsyncModulator::VsyncConfig::appWorkDuration - constexpr static std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms; + constexpr std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms; - const auto currentVsyncPeriod = mScheduler->getDisplayStatInfo(systemTime()).vsyncPeriod; - const auto earlyLatchVsyncThreshold = currentVsyncPeriod / 2; + const nsecs_t currentVsyncPeriod = mScheduler->getVsyncSchedule().period().ns(); + const nsecs_t earlyLatchVsyncThreshold = currentVsyncPeriod / 2; const auto prediction = mFrameTimeline->getTokenManager()->getPredictionsForToken(vsyncId); if (!prediction.has_value()) { @@ -4081,11 +4064,9 @@ void SurfaceFlinger::queueTransaction(TransactionState& state) { Mutex::Autolock lock(mQueueLock); // Generate a CountDownLatch pending state if this is a synchronous transaction. - if ((state.flags & eSynchronous) || state.inputWindowCommands.syncInputWindows) { - state.transactionCommittedSignal = std::make_shared<CountDownLatch>( - (state.inputWindowCommands.syncInputWindows - ? (CountDownLatch::eSyncInputWindows | CountDownLatch::eSyncTransaction) - : CountDownLatch::eSyncTransaction)); + if (state.flags & eSynchronous) { + state.transactionCommittedSignal = + std::make_shared<CountDownLatch>(CountDownLatch::eSyncTransaction); } mTransactionQueue.emplace_back(state); @@ -4467,6 +4448,11 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (what & layer_state_t::eBlurRegionsChanged) { if (layer->setBlurRegions(s.blurRegions)) flags |= eTraversalNeeded; } + if (what & layer_state_t::eRenderBorderChanged) { + if (layer->enableBorder(s.borderEnabled, s.borderWidth, s.borderColor)) { + flags |= eTraversalNeeded; + } + } if (what & layer_state_t::eLayerStackChanged) { ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer); // We only allow setting layer stacks for top level layers, @@ -4518,9 +4504,10 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime } std::optional<nsecs_t> dequeueBufferTimestamp; if (what & layer_state_t::eMetadataChanged) { - dequeueBufferTimestamp = s.metadata.getInt64(METADATA_DEQUEUE_TIME); + dequeueBufferTimestamp = s.metadata.getInt64(gui::METADATA_DEQUEUE_TIME); - if (const int32_t gameMode = s.metadata.getInt32(METADATA_GAME_MODE, -1); gameMode != -1) { + if (const int32_t gameMode = s.metadata.getInt32(gui::METADATA_GAME_MODE, -1); + gameMode != -1) { // The transaction will be received on the Task layer and needs to be applied to all // child layers. Child layers that are added at a later point will obtain the game mode // info through addChild(). @@ -4537,6 +4524,14 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (what & layer_state_t::eShadowRadiusChanged) { if (layer->setShadowRadius(s.shadowRadius)) flags |= eTraversalNeeded; } + if (what & layer_state_t::eDefaultFrameRateCompatibilityChanged) { + const auto compatibility = + Layer::FrameRate::convertCompatibility(s.defaultFrameRateCompatibility); + + if (layer->setDefaultFrameRateCompatibility(compatibility)) { + flags |= eTraversalNeeded; + } + } if (what & layer_state_t::eFrameRateSelectionPriority) { if (layer->setFrameRateSelectionPriority(s.frameRateSelectionPriority)) { flags |= eTraversalNeeded; @@ -4587,7 +4582,7 @@ uint32_t SurfaceFlinger::setClientStateLocked(const FrameTimelineInfo& frameTime if (what & layer_state_t::eDropInputModeChanged) { if (layer->setDropInputMode(s.dropInputMode)) { flags |= eTraversalNeeded; - mInputInfoChanged = true; + mUpdateInputInfo = true; } } // This has to happen after we reparent children because when we reparent to null we remove @@ -4736,42 +4731,6 @@ status_t SurfaceFlinger::createLayer(LayerCreationArgs& args, sp<IBinder>* outHa return result; } -status_t SurfaceFlinger::createBufferQueueLayer(LayerCreationArgs& args, PixelFormat& format, - sp<IBinder>* handle, - sp<IGraphicBufferProducer>* gbp, - sp<Layer>* outLayer) { - // initialize the surfaces - switch (format) { - case PIXEL_FORMAT_TRANSPARENT: - case PIXEL_FORMAT_TRANSLUCENT: - format = PIXEL_FORMAT_RGBA_8888; - break; - case PIXEL_FORMAT_OPAQUE: - format = PIXEL_FORMAT_RGBX_8888; - break; - } - - sp<BufferQueueLayer> layer; - args.textureName = getNewTexture(); - { - // Grab the SF state lock during this since it's the only safe way to access - // RenderEngine when creating a BufferLayerConsumer - // TODO: Check if this lock is still needed here - Mutex::Autolock lock(mStateLock); - layer = getFactory().createBufferQueueLayer(args); - } - - status_t err = layer->setDefaultBufferProperties(0, 0, format); - if (err == NO_ERROR) { - *handle = layer->getHandle(); - *gbp = layer->getProducer(); - *outLayer = layer; - } - - ALOGE_IF(err, "createBufferQueueLayer() failed (%s)", strerror(-err)); - return err; -} - status_t SurfaceFlinger::createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* handle, sp<Layer>* outLayer) { args.textureName = getNewTexture(); @@ -4846,10 +4805,6 @@ void SurfaceFlinger::onInitializeDisplays() { const nsecs_t vsyncPeriod = display->refreshRateConfigs().getActiveMode()->getVsyncPeriod(); mAnimFrameTracker.setDisplayRefreshPeriod(vsyncPeriod); mActiveDisplayTransformHint = display->getTransformHint(); - // Use phase of 0 since phase is not known. - // Use latency of 0, which will snap to the ideal latency. - DisplayStatInfo stats{0 /* vsyncTime */, vsyncPeriod}; - setCompositorTimingSnapped(stats, 0); } void SurfaceFlinger::initializeDisplays() { @@ -4930,6 +4885,9 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal: // Update display while dozing getHwComposer().setPowerMode(displayId, mode); if (isDisplayActiveLocked(display) && currentMode == hal::PowerMode::DOZE_SUSPEND) { + ALOGI("Force repainting for DOZE_SUSPEND -> DOZE or ON."); + mVisibleRegionsDirty = true; + scheduleRepaint(); mScheduler->onScreenAcquired(mAppConnectionHandle); mScheduler->resyncToHardwareVsync(true, refreshRate); } @@ -5525,29 +5483,11 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { #pragma clang diagnostic push #pragma clang diagnostic error "-Wswitch-enum" switch (static_cast<ISurfaceComposerTag>(code)) { - case ENABLE_VSYNC_INJECTIONS: - case INJECT_VSYNC: - if (!hasMockHwc()) return PERMISSION_DENIED; - [[fallthrough]]; // These methods should at minimum make sure that the client requested // access to SF. - case BOOT_FINISHED: - case CLEAR_ANIMATION_FRAME_STATS: - case GET_ANIMATION_FRAME_STATS: - case OVERRIDE_HDR_TYPES: case GET_HDR_CAPABILITIES: - case SET_DESIRED_DISPLAY_MODE_SPECS: - case GET_DESIRED_DISPLAY_MODE_SPECS: - case SET_ACTIVE_COLOR_MODE: - case SET_BOOT_DISPLAY_MODE: case GET_AUTO_LOW_LATENCY_MODE_SUPPORT: case GET_GAME_CONTENT_TYPE_SUPPORT: - case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: - case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: - case GET_DISPLAYED_CONTENT_SAMPLE: - case ADD_TUNNEL_MODE_ENABLED_LISTENER: - case REMOVE_TUNNEL_MODE_ENABLED_LISTENER: - case SET_GLOBAL_SHADOW_SETTINGS: case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: { // OVERRIDE_HDR_TYPES is used by CTS tests, which acquire the necessary // permission dynamically. Don't use the permission cache for this check. @@ -5560,100 +5500,38 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } return OK; } - case GET_LAYER_DEBUG_INFO: { - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) { - ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - return OK; - } - // Used by apps to hook Choreographer to SurfaceFlinger. - case CREATE_DISPLAY_EVENT_CONNECTION: // The following calls are currently used by clients that do not // request necessary permissions. However, they do not expose any secret // information, so it is OK to pass them. - case AUTHENTICATE_SURFACE: case GET_ACTIVE_COLOR_MODE: case GET_ACTIVE_DISPLAY_MODE: case GET_DISPLAY_COLOR_MODES: - case GET_DISPLAY_NATIVE_PRIMARIES: - case GET_STATIC_DISPLAY_INFO: - case GET_DYNAMIC_DISPLAY_INFO: case GET_DISPLAY_MODES: - case GET_SUPPORTED_FRAME_TIMESTAMPS: // Calling setTransactionState is safe, because you need to have been // granted a reference to Client* and Handle* to do anything with it. - case SET_TRANSACTION_STATE: - case CREATE_CONNECTION: - case GET_COLOR_MANAGEMENT: - case GET_COMPOSITION_PREFERENCE: - case GET_PROTECTED_CONTENT_SUPPORT: - // setFrameRate() is deliberately available for apps to call without any - // special permissions. - case SET_FRAME_RATE: - case GET_DISPLAY_DECORATION_SUPPORT: - case SET_FRAME_TIMELINE_INFO: - case GET_GPU_CONTEXT_PRIORITY: - case GET_MAX_ACQUIRED_BUFFER_COUNT: { + case SET_TRANSACTION_STATE: { // This is not sensitive information, so should not require permission control. return OK; } - case ADD_FPS_LISTENER: - case REMOVE_FPS_LISTENER: - case ADD_REGION_SAMPLING_LISTENER: - case REMOVE_REGION_SAMPLING_LISTENER: { - // codes that require permission check - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - if ((uid != AID_GRAPHICS) && - !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { - ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - return OK; - } - case ADD_TRANSACTION_TRACE_LISTENER: { - IPCThreadState* ipc = IPCThreadState::self(); - const int uid = ipc->getCallingUid(); - if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) { - return OK; - } - return PERMISSION_DENIED; - } - case SET_OVERRIDE_FRAME_RATE: { - const int uid = IPCThreadState::self()->getCallingUid(); - if (uid == AID_ROOT || uid == AID_SYSTEM) { - return OK; - } - return PERMISSION_DENIED; - } - case ON_PULL_ATOM: { - const int uid = IPCThreadState::self()->getCallingUid(); - if (uid == AID_SYSTEM) { - return OK; - } - return PERMISSION_DENIED; - } - case ADD_WINDOW_INFOS_LISTENER: - case REMOVE_WINDOW_INFOS_LISTENER: { - const int uid = IPCThreadState::self()->getCallingUid(); - if (uid == AID_SYSTEM || uid == AID_GRAPHICS) { - return OK; - } - return PERMISSION_DENIED; - } + case BOOT_FINISHED: + // Used by apps to hook Choreographer to SurfaceFlinger. + case CREATE_DISPLAY_EVENT_CONNECTION: + case CREATE_CONNECTION: case CREATE_DISPLAY: case DESTROY_DISPLAY: case GET_PRIMARY_PHYSICAL_DISPLAY_ID: case GET_PHYSICAL_DISPLAY_IDS: case GET_PHYSICAL_DISPLAY_TOKEN: + case AUTHENTICATE_SURFACE: case SET_POWER_MODE: + case GET_SUPPORTED_FRAME_TIMESTAMPS: case GET_DISPLAY_STATE: case GET_DISPLAY_STATS: + case GET_STATIC_DISPLAY_INFO: + case GET_DYNAMIC_DISPLAY_INFO: + case GET_DISPLAY_NATIVE_PRIMARIES: + case SET_ACTIVE_COLOR_MODE: + case SET_BOOT_DISPLAY_MODE: case CLEAR_BOOT_DISPLAY_MODE: case GET_BOOT_DISPLAY_MODE_SUPPORT: case SET_AUTO_LOW_LATENCY_MODE: @@ -5661,12 +5539,43 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { case CAPTURE_LAYERS: case CAPTURE_DISPLAY: case CAPTURE_DISPLAY_BY_ID: + case CLEAR_ANIMATION_FRAME_STATS: + case GET_ANIMATION_FRAME_STATS: + case OVERRIDE_HDR_TYPES: + case ON_PULL_ATOM: + case ENABLE_VSYNC_INJECTIONS: + case INJECT_VSYNC: + case GET_LAYER_DEBUG_INFO: + case GET_COLOR_MANAGEMENT: + case GET_COMPOSITION_PREFERENCE: + case GET_DISPLAYED_CONTENT_SAMPLING_ATTRIBUTES: + case SET_DISPLAY_CONTENT_SAMPLING_ENABLED: + case GET_DISPLAYED_CONTENT_SAMPLE: + case GET_PROTECTED_CONTENT_SUPPORT: case IS_WIDE_COLOR_DISPLAY: + case ADD_REGION_SAMPLING_LISTENER: + case REMOVE_REGION_SAMPLING_LISTENER: + case ADD_FPS_LISTENER: + case REMOVE_FPS_LISTENER: + case ADD_TUNNEL_MODE_ENABLED_LISTENER: + case REMOVE_TUNNEL_MODE_ENABLED_LISTENER: + case ADD_WINDOW_INFOS_LISTENER: + case REMOVE_WINDOW_INFOS_LISTENER: + case SET_DESIRED_DISPLAY_MODE_SPECS: + case GET_DESIRED_DISPLAY_MODE_SPECS: case GET_DISPLAY_BRIGHTNESS_SUPPORT: case SET_DISPLAY_BRIGHTNESS: case ADD_HDR_LAYER_INFO_LISTENER: case REMOVE_HDR_LAYER_INFO_LISTENER: case NOTIFY_POWER_BOOST: + case SET_GLOBAL_SHADOW_SETTINGS: + case GET_DISPLAY_DECORATION_SUPPORT: + case SET_FRAME_RATE: + case SET_OVERRIDE_FRAME_RATE: + case SET_FRAME_TIMELINE_INFO: + case ADD_TRANSACTION_TRACE_LISTENER: + case GET_GPU_CONTEXT_PRIORITY: + case GET_MAX_ACQUIRED_BUFFER_COUNT: LOG_FATAL("Deprecated opcode: %d, migrated to AIDL", code); return PERMISSION_DENIED; } @@ -5878,7 +5787,8 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r (fixedStartingTime) ? fixedStartingTime : systemTime(); mScheduler ->schedule([&]() FTL_FAKE_GUARD(mStateLock) { - mLayerTracing.notify("start", startingTime); + mLayerTracing.notify(true /* visibleRegionDirty */, + startingTime, mLastCommittedVsyncId); }) .wait(); } @@ -6676,24 +6586,21 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::captureScreenCommon( }); if (captureListener) { - // TODO: The future returned by std::async blocks the main thread. Return a chain of - // futures to the Binder thread instead. - std::async([=]() mutable { - ATRACE_NAME("captureListener is nonnull!"); - auto fenceResult = renderFuture.get(); - // TODO(b/232535621): Change ScreenCaptureResults to store a FenceResult. - captureResults.result = fenceStatus(fenceResult); - captureResults.fence = std::move(fenceResult).value_or(Fence::NO_FENCE); - captureListener->onScreenCaptureCompleted(captureResults); - }); + // Defer blocking on renderFuture back to the Binder thread. + return ftl::Future(std::move(renderFuture)) + .then([captureListener, captureResults = std::move(captureResults)]( + FenceResult fenceResult) mutable -> FenceResult { + // TODO(b/232535621): Change ScreenCaptureResults to store a FenceResult. + captureResults.result = fenceStatus(fenceResult); + captureResults.fence = std::move(fenceResult).value_or(Fence::NO_FENCE); + captureListener->onScreenCaptureCompleted(captureResults); + return base::unexpected(NO_ERROR); + }) + .share(); } return renderFuture; }); - if (captureListener) { - return ftl::yield<FenceResult>(base::unexpected(NO_ERROR)).share(); - } - // Flatten nested futures. auto chain = ftl::Future(std::move(future)).then([](ftl::SharedFuture<FenceResult> future) { return future; @@ -6861,11 +6768,6 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( return future; } -void SurfaceFlinger::windowInfosReported() { - Mutex::Autolock _l(mStateLock); - signalSynchronousTransactions(CountDownLatch::eSyncInputWindows); -} - // --------------------------------------------------------------------------- void SurfaceFlinger::State::traverse(const LayerVector::Visitor& visitor) const { @@ -7098,45 +7000,12 @@ const std::unordered_map<std::string, uint32_t>& SurfaceFlinger::getGenericLayer // on the work to remove the table in that bug rather than adding more to // it. static const std::unordered_map<std::string, uint32_t> genericLayerMetadataKeyMap{ - {"org.chromium.arc.V1_0.TaskId", METADATA_TASK_ID}, - {"org.chromium.arc.V1_0.CursorInfo", METADATA_MOUSE_CURSOR}, + {"org.chromium.arc.V1_0.TaskId", gui::METADATA_TASK_ID}, + {"org.chromium.arc.V1_0.CursorInfo", gui::METADATA_MOUSE_CURSOR}, }; return genericLayerMetadataKeyMap; } -status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, - int8_t compatibility, int8_t changeFrameRateStrategy) { - if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, - "SurfaceFlinger::setFrameRate")) { - return BAD_VALUE; - } - - static_cast<void>(mScheduler->schedule([=] { - Mutex::Autolock lock(mStateLock); - if (authenticateSurfaceTextureLocked(surface)) { - sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer(); - if (layer == nullptr) { - ALOGE("Attempt to set frame rate on a layer that no longer exists"); - return BAD_VALUE; - } - const auto strategy = - Layer::FrameRate::convertChangeFrameRateStrategy(changeFrameRateStrategy); - if (layer->setFrameRate( - Layer::FrameRate(Fps::fromValue(frameRate), - Layer::FrameRate::convertCompatibility(compatibility), - strategy))) { - setTransactionFlags(eTraversalNeeded); - } - } else { - ALOGE("Attempt to set frame rate on an unrecognized IGraphicBufferProducer"); - return BAD_VALUE; - } - return NO_ERROR; - })); - - return NO_ERROR; -} - status_t SurfaceFlinger::setOverrideFrameRate(uid_t uid, float frameRate) { PhysicalDisplayId displayId = [&]() { Mutex::Autolock lock(mStateLock); @@ -7148,24 +7017,6 @@ status_t SurfaceFlinger::setOverrideFrameRate(uid_t uid, float frameRate) { return NO_ERROR; } -status_t SurfaceFlinger::setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface, - const FrameTimelineInfo& frameTimelineInfo) { - Mutex::Autolock lock(mStateLock); - if (!authenticateSurfaceTextureLocked(surface)) { - ALOGE("Attempt to set frame timeline info on an unrecognized IGraphicBufferProducer"); - return BAD_VALUE; - } - - sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer(); - if (layer == nullptr) { - ALOGE("Attempt to set frame timeline info on a layer that no longer exists"); - return BAD_VALUE; - } - - layer->setFrameTimelineInfoForBuffer(frameTimelineInfo); - return NO_ERROR; -} - void SurfaceFlinger::enableRefreshRateOverlay(bool enable) { for (const auto& [ignored, display] : mDisplays) { if (display->isInternal()) { @@ -7185,7 +7036,7 @@ status_t SurfaceFlinger::addTransactionTraceListener( return NO_ERROR; } -int SurfaceFlinger::getGPUContextPriority() { +int SurfaceFlinger::getGpuContextPriority() { return getRenderEngine().getContextPriority(); } @@ -7231,7 +7082,7 @@ int SurfaceFlinger::getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) con return calculateMaxAcquiredBufferCount(refreshRate, presentLatency); } -void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state) { +void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state, int64_t vsyncId) { sp<Layer> layer = state.layer.promote(); if (!layer) { ALOGD("Layer was destroyed soon after creation %p", state.layer.unsafe_get()); @@ -7261,7 +7112,9 @@ void SurfaceFlinger::handleLayerCreatedLocked(const LayerCreatedState& state) { } layer->updateTransformHint(mActiveDisplayTransformHint); - + if (mTransactionTracing) { + mTransactionTracing->onLayerAddedToDrawingState(layer->getSequence(), vsyncId); + } mInterceptor->saveSurfaceCreation(layer); } @@ -7345,7 +7198,7 @@ std::shared_ptr<renderengine::ExternalTexture> SurfaceFlinger::getExternalTextur return buffer; } -bool SurfaceFlinger::commitCreatedLayers() { +bool SurfaceFlinger::commitCreatedLayers(int64_t vsyncId) { std::vector<LayerCreatedState> createdLayers; { std::scoped_lock<std::mutex> lock(mCreatedLayersLock); @@ -7358,7 +7211,7 @@ bool SurfaceFlinger::commitCreatedLayers() { Mutex::Autolock _l(mStateLock); for (const auto& createdLayer : createdLayers) { - handleLayerCreatedLocked(createdLayer); + handleLayerCreatedLocked(createdLayer, vsyncId); } createdLayers.clear(); mLayersAdded = true; @@ -7367,24 +7220,58 @@ bool SurfaceFlinger::commitCreatedLayers() { // gui::ISurfaceComposer +binder::Status SurfaceComposerAIDL::bootFinished() { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } + mFlinger->bootFinished(); + return binder::Status::ok(); +} + +binder::Status SurfaceComposerAIDL::createDisplayEventConnection( + VsyncSource vsyncSource, EventRegistration eventRegistration, + sp<IDisplayEventConnection>* outConnection) { + sp<IDisplayEventConnection> conn = + mFlinger->createDisplayEventConnection(vsyncSource, eventRegistration); + if (conn == nullptr) { + *outConnection = nullptr; + return binderStatusFromStatusT(BAD_VALUE); + } else { + *outConnection = conn; + return binder::Status::ok(); + } +} + +binder::Status SurfaceComposerAIDL::createConnection(sp<gui::ISurfaceComposerClient>* outClient) { + const sp<Client> client = new Client(mFlinger); + if (client->initCheck() == NO_ERROR) { + *outClient = client; + return binder::Status::ok(); + } else { + *outClient = nullptr; + return binderStatusFromStatusT(BAD_VALUE); + } +} + binder::Status SurfaceComposerAIDL::createDisplay(const std::string& displayName, bool secure, sp<IBinder>* outDisplay) { status_t status = checkAccessPermission(); - if (status == OK) { - String8 displayName8 = String8::format("%s", displayName.c_str()); - *outDisplay = mFlinger->createDisplay(displayName8, secure); - return binder::Status::ok(); + if (status != OK) { + return binderStatusFromStatusT(status); } - return binder::Status::fromStatusT(status); + String8 displayName8 = String8::format("%s", displayName.c_str()); + *outDisplay = mFlinger->createDisplay(displayName8, secure); + return binder::Status::ok(); } binder::Status SurfaceComposerAIDL::destroyDisplay(const sp<IBinder>& display) { status_t status = checkAccessPermission(); - if (status == OK) { - mFlinger->destroyDisplay(display); - return binder::Status::ok(); + if (status != OK) { + return binderStatusFromStatusT(status); } - return binder::Status::fromStatusT(status); + mFlinger->destroyDisplay(display); + return binder::Status::ok(); } binder::Status SurfaceComposerAIDL::getPhysicalDisplayIds(std::vector<int64_t>* outDisplayIds) { @@ -7401,7 +7288,7 @@ binder::Status SurfaceComposerAIDL::getPhysicalDisplayIds(std::vector<int64_t>* binder::Status SurfaceComposerAIDL::getPrimaryPhysicalDisplayId(int64_t* outDisplayId) { status_t status = checkAccessPermission(); if (status != OK) { - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); } PhysicalDisplayId id; @@ -7409,7 +7296,7 @@ binder::Status SurfaceComposerAIDL::getPrimaryPhysicalDisplayId(int64_t* outDisp if (status == NO_ERROR) { *outDisplayId = id.value; } - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::getPhysicalDisplayToken(int64_t displayId, @@ -7421,12 +7308,25 @@ binder::Status SurfaceComposerAIDL::getPhysicalDisplayToken(int64_t displayId, binder::Status SurfaceComposerAIDL::setPowerMode(const sp<IBinder>& display, int mode) { status_t status = checkAccessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); - + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->setPowerMode(display, mode); return binder::Status::ok(); } +binder::Status SurfaceComposerAIDL::getSupportedFrameTimestamps( + std::vector<FrameEvent>* outSupported) { + status_t status; + if (!outSupported) { + status = UNEXPECTED_NULL; + } else { + outSupported->clear(); + status = mFlinger->getSupportedFrameTimestamps(outSupported); + } + return binderStatusFromStatusT(status); +} + binder::Status SurfaceComposerAIDL::getDisplayStats(const sp<IBinder>& display, gui::DisplayStatInfo* outStatInfo) { DisplayStatInfo statInfo; @@ -7435,7 +7335,7 @@ binder::Status SurfaceComposerAIDL::getDisplayStats(const sp<IBinder>& display, outStatInfo->vsyncTime = static_cast<long>(statInfo.vsyncTime); outStatInfo->vsyncPeriod = static_cast<long>(statInfo.vsyncPeriod); } - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::getDisplayState(const sp<IBinder>& display, @@ -7448,37 +7348,175 @@ binder::Status SurfaceComposerAIDL::getDisplayState(const sp<IBinder>& display, outState->layerStackSpaceRect.width = state.layerStackSpaceRect.width; outState->layerStackSpaceRect.height = state.layerStackSpaceRect.height; } - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); } -binder::Status SurfaceComposerAIDL::clearBootDisplayMode(const sp<IBinder>& display) { +binder::Status SurfaceComposerAIDL::getStaticDisplayInfo(const sp<IBinder>& display, + gui::StaticDisplayInfo* outInfo) { + using Tag = gui::DeviceProductInfo::ManufactureOrModelDate::Tag; + ui::StaticDisplayInfo info; + status_t status = mFlinger->getStaticDisplayInfo(display, &info); + if (status == NO_ERROR) { + // convert ui::StaticDisplayInfo to gui::StaticDisplayInfo + outInfo->connectionType = static_cast<gui::DisplayConnectionType>(info.connectionType); + outInfo->density = info.density; + outInfo->secure = info.secure; + outInfo->installOrientation = static_cast<gui::Rotation>(info.installOrientation); + + gui::DeviceProductInfo dinfo; + std::optional<DeviceProductInfo> dpi = info.deviceProductInfo; + dinfo.name = std::move(dpi->name); + dinfo.manufacturerPnpId = + std::vector<uint8_t>(dpi->manufacturerPnpId.begin(), dpi->manufacturerPnpId.end()); + dinfo.productId = dpi->productId; + dinfo.relativeAddress = + std::vector<uint8_t>(dpi->relativeAddress.begin(), dpi->relativeAddress.end()); + if (const auto* model = + std::get_if<DeviceProductInfo::ModelYear>(&dpi->manufactureOrModelDate)) { + gui::DeviceProductInfo::ModelYear modelYear; + modelYear.year = model->year; + dinfo.manufactureOrModelDate.set<Tag::modelYear>(modelYear); + } else if (const auto* manufacture = std::get_if<DeviceProductInfo::ManufactureYear>( + &dpi->manufactureOrModelDate)) { + gui::DeviceProductInfo::ManufactureYear date; + date.modelYear.year = manufacture->year; + dinfo.manufactureOrModelDate.set<Tag::manufactureYear>(date); + } else if (const auto* manufacture = std::get_if<DeviceProductInfo::ManufactureWeekAndYear>( + &dpi->manufactureOrModelDate)) { + gui::DeviceProductInfo::ManufactureWeekAndYear date; + date.manufactureYear.modelYear.year = manufacture->year; + date.week = manufacture->week; + dinfo.manufactureOrModelDate.set<Tag::manufactureWeekAndYear>(date); + } + + outInfo->deviceProductInfo = dinfo; + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getDynamicDisplayInfo(const sp<IBinder>& display, + gui::DynamicDisplayInfo* outInfo) { + ui::DynamicDisplayInfo info; + status_t status = mFlinger->getDynamicDisplayInfo(display, &info); + if (status == NO_ERROR) { + // convert ui::DynamicDisplayInfo to gui::DynamicDisplayInfo + outInfo->supportedDisplayModes.clear(); + outInfo->supportedDisplayModes.reserve(info.supportedDisplayModes.size()); + for (const auto& mode : info.supportedDisplayModes) { + gui::DisplayMode outMode; + outMode.id = mode.id; + outMode.resolution.width = mode.resolution.width; + outMode.resolution.height = mode.resolution.height; + outMode.xDpi = mode.xDpi; + outMode.yDpi = mode.yDpi; + outMode.refreshRate = mode.refreshRate; + outMode.appVsyncOffset = mode.appVsyncOffset; + outMode.sfVsyncOffset = mode.sfVsyncOffset; + outMode.presentationDeadline = mode.presentationDeadline; + outMode.group = mode.group; + outInfo->supportedDisplayModes.push_back(outMode); + } + + outInfo->activeDisplayModeId = info.activeDisplayModeId; + + outInfo->supportedColorModes.clear(); + outInfo->supportedColorModes.reserve(info.supportedColorModes.size()); + for (const auto& cmode : info.supportedColorModes) { + outInfo->supportedColorModes.push_back(static_cast<int32_t>(cmode)); + } + + outInfo->activeColorMode = static_cast<int32_t>(info.activeColorMode); + + gui::HdrCapabilities& hdrCapabilities = outInfo->hdrCapabilities; + hdrCapabilities.supportedHdrTypes.clear(); + hdrCapabilities.supportedHdrTypes.reserve( + info.hdrCapabilities.getSupportedHdrTypes().size()); + for (const auto& hdr : info.hdrCapabilities.getSupportedHdrTypes()) { + hdrCapabilities.supportedHdrTypes.push_back(static_cast<int32_t>(hdr)); + } + hdrCapabilities.maxLuminance = info.hdrCapabilities.getDesiredMaxLuminance(); + hdrCapabilities.maxAverageLuminance = info.hdrCapabilities.getDesiredMaxAverageLuminance(); + hdrCapabilities.minLuminance = info.hdrCapabilities.getDesiredMinLuminance(); + + outInfo->autoLowLatencyModeSupported = info.autoLowLatencyModeSupported; + outInfo->gameContentTypeSupported = info.gameContentTypeSupported; + outInfo->preferredBootDisplayMode = info.preferredBootDisplayMode; + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getDisplayNativePrimaries(const sp<IBinder>& display, + gui::DisplayPrimaries* outPrimaries) { + ui::DisplayPrimaries primaries; + status_t status = mFlinger->getDisplayNativePrimaries(display, primaries); + if (status == NO_ERROR) { + outPrimaries->red.X = primaries.red.X; + outPrimaries->red.Y = primaries.red.Y; + outPrimaries->red.Z = primaries.red.Z; + + outPrimaries->green.X = primaries.green.X; + outPrimaries->green.Y = primaries.green.Y; + outPrimaries->green.Z = primaries.green.Z; + + outPrimaries->blue.X = primaries.blue.X; + outPrimaries->blue.Y = primaries.blue.Y; + outPrimaries->blue.Z = primaries.blue.Z; + + outPrimaries->white.X = primaries.white.X; + outPrimaries->white.Y = primaries.white.Y; + outPrimaries->white.Z = primaries.white.Z; + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::setActiveColorMode(const sp<IBinder>& display, int colorMode) { + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->setActiveColorMode(display, static_cast<ui::ColorMode>(colorMode)); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::setBootDisplayMode(const sp<IBinder>& display, + int displayModeId) { status_t status = checkAccessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); + if (status == OK) { + status = mFlinger->setBootDisplayMode(display, + static_cast<ui::DisplayModeId>(displayModeId)); + } + return binderStatusFromStatusT(status); +} - status = mFlinger->clearBootDisplayMode(display); - return binder::Status::fromStatusT(status); +binder::Status SurfaceComposerAIDL::clearBootDisplayMode(const sp<IBinder>& display) { + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->clearBootDisplayMode(display); + } + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::getBootDisplayModeSupport(bool* outMode) { status_t status = checkAccessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); - - status = mFlinger->getBootDisplayModeSupport(outMode); - return binder::Status::fromStatusT(status); + if (status == OK) { + status = mFlinger->getBootDisplayModeSupport(outMode); + } + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::setAutoLowLatencyMode(const sp<IBinder>& display, bool on) { status_t status = checkAccessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); - + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->setAutoLowLatencyMode(display, on); return binder::Status::ok(); } binder::Status SurfaceComposerAIDL::setGameContentType(const sp<IBinder>& display, bool on) { status_t status = checkAccessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); - + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->setGameContentType(display, on); return binder::Status::ok(); } @@ -7486,7 +7524,7 @@ binder::Status SurfaceComposerAIDL::setGameContentType(const sp<IBinder>& displa binder::Status SurfaceComposerAIDL::captureDisplay( const DisplayCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) { status_t status = mFlinger->captureDisplay(args, captureListener); - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::captureDisplayById( @@ -7500,60 +7538,465 @@ binder::Status SurfaceComposerAIDL::captureDisplayById( } else { status = PERMISSION_DENIED; } - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::captureLayers( const LayerCaptureArgs& args, const sp<IScreenCaptureListener>& captureListener) { status_t status = mFlinger->captureLayers(args, captureListener); - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::clearAnimationFrameStats() { + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->clearAnimationFrameStats(); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getAnimationFrameStats(gui::FrameStats* outStats) { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } + + FrameStats stats; + status = mFlinger->getAnimationFrameStats(&stats); + if (status == NO_ERROR) { + outStats->refreshPeriodNano = stats.refreshPeriodNano; + outStats->desiredPresentTimesNano.reserve(stats.desiredPresentTimesNano.size()); + for (const auto& t : stats.desiredPresentTimesNano) { + outStats->desiredPresentTimesNano.push_back(t); + } + outStats->actualPresentTimesNano.reserve(stats.actualPresentTimesNano.size()); + for (const auto& t : stats.actualPresentTimesNano) { + outStats->actualPresentTimesNano.push_back(t); + } + outStats->frameReadyTimesNano.reserve(stats.frameReadyTimesNano.size()); + for (const auto& t : stats.frameReadyTimesNano) { + outStats->frameReadyTimesNano.push_back(t); + } + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::overrideHdrTypes(const sp<IBinder>& display, + const std::vector<int32_t>& hdrTypes) { + // overrideHdrTypes is used by CTS tests, which acquire the necessary + // permission dynamically. Don't use the permission cache for this check. + status_t status = checkAccessPermission(false); + if (status != OK) { + return binderStatusFromStatusT(status); + } + + std::vector<ui::Hdr> hdrTypesVector; + for (int32_t i : hdrTypes) { + hdrTypesVector.push_back(static_cast<ui::Hdr>(i)); + } + status = mFlinger->overrideHdrTypes(display, hdrTypesVector); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::onPullAtom(int32_t atomId, gui::PullAtomData* outPullData) { + status_t status; + const int uid = IPCThreadState::self()->getCallingUid(); + if (uid != AID_SYSTEM) { + status = PERMISSION_DENIED; + } else { + status = mFlinger->onPullAtom(atomId, &outPullData->data, &outPullData->success); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::enableVSyncInjections(bool enable) { + if (!mFlinger->hasMockHwc()) { + return binderStatusFromStatusT(PERMISSION_DENIED); + } + + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->enableVSyncInjections(enable); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::injectVSync(int64_t when) { + if (!mFlinger->hasMockHwc()) { + return binderStatusFromStatusT(PERMISSION_DENIED); + } + + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->injectVSync(when); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) { + if (!outLayers) { + return binderStatusFromStatusT(UNEXPECTED_NULL); + } + + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) && !PermissionCache::checkPermission(sDump, pid, uid)) { + ALOGE("Layer debug info permission denied for pid=%d, uid=%d", pid, uid); + return binderStatusFromStatusT(PERMISSION_DENIED); + } + status_t status = mFlinger->getLayerDebugInfo(outLayers); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getColorManagement(bool* outGetColorManagement) { + status_t status = mFlinger->getColorManagement(outGetColorManagement); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getCompositionPreference(gui::CompositionPreference* outPref) { + ui::Dataspace dataspace; + ui::PixelFormat pixelFormat; + ui::Dataspace wideColorGamutDataspace; + ui::PixelFormat wideColorGamutPixelFormat; + status_t status = + mFlinger->getCompositionPreference(&dataspace, &pixelFormat, &wideColorGamutDataspace, + &wideColorGamutPixelFormat); + if (status == NO_ERROR) { + outPref->defaultDataspace = static_cast<int32_t>(dataspace); + outPref->defaultPixelFormat = static_cast<int32_t>(pixelFormat); + outPref->wideColorGamutDataspace = static_cast<int32_t>(wideColorGamutDataspace); + outPref->wideColorGamutPixelFormat = static_cast<int32_t>(wideColorGamutPixelFormat); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getDisplayedContentSamplingAttributes( + const sp<IBinder>& display, gui::ContentSamplingAttributes* outAttrs) { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } + + ui::PixelFormat format; + ui::Dataspace dataspace; + uint8_t componentMask; + status = mFlinger->getDisplayedContentSamplingAttributes(display, &format, &dataspace, + &componentMask); + if (status == NO_ERROR) { + outAttrs->format = static_cast<int32_t>(format); + outAttrs->dataspace = static_cast<int32_t>(dataspace); + outAttrs->componentMask = static_cast<int8_t>(componentMask); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::setDisplayContentSamplingEnabled(const sp<IBinder>& display, + bool enable, + int8_t componentMask, + int64_t maxFrames) { + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->setDisplayContentSamplingEnabled(display, enable, + static_cast<uint8_t>(componentMask), + static_cast<uint64_t>(maxFrames)); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getDisplayedContentSample(const sp<IBinder>& display, + int64_t maxFrames, int64_t timestamp, + gui::DisplayedFrameStats* outStats) { + if (!outStats) { + return binderStatusFromStatusT(BAD_VALUE); + } + + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } + + DisplayedFrameStats stats; + status = mFlinger->getDisplayedContentSample(display, static_cast<uint64_t>(maxFrames), + static_cast<uint64_t>(timestamp), &stats); + if (status == NO_ERROR) { + // convert from ui::DisplayedFrameStats to gui::DisplayedFrameStats + outStats->numFrames = static_cast<int64_t>(stats.numFrames); + outStats->component_0_sample.reserve(stats.component_0_sample.size()); + for (const auto& s : stats.component_0_sample) { + outStats->component_0_sample.push_back(static_cast<int64_t>(s)); + } + outStats->component_1_sample.reserve(stats.component_1_sample.size()); + for (const auto& s : stats.component_1_sample) { + outStats->component_1_sample.push_back(static_cast<int64_t>(s)); + } + outStats->component_2_sample.reserve(stats.component_2_sample.size()); + for (const auto& s : stats.component_2_sample) { + outStats->component_2_sample.push_back(static_cast<int64_t>(s)); + } + outStats->component_3_sample.reserve(stats.component_3_sample.size()); + for (const auto& s : stats.component_3_sample) { + outStats->component_3_sample.push_back(static_cast<int64_t>(s)); + } + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getProtectedContentSupport(bool* outSupported) { + status_t status = mFlinger->getProtectedContentSupport(outSupported); + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::isWideColorDisplay(const sp<IBinder>& token, bool* outIsWideColorDisplay) { status_t status = mFlinger->isWideColorDisplay(token, outIsWideColorDisplay); - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::addRegionSamplingListener( + const gui::ARect& samplingArea, const sp<IBinder>& stopLayerHandle, + const sp<gui::IRegionSamplingListener>& listener) { + status_t status = checkReadFrameBufferPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } + android::Rect rect; + rect.left = samplingArea.left; + rect.top = samplingArea.top; + rect.right = samplingArea.right; + rect.bottom = samplingArea.bottom; + status = mFlinger->addRegionSamplingListener(rect, stopLayerHandle, listener); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::removeRegionSamplingListener( + const sp<gui::IRegionSamplingListener>& listener) { + status_t status = checkReadFrameBufferPermission(); + if (status == OK) { + status = mFlinger->removeRegionSamplingListener(listener); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::addFpsListener(int32_t taskId, + const sp<gui::IFpsListener>& listener) { + status_t status = checkReadFrameBufferPermission(); + if (status == OK) { + status = mFlinger->addFpsListener(taskId, listener); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::removeFpsListener(const sp<gui::IFpsListener>& listener) { + status_t status = checkReadFrameBufferPermission(); + if (status == OK) { + status = mFlinger->removeFpsListener(listener); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::addTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) { + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->addTunnelModeEnabledListener(listener); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::removeTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) { + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->removeTunnelModeEnabledListener(listener); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::setDesiredDisplayModeSpecs( + const sp<IBinder>& displayToken, int32_t defaultMode, bool allowGroupSwitching, + float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin, + float appRequestRefreshRateMax) { + status_t status = checkAccessPermission(); + if (status == OK) { + status = mFlinger->setDesiredDisplayModeSpecs(displayToken, + static_cast<ui::DisplayModeId>(defaultMode), + allowGroupSwitching, primaryRefreshRateMin, + primaryRefreshRateMax, + appRequestRefreshRateMin, + appRequestRefreshRateMax); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, + gui::DisplayModeSpecs* outSpecs) { + if (!outSpecs) { + return binderStatusFromStatusT(BAD_VALUE); + } + + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } + + ui::DisplayModeId displayModeId; + bool allowGroupSwitching; + float primaryRefreshRateMin; + float primaryRefreshRateMax; + float appRequestRefreshRateMin; + float appRequestRefreshRateMax; + status = mFlinger->getDesiredDisplayModeSpecs(displayToken, &displayModeId, + &allowGroupSwitching, &primaryRefreshRateMin, + &primaryRefreshRateMax, &appRequestRefreshRateMin, + &appRequestRefreshRateMax); + if (status == NO_ERROR) { + outSpecs->defaultMode = displayModeId; + outSpecs->allowGroupSwitching = allowGroupSwitching; + outSpecs->primaryRefreshRateMin = primaryRefreshRateMin; + outSpecs->primaryRefreshRateMax = primaryRefreshRateMax; + outSpecs->appRequestRefreshRateMin = appRequestRefreshRateMin; + outSpecs->appRequestRefreshRateMax = appRequestRefreshRateMax; + } + + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::getDisplayBrightnessSupport(const sp<IBinder>& displayToken, bool* outSupport) { status_t status = mFlinger->getDisplayBrightnessSupport(displayToken, outSupport); - return binder::Status::fromStatusT(status); + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::setDisplayBrightness(const sp<IBinder>& displayToken, const gui::DisplayBrightness& brightness) { status_t status = checkControlDisplayBrightnessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); - - status = mFlinger->setDisplayBrightness(displayToken, brightness); - return binder::Status::fromStatusT(status); + if (status == OK) { + status = mFlinger->setDisplayBrightness(displayToken, brightness); + } + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::addHdrLayerInfoListener( const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) { status_t status = checkControlDisplayBrightnessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); - - status = mFlinger->addHdrLayerInfoListener(displayToken, listener); - return binder::Status::fromStatusT(status); + if (status == OK) { + status = mFlinger->addHdrLayerInfoListener(displayToken, listener); + } + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::removeHdrLayerInfoListener( const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) { status_t status = checkControlDisplayBrightnessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); - - status = mFlinger->removeHdrLayerInfoListener(displayToken, listener); - return binder::Status::fromStatusT(status); + if (status == OK) { + status = mFlinger->removeHdrLayerInfoListener(displayToken, listener); + } + return binderStatusFromStatusT(status); } binder::Status SurfaceComposerAIDL::notifyPowerBoost(int boostId) { status_t status = checkAccessPermission(); - if (status != OK) return binder::Status::fromStatusT(status); + if (status == OK) { + status = mFlinger->notifyPowerBoost(boostId); + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::setGlobalShadowSettings(const gui::Color& ambientColor, + const gui::Color& spotColor, + float lightPosY, float lightPosZ, + float lightRadius) { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } + + half4 ambientColorHalf = {ambientColor.r, ambientColor.g, ambientColor.b, ambientColor.a}; + half4 spotColorHalf = {spotColor.r, spotColor.g, spotColor.b, spotColor.a}; + status = mFlinger->setGlobalShadowSettings(ambientColorHalf, spotColorHalf, lightPosY, + lightPosZ, lightRadius); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::getDisplayDecorationSupport( + const sp<IBinder>& displayToken, std::optional<gui::DisplayDecorationSupport>* outSupport) { + std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport> support; + status_t status = mFlinger->getDisplayDecorationSupport(displayToken, &support); + if (status != NO_ERROR) { + ALOGE("getDisplayDecorationSupport failed with error %d", status); + return binderStatusFromStatusT(status); + } + + if (!support || !support.has_value()) { + outSupport->reset(); + } else { + outSupport->emplace(); + outSupport->value().format = static_cast<int32_t>(support->format); + outSupport->value().alphaInterpretation = + static_cast<int32_t>(support->alphaInterpretation); + } + + return binder::Status::ok(); +} + +binder::Status SurfaceComposerAIDL::setOverrideFrameRate(int32_t uid, float frameRate) { + status_t status; + const int c_uid = IPCThreadState::self()->getCallingUid(); + if (c_uid == AID_ROOT || c_uid == AID_SYSTEM) { + status = mFlinger->setOverrideFrameRate(uid, frameRate); + } else { + ALOGE("setOverrideFrameRate() permission denied for uid: %d", c_uid); + status = PERMISSION_DENIED; + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::addTransactionTraceListener( + const sp<gui::ITransactionTraceListener>& listener) { + status_t status; + IPCThreadState* ipc = IPCThreadState::self(); + const int uid = ipc->getCallingUid(); + if (uid == AID_ROOT || uid == AID_GRAPHICS || uid == AID_SYSTEM || uid == AID_SHELL) { + status = mFlinger->addTransactionTraceListener(listener); + } else { + status = PERMISSION_DENIED; + } + return binderStatusFromStatusT(status); +} - status = mFlinger->notifyPowerBoost(boostId); - return binder::Status::fromStatusT(status); +binder::Status SurfaceComposerAIDL::getGpuContextPriority(int32_t* outPriority) { + *outPriority = mFlinger->getGpuContextPriority(); + return binder::Status::ok(); +} + +binder::Status SurfaceComposerAIDL::getMaxAcquiredBufferCount(int32_t* buffers) { + status_t status = mFlinger->getMaxAcquiredBufferCount(buffers); + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::addWindowInfosListener( + const sp<gui::IWindowInfosListener>& windowInfosListener) { + status_t status; + const int uid = IPCThreadState::self()->getCallingUid(); + if (uid == AID_SYSTEM || uid == AID_GRAPHICS) { + status = mFlinger->addWindowInfosListener(windowInfosListener); + } else { + status = PERMISSION_DENIED; + } + return binderStatusFromStatusT(status); +} + +binder::Status SurfaceComposerAIDL::removeWindowInfosListener( + const sp<gui::IWindowInfosListener>& windowInfosListener) { + status_t status; + const int uid = IPCThreadState::self()->getCallingUid(); + if (uid == AID_SYSTEM || uid == AID_GRAPHICS) { + status = mFlinger->removeWindowInfosListener(windowInfosListener); + } else { + status = PERMISSION_DENIED; + } + return binderStatusFromStatusT(status); } status_t SurfaceComposerAIDL::checkAccessPermission(bool usePermissionCache) { @@ -7578,6 +8021,17 @@ status_t SurfaceComposerAIDL::checkControlDisplayBrightnessPermission() { return OK; } +status_t SurfaceComposerAIDL::checkReadFrameBufferPermission() { + IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_GRAPHICS) && !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) { + ALOGE("Permission Denial: can't read framebuffer pid=%d, uid=%d", pid, uid); + return PERMISSION_DENIED; + } + return OK; +} + } // namespace android #if defined(__gl_h_) diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 83134a2ebc..7d23c3c58f 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -25,15 +25,17 @@ #include <android/gui/BnSurfaceComposer.h> #include <android/gui/DisplayStatInfo.h> #include <android/gui/DisplayState.h> +#include <android/gui/ISurfaceComposerClient.h> #include <cutils/atomic.h> #include <cutils/compiler.h> #include <ftl/future.h> #include <ftl/small_map.h> #include <gui/BufferQueue.h> +#include <gui/CompositorTiming.h> #include <gui/FrameTimestamps.h> #include <gui/ISurfaceComposer.h> -#include <gui/ISurfaceComposerClient.h> #include <gui/ITransactionCompletedListener.h> +#include <gui/LayerDebugInfo.h> #include <gui/LayerState.h> #include <layerproto/LayerProtoHeader.h> #include <math/mat4.h> @@ -167,10 +169,6 @@ enum class LatchUnsignaledConfig { using DisplayColorSetting = compositionengine::OutputColorSetting; struct SurfaceFlingerBE { - // protected by mCompositorTimingLock; - mutable std::mutex mCompositorTimingLock; - CompositorTiming mCompositorTiming; - // Only accessed from the main thread. struct CompositePresentTime { nsecs_t composite = -1; @@ -309,9 +307,6 @@ public: renderengine::RenderEngine& getRenderEngine() const; - bool authenticateSurfaceTextureLocked( - const sp<IGraphicBufferProducer>& bufferProducer) const; - void onLayerFirstRef(Layer*); void onLayerDestroyed(Layer*); void onLayerUpdate(); @@ -335,7 +330,6 @@ public: // If set, disables reusing client composition buffers. This can be set by // debug.sf.disable_client_composition_cache bool mDisableClientCompositionCache = false; - void windowInfosReported(); // Disables expensive rendering for all displays // This is scheduled on the main thread @@ -375,13 +369,11 @@ protected: private: friend class BufferLayer; - friend class BufferQueueLayer; friend class BufferStateLayer; friend class Client; friend class FpsReporter; friend class TunnelModeEnabledReporter; friend class Layer; - friend class MonitoredProducer; friend class RefreshRateOverlay; friend class RegionSamplingThread; friend class LayerRenderArea; @@ -519,10 +511,11 @@ private: } } - static const int MAX_TRACING_MEMORY = 100 * 1024 * 1024; // 100MB // Maximum allowed number of display frames that can be set through backdoor static const int MAX_ALLOWED_DISPLAY_FRAMES = 2048; + static const size_t MAX_LAYERS = 4096; + // Implements IBinder. status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) override; status_t dump(int fd, const Vector<String16>& args) override { return priorityDump(fd, args); } @@ -530,7 +523,6 @@ private: EXCLUDES(mStateLock); // Implements ISurfaceComposer - sp<ISurfaceComposerClient> createConnection() override; sp<IBinder> createDisplay(const String8& displayName, bool secure); void destroyDisplay(const sp<IBinder>& displayToken); std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const EXCLUDES(mStateLock) { @@ -549,13 +541,12 @@ private: const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) override; - void bootFinished() override; - bool authenticateSurfaceTexture( - const sp<IGraphicBufferProducer>& bufferProducer) const override; - status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override; + void bootFinished(); + virtual status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const; sp<IDisplayEventConnection> createDisplayEventConnection( - ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp, - ISurfaceComposer::EventRegistrationFlags eventRegistration = {}) override; + gui::ISurfaceComposer::VsyncSource vsyncSource = + gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, + EventRegistrationFlags eventRegistration = {}); status_t captureDisplay(const DisplayCaptureArgs&, const sp<IScreenCaptureListener>&); status_t captureDisplay(DisplayId, const sp<IScreenCaptureListener>&); @@ -565,62 +556,58 @@ private: status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*) EXCLUDES(mStateLock); status_t getStaticDisplayInfo(const sp<IBinder>& displayToken, ui::StaticDisplayInfo*) - EXCLUDES(mStateLock) override; + EXCLUDES(mStateLock); status_t getDynamicDisplayInfo(const sp<IBinder>& displayToken, ui::DynamicDisplayInfo*) - EXCLUDES(mStateLock) override; - status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken, - ui::DisplayPrimaries&) override; - status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode) override; + EXCLUDES(mStateLock); + status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken, ui::DisplayPrimaries&); + status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode); status_t getBootDisplayModeSupport(bool* outSupport) const; - status_t setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id) override; + status_t setBootDisplayMode(const sp<IBinder>& displayToken, ui::DisplayModeId id); status_t clearBootDisplayMode(const sp<IBinder>& displayToken); void setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on); void setGameContentType(const sp<IBinder>& displayToken, bool on); void setPowerMode(const sp<IBinder>& displayToken, int mode); - status_t clearAnimationFrameStats() override; - status_t getAnimationFrameStats(FrameStats* outStats) const override; + status_t clearAnimationFrameStats(); + status_t getAnimationFrameStats(FrameStats* outStats) const; status_t overrideHdrTypes(const sp<IBinder>& displayToken, - const std::vector<ui::Hdr>& hdrTypes) override; - status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success) override; - status_t enableVSyncInjections(bool enable) override; - status_t injectVSync(nsecs_t when) override; - status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) override; - status_t getColorManagement(bool* outGetColorManagement) const override; + const std::vector<ui::Hdr>& hdrTypes); + status_t onPullAtom(const int32_t atomId, std::string* pulledData, bool* success); + status_t enableVSyncInjections(bool enable); + status_t injectVSync(nsecs_t when); + status_t getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers); + status_t getColorManagement(bool* outGetColorManagement) const; status_t getCompositionPreference(ui::Dataspace* outDataspace, ui::PixelFormat* outPixelFormat, ui::Dataspace* outWideColorGamutDataspace, - ui::PixelFormat* outWideColorGamutPixelFormat) const override; + ui::PixelFormat* outWideColorGamutPixelFormat) const; status_t getDisplayedContentSamplingAttributes(const sp<IBinder>& displayToken, ui::PixelFormat* outFormat, ui::Dataspace* outDataspace, - uint8_t* outComponentMask) const override; + uint8_t* outComponentMask) const; status_t setDisplayContentSamplingEnabled(const sp<IBinder>& displayToken, bool enable, - uint8_t componentMask, uint64_t maxFrames) override; + uint8_t componentMask, uint64_t maxFrames); status_t getDisplayedContentSample(const sp<IBinder>& displayToken, uint64_t maxFrames, - uint64_t timestamp, - DisplayedFrameStats* outStats) const override; - status_t getProtectedContentSupport(bool* outSupported) const override; + uint64_t timestamp, DisplayedFrameStats* outStats) const; + status_t getProtectedContentSupport(bool* outSupported) const; status_t isWideColorDisplay(const sp<IBinder>& displayToken, bool* outIsWideColorDisplay) const; status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle, - const sp<IRegionSamplingListener>& listener) override; - status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override; - status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) override; - status_t removeFpsListener(const sp<gui::IFpsListener>& listener) override; - status_t addTunnelModeEnabledListener( - const sp<gui::ITunnelModeEnabledListener>& listener) override; - status_t removeTunnelModeEnabledListener( - const sp<gui::ITunnelModeEnabledListener>& listener) override; + const sp<IRegionSamplingListener>& listener); + status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener); + status_t addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener); + status_t removeFpsListener(const sp<gui::IFpsListener>& listener); + status_t addTunnelModeEnabledListener(const sp<gui::ITunnelModeEnabledListener>& listener); + status_t removeTunnelModeEnabledListener(const sp<gui::ITunnelModeEnabledListener>& listener); status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, ui::DisplayModeId displayModeId, bool allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin, - float appRequestRefreshRateMax) override; + float appRequestRefreshRateMax); status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, ui::DisplayModeId* outDefaultMode, bool* outAllowGroupSwitching, float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax, float* outAppRequestRefreshRateMin, - float* outAppRequestRefreshRateMax) override; + float* outAppRequestRefreshRateMax); status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken, bool* outSupport) const; status_t setDisplayBrightness(const sp<IBinder>& displayToken, const gui::DisplayBrightness& brightness); @@ -630,30 +617,28 @@ private: const sp<gui::IHdrLayerInfoListener>& listener); status_t notifyPowerBoost(int32_t boostId); status_t setGlobalShadowSettings(const half4& ambientColor, const half4& spotColor, - float lightPosY, float lightPosZ, float lightRadius) override; + float lightPosY, float lightPosZ, float lightRadius); status_t getDisplayDecorationSupport( const sp<IBinder>& displayToken, std::optional<aidl::android::hardware::graphics::common::DisplayDecorationSupport>* - outSupport) const override; + outSupport) const; status_t setFrameRate(const sp<IGraphicBufferProducer>& surface, float frameRate, - int8_t compatibility, int8_t changeFrameRateStrategy) override; + int8_t compatibility, int8_t changeFrameRateStrategy); status_t setFrameTimelineInfo(const sp<IGraphicBufferProducer>& surface, - const FrameTimelineInfo& frameTimelineInfo) override; + const gui::FrameTimelineInfo& frameTimelineInfo); - status_t setOverrideFrameRate(uid_t uid, float frameRate) override; + status_t setOverrideFrameRate(uid_t uid, float frameRate); - status_t addTransactionTraceListener( - const sp<gui::ITransactionTraceListener>& listener) override; + status_t addTransactionTraceListener(const sp<gui::ITransactionTraceListener>& listener); - int getGPUContextPriority() override; + int getGpuContextPriority(); - status_t getMaxAcquiredBufferCount(int* buffers) const override; + status_t getMaxAcquiredBufferCount(int* buffers) const; - status_t addWindowInfosListener( - const sp<gui::IWindowInfosListener>& windowInfosListener) const override; + status_t addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener) const; status_t removeWindowInfosListener( - const sp<gui::IWindowInfosListener>& windowInfosListener) const override; + const sp<gui::IWindowInfosListener>& windowInfosListener) const; // Implements IBinder::DeathRecipient. void binderDied(const wp<IBinder>& who) override; @@ -832,10 +817,6 @@ private: const sp<Layer>& parentLayer = nullptr, uint32_t* outTransformHint = nullptr); - status_t createBufferQueueLayer(LayerCreationArgs& args, PixelFormat& format, - sp<IBinder>* outHandle, sp<IGraphicBufferProducer>* outGbp, - sp<Layer>* outLayer); - status_t createBufferStateLayer(LayerCreationArgs& args, sp<IBinder>* outHandle, sp<Layer>* outLayer); @@ -973,11 +954,9 @@ private: * Compositing */ void postComposition(); - void getCompositorTiming(CompositorTiming* compositorTiming); - void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime, - std::shared_ptr<FenceTime>& presentFenceTime); - void setCompositorTimingSnapped(const DisplayStatInfo& stats, - nsecs_t compositeToPresentLatency); + + // Returns the composite-to-present latency of the latest presented frame. + nsecs_t trackPresentLatency(nsecs_t compositeTime, std::shared_ptr<FenceTime> presentFenceTime); void postFrame() REQUIRES(kMainThreadContext); @@ -1012,31 +991,17 @@ private: getHwComposer().setVsyncEnabled(id, enabled); } - struct FenceWithFenceTime { - sp<Fence> fence = Fence::NO_FENCE; - std::shared_ptr<FenceTime> fenceTime = FenceTime::NO_FENCE; - }; - - // Gets the fence for the previous frame. - // Must be called on the main thread. - FenceWithFenceTime previousFrameFence(); + using FenceTimePtr = std::shared_ptr<FenceTime>; - // Whether the previous frame has not yet been presented to the display. - // If graceTimeMs is positive, this method waits for at most the provided - // grace period before reporting if the frame missed. - // Must be called on the main thread. - bool previousFramePending(int graceTimeMs = 0); + const FenceTimePtr& getPreviousPresentFence(nsecs_t frameTime, Period) + REQUIRES(kMainThreadContext); - // Returns the previous time that the frame was presented. If the frame has - // not been presented yet, then returns Fence::SIGNAL_TIME_PENDING. If there - // is no pending frame, then returns Fence::SIGNAL_TIME_INVALID. - // Must be called on the main thread. - nsecs_t previousFramePresentTime(); + // Blocks the thread waiting for up to graceTimeMs in case the fence is about to signal. + static bool isFencePending(const FenceTimePtr&, int graceTimeMs); // Calculates the expected present time for this frame. For negative offsets, performs a // correction using the predicted vsync for the next frame instead. - - nsecs_t calculateExpectedPresentTime(DisplayStatInfo) const; + TimePoint calculateExpectedPresentTime(nsecs_t frameTime) const; /* * Display identification @@ -1178,7 +1143,7 @@ private: float mGlobalSaturationFactor = 1.0f; mat4 mClientColorMatrix; - size_t mMaxGraphicBufferProducerListSize = ISurfaceComposer::MAX_LAYERS; + size_t mMaxGraphicBufferProducerListSize = MAX_LAYERS; // If there are more GraphicBufferProducers tracked by SurfaceFlinger than // this threshold, then begin logging. size_t mGraphicBufferProducerListSizeLogThreshold = @@ -1212,7 +1177,7 @@ private: // Set during transaction application stage to track if the input info or children // for a layer has changed. // TODO: Also move visibleRegions over to a boolean system. - bool mInputInfoChanged = false; + bool mUpdateInputInfo = false; bool mSomeChildrenChanged; bool mSomeDataspaceChanged = false; bool mForceTransactionDisplayChange = false; @@ -1224,7 +1189,7 @@ private: std::unordered_set<sp<Layer>, SpHash<Layer>> mLayersWithQueuedFrames; // Tracks layers that need to update a display's dirty region. std::vector<sp<Layer>> mLayersPendingRefresh; - std::array<FenceWithFenceTime, 2> mPreviousPresentFences; + // True if in the previous frame at least one layer was composed via the GPU. bool mHadClientComposition = false; // True if in the previous frame at least one layer was composed via HW Composer. @@ -1275,6 +1240,8 @@ private: const std::unique_ptr<FrameTracer> mFrameTracer; const std::unique_ptr<frametimeline::FrameTimeline> mFrameTimeline; + int64_t mLastCommittedVsyncId = -1; + // If blurs should be enabled on this device. bool mSupportsBlur = false; // If blurs are considered expensive and should require high GPU frequency. @@ -1359,6 +1326,12 @@ private: std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats; + struct FenceWithFenceTime { + sp<Fence> fence = Fence::NO_FENCE; + FenceTimePtr fenceTime = FenceTime::NO_FENCE; + }; + std::array<FenceWithFenceTime, 2> mPreviousPresentFences; + std::atomic<nsecs_t> mExpectedPresentTime = 0; nsecs_t mScheduledPresentTime = 0; hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE; @@ -1414,8 +1387,9 @@ private: // A temporay pool that store the created layers and will be added to current state in main // thread. std::vector<LayerCreatedState> mCreatedLayers GUARDED_BY(mCreatedLayersLock); - bool commitCreatedLayers(); - void handleLayerCreatedLocked(const LayerCreatedState& state) REQUIRES(mStateLock); + bool commitCreatedLayers(int64_t vsyncId); + void handleLayerCreatedLocked(const LayerCreatedState& state, int64_t vsyncId) + REQUIRES(mStateLock); std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint; @@ -1449,8 +1423,13 @@ private: class SurfaceComposerAIDL : public gui::BnSurfaceComposer { public: - SurfaceComposerAIDL(sp<SurfaceFlinger> sf) { mFlinger = sf; } + SurfaceComposerAIDL(sp<SurfaceFlinger> sf) : mFlinger(std::move(sf)) {} + binder::Status bootFinished() override; + binder::Status createDisplayEventConnection( + VsyncSource vsyncSource, EventRegistration eventRegistration, + sp<gui::IDisplayEventConnection>* outConnection) override; + binder::Status createConnection(sp<gui::ISurfaceComposerClient>* outClient) override; binder::Status createDisplay(const std::string& displayName, bool secure, sp<IBinder>* outDisplay) override; binder::Status destroyDisplay(const sp<IBinder>& display) override; @@ -1458,10 +1437,19 @@ public: binder::Status getPrimaryPhysicalDisplayId(int64_t* outDisplayId) override; binder::Status getPhysicalDisplayToken(int64_t displayId, sp<IBinder>* outDisplay) override; binder::Status setPowerMode(const sp<IBinder>& display, int mode) override; + binder::Status getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) override; binder::Status getDisplayStats(const sp<IBinder>& display, gui::DisplayStatInfo* outStatInfo) override; binder::Status getDisplayState(const sp<IBinder>& display, gui::DisplayState* outState) override; + binder::Status getStaticDisplayInfo(const sp<IBinder>& display, + gui::StaticDisplayInfo* outInfo) override; + binder::Status getDynamicDisplayInfo(const sp<IBinder>& display, + gui::DynamicDisplayInfo* outInfo) override; + binder::Status getDisplayNativePrimaries(const sp<IBinder>& display, + gui::DisplayPrimaries* outPrimaries) override; + binder::Status setActiveColorMode(const sp<IBinder>& display, int colorMode) override; + binder::Status setBootDisplayMode(const sp<IBinder>& display, int displayModeId) override; binder::Status clearBootDisplayMode(const sp<IBinder>& display) override; binder::Status getBootDisplayModeSupport(bool* outMode) override; binder::Status setAutoLowLatencyMode(const sp<IBinder>& display, bool on) override; @@ -1471,8 +1459,45 @@ public: binder::Status captureDisplayById(int64_t, const sp<IScreenCaptureListener>&) override; binder::Status captureLayers(const LayerCaptureArgs&, const sp<IScreenCaptureListener>&) override; + binder::Status clearAnimationFrameStats() override; + binder::Status getAnimationFrameStats(gui::FrameStats* outStats) override; + binder::Status overrideHdrTypes(const sp<IBinder>& display, + const std::vector<int32_t>& hdrTypes) override; + binder::Status onPullAtom(int32_t atomId, gui::PullAtomData* outPullData) override; + binder::Status enableVSyncInjections(bool enable) override; + binder::Status injectVSync(int64_t when) override; + binder::Status getLayerDebugInfo(std::vector<gui::LayerDebugInfo>* outLayers) override; + binder::Status getColorManagement(bool* outGetColorManagement) override; + binder::Status getCompositionPreference(gui::CompositionPreference* outPref) override; + binder::Status getDisplayedContentSamplingAttributes( + const sp<IBinder>& display, gui::ContentSamplingAttributes* outAttrs) override; + binder::Status setDisplayContentSamplingEnabled(const sp<IBinder>& display, bool enable, + int8_t componentMask, + int64_t maxFrames) override; + binder::Status getDisplayedContentSample(const sp<IBinder>& display, int64_t maxFrames, + int64_t timestamp, + gui::DisplayedFrameStats* outStats) override; + binder::Status getProtectedContentSupport(bool* outSupporte) override; binder::Status isWideColorDisplay(const sp<IBinder>& token, bool* outIsWideColorDisplay) override; + binder::Status addRegionSamplingListener( + const gui::ARect& samplingArea, const sp<IBinder>& stopLayerHandle, + const sp<gui::IRegionSamplingListener>& listener) override; + binder::Status removeRegionSamplingListener( + const sp<gui::IRegionSamplingListener>& listener) override; + binder::Status addFpsListener(int32_t taskId, const sp<gui::IFpsListener>& listener) override; + binder::Status removeFpsListener(const sp<gui::IFpsListener>& listener) override; + binder::Status addTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) override; + binder::Status removeTunnelModeEnabledListener( + const sp<gui::ITunnelModeEnabledListener>& listener) override; + binder::Status setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, int32_t defaultMode, + bool allowGroupSwitching, float primaryRefreshRateMin, + float primaryRefreshRateMax, + float appRequestRefreshRateMin, + float appRequestRefreshRateMax) override; + binder::Status getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, + gui::DisplayModeSpecs* outSpecs) override; binder::Status getDisplayBrightnessSupport(const sp<IBinder>& displayToken, bool* outSupport) override; binder::Status setDisplayBrightness(const sp<IBinder>& displayToken, @@ -1483,11 +1508,27 @@ public: const sp<IBinder>& displayToken, const sp<gui::IHdrLayerInfoListener>& listener) override; binder::Status notifyPowerBoost(int boostId) override; + binder::Status setGlobalShadowSettings(const gui::Color& ambientColor, + const gui::Color& spotColor, float lightPosY, + float lightPosZ, float lightRadius) override; + binder::Status getDisplayDecorationSupport( + const sp<IBinder>& displayToken, + std::optional<gui::DisplayDecorationSupport>* outSupport) override; + binder::Status setOverrideFrameRate(int32_t uid, float frameRate) override; + binder::Status addTransactionTraceListener( + const sp<gui::ITransactionTraceListener>& listener) override; + binder::Status getGpuContextPriority(int32_t* outPriority) override; + binder::Status getMaxAcquiredBufferCount(int32_t* buffers) override; + binder::Status addWindowInfosListener( + const sp<gui::IWindowInfosListener>& windowInfosListener) override; + binder::Status removeWindowInfosListener( + const sp<gui::IWindowInfosListener>& windowInfosListener) override; private: static const constexpr bool kUsePermissionCache = true; status_t checkAccessPermission(bool usePermissionCache = kUsePermissionCache); status_t checkControlDisplayBrightnessPermission(); + status_t checkReadFrameBufferPermission(); private: sp<SurfaceFlinger> mFlinger; diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp index b81b445dad..2399a39241 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp @@ -22,15 +22,12 @@ #include <cutils/properties.h> #include <ui/GraphicBuffer.h> -#include "BufferLayerConsumer.h" -#include "BufferQueueLayer.h" #include "BufferStateLayer.h" #include "ContainerLayer.h" #include "DisplayDevice.h" #include "EffectLayer.h" #include "FrameTracer/FrameTracer.h" #include "Layer.h" -#include "MonitoredProducer.h" #include "NativeWindowSurface.h" #include "StartPropertySetThread.h" #include "SurfaceFlingerDefaultFactory.h" @@ -84,18 +81,6 @@ void DefaultFactory::createBufferQueue(sp<IGraphicBufferProducer>* outProducer, BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger); } -sp<IGraphicBufferProducer> DefaultFactory::createMonitoredProducer( - const sp<IGraphicBufferProducer>& producer, const sp<SurfaceFlinger>& flinger, - const wp<Layer>& layer) { - return new MonitoredProducer(producer, flinger, layer); -} - -sp<BufferLayerConsumer> DefaultFactory::createBufferLayerConsumer( - const sp<IGraphicBufferConsumer>& consumer, renderengine::RenderEngine& renderEngine, - uint32_t textureName, Layer* layer) { - return new BufferLayerConsumer(consumer, renderEngine, textureName, layer); -} - std::unique_ptr<surfaceflinger::NativeWindowSurface> DefaultFactory::createNativeWindowSurface( const sp<IGraphicBufferProducer>& producer) { return surfaceflinger::impl::createNativeWindowSurface(producer); @@ -109,10 +94,6 @@ sp<ContainerLayer> DefaultFactory::createContainerLayer(const LayerCreationArgs& return new ContainerLayer(args); } -sp<BufferQueueLayer> DefaultFactory::createBufferQueueLayer(const LayerCreationArgs& args) { - return new BufferQueueLayer(args); -} - sp<BufferStateLayer> DefaultFactory::createBufferStateLayer(const LayerCreationArgs& args) { return new BufferStateLayer(args); } diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h index 501629d4da..4000e09bbc 100644 --- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h +++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h @@ -38,16 +38,9 @@ public: void createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer, bool consumerIsSurfaceFlinger) override; - sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>&, - const sp<SurfaceFlinger>&, - const wp<Layer>&) override; - sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>&, - renderengine::RenderEngine&, uint32_t tex, - Layer*) override; std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface( const sp<IGraphicBufferProducer>&) override; std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override; - sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) override; sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) override; sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) override; sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) override; diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index 6153e8e354..77a75c4e25 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -30,7 +30,6 @@ namespace android { typedef int32_t PixelFormat; -class BufferQueueLayer; class BufferLayerConsumer; class BufferStateLayer; class ContainerLayer; @@ -86,19 +85,12 @@ public: virtual void createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer, bool consumerIsSurfaceFlinger) = 0; - virtual sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>&, - const sp<SurfaceFlinger>&, - const wp<Layer>&) = 0; - virtual sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>&, - renderengine::RenderEngine&, - uint32_t tex, Layer*) = 0; virtual std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface( const sp<IGraphicBufferProducer>&) = 0; virtual std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() = 0; - virtual sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs& args) = 0; virtual sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) = 0; virtual sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) = 0; virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0; diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index 7a159b8eb7..61d7c22a2a 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -34,6 +34,8 @@ #include <scheduler/Fps.h> +using android::gui::GameMode; +using android::gui::LayerMetadata; using namespace android::surfaceflinger; namespace android { diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h index 237ae8d761..60aa810e8b 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h +++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h @@ -24,6 +24,9 @@ #include <unordered_map> #include <vector> +using android::gui::GameMode; +using android::gui::LayerMetadata; + namespace android { namespace surfaceflinger { diff --git a/services/surfaceflinger/Tracing/LayerTracing.cpp b/services/surfaceflinger/Tracing/LayerTracing.cpp index 49554c7dd8..afa3e50b15 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.cpp +++ b/services/surfaceflinger/Tracing/LayerTracing.cpp @@ -98,7 +98,7 @@ void LayerTracing::dump(std::string& result) const { mBuffer->dump(result); } -void LayerTracing::notify(bool visibleRegionDirty, int64_t time) { +void LayerTracing::notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId) { std::scoped_lock lock(mTraceLock); if (!mEnabled) { return; @@ -129,6 +129,7 @@ void LayerTracing::notify(bool visibleRegionDirty, int64_t time) { entry.set_excludes_composition_state(true); } mFlinger.dumpDisplayProto(entry); + entry.set_vsync_id(vsyncId); mBuffer->emplace(std::move(entry)); } diff --git a/services/surfaceflinger/Tracing/LayerTracing.h b/services/surfaceflinger/Tracing/LayerTracing.h index 88a19ecdf1..e73dac62e4 100644 --- a/services/surfaceflinger/Tracing/LayerTracing.h +++ b/services/surfaceflinger/Tracing/LayerTracing.h @@ -47,7 +47,7 @@ public: bool isEnabled() const; status_t writeToFile(); LayersTraceFileProto createTraceFileProto() const; - void notify(bool visibleRegionDirty, int64_t time); + void notify(bool visibleRegionDirty, int64_t time, int64_t vsyncId); enum : uint32_t { TRACE_INPUT = 1 << 1, diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp index a73eccf0e5..65918f6ab7 100644 --- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp +++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp @@ -15,6 +15,7 @@ */ #include <gui/SurfaceComposerClient.h> +#include <ui/Fence.h> #include <ui/Rect.h> #include "LayerProtoHelper.h" @@ -458,7 +459,7 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta layer.parentSurfaceControlForChild = new SurfaceControl(SurfaceComposerClient::getDefault(), mMapper->getLayerHandle(static_cast<int32_t>(layerId)), - nullptr, static_cast<int32_t>(layerId)); + static_cast<int32_t>(layerId)); } } if (proto.what() & layer_state_t::eRelativeLayerChanged) { @@ -469,7 +470,7 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta layer.relativeLayerSurfaceControl = new SurfaceControl(SurfaceComposerClient::getDefault(), mMapper->getLayerHandle(static_cast<int32_t>(layerId)), - nullptr, static_cast<int32_t>(layerId)); + static_cast<int32_t>(layerId)); } layer.z = proto.z(); } @@ -497,8 +498,13 @@ void TransactionProtoParser::fromProto(const proto::LayerState& proto, layer_sta inputInfo.replaceTouchableRegionWithCrop = windowInfoProto.replace_touchable_region_with_crop(); int64_t layerId = windowInfoProto.crop_layer_id(); - inputInfo.touchableRegionCropHandle = - mMapper->getLayerHandle(static_cast<int32_t>(layerId)); + if (layerId != -1) { + inputInfo.touchableRegionCropHandle = + mMapper->getLayerHandle(static_cast<int32_t>(layerId)); + } else { + inputInfo.touchableRegionCropHandle = nullptr; + } + layer.windowInfoHandle = sp<gui::WindowInfoHandle>::make(inputInfo); } if (proto.what() & layer_state_t::eBackgroundColorChanged) { diff --git a/services/surfaceflinger/Tracing/TransactionTracing.cpp b/services/surfaceflinger/Tracing/TransactionTracing.cpp index 6381758c7b..af0594e3b6 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.cpp +++ b/services/surfaceflinger/Tracing/TransactionTracing.cpp @@ -152,17 +152,33 @@ void TransactionTracing::addQueuedTransaction(const TransactionState& transactio mTransactionQueue.push(state); } -void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions, - int64_t vsyncId) { +TransactionTracing::CommittedTransactions& +TransactionTracing::findOrCreateCommittedTransactionRecord(int64_t vsyncId) { + for (auto& pendingTransaction : mPendingTransactions) { + if (pendingTransaction.vsyncId == vsyncId) { + return pendingTransaction; + } + } + CommittedTransactions committedTransactions; committedTransactions.vsyncId = vsyncId; committedTransactions.timestamp = systemTime(); + mPendingTransactions.emplace_back(committedTransactions); + return mPendingTransactions.back(); +} + +void TransactionTracing::onLayerAddedToDrawingState(int layerId, int64_t vsyncId) { + CommittedTransactions& committedTransactions = findOrCreateCommittedTransactionRecord(vsyncId); + committedTransactions.createdLayerIds.emplace_back(layerId); +} + +void TransactionTracing::addCommittedTransactions(std::vector<TransactionState>& transactions, + int64_t vsyncId) { + CommittedTransactions& committedTransactions = findOrCreateCommittedTransactionRecord(vsyncId); committedTransactions.transactionIds.reserve(transactions.size()); for (const auto& transaction : transactions) { committedTransactions.transactionIds.emplace_back(transaction.id); } - - mPendingTransactions.emplace_back(committedTransactions); tryPushToTracingThread(); } @@ -235,15 +251,24 @@ void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& comm for (const CommittedTransactions& entry : committedTransactions) { entryProto.set_elapsed_realtime_nanos(entry.timestamp); entryProto.set_vsync_id(entry.vsyncId); - entryProto.mutable_added_layers()->Reserve(static_cast<int32_t>(mCreatedLayers.size())); - for (auto& newLayer : mCreatedLayers) { - entryProto.mutable_added_layers()->Add(std::move(newLayer)); + entryProto.mutable_added_layers()->Reserve( + static_cast<int32_t>(entry.createdLayerIds.size())); + + for (const int32_t& id : entry.createdLayerIds) { + auto it = mCreatedLayers.find(id); + if (it != mCreatedLayers.end()) { + entryProto.mutable_added_layers()->Add(std::move(it->second)); + mCreatedLayers.erase(it); + } else { + ALOGW("Could not created layer with id %d", id); + } } + entryProto.mutable_removed_layers()->Reserve(static_cast<int32_t>(removedLayers.size())); for (auto& removedLayer : removedLayers) { entryProto.mutable_removed_layers()->Add(removedLayer); + mCreatedLayers.erase(removedLayer); } - mCreatedLayers.clear(); entryProto.mutable_transactions()->Reserve( static_cast<int32_t>(entry.transactionIds.size())); for (const uint64_t& id : entry.transactionIds) { @@ -256,6 +281,14 @@ void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& comm } } + entryProto.mutable_removed_layer_handles()->Reserve( + static_cast<int32_t>(mRemovedLayerHandles.size())); + for (auto& [handle, layerId] : mRemovedLayerHandles) { + entryProto.mutable_removed_layer_handles()->Add(layerId); + mLayerHandles.erase(handle); + } + mRemovedLayerHandles.clear(); + std::string serializedProto; entryProto.SerializeToString(&serializedProto); entryProto.Clear(); @@ -263,13 +296,6 @@ void TransactionTracing::addEntry(const std::vector<CommittedTransactions>& comm removedEntries.reserve(removedEntries.size() + entries.size()); removedEntries.insert(removedEntries.end(), std::make_move_iterator(entries.begin()), std::make_move_iterator(entries.end())); - - entryProto.mutable_removed_layer_handles()->Reserve( - static_cast<int32_t>(mRemovedLayerHandles.size())); - for (auto& handle : mRemovedLayerHandles) { - entryProto.mutable_removed_layer_handles()->Add(handle); - } - mRemovedLayerHandles.clear(); } proto::TransactionTraceEntry removedEntryProto; @@ -304,7 +330,7 @@ void TransactionTracing::onLayerAdded(BBinder* layerHandle, int layerId, const s ALOGW("Duplicate handles found. %p", layerHandle); } mLayerHandles[layerHandle] = layerId; - mCreatedLayers.push_back(mProtoParser.toProto(args)); + mCreatedLayers[layerId] = mProtoParser.toProto(args); } void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId, @@ -315,7 +341,7 @@ void TransactionTracing::onMirrorLayerAdded(BBinder* layerHandle, int layerId, ALOGW("Duplicate handles found. %p", layerHandle); } mLayerHandles[layerHandle] = layerId; - mCreatedLayers.emplace_back(mProtoParser.toProto(args)); + mCreatedLayers[layerId] = mProtoParser.toProto(args); } void TransactionTracing::onLayerRemoved(int32_t layerId) { @@ -330,9 +356,7 @@ void TransactionTracing::onHandleRemoved(BBinder* layerHandle) { ALOGW("handle not found. %p", layerHandle); return; } - - mRemovedLayerHandles.push_back(it->second); - mLayerHandles.erase(it); + mRemovedLayerHandles.emplace_back(layerHandle, it->second); } void TransactionTracing::tryPushToTracingThread() { @@ -376,10 +400,15 @@ void TransactionTracing::updateStartingStateLocked( } } + for (const int32_t removedLayerHandleId : removedEntry.removed_layer_handles()) { + mRemovedLayerHandlesAtStart.insert(removedLayerHandleId); + } + // Clean up stale starting states since the layer has been removed and the buffer does not // contain any references to the layer. for (const int32_t removedLayerId : removedEntry.removed_layers()) { mStartingStates.erase(removedLayerId); + mRemovedLayerHandlesAtStart.erase(removedLayerId); } } @@ -401,6 +430,12 @@ void TransactionTracing::addStartingStateToProtoLocked(proto::TransactionTraceFi transactionProto.set_vsync_id(0); transactionProto.set_post_time(mStartingTimestamp); entryProto->mutable_transactions()->Add(std::move(transactionProto)); + + entryProto->mutable_removed_layer_handles()->Reserve( + static_cast<int32_t>(mRemovedLayerHandlesAtStart.size())); + for (const int32_t removedLayerHandleId : mRemovedLayerHandlesAtStart) { + entryProto->mutable_removed_layer_handles()->Add(removedLayerHandleId); + } } proto::TransactionTraceFile TransactionTracing::writeToProto() { diff --git a/services/surfaceflinger/Tracing/TransactionTracing.h b/services/surfaceflinger/Tracing/TransactionTracing.h index 4c291f960f..ae01d3c0cc 100644 --- a/services/surfaceflinger/Tracing/TransactionTracing.h +++ b/services/surfaceflinger/Tracing/TransactionTracing.h @@ -64,6 +64,7 @@ public: int mirrorFromId); void onLayerRemoved(int layerId); void onHandleRemoved(BBinder* layerHandle); + void onLayerAddedToDrawingState(int layerId, int64_t vsyncId); void dump(std::string&) const; static constexpr auto CONTINUOUS_TRACING_BUFFER_SIZE = 512 * 1024; static constexpr auto ACTIVE_TRACING_BUFFER_SIZE = 100 * 1024 * 1024; @@ -81,11 +82,13 @@ private: GUARDED_BY(mTraceLock); LocklessStack<proto::TransactionState> mTransactionQueue; nsecs_t mStartingTimestamp GUARDED_BY(mTraceLock); - std::vector<proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock); + std::unordered_map<int, proto::LayerCreationArgs> mCreatedLayers GUARDED_BY(mTraceLock); std::unordered_map<BBinder* /* layerHandle */, int32_t /* layerId */> mLayerHandles GUARDED_BY(mTraceLock); - std::vector<int32_t /* layerId */> mRemovedLayerHandles GUARDED_BY(mTraceLock); + std::vector<std::pair<BBinder* /* layerHandle */, int32_t /* layerId */>> mRemovedLayerHandles + GUARDED_BY(mTraceLock); std::map<int32_t /* layerId */, TracingLayerState> mStartingStates GUARDED_BY(mTraceLock); + std::set<int32_t /* layerId */> mRemovedLayerHandlesAtStart GUARDED_BY(mTraceLock); TransactionProtoParser mProtoParser GUARDED_BY(mTraceLock); // Parses the transaction to proto without holding any tracing locks so we can generate proto // in the binder thread without any contention. @@ -100,6 +103,7 @@ private: std::condition_variable mTransactionsAddedToBufferCv; struct CommittedTransactions { std::vector<uint64_t> transactionIds; + std::vector<int32_t> createdLayerIds; int64_t vsyncId; int64_t timestamp; }; @@ -117,7 +121,7 @@ private: void tryPushToTracingThread() EXCLUDES(mMainThreadLock); void addStartingStateToProtoLocked(proto::TransactionTraceFile& proto) REQUIRES(mTraceLock); void updateStartingStateLocked(const proto::TransactionTraceEntry& entry) REQUIRES(mTraceLock); - + CommittedTransactions& findOrCreateCommittedTransactionRecord(int64_t vsyncId); // TEST // Wait until all the committed transactions for the specified vsync id are added to the buffer. void flush(int64_t vsyncId) EXCLUDES(mMainThreadLock); diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp index cf44effe50..c4b1b0fb13 100644 --- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp +++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp @@ -16,6 +16,7 @@ #undef LOG_TAG #define LOG_TAG "LayerTraceGenerator" +//#define LOG_NDEBUG 0 #include <TestableSurfaceFlinger.h> #include <Tracing/TransactionProtoParser.h> @@ -70,19 +71,6 @@ public: sp<IGraphicBufferConsumer>* /* outConsumer */, bool /* consumerIsSurfaceFlinger */) override {} - sp<IGraphicBufferProducer> createMonitoredProducer( - const sp<IGraphicBufferProducer>& /* producer */, - const sp<SurfaceFlinger>& /* flinger */, const wp<Layer>& /* layer */) override { - return nullptr; - } - - sp<BufferLayerConsumer> createBufferLayerConsumer( - const sp<IGraphicBufferConsumer>& /* consumer */, - renderengine::RenderEngine& /* renderEngine */, uint32_t /* textureName */, - Layer* /* layer */) override { - return nullptr; - } - std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface( const sp<IGraphicBufferProducer>& /* producer */) override { return nullptr; @@ -104,10 +92,6 @@ public: return new EffectLayer(args); } - sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override { - return nullptr; - } - std::unique_ptr<FrameTracer> createFrameTracer() override { return std::make_unique<testing::NiceMock<mock::FrameTracer>>(); } @@ -142,6 +126,14 @@ public: transact(1033, data, &reply, 0 /* flags */); } + void setLayerTraceSize(int32_t sizeInKb) { + Parcel data; + Parcel reply; + data.writeInterfaceToken(String16("android.ui.ISurfaceComposer")); + data.writeInt32(sizeInKb); + transact(1029, data, &reply, 0 /* flags */); + } + void startLayerTracing(int64_t traceStartTime) { Parcel data; Parcel reply; @@ -181,6 +173,7 @@ public: bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, const char* outputLayersTracePath) { if (traceFile.entry_size() == 0) { + ALOGD("Trace file is empty"); return false; } @@ -205,6 +198,7 @@ bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, mFlinger.mutableMaxRenderTargetSize() = 16384; flinger->setLayerTracingFlags(LayerTracing::TRACE_INPUT | LayerTracing::TRACE_BUFFERS); + flinger->setLayerTraceSize(512 * 1024); // 512MB buffer size flinger->startLayerTracing(traceFile.entry(0).elapsed_realtime_nanos()); std::unique_ptr<TraceGenFlingerDataMapper> mapper = std::make_unique<TraceGenFlingerDataMapper>(); @@ -217,9 +211,10 @@ bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, for (int i = 0; i < traceFile.entry_size(); i++) { proto::TransactionTraceEntry entry = traceFile.entry(i); ALOGV(" Entry %04d/%04d for time=%" PRId64 " vsyncid=%" PRId64 - " layers +%d -%d transactions=%d", + " layers +%d -%d handles -%d transactions=%d", i, traceFile.entry_size(), entry.elapsed_realtime_nanos(), entry.vsync_id(), - entry.added_layers_size(), entry.removed_layers_size(), entry.transactions_size()); + entry.added_layers_size(), entry.removed_layers_size(), + entry.removed_layer_handles_size(), entry.transactions_size()); for (int j = 0; j < entry.added_layers_size(); j++) { // create layers @@ -238,7 +233,7 @@ bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, (dataMapper->mLayerHandles.find(tracingArgs.parentId) == dataMapper->mLayerHandles.end())) { args.addToRoot = false; - } else { + } else if (tracingArgs.parentId != -1) { parentHandle = dataMapper->getLayerHandle(tracingArgs.parentId); } mFlinger.createLayer(args, &outHandle, parentHandle, &outLayerId, @@ -265,13 +260,13 @@ bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile, transaction.listenerCallbacks, transaction.id); } - for (int j = 0; j < entry.removed_layer_handles_size(); j++) { - dataMapper->mLayerHandles.erase(entry.removed_layer_handles(j)); - } - frameTime = entry.elapsed_realtime_nanos(); vsyncId = entry.vsync_id(); mFlinger.commit(frameTime, vsyncId); + + for (int j = 0; j < entry.removed_layer_handles_size(); j++) { + dataMapper->mLayerHandles.erase(entry.removed_layer_handles(j)); + } } flinger->stopLayerTracing(outputLayersTracePath); diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h index 900d566942..bbfeac1643 100644 --- a/services/surfaceflinger/TransactionState.h +++ b/services/surfaceflinger/TransactionState.h @@ -106,7 +106,6 @@ class CountDownLatch { public: enum { eSyncTransaction = 1 << 0, - eSyncInputWindows = 1 << 1, }; explicit CountDownLatch(uint32_t flags) : mFlags(flags) {} diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp index 30b9d8f1cb..4a8f157de1 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp +++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp @@ -26,21 +26,39 @@ using gui::DisplayInfo; using gui::IWindowInfosListener; using gui::WindowInfo; -struct WindowInfosListenerInvoker::WindowInfosReportedListener - : gui::BnWindowInfosReportedListener { - explicit WindowInfosReportedListener(WindowInfosListenerInvoker& invoker) : mInvoker(invoker) {} +struct WindowInfosListenerInvoker::WindowInfosReportedListener : gui::BnWindowInfosReportedListener, + DeathRecipient { + explicit WindowInfosReportedListener( + size_t callbackCount, + const std::unordered_set<sp<gui::IWindowInfosReportedListener>, + SpHash<gui::IWindowInfosReportedListener>>& + windowInfosReportedListeners) + : mCallbacksPending(callbackCount), + mWindowInfosReportedListeners(windowInfosReportedListeners) {} binder::Status onWindowInfosReported() override { - mInvoker.windowInfosReported(); + // TODO(b/222421815) There could potentially be callbacks that we don't need to wait for + // before calling the WindowInfosReportedListeners coming from InputWindowCommands. Filter + // the list of callbacks down to those from system server. + if (--mCallbacksPending == 0) { + for (const auto& listener : mWindowInfosReportedListeners) { + sp<IBinder> asBinder = IInterface::asBinder(listener); + if (asBinder->isBinderAlive()) { + listener->onWindowInfosReported(); + } + } + } return binder::Status::ok(); } - WindowInfosListenerInvoker& mInvoker; -}; + void binderDied(const wp<IBinder>&) { onWindowInfosReported(); } -WindowInfosListenerInvoker::WindowInfosListenerInvoker(SurfaceFlinger& flinger) - : mFlinger(flinger), - mWindowInfosReportedListener(sp<WindowInfosReportedListener>::make(*this)) {} +private: + std::atomic<size_t> mCallbacksPending; + std::unordered_set<sp<gui::IWindowInfosReportedListener>, + SpHash<gui::IWindowInfosReportedListener>> + mWindowInfosReportedListeners; +}; void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) { sp<IBinder> asBinder = IInterface::asBinder(listener); @@ -64,9 +82,11 @@ void WindowInfosListenerInvoker::binderDied(const wp<IBinder>& who) { mWindowInfosListeners.erase(who); } -void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo>& windowInfos, - const std::vector<DisplayInfo>& displayInfos, - bool shouldSync) { +void WindowInfosListenerInvoker::windowInfosChanged( + const std::vector<WindowInfo>& windowInfos, const std::vector<DisplayInfo>& displayInfos, + const std::unordered_set<sp<gui::IWindowInfosReportedListener>, + SpHash<gui::IWindowInfosReportedListener>>& + windowInfosReportedListeners) { ftl::SmallVector<const sp<IWindowInfosListener>, kStaticCapacity> windowInfosListeners; { std::scoped_lock lock(mListenersMutex); @@ -75,18 +95,25 @@ void WindowInfosListenerInvoker::windowInfosChanged(const std::vector<WindowInfo } } - mCallbacksPending = windowInfosListeners.size(); - + auto windowInfosReportedListener = windowInfosReportedListeners.empty() + ? nullptr + : sp<WindowInfosReportedListener>::make(windowInfosListeners.size(), + windowInfosReportedListeners); for (const auto& listener : windowInfosListeners) { - listener->onWindowInfosChanged(windowInfos, displayInfos, - shouldSync ? mWindowInfosReportedListener : nullptr); - } -} + sp<IBinder> asBinder = IInterface::asBinder(listener); + + // linkToDeath is used here to ensure that the windowInfosReportedListeners + // are called even if one of the windowInfosListeners dies before + // calling onWindowInfosReported. + if (windowInfosReportedListener) { + asBinder->linkToDeath(windowInfosReportedListener); + } -void WindowInfosListenerInvoker::windowInfosReported() { - mCallbacksPending--; - if (mCallbacksPending == 0) { - mFlinger.windowInfosReported(); + auto status = listener->onWindowInfosChanged(windowInfos, displayInfos, + windowInfosReportedListener); + if (windowInfosReportedListener && !status.isOk()) { + windowInfosReportedListener->onWindowInfosReported(); + } } } diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h index d8d8d0f570..a1d66a186e 100644 --- a/services/surfaceflinger/WindowInfosListenerInvoker.h +++ b/services/surfaceflinger/WindowInfosListenerInvoker.h @@ -29,22 +29,21 @@ class SurfaceFlinger; class WindowInfosListenerInvoker : public IBinder::DeathRecipient { public: - explicit WindowInfosListenerInvoker(SurfaceFlinger&); - void addWindowInfosListener(sp<gui::IWindowInfosListener>); void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener); void windowInfosChanged(const std::vector<gui::WindowInfo>&, - const std::vector<gui::DisplayInfo>&, bool shouldSync); + const std::vector<gui::DisplayInfo>&, + const std::unordered_set<sp<gui::IWindowInfosReportedListener>, + SpHash<gui::IWindowInfosReportedListener>>& + windowInfosReportedListeners); protected: void binderDied(const wp<IBinder>& who) override; private: struct WindowInfosReportedListener; - void windowInfosReported(); - SurfaceFlinger& mFlinger; std::mutex mListenersMutex; static constexpr size_t kStaticCapacity = 3; @@ -52,7 +51,6 @@ private: mWindowInfosListeners GUARDED_BY(mListenersMutex); sp<gui::IWindowInfosReportedListener> mWindowInfosReportedListener; - std::atomic<size_t> mCallbacksPending{0}; }; } // namespace android diff --git a/services/surfaceflinger/fuzzer/Android.bp b/services/surfaceflinger/fuzzer/Android.bp index b0b6bf14ab..7350e09cb5 100644 --- a/services/surfaceflinger/fuzzer/Android.bp +++ b/services/surfaceflinger/fuzzer/Android.bp @@ -127,3 +127,13 @@ cc_fuzz { "surfaceflinger_layer_fuzzer.cpp", ], } + +cc_fuzz { + name: "surfaceflinger_frametracer_fuzzer", + defaults: [ + "surfaceflinger_fuzz_defaults", + ], + srcs: [ + "surfaceflinger_frametracer_fuzzer.cpp", + ], +} diff --git a/services/surfaceflinger/fuzzer/README.md b/services/surfaceflinger/fuzzer/README.md index 78a7596ef3..7a5f229ae9 100644 --- a/services/surfaceflinger/fuzzer/README.md +++ b/services/surfaceflinger/fuzzer/README.md @@ -4,6 +4,7 @@ + [DisplayHardware](#DisplayHardware) + [Scheduler](#Scheduler) + [Layer](#Layer) ++ [FrameTracer](#FrameTracer) # <a name="SurfaceFlinger"></a> Fuzzer for SurfaceFlinger @@ -93,3 +94,16 @@ You can find the possible values in the fuzzer's source code. $ adb sync data $ adb shell /data/fuzz/arm64/surfaceflinger_layer_fuzzer/surfaceflinger_layer_fuzzer ``` + +# <a name="FrameTracer"></a> Fuzzer for FrameTracer + +#### Steps to run +1. Build the fuzzer +``` + $ mm -j$(nproc) surfaceflinger_frametracer_fuzzer +``` +2. To run on device +``` + $ adb sync data + $ adb shell /data/fuzz/arm64/surfaceflinger_frametracer_fuzzer/surfaceflinger_frametracer_fuzzer +``` diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp new file mode 100644 index 0000000000..a22a778989 --- /dev/null +++ b/services/surfaceflinger/fuzzer/surfaceflinger_frametracer_fuzzer.cpp @@ -0,0 +1,132 @@ +/* + * Copyright 2021 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 <FrameTracer/FrameTracer.h> +#include <fuzzer/FuzzedDataProvider.h> +#include <perfetto/trace/trace.pb.h> + +namespace android::fuzz { + +using namespace google::protobuf; + +constexpr size_t kMaxStringSize = 100; +constexpr size_t kMinLayerIds = 1; +constexpr size_t kMaxLayerIds = 10; +constexpr int32_t kConfigDuration = 500; +constexpr int32_t kBufferSize = 1024; +constexpr int32_t kTimeOffset = 100000; + +class FrameTracerFuzzer { +public: + FrameTracerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size) { + // Fuzzer is single-threaded, so no need to be thread-safe. + static bool wasInitialized = false; + if (!wasInitialized) { + perfetto::TracingInitArgs args; + args.backends = perfetto::kInProcessBackend; + perfetto::Tracing::Initialize(args); + wasInitialized = true; + } + mFrameTracer = std::make_unique<android::FrameTracer>(); + } + ~FrameTracerFuzzer() { mFrameTracer.reset(); } + void process(); + +private: + std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest(); + void traceTimestamp(); + std::vector<int32_t> generateLayerIds(size_t numLayerIds); + void traceTimestamp(std::vector<int32_t> layerIds, size_t numLayerIds); + void traceFence(std::vector<int32_t> layerIds, size_t numLayerIds); + std::unique_ptr<android::FrameTracer> mFrameTracer = nullptr; + FuzzedDataProvider mFdp; + android::FenceToFenceTimeMap mFenceFactory; +}; + +std::unique_ptr<perfetto::TracingSession> FrameTracerFuzzer::getTracingSessionForTest() { + perfetto::TraceConfig cfg; + cfg.set_duration_ms(kConfigDuration); + cfg.add_buffers()->set_size_kb(kBufferSize); + auto* dsCfg = cfg.add_data_sources()->mutable_config(); + dsCfg->set_name(android::FrameTracer::kFrameTracerDataSource); + + auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend); + tracingSession->Setup(cfg); + return tracingSession; +} + +std::vector<int32_t> FrameTracerFuzzer::generateLayerIds(size_t numLayerIds) { + std::vector<int32_t> layerIds; + for (size_t i = 0; i < numLayerIds; ++i) { + layerIds.push_back(mFdp.ConsumeIntegral<int32_t>()); + } + return layerIds; +} + +void FrameTracerFuzzer::traceTimestamp(std::vector<int32_t> layerIds, size_t numLayerIds) { + int32_t layerId = layerIds.at(mFdp.ConsumeIntegralInRange<size_t>(0, numLayerIds - 1)); + mFrameTracer->traceTimestamp(layerId, mFdp.ConsumeIntegral<uint64_t>() /*bufferID*/, + mFdp.ConsumeIntegral<uint64_t>() /*frameNumber*/, + mFdp.ConsumeIntegral<nsecs_t>() /*timestamp*/, + android::FrameTracer::FrameEvent::UNSPECIFIED, + mFdp.ConsumeIntegral<nsecs_t>() /*duration*/); +} + +void FrameTracerFuzzer::traceFence(std::vector<int32_t> layerIds, size_t numLayerIds) { + const nsecs_t signalTime = systemTime(); + const nsecs_t startTime = signalTime + kTimeOffset; + auto fence = mFenceFactory.createFenceTimeForTest(android::Fence::NO_FENCE); + mFenceFactory.signalAllForTest(android::Fence::NO_FENCE, signalTime); + int32_t layerId = layerIds.at(mFdp.ConsumeIntegralInRange<size_t>(0, numLayerIds - 1)); + mFrameTracer->traceFence(layerId, mFdp.ConsumeIntegral<uint64_t>() /*bufferID*/, + mFdp.ConsumeIntegral<uint64_t>() /*frameNumber*/, fence, + android::FrameTracer::FrameEvent::ACQUIRE_FENCE, startTime); +} + +void FrameTracerFuzzer::process() { + mFrameTracer->registerDataSource(); + + auto tracingSession = getTracingSessionForTest(); + tracingSession->StartBlocking(); + + size_t numLayerIds = mFdp.ConsumeIntegralInRange<size_t>(kMinLayerIds, kMaxLayerIds); + std::vector<int32_t> layerIds = generateLayerIds(numLayerIds); + + for (auto it = layerIds.begin(); it != layerIds.end(); ++it) { + mFrameTracer->traceNewLayer(*it /*layerId*/, + mFdp.ConsumeRandomLengthString(kMaxStringSize) /*layerName*/); + } + + traceTimestamp(layerIds, numLayerIds); + traceFence(layerIds, numLayerIds); + + mFenceFactory.signalAllForTest(android::Fence::NO_FENCE, systemTime()); + + tracingSession->StopBlocking(); + + for (auto it = layerIds.begin(); it != layerIds.end(); ++it) { + mFrameTracer->onDestroy(*it); + } +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + FrameTracerFuzzer frameTracerFuzzer(data, size); + frameTracerFuzzer.process(); + return 0; +} + +} // namespace android::fuzz diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp index f25043cd6d..8e60247c2d 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp @@ -151,7 +151,6 @@ void SurfaceFlingerFuzzer::invokeFlinger() { sp<IBinder> handle = defaultServiceManager()->checkService( String16(mFdp.ConsumeRandomLengthString().c_str())); mFlinger->fromHandle(handle); - mFlinger->windowInfosReported(); mFlinger->disableExpensiveRendering(); } diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h index 867a1985bd..3338da012a 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h +++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h @@ -30,7 +30,6 @@ #include <ui/DisplayStatInfo.h> #include <ui/DynamicDisplayInfo.h> -#include "BufferQueueLayer.h" #include "BufferStateLayer.h" #include "ContainerLayer.h" #include "DisplayDevice.h" @@ -334,18 +333,6 @@ public: mCreateBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger); } - sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer> &producer, - const sp<SurfaceFlinger> &flinger, - const wp<Layer> &layer) override { - return new MonitoredProducer(producer, flinger, layer); - } - - sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer> &consumer, - renderengine::RenderEngine &renderEngine, - uint32_t textureName, Layer *layer) override { - return new BufferLayerConsumer(consumer, renderEngine, textureName, layer); - } - std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface( const sp<IGraphicBufferProducer> &producer) override { if (!mCreateNativeWindowSurface) return nullptr; @@ -356,10 +343,6 @@ public: return compositionengine::impl::createCompositionEngine(); } - sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs &) override { - return nullptr; - } - sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs &) override { return nullptr; } @@ -540,19 +523,9 @@ public: mFlinger->setVsyncConfig(vsyncConfig, fdp->ConsumeIntegral<nsecs_t>()); } - void updateCompositorTiming(FuzzedDataProvider *fdp) { - std::shared_ptr<FenceTime> presentFenceTime = FenceTime::NO_FENCE; - mFlinger->updateCompositorTiming({}, fdp->ConsumeIntegral<nsecs_t>(), presentFenceTime); - } - - void getCompositorTiming() { - CompositorTiming compositorTiming; - mFlinger->getCompositorTiming(&compositorTiming); - } - sp<IBinder> fuzzBoot(FuzzedDataProvider *fdp) { mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(fdp->ConsumeBool()); - mFlinger->createConnection(); + const sp<Client> client = new Client(mFlinger); DisplayIdGenerator<HalVirtualDisplayId> kGenerator; HalVirtualDisplayId halVirtualDisplayId = kGenerator.generateId().value(); @@ -585,7 +558,6 @@ public: sp<IBinder> display = fuzzBoot(&mFdp); sp<IGraphicBufferProducer> bufferProducer = sp<mock::GraphicBufferProducer>::make(); - mFlinger->authenticateSurfaceTexture(bufferProducer.get()); mFlinger->createDisplayEventConnection(); @@ -645,11 +617,8 @@ public: mFlinger->postComposition(); - getCompositorTiming(); - - updateCompositorTiming(&mFdp); + mFlinger->trackPresentLatency(mFdp.ConsumeIntegral<nsecs_t>(), FenceTime::NO_FENCE); - mFlinger->setCompositorTimingSnapped({}, mFdp.ConsumeIntegral<nsecs_t>()); FTL_FAKE_GUARD(kMainThreadContext, mFlinger->postFrame()); mFlinger->calculateExpectedPresentTime({}); @@ -779,7 +748,7 @@ public: return mFlinger->onTransact(code, data, reply, flags); } - auto getGPUContextPriority() { return mFlinger->getGPUContextPriority(); } + auto getGpuContextPriority() { return mFlinger->getGpuContextPriority(); } auto calculateMaxAcquiredBufferCount(Fps refreshRate, std::chrono::nanoseconds presentLatency) const { diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp index 34cf90628a..4d90b1e56e 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_layer_fuzzer.cpp @@ -18,9 +18,7 @@ #include <Client.h> #include <DisplayDevice.h> #include <EffectLayer.h> -#include <LayerRejecter.h> #include <LayerRenderArea.h> -#include <MonitoredProducer.h> #include <ftl/future.h> #include <fuzzer/FuzzedDataProvider.h> #include <gui/IProducerListener.h> @@ -59,8 +57,10 @@ Rect LayerFuzzer::getFuzzedRect() { } FrameTimelineInfo LayerFuzzer::getFuzzedFrameTimelineInfo() { - return FrameTimelineInfo{.vsyncId = mFdp.ConsumeIntegral<int64_t>(), - .inputEventId = mFdp.ConsumeIntegral<int32_t>()}; + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = mFdp.ConsumeIntegral<int64_t>(); + ftInfo.inputEventId = mFdp.ConsumeIntegral<int32_t>(); + return ftInfo; } LayerCreationArgs LayerFuzzer::createLayerCreationArgs(TestableSurfaceFlinger* flinger, @@ -115,17 +115,18 @@ void LayerFuzzer::invokeBufferStateLayer() { sp<Fence> fence = sp<Fence>::make(); const std::shared_ptr<FenceTime> fenceTime = std::make_shared<FenceTime>(fence); - const CompositorTiming compositor = {mFdp.ConsumeIntegral<int64_t>(), - mFdp.ConsumeIntegral<int64_t>(), - mFdp.ConsumeIntegral<int64_t>()}; + const CompositorTiming compositorTiming(mFdp.ConsumeIntegral<int64_t>(), + mFdp.ConsumeIntegral<int64_t>(), + mFdp.ConsumeIntegral<int64_t>(), + mFdp.ConsumeIntegral<int64_t>()); layer->onLayerDisplayed(ftl::yield<FenceResult>(fence).share()); layer->onLayerDisplayed( ftl::yield<FenceResult>(base::unexpected(mFdp.ConsumeIntegral<status_t>())).share()); layer->releasePendingBuffer(mFdp.ConsumeIntegral<int64_t>()); - layer->finalizeFrameEventHistory(fenceTime, compositor); - layer->onPostComposition(nullptr, fenceTime, fenceTime, compositor); + layer->finalizeFrameEventHistory(fenceTime, compositorTiming); + layer->onPostComposition(nullptr, fenceTime, fenceTime, compositorTiming); layer->isBufferDue(mFdp.ConsumeIntegral<int64_t>()); layer->setTransform(mFdp.ConsumeIntegral<uint32_t>()); diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp index da60a6981b..1a91a69492 100644 --- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp +++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp @@ -319,7 +319,7 @@ void SchedulerFuzzer::fuzzRefreshRateSelection() { LayerCreationArgs args(flinger.flinger(), client, mFdp.ConsumeRandomLengthString(kRandomStringLength) /*name*/, mFdp.ConsumeIntegral<uint16_t>() /*layerFlags*/, LayerMetadata()); - sp<Layer> layer = new BufferQueueLayer(args); + sp<Layer> layer = new BufferStateLayer(args); layer->setFrameRateSelectionPriority(mFdp.ConsumeIntegral<int16_t>()); } diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h index 52503bad3a..cdc2706ee2 100644 --- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h +++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h @@ -24,6 +24,8 @@ #include <unordered_map> #include <vector> +using android::gui::LayerMetadata; + namespace android { namespace surfaceflinger { diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto index 13647b669e..7def02422e 100644 --- a/services/surfaceflinger/layerproto/layerstrace.proto +++ b/services/surfaceflinger/layerproto/layerstrace.proto @@ -40,7 +40,7 @@ message LayersTraceFileProto { repeated LayersTraceProto entry = 2; } -/* one window manager trace entry. */ +/* one layers trace entry. */ message LayersTraceProto { /* required: elapsed realtime in nanos since boot of when this entry was logged */ optional sfixed64 elapsed_realtime_nanos = 1; @@ -60,4 +60,6 @@ message LayersTraceProto { optional uint32 missed_entries = 6; repeated DisplayProto displays = 7; + + optional int64 vsync_id = 8; } diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp index ceddf2727a..276431e661 100644 --- a/services/surfaceflinger/tests/Android.bp +++ b/services/surfaceflinger/tests/Android.bp @@ -34,6 +34,7 @@ cc_test { "DisplayConfigs_test.cpp", "DisplayEventReceiver_test.cpp", "EffectLayer_test.cpp", + "LayerBorder_test.cpp", "InvalidHandles_test.cpp", "LayerCallback_test.cpp", "LayerRenderTypeTransaction_test.cpp", diff --git a/services/surfaceflinger/tests/BootDisplayMode_test.cpp b/services/surfaceflinger/tests/BootDisplayMode_test.cpp index d70908e390..432e227cae 100644 --- a/services/surfaceflinger/tests/BootDisplayMode_test.cpp +++ b/services/surfaceflinger/tests/BootDisplayMode_test.cpp @@ -18,6 +18,7 @@ #include <gtest/gtest.h> +#include <gui/AidlStatusUtil.h> #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> #include <private/gui/ComposerServiceAIDL.h> @@ -25,15 +26,17 @@ namespace android { +using gui::aidl_utils::statusTFromBinderStatus; + TEST(BootDisplayModeTest, setBootDisplayMode) { - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - sp<gui::ISurfaceComposer> sf_aidl(ComposerServiceAIDL::getComposerService()); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); auto displayToken = SurfaceComposerClient::getInternalDisplayToken(); bool bootModeSupport = false; - binder::Status status = sf_aidl->getBootDisplayModeSupport(&bootModeSupport); - ASSERT_NO_FATAL_FAILURE(status.transactionError()); + binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport); + ASSERT_NO_FATAL_FAILURE(statusTFromBinderStatus(status)); if (bootModeSupport) { - ASSERT_EQ(NO_ERROR, sf->setBootDisplayMode(displayToken, 0)); + status = sf->setBootDisplayMode(displayToken, 0); + ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status)); } } @@ -42,10 +45,10 @@ TEST(BootDisplayModeTest, clearBootDisplayMode) { auto displayToken = SurfaceComposerClient::getInternalDisplayToken(); bool bootModeSupport = false; binder::Status status = sf->getBootDisplayModeSupport(&bootModeSupport); - ASSERT_NO_FATAL_FAILURE(status.transactionError()); + ASSERT_NO_FATAL_FAILURE(statusTFromBinderStatus(status)); if (bootModeSupport) { status = sf->clearBootDisplayMode(displayToken); - ASSERT_EQ(NO_ERROR, status.transactionError()); + ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status)); } } diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp index d33bc1080c..8a443b823d 100644 --- a/services/surfaceflinger/tests/Credentials_test.cpp +++ b/services/surfaceflinger/tests/Credentials_test.cpp @@ -18,13 +18,14 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" +#include <android/gui/ISurfaceComposer.h> #include <gtest/gtest.h> -#include <gui/ISurfaceComposer.h> +#include <gui/AidlStatusUtil.h> #include <gui/LayerDebugInfo.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> #include <private/android_filesystem_config.h> -#include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <ui/DisplayMode.h> #include <ui/DynamicDisplayInfo.h> #include <utils/String8.h> @@ -34,6 +35,8 @@ namespace android { using Transaction = SurfaceComposerClient::Transaction; +using gui::LayerDebugInfo; +using gui::aidl_utils::statusTFromBinderStatus; using ui::ColorMode; namespace { @@ -307,23 +310,26 @@ TEST_F(CredentialsTest, CaptureLayersTest) { */ TEST_F(CredentialsTest, GetLayerDebugInfo) { setupBackgroundSurface(); - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); // Historically, only root and shell can access the getLayerDebugInfo which // is called when we call dumpsys. I don't see a reason why we should change this. std::vector<LayerDebugInfo> outLayers; // Check with root. seteuid(AID_ROOT); - ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers)); + binder::Status status = sf->getLayerDebugInfo(&outLayers); + ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status)); // Check as a shell. seteuid(AID_SHELL); - ASSERT_EQ(NO_ERROR, sf->getLayerDebugInfo(&outLayers)); + status = sf->getLayerDebugInfo(&outLayers); + ASSERT_EQ(NO_ERROR, statusTFromBinderStatus(status)); // Check as anyone else. seteuid(AID_ROOT); seteuid(AID_BIN); - ASSERT_EQ(PERMISSION_DENIED, sf->getLayerDebugInfo(&outLayers)); + status = sf->getLayerDebugInfo(&outLayers); + ASSERT_EQ(PERMISSION_DENIED, statusTFromBinderStatus(status)); } TEST_F(CredentialsTest, IsWideColorDisplayBasicCorrectness) { diff --git a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp index 0e54664f77..0df7e2fafa 100644 --- a/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp +++ b/services/surfaceflinger/tests/DisplayEventReceiver_test.cpp @@ -36,7 +36,8 @@ TEST_F(DisplayEventReceiverTest, getLatestVsyncEventData) { EXPECT_GT(vsyncEventData.frameTimelines[0].deadlineTimestamp, now) << "Deadline timestamp should be greater than frame time"; for (size_t i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) { - EXPECT_NE(FrameTimelineInfo::INVALID_VSYNC_ID, vsyncEventData.frameTimelines[i].vsyncId); + EXPECT_NE(gui::FrameTimelineInfo::INVALID_VSYNC_ID, + vsyncEventData.frameTimelines[i].vsyncId); EXPECT_GT(vsyncEventData.frameTimelines[i].expectedPresentationTime, vsyncEventData.frameTimelines[i].deadlineTimestamp) << "Expected vsync timestamp should be greater than deadline"; @@ -51,4 +52,4 @@ TEST_F(DisplayEventReceiverTest, getLatestVsyncEventData) { } } -} // namespace android
\ No newline at end of file +} // namespace android diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp index d192a2d83d..023133f2c3 100644 --- a/services/surfaceflinger/tests/InvalidHandles_test.cpp +++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp @@ -48,7 +48,7 @@ protected: } sp<SurfaceControl> makeNotSurfaceControl() { - return new SurfaceControl(mScc, new NotALayer(), nullptr, true); + return new SurfaceControl(mScc, new NotALayer(), 1); } }; @@ -64,4 +64,4 @@ TEST_F(InvalidHandleTest, captureLayersInvalidHandle) { } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file +#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/tests/LayerBorder_test.cpp b/services/surfaceflinger/tests/LayerBorder_test.cpp new file mode 100644 index 0000000000..f80c7055da --- /dev/null +++ b/services/surfaceflinger/tests/LayerBorder_test.cpp @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2022 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. + */ + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +// TODO: Amend all tests when screenshots become fully reworked for borders +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wconversion" + +#include <chrono> // std::chrono::seconds +#include <thread> // std::this_thread::sleep_for +#include "LayerTransactionTest.h" + +namespace android { + +class LayerBorderTest : public LayerTransactionTest { +protected: + virtual void SetUp() { + LayerTransactionTest::SetUp(); + ASSERT_EQ(NO_ERROR, mClient->initCheck()); + + toHalf3 = ColorTransformHelper::toHalf3; + toHalf4 = ColorTransformHelper::toHalf4; + + const auto display = SurfaceComposerClient::getInternalDisplayToken(); + ASSERT_FALSE(display == nullptr); + mColorOrange = toHalf4({255, 140, 0, 255}); + mParentLayer = createColorLayer("Parent layer", Color::RED); + + mContainerLayer = mClient->createSurface(String8("Container Layer"), 0 /* width */, + 0 /* height */, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceContainer | + ISurfaceComposerClient::eNoColorFill, + mParentLayer->getHandle()); + EXPECT_NE(nullptr, mContainerLayer.get()) << "failed to create container layer"; + + mEffectLayer1 = mClient->createSurface(String8("Effect Layer"), 0 /* width */, + 0 /* height */, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect | + ISurfaceComposerClient::eNoColorFill, + mContainerLayer->getHandle()); + EXPECT_NE(nullptr, mEffectLayer1.get()) << "failed to create effect layer 1"; + + mEffectLayer2 = mClient->createSurface(String8("Effect Layer"), 0 /* width */, + 0 /* height */, PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect | + ISurfaceComposerClient::eNoColorFill, + mContainerLayer->getHandle()); + + EXPECT_NE(nullptr, mEffectLayer2.get()) << "failed to create effect layer 2"; + + asTransaction([&](Transaction& t) { + t.setDisplayLayerStack(display, ui::DEFAULT_LAYER_STACK); + t.setLayer(mParentLayer, INT32_MAX - 20).show(mParentLayer); + t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque); + + t.setColor(mEffectLayer1, toHalf3(Color::BLUE)); + + t.setColor(mEffectLayer2, toHalf3(Color::GREEN)); + }); + } + + virtual void TearDown() { + // Uncomment the line right below when running any of the tests + // std::this_thread::sleep_for (std::chrono::seconds(30)); + LayerTransactionTest::TearDown(); + mParentLayer = 0; + } + + std::function<half3(Color)> toHalf3; + std::function<half4(Color)> toHalf4; + sp<SurfaceControl> mParentLayer, mContainerLayer, mEffectLayer1, mEffectLayer2; + half4 mColorOrange; +}; + +TEST_F(LayerBorderTest, OverlappingVisibleRegions) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + + t.enableBorder(mContainerLayer, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, PartiallyCoveredVisibleRegion) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + + t.enableBorder(mEffectLayer1, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, NonOverlappingVisibleRegion) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 200, 200)); + t.setCrop(mEffectLayer2, Rect(400, 400, 600, 600)); + + t.enableBorder(mContainerLayer, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, EmptyVisibleRegion) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(200, 200, 400, 400)); + t.setCrop(mEffectLayer2, Rect(0, 0, 600, 600)); + + t.enableBorder(mEffectLayer1, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, ZOrderAdjustment) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + t.setLayer(mParentLayer, 10); + t.setLayer(mEffectLayer1, 30); + t.setLayer(mEffectLayer2, 20); + + t.enableBorder(mEffectLayer1, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, GrandChildHierarchy) { + sp<SurfaceControl> containerLayer2 = + mClient->createSurface(String8("Container Layer"), 0 /* width */, 0 /* height */, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceContainer | + ISurfaceComposerClient::eNoColorFill, + mContainerLayer->getHandle()); + EXPECT_NE(nullptr, containerLayer2.get()) << "failed to create container layer 2"; + + sp<SurfaceControl> effectLayer3 = + mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceEffect | + ISurfaceComposerClient::eNoColorFill, + containerLayer2->getHandle()); + + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + t.setCrop(effectLayer3, Rect(400, 400, 800, 800)); + t.setColor(effectLayer3, toHalf3(Color::BLUE)); + + t.enableBorder(mContainerLayer, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(effectLayer3); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, TransparentAlpha) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + t.setAlpha(mEffectLayer1, 0.0f); + + t.enableBorder(mContainerLayer, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, SemiTransparentAlpha) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + t.setAlpha(mEffectLayer2, 0.5f); + + t.enableBorder(mEffectLayer2, true, 20, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, InvisibleLayers) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + + t.enableBorder(mContainerLayer, true, 20, mColorOrange); + t.hide(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, BufferStateLayer) { + asTransaction([&](Transaction& t) { + t.hide(mEffectLayer1); + t.hide(mEffectLayer2); + t.show(mContainerLayer); + + sp<SurfaceControl> bufferStateLayer = + mClient->createSurface(String8("BufferState"), 0 /* width */, 0 /* height */, + PIXEL_FORMAT_RGBA_8888, + ISurfaceComposerClient::eFXSurfaceBufferState, + mContainerLayer->getHandle()); + + sp<GraphicBuffer> buffer = + new GraphicBuffer(400, 400, PIXEL_FORMAT_RGBA_8888, 1, + BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN | + BufferUsage::COMPOSER_OVERLAY | BufferUsage::GPU_TEXTURE, + "test"); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 200, 200), Color::GREEN); + TransactionUtils::fillGraphicBufferColor(buffer, Rect(200, 200, 400, 400), Color::BLUE); + + t.setBuffer(bufferStateLayer, buffer); + t.setPosition(bufferStateLayer, 100, 100); + t.show(bufferStateLayer); + t.enableBorder(mContainerLayer, true, 20, mColorOrange); + }); +} + +TEST_F(LayerBorderTest, CustomWidth) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + + t.enableBorder(mContainerLayer, true, 50, mColorOrange); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, CustomColor) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 400, 400)); + t.setCrop(mEffectLayer2, Rect(200, 200, 600, 600)); + + t.enableBorder(mContainerLayer, true, 20, toHalf4({255, 0, 255, 255})); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +TEST_F(LayerBorderTest, CustomWidthAndColorAndOpacity) { + asTransaction([&](Transaction& t) { + t.setCrop(mEffectLayer1, Rect(0, 0, 200, 200)); + t.setCrop(mEffectLayer2, Rect(400, 400, 600, 600)); + + t.enableBorder(mContainerLayer, true, 40, toHalf4({255, 255, 0, 128})); + t.show(mEffectLayer1); + t.show(mEffectLayer2); + t.show(mContainerLayer); + }); +} + +} // namespace android + +// TODO(b/129481165): remove the #pragma below and fix conversion issues +#pragma clang diagnostic pop // ignored "-Wconversion" diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp index 219db8c148..c8df0a09be 100644 --- a/services/surfaceflinger/tests/LayerCallback_test.cpp +++ b/services/surfaceflinger/tests/LayerCallback_test.cpp @@ -1050,7 +1050,10 @@ TEST_F(LayerCallbackTest, ExpectedPresentTime) { } const Vsync vsync = waitForNextVsync(); - transaction.setFrameTimelineInfo({vsync.vsyncId, 0}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = vsync.vsyncId; + ftInfo.inputEventId = 0; + transaction.setFrameTimelineInfo(ftInfo); transaction.apply(); ExpectedResult expected; diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h index 6bd7920a62..b46db65f84 100644 --- a/services/surfaceflinger/tests/LayerTransactionTest.h +++ b/services/surfaceflinger/tests/LayerTransactionTest.h @@ -23,9 +23,11 @@ #include <cutils/properties.h> #include <gtest/gtest.h> +#include <gui/AidlStatusUtil.h> #include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> #include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <ui/DisplayMode.h> #include "BufferGenerator.h" @@ -44,8 +46,9 @@ protected: ASSERT_NO_FATAL_FAILURE(SetUpDisplay()); - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed)); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); + binder::Status status = sf->getColorManagement(&mColorManagementUsed); + ASSERT_NO_FATAL_FAILURE(gui::aidl_utils::statusTFromBinderStatus(status)); mCaptureArgs.displayToken = mDisplay; } diff --git a/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp b/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp index 4efec7738a..e43ef952d6 100644 --- a/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp +++ b/services/surfaceflinger/tests/SetFrameRateOverride_test.cpp @@ -14,9 +14,9 @@ * limitations under the License. */ +#include <android/gui/ISurfaceComposer.h> #include <gtest/gtest.h> #include <gui/DisplayEventReceiver.h> -#include <gui/ISurfaceComposer.h> #include <gui/SurfaceComposerClient.h> #include <sys/epoll.h> #include <algorithm> @@ -24,12 +24,14 @@ namespace android { namespace { using FrameRateOverride = DisplayEventReceiver::Event::FrameRateOverride; +using gui::ISurfaceComposer; class SetFrameRateOverrideTest : public ::testing::Test { protected: void SetUp() override { - const ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp; - const ISurfaceComposer::EventRegistrationFlags eventRegistration = { + const ISurfaceComposer::VsyncSource vsyncSource = + ISurfaceComposer::VsyncSource::eVsyncSourceApp; + const EventRegistrationFlags eventRegistration = { ISurfaceComposer::EventRegistration::frameRateOverride}; mDisplayEventReceiver = diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp index b38032d265..f824fdff3a 100644 --- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp +++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp @@ -86,7 +86,9 @@ public: class DelayedEventGenerator { public: explicit DelayedEventGenerator(std::function<void()> onTimerExpired) - : mOnTimerExpired(onTimerExpired), mThread([this]() { loop(); }) {} + : mOnTimerExpired(onTimerExpired) { + mThread = std::thread([this]() { loop(); }); + } ~DelayedEventGenerator() { ALOGI("DelayedEventGenerator exiting."); diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp index b3b4ec15cd..00845d793f 100644 --- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp +++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp @@ -29,6 +29,7 @@ #include "MockComposerHal.h" #include <binder/Parcel.h> +#include <gui/AidlStatusUtil.h> #include <gui/DisplayEventReceiver.h> #include <gui/ISurfaceComposer.h> #include <gui/LayerDebugInfo.h> @@ -43,6 +44,7 @@ #include <hwbinder/ProcessState.h> #include <log/log.h> #include <private/gui/ComposerService.h> +#include <private/gui/ComposerServiceAIDL.h> #include <ui/DisplayMode.h> #include <ui/DynamicDisplayInfo.h> #include <utils/Looper.h> @@ -243,8 +245,9 @@ protected: mComposerClient = new SurfaceComposerClient; ASSERT_EQ(NO_ERROR, mComposerClient->initCheck()); - mReceiver.reset(new DisplayEventReceiver(ISurfaceComposer::eVsyncSourceApp, - ISurfaceComposer::EventRegistration::modeChanged)); + mReceiver.reset( + new DisplayEventReceiver(gui::ISurfaceComposer::VsyncSource::eVsyncSourceApp, + gui::ISurfaceComposer::EventRegistration::modeChanged)); mLooper = new Looper(false); mLooper->addFd(mReceiver->getFd(), 0, ALOOPER_EVENT_INPUT, processDisplayEvents, this); } @@ -992,7 +995,7 @@ using DisplayTest_2_1 = DisplayTest<FakeComposerService_2_1>; // Tests that VSYNC injection can be safely toggled while invalidating. TEST_F(DisplayTest_2_1, VsyncInjection) { - const auto flinger = ComposerService::getComposerService(); + const auto flinger = ComposerServiceAIDL::getComposerService(); bool enable = true; for (int i = 0; i < 100; i++) { @@ -1238,9 +1241,10 @@ protected: sFakeComposer->clearFrames(); ASSERT_EQ(0, sFakeComposer->getFrameCount()); - sp<ISurfaceComposer> sf(ComposerService::getComposerService()); - std::vector<LayerDebugInfo> layers; - status_t result = sf->getLayerDebugInfo(&layers); + sp<gui::ISurfaceComposer> sf(ComposerServiceAIDL::getComposerService()); + std::vector<gui::LayerDebugInfo> layers; + binder::Status status = sf->getLayerDebugInfo(&layers); + status_t result = gui::aidl_utils::statusTFromBinderStatus(status); if (result != NO_ERROR) { ALOGE("Failed to get layers %s %d", strerror(-result), result); } else { diff --git a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp index ac4354cde1..0e214af706 100644 --- a/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp +++ b/services/surfaceflinger/tests/tracing/TransactionTraceTestSuite.cpp @@ -83,6 +83,37 @@ protected: std::vector<std::filesystem::path> TransactionTraceTestSuite::sTransactionTraces{}; +struct LayerInfo { + int id; + std::string name; + int parent; + int z; + uint64_t curr_frame; + float x; + float y; +}; + +bool operator==(const LayerInfo& lh, const LayerInfo& rh) { + return std::make_tuple(lh.id, lh.name, lh.parent, lh.z, lh.curr_frame) == + std::make_tuple(rh.id, rh.name, rh.parent, rh.z, rh.curr_frame); +} + +bool compareById(const LayerInfo& a, const LayerInfo& b) { + return a.id < b.id; +} + +inline void PrintTo(const LayerInfo& info, ::std::ostream* os) { + *os << "Layer [" << info.id << "] name=" << info.name << " parent=" << info.parent + << " z=" << info.z << " curr_frame=" << info.curr_frame << " x=" << info.x + << " y=" << info.y; +} + +struct find_id : std::unary_function<LayerInfo, bool> { + int id; + find_id(int id) : id(id) {} + bool operator()(LayerInfo const& m) const { return m.id == id; } +}; + TEST_P(TransactionTraceTestSuite, validateEndState) { ASSERT_GT(mActualLayersTraceProto.entry_size(), 0); ASSERT_GT(mExpectedLayersTraceProto.entry_size(), 0); @@ -92,19 +123,64 @@ TEST_P(TransactionTraceTestSuite, validateEndState) { auto actualLastEntry = mActualLayersTraceProto.entry(mActualLayersTraceProto.entry_size() - 1); EXPECT_EQ(expectedLastEntry.layers().layers_size(), actualLastEntry.layers().layers_size()); - for (int i = 0; - i < expectedLastEntry.layers().layers_size() && i < actualLastEntry.layers().layers_size(); - i++) { - auto expectedLayer = expectedLastEntry.layers().layers(i); - auto actualLayer = actualLastEntry.layers().layers(i); - EXPECT_EQ(expectedLayer.id(), actualLayer.id()); - EXPECT_EQ(expectedLayer.name(), actualLayer.name()); - EXPECT_EQ(expectedLayer.parent(), actualLayer.parent()); - EXPECT_EQ(expectedLayer.z(), actualLayer.z()); - EXPECT_EQ(expectedLayer.curr_frame(), actualLayer.curr_frame()); - ALOGV("Validating %s[%d] parent=%d z=%d frame=%" PRIu64, expectedLayer.name().c_str(), - expectedLayer.id(), expectedLayer.parent(), expectedLayer.z(), - expectedLayer.curr_frame()); + + std::vector<LayerInfo> expectedLayers; + expectedLayers.reserve(static_cast<size_t>(expectedLastEntry.layers().layers_size())); + for (int i = 0; i < expectedLastEntry.layers().layers_size(); i++) { + auto layer = expectedLastEntry.layers().layers(i); + expectedLayers.push_back({layer.id(), layer.name(), layer.parent(), layer.z(), + layer.curr_frame(), + layer.has_position() ? layer.position().x() : -1, + layer.has_position() ? layer.position().y() : -1}); + } + std::sort(expectedLayers.begin(), expectedLayers.end(), compareById); + + std::vector<LayerInfo> actualLayers; + actualLayers.reserve(static_cast<size_t>(actualLastEntry.layers().layers_size())); + for (int i = 0; i < actualLastEntry.layers().layers_size(); i++) { + auto layer = actualLastEntry.layers().layers(i); + actualLayers.push_back({layer.id(), layer.name(), layer.parent(), layer.z(), + layer.curr_frame(), + layer.has_position() ? layer.position().x() : -1, + layer.has_position() ? layer.position().y() : -1}); + } + std::sort(actualLayers.begin(), actualLayers.end(), compareById); + + size_t i = 0; + for (; i < actualLayers.size() && i < expectedLayers.size(); i++) { + auto it = std::find_if(actualLayers.begin(), actualLayers.end(), + find_id(expectedLayers[i].id)); + EXPECT_NE(it, actualLayers.end()); + EXPECT_EQ(expectedLayers[i], *it); + ALOGV("Validating %s[%d] parent=%d z=%d frame=%" PRIu64, expectedLayers[i].name.c_str(), + expectedLayers[i].id, expectedLayers[i].parent, expectedLayers[i].z, + expectedLayers[i].curr_frame); + } + + EXPECT_EQ(expectedLayers.size(), actualLayers.size()); + + if (i < actualLayers.size()) { + for (size_t j = 0; j < actualLayers.size(); j++) { + if (std::find_if(expectedLayers.begin(), expectedLayers.end(), + find_id(actualLayers[j].id)) == expectedLayers.end()) { + ALOGD("actualLayers [%d]:%s parent=%d z=%d frame=%" PRIu64, actualLayers[j].id, + actualLayers[j].name.c_str(), actualLayers[j].parent, actualLayers[j].z, + actualLayers[j].curr_frame); + } + } + FAIL(); + } + + if (i < expectedLayers.size()) { + for (size_t j = 0; j < expectedLayers.size(); j++) { + if (std::find_if(actualLayers.begin(), actualLayers.end(), + find_id(expectedLayers[j].id)) == actualLayers.end()) { + ALOGD("expectedLayers [%d]:%s parent=%d z=%d frame=%" PRIu64, expectedLayers[j].id, + expectedLayers[j].name.c_str(), expectedLayers[j].parent, expectedLayers[j].z, + expectedLayers[j].curr_frame); + } + } + FAIL(); } } diff --git a/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope b/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope Binary files differnew file mode 100644 index 0000000000..16a91ee6ee --- /dev/null +++ b/services/surfaceflinger/tests/tracing/testdata/layers_trace_nodisplayfound.winscope diff --git a/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope Binary files differnew file mode 100644 index 0000000000..cd62ab8ce0 --- /dev/null +++ b/services/surfaceflinger/tests/tracing/testdata/transactions_trace_nodisplayfound.winscope diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index bbfedc7685..f6ebfe5af1 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -37,7 +37,6 @@ #include <system/window.h> #include <utils/String8.h> -#include "BufferQueueLayer.h" #include "ContainerLayer.h" #include "DisplayRenderArea.h" #include "EffectLayer.h" @@ -492,65 +491,31 @@ struct BaseLayerProperties { static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::PREMULTIPLIED; - static void enqueueBuffer(CompositionTest*, sp<BufferQueueLayer> layer) { - auto producer = layer->getProducer(); - - IGraphicBufferProducer::QueueBufferOutput qbo; - status_t result = producer->connect(nullptr, NATIVE_WINDOW_API_EGL, false, &qbo); - if (result != NO_ERROR) { - ALOGE("Failed to connect() (%d)", result); - return; - } - - int slot; - sp<Fence> fence; - result = producer->dequeueBuffer(&slot, &fence, LayerProperties::WIDTH, - LayerProperties::HEIGHT, LayerProperties::FORMAT, - LayerProperties::USAGE, nullptr, nullptr); - if (result != IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { - ALOGE("Failed to dequeueBuffer() (%d)", result); - return; - } - - sp<GraphicBuffer> buffer; - result = producer->requestBuffer(slot, &buffer); - if (result != NO_ERROR) { - ALOGE("Failed to requestBuffer() (%d)", result); - return; - } - - IGraphicBufferProducer::QueueBufferInput qbi(systemTime(), false /* isAutoTimestamp */, - LayerProperties::DATASPACE, - Rect(LayerProperties::WIDTH, - LayerProperties::HEIGHT), - LayerProperties::SCALING_MODE, - LayerProperties::TRANSFORM, Fence::NO_FENCE); - result = producer->queueBuffer(slot, qbi, &qbo); - if (result != NO_ERROR) { - ALOGE("Failed to queueBuffer (%d)", result); - return; - } - } - - static void setupLatchedBuffer(CompositionTest* test, sp<BufferQueueLayer> layer) { - // TODO: Eliminate the complexity of actually creating a buffer - layer->setSizeForTest(LayerProperties::WIDTH, LayerProperties::HEIGHT); - status_t err = - layer->setDefaultBufferProperties(LayerProperties::WIDTH, LayerProperties::HEIGHT, - LayerProperties::FORMAT); - ASSERT_EQ(NO_ERROR, err); + static void setupLatchedBuffer(CompositionTest* test, sp<BufferStateLayer> layer) { Mock::VerifyAndClear(test->mRenderEngine); - EXPECT_CALL(*test->mFlinger.scheduler(), scheduleFrame()).Times(1); - enqueueBuffer(test, layer); - Mock::VerifyAndClearExpectations(test->mFlinger.scheduler()); + const auto buffer = std::make_shared< + renderengine::mock::FakeExternalTexture>(LayerProperties::WIDTH, + LayerProperties::HEIGHT, + DEFAULT_TEXTURE_ID, + LayerProperties::FORMAT, + LayerProperties::USAGE | + GraphicBuffer::USAGE_HW_TEXTURE); + + auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer); + layerDrawingState.crop = Rect(0, 0, LayerProperties::HEIGHT, LayerProperties::WIDTH); + layerDrawingState.buffer = buffer; + layerDrawingState.acquireFence = Fence::NO_FENCE; + layerDrawingState.dataspace = ui::Dataspace::UNKNOWN; + layer->setSurfaceDamageRegion( + Region(Rect(LayerProperties::HEIGHT, LayerProperties::WIDTH))); bool ignoredRecomputeVisibleRegions; layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, 0); Mock::VerifyAndClear(test->mRenderEngine); } - static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) { + static void setupLayerState(CompositionTest* test, sp<BufferStateLayer> layer) { setupLatchedBuffer(test, layer); } @@ -664,7 +629,8 @@ struct BaseLayerProperties { EXPECT_EQ(false, layer.source.buffer.isY410BT2020); EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha); EXPECT_EQ(false, layer.source.buffer.isOpaque); - EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.x); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.y); EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace); EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha); return resultFuture; @@ -714,7 +680,8 @@ struct BaseLayerProperties { EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1], LayerProperties::COLOR[2]), layer.source.solidColor); - EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.x); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.y); EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace); EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha); return resultFuture; @@ -736,7 +703,7 @@ struct SidebandLayerProperties : public BaseLayerProperties<SidebandLayerPropert using Base = BaseLayerProperties<SidebandLayerProperties>; static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE; - static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) { + static void setupLayerState(CompositionTest* test, sp<BufferStateLayer> layer) { sp<NativeHandle> stream = NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM), false); @@ -792,7 +759,8 @@ struct CommonSecureLayerProperties : public BaseLayerProperties<LayerProperties> const renderengine::LayerSettings layer = layerSettings.back(); EXPECT_THAT(layer.source.buffer.buffer, IsNull()); EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor); - EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.x); + EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius.y); EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace); EXPECT_EQ(1.0f, layer.alpha); return resultFuture; @@ -818,14 +786,14 @@ struct SecureLayerProperties : public CommonSecureLayerProperties<SecureLayerPro struct CursorLayerProperties : public BaseLayerProperties<CursorLayerProperties> { using Base = BaseLayerProperties<CursorLayerProperties>; - static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) { + static void setupLayerState(CompositionTest* test, sp<BufferStateLayer> layer) { Base::setupLayerState(test, layer); test->mFlinger.setLayerPotentialCursor(layer, true); } }; struct NoLayerVariant { - using FlingerLayerType = sp<BufferQueueLayer>; + using FlingerLayerType = sp<BufferStateLayer>; static FlingerLayerType createLayer(CompositionTest*) { return FlingerLayerType(); } static void injectLayer(CompositionTest*, FlingerLayerType) {} @@ -932,17 +900,17 @@ struct EffectLayerVariant : public BaseLayerVariant<LayerProperties> { template <typename LayerProperties> struct BufferLayerVariant : public BaseLayerVariant<LayerProperties> { using Base = BaseLayerVariant<LayerProperties>; - using FlingerLayerType = sp<BufferQueueLayer>; + using FlingerLayerType = sp<BufferStateLayer>; static FlingerLayerType createLayer(CompositionTest* test) { test->mFlinger.mutableTexturePool().push_back(DEFAULT_TEXTURE_ID); FlingerLayerType layer = - Base::template createLayerWithFactory<BufferQueueLayer>(test, [test]() { + Base::template createLayerWithFactory<BufferStateLayer>(test, [test]() { LayerCreationArgs args(test->mFlinger.flinger(), sp<Client>(), "test-layer", LayerProperties::LAYER_FLAGS, LayerMetadata()); args.textureName = test->mFlinger.mutableTexturePool().back(); - return new BufferQueueLayer(args); + return new BufferStateLayer(args); }); LayerProperties::setupLayerState(test, layer); diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index c033af8645..7ee04b0466 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -72,7 +72,7 @@ protected: public: MockEventThreadConnection(impl::EventThread* eventThread, uid_t callingUid, ResyncCallback&& resyncCallback, - ISurfaceComposer::EventRegistrationFlags eventRegistration) + EventRegistrationFlags eventRegistration) : EventThreadConnection(eventThread, callingUid, std::move(resyncCallback), eventRegistration) {} MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event)); @@ -85,10 +85,9 @@ protected: ~EventThreadTest() override; void createThread(std::unique_ptr<VSyncSource>); - sp<MockEventThreadConnection> createConnection( - ConnectionEventRecorder& recorder, - ISurfaceComposer::EventRegistrationFlags eventRegistration = {}, - uid_t ownerUid = mConnectionUid); + sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder, + EventRegistrationFlags eventRegistration = {}, + uid_t ownerUid = mConnectionUid); void expectVSyncSetEnabledCallReceived(bool expectedState); void expectVSyncSetDurationCallReceived(std::chrono::nanoseconds expectedDuration, @@ -149,11 +148,12 @@ EventThreadTest::EventThreadTest() { .WillRepeatedly(Invoke(mVSyncSetDurationCallRecorder.getInvocable())); createThread(std::move(vsyncSource)); - mConnection = createConnection(mConnectionEventCallRecorder, - ISurfaceComposer::EventRegistration::modeChanged | - ISurfaceComposer::EventRegistration::frameRateOverride); + mConnection = + createConnection(mConnectionEventCallRecorder, + gui::ISurfaceComposer::EventRegistration::modeChanged | + gui::ISurfaceComposer::EventRegistration::frameRateOverride); mThrottledConnection = createConnection(mThrottledConnectionEventCallRecorder, - ISurfaceComposer::EventRegistration::modeChanged, + gui::ISurfaceComposer::EventRegistration::modeChanged, mThrottledConnectionUid); // A display must be connected for VSYNC events to be delivered. @@ -190,8 +190,8 @@ void EventThreadTest::createThread(std::unique_ptr<VSyncSource> source) { } sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection( - ConnectionEventRecorder& recorder, - ISurfaceComposer::EventRegistrationFlags eventRegistration, uid_t ownerUid) { + ConnectionEventRecorder& recorder, EventRegistrationFlags eventRegistration, + uid_t ownerUid) { sp<MockEventThreadConnection> connection = new MockEventThreadConnection(mThread.get(), ownerUid, mResyncCallRecorder.getInvocable(), eventRegistration); diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp index bb1f4328b5..3a9b805861 100644 --- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp +++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp @@ -24,7 +24,6 @@ #include <gtest/gtest.h> #include <gui/LayerMetadata.h> -#include "BufferQueueLayer.h" #include "BufferStateLayer.h" #include "EffectLayer.h" #include "FpsReporter.h" @@ -51,6 +50,7 @@ using android::Hwc2::IComposer; using android::Hwc2::IComposerClient; using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; +using gui::LayerMetadata; struct TestableFpsListener : public gui::BnFpsListener { TestableFpsListener() {} @@ -153,7 +153,7 @@ TEST_F(FpsReporterTest, callsListeners) { mParent = createBufferStateLayer(); constexpr int32_t kTaskId = 12; LayerMetadata targetMetadata; - targetMetadata.setInt32(METADATA_TASK_ID, kTaskId); + targetMetadata.setInt32(gui::METADATA_TASK_ID, kTaskId); mTarget = createBufferStateLayer(targetMetadata); mChild = createBufferStateLayer(); mGrandChild = createBufferStateLayer(); @@ -188,7 +188,7 @@ TEST_F(FpsReporterTest, callsListeners) { TEST_F(FpsReporterTest, rateLimits) { const constexpr int32_t kTaskId = 12; LayerMetadata targetMetadata; - targetMetadata.setInt32(METADATA_TASK_ID, kTaskId); + targetMetadata.setInt32(gui::METADATA_TASK_ID, kTaskId); mTarget = createBufferStateLayer(targetMetadata); mFlinger.mutableCurrentState().layersSortedByZ.add(mTarget); diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp index f1efa9286d..756db8a1d1 100644 --- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp @@ -217,9 +217,12 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_noToken) { TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); flushTokens(); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = token1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, - sLayerIdOne, sLayerNameOne, sLayerNameOne, + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Expired); @@ -227,9 +230,12 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) { TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validToken) { int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = token1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, - sLayerIdOne, sLayerNameOne, sLayerNameOne, + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); EXPECT_EQ(surfaceFrame->getPredictionState(), PredictionState::Valid); @@ -239,9 +245,12 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validToken) { TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validInputEventId) { int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); constexpr int32_t inputEventId = 1; + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = token1; + ftInfo.inputEventId = inputEventId; auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({token1, inputEventId}, sPidOne, sUidOne, - sLayerIdOne, sLayerNameOne, sLayerNameOne, + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); EXPECT_EQ(inputEventId, surfaceFrame->getInputEventId()); @@ -250,9 +259,12 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_validInputEventId) { TEST_F(FrameTimelineTest, presentFenceSignaled_droppedFramesNotUpdated) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = token1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, - sLayerIdOne, sLayerNameOne, sLayerNameOne, + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); // Set up the display frame @@ -278,14 +290,17 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_presentedFramesUpdated) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdTwo, sLayerNameTwo, - sLayerNameTwo, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdTwo, + sLayerNameTwo, sLayerNameTwo, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); @@ -324,9 +339,11 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { {10 + frameTimeFactor, 20 + frameTimeFactor, 30 + frameTimeFactor}); int64_t sfToken = mTokenManager->generateTokenForPredictions( {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, - sPidOne, sUidOne, sLayerIdOne, + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11)); @@ -347,10 +364,13 @@ TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) { {10 + frameTimeFactor, 20 + frameTimeFactor, 30 + frameTimeFactor}); int64_t sfToken = mTokenManager->generateTokenForPredictions( {22 + frameTimeFactor, 26 + frameTimeFactor, 30 + frameTimeFactor}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -442,11 +462,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_invalidSignalTime) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -470,11 +493,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_doesNotReportForInvalidTokens) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = -1; int64_t sfToken1 = -1; + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -495,11 +521,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -521,11 +550,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfGpu) { auto gpuFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setAcquireFenceTime(20); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -546,11 +578,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); surfaceFrame1->setAcquireFenceTime(20); @@ -570,11 +605,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(45); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -596,11 +634,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({40, 60, 92}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(50); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -622,11 +663,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -648,11 +692,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 58}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken1, 82, refreshRate); @@ -676,11 +723,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(45); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); @@ -706,11 +756,14 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_displayFramePredictionExpiredPres auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(45); // Trigger a prediction expiry flushTokens(); @@ -744,9 +797,12 @@ TEST_F(FrameTimelineTest, tracing_noPacketsSentWithoutTraceStart) { auto tracingSession = getTracingSessionForTest(); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = token1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, - sLayerIdOne, sLayerNameOne, sLayerNameOne, + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); // Set up the display frame @@ -771,9 +827,12 @@ TEST_F(FrameTimelineTest, tracing_sanityTest) { tracingSession->StartBlocking(); int64_t token1 = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t token2 = mTokenManager->generateTokenForPredictions({40, 50, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = token1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, - sLayerIdOne, sLayerNameOne, sLayerNameOne, + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, /*isBuffer*/ true, sGameMode); // Set up the display frame @@ -1133,14 +1192,18 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_emitsValidTracePacket) { int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 25, 40}); int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({30, 35, 40}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken; + ftInfo.inputEventId = sInputEventId; + auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setActualQueueTime(10); surfaceFrame1->setDropTime(15); @@ -1293,10 +1356,13 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredIsAppMissedDeadline // Flush the token so that it would expire flushTokens(); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken; + ftInfo.inputEventId = 0; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0}, - sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setActualQueueTime(appEndTime); surfaceFrame1->setAcquireFenceTime(appEndTime); @@ -1369,10 +1435,13 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDroppedFramesTraced // Flush the token so that it would expire flushTokens(); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken; + ftInfo.inputEventId = 0; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0}, - sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); constexpr nsecs_t sfStartTime = std::chrono::nanoseconds(22ms).count(); constexpr nsecs_t sfEndTime = std::chrono::nanoseconds(30ms).count(); @@ -1438,10 +1507,13 @@ TEST_F(FrameTimelineTest, jankClassification_presentOnTimeDoesNotClassify) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 20, 30}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 30, 30}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame); @@ -1654,10 +1726,13 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70}); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(16); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1674,10 +1749,13 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = surfaceFrameToken2; + ftInfo2.inputEventId = sInputEventId; auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo2, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(36); mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1734,10 +1812,13 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70}); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(16); mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1754,10 +1835,13 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = surfaceFrameToken2; + ftInfo2.inputEventId = sInputEventId; auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo2, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(36); mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1813,10 +1897,13 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishEarlyPresent) auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 50, 50}); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 26, 60}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken1, 42, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1857,10 +1944,13 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) int64_t sfToken2 = mTokenManager->generateTokenForPredictions({42, 50, 50}); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 30}); int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 50}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(26); mFrameTimeline->setSfWakeUp(sfToken1, 32, Fps::fromPeriodNsecs(11)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1877,10 +1967,13 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameLateFinishLatePresent) // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = surfaceFrameToken2; + ftInfo2.inputEventId = sInputEventId; auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo2, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(40); mFrameTimeline->setSfWakeUp(sfToken2, 43, Fps::fromPeriodNsecs(11)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1932,10 +2025,13 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({112, 120, 120}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(50); mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -1952,10 +2048,13 @@ TEST_F(FrameTimelineTest, jankClassification_multiJankBufferStuffingAndAppDeadli // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = surfaceFrameToken2; + ftInfo2.inputEventId = sInputEventId; auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo2, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(84); mFrameTimeline->setSfWakeUp(sfToken2, 112, Fps::fromPeriodNsecs(30)); surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54); @@ -2010,10 +2109,13 @@ TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffin int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60}); int64_t sfToken2 = mTokenManager->generateTokenForPredictions({82, 90, 90}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = surfaceFrameToken1; + ftInfo.inputEventId = sInputEventId; auto surfaceFrame1 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame1->setAcquireFenceTime(50); mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30)); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); @@ -2030,10 +2132,13 @@ TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffin // Trigger a flush by finalizing the next DisplayFrame auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = surfaceFrameToken2; + ftInfo2.inputEventId = sInputEventId; auto surfaceFrame2 = - mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne, - sUidOne, sLayerIdOne, sLayerNameOne, - sLayerNameOne, /*isBuffer*/ true, sGameMode); + mFrameTimeline->createSurfaceFrameForToken(ftInfo2, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); surfaceFrame2->setAcquireFenceTime(80); mFrameTimeline->setSfWakeUp(sfToken2, 82, Fps::fromPeriodNsecs(30)); // Setting previous latch time to 54, adjusted deadline will be 54 + vsyncTime(30) = 84 @@ -2237,4 +2342,38 @@ TEST_F(FrameTimelineTest, computeFps_averagesOverMultipleFrames) { EXPECT_EQ(mFrameTimeline->computeFps({sLayerIdOne}), 5.0f); } +TEST_F(FrameTimelineTest, getMinTime) { + // Use SurfaceFrame::getBaseTime to test the getMinTime. + FrameTimelineInfo ftInfo; + + // Valid prediction state test. + ftInfo.vsyncId = 0L; + mTokenManager->generateTokenForPredictions({10}); + auto surfaceFrame = + mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); + ASSERT_EQ(surfaceFrame->getBaseTime(), 10); + + // Test prediction state which is not valid. + ftInfo.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID; + surfaceFrame = mFrameTimeline->createSurfaceFrameForToken(ftInfo, sPidOne, sUidOne, sLayerIdOne, + sLayerNameOne, sLayerNameOne, + /*isBuffer*/ true, sGameMode); + // Start time test. + surfaceFrame->setActualStartTime(200); + ASSERT_EQ(surfaceFrame->getBaseTime(), 200); + + // End time test. + surfaceFrame->setAcquireFenceTime(100); + ASSERT_EQ(surfaceFrame->getBaseTime(), 100); + + // Present time test. + auto presentFence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); + surfaceFrame->setPresentState(SurfaceFrame::PresentState::Presented); + mFrameTimeline->addSurfaceFrame(surfaceFrame); + presentFence->signalForTest(std::chrono::nanoseconds(50ns).count()); + mFrameTimeline->setSfPresent(50, presentFence); + ASSERT_EQ(surfaceFrame->getBaseTime(), 50); +} } // namespace android::frametimeline diff --git a/services/surfaceflinger/tests/unittests/GameModeTest.cpp b/services/surfaceflinger/tests/unittests/GameModeTest.cpp index 981ca1d227..b79909ad9d 100644 --- a/services/surfaceflinger/tests/unittests/GameModeTest.cpp +++ b/services/surfaceflinger/tests/unittests/GameModeTest.cpp @@ -34,6 +34,8 @@ using testing::_; using testing::Mock; using testing::Return; using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; +using gui::GameMode; +using gui::LayerMetadata; class GameModeTest : public testing::Test { public: @@ -92,7 +94,7 @@ public: // Mocks the behavior of applying a transaction from WMShell void setGameModeMetadata(sp<Layer> layer, GameMode gameMode) { - mLayerMetadata.setInt32(METADATA_GAME_MODE, static_cast<int32_t>(gameMode)); + mLayerMetadata.setInt32(gui::METADATA_GAME_MODE, static_cast<int32_t>(gameMode)); layer->setMetadata(mLayerMetadata); layer->setGameModeForTree(gameMode); } diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 17511cd615..972198cbdb 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -141,6 +141,54 @@ protected: namespace { +TEST_F(LayerHistoryTest, singleLayerNoVoteDefaultCompatibility) { + const auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getDefaultFrameRateCompatibility()) + .WillOnce(Return(LayerInfo::FrameRateCompatibility::NoVote)); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + + // No layers returned if no layers are active. + EXPECT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(0, activeLayerCount()); + + history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer); + history().setDefaultFrameRateCompatibility(layer.get(), true /* contentDetectionEnabled */); + + EXPECT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(1, activeLayerCount()); +} + +TEST_F(LayerHistoryTest, singleLayerMinVoteDefaultCompatibility) { + const auto layer = createLayer(); + EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); + EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); + EXPECT_CALL(*layer, getDefaultFrameRateCompatibility()) + .WillOnce(Return(LayerInfo::FrameRateCompatibility::Min)); + + EXPECT_EQ(1, layerCount()); + EXPECT_EQ(0, activeLayerCount()); + + nsecs_t time = systemTime(); + + EXPECT_TRUE(summarizeLayerHistory(time).empty()); + EXPECT_EQ(0, activeLayerCount()); + + history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer); + history().setDefaultFrameRateCompatibility(layer.get(), true /* contentDetectionEnabled */); + + auto summary = summarizeLayerHistory(time); + ASSERT_EQ(1, summarizeLayerHistory(time).size()); + + EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); + EXPECT_EQ(1, activeLayerCount()); +} + TEST_F(LayerHistoryTest, oneLayer) { const auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); diff --git a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp index 373fd74020..e6e02c1806 100644 --- a/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerMetadataTest.cpp @@ -27,6 +27,8 @@ #include <gui/LayerMetadata.h> #include <log/log.h> +using android::gui::LayerMetadata; + namespace android { namespace { @@ -113,4 +115,4 @@ TEST_F(LayerMetadataTest, merge) { } // namespace android // TODO(b/129481165): remove the #pragma below and fix conversion issues -#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file +#pragma clang diagnostic pop // ignored "-Wextra" diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp index 37cf05ef64..3d576f4450 100644 --- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp @@ -85,12 +85,6 @@ TEST_F(OnInitializeDisplaysTest, onInitializeDisplaysSetsUpPrimaryDisplay) { // The display transaction needed flag should be set. EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded)); - - // The compositor timing should be set to default values - const auto& compositorTiming = mFlinger.getCompositorTiming(); - EXPECT_EQ(-DEFAULT_VSYNC_PERIOD, compositorTiming.deadline); - EXPECT_EQ(DEFAULT_VSYNC_PERIOD, compositorTiming.interval); - EXPECT_EQ(DEFAULT_VSYNC_PERIOD, compositorTiming.presentLatency); } } // namespace diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index b70fdcd93e..60285f98f4 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -29,7 +29,6 @@ #include <compositionengine/mock/DisplaySurface.h> #include <gui/ScreenCaptureResults.h> -#include "BufferQueueLayer.h" #include "BufferStateLayer.h" #include "ContainerLayer.h" #include "DisplayDevice.h" @@ -112,18 +111,6 @@ public: mCreateBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger); } - sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>& producer, - const sp<SurfaceFlinger>& flinger, - const wp<Layer>& layer) override { - return new MonitoredProducer(producer, flinger, layer); - } - - sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>& consumer, - renderengine::RenderEngine& renderEngine, - uint32_t textureName, Layer* layer) override { - return new BufferLayerConsumer(consumer, renderEngine, textureName, layer); - } - std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface( const sp<IGraphicBufferProducer>& producer) override { if (!mCreateNativeWindowSurface) return nullptr; @@ -134,10 +121,6 @@ public: return compositionengine::impl::createCompositionEngine(); } - sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override { - return nullptr; - } - sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs&) override { return nullptr; } @@ -460,7 +443,7 @@ public: return mFlinger->onTransact(code, data, reply, flags); } - auto getGPUContextPriority() { return mFlinger->getGPUContextPriority(); } + auto getGpuContextPriority() { return mFlinger->getGpuContextPriority(); } auto calculateMaxAcquiredBufferCount(Fps refreshRate, std::chrono::nanoseconds presentLatency) const { @@ -506,8 +489,6 @@ public: } auto& getCompositionEngine() const { return mFlinger->getCompositionEngine(); } - const auto& getCompositorTiming() const { return mFlinger->getBE().mCompositorTiming; } - mock::FrameTracer* getFrameTracer() const { return static_cast<mock::FrameTracer*>(mFlinger->mFrameTracer.get()); } diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index ded75318ed..84f11704d0 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -107,22 +107,20 @@ public: EXPECT_EQ(info.desiredPresentTime, state.desiredPresentTime); } - void setupSingle(TransactionInfo& transaction, uint32_t flags, bool syncInputWindows, - int64_t desiredPresentTime, bool isAutoTimestamp, - const FrameTimelineInfo& frameTimelineInfo) { + void setupSingle(TransactionInfo& transaction, uint32_t flags, int64_t desiredPresentTime, + bool isAutoTimestamp, const FrameTimelineInfo& frameTimelineInfo) { mTransactionNumber++; transaction.flags |= flags; // ISurfaceComposer::eSynchronous; - transaction.inputWindowCommands.syncInputWindows = syncInputWindows; transaction.desiredPresentTime = desiredPresentTime; transaction.isAutoTimestamp = isAutoTimestamp; transaction.frameTimelineInfo = frameTimelineInfo; } - void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) { + void NotPlacedOnTransactionQueue(uint32_t flags) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); TransactionInfo transaction; - setupSingle(transaction, flags, syncInputWindows, + setupSingle(transaction, flags, /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, FrameTimelineInfo{}); nsecs_t applicationTime = systemTime(); @@ -133,12 +131,10 @@ public: transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks, transaction.id); - // If transaction is synchronous or syncs input windows, SF - // applyTransactionState should time out (5s) wating for SF to commit - // the transaction or to receive a signal that syncInputWindows has - // completed. If this is animation, it should not time out waiting. + // If transaction is synchronous, SF applyTransactionState should time out (5s) wating for + // SF to commit the transaction. If this is animation, it should not time out waiting. nsecs_t returnedTime = systemTime(); - if (flags & ISurfaceComposer::eSynchronous || syncInputWindows) { + if (flags & ISurfaceComposer::eSynchronous) { EXPECT_GE(returnedTime, applicationTime + mFlinger.getAnimationTransactionTimeout()); } else { EXPECT_LE(returnedTime, applicationTime + mFlinger.getAnimationTransactionTimeout()); @@ -148,7 +144,7 @@ public: EXPECT_EQ(1u, transactionQueue.size()); } - void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) { + void PlaceOnTransactionQueue(uint32_t flags) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); @@ -156,8 +152,8 @@ public: // but afterwards it will look like the desired present time has passed nsecs_t time = systemTime(); TransactionInfo transaction; - setupSingle(transaction, flags, syncInputWindows, - /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{}); + setupSingle(transaction, flags, /*desiredPresentTime*/ time + s2ns(1), false, + FrameTimelineInfo{}); nsecs_t applicationSentTime = systemTime(); mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, transaction.displays, transaction.flags, @@ -167,7 +163,7 @@ public: transaction.id); nsecs_t returnedTime = systemTime(); - if ((flags & ISurfaceComposer::eSynchronous) || syncInputWindows) { + if (flags & ISurfaceComposer::eSynchronous) { EXPECT_GE(systemTime(), applicationSentTime + mFlinger.getAnimationTransactionTimeout()); } else { @@ -179,25 +175,21 @@ public: EXPECT_EQ(1u, transactionQueue.size()); } - void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) { + void BlockedByPriorTransaction(uint32_t flags) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); nsecs_t time = systemTime(); - if (!syncInputWindows) { - EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(2); - } else { - EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); - } + EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(2); + // transaction that should go on the pending thread TransactionInfo transactionA; - setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, - /*desiredPresentTime*/ time + s2ns(1), false, FrameTimelineInfo{}); + setupSingle(transactionA, /*flags*/ 0, /*desiredPresentTime*/ time + s2ns(1), false, + FrameTimelineInfo{}); // transaction that would not have gone on the pending thread if not // blocked TransactionInfo transactionB; - setupSingle(transactionB, flags, syncInputWindows, - /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, - FrameTimelineInfo{}); + setupSingle(transactionB, flags, /*desiredPresentTime*/ systemTime(), + /*isAutoTimestamp*/ true, FrameTimelineInfo{}); nsecs_t applicationSentTime = systemTime(); mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, @@ -226,8 +218,7 @@ public: // if this is an animation, this thread should be blocked for 5s // in setTransactionState waiting for transactionA to flush. Otherwise, // the transaction should be placed on the pending queue - if (flags & (ISurfaceComposer::eSynchronous) || - syncInputWindows) { + if (flags & ISurfaceComposer::eSynchronous) { EXPECT_GE(systemTime(), applicationSentTime + mFlinger.getAnimationTransactionTimeout()); } else { @@ -253,8 +244,8 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { EXPECT_CALL(*mFlinger.scheduler(), scheduleFrame()).Times(1); TransactionInfo transactionA; // transaction to go on pending queue - setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false, - /*desiredPresentTime*/ s2ns(1), false, FrameTimelineInfo{}); + setupSingle(transactionA, /*flags*/ 0, /*desiredPresentTime*/ s2ns(1), false, + FrameTimelineInfo{}); mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, transactionA.displays, transactionA.flags, transactionA.applyToken, transactionA.inputWindowCommands, transactionA.desiredPresentTime, @@ -285,31 +276,23 @@ TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) { } TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) { - NotPlacedOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false); + NotPlacedOnTransactionQueue(ISurfaceComposer::eSynchronous); } TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_SyncInputWindows) { - NotPlacedOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true); + NotPlacedOnTransactionQueue(/*flags*/ 0); } TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Synchronous) { - PlaceOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false); + PlaceOnTransactionQueue(ISurfaceComposer::eSynchronous); } TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_SyncInputWindows) { - PlaceOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true); + PlaceOnTransactionQueue(/*flags*/ 0); } TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Synchronous) { - BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false); -} - -TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Animation) { - BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false); -} - -TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_SyncInputWindows) { - BlockedByPriorTransaction(/*flags*/ 0, /*syncInputWindows*/ true); + BlockedByPriorTransaction(ISurfaceComposer::eSynchronous); } TEST_F(TransactionApplicationTest, FromHandle) { @@ -359,13 +342,11 @@ public: const std::vector<ComposerState>& states) { TransactionInfo transaction; const uint32_t kFlags = ISurfaceComposer::eSynchronous; - const bool kSyncInputWindows = false; const nsecs_t kDesiredPresentTime = systemTime(); const bool kIsAutoTimestamp = true; const auto kFrameTimelineInfo = FrameTimelineInfo{}; - setupSingle(transaction, kFlags, kSyncInputWindows, kDesiredPresentTime, kIsAutoTimestamp, - kFrameTimelineInfo); + setupSingle(transaction, kFlags, kDesiredPresentTime, kIsAutoTimestamp, kFrameTimelineInfo); transaction.applyToken = applyToken; for (const auto& state : states) { transaction.states.push_back(state); diff --git a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp index f5e3b77ca6..669fa3a7f0 100644 --- a/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionProtoParserTest.cpp @@ -49,8 +49,7 @@ TEST(TransactionProtoParserTest, parse) { ComposerState s; if (i == 1) { layer.parentSurfaceControlForChild = - new SurfaceControl(SurfaceComposerClient::getDefault(), layerHandle, nullptr, - 42); + new SurfaceControl(SurfaceComposerClient::getDefault(), layerHandle, 42); } s.state = layer; t1.states.add(s); diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp index 5bb4c92a8e..6d583036fa 100644 --- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp @@ -100,8 +100,10 @@ public: void PresentedSurfaceFrameForBufferlessTransaction() { sp<BufferStateLayer> layer = createBufferStateLayer(); - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, - 10); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo, 10); EXPECT_EQ(1u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_TRUE(layer->mDrawingState.bufferSurfaceFrameTX == nullptr); const auto surfaceFrame = layer->mDrawingState.bufferlessSurfaceFramesTX.at(/*token*/ 1); @@ -125,8 +127,10 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo); acquireFence->signalForTest(12); commitTransaction(layer.get()); @@ -159,8 +163,10 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, ftInfo); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX; @@ -177,8 +183,7 @@ public: 2ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, ftInfo); nsecs_t end = systemTime(); acquireFence2->signalForTest(12); @@ -204,9 +209,11 @@ public: void BufferlessSurfaceFramePromotedToBufferSurfaceFrame() { sp<BufferStateLayer> layer = createBufferStateLayer(); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, - 10); + layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo, 10); EXPECT_EQ(1u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_EQ(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); @@ -223,8 +230,7 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo); acquireFence->signalForTest(12); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); @@ -257,28 +263,33 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, - 10); + layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo, 10); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); } void MultipleSurfaceFramesPresentedTogether() { sp<BufferStateLayer> layer = createBufferStateLayer(); - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0}, - 10); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo, 10); EXPECT_EQ(1u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_EQ(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto bufferlessSurfaceFrame1 = layer->mDrawingState.bufferlessSurfaceFramesTX.at(/*token*/ 1); - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 4, /*inputEventId*/ 0}, - 10); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = 4; + ftInfo2.inputEventId = 0; + layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo2, 10); EXPECT_EQ(2u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_EQ(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto bufferlessSurfaceFrame2 = layer->mDrawingState.bufferlessSurfaceFramesTX[4]; @@ -295,8 +306,10 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 3, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfo3; + ftInfo3.vsyncId = 3; + ftInfo3.inputEventId = 0; + layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo3); EXPECT_EQ(2u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto bufferSurfaceFrameTX = layer->mDrawingState.bufferSurfaceFrameTX; @@ -339,8 +352,10 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, ftInfo); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame = layer->mDrawingState.bufferSurfaceFrameTX; @@ -355,8 +370,7 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, ftInfo); acquireFence2->signalForTest(12); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); @@ -391,8 +405,10 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setBuffer(externalTexture1, bufferData, 10, 20, false, std::nullopt, ftInfo); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); const auto droppedSurfaceFrame1 = layer->mDrawingState.bufferSurfaceFrameTX; @@ -409,8 +425,10 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ FrameTimelineInfo::INVALID_VSYNC_ID, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfoInv; + ftInfoInv.vsyncId = FrameTimelineInfo::INVALID_VSYNC_ID; + ftInfoInv.inputEventId = 0; + layer->setBuffer(externalTexture2, bufferData, 10, 20, false, std::nullopt, ftInfoInv); auto dropEndTime1 = systemTime(); EXPECT_EQ(0u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); @@ -428,8 +446,10 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture3, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 2, /*inputEventId*/ 0}); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = 2; + ftInfo2.inputEventId = 0; + layer->setBuffer(externalTexture3, bufferData, 10, 20, false, std::nullopt, ftInfo2); auto dropEndTime2 = systemTime(); acquireFence3->signalForTest(12); @@ -476,11 +496,14 @@ public: 1ULL /* bufferId */, HAL_PIXEL_FORMAT_RGBA_8888, 0ULL /*usage*/); - layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, - {/*vsyncId*/ 1, /*inputEventId*/ 0}); - layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2, - /*inputEventId*/ 0}, - 10); + FrameTimelineInfo ftInfo; + ftInfo.vsyncId = 1; + ftInfo.inputEventId = 0; + layer->setBuffer(externalTexture, bufferData, 10, 20, false, std::nullopt, ftInfo); + FrameTimelineInfo ftInfo2; + ftInfo2.vsyncId = 2; + ftInfo2.inputEventId = 0; + layer->setFrameTimelineVsyncForBufferlessTransaction(ftInfo2, 10); ASSERT_NE(nullptr, layer->mDrawingState.bufferSurfaceFrameTX); EXPECT_EQ(1u, layer->mDrawingState.bufferlessSurfaceFramesTX.size()); auto& bufferlessSurfaceFrame = diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp index 61b72a0b9b..8ec918dfb3 100644 --- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp @@ -127,6 +127,8 @@ protected: std::vector<TransactionState> transactions; transactions.emplace_back(transaction); VSYNC_ID_FIRST_LAYER_CHANGE = ++mVsyncId; + mTracing.onLayerAddedToDrawingState(mParentLayerId, VSYNC_ID_FIRST_LAYER_CHANGE); + mTracing.onLayerAddedToDrawingState(mChildLayerId, VSYNC_ID_FIRST_LAYER_CHANGE); mTracing.addCommittedTransactions(transactions, VSYNC_ID_FIRST_LAYER_CHANGE); flush(VSYNC_ID_FIRST_LAYER_CHANGE); } @@ -238,6 +240,8 @@ protected: const sp<IBinder> fakeMirrorLayerHandle = new BBinder(); mTracing.onMirrorLayerAdded(fakeMirrorLayerHandle->localBinder(), mMirrorLayerId, "Mirror", mLayerId); + mTracing.onLayerAddedToDrawingState(mLayerId, mVsyncId); + mTracing.onLayerAddedToDrawingState(mMirrorLayerId, mVsyncId); // add some layer transaction { @@ -257,7 +261,7 @@ protected: std::vector<TransactionState> transactions; transactions.emplace_back(transaction); - mTracing.addCommittedTransactions(transactions, ++mVsyncId); + mTracing.addCommittedTransactions(transactions, mVsyncId); flush(mVsyncId); } } diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h index c5ca86a651..d30dc42cbb 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h +++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h @@ -28,8 +28,7 @@ public: ~EventThread() override; MOCK_CONST_METHOD2(createEventConnection, - sp<EventThreadConnection>(ResyncCallback, - ISurfaceComposer::EventRegistrationFlags)); + sp<EventThreadConnection>(ResyncCallback, EventRegistrationFlags)); MOCK_METHOD0(onScreenReleased, void()); MOCK_METHOD0(onScreenAcquired, void()); MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool)); diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h index 0840a2f77c..d086d79834 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockLayer.h +++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h @@ -25,7 +25,10 @@ namespace android::mock { class MockLayer : public Layer { public: MockLayer(SurfaceFlinger* flinger, std::string name) - : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) {} + : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 0, {})) { + EXPECT_CALL(*this, getDefaultFrameRateCompatibility()) + .WillOnce(testing::Return(scheduler::LayerInfo::FrameRateCompatibility::Default)); + } explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {} MOCK_CONST_METHOD0(getType, const char*()); @@ -33,6 +36,8 @@ public: MOCK_CONST_METHOD0(isVisible, bool()); MOCK_METHOD0(createClone, sp<Layer>()); MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate()); + MOCK_CONST_METHOD0(getDefaultFrameRateCompatibility, + scheduler::LayerInfo::FrameRateCompatibility()); MOCK_CONST_METHOD0(getOwnerUid, uid_t()); MOCK_CONST_METHOD0(getDataSpace, ui::Dataspace()); }; diff --git a/services/surfaceflinger/tests/utils/ColorUtils.h b/services/surfaceflinger/tests/utils/ColorUtils.h index 07916b60a7..38c422a26d 100644 --- a/services/surfaceflinger/tests/utils/ColorUtils.h +++ b/services/surfaceflinger/tests/utils/ColorUtils.h @@ -33,6 +33,10 @@ struct Color { static const Color WHITE; static const Color BLACK; static const Color TRANSPARENT; + + half3 toHalf3() { return half3{r / 255.0f, g / 255.0f, b / 255.0f}; } + + half4 toHalf4() { return half4{r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f}; } }; const Color Color::RED{255, 0, 0, 255}; @@ -81,6 +85,14 @@ public: } color = ret; } + + static half3 toHalf3(const Color& color) { + return half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f}; + } + + static half4 toHalf4(const Color& color) { + return half4{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f, color.a / 255.0f}; + } }; } // namespace } // namespace android diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h index f879430db0..6ada54954a 100644 --- a/services/surfaceflinger/tests/utils/ScreenshotUtils.h +++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h @@ -15,6 +15,7 @@ */ #pragma once +#include <gui/AidlStatusUtil.h> #include <gui/SyncScreenCaptureListener.h> #include <private/gui/ComposerServiceAIDL.h> #include <ui/Rect.h> @@ -24,6 +25,8 @@ namespace android { +using gui::aidl_utils::statusTFromBinderStatus; + namespace { // A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check @@ -38,9 +41,9 @@ public: captureArgs.dataspace = ui::Dataspace::V0_SRGB; const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); binder::Status status = sf->captureDisplay(captureArgs, captureListener); - - if (status.transactionError() != NO_ERROR) { - return status.transactionError(); + status_t err = statusTFromBinderStatus(status); + if (err != NO_ERROR) { + return err; } captureResults = captureListener->waitForResults(); return captureResults.result; @@ -72,8 +75,9 @@ public: captureArgs.dataspace = ui::Dataspace::V0_SRGB; const sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener(); binder::Status status = sf->captureLayers(captureArgs, captureListener); - if (status.transactionError() != NO_ERROR) { - return status.transactionError(); + status_t err = statusTFromBinderStatus(status); + if (err != NO_ERROR) { + return err; } captureResults = captureListener->waitForResults(); return captureResults.result; diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp index b44c60ef60..8e46442fd6 100644 --- a/vulkan/libvulkan/swapchain.cpp +++ b/vulkan/libvulkan/swapchain.cpp @@ -1854,6 +1854,11 @@ VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) { if (swapchain_result != VK_SUCCESS) { OrphanSwapchain(device, &swapchain); } + // Android will only return VK_SUBOPTIMAL_KHR for vkQueuePresentKHR, + // and only when the window's transform/rotation changes. Extent + // changes will not cause VK_SUBOPTIMAL_KHR because of the + // application issues that were caused when the following transform + // change was added. int window_transform_hint; err = window->query(window, NATIVE_WINDOW_TRANSFORM_HINT, &window_transform_hint); |