blob: 5cbf2efba641e35eff76fb8322f837b5b717f022 [file] [log] [blame]
/*
* Copyright (C) 2017 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.
*/
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wconversion"
//#define LOG_NDEBUG 0
#undef LOG_TAG
#define LOG_TAG "FakeComposer"
#include "FakeComposerClient.h"
#include <gui/SurfaceComposerClient.h>
#include <log/log.h>
#include <gtest/gtest.h>
#include <inttypes.h>
#include <time.h>
#include <algorithm>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <set>
#include <thread>
constexpr Config NULL_DISPLAY_CONFIG = static_cast<Config>(0);
using namespace sftest;
using android::Condition;
using android::Mutex;
using Clock = std::chrono::steady_clock;
using TimePoint = std::chrono::time_point<Clock>;
namespace {
// Internal state of a layer in the HWC API.
class LayerImpl {
public:
LayerImpl() = default;
bool mValid = true;
RenderState mRenderState;
uint32_t mZ = 0;
};
// Struct for storing per frame rectangle state. Contains the render
// state shared to the test case. Basically a snapshot and a subset of
// LayerImpl sufficient to re-create the pixels of a layer for the
// frame.
struct FrameRect {
public:
FrameRect(Layer layer_, const RenderState& state, uint32_t z_)
: layer(layer_), renderState(state), z(z_) {}
const Layer layer;
const RenderState renderState;
const uint32_t z;
};
// Collection of FrameRects forming one rendered frame. Could store
// related fences and other data in the future.
class Frame {
public:
Frame() = default;
std::vector<std::unique_ptr<FrameRect>> rectangles;
};
class DelayedEventGenerator {
public:
explicit DelayedEventGenerator(std::function<void()> onTimerExpired)
: mOnTimerExpired(onTimerExpired), mThread([this]() { loop(); }) {}
~DelayedEventGenerator() {
ALOGI("DelayedEventGenerator exiting.");
{
std::unique_lock<std::mutex> lock(mMutex);
mRunning = false;
mWakeups.clear();
mCondition.notify_one();
}
mThread.join();
ALOGI("DelayedEventGenerator exited.");
}
void wakeAfter(std::chrono::nanoseconds waitTime) {
std::unique_lock<std::mutex> lock(mMutex);
mWakeups.insert(Clock::now() + waitTime);
mCondition.notify_one();
}
private:
void loop() {
while (true) {
// Lock scope
{
std::unique_lock<std::mutex> lock(mMutex);
mCondition.wait(lock, [this]() { return !mRunning || !mWakeups.empty(); });
if (!mRunning && mWakeups.empty()) {
// This thread should only exit once the destructor has been called and all
// wakeups have been processed
return;
}
// At this point, mWakeups will not be empty
TimePoint target = *(mWakeups.begin());
auto status = mCondition.wait_until(lock, target);
while (status == std::cv_status::no_timeout) {
// This was either a spurious wakeup or another wakeup was added, so grab the
// oldest point and wait again
target = *(mWakeups.begin());
status = mCondition.wait_until(lock, target);
}
// status must have been timeout, so we can finally clear this point
mWakeups.erase(target);
}
// Callback *without* locks!
mOnTimerExpired();
}
}
std::function<void()> mOnTimerExpired;
std::thread mThread;
std::mutex mMutex;
std::condition_variable mCondition;
bool mRunning = true;
std::set<TimePoint> mWakeups;
};
} // namespace
FakeComposerClient::FakeComposerClient()
: mEventCallback(nullptr),
mEventCallback_2_4(nullptr),
mCurrentConfig(NULL_DISPLAY_CONFIG),
mVsyncEnabled(false),
mLayers(),
mDelayedEventGenerator(
std::make_unique<DelayedEventGenerator>([this]() { this->requestVSync(); })),
mSurfaceComposer(nullptr) {}
FakeComposerClient::~FakeComposerClient() {}
bool FakeComposerClient::hasCapability(hwc2_capability_t /*capability*/) {
return false;
}
std::string FakeComposerClient::dumpDebugInfo() {
return {};
}
void FakeComposerClient::registerEventCallback(EventCallback* callback) {
ALOGV("registerEventCallback");
LOG_FATAL_IF(mEventCallback_2_4 != nullptr,
"already registered using registerEventCallback_2_4");
mEventCallback = callback;
if (mEventCallback) {
mEventCallback->onHotplug(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
}
}
void FakeComposerClient::unregisterEventCallback() {
ALOGV("unregisterEventCallback");
mEventCallback = nullptr;
}
void FakeComposerClient::hotplugDisplay(Display display, IComposerCallback::Connection state) {
if (mEventCallback) {
mEventCallback->onHotplug(display, state);
} else if (mEventCallback_2_4) {
mEventCallback_2_4->onHotplug(display, state);
}
}
void FakeComposerClient::refreshDisplay(Display display) {
if (mEventCallback) {
mEventCallback->onRefresh(display);
} else if (mEventCallback_2_4) {
mEventCallback_2_4->onRefresh(display);
}
}
uint32_t FakeComposerClient::getMaxVirtualDisplayCount() {
ALOGV("getMaxVirtualDisplayCount");
return 1;
}
V2_1::Error FakeComposerClient::createVirtualDisplay(uint32_t /*width*/, uint32_t /*height*/,
V1_0::PixelFormat* /*format*/,
Display* /*outDisplay*/) {
ALOGV("createVirtualDisplay");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::destroyVirtualDisplay(Display /*display*/) {
ALOGV("destroyVirtualDisplay");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::createLayer(Display /*display*/, Layer* outLayer) {
ALOGV("createLayer");
*outLayer = mLayers.size();
auto newLayer = std::make_unique<LayerImpl>();
mLayers.push_back(std::move(newLayer));
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::destroyLayer(Display /*display*/, Layer layer) {
ALOGV("destroyLayer");
mLayers[layer]->mValid = false;
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::getActiveConfig(Display display, Config* outConfig) {
ALOGV("getActiveConfig");
if (mMockHal) {
return mMockHal->getActiveConfig(display, outConfig);
}
// TODO Assert outConfig != nullptr
// TODO This is my reading of the
// IComposerClient::getActiveConfig, but returning BAD_CONFIG
// seems to not fit SurfaceFlinger plans. See version 2 below.
// if (mCurrentConfig == NULL_DISPLAY_CONFIG) {
// return V2_1::Error::BAD_CONFIG;
// }
//*outConfig = mCurrentConfig;
*outConfig = 1; // Very special config for you my friend
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::getClientTargetSupport(Display /*display*/, uint32_t /*width*/,
uint32_t /*height*/,
V1_0::PixelFormat /*format*/,
V1_0::Dataspace /*dataspace*/) {
ALOGV("getClientTargetSupport");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::getColorModes(Display /*display*/,
hidl_vec<V1_0::ColorMode>* /*outModes*/) {
ALOGV("getColorModes");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::getDisplayAttribute(Display display, Config config,
V2_1::IComposerClient::Attribute attribute,
int32_t* outValue) {
auto tmpError =
getDisplayAttribute_2_4(display, config,
static_cast<IComposerClient::Attribute>(attribute), outValue);
return static_cast<V2_1::Error>(tmpError);
}
V2_1::Error FakeComposerClient::getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) {
ALOGV("getDisplayConfigs");
if (mMockHal) {
return mMockHal->getDisplayConfigs(display, outConfigs);
}
// TODO assert display == 1, outConfigs != nullptr
outConfigs->resize(1);
(*outConfigs)[0] = 1;
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::getDisplayName(Display /*display*/, hidl_string* /*outName*/) {
ALOGV("getDisplayName");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::getDisplayType(Display /*display*/,
IComposerClient::DisplayType* outType) {
ALOGV("getDisplayType");
// TODO: This setting nothing on the output had no effect on initial trials. Is first display
// assumed to be physical?
*outType = static_cast<IComposerClient::DisplayType>(HWC2_DISPLAY_TYPE_PHYSICAL);
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::getDozeSupport(Display /*display*/, bool* /*outSupport*/) {
ALOGV("getDozeSupport");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::getHdrCapabilities(Display /*display*/,
hidl_vec<V1_0::Hdr>* /*outTypes*/,
float* /*outMaxLuminance*/,
float* /*outMaxAverageLuminance*/,
float* /*outMinLuminance*/) {
ALOGV("getHdrCapabilities");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setActiveConfig(Display display, Config config) {
ALOGV("setActiveConfig");
if (mMockHal) {
return mMockHal->setActiveConfig(display, config);
}
mCurrentConfig = config;
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setColorMode(Display /*display*/, V1_0::ColorMode /*mode*/) {
ALOGV("setColorMode");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setPowerMode(Display /*display*/,
V2_1::IComposerClient::PowerMode /*mode*/) {
ALOGV("setPowerMode");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setVsyncEnabled(Display /*display*/,
IComposerClient::Vsync enabled) {
mVsyncEnabled = (enabled == IComposerClient::Vsync::ENABLE);
ALOGV("setVsyncEnabled(%s)", mVsyncEnabled ? "ENABLE" : "DISABLE");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setColorTransform(Display /*display*/, const float* /*matrix*/,
int32_t /*hint*/) {
ALOGV("setColorTransform");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setClientTarget(Display /*display*/, buffer_handle_t /*target*/,
int32_t /*acquireFence*/, int32_t /*dataspace*/,
const std::vector<hwc_rect_t>& /*damage*/) {
ALOGV("setClientTarget");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setOutputBuffer(Display /*display*/, buffer_handle_t /*buffer*/,
int32_t /*releaseFence*/) {
ALOGV("setOutputBuffer");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::validateDisplay(
Display /*display*/, std::vector<Layer>* /*outChangedLayers*/,
std::vector<IComposerClient::Composition>* /*outCompositionTypes*/,
uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/,
std::vector<uint32_t>* /*outRequestMasks*/) {
ALOGV("validateDisplay");
// TODO: Assume touching nothing means All Korrekt!
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::acceptDisplayChanges(Display /*display*/) {
ALOGV("acceptDisplayChanges");
// Didn't ask for changes because software is omnipotent.
return V2_1::Error::NONE;
}
bool layerZOrdering(const std::unique_ptr<FrameRect>& a, const std::unique_ptr<FrameRect>& b) {
return a->z <= b->z;
}
V2_1::Error FakeComposerClient::presentDisplay(Display /*display*/, int32_t* /*outPresentFence*/,
std::vector<Layer>* /*outLayers*/,
std::vector<int32_t>* /*outReleaseFences*/) {
ALOGV("presentDisplay");
// TODO Leaving layers and their fences out for now. Doing so
// means that we've already processed everything. Important to
// test that the fences are respected, though. (How?)
std::unique_ptr<Frame> newFrame(new Frame);
for (uint64_t layer = 0; layer < mLayers.size(); layer++) {
const LayerImpl& layerImpl = *mLayers[layer];
if (!layerImpl.mValid) continue;
auto rect = std::make_unique<FrameRect>(layer, layerImpl.mRenderState, layerImpl.mZ);
newFrame->rectangles.push_back(std::move(rect));
}
std::sort(newFrame->rectangles.begin(), newFrame->rectangles.end(), layerZOrdering);
{
Mutex::Autolock _l(mStateMutex);
mFrames.push_back(std::move(newFrame));
mFramesAvailable.broadcast();
}
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setLayerCursorPosition(Display /*display*/, Layer /*layer*/,
int32_t /*x*/, int32_t /*y*/) {
ALOGV("setLayerCursorPosition");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setLayerBuffer(Display /*display*/, Layer layer,
buffer_handle_t buffer, int32_t acquireFence) {
ALOGV("setLayerBuffer");
LayerImpl& l = getLayerImpl(layer);
if (buffer != l.mRenderState.mBuffer) {
l.mRenderState.mSwapCount++; // TODO: Is setting to same value a swap or not?
}
l.mRenderState.mBuffer = buffer;
l.mRenderState.mAcquireFence = acquireFence;
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setLayerSurfaceDamage(Display /*display*/, Layer /*layer*/,
const std::vector<hwc_rect_t>& /*damage*/) {
ALOGV("setLayerSurfaceDamage");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setLayerBlendMode(Display /*display*/, Layer layer, int32_t mode) {
ALOGV("setLayerBlendMode");
getLayerImpl(layer).mRenderState.mBlendMode = static_cast<hwc2_blend_mode_t>(mode);
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setLayerColor(Display /*display*/, Layer layer,
IComposerClient::Color color) {
ALOGV("setLayerColor");
getLayerImpl(layer).mRenderState.mLayerColor.r = color.r;
getLayerImpl(layer).mRenderState.mLayerColor.g = color.g;
getLayerImpl(layer).mRenderState.mLayerColor.b = color.b;
getLayerImpl(layer).mRenderState.mLayerColor.a = color.a;
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setLayerCompositionType(Display /*display*/, Layer /*layer*/,
int32_t /*type*/) {
ALOGV("setLayerCompositionType");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setLayerDataspace(Display /*display*/, Layer /*layer*/,
int32_t /*dataspace*/) {
ALOGV("setLayerDataspace");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setLayerDisplayFrame(Display /*display*/, Layer layer,
const hwc_rect_t& frame) {
ALOGV("setLayerDisplayFrame (%d, %d, %d, %d)", frame.left, frame.top, frame.right,
frame.bottom);
getLayerImpl(layer).mRenderState.mDisplayFrame = frame;
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setLayerPlaneAlpha(Display /*display*/, Layer layer, float alpha) {
ALOGV("setLayerPlaneAlpha");
getLayerImpl(layer).mRenderState.mPlaneAlpha = alpha;
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setLayerSidebandStream(Display /*display*/, Layer /*layer*/,
buffer_handle_t /*stream*/) {
ALOGV("setLayerSidebandStream");
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setLayerSourceCrop(Display /*display*/, Layer layer,
const hwc_frect_t& crop) {
ALOGV("setLayerSourceCrop");
getLayerImpl(layer).mRenderState.mSourceCrop = crop;
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setLayerTransform(Display /*display*/, Layer layer,
int32_t transform) {
ALOGV("setLayerTransform");
getLayerImpl(layer).mRenderState.mTransform = static_cast<hwc_transform_t>(transform);
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setLayerVisibleRegion(Display /*display*/, Layer layer,
const std::vector<hwc_rect_t>& visible) {
ALOGV("setLayerVisibleRegion");
getLayerImpl(layer).mRenderState.mVisibleRegion = visible;
return V2_1::Error::NONE;
}
V2_1::Error FakeComposerClient::setLayerZOrder(Display /*display*/, Layer layer, uint32_t z) {
ALOGV("setLayerZOrder");
getLayerImpl(layer).mZ = z;
return V2_1::Error::NONE;
}
// Composer 2.2
V2_1::Error FakeComposerClient::getPerFrameMetadataKeys(
Display /*display*/, std::vector<V2_2::IComposerClient::PerFrameMetadataKey>* /*outKeys*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::setLayerPerFrameMetadata(
Display /*display*/, Layer /*layer*/,
const std::vector<V2_2::IComposerClient::PerFrameMetadata>& /*metadata*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::getReadbackBufferAttributes(
Display /*display*/, graphics::common::V1_1::PixelFormat* /*outFormat*/,
graphics::common::V1_1::Dataspace* /*outDataspace*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::setReadbackBuffer(Display /*display*/,
const native_handle_t* /*bufferHandle*/,
android::base::unique_fd /*fenceFd*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::getReadbackBufferFence(Display /*display*/,
android::base::unique_fd* /*outFenceFd*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::createVirtualDisplay_2_2(
uint32_t /*width*/, uint32_t /*height*/, graphics::common::V1_1::PixelFormat* /*format*/,
Display* /*outDisplay*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::getClientTargetSupport_2_2(
Display /*display*/, uint32_t /*width*/, uint32_t /*height*/,
graphics::common::V1_1::PixelFormat /*format*/,
graphics::common::V1_1::Dataspace /*dataspace*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::setPowerMode_2_2(Display /*display*/,
V2_2::IComposerClient::PowerMode /*mode*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::setLayerFloatColor(Display /*display*/, Layer /*layer*/,
V2_2::IComposerClient::FloatColor /*color*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::getColorModes_2_2(
Display /*display*/, hidl_vec<graphics::common::V1_1::ColorMode>* /*outModes*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::getRenderIntents(
Display /*display*/, graphics::common::V1_1::ColorMode /*mode*/,
std::vector<graphics::common::V1_1::RenderIntent>* /*outIntents*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::setColorMode_2_2(Display /*display*/,
graphics::common::V1_1::ColorMode /*mode*/,
graphics::common::V1_1::RenderIntent /*intent*/) {
return V2_1::Error::UNSUPPORTED;
}
std::array<float, 16> FakeComposerClient::getDataspaceSaturationMatrix(
graphics::common::V1_1::Dataspace /*dataspace*/) {
return {};
}
// Composer 2.3
V2_1::Error FakeComposerClient::getPerFrameMetadataKeys_2_3(
Display /*display*/, std::vector<V2_3::IComposerClient::PerFrameMetadataKey>* /*outKeys*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::setColorMode_2_3(Display /*display*/,
graphics::common::V1_2::ColorMode /*mode*/,
graphics::common::V1_1::RenderIntent /*intent*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::getRenderIntents_2_3(
Display /*display*/, graphics::common::V1_2::ColorMode /*mode*/,
std::vector<graphics::common::V1_1::RenderIntent>* /*outIntents*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::getColorModes_2_3(
Display /*display*/, hidl_vec<graphics::common::V1_2::ColorMode>* /*outModes*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::getClientTargetSupport_2_3(
Display /*display*/, uint32_t /*width*/, uint32_t /*height*/,
graphics::common::V1_2::PixelFormat /*format*/,
graphics::common::V1_2::Dataspace /*dataspace*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::getReadbackBufferAttributes_2_3(
Display /*display*/, graphics::common::V1_2::PixelFormat* /*outFormat*/,
graphics::common::V1_2::Dataspace* /*outDataspace*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::getHdrCapabilities_2_3(
Display /*display*/, hidl_vec<graphics::common::V1_2::Hdr>* /*outTypes*/,
float* /*outMaxLuminance*/, float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::setLayerPerFrameMetadata_2_3(
Display /*display*/, Layer /*layer*/,
const std::vector<V2_3::IComposerClient::PerFrameMetadata>& /*metadata*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::getDisplayIdentificationData(Display /*display*/,
uint8_t* /*outPort*/,
std::vector<uint8_t>* /*outData*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::setLayerColorTransform(Display /*display*/, Layer /*layer*/,
const float* /*matrix*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::getDisplayedContentSamplingAttributes(
uint64_t /*display*/, graphics::common::V1_2::PixelFormat& /*format*/,
graphics::common::V1_2::Dataspace& /*dataspace*/,
hidl_bitfield<V2_3::IComposerClient::FormatColorComponent>& /*componentMask*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::setDisplayedContentSamplingEnabled(
uint64_t /*display*/, V2_3::IComposerClient::DisplayedContentSampling /*enable*/,
hidl_bitfield<V2_3::IComposerClient::FormatColorComponent> /*componentMask*/,
uint64_t /*maxFrames*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::getDisplayedContentSample(
uint64_t /*display*/, uint64_t /*maxFrames*/, uint64_t /*timestamp*/,
uint64_t& /*frameCount*/, hidl_vec<uint64_t>& /*sampleComponent0*/,
hidl_vec<uint64_t>& /*sampleComponent1*/, hidl_vec<uint64_t>& /*sampleComponent2*/,
hidl_vec<uint64_t>& /*sampleComponent3*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::getDisplayCapabilities(
Display /*display*/,
std::vector<V2_3::IComposerClient::DisplayCapability>* /*outCapabilities*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::setLayerPerFrameMetadataBlobs(
Display /*display*/, Layer /*layer*/,
std::vector<V2_3::IComposerClient::PerFrameMetadataBlob>& /*blobs*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::getDisplayBrightnessSupport(Display /*display*/,
bool* /*outSupport*/) {
return V2_1::Error::UNSUPPORTED;
}
V2_1::Error FakeComposerClient::setDisplayBrightness(Display /*display*/, float /*brightness*/) {
return V2_1::Error::UNSUPPORTED;
}
// Composer 2.4
void FakeComposerClient::registerEventCallback_2_4(EventCallback_2_4* callback) {
ALOGV("registerEventCallback_2_4");
LOG_FATAL_IF(mEventCallback != nullptr, "already registered using registerEventCallback");
mEventCallback_2_4 = callback;
if (mEventCallback_2_4) {
mEventCallback_2_4->onHotplug(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
}
}
void FakeComposerClient::unregisterEventCallback_2_4() {
ALOGV("unregisterEventCallback_2_4");
mEventCallback_2_4 = nullptr;
}
V2_4::Error FakeComposerClient::getDisplayCapabilities_2_4(
Display /*display*/,
std::vector<V2_4::IComposerClient::DisplayCapability>* /*outCapabilities*/) {
return V2_4::Error::UNSUPPORTED;
}
V2_4::Error FakeComposerClient::getDisplayConnectionType(
Display /*display*/, V2_4::IComposerClient::DisplayConnectionType* /*outType*/) {
return V2_4::Error::UNSUPPORTED;
}
V2_4::Error FakeComposerClient::getDisplayAttribute_2_4(Display display, Config config,
IComposerClient::Attribute attribute,
int32_t* outValue) {
ALOGV("getDisplayAttribute (%d, %d, %d, %p)", static_cast<int>(display),
static_cast<int>(config), static_cast<int>(attribute), outValue);
if (mMockHal) {
return mMockHal->getDisplayAttribute_2_4(display, config, attribute, outValue);
}
// TODO: SOOO much fun to be had with these alone
switch (attribute) {
case IComposerClient::Attribute::WIDTH:
*outValue = 1920;
break;
case IComposerClient::Attribute::HEIGHT:
*outValue = 1080;
break;
case IComposerClient::Attribute::VSYNC_PERIOD:
*outValue = 1666666666;
break; // TOOD: Tests break down if lowered to 16ms?
case IComposerClient::Attribute::DPI_X:
*outValue = 240;
break;
case IComposerClient::Attribute::DPI_Y:
*outValue = 240;
break;
default:
LOG_ALWAYS_FATAL("Say what!?! New attribute");
}
return Error::NONE;
}
V2_4::Error FakeComposerClient::getDisplayVsyncPeriod(Display display,
V2_4::VsyncPeriodNanos* outVsyncPeriod) {
ALOGV("getDisplayVsyncPeriod");
if (mMockHal) {
return mMockHal->getDisplayVsyncPeriod(display, outVsyncPeriod);
}
return V2_4::Error::UNSUPPORTED;
}
V2_4::Error FakeComposerClient::setActiveConfigWithConstraints(
Display display, Config config,
const V2_4::IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
VsyncPeriodChangeTimeline* timeline) {
ALOGV("setActiveConfigWithConstraints");
if (mMockHal) {
return mMockHal->setActiveConfigWithConstraints(display, config,
vsyncPeriodChangeConstraints, timeline);
}
return V2_4::Error::UNSUPPORTED;
}
V2_4::Error FakeComposerClient::setAutoLowLatencyMode(Display, bool) {
ALOGV("setAutoLowLatencyMode");
return V2_4::Error::UNSUPPORTED;
}
V2_4::Error FakeComposerClient::getSupportedContentTypes(
Display, std::vector<IComposerClient::ContentType>*) {
ALOGV("getSupportedContentTypes");
return V2_4::Error::UNSUPPORTED;
}
V2_4::Error FakeComposerClient::setContentType(Display, IComposerClient::ContentType) {
ALOGV("setContentType");
return V2_4::Error::UNSUPPORTED;
}
V2_4::Error FakeComposerClient::validateDisplay_2_4(
Display /*display*/, std::vector<Layer>* /*outChangedLayers*/,
std::vector<IComposerClient::Composition>* /*outCompositionTypes*/,
uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/,
std::vector<uint32_t>* /*outRequestMasks*/,
IComposerClient::ClientTargetProperty* /*outClientTargetProperty*/) {
return V2_4::Error::NONE;
}
V2_4::Error FakeComposerClient::setLayerGenericMetadata(Display, Layer, const std::string&, bool,
const std::vector<uint8_t>&) {
ALOGV("setLayerGenericMetadata");
return V2_4::Error::UNSUPPORTED;
}
V2_4::Error FakeComposerClient::getLayerGenericMetadataKeys(
std::vector<IComposerClient::LayerGenericMetadataKey>*) {
ALOGV("getLayerGenericMetadataKeys");
return V2_4::Error::UNSUPPORTED;
}
//////////////////////////////////////////////////////////////////
void FakeComposerClient::requestVSync(uint64_t vsyncTime) {
if (mEventCallback || mEventCallback_2_4) {
uint64_t timestamp = vsyncTime;
ALOGV("Vsync");
if (timestamp == 0) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
timestamp = ts.tv_sec * 1000 * 1000 * 1000 + ts.tv_nsec;
}
if (mSurfaceComposer != nullptr) {
mSurfaceComposer->injectVSync(timestamp);
} else if (mEventCallback) {
mEventCallback->onVsync(PRIMARY_DISPLAY, timestamp);
} else {
mEventCallback_2_4->onVsync_2_4(PRIMARY_DISPLAY, timestamp, 16'666'666);
}
}
}
void FakeComposerClient::runVSyncAfter(std::chrono::nanoseconds wait) {
mDelayedEventGenerator->wakeAfter(wait);
}
LayerImpl& FakeComposerClient::getLayerImpl(Layer handle) {
// TODO Change these to an internal state check that can be
// invoked from the gtest? GTest macros do not seem all that safe
// when used outside the test class
EXPECT_GE(handle, static_cast<Layer>(0));
EXPECT_LT(handle, mLayers.size());
return *(mLayers[handle]);
}
int FakeComposerClient::getFrameCount() const {
return mFrames.size();
}
static std::vector<RenderState> extractRenderState(
const std::vector<std::unique_ptr<FrameRect>>& internalRects) {
std::vector<RenderState> result;
result.reserve(internalRects.size());
for (const std::unique_ptr<FrameRect>& rect : internalRects) {
result.push_back(rect->renderState);
}
return result;
}
std::vector<RenderState> FakeComposerClient::getFrameRects(int frame) const {
Mutex::Autolock _l(mStateMutex);
return extractRenderState(mFrames[frame]->rectangles);
}
std::vector<RenderState> FakeComposerClient::getLatestFrame() const {
Mutex::Autolock _l(mStateMutex);
return extractRenderState(mFrames[mFrames.size() - 1]->rectangles);
}
void FakeComposerClient::runVSyncAndWait(std::chrono::nanoseconds maxWait) {
int currentFrame = 0;
{
Mutex::Autolock _l(mStateMutex); // I hope this is ok...
currentFrame = static_cast<int>(mFrames.size());
requestVSync();
}
waitUntilFrame(currentFrame + 1, maxWait);
}
void FakeComposerClient::waitUntilFrame(int targetFrame, std::chrono::nanoseconds maxWait) const {
Mutex::Autolock _l(mStateMutex);
while (mFrames.size() < static_cast<size_t>(targetFrame)) {
android::status_t result = mFramesAvailable.waitRelative(mStateMutex, maxWait.count());
if (result == android::TIMED_OUT) {
ALOGE("Waiting for frame %d (at frame %zu now) timed out after %lld ns", targetFrame,
mFrames.size(), maxWait.count());
return;
}
}
}
void FakeComposerClient::clearFrames() {
Mutex::Autolock _l(mStateMutex);
mFrames.clear();
for (const std::unique_ptr<LayerImpl>& layer : mLayers) {
if (layer->mValid) {
layer->mRenderState.mSwapCount = 0;
}
}
}
void FakeComposerClient::onSurfaceFlingerStart() {
mSurfaceComposer = nullptr;
do {
mSurfaceComposer = new android::SurfaceComposerClient;
android::status_t initResult = mSurfaceComposer->initCheck();
if (initResult != android::NO_ERROR) {
ALOGD("Init result: %d", initResult);
mSurfaceComposer = nullptr;
std::this_thread::sleep_for(10ms);
}
} while (mSurfaceComposer == nullptr);
ALOGD("SurfaceComposerClient created");
mSurfaceComposer->enableVSyncInjections(true);
}
void FakeComposerClient::onSurfaceFlingerStop() {
mSurfaceComposer->dispose();
mSurfaceComposer.clear();
}
// Includes destroyed layers, stored in order of creation.
int FakeComposerClient::getLayerCount() const {
return mLayers.size();
}
Layer FakeComposerClient::getLayer(size_t index) const {
// NOTE: If/when passing calls through to actual implementation,
// this might get more involving.
return static_cast<Layer>(index);
}
// TODO(b/129481165): remove the #pragma below and fix conversion issues
#pragma clang diagnostic pop // ignored "-Wconversion"