/* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include "BufferQueueLayer.h" #include "BufferStateLayer.h" #include "ContainerLayer.h" #include "DisplayDevice.h" #include "EffectLayer.h" #include "FakeVsyncConfiguration.h" #include "FrameTracer/FrameTracer.h" #include "Layer.h" #include "NativeWindowSurface.h" #include "Scheduler/MessageQueue.h" #include "Scheduler/RefreshRateConfigs.h" #include "StartPropertySetThread.h" #include "SurfaceFlinger.h" #include "SurfaceFlingerDefaultFactory.h" #include "SurfaceInterceptor.h" #include "TestableScheduler.h" #include "mock/DisplayHardware/MockComposer.h" #include "mock/DisplayHardware/MockDisplayMode.h" #include "mock/MockFrameTimeline.h" #include "mock/MockFrameTracer.h" #include "mock/MockSchedulerCallback.h" namespace android { class EventThread; namespace renderengine { class RenderEngine; } // namespace renderengine namespace Hwc2 { class Composer; } // namespace Hwc2 namespace hal = android::hardware::graphics::composer::hal; namespace surfaceflinger::test { class Factory final : public surfaceflinger::Factory { public: ~Factory() = default; std::unique_ptr createHWComposer(const std::string&) override { return nullptr; } std::unique_ptr createVsyncConfiguration( Fps /*currentRefreshRate*/) override { return std::make_unique(); } sp createSurfaceInterceptor() override { return new android::impl::SurfaceInterceptor(); } sp createStartPropertySetThread(bool timestampPropertyValue) override { return new StartPropertySetThread(timestampPropertyValue); } sp createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) override { return new DisplayDevice(creationArgs); } sp createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, std::string requestorName) override { return new GraphicBuffer(width, height, format, layerCount, usage, requestorName); } void createBufferQueue(sp* outProducer, sp* outConsumer, bool consumerIsSurfaceFlinger) override { if (!mCreateBufferQueue) { BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger); return; } mCreateBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger); } sp createMonitoredProducer(const sp& producer, const sp& flinger, const wp& layer) override { return new MonitoredProducer(producer, flinger, layer); } sp createBufferLayerConsumer(const sp& consumer, renderengine::RenderEngine& renderEngine, uint32_t textureName, Layer* layer) override { return new BufferLayerConsumer(consumer, renderEngine, textureName, layer); } std::unique_ptr createNativeWindowSurface( const sp& producer) override { if (!mCreateNativeWindowSurface) return nullptr; return mCreateNativeWindowSurface(producer); } std::unique_ptr createCompositionEngine() override { return compositionengine::impl::createCompositionEngine(); } sp createBufferQueueLayer(const LayerCreationArgs&) override { return nullptr; } sp createBufferStateLayer(const LayerCreationArgs&) override { return nullptr; } sp createEffectLayer(const LayerCreationArgs&) override { return nullptr; } sp createContainerLayer(const LayerCreationArgs&) override { return nullptr; } std::unique_ptr createFrameTracer() override { return std::make_unique(); } std::unique_ptr createFrameTimeline( std::shared_ptr timeStats, pid_t surfaceFlingerPid = 0) override { return std::make_unique(timeStats, surfaceFlingerPid); } using CreateBufferQueueFunction = std::function* /* outProducer */, sp* /* outConsumer */, bool /* consumerIsSurfaceFlinger */)>; CreateBufferQueueFunction mCreateBufferQueue; using CreateNativeWindowSurfaceFunction = std::function( const sp&)>; CreateNativeWindowSurfaceFunction mCreateNativeWindowSurface; using CreateCompositionEngineFunction = std::function()>; CreateCompositionEngineFunction mCreateCompositionEngine; }; } // namespace surfaceflinger::test class TestableSurfaceFlinger { public: using HotplugEvent = SurfaceFlinger::HotplugEvent; TestableSurfaceFlinger(sp flinger = nullptr) : mFlinger(flinger) { if (!mFlinger) { mFlinger = sp::make(mFactory, SurfaceFlinger::SkipInitialization); } mFlinger->mAnimationTransactionTimeout = ms2ns(10); } SurfaceFlinger* flinger() { return mFlinger.get(); } scheduler::TestableScheduler* scheduler() { return mScheduler; } // Extend this as needed for accessing SurfaceFlinger private (and public) // functions. void setupRenderEngine(std::unique_ptr renderEngine) { mFlinger->mCompositionEngine->setRenderEngine(std::move(renderEngine)); } void setupComposer(std::unique_ptr composer) { mFlinger->mCompositionEngine->setHwComposer( std::make_unique(std::move(composer))); } void setupPowerAdvisor(std::unique_ptr powerAdvisor) { mFlinger->mPowerAdvisor = std::move(powerAdvisor); } void setupTimeStats(const std::shared_ptr& timeStats) { mFlinger->mCompositionEngine->setTimeStats(timeStats); } enum class SchedulerCallbackImpl { kNoOp, kMock }; static constexpr struct OneDisplayMode { } kOneDisplayMode; static constexpr struct TwoDisplayModes { } kTwoDisplayModes; using RefreshRateConfigsPtr = std::shared_ptr; using DisplayModesVariant = std::variant; void setupScheduler(std::unique_ptr vsyncController, std::unique_ptr vsyncTracker, std::unique_ptr appEventThread, std::unique_ptr sfEventThread, SchedulerCallbackImpl callbackImpl = SchedulerCallbackImpl::kNoOp, DisplayModesVariant modesVariant = kOneDisplayMode, bool useNiceMock = false) { RefreshRateConfigsPtr configs; if (std::holds_alternative(modesVariant)) { configs = std::move(std::get(modesVariant)); } else { constexpr DisplayModeId kModeId60{0}; DisplayModes modes = makeModes(mock::createDisplayMode(kModeId60, 60_Hz)); if (std::holds_alternative(modesVariant)) { constexpr DisplayModeId kModeId90{1}; modes.try_emplace(kModeId90, mock::createDisplayMode(kModeId90, 90_Hz)); } configs = std::make_shared(modes, kModeId60); } const auto fps = configs->getActiveMode()->getFps(); mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps); mFlinger->mVsyncModulator = sp::make( mFlinger->mVsyncConfiguration->getCurrentConfigs()); mFlinger->mRefreshRateStats = std::make_unique(*mFlinger->mTimeStats, fps, hal::PowerMode::OFF); using Callback = scheduler::ISchedulerCallback; Callback& callback = callbackImpl == SchedulerCallbackImpl::kNoOp ? static_cast(mNoOpSchedulerCallback) : static_cast(mSchedulerCallback); if (useNiceMock) { mScheduler = new testing::NiceMock(std::move(vsyncController), std::move(vsyncTracker), std::move(configs), callback); } else { mScheduler = new scheduler::TestableScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(configs), callback); } mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread)); mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread)); resetScheduler(mScheduler); } void resetScheduler(scheduler::Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); } scheduler::TestableScheduler& mutableScheduler() { return *mScheduler; } scheduler::mock::SchedulerCallback& mockSchedulerCallback() { return mSchedulerCallback; } auto& mutableVsyncModulator() { return mFlinger->mVsyncModulator; } using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction; void setCreateBufferQueueFunction(CreateBufferQueueFunction f) { mFactory.mCreateBufferQueue = f; } using CreateNativeWindowSurfaceFunction = surfaceflinger::test::Factory::CreateNativeWindowSurfaceFunction; void setCreateNativeWindowSurface(CreateNativeWindowSurfaceFunction f) { mFactory.mCreateNativeWindowSurface = f; } void setInternalDisplayPrimaries(const ui::DisplayPrimaries& primaries) { memcpy(&mFlinger->mInternalDisplayPrimaries, &primaries, sizeof(ui::DisplayPrimaries)); } static auto& mutableLayerDrawingState(const sp& layer) { return layer->mDrawingState; } auto& mutableStateLock() { return mFlinger->mStateLock; } static auto findOutputLayerForDisplay(const sp& layer, const sp& display) { return layer->findOutputLayerForDisplay(display.get()); } static void setLayerSidebandStream(const sp& layer, const sp& sidebandStream) { layer->mDrawingState.sidebandStream = sidebandStream; layer->mSidebandStream = sidebandStream; layer->editCompositionState()->sidebandStream = sidebandStream; } void setLayerCompositionType(const sp& layer, aidl::android::hardware::graphics::composer3::Composition type) { auto outputLayer = findOutputLayerForDisplay(layer, mFlinger->getDefaultDisplayDevice()); LOG_ALWAYS_FATAL_IF(!outputLayer); auto& state = outputLayer->editState(); LOG_ALWAYS_FATAL_IF(!outputLayer->getState().hwc); (*state.hwc).hwcCompositionType = type; } static void setLayerPotentialCursor(const sp& layer, bool potentialCursor) { layer->mPotentialCursor = potentialCursor; } static void setLayerDrawingParent(const sp& layer, const sp& drawingParent) { layer->mDrawingParent = drawingParent; } void setPowerHintSessionMode(bool early, bool late) { mFlinger->mPowerHintSessionMode = {.late = late, .early = early}; } /* ------------------------------------------------------------------------ * Forwarding for functions being tested */ nsecs_t commit(nsecs_t frameTime, int64_t vsyncId, nsecs_t expectedVSyncTime) { mFlinger->commit(frameTime, vsyncId, expectedVSyncTime); return frameTime; } nsecs_t commit(nsecs_t frameTime, int64_t vsyncId) { std::chrono::nanoseconds period = 10ms; return commit(frameTime, vsyncId, frameTime + period.count()); } nsecs_t commit() { const nsecs_t now = systemTime(); const nsecs_t expectedVsyncTime = now + 10'000'000; return commit(now, kVsyncId, expectedVsyncTime); } void commitAndComposite(const nsecs_t frameTime, const int64_t vsyncId, const nsecs_t expectedVsyncTime) { mFlinger->composite(commit(frameTime, vsyncId, expectedVsyncTime), kVsyncId); } void commitAndComposite() { mFlinger->composite(commit(), kVsyncId); } auto createDisplay(const String8& displayName, bool secure) { return mFlinger->createDisplay(displayName, secure); } auto destroyDisplay(const sp& displayToken) { return mFlinger->destroyDisplay(displayToken); } auto getDisplay(const sp& displayToken) { Mutex::Autolock lock(mFlinger->mStateLock); return mFlinger->getDisplayDeviceLocked(displayToken); } void enableHalVirtualDisplays(bool enable) { mFlinger->enableHalVirtualDisplays(enable); } auto setupNewDisplayDeviceInternal( const wp& displayToken, std::shared_ptr compositionDisplay, const DisplayDeviceState& state, const sp& dispSurface, const sp& producer) NO_THREAD_SAFETY_ANALYSIS { return mFlinger->setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state, dispSurface, producer); } auto commitTransactionsLocked(uint32_t transactionFlags) { Mutex::Autolock lock(mFlinger->mStateLock); return mFlinger->commitTransactionsLocked(transactionFlags); } void onComposerHalHotplug(hal::HWDisplayId hwcDisplayId, hal::Connection connection) { mFlinger->onComposerHalHotplug(hwcDisplayId, connection); } auto setDisplayStateLocked(const DisplayState& s) { Mutex::Autolock lock(mFlinger->mStateLock); return mFlinger->setDisplayStateLocked(s); } // Allow reading display state without locking, as if called on the SF main thread. auto onInitializeDisplays() NO_THREAD_SAFETY_ANALYSIS { return mFlinger->onInitializeDisplays(); } auto notifyPowerBoost(int32_t boostId) { return mFlinger->notifyPowerBoost(boostId); } auto setDisplayBrightness(const sp& display, const gui::DisplayBrightness& brightness) { return mFlinger->setDisplayBrightness(display, brightness); } // Allow reading display state without locking, as if called on the SF main thread. auto setPowerModeInternal(const sp& display, hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS { return mFlinger->setPowerModeInternal(display, mode); } auto renderScreenImpl(const RenderArea& renderArea, SurfaceFlinger::TraverseLayersFunction traverseLayers, const std::shared_ptr& buffer, bool forSystem, bool regionSampling) { ScreenCaptureResults captureResults; return mFlinger->renderScreenImpl(renderArea, traverseLayers, buffer, forSystem, regionSampling, false /* grayscale */, captureResults); } auto traverseLayersInLayerStack(ui::LayerStack layerStack, int32_t uid, const LayerVector::Visitor& visitor) { return mFlinger->SurfaceFlinger::traverseLayersInLayerStack(layerStack, uid, visitor); } auto getDisplayNativePrimaries(const sp& displayToken, ui::DisplayPrimaries &primaries) { return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries); } auto& getTransactionQueue() { return mFlinger->mTransactionQueue; } auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; } auto& getTransactionCommittedSignals() { return mFlinger->mTransactionCommittedSignals; } auto setTransactionState( const FrameTimelineInfo& frameTimelineInfo, const Vector& states, const Vector& displays, uint32_t flags, const sp& applyToken, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks, std::vector& listenerCallbacks, uint64_t transactionId) { return mFlinger->setTransactionState(frameTimelineInfo, states, displays, flags, applyToken, inputWindowCommands, desiredPresentTime, isAutoTimestamp, uncacheBuffer, hasListenerCallbacks, listenerCallbacks, transactionId); } auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(0); }; auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { return mFlinger->onTransact(code, data, reply, flags); } auto getGPUContextPriority() { return mFlinger->getGPUContextPriority(); } auto calculateMaxAcquiredBufferCount(Fps refreshRate, std::chrono::nanoseconds presentLatency) const { return SurfaceFlinger::calculateMaxAcquiredBufferCount(refreshRate, presentLatency); } auto setDesiredDisplayModeSpecs(const sp& displayToken, ui::DisplayModeId defaultMode, bool allowGroupSwitching, float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin, float appRequestRefreshRateMax) { return mFlinger->setDesiredDisplayModeSpecs(displayToken, defaultMode, allowGroupSwitching, primaryRefreshRateMin, primaryRefreshRateMax, appRequestRefreshRateMin, appRequestRefreshRateMax); } void onActiveDisplayChanged(const sp& activeDisplay) { Mutex::Autolock lock(mFlinger->mStateLock); mFlinger->onActiveDisplayChangedLocked(activeDisplay); } auto createLayer(LayerCreationArgs& args, sp* outHandle, const sp& parentHandle, int32_t* outLayerId, const sp& parentLayer, uint32_t* outTransformHint) { return mFlinger->createLayer(args, outHandle, parentHandle, outLayerId, parentLayer, outTransformHint); } auto mirrorLayer(const LayerCreationArgs& args, const sp& mirrorFromHandle, sp* outHandle, int32_t* outLayerId) { return mFlinger->mirrorLayer(args, mirrorFromHandle, outHandle, outLayerId); } /* ------------------------------------------------------------------------ * Read-only access to private data to assert post-conditions. */ const auto& getAnimFrameTracker() const { return mFlinger->mAnimFrameTracker; } const auto& getHasPoweredOff() const { return mFlinger->mHasPoweredOff; } const auto& getVisibleRegionsDirty() const { return mFlinger->mVisibleRegionsDirty; } auto& getHwComposer() const { return static_cast(mFlinger->getHwComposer()); } auto& getCompositionEngine() const { return mFlinger->getCompositionEngine(); } const auto& getCompositorTiming() const { return mFlinger->getBE().mCompositorTiming; } mock::FrameTracer* getFrameTracer() const { return static_cast(mFlinger->mFrameTracer.get()); } nsecs_t getAnimationTransactionTimeout() const { return mFlinger->mAnimationTransactionTimeout; } /* ------------------------------------------------------------------------ * Read-write access to private data to set up preconditions and assert * post-conditions. */ const auto& displays() const { return mFlinger->mDisplays; } const auto& currentState() const { return mFlinger->mCurrentState; } const auto& drawingState() const { return mFlinger->mDrawingState; } const auto& transactionFlags() const { return mFlinger->mTransactionFlags; } const auto& hwcPhysicalDisplayIdMap() const { return getHwComposer().mPhysicalDisplayIdMap; } auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; } auto& mutableCurrentState() { return mFlinger->mCurrentState; } auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; } auto& mutableDisplays() { return mFlinger->mDisplays; } auto& mutableDrawingState() { return mFlinger->mDrawingState; } auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; } auto& mutableInterceptor() { return mFlinger->mInterceptor; } auto& mutableMainThreadId() { return mFlinger->mMainThreadId; } auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; } auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; } auto& mutableTexturePool() { return mFlinger->mTexturePool; } auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; } auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; } auto& mutableMaxRenderTargetSize() { return mFlinger->mMaxRenderTargetSize; } auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; } auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; } auto& mutablePrimaryHwcDisplayId() { return getHwComposer().mPrimaryHwcDisplayId; } auto& mutableActiveDisplayToken() { return mFlinger->mActiveDisplayToken; } auto fromHandle(const sp& handle) { return mFlinger->fromHandle(handle); } ~TestableSurfaceFlinger() { // All these pointer and container clears help ensure that GMock does // not report a leaked object, since the SurfaceFlinger instance may // still be referenced by something despite our best efforts to destroy // it after each test is done. mutableDisplays().clear(); mutableCurrentState().displays.clear(); mutableDrawingState().displays.clear(); mutableInterceptor().clear(); mFlinger->mScheduler.reset(); mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr()); mFlinger->mCompositionEngine->setRenderEngine( std::unique_ptr()); } /* ------------------------------------------------------------------------ * Wrapper classes for Read-write access to private data to set up * preconditions and assert post-conditions. */ struct HWC2Display : public HWC2::impl::Display { HWC2Display( Hwc2::Composer& composer, const std::unordered_set& capabilities, hal::HWDisplayId id, hal::DisplayType type) : HWC2::impl::Display(composer, capabilities, id, type) {} ~HWC2Display() { // Prevents a call to disable vsyncs. mType = hal::DisplayType::INVALID; } auto& mutableIsConnected() { return this->mIsConnected; } auto& mutableLayers() { return this->mLayers; } }; class FakeHwcDisplayInjector { public: static constexpr hal::HWDisplayId DEFAULT_HWC_DISPLAY_ID = 1000; static constexpr ui::Size DEFAULT_RESOLUTION{1920, 1280}; static constexpr int32_t DEFAULT_VSYNC_PERIOD = 16'666'667; static constexpr int32_t DEFAULT_CONFIG_GROUP = 7; static constexpr int32_t DEFAULT_DPI = 320; static constexpr hal::HWConfigId DEFAULT_ACTIVE_CONFIG = 0; static constexpr hal::PowerMode DEFAULT_POWER_MODE = hal::PowerMode::ON; FakeHwcDisplayInjector(HalDisplayId displayId, hal::DisplayType hwcDisplayType, bool isPrimary) : mDisplayId(displayId), mHwcDisplayType(hwcDisplayType), mIsPrimary(isPrimary) {} auto& setHwcDisplayId(hal::HWDisplayId displayId) { mHwcDisplayId = displayId; return *this; } auto& setResolution(ui::Size resolution) { mResolution = resolution; return *this; } auto& setVsyncPeriod(nsecs_t vsyncPeriod) { mVsyncPeriod = vsyncPeriod; return *this; } auto& setDpiX(int32_t dpi) { mDpiX = dpi; return *this; } auto& setDpiY(int32_t dpi) { mDpiY = dpi; return *this; } auto& setActiveConfig(hal::HWConfigId config) { mActiveConfig = config; return *this; } auto& setCapabilities( const std::unordered_set* capabilities) { mCapabilities = capabilities; return *this; } auto& setPowerMode(hal::PowerMode mode) { mPowerMode = mode; return *this; } void inject(TestableSurfaceFlinger* flinger, Hwc2::mock::Composer* composer) { using ::testing::_; using ::testing::DoAll; using ::testing::Return; using ::testing::SetArgPointee; static const std::unordered_set< aidl::android::hardware::graphics::composer3::Capability> defaultCapabilities; if (mCapabilities == nullptr) mCapabilities = &defaultCapabilities; // Caution - Make sure that any values passed by reference here do // not refer to an instance owned by FakeHwcDisplayInjector. This // class has temporary lifetime, while the constructed HWC2::Display // is much longer lived. auto display = std::make_unique(*composer, *mCapabilities, mHwcDisplayId, mHwcDisplayType); display->mutableIsConnected() = true; display->setPowerMode(mPowerMode); flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = std::move(display); EXPECT_CALL(*composer, getDisplayConfigs(mHwcDisplayId, _)) .WillRepeatedly( DoAll(SetArgPointee<1>(std::vector{mActiveConfig}), Return(hal::Error::NONE))); EXPECT_CALL(*composer, getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::WIDTH, _)) .WillRepeatedly(DoAll(SetArgPointee<3>(mResolution.getWidth()), Return(hal::Error::NONE))); EXPECT_CALL(*composer, getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::HEIGHT, _)) .WillRepeatedly(DoAll(SetArgPointee<3>(mResolution.getHeight()), Return(hal::Error::NONE))); EXPECT_CALL(*composer, getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::VSYNC_PERIOD, _)) .WillRepeatedly(DoAll(SetArgPointee<3>(static_cast(mVsyncPeriod)), Return(hal::Error::NONE))); EXPECT_CALL(*composer, getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::DPI_X, _)) .WillRepeatedly(DoAll(SetArgPointee<3>(mDpiX), Return(hal::Error::NONE))); EXPECT_CALL(*composer, getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::DPI_Y, _)) .WillRepeatedly(DoAll(SetArgPointee<3>(mDpiY), Return(hal::Error::NONE))); EXPECT_CALL(*composer, getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::CONFIG_GROUP, _)) .WillRepeatedly( DoAll(SetArgPointee<3>(mConfigGroup), Return(hal::Error::NONE))); if (mHwcDisplayType == hal::DisplayType::PHYSICAL) { const auto physicalId = PhysicalDisplayId::tryCast(mDisplayId); LOG_ALWAYS_FATAL_IF(!physicalId); flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, *physicalId); if (mIsPrimary) { flinger->mutablePrimaryHwcDisplayId() = mHwcDisplayId; } else { // If there is an external HWC display, there should always be a primary ID // as well. Set it to some arbitrary value. auto& primaryId = flinger->mutablePrimaryHwcDisplayId(); if (!primaryId) primaryId = mHwcDisplayId - 1; } } } private: const HalDisplayId mDisplayId; const hal::DisplayType mHwcDisplayType; const bool mIsPrimary; hal::HWDisplayId mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID; ui::Size mResolution = DEFAULT_RESOLUTION; nsecs_t mVsyncPeriod = DEFAULT_VSYNC_PERIOD; int32_t mDpiX = DEFAULT_DPI; int32_t mDpiY = DEFAULT_DPI; int32_t mConfigGroup = DEFAULT_CONFIG_GROUP; hal::HWConfigId mActiveConfig = DEFAULT_ACTIVE_CONFIG; hal::PowerMode mPowerMode = DEFAULT_POWER_MODE; const std::unordered_set* mCapabilities = nullptr; }; class FakeDisplayDeviceInjector { public: FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, std::shared_ptr display, std::optional connectionType, std::optional hwcDisplayId, bool isPrimary) : mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), flinger.mFlinger->getHwComposer(), mDisplayToken, display), mHwcDisplayId(hwcDisplayId) { mCreationArgs.connectionType = connectionType; mCreationArgs.isPrimary = isPrimary; mCreationArgs.initialPowerMode = hal::PowerMode::ON; } sp token() const { return mDisplayToken; } DisplayDeviceState& mutableDrawingDisplayState() { return mFlinger.mutableDrawingState().displays.editValueFor(mDisplayToken); } DisplayDeviceState& mutableCurrentDisplayState() { return mFlinger.mutableCurrentState().displays.editValueFor(mDisplayToken); } const auto& getDrawingDisplayState() { return mFlinger.mutableDrawingState().displays.valueFor(mDisplayToken); } const auto& getCurrentDisplayState() { return mFlinger.mutableCurrentState().displays.valueFor(mDisplayToken); } const sp& mutableDisplayDevice() { return mFlinger.mutableDisplays().get(mDisplayToken)->get(); } // If `configs` is nullptr, the injector creates RefreshRateConfigs from the `modes`. // Otherwise, it uses `configs`, which the caller must create using the same `modes`. // // TODO(b/182939859): Once `modes` can be retrieved from RefreshRateConfigs, remove // the `configs` parameter in favor of an alternative setRefreshRateConfigs API. auto& setDisplayModes(DisplayModes modes, DisplayModeId activeModeId, std::shared_ptr configs = nullptr) { mCreationArgs.supportedModes = std::move(modes); mCreationArgs.activeModeId = activeModeId; mCreationArgs.refreshRateConfigs = std::move(configs); return *this; } auto& setNativeWindow(const sp& nativeWindow) { mCreationArgs.nativeWindow = nativeWindow; return *this; } auto& setDisplaySurface(const sp& displaySurface) { mCreationArgs.displaySurface = displaySurface; return *this; } auto& setSecure(bool secure) { mCreationArgs.isSecure = secure; return *this; } auto& setPowerMode(std::optional mode) { mCreationArgs.initialPowerMode = mode; return *this; } auto& setHwcColorModes( const std::unordered_map> hwcColorModes) { mCreationArgs.hwcColorModes = hwcColorModes; return *this; } auto& setHasWideColorGamut(bool hasWideColorGamut) { mCreationArgs.hasWideColorGamut = hasWideColorGamut; return *this; } auto& setPhysicalOrientation(ui::Rotation orientation) { mCreationArgs.physicalOrientation = orientation; return *this; } sp inject() NO_THREAD_SAFETY_ANALYSIS { const auto displayId = mCreationArgs.compositionDisplay->getDisplayId(); auto& modes = mCreationArgs.supportedModes; auto& activeModeId = mCreationArgs.activeModeId; if (displayId && !mCreationArgs.refreshRateConfigs) { if (const auto physicalId = PhysicalDisplayId::tryCast(*displayId)) { if (modes.empty()) { constexpr DisplayModeId kModeId{0}; DisplayModePtr mode = DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG) .setId(kModeId) .setPhysicalDisplayId(*physicalId) .setResolution(FakeHwcDisplayInjector::DEFAULT_RESOLUTION) .setVsyncPeriod( FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD) .setDpiX(FakeHwcDisplayInjector::DEFAULT_DPI) .setDpiY(FakeHwcDisplayInjector::DEFAULT_DPI) .setGroup(FakeHwcDisplayInjector::DEFAULT_CONFIG_GROUP) .build(); modes = ftl::init::map(kModeId, std::move(mode)); activeModeId = kModeId; } mCreationArgs.refreshRateConfigs = std::make_shared(modes, activeModeId); } } DisplayDeviceState state; if (const auto type = mCreationArgs.connectionType) { LOG_ALWAYS_FATAL_IF(!displayId); const auto physicalId = PhysicalDisplayId::tryCast(*displayId); LOG_ALWAYS_FATAL_IF(!physicalId); LOG_ALWAYS_FATAL_IF(!mHwcDisplayId); const auto activeMode = modes.get(activeModeId); LOG_ALWAYS_FATAL_IF(!activeMode); state.physical = {.id = *physicalId, .type = *type, .hwcDisplayId = *mHwcDisplayId, .deviceProductInfo = {}, .supportedModes = modes, .activeMode = activeMode->get()}; if (mCreationArgs.isPrimary) { mFlinger.mutableActiveDisplayToken() = mDisplayToken; } } state.isSecure = mCreationArgs.isSecure; sp display = sp::make(mCreationArgs); if (!display->isVirtual()) { display->setActiveMode(activeModeId); } mFlinger.mutableDisplays().emplace_or_replace(mDisplayToken, display); mFlinger.mutableCurrentState().displays.add(mDisplayToken, state); mFlinger.mutableDrawingState().displays.add(mDisplayToken, state); if (const auto& physical = state.physical) { mFlinger.mutablePhysicalDisplayTokens().emplace_or_replace(physical->id, mDisplayToken); } return display; } private: TestableSurfaceFlinger& mFlinger; sp mDisplayToken = new BBinder(); DisplayDeviceCreationArgs mCreationArgs; const std::optional mHwcDisplayId; }; private: constexpr static int64_t kVsyncId = 123; surfaceflinger::test::Factory mFactory; sp mFlinger; scheduler::mock::SchedulerCallback mSchedulerCallback; scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback; scheduler::TestableScheduler* mScheduler = nullptr; }; } // namespace android