diff options
39 files changed, 542 insertions, 257 deletions
diff --git a/aidl/gui/android/view/Surface.aidl b/aidl/gui/android/view/Surface.aidl index 7e892205d5..bb3faaff79 100644 --- a/aidl/gui/android/view/Surface.aidl +++ b/aidl/gui/android/view/Surface.aidl @@ -17,4 +17,4 @@ package android.view; -parcelable Surface cpp_header "gui/view/Surface.h"; +@JavaOnlyStableParcelable @NdkOnlyStableParcelable parcelable Surface cpp_header "gui/view/Surface.h" ndk_header "android/native_window_aidl.h"; diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp index 6fe4fcd876..43a309409d 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp +++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/Android.bp @@ -14,6 +14,8 @@ rust_bindgen { "--size_t-is-usize", "--allowlist-function", "createRandomParcel", + "--allowlist-function", + "fuzzRustService", ], shared_libs: [ "libc++", diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs index ee3b6f813a..1bbd6742f2 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs +++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/src/lib.rs @@ -16,7 +16,8 @@ use binder::binder_impl::Parcel; use binder::unstable_api::{AParcel, AsNative}; -use binder_random_parcel_bindgen::createRandomParcel; +use binder::SpIBinder; +use binder_random_parcel_bindgen::{createRandomParcel, fuzzRustService}; use std::os::raw::c_void; /// This API creates a random parcel to be used by fuzzers @@ -31,3 +32,13 @@ pub fn create_random_parcel(fuzzer_data: &[u8]) -> Parcel { } parcel } + +/// This API automatically fuzzes provided service +pub fn fuzz_service(binder: &mut SpIBinder, fuzzer_data: &[u8]) { + let ptr = binder.as_native_mut() as *mut c_void; + unsafe { + // Safety: `SpIBinder::as_native_mut` and `slice::as_ptr` always + // return valid pointers. + fuzzRustService(ptr, fuzzer_data.as_ptr(), fuzzer_data.len()); + } +} diff --git a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp index 167a64e548..831bd5660c 100644 --- a/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp +++ b/libs/binder/rust/tests/parcel_fuzzer/random_parcel/wrappers/RandomParcelWrapper.hpp @@ -19,4 +19,7 @@ extern "C" { // This API is used by rust to fill random parcel. void createRandomParcel(void* aParcel, const uint8_t* data, size_t len); + + // This API is used by fuzzers to automatically fuzz aidl services + void fuzzRustService(void* binder, const uint8_t* data, size_t len); }
\ No newline at end of file diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp index 462ef9a5e9..a1fb70131e 100644 --- a/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp +++ b/libs/binder/tests/parcel_fuzzer/libbinder_ndk_driver.cpp @@ -29,3 +29,12 @@ void fuzzService(AIBinder* binder, FuzzedDataProvider&& provider) { } } // namespace android + +extern "C" { +// This API is used by fuzzers to automatically fuzz aidl services +void fuzzRustService(void* binder, const uint8_t* data, size_t len) { + AIBinder* aiBinder = static_cast<AIBinder*>(binder); + FuzzedDataProvider provider(data, len); + android::fuzzService(aiBinder, std::move(provider)); +} +} // extern "C" diff --git a/libs/gui/fuzzer/Android.bp b/libs/gui/fuzzer/Android.bp index cdc9376a44..1c61d6bb8b 100644 --- a/libs/gui/fuzzer/Android.bp +++ b/libs/gui/fuzzer/Android.bp @@ -46,7 +46,7 @@ cc_defaults { "android.hardware.configstore-utils", "android.hardware.graphics.bufferqueue@1.0", "android.hardware.graphics.bufferqueue@2.0", - "android.hardware.power-V2-cpp", + "android.hardware.power-V4-cpp", "android.hidl.token@1.0", "libSurfaceFlingerProp", "libgui", diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h index 1f19f4e1da..7aec0bf09d 100644 --- a/libs/gui/include/gui/Surface.h +++ b/libs/gui/include/gui/Surface.h @@ -113,6 +113,24 @@ public: return surface != nullptr && surface->getIGraphicBufferProducer() != nullptr; } + static sp<IGraphicBufferProducer> getIGraphicBufferProducer(ANativeWindow* window) { + int val; + if (window->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &val) >= 0 && + val == NATIVE_WINDOW_SURFACE) { + return ((Surface*) window)->mGraphicBufferProducer; + } + return nullptr; + } + + static sp<IBinder> getSurfaceControlHandle(ANativeWindow* window) { + int val; + if (window->query(window, NATIVE_WINDOW_CONCRETE_TYPE, &val) >= 0 && + val == NATIVE_WINDOW_SURFACE) { + return ((Surface*) window)->mSurfaceControlHandle; + } + return nullptr; + } + /* Attaches a sideband buffer stream to the Surface's IGraphicBufferProducer. * * A sideband stream is a device-specific mechanism for passing buffers diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp index b0750809f8..c345385839 100644 --- a/libs/nativewindow/ANativeWindow.cpp +++ b/libs/nativewindow/ANativeWindow.cpp @@ -20,10 +20,15 @@ // from nativewindow/includes/system/window.h // (not to be confused with the compatibility-only window.h from system/core/includes) #include <system/window.h> +#include <android/native_window_aidl.h> #include <private/android/AHardwareBufferHelpers.h> +#include <log/log.h> #include <ui/GraphicBuffer.h> +#include <gui/Surface.h> +#include <gui/view/Surface.h> +#include <android/binder_libbinder.h> using namespace android; @@ -59,6 +64,13 @@ static bool isDataSpaceValid(ANativeWindow* window, int32_t dataSpace) { return false; } } +static sp<IGraphicBufferProducer> IGraphicBufferProducer_from_ANativeWindow(ANativeWindow* window) { + return Surface::getIGraphicBufferProducer(window); +} + +static sp<IBinder> SurfaceControlHandle_from_ANativeWindow(ANativeWindow* window) { + return Surface::getSurfaceControlHandle(window); +} /************************************************************************************************** * NDK @@ -350,6 +362,42 @@ int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation return native_window_set_auto_prerotation(window, autoPrerotation); } +binder_status_t ANativeWindow_readFromParcel( + const AParcel* _Nonnull parcel, ANativeWindow* _Nullable* _Nonnull outWindow) { + const Parcel* nativeParcel = AParcel_viewPlatformParcel(parcel); + + // Use a android::view::Surface to unparcel the window + std::shared_ptr<android::view::Surface> shimSurface = std::shared_ptr<android::view::Surface>(); + status_t ret = shimSurface->readFromParcel(nativeParcel); + if (ret != OK) { + ALOGE("%s: Error: Failed to create android::view::Surface from AParcel", __FUNCTION__); + return STATUS_BAD_VALUE; + } + sp<Surface> surface = sp<Surface>::make( + shimSurface->graphicBufferProducer, false, shimSurface->surfaceControlHandle); + ANativeWindow* anw = surface.get(); + ANativeWindow_acquire(anw); + *outWindow = anw; + return STATUS_OK; +} + +binder_status_t ANativeWindow_writeToParcel( + ANativeWindow* _Nonnull window, AParcel* _Nonnull parcel) { + int value; + int err = (*window->query)(window, NATIVE_WINDOW_CONCRETE_TYPE, &value); + if (err != OK || value != NATIVE_WINDOW_SURFACE) { + ALOGE("Error: ANativeWindow is not backed by Surface"); + return STATUS_BAD_VALUE; + } + // Use a android::view::Surface to parcelize the window + std::shared_ptr<android::view::Surface> shimSurface = std::shared_ptr<android::view::Surface>(); + shimSurface->graphicBufferProducer = IGraphicBufferProducer_from_ANativeWindow(window); + shimSurface->surfaceControlHandle = SurfaceControlHandle_from_ANativeWindow(window); + + Parcel* nativeParcel = AParcel_viewPlatformParcel(parcel); + return shimSurface->writeToParcel(nativeParcel); +} + /************************************************************************************************** * apex-stable **************************************************************************************************/ diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp index 3b58265440..bc0bfc52d5 100644 --- a/libs/nativewindow/Android.bp +++ b/libs/nativewindow/Android.bp @@ -110,9 +110,11 @@ cc_library { static_libs: [ "libarect", "libgrallocusage", + "libgui_aidl_static", ], header_libs: [ + "libgui_headers", "libarect_headers", "libnativebase_headers", "libnativewindow_headers", diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h index 281ec52528..a27e3dd503 100644 --- a/libs/nativewindow/include/android/native_window.h +++ b/libs/nativewindow/include/android/native_window.h @@ -376,7 +376,7 @@ int32_t ANativeWindow_clearFrameRate(ANativeWindow* window) __INTRODUCED_IN(__ANDROID_API_U__); #ifdef __cplusplus -}; +} #endif #endif // ANDROID_NATIVE_WINDOW_H diff --git a/libs/nativewindow/include/android/native_window_aidl.h b/libs/nativewindow/include/android/native_window_aidl.h new file mode 100644 index 0000000000..a252245a10 --- /dev/null +++ b/libs/nativewindow/include/android/native_window_aidl.h @@ -0,0 +1,161 @@ +/* + * 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. + */ + +/** + * @file native_window_aidl.h + * @brief NativeWindow NDK AIDL glue code + */ + +/** + * @addtogroup ANativeWindow + * + * Parcelable support for ANativeWindow. Can be used with libbinder_ndk + * + * @{ + */ + +#ifndef ANDROID_NATIVE_WINDOW_AIDL_H +#define ANDROID_NATIVE_WINDOW_AIDL_H + +#include <android/binder_parcel.h> +#include <android/native_window.h> +#include <sys/cdefs.h> + +__BEGIN_DECLS + +/** + * Read an ANativeWindow from a AParcel. The output buffer will have an + * initial reference acquired and will need to be released with + * ANativeWindow_release. + * + * Available since API level 34. + * + * \return STATUS_OK on success + * STATUS_BAD_VALUE if the parcel or outBuffer is null, or if there's an + * issue deserializing (eg, corrupted parcel) + * STATUS_BAD_TYPE if the parcel's current data position is not that of + * an ANativeWindow type + * STATUS_NO_MEMORY if an allocation fails + */ +binder_status_t ANativeWindow_readFromParcel(const AParcel* _Nonnull parcel, + ANativeWindow* _Nullable* _Nonnull outWindow) __INTRODUCED_IN(__ANDROID_API_U__); + +/** + * Write an ANativeWindow to an AParcel. + * + * Available since API level 34. + * + * \return STATUS_OK on success. + * STATUS_BAD_VALUE if either buffer or parcel is null, or if the ANativeWindow* + * fails to serialize (eg, internally corrupted) + * STATUS_NO_MEMORY if the parcel runs out of space to store the buffer & is + * unable to allocate more + * STATUS_FDS_NOT_ALLOWED if the parcel does not allow storing FDs + */ +binder_status_t ANativeWindow_writeToParcel(ANativeWindow* _Nonnull window, + AParcel* _Nonnull parcel) __INTRODUCED_IN(__ANDROID_API_U__); + +__END_DECLS + +// Only enable the AIDL glue helper if this is C++ +#ifdef __cplusplus + +namespace aidl::android::hardware { + +/** + * Wrapper class that enables interop with AIDL NDK generation + * Takes ownership of the ANativeWindow* given to it in reset() and will automatically + * destroy it in the destructor, similar to a smart pointer container + */ +class NativeWindow { +public: + NativeWindow() noexcept {} + explicit NativeWindow(ANativeWindow* _Nullable window) { + reset(window); + } + + explicit NativeWindow(NativeWindow&& other) noexcept { + mWindow = other.release(); // steal ownership from r-value + } + + ~NativeWindow() { + reset(); + } + + binder_status_t readFromParcel(const AParcel* _Nonnull parcel) { + reset(); + return ANativeWindow_readFromParcel(parcel, &mWindow); + } + + binder_status_t writeToParcel(AParcel* _Nonnull parcel) const { + if (!mWindow) { + return STATUS_BAD_VALUE; + } + return ANativeWindow_writeToParcel(mWindow, parcel); + } + + /** + * Destroys any currently owned ANativeWindow* and takes ownership of the given + * ANativeWindow* + * + * @param buffer The buffer to take ownership of + */ + void reset(ANativeWindow* _Nullable window = nullptr) noexcept { + if (mWindow) { + ANativeWindow_release(mWindow); + mWindow = nullptr; + } + if (window != nullptr) { + ANativeWindow_acquire(window); + } + mWindow = window; + } + inline ANativeWindow* _Nullable operator-> () const { return mWindow; } + inline ANativeWindow* _Nullable get() const { return mWindow; } + inline explicit operator bool () const { return mWindow != nullptr; } + + NativeWindow& operator=(NativeWindow&& other) noexcept { + mWindow = other.release(); // steal ownership from r-value + return *this; + } + + /** + * Stops managing any contained ANativeWindow*, returning it to the caller. Ownership + * is released. + * @return ANativeWindow* or null if this was empty + */ + [[nodiscard]] ANativeWindow* _Nullable release() noexcept { + ANativeWindow* _Nullable ret = mWindow; + mWindow = nullptr; + return ret; + } +private: + ANativeWindow* _Nullable mWindow = nullptr; + NativeWindow(const NativeWindow &other) = delete; + NativeWindow& operator=(const NativeWindow &other) = delete; +}; + +} // aidl::android::hardware + // +namespace aidl::android::view { + using Surface = aidl::android::hardware::NativeWindow; +} + +#endif // __cplusplus + +#endif // ANDROID_NATIVE_WINDOW_AIDL_H + +/** @} */ diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt index ce108b6096..76d23fab1d 100644 --- a/libs/nativewindow/libnativewindow.map.txt +++ b/libs/nativewindow/libnativewindow.map.txt @@ -57,6 +57,8 @@ LIBNATIVEWINDOW { ANativeWindow_setUsage; # llndk ANativeWindow_tryAllocateBuffers; # introduced=30 ANativeWindow_unlockAndPost; + ANativeWindow_readFromParcel; # introduced=UpsideDownCake + ANativeWindow_writeToParcel; # introduced=UpsideDownCake local: *; }; diff --git a/libs/renderengine/RenderEngine.cpp b/libs/renderengine/RenderEngine.cpp index 9d9cb6b2bc..f1fc0a45ad 100644 --- a/libs/renderengine/RenderEngine.cpp +++ b/libs/renderengine/RenderEngine.cpp @@ -19,6 +19,7 @@ #include <cutils/properties.h> #include <log/log.h> #include "gl/GLESRenderEngine.h" +#include "renderengine/ExternalTexture.h" #include "threaded/RenderEngineThreaded.h" #include "skia/SkiaGLRenderEngine.h" @@ -70,10 +71,22 @@ ftl::Future<FenceResult> RenderEngine::drawLayers(const DisplaySettings& display base::unique_fd&& bufferFence) { const auto resultPromise = std::make_shared<std::promise<FenceResult>>(); std::future<FenceResult> resultFuture = resultPromise->get_future(); + updateProtectedContext(layers, buffer); drawLayersInternal(std::move(resultPromise), display, layers, buffer, useFramebufferCache, std::move(bufferFence)); return resultFuture; } +void RenderEngine::updateProtectedContext(const std::vector<LayerSettings>& layers, + const std::shared_ptr<ExternalTexture>& buffer) { + const bool needsProtectedContext = + (buffer && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED)) || + std::any_of(layers.begin(), layers.end(), [](const LayerSettings& layer) { + const std::shared_ptr<ExternalTexture>& buffer = layer.source.buffer.buffer; + return buffer && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED); + }); + useProtectedContext(needsProtectedContext); +} + } // namespace renderengine } // namespace android diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h index 1ee5cbaa3d..1b3492154b 100644 --- a/libs/renderengine/gl/GLESRenderEngine.h +++ b/libs/renderengine/gl/GLESRenderEngine.h @@ -61,7 +61,7 @@ public: std::future<void> primeCache() override; void genTextures(size_t count, uint32_t* names) override; void deleteTextures(size_t count, uint32_t const* names) override; - bool isProtected() const override { return mInProtectedContext; } + bool isProtected() const { return mInProtectedContext; } bool supportsProtectedContent() const override; void useProtectedContext(bool useProtectedContext) override; void cleanupPostRender() override; diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h index 199392c160..9182febbe0 100644 --- a/libs/renderengine/include/renderengine/RenderEngine.h +++ b/libs/renderengine/include/renderengine/RenderEngine.h @@ -126,12 +126,8 @@ public: // ----- BEGIN NEW INTERFACE ----- // queries that are required to be thread safe - virtual bool isProtected() const = 0; virtual bool supportsProtectedContent() const = 0; - // Attempt to switch RenderEngine into and out of protectedContext mode - virtual void useProtectedContext(bool useProtectedContext) = 0; - // Notify RenderEngine of changes to the dimensions of the active display // so that it can configure its internal caches accordingly. virtual void onActiveDisplaySizeChanged(ui::Size size) = 0; @@ -238,6 +234,13 @@ protected: friend class RenderEngineTest_cleanupPostRender_cleansUpOnce_Test; const RenderEngineType mRenderEngineType; + // Update protectedContext mode depending on whether or not any layer has a protected buffer. + void updateProtectedContext(const std::vector<LayerSettings>&, + const std::shared_ptr<ExternalTexture>&); + + // Attempt to switch RenderEngine into and out of protectedContext mode + virtual void useProtectedContext(bool useProtectedContext) = 0; + virtual void drawLayersInternal( const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, const DisplaySettings& display, const std::vector<LayerSettings>& layers, diff --git a/libs/renderengine/skia/SkiaRenderEngine.h b/libs/renderengine/skia/SkiaRenderEngine.h index e7c5b8f0ab..1973c7d065 100644 --- a/libs/renderengine/skia/SkiaRenderEngine.h +++ b/libs/renderengine/skia/SkiaRenderEngine.h @@ -68,7 +68,6 @@ public: std::future<void> primeCache() override final; void cleanupPostRender() override final; void cleanFramebufferCache() override final{ } - bool isProtected() const override final{ return mInProtectedContext; } bool supportsBackgroundBlur() override final { return mBlurFilter != nullptr; } @@ -102,6 +101,8 @@ protected: size_t getMaxViewportDims() const override final; GrDirectContext* getActiveGrContext(); + bool isProtected() const { return mInProtectedContext; } + // Implements PersistentCache as a way to monitor what SkSL shaders Skia has // cached. class SkSLCacheMonitor : public GrContextOptions::PersistentCache { diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp index 1a96289bc0..fe3a16d4bf 100644 --- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp +++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp @@ -17,8 +17,10 @@ #include <cutils/properties.h> #include <gmock/gmock.h> #include <gtest/gtest.h> +#include <hardware/gralloc.h> #include <renderengine/impl/ExternalTexture.h> #include <renderengine/mock/RenderEngine.h> +#include <ui/PixelFormat.h> #include "../threaded/RenderEngineThreaded.h" namespace android { @@ -95,18 +97,6 @@ TEST_F(RenderEngineThreadedTest, getMaxViewportDims_returns0) { ASSERT_EQ(dims, result); } -TEST_F(RenderEngineThreadedTest, isProtected_returnsFalse) { - EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(false)); - status_t result = mThreadedRE->isProtected(); - ASSERT_EQ(false, result); -} - -TEST_F(RenderEngineThreadedTest, isProtected_returnsTrue) { - EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(true)); - size_t result = mThreadedRE->isProtected(); - ASSERT_EQ(true, result); -} - TEST_F(RenderEngineThreadedTest, supportsProtectedContent_returnsFalse) { EXPECT_CALL(*mRenderEngine, supportsProtectedContent()).WillOnce(Return(false)); status_t result = mThreadedRE->supportsProtectedContent(); @@ -119,28 +109,6 @@ TEST_F(RenderEngineThreadedTest, supportsProtectedContent_returnsTrue) { ASSERT_EQ(true, result); } -TEST_F(RenderEngineThreadedTest, useProtectedContext) { - EXPECT_CALL(*mRenderEngine, useProtectedContext(true)); - auto& ipExpect = EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(false)); - EXPECT_CALL(*mRenderEngine, supportsProtectedContent()).WillOnce(Return(true)); - EXPECT_CALL(*mRenderEngine, isProtected()).After(ipExpect).WillOnce(Return(true)); - - mThreadedRE->useProtectedContext(true); - ASSERT_EQ(true, mThreadedRE->isProtected()); - - // call ANY synchronous function to ensure that useProtectedContext has completed. - mThreadedRE->getContextPriority(); - ASSERT_EQ(true, mThreadedRE->isProtected()); -} - -TEST_F(RenderEngineThreadedTest, useProtectedContext_quickReject) { - EXPECT_CALL(*mRenderEngine, useProtectedContext(false)).Times(0); - EXPECT_CALL(*mRenderEngine, isProtected()).WillOnce(Return(false)); - mThreadedRE->useProtectedContext(false); - // call ANY synchronous function to ensure that useProtectedContext has completed. - mThreadedRE->getContextPriority(); -} - TEST_F(RenderEngineThreadedTest, PostRenderCleanup_skipped) { EXPECT_CALL(*mRenderEngine, canSkipPostRenderCleanup()).WillOnce(Return(true)); EXPECT_CALL(*mRenderEngine, cleanupPostRender()).Times(0); @@ -182,6 +150,68 @@ TEST_F(RenderEngineThreadedTest, drawLayers) { base::unique_fd bufferFence; + EXPECT_CALL(*mRenderEngine, useProtectedContext(false)); + EXPECT_CALL(*mRenderEngine, drawLayersInternal) + .WillOnce([&](const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const renderengine::DisplaySettings&, + const std::vector<renderengine::LayerSettings>&, + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&) { resultPromise->set_value(Fence::NO_FENCE); }); + + ftl::Future<FenceResult> future = + mThreadedRE->drawLayers(settings, layers, buffer, false, std::move(bufferFence)); + ASSERT_TRUE(future.valid()); + auto result = future.get(); + ASSERT_TRUE(result.ok()); +} + +TEST_F(RenderEngineThreadedTest, drawLayers_protectedLayer) { + renderengine::DisplaySettings settings; + auto layerBuffer = sp<GraphicBuffer>::make(); + layerBuffer->usage |= GRALLOC_USAGE_PROTECTED; + renderengine::LayerSettings layer; + layer.source.buffer.buffer = std::make_shared< + renderengine::impl::ExternalTexture>(std::move(layerBuffer), *mRenderEngine, + renderengine::impl::ExternalTexture::Usage:: + READABLE); + std::vector<renderengine::LayerSettings> layers = {std::move(layer)}; + std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared< + renderengine::impl:: + ExternalTexture>(sp<GraphicBuffer>::make(), *mRenderEngine, + renderengine::impl::ExternalTexture::Usage::READABLE | + renderengine::impl::ExternalTexture::Usage::WRITEABLE); + + base::unique_fd bufferFence; + + EXPECT_CALL(*mRenderEngine, useProtectedContext(true)); + EXPECT_CALL(*mRenderEngine, drawLayersInternal) + .WillOnce([&](const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, + const renderengine::DisplaySettings&, + const std::vector<renderengine::LayerSettings>&, + const std::shared_ptr<renderengine::ExternalTexture>&, const bool, + base::unique_fd&&) { resultPromise->set_value(Fence::NO_FENCE); }); + + ftl::Future<FenceResult> future = + mThreadedRE->drawLayers(settings, layers, buffer, false, std::move(bufferFence)); + ASSERT_TRUE(future.valid()); + auto result = future.get(); + ASSERT_TRUE(result.ok()); +} + +TEST_F(RenderEngineThreadedTest, drawLayers_protectedOutputBuffer) { + renderengine::DisplaySettings settings; + std::vector<renderengine::LayerSettings> layers; + auto graphicBuffer = sp<GraphicBuffer>::make(); + graphicBuffer->usage |= GRALLOC_USAGE_PROTECTED; + std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared< + renderengine::impl:: + ExternalTexture>(std::move(graphicBuffer), *mRenderEngine, + renderengine::impl::ExternalTexture::Usage::READABLE | + renderengine::impl::ExternalTexture::Usage::WRITEABLE); + + base::unique_fd bufferFence; + + EXPECT_CALL(*mRenderEngine, useProtectedContext(true)); EXPECT_CALL(*mRenderEngine, drawLayersInternal) .WillOnce([&](const std::shared_ptr<std::promise<FenceResult>>&& resultPromise, const renderengine::DisplaySettings&, diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp index b41e8432a9..8aa41b3e50 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.cpp +++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp @@ -90,7 +90,6 @@ void RenderEngineThreaded::threadMain(CreateInstanceFactory factory) NO_THREAD_S } mRenderEngine = factory(); - mIsProtected = mRenderEngine->isProtected(); pthread_setname_np(pthread_self(), mThreadName); @@ -255,41 +254,11 @@ size_t RenderEngineThreaded::getMaxViewportDims() const { return mRenderEngine->getMaxViewportDims(); } -bool RenderEngineThreaded::isProtected() const { - waitUntilInitialized(); - std::lock_guard lock(mThreadMutex); - return mIsProtected; -} - bool RenderEngineThreaded::supportsProtectedContent() const { waitUntilInitialized(); return mRenderEngine->supportsProtectedContent(); } -void RenderEngineThreaded::useProtectedContext(bool useProtectedContext) { - if (isProtected() == useProtectedContext || - (useProtectedContext && !supportsProtectedContent())) { - return; - } - - { - std::lock_guard lock(mThreadMutex); - mFunctionCalls.push([useProtectedContext, this](renderengine::RenderEngine& instance) { - ATRACE_NAME("REThreaded::useProtectedContext"); - instance.useProtectedContext(useProtectedContext); - if (instance.isProtected() != useProtectedContext) { - ALOGE("Failed to switch RenderEngine context."); - // reset the cached mIsProtected value to a good state, but this does not - // prevent other callers of this method and isProtected from reading the - // invalid cached value. - mIsProtected = instance.isProtected(); - } - }); - mIsProtected = useProtectedContext; - } - mCondition.notify_one(); -} - void RenderEngineThreaded::cleanupPostRender() { if (canSkipPostRenderCleanup()) { return; @@ -334,6 +303,7 @@ ftl::Future<FenceResult> RenderEngineThreaded::drawLayers( mFunctionCalls.push([resultPromise, display, layers, buffer, useFramebufferCache, fd](renderengine::RenderEngine& instance) { ATRACE_NAME("REThreaded::drawLayers"); + instance.updateProtectedContext(layers, buffer); instance.drawLayersInternal(std::move(resultPromise), display, layers, buffer, useFramebufferCache, base::unique_fd(fd)); }); diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h index bf2ebea2a0..168e2d2b06 100644 --- a/libs/renderengine/threaded/RenderEngineThreaded.h +++ b/libs/renderengine/threaded/RenderEngineThreaded.h @@ -51,9 +51,7 @@ public: size_t getMaxTextureSize() const override; size_t getMaxViewportDims() const override; - bool isProtected() const override; bool supportsProtectedContent() const override; - void useProtectedContext(bool useProtectedContext) override; void cleanupPostRender() override; ftl::Future<FenceResult> drawLayers(const DisplaySettings& display, @@ -84,6 +82,9 @@ private: void waitUntilInitialized() const; static status_t setSchedFifo(bool enabled); + // No-op. This method is only called on leaf implementations of RenderEngine. + void useProtectedContext(bool) override {} + /* ------------------------------------------------------------------------ * Threading */ @@ -107,7 +108,6 @@ private: * Render Engine */ std::unique_ptr<renderengine::RenderEngine> mRenderEngine; - std::atomic<bool> mIsProtected = false; }; } // namespace threaded } // namespace renderengine diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp index ba3d9802a1..3947cf7b9f 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp +++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp @@ -437,6 +437,10 @@ void TouchInputMapper::configureParameters() { mParameters.supportsUsi = false; getDeviceContext().getConfiguration().tryGetProperty("touch.supportsUsi", mParameters.supportsUsi); + + mParameters.enableForInactiveViewport = false; + getDeviceContext().getConfiguration().tryGetProperty("touch.enableForInactiveViewport", + mParameters.enableForInactiveViewport); } void TouchInputMapper::dumpParameters(std::string& dump) { @@ -454,6 +458,8 @@ void TouchInputMapper::dumpParameters(std::string& dump) { dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); dump += INDENT4 "Orientation: " + ftl::enum_string(mParameters.orientation) + "\n"; dump += StringPrintf(INDENT4 "SupportsUsi: %s\n", toString(mParameters.supportsUsi)); + dump += StringPrintf(INDENT4 "EnableForInactiveViewport: %s\n", + toString(mParameters.enableForInactiveViewport)); } void TouchInputMapper::configureRawPointerAxes() { @@ -824,6 +830,8 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) mDeviceMode = DeviceMode::POINTER; if (hasStylus()) { mSource |= AINPUT_SOURCE_STYLUS; + } else { + mSource |= AINPUT_SOURCE_TOUCHPAD; } } else if (isTouchScreen()) { mSource = AINPUT_SOURCE_TOUCHSCREEN; @@ -856,7 +864,7 @@ void TouchInputMapper::configureInputDevice(nsecs_t when, bool* outResetNeeded) "becomes available.", getDeviceName().c_str()); mDeviceMode = DeviceMode::DISABLED; - } else if (!newViewportOpt->isActive) { + } else if (!mParameters.enableForInactiveViewport && !newViewportOpt->isActive) { ALOGI("Disabling %s (device %i) because the associated viewport is not active", getDeviceName().c_str(), getDeviceId()); mDeviceMode = DeviceMode::DISABLED; @@ -3556,6 +3564,8 @@ std::list<NotifyArgs> TouchInputMapper::abortPointerMouse(nsecs_t when, nsecs_t std::list<NotifyArgs> TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsecs_t readTime, uint32_t policyFlags, bool down, bool hovering) { + LOG_ALWAYS_FATAL_IF(mDeviceMode != DeviceMode::POINTER, + "%s cannot be used when the device is not in POINTER mode.", __func__); std::list<NotifyArgs> out; int32_t metaState = getContext()->getGlobalMetaState(); @@ -3682,6 +3692,10 @@ std::list<NotifyArgs> TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsec if (down || hovering) { mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords); mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties); + mPointerSimple.displayId = displayId; + mPointerSimple.source = mSource; + mPointerSimple.lastCursorX = xCursorPosition; + mPointerSimple.lastCursorY = yCursorPosition; } else { mPointerSimple.reset(); } @@ -3690,10 +3704,25 @@ std::list<NotifyArgs> TouchInputMapper::dispatchPointerSimple(nsecs_t when, nsec std::list<NotifyArgs> TouchInputMapper::abortPointerSimple(nsecs_t when, nsecs_t readTime, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - return dispatchPointerSimple(when, readTime, policyFlags, false, false); + std::list<NotifyArgs> out; + if (mPointerSimple.down || mPointerSimple.hovering) { + int32_t metaState = getContext()->getGlobalMetaState(); + out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(), + mPointerSimple.source, mPointerSimple.displayId, policyFlags, + AMOTION_EVENT_ACTION_CANCEL, 0, AMOTION_EVENT_FLAG_CANCELED, + metaState, mLastRawState.buttonState, + MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, + &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, + mOrientedXPrecision, mOrientedYPrecision, + mPointerSimple.lastCursorX, mPointerSimple.lastCursorY, + mPointerSimple.downTime, + /* videoFrames */ {})); + if (mPointerController != nullptr) { + mPointerController->fade(PointerControllerInterface::Transition::GRADUAL); + } + } + mPointerSimple.reset(); + return out; } NotifyMotionArgs TouchInputMapper::dispatchMotion( diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h index 2bb9ecebe4..d5e4d5ae28 100644 --- a/services/inputflinger/reader/mapper/TouchInputMapper.h +++ b/services/inputflinger/reader/mapper/TouchInputMapper.h @@ -236,6 +236,9 @@ protected: // Whether the device supports the Universal Stylus Initiative (USI) protocol for styluses. bool supportsUsi; + + // Allows touches while the display is off. + bool enableForInactiveViewport; } mParameters; // Immutable calibration parameters in parsed form. @@ -678,6 +681,12 @@ private: // Time the pointer last went down. nsecs_t downTime; + // Values reported for the last pointer event. + uint32_t source; + int32_t displayId; + float lastCursorX; + float lastCursorY; + void reset() { currentCoords.clear(); currentProperties.clear(); @@ -686,6 +695,10 @@ private: down = false; hovering = false; downTime = 0; + source = 0; + displayId = ADISPLAY_ID_NONE; + lastCursorX = 0.f; + lastCursorY = 0.f; } } mPointerSimple; diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 0c2742fd16..ecc42ba5c2 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -5666,7 +5666,7 @@ TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsNotSpecifiedAndNot prepareAxes(POSITION); SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>(); - ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources()); + ASSERT_EQ(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, mapper.getSources()); } TEST_F(SingleTouchInputMapperTest, GetSources_WhenDeviceTypeIsTouchScreen_ReturnsTouchScreen) { @@ -9038,8 +9038,8 @@ TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) { prepareAxes(POSITION); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); - // Check source is mouse that would obtain the PointerController. - ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources()); + // Check source is a touchpad that would obtain the PointerController. + ASSERT_EQ(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, mapper.getSources()); NotifyMotionArgs motionArgs; processPosition(mapper, 100, 100); @@ -9082,6 +9082,7 @@ TEST_F(MultiTouchInputMapperTest, Process_SendsReadTime) { */ TEST_F(MultiTouchInputMapperTest, WhenViewportIsNotActive_TouchesAreDropped) { addConfigurationProperty("touch.deviceType", "touchScreen"); + // Don't set touch.enableForInactiveViewport to verify the default behavior. mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0, false /*isActive*/, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); @@ -9096,8 +9097,31 @@ TEST_F(MultiTouchInputMapperTest, WhenViewportIsNotActive_TouchesAreDropped) { mFakeListener->assertNotifyMotionWasNotCalled(); } +/** + * When the viewport is not active (isActive=false) and touch.enableForInactiveViewport is true, + * the touch mapper can process the events and the events can be delivered to the listener. + */ +TEST_F(MultiTouchInputMapperTest, WhenViewportIsNotActive_TouchesAreProcessed) { + addConfigurationProperty("touch.deviceType", "touchScreen"); + addConfigurationProperty("touch.enableForInactiveViewport", "1"); + mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, + DISPLAY_ORIENTATION_0, false /*isActive*/, UNIQUE_ID, NO_PORT, + ViewportType::INTERNAL); + configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO); + prepareAxes(POSITION); + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + + NotifyMotionArgs motionArgs; + processPosition(mapper, 100, 100); + processSync(mapper); + + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, motionArgs.action); +} + TEST_F(MultiTouchInputMapperTest, Process_DeactivateViewport_AbortTouches) { addConfigurationProperty("touch.deviceType", "touchScreen"); + addConfigurationProperty("touch.enableForInactiveViewport", "0"); mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0, true /*isActive*/, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL); @@ -10042,11 +10066,11 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchpadCapture) { ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args)); ASSERT_EQ(AMOTION_EVENT_ACTION_UP, args.action); - // non captured touchpad should be a mouse source + // A non captured touchpad should have a mouse and touchpad source. mFakePolicy->setPointerCapture(false); configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs)); - ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources()); + ASSERT_EQ(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, mapper.getSources()); } TEST_F(MultiTouchInputMapperTest, Process_UnCapturedTouchpadPointer) { @@ -10105,10 +10129,10 @@ TEST_F(MultiTouchInputMapperTest, WhenCapturedAndNotCaptured_GetSources) { mFakePolicy->setPointerCapture(false); MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); - // uncaptured touchpad should be a pointer device - ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources()); + // An uncaptured touchpad should be a pointer device, with additional touchpad source. + ASSERT_EQ(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, mapper.getSources()); - // captured touchpad should be a touchpad device + // A captured touchpad should just have a touchpad source. mFakePolicy->setPointerCapture(true); configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE); ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources()); @@ -10420,6 +10444,46 @@ TEST_F(MultiTouchPointerModeTest, TwoFingerSwipeOffsets) { ASSERT_GT(motionArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET), 0); } +TEST_F(MultiTouchPointerModeTest, WhenViewportActiveStatusChanged_PointerGestureIsReset) { + preparePointerMode(25 /*xResolution*/, 25 /*yResolution*/); + mFakeEventHub->addKey(EVENTHUB_ID, BTN_TOOL_PEN, 0, AKEYCODE_UNKNOWN, 0); + MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>(); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled()); + + // Start a stylus gesture. + processKey(mapper, BTN_TOOL_PEN, 1); + processId(mapper, FIRST_TRACKING_ID); + processPosition(mapper, 100, 200); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_DOWN), + WithSource(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS), + WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)))); + // TODO(b/257078296): Pointer mode generates extra event. + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_MOVE), + WithSource(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS), + WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)))); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); + + // Make the viewport inactive. This will put the device in disabled mode, and the ongoing stylus + // gesture should be disabled. + auto viewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL); + viewport->isActive = false; + mFakePolicy->updateViewport(*viewport); + configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL), + WithSource(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS), + WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)))); + // TODO(b/257078296): Pointer mode generates extra event. + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled( + AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL), + WithSource(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS), + WithToolType(AMOTION_EVENT_TOOL_TYPE_STYLUS)))); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled()); +} + // --- JoystickInputMapperTest --- class JoystickInputMapperTest : public InputMapperTest { diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 892c07d3e3..999c03f96b 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -49,7 +49,7 @@ cc_defaults { "android.hardware.graphics.composer@2.4", "android.hardware.power@1.0", "android.hardware.power@1.3", - "android.hardware.power-V2-cpp", + "android.hardware.power-V4-cpp", "libbase", "libbinder", "libbinder_ndk", diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp index 0ae8bf98bf..c1460cfc95 100644 --- a/services/surfaceflinger/CompositionEngine/Android.bp +++ b/services/surfaceflinger/CompositionEngine/Android.bp @@ -25,7 +25,7 @@ cc_defaults { "android.hardware.graphics.composer@2.4", "android.hardware.power@1.0", "android.hardware.power@1.3", - "android.hardware.power-V2-cpp", + "android.hardware.power-V4-cpp", "libbase", "libcutils", "libgui", diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h index 8661063e12..7c10fa57ec 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h @@ -58,7 +58,7 @@ public: virtual renderengine::RenderEngine& getRenderEngine() const = 0; virtual void setRenderEngine(renderengine::RenderEngine*) = 0; - virtual TimeStats& getTimeStats() const = 0; + virtual TimeStats* getTimeStats() const = 0; virtual void setTimeStats(const std::shared_ptr<TimeStats>&) = 0; virtual bool needsAnotherUpdate() const = 0; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h index 2af6c80f1e..c6995576a1 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h @@ -36,7 +36,7 @@ public: renderengine::RenderEngine& getRenderEngine() const override; void setRenderEngine(renderengine::RenderEngine*) override; - TimeStats& getTimeStats() const override; + TimeStats* getTimeStats() const override; void setTimeStats(const std::shared_ptr<TimeStats>&) override; bool needsAnotherUpdate() const override; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h index fc71649949..9b2387b966 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h @@ -42,7 +42,7 @@ public: MOCK_CONST_METHOD0(getRenderEngine, renderengine::RenderEngine&()); MOCK_METHOD1(setRenderEngine, void(renderengine::RenderEngine*)); - MOCK_CONST_METHOD0(getTimeStats, TimeStats&()); + MOCK_CONST_METHOD0(getTimeStats, TimeStats*()); MOCK_METHOD1(setTimeStats, void(const std::shared_ptr<TimeStats>&)); MOCK_CONST_METHOD0(needsAnotherUpdate, bool()); diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp index e42f11a9b9..15fadbc8ee 100644 --- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp +++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp @@ -72,8 +72,8 @@ void CompositionEngine::setRenderEngine(renderengine::RenderEngine* renderEngine mRenderEngine = renderEngine; } -TimeStats& CompositionEngine::getTimeStats() const { - return *mTimeStats.get(); +TimeStats* CompositionEngine::getTimeStats() const { + return mTimeStats.get(); } void CompositionEngine::setTimeStats(const std::shared_ptr<TimeStats>& timeStats) { diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 0622534491..c2b1f0679c 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -1178,15 +1178,9 @@ void Output::updateProtectedContentState() { bool needsProtected = std::any_of(layers.begin(), layers.end(), [](auto* layer) { return layer->getLayerFE().getCompositionState()->hasProtectedContent; }); - if (needsProtected != renderEngine.isProtected()) { - renderEngine.useProtectedContext(needsProtected); - } - if (needsProtected != mRenderSurface->isProtected() && - needsProtected == renderEngine.isProtected()) { + if (needsProtected != mRenderSurface->isProtected()) { mRenderSurface->setProtected(needsProtected); } - } else if (!outputState.isSecure && renderEngine.isProtected()) { - renderEngine.useProtectedContext(false); } } @@ -1340,10 +1334,13 @@ std::optional<base::unique_fd> Output::composeSurfaces( const auto fence = std::move(fenceResult).value_or(Fence::NO_FENCE); - if (auto& timeStats = getCompositionEngine().getTimeStats(); fence->isValid()) { - timeStats.recordRenderEngineDuration(renderEngineStart, std::make_shared<FenceTime>(fence)); - } else { - timeStats.recordRenderEngineDuration(renderEngineStart, systemTime()); + if (auto timeStats = getCompositionEngine().getTimeStats()) { + if (fence->isValid()) { + timeStats->recordRenderEngineDuration(renderEngineStart, + std::make_shared<FenceTime>(fence)); + } else { + timeStats->recordRenderEngineDuration(renderEngineStart, systemTime()); + } } for (auto* clientComposedLayer : clientCompositionLayersFE) { diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp index 8d99f894a6..60ed660c7a 100644 --- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp @@ -71,7 +71,7 @@ TEST_F(CompositionEngineTest, canSetRenderEngine) { TEST_F(CompositionEngineTest, canSetTimeStats) { mEngine.setTimeStats(mTimeStats); - EXPECT_EQ(mTimeStats.get(), &mEngine.getTimeStats()); + EXPECT_EQ(mTimeStats.get(), mEngine.getTimeStats()); } /* diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 514a8ff8fc..21099876f4 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -3332,8 +3332,7 @@ struct OutputComposeSurfacesTest : public testing::Test { EXPECT_CALL(mOutput, getCompositionEngine()).WillRepeatedly(ReturnRef(mCompositionEngine)); EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine)); - EXPECT_CALL(mCompositionEngine, getTimeStats()) - .WillRepeatedly(ReturnRef(*mTimeStats.get())); + EXPECT_CALL(mCompositionEngine, getTimeStats()).WillRepeatedly(Return(mTimeStats.get())); EXPECT_CALL(*mDisplayColorProfile, getHdrCapabilities()) .WillRepeatedly(ReturnRef(kHdrCapabilities)); } @@ -4010,39 +4009,11 @@ struct OutputComposeSurfacesTest_HandlesProtectedContent : public OutputComposeS Layer mLayer2; }; -TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifDisplayIsNotSecure) { - mOutput.mState.isSecure = false; - mLayer2.mLayerFEState.hasProtectedContent = true; - EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true)); - EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true)); - EXPECT_CALL(mRenderEngine, useProtectedContext(false)); - - base::unique_fd fd; - std::shared_ptr<renderengine::ExternalTexture> tex; - mOutput.updateProtectedContentState(); - mOutput.dequeueRenderBuffer(&fd, &tex); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); -} - -TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifRenderEngineDoesNotSupportIt) { - mOutput.mState.isSecure = true; - mLayer2.mLayerFEState.hasProtectedContent = true; - EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false)); - - base::unique_fd fd; - std::shared_ptr<renderengine::ExternalTexture> tex; - mOutput.updateProtectedContentState(); - mOutput.dequeueRenderBuffer(&fd, &tex); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); -} - TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNoProtectedContentLayers) { mOutput.mState.isSecure = true; mLayer2.mLayerFEState.hasProtectedContent = false; EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true)); - EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true)).WillOnce(Return(false)); EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true)); - EXPECT_CALL(mRenderEngine, useProtectedContext(false)); EXPECT_CALL(*mRenderSurface, setProtected(false)); base::unique_fd fd; @@ -4060,10 +4031,7 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifNotEnabled) { // For this test, we also check the call order of key functions. InSequence seq; - EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(false)); - EXPECT_CALL(mRenderEngine, useProtectedContext(true)); EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false)); - EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true)); EXPECT_CALL(*mRenderSurface, setProtected(true)); // Must happen after setting the protected content state. EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer)); @@ -4081,7 +4049,6 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEveryw mOutput.mState.isSecure = true; mLayer2.mLayerFEState.hasProtectedContent = true; EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true)); - EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true)); EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true)); base::unique_fd fd; @@ -4091,43 +4058,11 @@ TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledEveryw mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); } -TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifFailsToEnableInRenderEngine) { - mOutput.mState.isSecure = true; - mLayer2.mLayerFEState.hasProtectedContent = true; - EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true)); - EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(false)).WillOnce(Return(false)); - EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false)); - EXPECT_CALL(mRenderEngine, useProtectedContext(true)); - - base::unique_fd fd; - std::shared_ptr<renderengine::ExternalTexture> tex; - mOutput.updateProtectedContentState(); - mOutput.dequeueRenderBuffer(&fd, &tex); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); -} - -TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderEngine) { - mOutput.mState.isSecure = true; - mLayer2.mLayerFEState.hasProtectedContent = true; - EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true)); - EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true)).WillOnce(Return(true)); - EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(false)); - EXPECT_CALL(*mRenderSurface, setProtected(true)); - - base::unique_fd fd; - std::shared_ptr<renderengine::ExternalTexture> tex; - mOutput.updateProtectedContentState(); - mOutput.dequeueRenderBuffer(&fd, &tex); - mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs, tex, fd); -} - TEST_F(OutputComposeSurfacesTest_HandlesProtectedContent, ifAlreadyEnabledInRenderSurface) { mOutput.mState.isSecure = true; mLayer2.mLayerFEState.hasProtectedContent = true; EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true)); - EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(false)); EXPECT_CALL(*mRenderSurface, isProtected).WillOnce(Return(true)); - EXPECT_CALL(mRenderEngine, useProtectedContext(true)); base::unique_fd fd; std::shared_ptr<renderengine::ExternalTexture> tex; diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 499cee68f1..0e1b775a8c 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -94,7 +94,7 @@ void Scheduler::startTimers() { } } -void Scheduler::setRefreshRateSelector(std::shared_ptr<RefreshRateSelector> selectorPtr) { +void Scheduler::setRefreshRateSelector(RefreshRateSelectorPtr selectorPtr) { // The current RefreshRateSelector instance may outlive this call, so unbind its idle timer. { // mRefreshRateSelectorLock is not locked here to avoid the deadlock @@ -126,13 +126,12 @@ void Scheduler::setRefreshRateSelector(std::shared_ptr<RefreshRateSelector> sele mRefreshRateSelector->startIdleTimer(); } -void Scheduler::registerDisplay(sp<const DisplayDevice> display) { - if (display->isPrimary()) { - mLeaderDisplayId = display->getPhysicalId(); +void Scheduler::registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr) { + if (!mLeaderDisplayId) { + mLeaderDisplayId = displayId; } - const bool ok = mDisplays.try_emplace(display->getPhysicalId(), std::move(display)).second; - ALOGE_IF(!ok, "%s: Duplicate display", __func__); + mRefreshRateSelectors.emplace_or_replace(displayId, std::move(selectorPtr)); } void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) { @@ -140,7 +139,7 @@ void Scheduler::unregisterDisplay(PhysicalDisplayId displayId) { mLeaderDisplayId.reset(); } - mDisplays.erase(displayId); + mRefreshRateSelectors.erase(displayId); } void Scheduler::run() { @@ -711,10 +710,9 @@ auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { const auto globalSignals = makeGlobalSignals(); - for (const auto& [id, display] : mDisplays) { + for (const auto& [id, selectorPtr] : mRefreshRateSelectors) { auto rankedRefreshRates = - display->holdRefreshRateSelector() - ->getRankedRefreshRates(mPolicy.contentRequirements, globalSignals); + selectorPtr->getRankedRefreshRates(mPolicy.contentRequirements, globalSignals); for (const auto& [modePtr, score] : rankedRefreshRates.ranking) { const auto [it, inserted] = refreshRateTallies.try_emplace(modePtr->getFps(), score); @@ -733,7 +731,7 @@ auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { // Find the first refresh rate common to all displays. while (maxScoreIt != refreshRateTallies.cend() && - maxScoreIt->second.displayCount != mDisplays.size()) { + maxScoreIt->second.displayCount != mRefreshRateSelectors.size()) { ++maxScoreIt; } @@ -742,7 +740,8 @@ auto Scheduler::chooseDisplayModes() const -> DisplayModeChoiceMap { for (auto it = maxScoreIt + 1; it != refreshRateTallies.cend(); ++it) { const auto [fps, tally] = *it; - if (tally.displayCount == mDisplays.size() && tally.score > maxScoreIt->second.score) { + if (tally.displayCount == mRefreshRateSelectors.size() && + tally.score > maxScoreIt->second.score) { maxScoreIt = it; } } diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 39c41b99da..901cf74558 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -39,7 +39,6 @@ #include "Display/DisplayMap.h" #include "Display/DisplayModeRequest.h" -#include "DisplayDevice.h" #include "EventThread.h" #include "FrameRateOverrideMappings.h" #include "LayerHistory.h" @@ -107,10 +106,11 @@ public: virtual ~Scheduler(); void startTimers(); - void setRefreshRateSelector(std::shared_ptr<RefreshRateSelector>) - EXCLUDES(mRefreshRateSelectorLock); - void registerDisplay(sp<const DisplayDevice>); + using RefreshRateSelectorPtr = std::shared_ptr<RefreshRateSelector>; + void setRefreshRateSelector(RefreshRateSelectorPtr) EXCLUDES(mRefreshRateSelectorLock); + + void registerDisplay(PhysicalDisplayId, RefreshRateSelectorPtr); void unregisterDisplay(PhysicalDisplayId); void run(); @@ -299,8 +299,7 @@ private: EXCLUDES(mRefreshRateSelectorLock); android::impl::EventThread::GetVsyncPeriodFunction makeGetVsyncPeriodFunction() const; - std::shared_ptr<RefreshRateSelector> holdRefreshRateSelector() const - EXCLUDES(mRefreshRateSelectorLock) { + RefreshRateSelectorPtr holdRefreshRateSelector() const EXCLUDES(mRefreshRateSelectorLock) { std::scoped_lock lock(mRefreshRateSelectorLock); return mRefreshRateSelector; } @@ -336,7 +335,7 @@ private: mutable std::mutex mPolicyLock; - display::PhysicalDisplayMap<PhysicalDisplayId, sp<const DisplayDevice>> mDisplays; + display::PhysicalDisplayMap<PhysicalDisplayId, RefreshRateSelectorPtr> mRefreshRateSelectors; std::optional<PhysicalDisplayId> mLeaderDisplayId; struct Policy { @@ -359,8 +358,9 @@ private: std::optional<ModeChangedParams> cachedModeChangedParams; } mPolicy GUARDED_BY(mPolicyLock); + // TODO(b/255635821): Remove this by instead looking up the `mLeaderDisplayId` selector. mutable std::mutex mRefreshRateSelectorLock; - std::shared_ptr<RefreshRateSelector> mRefreshRateSelector GUARDED_BY(mRefreshRateSelectorLock); + RefreshRateSelectorPtr mRefreshRateSelector GUARDED_BY(mRefreshRateSelectorLock); std::mutex mVsyncTimelineLock; std::optional<hal::VsyncPeriodChangeTimeline> mLastVsyncPeriodChangeTimeline diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 89d905a4ad..53066024d0 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -2937,11 +2937,15 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken, displaySurface, producer); if (mScheduler && !display->isVirtual()) { + auto selectorPtr = display->holdRefreshRateSelector(); + // Display modes are reloaded on hotplug reconnect. if (display->isPrimary()) { - mScheduler->setRefreshRateSelector(display->holdRefreshRateSelector()); + mScheduler->setRefreshRateSelector(selectorPtr); } - mScheduler->registerDisplay(display); + + const auto displayId = display->getPhysicalId(); + mScheduler->registerDisplay(displayId, std::move(selectorPtr)); dispatchDisplayHotplugEvent(display->getPhysicalId(), true); } @@ -2994,8 +2998,6 @@ void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken, display->disconnect(); if (display->isVirtual()) { releaseVirtualDisplay(display->getVirtualId()); - } else { - mScheduler->unregisterDisplay(display->getPhysicalId()); } } @@ -3409,8 +3411,8 @@ void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) { } mScheduler->createVsyncSchedule(features); - mScheduler->setRefreshRateSelector(std::move(selectorPtr)); - mScheduler->registerDisplay(display); + mScheduler->setRefreshRateSelector(selectorPtr); + mScheduler->registerDisplay(display->getPhysicalId(), std::move(selectorPtr)); } setVsyncEnabled(false); mScheduler->startTimers(); @@ -6523,7 +6525,6 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( // Use an empty fence for the buffer fence, since we just created the buffer so // there is no need for synchronization with the GPU. base::unique_fd bufferFence; - getRenderEngine().useProtectedContext(useProtected); constexpr bool kUseFramebufferCache = false; const auto future = getRenderEngine() @@ -6535,9 +6536,6 @@ ftl::SharedFuture<FenceResult> SurfaceFlinger::renderScreenImpl( layer->onLayerDisplayed(future); } - // Always switch back to unprotected context. - getRenderEngine().useProtectedContext(false); - return future; } diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index 5daa398545..d88da4da4a 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -150,7 +150,7 @@ cc_defaults { "android.hardware.power@1.1", "android.hardware.power@1.2", "android.hardware.power@1.3", - "android.hardware.power-V2-cpp", + "android.hardware.power-V4-cpp", "libaidlcommonsupport", "libcompositionengine_mocks", "libcompositionengine", diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index 066083fffa..ea4666ed4b 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -20,7 +20,6 @@ #include <mutex> -#include "FakeDisplayInjector.h" #include "Scheduler/EventThread.h" #include "Scheduler/RefreshRateSelector.h" #include "TestableScheduler.h" @@ -41,7 +40,6 @@ namespace { using MockEventThread = android::mock::EventThread; using MockLayer = android::mock::MockLayer; -using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector; class SchedulerTest : public testing::Test { protected: @@ -90,10 +88,6 @@ protected: sp<MockEventThreadConnection> mEventThreadConnection; TestableSurfaceFlinger mFlinger; - Hwc2::mock::PowerAdvisor mPowerAdvisor; - sp<android::mock::NativeWindow> mNativeWindow = sp<android::mock::NativeWindow>::make(); - - FakeDisplayInjector mFakeDisplayInjector{mFlinger, mPowerAdvisor, mNativeWindow}; }; SchedulerTest::SchedulerTest() { @@ -240,14 +234,11 @@ MATCHER(Is120Hz, "") { } TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { - const auto display = mFakeDisplayInjector.injectInternalDisplay( - [&](FakeDisplayDeviceInjector& injector) { - injector.setDisplayModes(kDisplay1Modes, kDisplay1Mode60->getId()); - }, - {.displayId = kDisplayId1}); + const auto selectorPtr = + std::make_shared<RefreshRateSelector>(kDisplay1Modes, kDisplay1Mode60->getId()); - mScheduler->registerDisplay(display); - mScheduler->setRefreshRateSelector(display->holdRefreshRateSelector()); + mScheduler->registerDisplay(kDisplayId1, selectorPtr); + mScheduler->setRefreshRateSelector(selectorPtr); const sp<MockLayer> layer = sp<MockLayer>::make(mFlinger.flinger()); EXPECT_CALL(*layer, isVisible()).WillOnce(Return(true)); @@ -269,13 +260,9 @@ TEST_F(SchedulerTest, chooseRefreshRateForContentSelectsMaxRefreshRate) { } TEST_F(SchedulerTest, chooseDisplayModesSingleDisplay) { - const auto display = mFakeDisplayInjector.injectInternalDisplay( - [&](FakeDisplayDeviceInjector& injector) { - injector.setDisplayModes(kDisplay1Modes, kDisplay1Mode60->getId()); - }, - {.displayId = kDisplayId1}); - - mScheduler->registerDisplay(display); + mScheduler->registerDisplay(kDisplayId1, + std::make_shared<RefreshRateSelector>(kDisplay1Modes, + kDisplay1Mode60->getId())); std::vector<RefreshRateSelector::LayerRequirement> layers = std::vector<RefreshRateSelector::LayerRequirement>({{.weight = 1.f}, {.weight = 1.f}}); @@ -314,23 +301,16 @@ TEST_F(SchedulerTest, chooseDisplayModesSingleDisplay) { EXPECT_EQ(choice->get(), DisplayModeChoice(kDisplay1Mode120, globalSignals)); mScheduler->unregisterDisplay(kDisplayId1); - EXPECT_TRUE(mScheduler->mutableDisplays().empty()); + EXPECT_FALSE(mScheduler->hasRefreshRateSelectors()); } TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { - const auto display1 = mFakeDisplayInjector.injectInternalDisplay( - [&](FakeDisplayDeviceInjector& injector) { - injector.setDisplayModes(kDisplay1Modes, kDisplay1Mode60->getId()); - }, - {.displayId = kDisplayId1, .hwcDisplayId = 42, .isPrimary = true}); - const auto display2 = mFakeDisplayInjector.injectInternalDisplay( - [&](FakeDisplayDeviceInjector& injector) { - injector.setDisplayModes(kDisplay2Modes, kDisplay2Mode60->getId()); - }, - {.displayId = kDisplayId2, .hwcDisplayId = 41, .isPrimary = false}); - - mScheduler->registerDisplay(display1); - mScheduler->registerDisplay(display2); + mScheduler->registerDisplay(kDisplayId1, + std::make_shared<RefreshRateSelector>(kDisplay1Modes, + kDisplay1Mode60->getId())); + mScheduler->registerDisplay(kDisplayId2, + std::make_shared<RefreshRateSelector>(kDisplay2Modes, + kDisplay2Mode60->getId())); using DisplayModeChoice = TestableScheduler::DisplayModeChoice; TestableScheduler::DisplayModeChoiceMap expectedChoices; @@ -380,13 +360,10 @@ TEST_F(SchedulerTest, chooseDisplayModesMultipleDisplays) { } { // This display does not support 120 Hz, so we should choose 60 Hz despite the touch signal. - const auto display3 = mFakeDisplayInjector.injectInternalDisplay( - [&](FakeDisplayDeviceInjector& injector) { - injector.setDisplayModes(kDisplay3Modes, kDisplay3Mode60->getId()); - }, - {.displayId = kDisplayId3, .hwcDisplayId = 40, .isPrimary = false}); - - mScheduler->registerDisplay(display3); + mScheduler + ->registerDisplay(kDisplayId3, + std::make_shared<RefreshRateSelector>(kDisplay3Modes, + kDisplay3Mode60->getId())); const GlobalSignals globalSignals = {.touch = true}; mScheduler->replaceTouchTimer(10); diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index 2814d38b47..95c99150b3 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -32,15 +32,13 @@ namespace android::scheduler { class TestableScheduler : public Scheduler, private ICompositor { public: - TestableScheduler(std::shared_ptr<RefreshRateSelector> selectorPtr, - ISchedulerCallback& callback) + TestableScheduler(RefreshRateSelectorPtr selectorPtr, ISchedulerCallback& callback) : TestableScheduler(std::make_unique<mock::VsyncController>(), std::make_unique<mock::VSyncTracker>(), std::move(selectorPtr), callback) {} TestableScheduler(std::unique_ptr<VsyncController> controller, - std::unique_ptr<VSyncTracker> tracker, - std::shared_ptr<RefreshRateSelector> selectorPtr, + std::unique_ptr<VSyncTracker> tracker, RefreshRateSelectorPtr selectorPtr, ISchedulerCallback& callback) : Scheduler(*this, callback, Feature::kContentDetection) { mVsyncSchedule.emplace(VsyncSchedule(std::move(tracker), nullptr, std::move(controller))); @@ -68,16 +66,15 @@ public: auto& mutablePrimaryHWVsyncEnabled() { return mPrimaryHWVsyncEnabled; } auto& mutableHWVsyncAvailable() { return mHWVsyncAvailable; } - auto& mutableLayerHistory() { return mLayerHistory; } + auto refreshRateSelector() { return holdRefreshRateSelector(); } + bool hasRefreshRateSelectors() const { return !mRefreshRateSelectors.empty(); } - auto& mutableDisplays() { return mDisplays; } + auto& mutableLayerHistory() { return mLayerHistory; } size_t layerHistorySize() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mActiveLayerInfos.size() + mLayerHistory.mInactiveLayerInfos.size(); } - auto refreshRateSelector() { return holdRefreshRateSelector(); } - size_t getNumActiveLayers() NO_THREAD_SAFETY_ANALYSIS { return mLayerHistory.mActiveLayerInfos.size(); } diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index ff79ce099e..35c037c051 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -842,7 +842,8 @@ public: sp<DisplayDevice> display = sp<DisplayDevice>::make(mCreationArgs); mFlinger.mutableDisplays().emplace_or_replace(mDisplayToken, display); if (mFlinger.scheduler()) { - mFlinger.scheduler()->registerDisplay(display); + mFlinger.scheduler()->registerDisplay(display->getPhysicalId(), + display->holdRefreshRateSelector()); } DisplayDeviceState state; diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h index 439f6f4e75..5f749dfbcc 100644 --- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h +++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockIPowerHintSession.h @@ -23,6 +23,7 @@ using android::binder::Status; using android::hardware::power::IPowerHintSession; +using android::hardware::power::SessionHint; using namespace android::hardware::power; @@ -40,6 +41,7 @@ public: MOCK_METHOD(std::string, getInterfaceHash, (), (override)); MOCK_METHOD(Status, updateTargetWorkDuration, (int64_t), (override)); MOCK_METHOD(Status, reportActualWorkDuration, (const ::std::vector<WorkDuration>&), (override)); + MOCK_METHOD(Status, sendHint, (SessionHint), (override)); }; } // namespace android::Hwc2::mock |