| /* |
| * 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 "DisplayDevice.h" |
| #include "SurfaceFlinger.h" |
| |
| namespace android { |
| |
| class EventThread; |
| |
| namespace RE { |
| class RenderEngine; |
| } |
| |
| namespace Hwc2 { |
| class Composer; |
| } |
| |
| class TestableSurfaceFlinger { |
| public: |
| // Extend this as needed for accessing SurfaceFlinger private (and public) |
| // functions. |
| |
| void setupRenderEngine(std::unique_ptr<RE::RenderEngine> renderEngine) { |
| mFlinger->getBE().mRenderEngine = std::move(renderEngine); |
| } |
| |
| void setupComposer(std::unique_ptr<Hwc2::Composer> composer) { |
| mFlinger->getBE().mHwc.reset(new HWComposer(std::move(composer))); |
| } |
| |
| using CreateBufferQueueFunction = SurfaceFlinger::CreateBufferQueueFunction; |
| void setCreateBufferQueueFunction(CreateBufferQueueFunction f) { |
| mFlinger->mCreateBufferQueue = f; |
| } |
| |
| using CreateNativeWindowSurfaceFunction = SurfaceFlinger::CreateNativeWindowSurfaceFunction; |
| void setCreateNativeWindowSurface(CreateNativeWindowSurfaceFunction f) { |
| mFlinger->mCreateNativeWindowSurface = f; |
| } |
| |
| using HotplugEvent = SurfaceFlinger::HotplugEvent; |
| |
| /* ------------------------------------------------------------------------ |
| * Forwarding for functions being tested |
| */ |
| |
| auto createDisplay(const String8& displayName, bool secure) { |
| return mFlinger->createDisplay(displayName, secure); |
| } |
| |
| auto destroyDisplay(const sp<IBinder>& displayToken) { |
| return mFlinger->destroyDisplay(displayToken); |
| } |
| |
| auto resetDisplayState() { return mFlinger->resetDisplayState(); } |
| |
| auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken, int32_t displayId, |
| const DisplayDeviceState& state, |
| const sp<DisplaySurface>& dispSurface, |
| const sp<IGraphicBufferProducer>& producer) { |
| return mFlinger->setupNewDisplayDeviceInternal(displayToken, displayId, state, dispSurface, |
| producer); |
| } |
| |
| auto handleTransactionLocked(uint32_t transactionFlags) { |
| return mFlinger->handleTransactionLocked(transactionFlags); |
| } |
| |
| auto onHotplugReceived(int32_t sequenceId, hwc2_display_t display, |
| HWC2::Connection connection) { |
| return mFlinger->onHotplugReceived(sequenceId, display, connection); |
| } |
| |
| auto setDisplayStateLocked(const DisplayState& s) { return mFlinger->setDisplayStateLocked(s); } |
| |
| auto onInitializeDisplays() { return mFlinger->onInitializeDisplays(); } |
| |
| auto setPowerModeInternal(const sp<DisplayDevice>& display, int mode, |
| bool stateLockHeld = false) { |
| return mFlinger->setPowerModeInternal(display, mode, stateLockHeld); |
| } |
| |
| /* ------------------------------------------------------------------------ |
| * 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& getHWVsyncAvailable() const { return mFlinger->mHWVsyncAvailable; } |
| const auto& getVisibleRegionsDirty() const { return mFlinger->mVisibleRegionsDirty; } |
| |
| const auto& getCompositorTiming() const { return mFlinger->getBE().mCompositorTiming; } |
| |
| /* ------------------------------------------------------------------------ |
| * Read-write access to private data to set up preconditions and assert |
| * post-conditions. |
| */ |
| |
| auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; } |
| auto& mutableUseColorManagement() { return SurfaceFlinger::useColorManagement; } |
| |
| auto& mutableDisplayTokens() { return mFlinger->mDisplayTokens; } |
| auto& mutableCurrentState() { return mFlinger->mCurrentState; } |
| auto& mutableDisplays() { return mFlinger->mDisplays; } |
| auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; } |
| auto& mutableDrawingState() { return mFlinger->mDrawingState; } |
| auto& mutableEventControlThread() { return mFlinger->mEventControlThread; } |
| auto& mutableEventQueue() { return mFlinger->mEventQueue; } |
| auto& mutableEventThread() { return mFlinger->mEventThread; } |
| auto& mutableHWVsyncAvailable() { return mFlinger->mHWVsyncAvailable; } |
| auto& mutableInterceptor() { return mFlinger->mInterceptor; } |
| auto& mutableMainThreadId() { return mFlinger->mMainThreadId; } |
| auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; } |
| auto& mutablePrimaryDispSync() { return mFlinger->mPrimaryDispSync; } |
| auto& mutablePrimaryHWVsyncEnabled() { return mFlinger->mPrimaryHWVsyncEnabled; } |
| auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; } |
| auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; } |
| |
| auto& mutableComposerSequenceId() { return mFlinger->getBE().mComposerSequenceId; } |
| auto& mutableHwcDisplayData() { return mFlinger->getBE().mHwc->mDisplayData; } |
| auto& mutableHwcDisplaySlots() { return mFlinger->getBE().mHwc->mHwcDisplaySlots; } |
| |
| ~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(); |
| mutableEventControlThread().reset(); |
| mutableEventQueue().reset(); |
| mutableEventThread().reset(); |
| mutableInterceptor().reset(); |
| mutablePrimaryDispSync().reset(); |
| mFlinger->getBE().mHwc.reset(); |
| mFlinger->getBE().mRenderEngine.reset(); |
| } |
| |
| /* ------------------------------------------------------------------------ |
| * Wrapper classes for Read-write access to private data to set up |
| * preconditions and assert post-conditions. |
| */ |
| class FakePowerAdvisor : public Hwc2::PowerAdvisor { |
| public: |
| FakePowerAdvisor() = default; |
| ~FakePowerAdvisor() override = default; |
| void setExpensiveRenderingExpected(hwc2_display_t, bool) override { } |
| }; |
| |
| struct HWC2Display : public HWC2::Display { |
| HWC2Display(Hwc2::Composer& composer, Hwc2::PowerAdvisor& advisor, |
| const std::unordered_set<HWC2::Capability>& capabilities, hwc2_display_t id, |
| HWC2::DisplayType type) |
| : HWC2::Display(composer, advisor, capabilities, id, type) {} |
| ~HWC2Display() { |
| // Prevents a call to disable vsyncs. |
| mType = HWC2::DisplayType::Invalid; |
| } |
| |
| auto& mutableIsConnected() { return this->mIsConnected; } |
| auto& mutableConfigs() { return this->mConfigs; } |
| }; |
| |
| class FakeHwcDisplayInjector { |
| public: |
| static constexpr hwc2_display_t DEFAULT_HWC_DISPLAY_ID = 1000; |
| static constexpr int32_t DEFAULT_WIDTH = 1920; |
| static constexpr int32_t DEFAULT_HEIGHT = 1280; |
| static constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'666; |
| static constexpr int32_t DEFAULT_DPI = 320; |
| static constexpr int32_t DEFAULT_ACTIVE_CONFIG = 0; |
| |
| FakeHwcDisplayInjector(DisplayDevice::DisplayType type, HWC2::DisplayType hwcDisplayType) |
| : mType(type), mHwcDisplayType(hwcDisplayType) {} |
| |
| auto& setHwcDisplayId(hwc2_display_t displayId) { |
| mHwcDisplayId = displayId; |
| return *this; |
| } |
| |
| auto& setWidth(int32_t width) { |
| mWidth = width; |
| return *this; |
| } |
| |
| auto& setHeight(int32_t height) { |
| mHeight = height; |
| return *this; |
| } |
| |
| auto& setRefreshRate(int32_t refreshRate) { |
| mRefreshRate = refreshRate; |
| return *this; |
| } |
| |
| auto& setDpiX(int32_t dpi) { |
| mDpiX = dpi; |
| return *this; |
| } |
| |
| auto& setDpiY(int32_t dpi) { |
| mDpiY = dpi; |
| return *this; |
| } |
| |
| auto& setActiveConfig(int32_t config) { |
| mActiveConfig = config; |
| return *this; |
| } |
| |
| auto& setCapabilities(const std::unordered_set<HWC2::Capability>* capabilities) { |
| mCapabilities = capabilities; |
| return *this; |
| } |
| |
| auto& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) { |
| mPowerAdvisor = powerAdvisor; |
| return *this; |
| } |
| |
| void inject(TestableSurfaceFlinger* flinger, Hwc2::Composer* composer) { |
| static FakePowerAdvisor defaultPowerAdvisor; |
| if (mPowerAdvisor == nullptr) mPowerAdvisor = &defaultPowerAdvisor; |
| static const std::unordered_set<HWC2::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<HWC2Display>(*composer, *mPowerAdvisor, *mCapabilities, |
| mHwcDisplayId, mHwcDisplayType); |
| |
| auto config = HWC2::Display::Config::Builder(*display, mActiveConfig); |
| config.setWidth(mWidth); |
| config.setHeight(mHeight); |
| config.setVsyncPeriod(mRefreshRate); |
| config.setDpiX(mDpiX); |
| config.setDpiY(mDpiY); |
| display->mutableConfigs().emplace(mActiveConfig, config.build()); |
| display->mutableIsConnected() = true; |
| |
| ASSERT_TRUE(flinger->mutableHwcDisplayData().size() > static_cast<size_t>(mType)); |
| flinger->mutableHwcDisplayData()[mType] = HWComposer::DisplayData(); |
| flinger->mutableHwcDisplayData()[mType].hwcDisplay = display.get(); |
| flinger->mutableHwcDisplaySlots().emplace(mHwcDisplayId, mType); |
| |
| flinger->mFakeHwcDisplays.push_back(std::move(display)); |
| } |
| |
| private: |
| DisplayDevice::DisplayType mType; |
| HWC2::DisplayType mHwcDisplayType; |
| hwc2_display_t mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID; |
| int32_t mWidth = DEFAULT_WIDTH; |
| int32_t mHeight = DEFAULT_HEIGHT; |
| int32_t mRefreshRate = DEFAULT_REFRESH_RATE; |
| int32_t mDpiX = DEFAULT_DPI; |
| int32_t mDpiY = DEFAULT_DPI; |
| int32_t mActiveConfig = DEFAULT_ACTIVE_CONFIG; |
| const std::unordered_set<HWC2::Capability>* mCapabilities = nullptr; |
| Hwc2::PowerAdvisor* mPowerAdvisor = nullptr; |
| }; |
| |
| class FakeDisplayDeviceInjector { |
| public: |
| FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, DisplayDevice::DisplayType type, |
| int32_t displayId) |
| : mFlinger(flinger), mType(type), mDisplayId(displayId) {} |
| |
| sp<IBinder> 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); |
| } |
| |
| auto& mutableDisplayDevice() { return mFlinger.mutableDisplays()[mDisplayToken]; } |
| |
| auto& setNativeWindow(const sp<ANativeWindow>& nativeWindow) { |
| mNativeWindow = nativeWindow; |
| return *this; |
| } |
| |
| auto& setDisplaySurface(const sp<DisplaySurface>& displaySurface) { |
| mDisplaySurface = displaySurface; |
| return *this; |
| } |
| |
| auto& setRenderSurface(std::unique_ptr<RE::Surface> renderSurface) { |
| mRenderSurface = std::move(renderSurface); |
| return *this; |
| } |
| |
| auto& setSecure(bool secure) { |
| mSecure = secure; |
| return *this; |
| } |
| |
| sp<DisplayDevice> inject() { |
| std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hdrAndRenderIntents; |
| sp<DisplayDevice> device = |
| new DisplayDevice(mFlinger.mFlinger.get(), mType, mDisplayId, mSecure, |
| mDisplayToken, mNativeWindow, mDisplaySurface, |
| std::move(mRenderSurface), 0, 0, false, HdrCapabilities(), 0, |
| hdrAndRenderIntents, HWC_POWER_MODE_NORMAL); |
| mFlinger.mutableDisplays().emplace(mDisplayToken, device); |
| |
| DisplayDeviceState state; |
| state.type = mType; |
| state.isSecure = mSecure; |
| mFlinger.mutableCurrentState().displays.add(mDisplayToken, state); |
| mFlinger.mutableDrawingState().displays.add(mDisplayToken, state); |
| |
| if (mType >= DisplayDevice::DISPLAY_PRIMARY && mType < DisplayDevice::DISPLAY_VIRTUAL) { |
| mFlinger.mutableDisplayTokens()[mType] = mDisplayToken; |
| } |
| |
| return device; |
| } |
| |
| private: |
| TestableSurfaceFlinger& mFlinger; |
| sp<BBinder> mDisplayToken = new BBinder(); |
| DisplayDevice::DisplayType mType; |
| const int32_t mDisplayId; |
| sp<ANativeWindow> mNativeWindow; |
| sp<DisplaySurface> mDisplaySurface; |
| std::unique_ptr<RE::Surface> mRenderSurface; |
| bool mSecure = false; |
| }; |
| |
| sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(SurfaceFlinger::SkipInitialization); |
| |
| // We need to keep a reference to these so they are properly destroyed. |
| std::vector<std::unique_ptr<HWC2Display>> mFakeHwcDisplays; |
| }; |
| |
| } // namespace android |