diff options
56 files changed, 774 insertions, 246 deletions
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index a447cda492..822ab7fbb7 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -437,6 +437,9 @@ private: maybe_open_reference_profile(parameters_.pkgName, parameters_.apk_path, parameters_.profile_name, profile_guided, is_public, parameters_.uid, is_secondary_dex); + // `maybe_open_reference_profile` installs a hook that clears the profile on + // destruction. Disable it. + reference_profile.DisableCleanup(); struct stat sbuf; if (reference_profile.fd() == -1 || (fstat(reference_profile.fd(), &sbuf) != -1 && sbuf.st_size == 0)) { diff --git a/include/android/bitmap.h b/include/android/bitmap.h index 35f87f96ae..87a14c021d 100644 --- a/include/android/bitmap.h +++ b/include/android/bitmap.h @@ -196,7 +196,7 @@ enum AndroidBitmapCompressFormat { * * @param userContext Pointer to user-defined data passed to * {@link AndroidBitmap_compress}. - * @param data Compressed data of |size| bytes to write. + * @param data Compressed data of `size` bytes to write. * @param size Length in bytes of data to write. * @return Whether the operation succeeded. */ @@ -205,7 +205,7 @@ typedef bool (*AndroidBitmap_CompressWriteFunc)(void* userContext, size_t size) __INTRODUCED_IN(30); /** - * Compress |pixels| as described by |info|. + * Compress `pixels` as described by `info`. * * Available since API level 30. * diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h index e0a8045d41..645fa8a5e7 100644 --- a/include/android/sharedmem.h +++ b/include/android/sharedmem.h @@ -53,7 +53,7 @@ extern "C" { /** * Create a shared memory region. * - * Create shared memory region and returns an file descriptor. The resulting file descriptor can be + * Create shared memory region and returns a file descriptor. The resulting file descriptor can be * mmap'ed to process memory space with PROT_READ | PROT_WRITE | PROT_EXEC. Access to shared memory * region can be restricted with {@link ASharedMemory_setProt}. * @@ -65,7 +65,7 @@ extern "C" { * cmsg(3) man pages for more information. * * If you intend to share this file descriptor with a child process after - * calling exec(3), note that you will need to use fcntl(2) with FD_SETFD + * calling exec(3), note that you will need to use fcntl(2) with F_SETFD * to clear the FD_CLOEXEC flag for this to work on all versions of Android. * * Available since API level 26. diff --git a/include/android/thermal.h b/include/android/thermal.h index 32580badc0..1f477f8233 100644 --- a/include/android/thermal.h +++ b/include/android/thermal.h @@ -188,13 +188,13 @@ int AThermal_unregisterThermalStatusListener(AThermalManager *manager, * Note that this only attempts to track the headroom of slow-moving sensors, such as * the skin temperature sensor. This means that there is no benefit to calling this function * more frequently than about once per second, and attempted to call significantly - * more frequently may result in the function returning {@code NaN}. + * more frequently may result in the function returning `NaN`. * * In addition, in order to be able to provide an accurate forecast, the system does * not attempt to forecast until it has multiple temperature samples from which to * extrapolate. This should only take a few seconds from the time of the first call, * but during this time, no forecasting will occur, and the current headroom will be - * returned regardless of the value of {@code forecastSeconds}. + * returned regardless of the value of `forecastSeconds`. * * The value returned is a non-negative float that represents how much of the thermal envelope * is in use (or is forecasted to be in use). A value of 1.0 indicates that the device is diff --git a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp index 25b8e975b3..3724fa100a 100644 --- a/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp +++ b/libs/binder/ndk/tests/libbinder_ndk_unit_test.cpp @@ -433,20 +433,21 @@ TEST(NdkBinder, GetLazyService) { EXPECT_EQ(STATUS_OK, AIBinder_ping(binder.get())); } -TEST(NdkBinder, IsUpdatable) { - bool isUpdatable = AServiceManager_isUpdatableViaApex("android.hardware.light.ILights/default"); - EXPECT_EQ(isUpdatable, false); -} - -TEST(NdkBinder, GetUpdatableViaApex) { - std::optional<std::string> updatableViaApex; - AServiceManager_getUpdatableApexName( - "android.hardware.light.ILights/default", &updatableViaApex, - [](const char* apexName, void* context) { - *static_cast<std::optional<std::string>*>(context) = apexName; - }); - EXPECT_EQ(updatableViaApex, std::nullopt) << *updatableViaApex; -} +// TEST(NdkBinder, IsUpdatable) { +// bool isUpdatable = +// AServiceManager_isUpdatableViaApex("android.hardware.light.ILights/default"); +// EXPECT_EQ(isUpdatable, true); +// } +// +// TEST(NdkBinder, GetUpdatableViaApex) { +// std::optional<std::string> updatableViaApex; +// AServiceManager_getUpdatableApexName( +// "android.hardware.light.ILights/default", &updatableViaApex, +// [](const char* apexName, void* context) { +// *static_cast<std::optional<std::string>*>(context) = apexName; +// }); +// EXPECT_NE(updatableViaApex, std::nullopt) << *updatableViaApex; +// } // This is too slow TEST(NdkBinder, CheckLazyServiceShutDown) { diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp index 2ea4d16260..9a27d2321b 100644 --- a/libs/gui/Android.bp +++ b/libs/gui/Android.bp @@ -204,27 +204,8 @@ cc_aconfig_library { aconfig_declarations: "libgui_flags", } -cc_library_shared { - name: "libgui", - vendor_available: true, - vndk: { - enabled: true, - private: true, - }, - double_loadable: true, - - defaults: ["libgui_bufferqueue-defaults"], - - static_libs: [ - "libgui_aidl_static", - "libgui_window_info_static", - "libguiflags", - ], - export_static_lib_headers: [ - "libgui_aidl_static", - "libgui_window_info_static", - ], - +filegroup { + name: "libgui-sources", srcs: [ ":framework_native_aidl_binder", ":framework_native_aidl_gui", @@ -268,11 +249,40 @@ cc_library_shared { "bufferqueue/2.0/B2HProducerListener.cpp", "bufferqueue/2.0/H2BGraphicBufferProducer.cpp", ], +} +cc_defaults { + name: "libgui-defaults", + defaults: ["libgui_bufferqueue-defaults"], + srcs: [":libgui-sources"], + static_libs: [ + "libgui_aidl_static", + "libgui_window_info_static", + "libguiflags", + ], shared_libs: [ "libbinder", "libGLESv2", ], +} + +cc_library_shared { + name: "libgui", + vendor_available: true, + vndk: { + enabled: true, + private: true, + }, + double_loadable: true, + + defaults: [ + "libgui-defaults", + ], + + export_static_lib_headers: [ + "libgui_aidl_static", + "libgui_window_info_static", + ], export_shared_lib_headers: [ "libbinder", @@ -346,6 +356,7 @@ filegroup { "BufferQueueProducer.cpp", "BufferQueueThreadState.cpp", "BufferSlot.cpp", + "FrameRateUtils.cpp", "FrameTimestamps.cpp", "GLConsumerUtils.cpp", "HdrMetadata.cpp", diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp index 207fa4fd31..dd0a028865 100644 --- a/libs/gui/BLASTBufferQueue.cpp +++ b/libs/gui/BLASTBufferQueue.cpp @@ -26,6 +26,8 @@ #include <gui/BufferQueueConsumer.h> #include <gui/BufferQueueCore.h> #include <gui/BufferQueueProducer.h> +#include <gui/Flags.h> +#include <gui/FrameRateUtils.h> #include <gui/GLConsumer.h> #include <gui/IProducerListener.h> #include <gui/Surface.h> @@ -39,6 +41,9 @@ #include <android-base/thread_annotations.h> #include <chrono> +#include <com_android_graphics_libgui_flags.h> + +using namespace com::android::graphics::libgui; using namespace std::chrono_literals; namespace { @@ -139,6 +144,16 @@ void BLASTBufferItemConsumer::onSidebandStreamChanged() { } } +#if FLAG_BQ_SET_FRAME_RATE +void BLASTBufferItemConsumer::onSetFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) { + sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote(); + if (bbq != nullptr) { + bbq->setFrameRate(frameRate, compatibility, changeFrameRateStrategy); + } +} +#endif + void BLASTBufferItemConsumer::resizeFrameEventHistory(size_t newSize) { Mutex::Autolock lock(mMutex); mFrameEventHistory.resize(newSize); @@ -890,6 +905,10 @@ public: status_t setFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy) override { + if (flags::bq_setframerate()) { + return Surface::setFrameRate(frameRate, compatibility, changeFrameRateStrategy); + } + std::lock_guard _lock{mMutex}; if (mDestroyed) { return DEAD_OBJECT; diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp index 66cad03fec..ab0f6d213f 100644 --- a/libs/gui/BufferQueue.cpp +++ b/libs/gui/BufferQueue.cpp @@ -22,6 +22,7 @@ #include <gui/BufferQueueConsumer.h> #include <gui/BufferQueueCore.h> #include <gui/BufferQueueProducer.h> +#include <gui/Flags.h> namespace android { @@ -98,6 +99,16 @@ void BufferQueue::ProxyConsumerListener::addAndGetFrameTimestamps( } } +#if FLAG_BQ_SET_FRAME_RATE +void BufferQueue::ProxyConsumerListener::onSetFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) { + sp<ConsumerListener> listener(mConsumerListener.promote()); + if (listener != nullptr) { + listener->onSetFrameRate(frameRate, compatibility, changeFrameRateStrategy); + } +} +#endif + void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer, sp<IGraphicBufferConsumer>* outConsumer, bool consumerIsSurfaceFlinger) { diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 920b83dba9..67dff6dec6 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -32,6 +32,8 @@ #include <gui/BufferItem.h> #include <gui/BufferQueueCore.h> #include <gui/BufferQueueProducer.h> +#include <gui/Flags.h> +#include <gui/FrameRateUtils.h> #include <gui/GLConsumer.h> #include <gui/IConsumerListener.h> #include <gui/IProducerListener.h> @@ -1751,4 +1753,27 @@ status_t BufferQueueProducer::setAutoPrerotation(bool autoPrerotation) { return NO_ERROR; } +#if FLAG_BQ_SET_FRAME_RATE +status_t BufferQueueProducer::setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) { + ATRACE_CALL(); + BQ_LOGV("setFrameRate: %.2f", frameRate); + + if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy, + "BufferQueueProducer::setFrameRate")) { + return BAD_VALUE; + } + + sp<IConsumerListener> listener; + { + std::lock_guard<std::mutex> lock(mCore->mMutex); + listener = mCore->mConsumerListener; + } + if (listener != nullptr) { + listener->onSetFrameRate(frameRate, compatibility, changeFrameRateStrategy); + } + return NO_ERROR; +} +#endif + } // namespace android diff --git a/libs/gui/FrameRateUtils.cpp b/libs/gui/FrameRateUtils.cpp new file mode 100644 index 0000000000..6993bfab45 --- /dev/null +++ b/libs/gui/FrameRateUtils.cpp @@ -0,0 +1,65 @@ +/* + * Copyright 2023 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 <gui/Flags.h> +#include <gui/FrameRateUtils.h> +#include <system/window.h> +#include <utils/Log.h> + +#include <cmath> + +namespace android { +// Returns true if the frameRate is valid. +// +// @param frameRate the frame rate in Hz +// @param compatibility a ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* +// @param changeFrameRateStrategy a ANATIVEWINDOW_CHANGE_FRAME_RATE_* +// @param functionName calling function or nullptr. Used for logging +// @param privileged whether caller has unscoped surfaceflinger access +bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy, + const char* inFunctionName, bool privileged) { + const char* functionName = inFunctionName != nullptr ? inFunctionName : "call"; + int floatClassification = std::fpclassify(frameRate); + if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) { + ALOGE("%s failed - invalid frame rate %f", functionName, frameRate); + return false; + } + + if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT && + compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE && + (!privileged || + (compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT && + compatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE))) { + ALOGE("%s failed - invalid compatibility value %d privileged: %s", functionName, + compatibility, privileged ? "yes" : "no"); + return false; + } + + if (__builtin_available(android 31, *)) { + if (changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS && + changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS) { + ALOGE("%s failed - invalid change frame rate strategy value %d", functionName, + changeFrameRateStrategy); + if (FLAG_BQ_SET_FRAME_RATE) { + return false; + } + } + } + + return true; +} + +} // namespace android diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index 918ff2dd25..d0c09e481d 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -27,11 +27,12 @@ #include <binder/Parcel.h> #include <binder/IInterface.h> -#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h> -#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h> #include <gui/BufferQueueDefs.h> +#include <gui/Flags.h> #include <gui/IGraphicBufferProducer.h> #include <gui/IProducerListener.h> +#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h> +#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h> namespace android { // ---------------------------------------------------------------------------- @@ -78,6 +79,7 @@ enum { CANCEL_BUFFERS, QUERY_MULTIPLE, GET_LAST_QUEUED_BUFFER2, + SET_FRAME_RATE, }; class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> @@ -761,6 +763,21 @@ public: } return result; } +#if FLAG_BQ_SET_FRAME_RATE + virtual status_t setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) override { + Parcel data, reply; + data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeFloat(frameRate); + data.writeInt32(compatibility); + data.writeInt32(changeFrameRateStrategy); + status_t result = remote()->transact(SET_FRAME_RATE, data, &reply); + if (result == NO_ERROR) { + result = reply.readInt32(); + } + return result; + } +#endif }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -956,6 +973,14 @@ status_t IGraphicBufferProducer::setAutoPrerotation(bool autoPrerotation) { return INVALID_OPERATION; } +#if FLAG_BQ_SET_FRAME_RATE +status_t IGraphicBufferProducer::setFrameRate(float /*frameRate*/, int8_t /*compatibility*/, + int8_t /*changeFrameRateStrategy*/) { + // No-op for IGBP other than BufferQueue. + return INVALID_OPERATION; +} +#endif + status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) { status_t res = OK; res = parcel->writeUint32(USE_BUFFER_QUEUE); @@ -1497,6 +1522,17 @@ status_t BnGraphicBufferProducer::onTransact( reply->writeInt32(result); return NO_ERROR; } +#if FLAG_BQ_SET_FRAME_RATE + case SET_FRAME_RATE: { + CHECK_INTERFACE(IGraphicBuffer, data, reply); + float frameRate = data.readFloat(); + int8_t compatibility = data.readInt32(); + int8_t changeFrameRateStrategy = data.readInt32(); + status_t result = setFrameRate(frameRate, compatibility, changeFrameRateStrategy); + reply->writeInt32(result); + return NO_ERROR; + } +#endif } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp index 27b1d8b09b..613721e103 100644 --- a/libs/gui/LayerState.cpp +++ b/libs/gui/LayerState.cpp @@ -22,6 +22,7 @@ #include <android/gui/ISurfaceComposerClient.h> #include <android/native_window.h> #include <binder/Parcel.h> +#include <gui/FrameRateUtils.h> #include <gui/IGraphicBufferProducer.h> #include <gui/LayerState.h> #include <gui/SurfaceControl.h> @@ -871,34 +872,6 @@ status_t InputWindowCommands::read(const Parcel& input) { return NO_ERROR; } -bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy, - const char* inFunctionName, bool privileged) { - const char* functionName = inFunctionName != nullptr ? inFunctionName : "call"; - int floatClassification = std::fpclassify(frameRate); - if (frameRate < 0 || floatClassification == FP_INFINITE || floatClassification == FP_NAN) { - ALOGE("%s failed - invalid frame rate %f", functionName, frameRate); - return false; - } - - if (compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT && - compatibility != ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE && - (!privileged || - (compatibility != ANATIVEWINDOW_FRAME_RATE_EXACT && - compatibility != ANATIVEWINDOW_FRAME_RATE_NO_VOTE))) { - ALOGE("%s failed - invalid compatibility value %d privileged: %s", functionName, - compatibility, privileged ? "yes" : "no"); - return false; - } - - if (changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS && - changeFrameRateStrategy != ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS) { - ALOGE("%s failed - invalid change frame rate strategy value %d", functionName, - changeFrameRateStrategy); - } - - return true; -} - // ---------------------------------------------------------------------------- namespace gui { diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 53a2f64d11..a87f05357f 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -43,6 +43,7 @@ #include <gui/AidlStatusUtil.h> #include <gui/BufferItem.h> +#include <gui/Flags.h> #include <gui/IProducerListener.h> #include <gui/ISurfaceComposer.h> @@ -50,8 +51,11 @@ #include <private/gui/ComposerService.h> #include <private/gui/ComposerServiceAIDL.h> +#include <com_android_graphics_libgui_flags.h> + namespace android { +using namespace com::android::graphics::libgui; using gui::aidl_utils::statusTFromBinderStatus; using ui::Dataspace; @@ -2565,8 +2569,22 @@ void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vector<int32_ mSurfaceListener->onBuffersDiscarded(discardedBufs); } -[[deprecated]] status_t Surface::setFrameRate(float /*frameRate*/, int8_t /*compatibility*/, - int8_t /*changeFrameRateStrategy*/) { +status_t Surface::setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) { +#if FLAG_BQ_SET_FRAME_RATE + if (flags::bq_setframerate()) { + status_t err = mGraphicBufferProducer->setFrameRate(frameRate, compatibility, + changeFrameRateStrategy); + ALOGE_IF(err, "IGraphicBufferProducer::setFrameRate(%.2f) returned %s", frameRate, + strerror(-err)); + return err; + } +#else + static_cast<void>(frameRate); + static_cast<void>(compatibility); + static_cast<void>(changeFrameRateStrategy); +#endif + 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 diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index c2543d182b..038764b800 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -26,6 +26,7 @@ #include <android/gui/IWindowInfosListener.h> #include <android/gui/TrustedPresentationThresholds.h> #include <android/os/IInputConstants.h> +#include <gui/FrameRateUtils.h> #include <gui/TraceUtils.h> #include <utils/Errors.h> #include <utils/Log.h> diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h index a49a85984f..02d7c4d2ac 100644 --- a/libs/gui/include/gui/BLASTBufferQueue.h +++ b/libs/gui/include/gui/BLASTBufferQueue.h @@ -17,9 +17,10 @@ #ifndef ANDROID_GUI_BLAST_BUFFER_QUEUE_H #define ANDROID_GUI_BLAST_BUFFER_QUEUE_H -#include <gui/IGraphicBufferProducer.h> -#include <gui/BufferItemConsumer.h> #include <gui/BufferItem.h> +#include <gui/BufferItemConsumer.h> +#include <gui/Flags.h> +#include <gui/IGraphicBufferProducer.h> #include <gui/SurfaceComposerClient.h> #include <utils/Condition.h> @@ -58,6 +59,10 @@ public: protected: void onSidebandStreamChanged() override EXCLUDES(mMutex); +#if FLAG_BQ_SET_FRAME_RATE + void onSetFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) override; +#endif private: const wp<BLASTBufferQueue> mBLASTBufferQueue; diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h index 690587f0e6..2756277f2c 100644 --- a/libs/gui/include/gui/BufferQueue.h +++ b/libs/gui/include/gui/BufferQueue.h @@ -19,9 +19,10 @@ #include <gui/BufferItem.h> #include <gui/BufferQueueDefs.h> +#include <gui/Flags.h> +#include <gui/IConsumerListener.h> #include <gui/IGraphicBufferConsumer.h> #include <gui/IGraphicBufferProducer.h> -#include <gui/IConsumerListener.h> namespace android { @@ -69,6 +70,10 @@ public: void addAndGetFrameTimestamps( const NewFrameEventsEntry* newTimestamps, FrameEventHistoryDelta* outDelta) override; +#if FLAG_BQ_SET_FRAME_RATE + void onSetFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) override; +#endif private: // mConsumerListener is a weak reference to the IConsumerListener. This is // the raison d'etre of ProxyConsumerListener. diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index 1d13dab623..38805d0221 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -18,6 +18,7 @@ #define ANDROID_GUI_BUFFERQUEUEPRODUCER_H #include <gui/BufferQueueDefs.h> +#include <gui/Flags.h> #include <gui/IGraphicBufferProducer.h> namespace android { @@ -201,6 +202,11 @@ public: // See IGraphicBufferProducer::setAutoPrerotation virtual status_t setAutoPrerotation(bool autoPrerotation); +#if FLAG_BQ_SET_FRAME_RATE + // See IGraphicBufferProducer::setFrameRate + status_t setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy) override; +#endif protected: // see IGraphicsBufferProducer::setMaxDequeuedBufferCount, but with the ability to retrieve the diff --git a/libs/gui/include/gui/Flags.h b/libs/gui/include/gui/Flags.h new file mode 100644 index 0000000000..a2cff56e97 --- /dev/null +++ b/libs/gui/include/gui/Flags.h @@ -0,0 +1,22 @@ +/* + * Copyright 2023 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 + +// TODO(281695725): replace this with build time flags, whenever they are available +#ifndef FLAG_BQ_SET_FRAME_RATE +#define FLAG_BQ_SET_FRAME_RATE false +#endif
\ No newline at end of file diff --git a/libs/gui/include/gui/FrameRateUtils.h b/libs/gui/include/gui/FrameRateUtils.h new file mode 100644 index 0000000000..16896efe1f --- /dev/null +++ b/libs/gui/include/gui/FrameRateUtils.h @@ -0,0 +1,26 @@ +/* + * Copyright 2023 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 <stdint.h> + +namespace android { + +bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy, + const char* inFunctionName, bool privileged = false); + +} // namespace android
\ No newline at end of file diff --git a/libs/gui/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h index 0ab2399eb2..e183bf2668 100644 --- a/libs/gui/include/gui/IConsumerListener.h +++ b/libs/gui/include/gui/IConsumerListener.h @@ -19,6 +19,8 @@ #include <binder/IInterface.h> #include <binder/SafeInterface.h> +#include <gui/Flags.h> + #include <utils/Errors.h> #include <utils/RefBase.h> @@ -90,6 +92,12 @@ public: // WARNING: This method can only be called when the BufferQueue is in the consumer's process. virtual void addAndGetFrameTimestamps(const NewFrameEventsEntry* /*newTimestamps*/, FrameEventHistoryDelta* /*outDelta*/) {} + +#if FLAG_BQ_SET_FRAME_RATE + // Notifies the consumer of a setFrameRate call from the producer side. + virtual void onSetFrameRate(float /*frameRate*/, int8_t /*compatibility*/, + int8_t /*changeFrameRateStrategy*/) {} +#endif }; #ifndef NO_BINDER diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 98df83453d..3562906870 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -31,6 +31,7 @@ #include <ui/Rect.h> #include <ui/Region.h> +#include <gui/Flags.h> #include <gui/FrameTimestamps.h> #include <gui/HdrMetadata.h> @@ -676,6 +677,12 @@ public: // the width and height used for dequeueBuffer will be additionally swapped. virtual status_t setAutoPrerotation(bool autoPrerotation); +#if FLAG_BQ_SET_FRAME_RATE + // Sets the apps intended frame rate. + virtual status_t setFrameRate(float frameRate, int8_t compatibility, + int8_t changeFrameRateStrategy); +#endif + struct RequestBufferOutput : public Flattenable<RequestBufferOutput> { RequestBufferOutput() = default; diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h index 35fcccdf78..4371007778 100644 --- a/libs/gui/include/gui/LayerState.h +++ b/libs/gui/include/gui/LayerState.h @@ -480,16 +480,6 @@ static inline int compare_type(const DisplayState& lhs, const DisplayState& rhs) return compare_type(lhs.token, rhs.token); } -// Returns true if the frameRate is valid. -// -// @param frameRate the frame rate in Hz -// @param compatibility a ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* -// @param changeFrameRateStrategy a ANATIVEWINDOW_CHANGE_FRAME_RATE_* -// @param functionName calling function or nullptr. Used for logging -// @param privileged whether caller has unscoped surfaceflinger access -bool ValidateFrameRate(float frameRate, int8_t compatibility, int8_t changeFrameRateStrategy, - const char* functionName, bool privileged = false); - }; // namespace android #endif // ANDROID_SF_LAYER_STATE_H diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp index 462ce6e14f..38c0eed474 100644 --- a/libs/gui/tests/Android.bp +++ b/libs/gui/tests/Android.bp @@ -15,9 +15,13 @@ cc_test { name: "libgui_test", test_suites: ["device-tests"], - cflags: [ + defaults: ["libgui-defaults"], + + cppflags: [ "-Wall", "-Werror", + "-Wno-extra", + "-DFLAG_BQ_SET_FRAME_RATE=true", ], srcs: [ @@ -28,6 +32,7 @@ cc_test { "CompositorTiming_test.cpp", "CpuConsumer_test.cpp", "EndToEndNativeInputTest.cpp", + "FrameRateUtilsTest.cpp", "DisplayInfo_test.cpp", "DisplayedContentSampling_test.cpp", "FillBuffer.cpp", @@ -53,19 +58,12 @@ cc_test { "android.hardware.configstore@1.0", "android.hardware.configstore-utils", "libSurfaceFlingerProp", - "libbase", - "liblog", - "libEGL", "libGLESv1_CM", - "libGLESv2", - "libbinder", - "libcutils", - "libgui", - "libhidlbase", "libinput", - "libui", - "libutils", - "libnativewindow", + ], + + static_libs: [ + "libgmock", ], header_libs: ["libsurfaceflinger_headers"], diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp index 0168877478..17aa5f1350 100644 --- a/libs/gui/tests/BufferQueue_test.cpp +++ b/libs/gui/tests/BufferQueue_test.cpp @@ -37,14 +37,18 @@ #include <system/window.h> +#include <gmock/gmock.h> #include <gtest/gtest.h> #include <future> #include <thread> +#include <com_android_graphics_libgui_flags.h> + using namespace std::chrono_literals; namespace android { +using namespace com::android::graphics::libgui; class BufferQueueTest : public ::testing::Test { @@ -1261,6 +1265,31 @@ TEST_F(BufferQueueTest, TestProducerConnectDisconnect) { ASSERT_EQ(NO_INIT, mProducer->disconnect(NATIVE_WINDOW_API_CPU)); } +TEST_F(BufferQueueTest, TestBqSetFrameRateFlagBuildTimeIsSet) { + if (flags::bq_setframerate()) { + ASSERT_EQ(true, FLAG_BQ_SET_FRAME_RATE); + } +} + +struct BufferItemConsumerSetFrameRateListener : public BufferItemConsumer { + BufferItemConsumerSetFrameRateListener(const sp<IGraphicBufferConsumer>& consumer) + : BufferItemConsumer(consumer, GRALLOC_USAGE_SW_READ_OFTEN, 1) {} + + MOCK_METHOD(void, onSetFrameRate, (float, int8_t, int8_t), (override)); +}; + +TEST_F(BufferQueueTest, TestSetFrameRate) { + sp<IGraphicBufferProducer> producer; + sp<IGraphicBufferConsumer> consumer; + BufferQueue::createBufferQueue(&producer, &consumer); + + sp<BufferItemConsumerSetFrameRateListener> bufferConsumer = + sp<BufferItemConsumerSetFrameRateListener>::make(consumer); + + EXPECT_CALL(*bufferConsumer, onSetFrameRate(12.34f, 1, 0)).Times(1); + producer->setFrameRate(12.34f, 1, 0); +} + class Latch { public: explicit Latch(int expected) : mExpected(expected) {} diff --git a/libs/gui/tests/FrameRateUtilsTest.cpp b/libs/gui/tests/FrameRateUtilsTest.cpp new file mode 100644 index 0000000000..5fe22b05f9 --- /dev/null +++ b/libs/gui/tests/FrameRateUtilsTest.cpp @@ -0,0 +1,74 @@ +/* + * Copyright 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. + */ + +#include <gtest/gtest.h> + +#include <gui/FrameRateUtils.h> +#include <inttypes.h> +#include <system/window.h> + +#include <com_android_graphics_libgui_flags.h> + +namespace android { +using namespace com::android::graphics::libgui; + +TEST(FrameRateUtilsTest, ValidateFrameRate) { + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS, "")); + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + + // Privileged APIs. + EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_FALSE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + + constexpr bool kPrivileged = true; + EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "", + kPrivileged)); + EXPECT_TRUE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "", + kPrivileged)); + + // Invalid frame rate. + EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_FALSE(ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_FALSE(ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, + ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + + // Invalid compatibility. + EXPECT_FALSE( + ValidateFrameRate(60.0f, -1, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + EXPECT_FALSE(ValidateFrameRate(60.0f, 2, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); + + // Invalid change frame rate strategy. + if (flags::bq_setframerate()) { + EXPECT_FALSE( + ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, -1, "")); + EXPECT_FALSE( + ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, 2, "")); + } +} + +} // namespace android diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp index 1f1439608b..16000139f7 100644 --- a/libs/input/InputTransport.cpp +++ b/libs/input/InputTransport.cpp @@ -476,8 +476,6 @@ status_t InputChannel::sendMessage(const InputMessage* msg) { } status_t InputChannel::receiveMessage(InputMessage* msg) { - ATRACE_NAME_IF(ATRACE_ENABLED(), - StringPrintf("receiveMessage(inputChannel=%s)", mName.c_str())); ssize_t nRead; do { nRead = ::recv(getFd(), msg, sizeof(InputMessage), MSG_DONTWAIT); diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp index ee961f0ffc..a0ec6adc65 100644 --- a/libs/input/tests/InputDevice_test.cpp +++ b/libs/input/tests/InputDevice_test.cpp @@ -20,6 +20,7 @@ #include <input/InputDevice.h> #include <input/KeyLayoutMap.h> #include <input/Keyboard.h> +#include <linux/uinput.h> #include "android-base/file.h" namespace android { @@ -97,7 +98,7 @@ TEST_F(InputDeviceKeyMapTest, keyCharacterMapWithOverlayParcelingTest) { ASSERT_EQ(*map, *mKeyMap.keyCharacterMap); } -TEST_F(InputDeviceKeyMapTest, keyCharacteMapApplyMultipleOverlaysTest) { +TEST_F(InputDeviceKeyMapTest, keyCharacterMapApplyMultipleOverlaysTest) { std::string frenchOverlayPath = base::GetExecutableDirectory() + "/data/french.kcm"; std::string englishOverlayPath = base::GetExecutableDirectory() + "/data/english_us.kcm"; std::string germanOverlayPath = base::GetExecutableDirectory() + "/data/german.kcm"; @@ -133,14 +134,33 @@ TEST_F(InputDeviceKeyMapTest, keyCharacteMapApplyMultipleOverlaysTest) { ASSERT_EQ(*mKeyMap.keyCharacterMap, *frenchOverlaidKeyCharacterMap); } -TEST_F(InputDeviceKeyMapTest, keyCharacteMapBadAxisLabel) { +TEST_F(InputDeviceKeyMapTest, keyCharacterMapApplyOverlayTest) { + std::string frenchOverlayPath = base::GetExecutableDirectory() + "/data/french.kcm"; + base::Result<std::shared_ptr<KeyCharacterMap>> frenchOverlay = + KeyCharacterMap::load(frenchOverlayPath, KeyCharacterMap::Format::OVERLAY); + ASSERT_TRUE(frenchOverlay.ok()) << "Cannot load KeyCharacterMap at " << frenchOverlayPath; + + // Apply the French overlay + mKeyMap.keyCharacterMap->combine(*frenchOverlay->get()); + + // Check if mapping for key_Q is correct + int32_t outKeyCode; + status_t mapKeyResult = mKeyMap.keyCharacterMap->mapKey(KEY_Q, /*usageCode=*/0, &outKeyCode); + ASSERT_EQ(mapKeyResult, OK) << "No mapping for KEY_Q for " << frenchOverlayPath; + ASSERT_EQ(outKeyCode, AKEYCODE_A); + + mapKeyResult = mKeyMap.keyCharacterMap->mapKey(KEY_E, /*usageCode=*/0, &outKeyCode); + ASSERT_NE(mapKeyResult, OK) << "Mapping exists for KEY_E for " << frenchOverlayPath; +} + +TEST_F(InputDeviceKeyMapTest, keyCharacterMapBadAxisLabel) { std::string klPath = base::GetExecutableDirectory() + "/data/bad_axis_label.kl"; base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath); ASSERT_FALSE(ret.ok()) << "Should not be able to load KeyLayout at " << klPath; } -TEST_F(InputDeviceKeyMapTest, keyCharacteMapBadLedLabel) { +TEST_F(InputDeviceKeyMapTest, keyCharacterMapBadLedLabel) { std::string klPath = base::GetExecutableDirectory() + "/data/bad_led_label.kl"; base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath); diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp index e253ad596e..cc1d12bc5c 100644 --- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp +++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp @@ -24,6 +24,7 @@ #include <EGL/egl.h> #include <EGL/eglext.h> #include <GrContextOptions.h> +#include <GrTypes.h> #include <android-base/stringprintf.h> #include <gl/GrGLInterface.h> #include <gui/TraceUtils.h> @@ -338,7 +339,8 @@ base::unique_fd SkiaGLRenderEngine::flushAndSubmit(GrDirectContext* grContext) { } else { ATRACE_BEGIN("Submit(sync=false)"); } - bool success = grContext->submit(requireSync); + bool success = grContext->submit(requireSync ? GrSyncCpu::kYes : + GrSyncCpu::kNo); ATRACE_END(); if (!success) { ALOGE("Failed to flush RenderEngine commands"); diff --git a/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h b/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h index 30149c11f0..b86ce5f450 100644 --- a/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h +++ b/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h @@ -136,7 +136,7 @@ private: size_t mHeight; // Position of EXIF package, default value is -1 which means no EXIF package appears. - size_t mExifPos; + ssize_t mExifPos = -1; }; } /* namespace android::ultrahdr */ diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp index 74760d9b32..3d70fcea71 100644 --- a/libs/ultrahdr/jpegr.cpp +++ b/libs/ultrahdr/jpegr.cpp @@ -85,13 +85,11 @@ static void copyJpegWithoutExif(jr_compressed_ptr pDest, jr_compressed_ptr pSource, size_t exif_pos, size_t exif_size) { - memcpy(pDest, pSource, sizeof(jpegr_compressed_struct)); - const size_t exif_offset = 4; //exif_pos has 4 bytes offset to the FF sign pDest->length = pSource->length - exif_size - exif_offset; pDest->data = new uint8_t[pDest->length]; - std::unique_ptr<uint8_t[]> dest_data; - dest_data.reset(reinterpret_cast<uint8_t*>(pDest->data)); + pDest->maxLength = pDest->length; + pDest->colorGamut = pSource->colorGamut; memcpy(pDest->data, pSource->data, exif_pos - exif_offset); memcpy((uint8_t*)pDest->data + exif_pos - exif_offset, (uint8_t*)pSource->data + exif_pos + exif_size, @@ -1262,13 +1260,13 @@ status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, if (!decoder.extractEXIF(primary_jpg_image_ptr->data, primary_jpg_image_ptr->length)) { return ERROR_JPEGR_DECODE_ERROR; } - jpegr_exif_struct exif_from_jpg; - exif_from_jpg.data = nullptr; - exif_from_jpg.length = 0; - jpegr_compressed_struct new_jpg_image; - new_jpg_image.data = nullptr; - new_jpg_image.length = 0; - if (decoder.getEXIFPos() != 0) { + jpegr_exif_struct exif_from_jpg = {.data = nullptr, .length = 0}; + jpegr_compressed_struct new_jpg_image = {.data = nullptr, + .length = 0, + .maxLength = 0, + .colorGamut = ULTRAHDR_COLORGAMUT_UNSPECIFIED}; + std::unique_ptr<uint8_t[]> dest_data; + if (decoder.getEXIFPos() >= 0) { if (pExif != nullptr) { ALOGE("received EXIF from outside while the primary image already contains EXIF"); return ERROR_JPEGR_INVALID_INPUT_TYPE; @@ -1277,6 +1275,7 @@ status_t JpegR::appendGainMap(jr_compressed_ptr primary_jpg_image_ptr, primary_jpg_image_ptr, decoder.getEXIFPos(), decoder.getEXIFSize()); + dest_data.reset(reinterpret_cast<uint8_t*>(new_jpg_image.data)); exif_from_jpg.data = decoder.getEXIFPtr(); exif_from_jpg.length = decoder.getEXIFSize(); pExif = &exif_from_jpg; diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp index 052efb6bbb..e5b1e44b44 100644 --- a/services/gpuservice/Android.bp +++ b/services/gpuservice/Android.bp @@ -21,7 +21,13 @@ cc_defaults { cc_defaults { name: "libgpuservice_defaults", - defaults: ["gpuservice_defaults"], + defaults: [ + "gpuservice_defaults", + "libvkjson_deps", + "libgfxstats_deps", + "libgpumem_deps", + "libgpumemtracer_deps", + ], cflags: [ "-DLOG_TAG=\"GpuService\"", ], @@ -29,17 +35,17 @@ cc_defaults { "libbase", "libbinder", "libcutils", - "libgfxstats", - "libgpumem", "libgpuwork", - "libgpumemtracer", "libgraphicsenv", "liblog", "libutils", - "libvkjson", ], static_libs: [ + "libgfxstats", + "libgpumem", + "libgpumemtracer", "libserviceutils", + "libvkjson", ], export_static_lib_headers: [ "libserviceutils", @@ -68,7 +74,7 @@ filegroup { ], } -cc_library_shared { +cc_library_static { name: "libgpuservice", defaults: ["libgpuservice_production_defaults"], export_include_dirs: ["include"], @@ -96,14 +102,17 @@ filegroup { cc_binary { name: "gpuservice", - defaults: ["libgpuservice_binary"], + defaults: [ + "libgpuservice_binary", + "libgpuservice_production_defaults", + ], init_rc: ["gpuservice.rc"], required: [ "bpfloader", "gpuMem.o", ], srcs: [":gpuservice_binary_sources"], - shared_libs: [ + static_libs: [ "libgpuservice", ], } diff --git a/services/gpuservice/gpumem/Android.bp b/services/gpuservice/gpumem/Android.bp index d0ea856fb5..66a30597a7 100644 --- a/services/gpuservice/gpumem/Android.bp +++ b/services/gpuservice/gpumem/Android.bp @@ -21,12 +21,8 @@ package { default_applicable_licenses: ["frameworks_native_license"], } -cc_library_shared { - name: "libgpumem", - srcs: [ - "GpuMem.cpp", - ], - header_libs: ["bpf_headers"], +cc_defaults { + name: "libgpumem_deps", shared_libs: [ "libbase", "libbpf_bcc", @@ -34,6 +30,17 @@ cc_library_shared { "liblog", "libutils", ], +} + +cc_library_static { + name: "libgpumem", + defaults: [ + "libgpumem_deps", + ], + srcs: [ + "GpuMem.cpp", + ], + header_libs: ["bpf_headers"], export_include_dirs: ["include"], export_header_lib_headers: ["bpf_headers"], export_shared_lib_headers: ["libbase"], diff --git a/services/gpuservice/gpustats/Android.bp b/services/gpuservice/gpustats/Android.bp index 54291ad6c6..0e64716e6d 100644 --- a/services/gpuservice/gpustats/Android.bp +++ b/services/gpuservice/gpustats/Android.bp @@ -7,11 +7,8 @@ package { default_applicable_licenses: ["frameworks_native_license"], } -cc_library_shared { - name: "libgfxstats", - srcs: [ - "GpuStats.cpp", - ], +cc_defaults { + name: "libgfxstats_deps", shared_libs: [ "libcutils", "libgraphicsenv", @@ -22,6 +19,16 @@ cc_library_shared { "libstatssocket", "libutils", ], +} + +cc_library_static { + name: "libgfxstats", + defaults: [ + "libgfxstats_deps", + ], + srcs: [ + "GpuStats.cpp", + ], export_include_dirs: ["include"], export_shared_lib_headers: [ "libstatspull", diff --git a/services/gpuservice/tests/fuzzers/Android.bp b/services/gpuservice/tests/fuzzers/Android.bp index 6bcc5e8601..d4d48c48ea 100644 --- a/services/gpuservice/tests/fuzzers/Android.bp +++ b/services/gpuservice/tests/fuzzers/Android.bp @@ -5,10 +5,12 @@ package { cc_fuzz { name: "gpu_service_fuzzer", defaults: [ + "libgpuservice_defaults", "service_fuzzer_defaults", "fuzzer_disable_leaks", ], static_libs: [ + "libgpuservice", "liblog", ], fuzz_config: { @@ -20,7 +22,4 @@ cc_fuzz { }, include_dirs: ["frameworks/native/services/gpuservice/"], srcs: ["GpuServiceFuzzer.cpp"], - shared_libs: [ - "libgpuservice", - ], } diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp index c870b17b79..8056a2c601 100644 --- a/services/gpuservice/tests/unittests/Android.bp +++ b/services/gpuservice/tests/unittests/Android.bp @@ -24,6 +24,9 @@ package { cc_test { name: "gpuservice_unittest", test_suites: ["device-tests"], + defaults: [ + "libgpuservice_defaults", + ], srcs: [ "GpuMemTest.cpp", "GpuMemTracerTest.cpp", @@ -36,9 +39,6 @@ cc_test { "libbinder", "libbpf_bcc", "libcutils", - "libgfxstats", - "libgpumem", - "libgpumemtracer", "libgraphicsenv", "liblog", "libprotobuf-cpp-lite", @@ -46,10 +46,10 @@ cc_test { "libstatslog", "libstatspull", "libutils", - "libgpuservice", ], static_libs: [ "libgmock", + "libgpuservice", "libperfetto_client_experimental", "perfetto_trace_protos", ], diff --git a/services/gpuservice/tracing/Android.bp b/services/gpuservice/tracing/Android.bp index a1bc1edad8..d636b7d195 100644 --- a/services/gpuservice/tracing/Android.bp +++ b/services/gpuservice/tracing/Android.bp @@ -21,20 +21,28 @@ package { default_applicable_licenses: ["frameworks_native_license"], } -cc_library_shared { - name: "libgpumemtracer", - srcs: [ - "GpuMemTracer.cpp", - ], +cc_defaults { + name: "libgpumemtracer_deps", shared_libs: [ - "libgpumem", "libbase", "liblog", "libutils", ], static_libs: [ + "libgpumem", "libperfetto_client_experimental", ], +} + +cc_library_static { + name: "libgpumemtracer", + defaults: [ + "libgpumemtracer_deps", + "libgpumem_deps", + ], + srcs: [ + "GpuMemTracer.cpp", + ], export_include_dirs: ["include"], export_static_lib_headers: [ "libperfetto_client_experimental", diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp index cb369a836e..fa8f5485c0 100644 --- a/services/inputflinger/dispatcher/Entry.cpp +++ b/services/inputflinger/dispatcher/Entry.cpp @@ -269,6 +269,11 @@ std::string MotionEntry::getDescription() const { return msg; } +std::ostream& operator<<(std::ostream& out, const MotionEntry& motionEntry) { + out << motionEntry.getDescription(); + return out; +} + // --- SensorEntry --- SensorEntry::SensorEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h index 8dc2a2a221..dd4aab85f5 100644 --- a/services/inputflinger/dispatcher/Entry.h +++ b/services/inputflinger/dispatcher/Entry.h @@ -24,6 +24,7 @@ #include <stdint.h> #include <utils/Timers.h> #include <functional> +#include <ostream> #include <string> namespace android::inputdispatcher { @@ -189,6 +190,8 @@ struct MotionEntry : EventEntry { ~MotionEntry() override; }; +std::ostream& operator<<(std::ostream& out, const MotionEntry& motionEntry); + struct SensorEntry : EventEntry { int32_t deviceId; uint32_t source; diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index d98641ec1d..0a1e8896b0 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -668,7 +668,15 @@ std::vector<TouchedWindow> getHoveringWindowsLocked(const TouchState* oldState, } else { // This pointer was already sent to the window. Use ACTION_HOVER_MOVE. if (CC_UNLIKELY(maskedAction != AMOTION_EVENT_ACTION_HOVER_MOVE)) { - LOG(FATAL) << "Expected ACTION_HOVER_MOVE instead of " << entry.getDescription(); + android::base::LogSeverity severity = android::base::LogSeverity::FATAL; + if (entry.flags & AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT) { + // The Accessibility injected touch exploration event stream + // has known inconsistencies, so log ERROR instead of + // crashing the device with FATAL. + // TODO(b/299977100): Move a11y severity back to FATAL. + severity = android::base::LogSeverity::ERROR; + } + LOG(severity) << "Expected ACTION_HOVER_MOVE instead of " << entry.getDescription(); } touchedWindow.targetFlags = InputTarget::Flags::DISPATCH_AS_IS; } diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp index 4221e42ae5..9dcf615479 100644 --- a/services/inputflinger/dispatcher/TouchState.cpp +++ b/services/inputflinger/dispatcher/TouchState.cpp @@ -288,4 +288,9 @@ std::string TouchState::dump() const { return out; } +std::ostream& operator<<(std::ostream& out, const TouchState& state) { + out << state.dump(); + return out; +} + } // namespace android::inputdispatcher diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h index 39e63e5894..f01693662c 100644 --- a/services/inputflinger/dispatcher/TouchState.h +++ b/services/inputflinger/dispatcher/TouchState.h @@ -17,6 +17,7 @@ #pragma once #include <bitset> +#include <ostream> #include <set> #include "TouchedWindow.h" @@ -79,5 +80,7 @@ struct TouchState { std::string dump() const; }; +std::ostream& operator<<(std::ostream& out, const TouchState& state); + } // namespace inputdispatcher } // namespace android diff --git a/services/inputflinger/dispatcher/TouchedWindow.cpp b/services/inputflinger/dispatcher/TouchedWindow.cpp index 9807a6da9b..ff4b425da3 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.cpp +++ b/services/inputflinger/dispatcher/TouchedWindow.cpp @@ -256,5 +256,10 @@ std::string TouchedWindow::dump() const { return out; } +std::ostream& operator<<(std::ostream& out, const TouchedWindow& window) { + out << window.dump(); + return out; +} + } // namespace inputdispatcher } // namespace android diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h index 0a38f9f5cd..3f760c0fac 100644 --- a/services/inputflinger/dispatcher/TouchedWindow.h +++ b/services/inputflinger/dispatcher/TouchedWindow.h @@ -20,6 +20,7 @@ #include <input/Input.h> #include <utils/BitSet.h> #include <bitset> +#include <ostream> #include <set> #include "InputTarget.h" @@ -92,5 +93,7 @@ private: static std::string deviceStateToString(const TouchedWindow::DeviceState& state); }; +std::ostream& operator<<(std::ostream& out, const TouchedWindow& window); + } // namespace inputdispatcher } // namespace android diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index b565454805..90bd7c9c74 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -130,7 +130,10 @@ TouchInputMapper::TouchInputMapper(InputDeviceContext& deviceContext, TouchInputMapper::~TouchInputMapper() {} uint32_t TouchInputMapper::getSources() const { - return mSource; + // The SOURCE_BLUETOOTH_STYLUS is added to events dynamically if the current stream is modified + // by the external stylus state. That's why we don't add it directly to mSource during + // configuration. + return mSource | (hasExternalStylus() ? AINPUT_SOURCE_BLUETOOTH_STYLUS : 0); } void TouchInputMapper::populateDeviceInfo(InputDeviceInfo& info) { @@ -932,9 +935,6 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) if (hasStylus()) { mSource |= AINPUT_SOURCE_STYLUS; } - if (hasExternalStylus()) { - mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS; - } } else if (mParameters.deviceType == Parameters::DeviceType::TOUCH_NAVIGATION) { mSource = AINPUT_SOURCE_TOUCH_NAVIGATION; mDeviceMode = DeviceMode::NAVIGATION; @@ -1664,6 +1664,10 @@ std::list<NotifyArgs> TouchInputMapper::cookAndDispatch(nsecs_t when, nsecs_t re mSource, mViewport.displayId, policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState); + if (mCurrentCookedState.cookedPointerData.pointerCount == 0) { + mCurrentStreamModifiedByExternalStylus = false; + } + // Clear some transient state. mCurrentRawState.rawVScroll = 0; mCurrentRawState.rawHScroll = 0; @@ -1715,6 +1719,10 @@ void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) { mExternalStylusButtonsApplied |= pressedButtons; mExternalStylusButtonsApplied &= ~releasedButtons; + + if (mExternalStylusButtonsApplied != 0 || releasedButtons != 0) { + mCurrentStreamModifiedByExternalStylus = true; + } } } @@ -1725,6 +1733,8 @@ void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) { return; } + mCurrentStreamModifiedByExternalStylus = true; + float pressure = lastPointerData.isTouching(*mFusedStylusPointerId) ? lastPointerData.pointerCoordsForId(*mFusedStylusPointerId) .getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) @@ -3821,6 +3831,9 @@ NotifyMotionArgs TouchInputMapper::dispatchMotion( ALOG_ASSERT(false); } } + if (mCurrentStreamModifiedByExternalStylus) { + source |= AINPUT_SOURCE_BLUETOOTH_STYLUS; + } const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE); const bool showDirectStylusPointer = mConfig.stylusPointerIconEnabled && diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index c5dfb00adb..bd9371d263 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -357,6 +357,8 @@ protected: bool mExternalStylusDataPending; // A subset of the buttons in mCurrentRawState that came from an external stylus. int32_t mExternalStylusButtonsApplied{0}; + // True if the current cooked pointer data was modified due to the state of an external stylus. + bool mCurrentStreamModifiedByExternalStylus{false}; // True if we sent a HOVER_ENTER event. bool mSentHoverEnter{false}; diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp index dc281a3d5f..dd003a6921 100644 --- a/services/inputflinger/tests/InputDispatcher_test.cpp +++ b/services/inputflinger/tests/InputDispatcher_test.cpp @@ -3349,6 +3349,31 @@ TEST_F(InputDispatcherTest, HoverExitIsSentToRemovedWindow) { } /** + * Test that invalid HOVER events sent by accessibility do not cause a fatal crash. + */ +TEST_F(InputDispatcherTest, InvalidA11yHoverStreamDoesNotCrash) { + std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>(); + sp<FakeWindowHandle> window = + sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT); + window->setFrame(Rect(0, 0, 1200, 800)); + + mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); + + mDispatcher->onWindowInfosChanged({{*window->getInfo()}, {}, 0, 0}); + + MotionEventBuilder hoverEnterBuilder = + MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE) + .pointer(PointerBuilder(0, ToolType::MOUSE).x(300).y(400)) + .addFlag(AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(*mDispatcher, hoverEnterBuilder.build())); + ASSERT_EQ(InputEventInjectionResult::SUCCEEDED, + injectMotionEvent(*mDispatcher, hoverEnterBuilder.build())); + window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); + window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER)); +} + +/** * If mouse is hovering when the touch goes down, the hovering should be stopped via HOVER_EXIT. */ TEST_F(InputDispatcherTest, TouchDownAfterMouseHover) { diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index bce0937890..6539593217 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -91,6 +91,9 @@ static constexpr int32_t ACTION_POINTER_1_DOWN = static constexpr int32_t ACTION_POINTER_1_UP = AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); +static constexpr uint32_t STYLUS_FUSION_SOURCE = + AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_BLUETOOTH_STYLUS; + // Minimum timestamp separation between subsequent input events from a Bluetooth device. static constexpr nsecs_t MIN_BLUETOOTH_TIMESTAMP_DELTA = ms2ns(4); // Maximum smoothing time delta so that we don't generate events too far into the future. @@ -2308,6 +2311,22 @@ TYPED_TEST(StylusButtonIntegrationTest, StylusButtonMotionEventsDisabled) { // ongoing stylus gesture that is being emitted by the touchscreen. using ExternalStylusIntegrationTest = BaseTouchIntegrationTest; +TEST_F(ExternalStylusIntegrationTest, ExternalStylusConnectionChangesTouchscreenSource) { + // Create an external stylus capable of reporting pressure data that + // should be fused with a touch pointer. + std::unique_ptr<UinputExternalStylusWithPressure> stylus = + createUinputDevice<UinputExternalStylusWithPressure>(); + ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged()); + ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyConfigurationChangedWasCalled()); + const auto stylusInfo = findDeviceByName(stylus->getName()); + ASSERT_TRUE(stylusInfo); + + // Connecting an external stylus changes the source of the touchscreen. + const auto deviceInfo = findDeviceByName(mDevice->getName()); + ASSERT_TRUE(deviceInfo); + ASSERT_TRUE(isFromSource(deviceInfo->getSources(), STYLUS_FUSION_SOURCE)); +} + TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureReported) { const Point centerPoint = mDevice->getCenterPoint(); @@ -2337,17 +2356,17 @@ TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureReported) { mDevice->sendDown(centerPoint); mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType(ToolType::STYLUS), WithButtonState(0), - WithDeviceId(touchscreenId), WithPressure(100.f / RAW_PRESSURE_MAX)))); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithToolType(ToolType::STYLUS), + WithButtonState(0), WithSource(STYLUS_FUSION_SOURCE), WithDeviceId(touchscreenId), + WithPressure(100.f / RAW_PRESSURE_MAX)))); // Change the pressure on the external stylus, and ensure the touchscreen generates a MOVE // event with the updated pressure. stylus->setPressure(200); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), - WithToolType(ToolType::STYLUS), WithButtonState(0), - WithDeviceId(touchscreenId), WithPressure(200.f / RAW_PRESSURE_MAX)))); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), WithToolType(ToolType::STYLUS), + WithButtonState(0), WithSource(STYLUS_FUSION_SOURCE), WithDeviceId(touchscreenId), + WithPressure(200.f / RAW_PRESSURE_MAX)))); // The external stylus did not generate any events. ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled()); @@ -2392,8 +2411,8 @@ TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureNotReported) { // it shows up as a finger pointer. ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType(ToolType::FINGER), WithDeviceId(touchscreenId), - WithPressure(1.f)))); + WithSource(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS), + WithToolType(ToolType::FINGER), WithDeviceId(touchscreenId), WithPressure(1.f)))); // Change the pressure on the external stylus. Since the pressure was not present at the start // of the gesture, it is ignored for now. @@ -2405,6 +2424,7 @@ TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureNotReported) { mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), + WithSource(AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_STYLUS), WithToolType(ToolType::FINGER)))); // Start a new gesture. Since we have a valid pressure value, it shows up as a stylus. @@ -2413,9 +2433,9 @@ TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureNotReported) { mDevice->sendDown(centerPoint); mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasCalled( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType(ToolType::STYLUS), WithButtonState(0), - WithDeviceId(touchscreenId), WithPressure(200.f / RAW_PRESSURE_MAX)))); + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), WithSource(STYLUS_FUSION_SOURCE), + WithToolType(ToolType::STYLUS), WithButtonState(0), WithDeviceId(touchscreenId), + WithPressure(200.f / RAW_PRESSURE_MAX)))); // The external stylus did not generate any events. ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled()); @@ -2447,14 +2467,15 @@ TEST_F(ExternalStylusIntegrationTest, UnfusedExternalStylus) { std::chrono::milliseconds(ns2ms(EXTERNAL_STYLUS_DATA_TIMEOUT)); mDevice->sendSync(); ASSERT_NO_FATAL_FAILURE( - mTestListener - ->assertNotifyMotionWasCalled(AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), - WithToolType( - ToolType::FINGER), - WithButtonState(0), - WithDeviceId(touchscreenId), - WithPressure(1.f)), - waitUntil)); + mTestListener->assertNotifyMotionWasCalled(AllOf(WithMotionAction( + AMOTION_EVENT_ACTION_DOWN), + WithToolType(ToolType::FINGER), + WithSource(AINPUT_SOURCE_TOUCHSCREEN | + AINPUT_SOURCE_STYLUS), + WithButtonState(0), + WithDeviceId(touchscreenId), + WithPressure(1.f)), + waitUntil)); // The external stylus did not generate any events. ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyMotionWasNotCalled()); @@ -7567,12 +7588,10 @@ public: protected: StylusState mStylusState{}; - static constexpr uint32_t EXPECTED_SOURCE = - AINPUT_SOURCE_TOUCHSCREEN | AINPUT_SOURCE_BLUETOOTH_STYLUS; void testStartFusedStylusGesture(SingleTouchInputMapper& mapper) { auto toolTypeSource = - AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS)); + AllOf(WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS)); // The first pointer is withheld. processDown(mapper, 100, 200); @@ -7606,7 +7625,7 @@ protected: processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(EXPECTED_SOURCE), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS)))); mStylusState.pressure = 0.f; @@ -7616,8 +7635,10 @@ protected: } void testUnsuccessfulFusionGesture(SingleTouchInputMapper& mapper) { + // When stylus fusion is not successful, events should be reported with the original source. + // In this case, it is from a touchscreen. auto toolTypeSource = - AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::FINGER)); + AllOf(WithSource(AINPUT_SOURCE_TOUCHSCREEN), WithToolType(ToolType::FINGER)); // The first pointer is withheld when an external stylus is connected, // and a timeout is requested. @@ -7657,7 +7678,7 @@ private: TEST_F(ExternalStylusFusionTest, UsesBluetoothStylusSource) { SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus(); - ASSERT_EQ(EXPECTED_SOURCE, mapper.getSources()); + ASSERT_EQ(STYLUS_FUSION_SOURCE, mapper.getSources()); } TEST_F(ExternalStylusFusionTest, UnsuccessfulFusion) { @@ -7674,8 +7695,7 @@ TEST_F(ExternalStylusFusionTest, SuccessfulFusion_TouchFirst) { // before the touch is reported by the touchscreen. TEST_F(ExternalStylusFusionTest, SuccessfulFusion_PressureFirst) { SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus(); - auto toolTypeSource = - AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS)); + auto toolTypeSource = AllOf(WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS)); // The external stylus reports pressure first. It is ignored for now. mStylusState.pressure = 1.f; @@ -7717,8 +7737,7 @@ TEST_F(ExternalStylusFusionTest, FusionIsRepeatedForEachNewGesture) { TEST_F(ExternalStylusFusionTest, FusedPointerReportsPressureChanges) { SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus(); - auto toolTypeSource = - AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS)); + auto toolTypeSource = AllOf(WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS)); mStylusState.pressure = 0.8f; processExternalStylusState(mapper); @@ -7779,7 +7798,7 @@ TEST_F(ExternalStylusFusionTest, FusedPointerReportsPressureChanges) { processUp(mapper); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( - AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(EXPECTED_SOURCE), + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_UP), WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS)))); ASSERT_NO_FATAL_FAILURE(mReader->getContext()->assertTimeoutWasNotRequested()); @@ -7788,7 +7807,7 @@ TEST_F(ExternalStylusFusionTest, FusedPointerReportsPressureChanges) { TEST_F(ExternalStylusFusionTest, FusedPointerReportsToolTypeChanges) { SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus(); - auto source = WithSource(EXPECTED_SOURCE); + auto source = WithSource(STYLUS_FUSION_SOURCE); mStylusState.pressure = 1.f; mStylusState.toolType = ToolType::ERASER; @@ -7841,8 +7860,7 @@ TEST_F(ExternalStylusFusionTest, FusedPointerReportsToolTypeChanges) { TEST_F(ExternalStylusFusionTest, FusedPointerReportsButtons) { SingleTouchInputMapper& mapper = initializeInputMapperWithExternalStylus(); - auto toolTypeSource = - AllOf(WithSource(EXPECTED_SOURCE), WithToolType(ToolType::STYLUS)); + auto toolTypeSource = AllOf(WithSource(STYLUS_FUSION_SOURCE), WithToolType(ToolType::STYLUS)); ASSERT_NO_FATAL_FAILURE(testStartFusedStylusGesture(mapper)); diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index 22db247cc9..fe56969884 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -844,10 +844,16 @@ void OutputLayer::applyDeviceLayerRequest(hal::LayerRequest request) { bool OutputLayer::needsFiltering() const { const auto& state = getState(); - const auto& displayFrame = state.displayFrame; const auto& sourceCrop = state.sourceCrop; - return sourceCrop.getHeight() != displayFrame.getHeight() || - sourceCrop.getWidth() != displayFrame.getWidth(); + auto displayFrameWidth = static_cast<float>(state.displayFrame.getWidth()); + auto displayFrameHeight = static_cast<float>(state.displayFrame.getHeight()); + + if (state.bufferTransform & HAL_TRANSFORM_ROT_90) { + std::swap(displayFrameWidth, displayFrameHeight); + } + + return sourceCrop.getHeight() != displayFrameHeight || + sourceCrop.getWidth() != displayFrameWidth; } std::optional<LayerFE::LayerSettings> OutputLayer::getOverrideCompositionSettings() const { diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index 9039d16aeb..630906a5b7 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -1614,5 +1614,20 @@ TEST_F(OutputLayerTest, needsFilteringReturnsTrueIfDisplaySizeDifferentFromSourc EXPECT_TRUE(mOutputLayer.needsFiltering()); } +TEST_F(OutputLayerTest, needsFilteringReturnsFalseIfRotatedDisplaySizeSameAsSourceSize) { + mOutputLayer.editState().displayFrame = Rect(100, 100, 300, 200); + mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.f, 200.f}; + mOutputLayer.editState().bufferTransform = Hwc2::Transform::ROT_90; + + EXPECT_FALSE(mOutputLayer.needsFiltering()); +} + +TEST_F(OutputLayerTest, needsFilteringReturnsTrueIfRotatedDisplaySizeDiffersFromSourceSize) { + mOutputLayer.editState().displayFrame = Rect(100, 100, 300, 200); + mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.f, 200.f}; + + EXPECT_TRUE(mOutputLayer.needsFiltering()); +} + } // namespace } // namespace android::compositionengine diff --git a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp index acec630167..fcc1e61c95 100644 --- a/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp +++ b/services/surfaceflinger/FrontEnd/RequestedLayerState.cpp @@ -468,12 +468,18 @@ Rect RequestedLayerState::getCroppedBufferSize(const Rect& bufferSize) const { Rect RequestedLayerState::getBufferCrop() const { // this is the crop rectangle that applies to the buffer // itself (as opposed to the window) - if (!bufferCrop.isEmpty()) { - // if the buffer crop is defined, we use that - return bufferCrop; + if (!bufferCrop.isEmpty() && externalTexture != nullptr) { + // if the buffer crop is defined and there's a valid buffer, intersect buffer size and crop + // since the crop should never exceed the size of the buffer. + Rect sizeAndCrop; + externalTexture->getBounds().intersect(bufferCrop, &sizeAndCrop); + return sizeAndCrop; } else if (externalTexture != nullptr) { // otherwise we use the whole buffer return externalTexture->getBounds(); + } else if (!bufferCrop.isEmpty()) { + // if the buffer crop is defined, we use that + return bufferCrop; } else { // if we don't have a buffer yet, we use an empty/invalid crop return Rect(); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 10768a9b0c..fadde51a33 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -5828,6 +5828,20 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { StringAppendF(&result, "Permission Denial: can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid); } else { + Dumper hwclayersDump = [this](const DumpArgs&, bool, std::string& result) + FTL_FAKE_GUARD(mStateLock) -> void const { + if (mLayerLifecycleManagerEnabled) { + mScheduler + ->schedule([this, &result]() FTL_FAKE_GUARD(kMainThreadContext) + FTL_FAKE_GUARD(mStateLock) { + dumpHwcLayersMinidump(result); + }) + .get(); + } else { + dumpHwcLayersMinidumpLockedLegacy(result); + } + }; + static const std::unordered_map<std::string, Dumper> dumpers = { {"--comp-displays"s, dumper(&SurfaceFlinger::dumpCompositionDisplays)}, {"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)}, @@ -5836,7 +5850,7 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) { {"--events"s, dumper(&SurfaceFlinger::dumpEvents)}, {"--frametimeline"s, argsDumper(&SurfaceFlinger::dumpFrameTimeline)}, {"--hdrinfo"s, dumper(&SurfaceFlinger::dumpHdrInfo)}, - {"--hwclayers"s, dumper(&SurfaceFlinger::dumpHwcLayersMinidumpLockedLegacy)}, + {"--hwclayers"s, std::move(hwclayersDump)}, {"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)}, {"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)}, {"--list"s, dumper(&SurfaceFlinger::listLayersLocked)}, @@ -7822,10 +7836,12 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( displayBrightnessNits = std::min(sdrWhitePointNits * kMaxScreenshotHeadroom, displayBrightnessNits); } + } - if (requestedDataspace == ui::Dataspace::UNKNOWN) { - renderIntent = state.renderIntent; - } + // Screenshots leaving the device should be colorimetric + if (requestedDataspace == ui::Dataspace::UNKNOWN && + renderArea->getHintForSeamlessTransition()) { + renderIntent = state.renderIntent; } } } @@ -7868,6 +7884,10 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( } } + // Screenshots leaving the device must not dim in gamma space. + const bool dimInGammaSpaceForEnhancedScreenshots = mDimInGammaSpaceForEnhancedScreenshots && + renderArea->getHintForSeamlessTransition(); + std::shared_ptr<ScreenCaptureOutput> output = createScreenCaptureOutput( ScreenCaptureOutputArgs{.compositionEngine = *compositionEngine, .colorProfile = colorProfile, @@ -7880,7 +7900,7 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( .regionSampling = regionSampling, .treat170mAsSrgb = mTreat170mAsSrgb, .dimInGammaSpaceForEnhancedScreenshots = - mDimInGammaSpaceForEnhancedScreenshots}); + dimInGammaSpaceForEnhancedScreenshots}); const float colorSaturation = grayscale ? 0 : 1; compositionengine::CompositionRefreshArgs refreshArgs{ diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h index 32821b7891..d7ac038a84 100644 --- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h +++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h @@ -384,6 +384,17 @@ protected: mLifecycleManager.applyTransactions(transactions); } + void setBufferCrop(uint32_t id, const Rect& bufferCrop) { + std::vector<TransactionState> transactions; + transactions.emplace_back(); + transactions.back().states.push_back({}); + + transactions.back().states.front().state.what = layer_state_t::eBufferCropChanged; + transactions.back().states.front().layerId = id; + transactions.back().states.front().state.bufferCrop = bufferCrop; + mLifecycleManager.applyTransactions(transactions); + } + void setDataspace(uint32_t id, ui::Dataspace dataspace) { std::vector<TransactionState> transactions; transactions.emplace_back(); diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp index 662f4bd466..1a9233d12c 100644 --- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp @@ -846,4 +846,33 @@ TEST_F(LayerSnapshotTest, setRefreshRateIndicatorCompositionType) { aidl::android::hardware::graphics::composer3::Composition::REFRESH_RATE_INDICATOR); } +TEST_F(LayerSnapshotTest, setBufferCrop) { + // validate no buffer but has crop + Rect crop = Rect(0, 0, 50, 50); + setBufferCrop(1, crop); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_EQ(getSnapshot(1)->geomContentCrop, crop); + + setBuffer(1, + std::make_shared<renderengine::mock::FakeExternalTexture>(100U /*width*/, + 100U /*height*/, + 42ULL /* bufferId */, + HAL_PIXEL_FORMAT_RGBA_8888, + 0 /*usage*/)); + // validate a buffer crop within the buffer bounds + setBufferCrop(1, crop); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_EQ(getSnapshot(1)->geomContentCrop, crop); + + // validate a buffer crop outside the buffer bounds + crop = Rect(0, 0, 150, 150); + setBufferCrop(1, crop); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_EQ(getSnapshot(1)->geomContentCrop, Rect(0, 0, 100, 100)); + + // validate no buffer crop + setBufferCrop(1, Rect()); + UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER); + EXPECT_EQ(getSnapshot(1)->geomContentCrop, Rect(0, 0, 100, 100)); +} } // namespace android::surfaceflinger::frontend diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp index 608fa762ef..9899d4290b 100644 --- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp +++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp @@ -19,6 +19,7 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> +#include <gui/FrameRateUtils.h> #include <gui/LayerMetadata.h> // TODO(b/129481165): remove the #pragma below and fix conversion issues @@ -325,48 +326,6 @@ INSTANTIATE_TEST_SUITE_P(PerLayerType, SetFrameRateTest, std::make_shared<EffectLayerFactory>()), PrintToStringParamName); -TEST_F(SetFrameRateTest, ValidateFrameRate) { - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ALWAYS, "")); - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - - // Privileged APIs. - EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - EXPECT_FALSE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - - constexpr bool kPrivileged = true; - EXPECT_TRUE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "", - kPrivileged)); - EXPECT_TRUE(ValidateFrameRate(0.0f, ANATIVEWINDOW_FRAME_RATE_NO_VOTE, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "", - kPrivileged)); - - // Invalid frame rate. - EXPECT_FALSE(ValidateFrameRate(-1, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - EXPECT_FALSE(ValidateFrameRate(1.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - EXPECT_FALSE(ValidateFrameRate(0.0f / 0.0f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT, - ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - - // Invalid compatibility. - EXPECT_FALSE( - ValidateFrameRate(60.0f, -1, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - EXPECT_FALSE(ValidateFrameRate(60.0f, 2, ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS, "")); - - // Invalid change frame rate strategy. - EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, -1, "")); - EXPECT_FALSE(ValidateFrameRate(60.0f, ANATIVEWINDOW_FRAME_RATE_EXACT, 2, "")); -} - TEST_P(SetFrameRateTest, SetOnParentActivatesTree) { const auto& layerFactory = GetParam(); diff --git a/services/surfaceflinger/tests/utils/WindowInfosListenerUtils.h b/services/surfaceflinger/tests/utils/WindowInfosListenerUtils.h index 8e28a75ed4..11723c7509 100644 --- a/services/surfaceflinger/tests/utils/WindowInfosListenerUtils.h +++ b/services/surfaceflinger/tests/utils/WindowInfosListenerUtils.h @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <android-base/properties.h> #include <gtest/gtest.h> #include <gui/SurfaceComposerClient.h> #include <private/android_filesystem_config.h> @@ -21,7 +22,8 @@ #include <future> namespace android { -using Transaction = SurfaceComposerClient::Transaction; + +using base::HwTimeoutMultiplier; using gui::DisplayInfo; using gui::WindowInfo; @@ -36,7 +38,8 @@ public: auto listener = sp<WindowInfosListener>::make(std::move(predicate), promise); mClient->addWindowInfosListener(listener); auto future = promise.get_future(); - bool satisfied = future.wait_for(std::chrono::seconds{1}) == std::future_status::ready; + bool satisfied = future.wait_for(std::chrono::seconds{5 * HwTimeoutMultiplier()}) == + std::future_status::ready; mClient->removeWindowInfosListener(listener); return satisfied; } diff --git a/vulkan/vkjson/Android.bp b/vulkan/vkjson/Android.bp index b544245a7a..de4271d47d 100644 --- a/vulkan/vkjson/Android.bp +++ b/vulkan/vkjson/Android.bp @@ -7,8 +7,19 @@ package { default_applicable_licenses: ["frameworks_native_license"], } -cc_library_shared { +cc_defaults { + name: "libvkjson_deps", + shared_libs: [ + "libjsoncpp", + "libvulkan", + ], +} + +cc_library_static { name: "libvkjson", + defaults: [ + "libvkjson_deps", + ], srcs: [ "vkjson.cc", "vkjson_instance.cc", @@ -24,10 +35,6 @@ cc_library_shared { export_include_dirs: [ ".", ], - shared_libs: [ - "libjsoncpp", - "libvulkan", - ], export_shared_lib_headers: [ "libvulkan", ], |