/* * 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 #include #include #include #include #include "DisplayDevice.h" #include "FakeVsyncConfiguration.h" #include "FrameTracer/FrameTracer.h" #include "FrontEnd/LayerCreationArgs.h" #include "FrontEnd/LayerHandle.h" #include "FrontEnd/RequestedLayerState.h" #include "Layer.h" #include "NativeWindowSurface.h" #include "RenderArea.h" #include "Scheduler/MessageQueue.h" #include "Scheduler/RefreshRateSelector.h" #include "SurfaceFlinger.h" #include "TestableScheduler.h" #include "android/gui/ISurfaceComposerClient.h" #include "mock/DisplayHardware/MockComposer.h" #include "mock/DisplayHardware/MockDisplayMode.h" #include "mock/DisplayHardware/MockPowerAdvisor.h" #include "mock/MockEventThread.h" #include "mock/MockFrameTimeline.h" #include "mock/MockFrameTracer.h" #include "mock/MockSchedulerCallback.h" #include "mock/system/window/MockNativeWindow.h" #include "Scheduler/VSyncTracker.h" #include "Scheduler/VsyncController.h" #include "mock/MockVSyncDispatch.h" #include "mock/MockVSyncTracker.h" #include "mock/MockVsyncController.h" namespace android { struct DisplayStatInfo; 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 createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) override { return sp::make(creationArgs); } sp createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount, uint64_t usage, std::string requestorName) override { return sp::make(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); } 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 createBufferStateLayer(const LayerCreationArgs&) override { return nullptr; } sp createEffectLayer(const LayerCreationArgs&) override { return nullptr; } sp createLayerFE(const std::string& layerName, const Layer* /* owner */) override { return sp::make(layerName); } 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; }; struct MockSchedulerOptions { PhysicalDisplayId displayId = PhysicalDisplayId::fromPort(0); bool useNiceMock = false; }; } // namespace surfaceflinger::test class TestableSurfaceFlinger { public: using HotplugEvent = SurfaceFlinger::HotplugEvent; TestableSurfaceFlinger(sp flinger = nullptr) : mFlinger(flinger) { if (!mFlinger) { mFlinger = sp::make(mFactory, SurfaceFlinger::SkipInitialization); } } 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->mRenderEngine = std::move(renderEngine); mFlinger->mCompositionEngine->setRenderEngine(mFlinger->mRenderEngine.get()); } void setupComposer(std::unique_ptr composer) { mFlinger->mCompositionEngine->setHwComposer( std::make_unique(std::move(composer))); mFlinger->mDisplayModeController.setHwComposer( &mFlinger->mCompositionEngine->getHwComposer()); } void setupPowerAdvisor(std::unique_ptr powerAdvisor) { mFlinger->mPowerAdvisor = std::move(powerAdvisor); } void setupTimeStats(const std::shared_ptr& timeStats) { mFlinger->mCompositionEngine->setTimeStats(timeStats); } void setupCompositionEngine( std::unique_ptr compositionEngine) { mFlinger->mCompositionEngine = std::move(compositionEngine); } enum class SchedulerCallbackImpl { kNoOp, kMock }; struct DefaultDisplayMode { // The ID of the injected RefreshRateSelector and its default display mode. PhysicalDisplayId displayId; }; using RefreshRateSelectorPtr = scheduler::Scheduler::RefreshRateSelectorPtr; using DisplayModesVariant = std::variant; surfaceflinger::Factory& getFactory() { return mFactory; } TimeStats& getTimeStats() { return *mFlinger->mTimeStats; } void setupScheduler(std::unique_ptr vsyncController, std::shared_ptr vsyncTracker, std::unique_ptr appEventThread, std::unique_ptr sfEventThread, DisplayModesVariant modesVariant, SchedulerCallbackImpl callbackImpl = SchedulerCallbackImpl::kNoOp, bool useNiceMock = false) { RefreshRateSelectorPtr selectorPtr = ftl::match( modesVariant, [](DefaultDisplayMode arg) { constexpr DisplayModeId kModeId60{0}; return std::make_shared( makeModes(mock::createDisplayMode(arg.displayId, kModeId60, 60_Hz)), kModeId60); }, [](RefreshRateSelectorPtr selectorPtr) { return selectorPtr; }); mTokenManager = std::make_unique(); using ISchedulerCallback = scheduler::ISchedulerCallback; ISchedulerCallback& schedulerCallback = callbackImpl == SchedulerCallbackImpl::kNoOp ? static_cast(mNoOpSchedulerCallback) : static_cast(mSchedulerCallback); if (useNiceMock) { mScheduler = new testing::NiceMock(std::move(vsyncController), std::move(vsyncTracker), std::move(selectorPtr), mFactory, *mFlinger->mTimeStats, schedulerCallback); } else { mScheduler = new scheduler::TestableScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(selectorPtr), mFactory, *mFlinger->mTimeStats, schedulerCallback); } mScheduler->initVsync(*mTokenManager, 0ms); mScheduler->setEventThread(scheduler::Cycle::Render, std::move(appEventThread)); mScheduler->setEventThread(scheduler::Cycle::LastComposite, std::move(sfEventThread)); resetScheduler(mScheduler); } void setupMockScheduler(surfaceflinger::test::MockSchedulerOptions options = {}) { using testing::_; using testing::Return; auto eventThread = makeMock(options.useNiceMock); auto sfEventThread = makeMock(options.useNiceMock); EXPECT_CALL(*eventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*eventThread, createEventConnection(_, _)) .WillOnce(Return(sp::make(eventThread.get(), mock::EventThread::kCallingUid))); EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_)); EXPECT_CALL(*sfEventThread, createEventConnection(_, _)) .WillOnce(Return(sp::make(sfEventThread.get(), mock::EventThread::kCallingUid))); auto vsyncController = makeMock(options.useNiceMock); auto vsyncTracker = makeSharedMock(options.useNiceMock); EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_, _)).WillRepeatedly(Return(0)); EXPECT_CALL(*vsyncTracker, currentPeriod()) .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); EXPECT_CALL(*vsyncTracker, minFramePeriod()) .WillRepeatedly( Return(Period::fromNs(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD))); EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_, _)).WillRepeatedly(Return(0)); setupScheduler(std::move(vsyncController), std::move(vsyncTracker), std::move(eventThread), std::move(sfEventThread), DefaultDisplayMode{options.displayId}, SchedulerCallbackImpl::kNoOp, options.useNiceMock); } void resetScheduler(scheduler::Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); } scheduler::TestableScheduler& mutableScheduler() { return *mScheduler; } scheduler::mock::SchedulerCallback& mockSchedulerCallback() { return mSchedulerCallback; } 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->editLayerSnapshot()->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; } /* ------------------------------------------------------------------------ * Forwarding for functions being tested */ void configure() { ftl::FakeGuard guard(kMainThreadContext); mFlinger->configure(); } void configureAndCommit() { configure(); commitTransactionsLocked(eDisplayTransactionNeeded); } void commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime, bool composite = false) { ftl::FakeGuard guard(kMainThreadContext); const auto displayIdOpt = mScheduler->pacesetterDisplayId(); LOG_ALWAYS_FATAL_IF(!displayIdOpt); const auto displayId = *displayIdOpt; scheduler::FrameTargeter frameTargeter(displayId, scheduler::Feature::kBackpressureGpuComposition); frameTargeter.beginFrame({.frameBeginTime = frameTime, .vsyncId = vsyncId, .expectedVsyncTime = expectedVsyncTime, .sfWorkDuration = 10ms, .hwcMinWorkDuration = 10ms}, *mScheduler->getVsyncSchedule()); scheduler::FrameTargets targets; scheduler::FrameTargeters targeters; for (const auto& [id, display] : FTL_FAKE_GUARD(mFlinger->mStateLock, mFlinger->mPhysicalDisplays)) { targets.try_emplace(id, &frameTargeter.target()); targeters.try_emplace(id, &frameTargeter); } mFlinger->commit(displayId, targets); if (composite) { mFlinger->composite(displayId, targeters); } } void commit(TimePoint frameTime, VsyncId vsyncId, bool composite = false) { return commit(frameTime, vsyncId, frameTime + Period(10ms), composite); } void commit(bool composite = false) { const TimePoint frameTime = scheduler::SchedulerClock::now(); commit(frameTime, kVsyncId, composite); } void commitAndComposite(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime) { constexpr bool kComposite = true; commit(frameTime, vsyncId, expectedVsyncTime, kComposite); } void commitAndComposite() { constexpr bool kComposite = true; commit(kComposite); } auto createVirtualDisplay(const std::string& displayName, bool isSecure, float requestedRefreshRate = 0.0f) { static const std::string kTestId = "virtual:libsurfaceflinger_unittest:TestableSurfaceFlinger"; return mFlinger->createVirtualDisplay(displayName, isSecure, kTestId, requestedRefreshRate); } auto createVirtualDisplay(const std::string& displayName, bool isSecure, const std::string& uniqueId, float requestedRefreshRate = 0.0f) { return mFlinger->createVirtualDisplay(displayName, isSecure, uniqueId, requestedRefreshRate); } auto destroyVirtualDisplay(const sp& displayToken) { return mFlinger->destroyVirtualDisplay(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); } void commitTransactionsLocked(uint32_t transactionFlags) { Mutex::Autolock lock(mFlinger->mStateLock); ftl::FakeGuard guard(kMainThreadContext); mFlinger->processDisplayChangesLocked(); mFlinger->commitTransactionsLocked(transactionFlags); } void onComposerHalHotplugEvent(hal::HWDisplayId hwcDisplayId, DisplayHotplugEvent event) { mFlinger->onComposerHalHotplugEvent(hwcDisplayId, event); } auto setDisplayStateLocked(const DisplayState& s) { Mutex::Autolock lock(mFlinger->mStateLock); return mFlinger->setDisplayStateLocked(s); } void initializeDisplays() FTL_FAKE_GUARD(kMainThreadContext) { mFlinger->initializeDisplays(); } 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 sp display, std::unique_ptr renderArea, SurfaceFlinger::GetLayerSnapshotsFunction getLayerSnapshotsFn, const std::shared_ptr& buffer, bool regionSampling) { Mutex::Autolock lock(mFlinger->mStateLock); ftl::FakeGuard guard(kMainThreadContext); ScreenCaptureResults captureResults; auto displayState = std::optional{display->getCompositionDisplay()->getState()}; auto layers = getLayerSnapshotsFn(); auto layerFEs = mFlinger->extractLayerFEs(layers); return mFlinger->renderScreenImpl(std::move(renderArea), buffer, regionSampling, false /* grayscale */, false /* isProtected */, captureResults, displayState, layers, layerFEs); } auto traverseLayersInLayerStack(ui::LayerStack layerStack, int32_t uid, std::unordered_set excludeLayerIds, const LayerVector::Visitor& visitor) { return mFlinger->traverseLayersInLayerStack(layerStack, uid, excludeLayerIds, visitor); } auto getDisplayNativePrimaries(const sp& displayToken, ui::DisplayPrimaries &primaries) { return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries); } auto& getTransactionQueue() { return mFlinger->mTransactionHandler.mLocklessTransactionQueue; } auto& getPendingTransactionQueue() { ftl::FakeGuard guard(kMainThreadContext); return mFlinger->mTransactionHandler.mPendingTransactionQueues; } size_t getPendingTransactionCount() { ftl::FakeGuard guard(kMainThreadContext); return mFlinger->mTransactionHandler.mPendingTransactionCount.load(); } auto setTransactionState( const FrameTimelineInfo& frameTimelineInfo, Vector& states, const Vector& displays, uint32_t flags, const sp& applyToken, const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp, const std::vector& uncacheBuffers, bool hasListenerCallbacks, std::vector& listenerCallbacks, uint64_t transactionId, const std::vector& mergedTransactionIds) { return mFlinger->setTransactionState(frameTimelineInfo, states, displays, flags, applyToken, inputWindowCommands, desiredPresentTime, isAutoTimestamp, uncacheBuffers, hasListenerCallbacks, listenerCallbacks, transactionId, mergedTransactionIds); } auto setTransactionStateInternal(TransactionState& transaction) { return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->mTransactionHandler.queueTransaction( std::move(transaction))); } auto flushTransactionQueues() { return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->flushTransactionQueues(kVsyncId)); } 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, const gui::DisplayModeSpecs& specs) { return mFlinger->setDesiredDisplayModeSpecs(displayToken, specs); } void onActiveDisplayChanged(const DisplayDevice* inactiveDisplayPtr, const DisplayDevice& activeDisplay) { Mutex::Autolock lock(mFlinger->mStateLock); ftl::FakeGuard guard(kMainThreadContext); mFlinger->onActiveDisplayChangedLocked(inactiveDisplayPtr, activeDisplay); } auto createLayer(LayerCreationArgs& args, const sp& parentHandle, gui::CreateSurfaceResult& outResult) { args.parentHandle = parentHandle; return mFlinger->createLayer(args, outResult); } auto mirrorLayer(const LayerCreationArgs& args, const sp& mirrorFromHandle, gui::CreateSurfaceResult& outResult) { return mFlinger->mirrorLayer(args, mirrorFromHandle, outResult); } void updateLayerMetadataSnapshot() { mFlinger->updateLayerMetadataSnapshot(); } void getDynamicDisplayInfoFromToken(const sp& displayToken, ui::DynamicDisplayInfo* dynamicDisplayInfo) { mFlinger->getDynamicDisplayInfoFromToken(displayToken, dynamicDisplayInfo); } sp createVirtualDisplayDevice(const sp displayToken, VirtualDisplayId displayId, float requestedRefreshRate) { constexpr ui::Size kResolution = {1080, 1920}; auto compositionDisplay = compositionengine::impl:: createDisplay(mFlinger->getCompositionEngine(), compositionengine::DisplayCreationArgsBuilder() .setId(displayId) .setPixels(kResolution) .setPowerAdvisor(&mPowerAdvisor) .build()); DisplayDeviceCreationArgs creationArgs(mFlinger, mFlinger->getHwComposer(), displayToken, compositionDisplay); creationArgs.requestedRefreshRate = Fps::fromValue(requestedRefreshRate); creationArgs.nativeWindow = sp::make(); return sp::make(creationArgs); } status_t getDisplayStats(const sp& displayToken, DisplayStatInfo* outInfo) { return mFlinger->getDisplayStats(displayToken, outInfo); } // Used to add a layer before updateLayerSnapshots is called. // Must have transactionsFlushed enabled for the new layer to be updated. void addLayer(std::unique_ptr& layer) { std::scoped_lock lock(mFlinger->mCreatedLayersLock); mFlinger->mNewLayers.emplace_back(std::move(layer)); } /* ------------------------------------------------------------------------ * Read-only access to private data to assert post-conditions. */ const auto& getVisibleRegionsDirty() const { return mFlinger->mVisibleRegionsDirty; } auto& getHwComposer() const { return static_cast(mFlinger->getHwComposer()); } auto& getCompositionEngine() const { return mFlinger->getCompositionEngine(); } mock::FrameTracer* getFrameTracer() const { return static_cast(mFlinger->mFrameTracer.get()); } void injectLegacyLayer(sp layer) { FTL_FAKE_GUARD(kMainThreadContext, mFlinger->mLegacyLayers[static_cast(layer->sequence)] = layer); }; void releaseLegacyLayer(uint32_t sequence) { FTL_FAKE_GUARD(kMainThreadContext, mFlinger->mLegacyLayers.erase(sequence)); }; auto setLayerHistoryDisplayArea(uint32_t displayArea) { return mFlinger->mScheduler->onActiveDisplayAreaChanged(displayArea); }; auto updateLayerHistory(nsecs_t now) { return FTL_FAKE_GUARD(kMainThreadContext, mFlinger->updateLayerHistory(now)); }; auto setDaltonizerType(ColorBlindnessType type) { mFlinger->mDaltonizer.setType(type); return mFlinger->updateColorMatrixLocked(); } auto updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs, bool transactionsFlushed, bool& out) { ftl::FakeGuard guard(kMainThreadContext); return mFlinger->updateLayerSnapshots(vsyncId, frameTimeNs, transactionsFlushed, out); } /* ------------------------------------------------------------------------ * Read-write access to private data to set up preconditions and assert * post-conditions. */ const auto& displays() const { return mFlinger->mDisplays; } const auto& physicalDisplays() const { return mFlinger->mPhysicalDisplays; } 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; } const auto& hwcDisplayData() const { return getHwComposer().mDisplayData; } auto& mutableSupportsWideColor() { return mFlinger->mSupportsWideColor; } auto& mutableDisplayModeController() { return mFlinger->mDisplayModeController; } auto& mutableCurrentState() { return mFlinger->mCurrentState; } auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; } auto& mutableDisplays() { return mFlinger->mDisplays; } auto& mutablePhysicalDisplays() { return mFlinger->mPhysicalDisplays; } auto& mutableDrawingState() { return mFlinger->mDrawingState; } auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; } auto& mutableVisibleRegionsDirty() { return mFlinger->mVisibleRegionsDirty; } auto& mutableMainThreadId() { return mFlinger->mMainThreadId; } auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; } 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& mutableActiveDisplayId() { return mFlinger->mActiveDisplayId; } auto& mutablePreviouslyComposedLayers() { return mFlinger->mPreviouslyComposedLayers; } auto& mutableActiveDisplayRotationFlags() { return SurfaceFlinger::sActiveDisplayRotationFlags; } auto& mutableMinAcquiredBuffers() { return SurfaceFlinger::minAcquiredBuffers; } auto& mutableLayersPendingRemoval() { return mFlinger->mLayersPendingRemoval; } auto& mutableLayerSnapshotBuilder() { return mFlinger->mLayerSnapshotBuilder; }; auto fromHandle(const sp& handle) { return LayerHandle::getLayer(handle); } auto initTransactionTraceWriter() { mFlinger->mTransactionTracing.emplace(); return mFlinger->initTransactionTraceWriter(); } // Needed since mLayerLifecycleManagerEnabled is false by default and must // be enabled for tests to go through the new front end path. void enableLayerLifecycleManager() { mFlinger->mLayerLifecycleManagerEnabled = true; } void notifyExpectedPresentIfRequired(PhysicalDisplayId displayId, Period vsyncPeriod, TimePoint expectedPresentTime, Fps frameInterval, std::optional timeoutOpt) { mFlinger->notifyExpectedPresentIfRequired(displayId, vsyncPeriod, expectedPresentTime, frameInterval, timeoutOpt); } void sendNotifyExpectedPresentHint(PhysicalDisplayId displayId) { ftl::FakeGuard guard(kMainThreadContext); mFlinger->sendNotifyExpectedPresentHint(displayId); } bool verifyHintIsScheduledOnPresent(PhysicalDisplayId displayId) { return mFlinger->mNotifyExpectedPresentMap.at(displayId).hintStatus == SurfaceFlinger::NotifyExpectedPresentHintStatus::ScheduleOnPresent; } bool verifyHintIsSent(PhysicalDisplayId displayId) { return mFlinger->mNotifyExpectedPresentMap.at(displayId).hintStatus == SurfaceFlinger::NotifyExpectedPresentHintStatus::Sent; } bool verifyHintStatusIsStart(PhysicalDisplayId displayId) { return mFlinger->mNotifyExpectedPresentMap.at(displayId).hintStatus == SurfaceFlinger::NotifyExpectedPresentHintStatus::Start; } bool verifyHintStatusIsScheduledOnTx(PhysicalDisplayId displayId) { return mFlinger->mNotifyExpectedPresentMap.at(displayId).hintStatus == SurfaceFlinger::NotifyExpectedPresentHintStatus::ScheduleOnTx; } bool verifyLastExpectedPresentTime(PhysicalDisplayId displayId, nsecs_t expectedPresentTime) { return mFlinger->mNotifyExpectedPresentMap.at(displayId) .lastExpectedPresentTimestamp.ns() == expectedPresentTime; } void setNotifyExpectedPresentData(PhysicalDisplayId displayId, TimePoint lastExpectedPresentTimestamp, Fps lastFrameInterval) { auto& displayData = mFlinger->mNotifyExpectedPresentMap[displayId]; displayData.lastExpectedPresentTimestamp = lastExpectedPresentTimestamp; displayData.lastFrameInterval = lastFrameInterval; } void resetNotifyExpectedPresentHintState(PhysicalDisplayId displayId) { mFlinger->mNotifyExpectedPresentMap.at(displayId).hintStatus = SurfaceFlinger::NotifyExpectedPresentHintStatus::Start; } ~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(); mFlinger->mLayersPendingRemoval.clear(); mFlinger->mScheduler.reset(); mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr()); mFlinger->mRenderEngine = std::unique_ptr(); mFlinger->mCompositionEngine->setRenderEngine(mFlinger->mRenderEngine.get()); mFlinger->mTransactionTracing.reset(); } /* ------------------------------------------------------------------------ * 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; 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 = hal::PowerMode::ON; 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, flinger.mFlinger->getHwComposer(), mDisplayToken, display), mConnectionType(connectionType), mHwcDisplayId(hwcDisplayId) { mCreationArgs.isPrimary = isPrimary; mCreationArgs.initialPowerMode = hal::PowerMode::ON; } sp token() const { return mDisplayToken; } auto physicalDisplay() const { return ftl::Optional(mCreationArgs.compositionDisplay->getDisplayId()) .and_then(&PhysicalDisplayId::tryCast) .and_then(display::getPhysicalDisplay(mFlinger.physicalDisplays())); } 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(); } auto& setDisplayModes(DisplayModes modes, DisplayModeId activeModeId) { mDisplayModes = std::move(modes); mActiveModeId = activeModeId; mCreationArgs.refreshRateSelector = nullptr; return *this; } auto& setRefreshRateSelector(RefreshRateSelectorPtr selectorPtr) { mDisplayModes = selectorPtr->displayModes(); mActiveModeId = selectorPtr->getActiveMode().modePtr->getId(); mCreationArgs.refreshRateSelector = std::move(selectorPtr); 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(hal::PowerMode 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; } // Used to avoid overwriting mocks injected by TestableSurfaceFlinger::setupMockScheduler. auto& skipSchedulerRegistration() { mSchedulerRegistration = false; return *this; } sp inject() NO_THREAD_SAFETY_ANALYSIS { return inject(std::make_unique(), std::make_shared()); } sp inject(std::unique_ptr controller, std::shared_ptr tracker) NO_THREAD_SAFETY_ANALYSIS { const auto displayId = mCreationArgs.compositionDisplay->getDisplayId(); LOG_ALWAYS_FATAL_IF(!displayId); auto& modes = mDisplayModes; auto& activeModeId = mActiveModeId; DisplayDeviceState state; state.isSecure = mCreationArgs.isSecure; if (const auto physicalId = PhysicalDisplayId::tryCast(*displayId)) { LOG_ALWAYS_FATAL_IF(!mConnectionType); LOG_ALWAYS_FATAL_IF(!mHwcDisplayId); if (mCreationArgs.isPrimary) { mFlinger.mutableActiveDisplayId() = *physicalId; } if (!mCreationArgs.refreshRateSelector) { 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.refreshRateSelector = std::make_shared(modes, activeModeId); } const auto activeModeOpt = modes.get(activeModeId); LOG_ALWAYS_FATAL_IF(!activeModeOpt); // Save a copy for use after `modes` is consumed. const Fps refreshRate = activeModeOpt->get()->getPeakFps(); state.physical = {.id = *physicalId, .hwcDisplayId = *mHwcDisplayId, .activeMode = activeModeOpt->get()}; const auto it = mFlinger.mutablePhysicalDisplays() .emplace_or_replace(*physicalId, mDisplayToken, *physicalId, *mConnectionType, std::move(modes), ui::ColorModes(), std::nullopt) .first; mFlinger.mutableDisplayModeController() .registerDisplay(*physicalId, it->second.snapshot(), mCreationArgs.refreshRateSelector); mFlinger.mutableDisplayModeController().setActiveMode(*physicalId, activeModeId, refreshRate, refreshRate); if (mFlinger.scheduler() && mSchedulerRegistration) { mFlinger.scheduler()->registerDisplay(*physicalId, mCreationArgs.refreshRateSelector, std::move(controller), std::move(tracker), mFlinger.mutableActiveDisplayId()); } } sp display = sp::make(mCreationArgs); mFlinger.mutableDisplays().emplace_or_replace(mDisplayToken, display); mFlinger.mutableCurrentState().displays.add(mDisplayToken, state); mFlinger.mutableDrawingState().displays.add(mDisplayToken, state); return display; } private: TestableSurfaceFlinger& mFlinger; sp mDisplayToken = sp::make(); DisplayDeviceCreationArgs mCreationArgs; DisplayModes mDisplayModes; DisplayModeId mActiveModeId; bool mSchedulerRegistration = true; const std::optional mConnectionType; const std::optional mHwcDisplayId; }; private: template static std::unique_ptr makeMock(bool useNiceMock) { return useNiceMock ? std::make_unique>() : std::make_unique(); } template static std::shared_ptr makeSharedMock(bool useNiceMock) { return useNiceMock ? std::make_shared>() : std::make_shared(); } static constexpr VsyncId kVsyncId{123}; surfaceflinger::test::Factory mFactory; sp mFlinger; scheduler::mock::SchedulerCallback mSchedulerCallback; scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback; std::unique_ptr mTokenManager; scheduler::TestableScheduler* mScheduler = nullptr; Hwc2::mock::PowerAdvisor mPowerAdvisor; }; } // namespace android