diff options
64 files changed, 1118 insertions, 865 deletions
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp index 04884bb3ec..180fd97d24 100644 --- a/libs/dumputils/dump_utils.cpp +++ b/libs/dumputils/dump_utils.cpp @@ -31,6 +31,7 @@ static const char* native_processes_to_dump[] = { "/system/bin/mediaextractor", // media.extractor "/system/bin/mediametrics", // media.metrics "/system/bin/mediaserver", + "/system/bin/netd", "/system/bin/sdcard", "/system/bin/statsd", "/system/bin/surfaceflinger", @@ -51,6 +52,7 @@ static const char* hal_interfaces_to_dump[] { "android.hardware.health@2.0::IHealth", "android.hardware.media.omx@1.0::IOmx", "android.hardware.media.omx@1.0::IOmxStore", + "android.hardware.power.stats@1.0::IPowerStats", "android.hardware.sensors@1.0::ISensors", "android.hardware.vr@1.0::IVr", NULL, diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp index 776c6e6c11..e2261360b6 100644 --- a/libs/gui/BufferQueueConsumer.cpp +++ b/libs/gui/BufferQueueConsumer.cpp @@ -190,6 +190,7 @@ status_t BufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, desiredPresent - expectedPresent, systemTime(CLOCK_MONOTONIC), front->mFrameNumber, maxFrameNumber); + ATRACE_NAME("PRESENT_LATER"); return PRESENT_LATER; } diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp index 96c55acdb0..e0e3431ca5 100644 --- a/libs/gui/BufferQueueCore.cpp +++ b/libs/gui/BufferQueueCore.cpp @@ -73,6 +73,8 @@ BufferQueueCore::BufferQueueCore() : mActiveBuffers(), mDequeueCondition(), mDequeueBufferCannotBlock(false), + mQueueBufferCanDrop(false), + mLegacyBufferDrop(true), mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), mDefaultWidth(1), mDefaultHeight(1), @@ -117,6 +119,8 @@ void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const mMaxAcquiredBufferCount, mMaxDequeuedBufferCount); outResult->appendFormat("%s mDequeueBufferCannotBlock=%d mAsyncMode=%d\n", prefix.string(), mDequeueBufferCannotBlock, mAsyncMode); + outResult->appendFormat("%s mQueueBufferCanDrop=%d mLegacyBufferDrop=%d\n", prefix.string(), + mQueueBufferCanDrop, mLegacyBufferDrop); outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.string(), mDefaultWidth, mDefaultHeight, mDefaultBufferFormat); outResult->appendFormat("transform-hint=%02x frame-counter=%" PRIu64, mTransformHint, diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp index 72ae3758c8..4ff69c57ce 100644 --- a/libs/gui/BufferQueueProducer.cpp +++ b/libs/gui/BufferQueueProducer.cpp @@ -889,7 +889,8 @@ status_t BufferQueueProducer::queueBuffer(int slot, item.mFence = acquireFence; item.mFenceTime = acquireFenceTime; item.mIsDroppable = mCore->mAsyncMode || - mCore->mDequeueBufferCannotBlock || + (!mCore->mLegacyBufferDrop && mConsumerIsSurfaceFlinger) || + (mCore->mLegacyBufferDrop && mCore->mQueueBufferCanDrop) || (mCore->mSharedBufferMode && mCore->mSharedBufferSlot == slot); item.mSurfaceDamage = surfaceDamage; item.mQueuedBuffer = true; @@ -1230,9 +1231,11 @@ status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener, mCore->mConnectedPid = BufferQueueThreadState::getCallingPid(); mCore->mBufferHasBeenQueued = false; mCore->mDequeueBufferCannotBlock = false; - if (mDequeueTimeout < 0) { - mCore->mDequeueBufferCannotBlock = - mCore->mConsumerControlledByApp && producerControlledByApp; + mCore->mQueueBufferCanDrop = false; + mCore->mLegacyBufferDrop = true; + if (mCore->mConsumerControlledByApp && producerControlledByApp) { + mCore->mDequeueBufferCannotBlock = mDequeueTimeout < 0; + mCore->mQueueBufferCanDrop = mDequeueTimeout <= 0; } mCore->mAllowAllocation = true; @@ -1516,12 +1519,26 @@ status_t BufferQueueProducer::setDequeueTimeout(nsecs_t timeout) { } mDequeueTimeout = timeout; - mCore->mDequeueBufferCannotBlock = false; + if (timeout >= 0) { + mCore->mDequeueBufferCannotBlock = false; + if (timeout != 0) { + mCore->mQueueBufferCanDrop = false; + } + } VALIDATE_CONSISTENCY(); return NO_ERROR; } +status_t BufferQueueProducer::setLegacyBufferDrop(bool drop) { + ATRACE_CALL(); + BQ_LOGV("setLegacyBufferDrop: drop = %d", drop); + + std::lock_guard<std::mutex> lock(mCore->mMutex); + mCore->mLegacyBufferDrop = drop; + return NO_ERROR; +} + status_t BufferQueueProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, float outTransformMatrix[16]) { ATRACE_CALL(); diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp index bf44121677..0e03b7d393 100644 --- a/libs/gui/IGraphicBufferProducer.cpp +++ b/libs/gui/IGraphicBufferProducer.cpp @@ -72,6 +72,7 @@ enum { GET_FRAME_TIMESTAMPS, GET_UNIQUE_ID, GET_CONSUMER_USAGE, + SET_LEGACY_BUFFER_DROP, }; class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer> @@ -437,6 +438,20 @@ public: return reply.readInt32(); } + virtual status_t setLegacyBufferDrop(bool drop) { + Parcel data, reply; + data.writeInterfaceToken( + IGraphicBufferProducer::getInterfaceDescriptor()); + data.writeInt32(drop); + status_t result = remote()->transact(SET_LEGACY_BUFFER_DROP, + data, &reply); + if (result != NO_ERROR) { + return result; + } + result = reply.readInt32(); + return result; + } + virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, float outTransformMatrix[16]) override { Parcel data, reply; @@ -637,6 +652,10 @@ public: return mBase->setDequeueTimeout(timeout); } + status_t setLegacyBufferDrop(bool drop) override { + return mBase->setLegacyBufferDrop(drop); + } + status_t getLastQueuedBuffer( sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, @@ -663,6 +682,12 @@ IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer, // ---------------------------------------------------------------------- +status_t IGraphicBufferProducer::setLegacyBufferDrop(bool drop) { + // No-op for IGBP other than BufferQueue. + (void) drop; + return INVALID_OPERATION; +} + status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) { status_t res = OK; res = parcel->writeUint32(USE_BUFFER_QUEUE); @@ -1018,6 +1043,13 @@ status_t BnGraphicBufferProducer::onTransact( } return NO_ERROR; } + case SET_LEGACY_BUFFER_DROP: { + CHECK_INTERFACE(IGraphicBufferProducer, data, reply); + bool drop = data.readInt32(); + int result = setLegacyBufferDrop(drop); + reply->writeInt32(result); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 8d7baf34ae..a3165ddb9e 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -109,7 +109,7 @@ public: } virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer, - const ui::Dataspace reqDataspace, + bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, ISurfaceComposer::Rotation rotation, bool captureSecureLayers) { @@ -137,6 +137,7 @@ public: *outBuffer = new GraphicBuffer(); reply.read(**outBuffer); + outCapturedSecureLayers = reply.readBool(); return result; } @@ -1027,12 +1028,17 @@ status_t BnSurfaceComposer::onTransact( int32_t rotation = data.readInt32(); bool captureSecureLayers = static_cast<bool>(data.readInt32()); - status_t res = captureScreen(display, &outBuffer, reqDataspace, reqPixelFormat, - sourceCrop, reqWidth, reqHeight, useIdentityTransform, - static_cast<ISurfaceComposer::Rotation>(rotation), captureSecureLayers); + bool capturedSecureLayers = false; + status_t res = captureScreen(display, &outBuffer, capturedSecureLayers, reqDataspace, + reqPixelFormat, sourceCrop, reqWidth, reqHeight, + useIdentityTransform, + static_cast<ISurfaceComposer::Rotation>(rotation), + captureSecureLayers); + reply->writeInt32(res); if (res == NO_ERROR) { reply->write(*outBuffer); + reply->writeBool(capturedSecureLayers); } return NO_ERROR; } diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp index 0e6170278f..611da89ef6 100644 --- a/libs/gui/SurfaceComposerClient.cpp +++ b/libs/gui/SurfaceComposerClient.cpp @@ -1542,13 +1542,15 @@ status_t SurfaceComposerClient::setDisplayBrightness(const sp<IBinder>& displayT status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace, const ui::PixelFormat reqPixelFormat, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, - uint32_t rotation, bool captureSecureLayers, sp<GraphicBuffer>* outBuffer) { + uint32_t rotation, bool captureSecureLayers, + sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers) { sp<ISurfaceComposer> s(ComposerService::getComposerService()); if (s == nullptr) return NO_INIT; - status_t ret = s->captureScreen(display, outBuffer, reqDataSpace, reqPixelFormat, sourceCrop, - reqWidth, reqHeight, useIdentityTransform, - static_cast<ISurfaceComposer::Rotation>(rotation), - captureSecureLayers); + status_t ret = + s->captureScreen(display, outBuffer, outCapturedSecureLayers, reqDataSpace, + reqPixelFormat, sourceCrop, reqWidth, reqHeight, useIdentityTransform, + static_cast<ISurfaceComposer::Rotation>(rotation), + captureSecureLayers); if (ret != NO_ERROR) { return ret; } @@ -1559,8 +1561,9 @@ status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspa const ui::PixelFormat reqPixelFormat, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, uint32_t rotation, sp<GraphicBuffer>* outBuffer) { - return capture(display, reqDataSpace, reqPixelFormat, sourceCrop, reqWidth, - reqHeight, useIdentityTransform, rotation, false, outBuffer); + bool ignored; + return capture(display, reqDataSpace, reqPixelFormat, sourceCrop, reqWidth, reqHeight, + useIdentityTransform, rotation, false, outBuffer, ignored); } status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h index 0e80283804..9c0ee99b59 100644 --- a/libs/gui/include/gui/BufferQueueCore.h +++ b/libs/gui/include/gui/BufferQueueCore.h @@ -226,6 +226,16 @@ private: // consumer are controlled by the application. bool mDequeueBufferCannotBlock; + // mQueueBufferCanDrop indicates whether queueBuffer is allowed to drop + // buffers in non-async mode. This flag is set during connect when both the + // producer and consumer are controlled by application. + bool mQueueBufferCanDrop; + + // mLegacyBufferDrop indicates whether mQueueBufferCanDrop is in effect. + // If this flag is set mQueueBufferCanDrop is working as explained. If not + // queueBuffer will not drop buffers unless consumer is SurfaceFlinger. + bool mLegacyBufferDrop; + // mDefaultBufferFormat can be set so it will override the buffer format // when it isn't specified in dequeueBuffer. PixelFormat mDefaultBufferFormat; diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h index 415e2a616e..d2a47a6aa8 100644 --- a/libs/gui/include/gui/BufferQueueProducer.h +++ b/libs/gui/include/gui/BufferQueueProducer.h @@ -174,6 +174,9 @@ public: // See IGraphicBufferProducer::setDequeueTimeout virtual status_t setDequeueTimeout(nsecs_t timeout) override; + // see IGraphicBufferProducer::setLegacyBufferDrop + virtual status_t setLegacyBufferDrop(bool drop); + // See IGraphicBufferProducer::getLastQueuedBuffer virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, float outTransformMatrix[16]) override; diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h index 9f7e22bac5..3dde8c8c80 100644 --- a/libs/gui/include/gui/IGraphicBufferProducer.h +++ b/libs/gui/include/gui/IGraphicBufferProducer.h @@ -592,12 +592,20 @@ public: // non-blocking mode and its corresponding spare buffer (which is used to // ensure a buffer is always available). // + // Note well: queueBuffer will stop buffer dropping behavior if timeout is + // strictly positive. If timeout is zero or negative, previous buffer + // dropping behavior will not be changed. + // // Return of a value other than NO_ERROR means an error has occurred: // * BAD_VALUE - Failure to adjust the number of available slots. This can // happen because of trying to allocate/deallocate the async // buffer. virtual status_t setDequeueTimeout(nsecs_t timeout) = 0; + // Used to enable/disable buffer drop behavior of queueBuffer. + // If it's not used, legacy drop behavior will be retained. + virtual status_t setLegacyBufferDrop(bool drop); + // Returns the last queued buffer along with a fence which must signal // before the contents of the buffer are read. If there are no buffers in // the queue, outBuffer will be populated with nullptr and outFence will be diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h index 14d92bf04e..415b2d58ec 100644 --- a/libs/gui/include/gui/ISurfaceComposer.h +++ b/libs/gui/include/gui/ISurfaceComposer.h @@ -212,7 +212,7 @@ public: * it) around its center. */ virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer, - const ui::Dataspace reqDataspace, + bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, Rotation rotation = eRotateNone, @@ -241,8 +241,10 @@ public: virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, Rotation rotation = eRotateNone) { - return captureScreen(display, outBuffer, ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, - sourceCrop, reqWidth, reqHeight, useIdentityTransform, rotation); + bool outIgnored; + return captureScreen(display, outBuffer, outIgnored, ui::Dataspace::V0_SRGB, + ui::PixelFormat::RGBA_8888, sourceCrop, reqWidth, reqHeight, + useIdentityTransform, rotation); } template <class AA> diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h index f64fb61ecb..9d344689df 100644 --- a/libs/gui/include/gui/SurfaceComposerClient.h +++ b/libs/gui/include/gui/SurfaceComposerClient.h @@ -509,7 +509,8 @@ public: static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace, const ui::PixelFormat reqPixelFormat, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, - uint32_t rotation, bool captureSecureLayers, sp<GraphicBuffer>* outBuffer); + uint32_t rotation, bool captureSecureLayers, + sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers); static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace, const ui::PixelFormat reqPixelFormat, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp index fa2e97f1a8..d5bdd74a86 100644 --- a/libs/gui/tests/Surface_test.cpp +++ b/libs/gui/tests/Surface_test.cpp @@ -126,7 +126,7 @@ TEST_F(SurfaceTest, QueuesToWindowComposerIsTrueWhenPurgatorized) { } // This test probably doesn't belong here. -TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { +TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersDontSucceed) { sp<ANativeWindow> anw(mSurface); // Verify the screenshot works with no protected buffers. @@ -136,8 +136,9 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { ASSERT_FALSE(display == nullptr); sp<GraphicBuffer> outBuffer; + bool ignored; ASSERT_EQ(NO_ERROR, - sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB, + sf->captureScreen(display, &outBuffer, ignored, ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), 64, 64, false)); ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), @@ -169,7 +170,7 @@ TEST_F(SurfaceTest, ScreenshotsOfProtectedBuffersSucceed) { ASSERT_EQ(NO_ERROR, anw->queueBuffer(anw.get(), buf, -1)); } ASSERT_EQ(NO_ERROR, - sf->captureScreen(display, &outBuffer, ui::Dataspace::V0_SRGB, + sf->captureScreen(display, &outBuffer, ignored, ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), 64, 64, false)); } @@ -615,6 +616,7 @@ public: status_t setActiveColorMode(const sp<IBinder>& /*display*/, ColorMode /*colorMode*/) override { return NO_ERROR; } status_t captureScreen(const sp<IBinder>& /*display*/, sp<GraphicBuffer>* /*outBuffer*/, + bool& /* outCapturedSecureLayers */, const ui::Dataspace /*reqDataspace*/, const ui::PixelFormat /*reqPixelFormat*/, Rect /*sourceCrop*/, uint32_t /*reqWidth*/, uint32_t /*reqHeight*/, diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index a6ed75f1ac..6570704aba 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -579,10 +579,9 @@ status_t SensorDevice::activateLocked(void* ident, int handle, int enabled) { } if (info.batchParams.indexOfKey(ident) >= 0) { - if (info.numActiveClients() == 1) { - // This is the first connection, we need to activate the underlying h/w sensor. - actuateHardware = true; - } + if (info.numActiveClients() > 0 && !info.isActive) { + actuateHardware = true; + } } else { // Log error. Every activate call should be preceded by a batch() call. ALOGE("\t >>>ERROR: activate called without batch"); @@ -631,6 +630,11 @@ status_t SensorDevice::activateLocked(void* ident, int handle, int enabled) { if (err != NO_ERROR && enabled) { // Failure when enabling the sensor. Clean up on failure. info.removeBatchParamsForIdent(ident); + } else { + // Update the isActive flag if there is no error. If there is an error when disabling a + // sensor, still set the flag to false since the batch parameters have already been + // removed. This ensures that everything remains in-sync. + info.isActive = enabled; } } diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h index 71b918f639..e8685c292c 100644 --- a/services/sensorservice/SensorDevice.h +++ b/services/sensorservice/SensorDevice.h @@ -165,6 +165,9 @@ private: // requested by the client. KeyedVector<void*, BatchParams> batchParams; + // Flag to track if the sensor is active + bool isActive = false; + // Sets batch parameters for this ident. Returns error if this ident is not already present // in the KeyedVector above. status_t setBatchParamsForIdent(void* ident, int flags, int64_t samplingPeriodNs, diff --git a/services/surfaceflinger/AllowedDisplayConfigs.h b/services/surfaceflinger/AllowedDisplayConfigs.h deleted file mode 100644 index 7ca62ea550..0000000000 --- a/services/surfaceflinger/AllowedDisplayConfigs.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2019 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 <log/log.h> -#include <vector> - -/* - * Used to represent the Display Configurations allowed to be set by SurfaceFlinger - */ -class AllowedDisplayConfigs { -private: - // Defining ConstructorTag as private to prevent instantiating this class from outside - // while still allowing it to be constructed by std::make_unique - struct ConstructorTag {}; - -public: - AllowedDisplayConfigs(ConstructorTag) {} - - class Builder { - public: - Builder() - : mAllowedDisplayConfigs(std::make_unique<AllowedDisplayConfigs>(ConstructorTag{})) {} - - std::unique_ptr<const AllowedDisplayConfigs> build() { - return std::move(mAllowedDisplayConfigs); - } - - // add a config to the allowed config set - Builder& addConfig(int32_t config) { - mAllowedDisplayConfigs->addConfig(config); - return *this; - } - - private: - std::unique_ptr<AllowedDisplayConfigs> mAllowedDisplayConfigs; - }; - - bool isConfigAllowed(int32_t config) const { - return (std::find(mConfigs.begin(), mConfigs.end(), config) != mConfigs.end()); - } - - void getAllowedConfigs(std::vector<int32_t>* outConfigs) const { - if (outConfigs) { - *outConfigs = mConfigs; - } - } - -private: - // add a config to the allowed config set - void addConfig(int32_t config) { mConfigs.push_back(config); } - - std::vector<int32_t> mConfigs; -}; diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp index 52c68df814..9080d29194 100644 --- a/services/surfaceflinger/Android.bp +++ b/services/surfaceflinger/Android.bp @@ -147,6 +147,7 @@ filegroup { "Scheduler/EventThread.cpp", "Scheduler/IdleTimer.cpp", "Scheduler/LayerHistory.cpp", + "Scheduler/LayerInfo.cpp", "Scheduler/MessageQueue.cpp", "Scheduler/Scheduler.cpp", "Scheduler/SchedulerUtils.cpp", diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp index 1b2b180c52..a08ae8c7e6 100644 --- a/services/surfaceflinger/BufferLayer.cpp +++ b/services/surfaceflinger/BufferLayer.cpp @@ -413,6 +413,7 @@ bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) // If the head buffer's acquire fence hasn't signaled yet, return and // try again later if (!fenceHasSignaled()) { + ATRACE_NAME("!fenceHasSignaled()"); mFlinger->signalLayerUpdate(); return false; } diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index b623991742..ff5f271960 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -398,8 +398,8 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { // Add this buffer from our internal queue tracker { // Autolock scope if (mFlinger->mUseSmart90ForVideo) { - // Report mApi ID for each layer. - mFlinger->mScheduler->addNativeWindowApi(item.mApi); + const nsecs_t presentTime = item.mIsAutoTimestamp ? 0 : item.mTimestamp; + mFlinger->mScheduler->addLayerPresentTime(mSchedulerLayerHandle, presentTime); } Mutex::Autolock lock(mQueueItemLock); diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index 64dfdc3d5e..2cbb917478 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -209,7 +209,8 @@ bool BufferStateLayer::setFrame(const Rect& frame) { return true; } -bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer) { +bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTime, + nsecs_t desiredPresentTime) { if (mCurrentState.buffer) { mReleasePreviousBuffer = true; } @@ -217,6 +218,15 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer) { mCurrentState.buffer = buffer; mCurrentState.modified = true; setTransactionFlags(eTransactionNeeded); + + mFlinger->mTimeStats->setPostTime(getSequence(), getFrameNumber(), getName().c_str(), postTime); + mDesiredPresentTime = desiredPresentTime; + + if (mFlinger->mUseSmart90ForVideo) { + const nsecs_t presentTime = (mDesiredPresentTime == -1) ? 0 : mDesiredPresentTime; + mFlinger->mScheduler->addLayerPresentTime(mSchedulerLayerHandle, presentTime); + } + return true; } @@ -348,14 +358,6 @@ FloatRect BufferStateLayer::computeSourceBounds(const FloatRect& parentBounds) c return parentBounds; } -void BufferStateLayer::setPostTime(nsecs_t postTime) { - mFlinger->mTimeStats->setPostTime(getSequence(), getFrameNumber(), getName().c_str(), postTime); -} - -void BufferStateLayer::setDesiredPresentTime(nsecs_t desiredPresentTime) { - mDesiredPresentTime = desiredPresentTime; -} - // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h index 668830a3fe..864a15db1f 100644 --- a/services/surfaceflinger/BufferStateLayer.h +++ b/services/surfaceflinger/BufferStateLayer.h @@ -63,7 +63,8 @@ public: bool setTransformToDisplayInverse(bool transformToDisplayInverse) override; bool setCrop(const Rect& crop) override; bool setFrame(const Rect& frame) override; - bool setBuffer(const sp<GraphicBuffer>& buffer) override; + bool setBuffer(const sp<GraphicBuffer>& buffer, nsecs_t postTime, + nsecs_t desiredPresentTime) override; bool setAcquireFence(const sp<Fence>& fence) override; bool setDataspace(ui::Dataspace dataspace) override; bool setHdrMetadata(const HdrMetadata& hdrMetadata) override; @@ -90,8 +91,6 @@ public: Rect getBufferSize(const State& s) const override; FloatRect computeSourceBounds(const FloatRect& parentBounds) const override; - void setPostTime(nsecs_t postTime) override; - void setDesiredPresentTime(nsecs_t desiredPresentTime) override; // ----------------------------------------------------------------------- // ----------------------------------------------------------------------- diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 1142df8460..2bbac72ffe 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -70,7 +70,10 @@ using base::StringAppendF; std::atomic<int32_t> Layer::sSequence{1}; Layer::Layer(const LayerCreationArgs& args) - : mFlinger(args.flinger), mName(args.name), mClientRef(args.client) { + : mFlinger(args.flinger), + mName(args.name), + mClientRef(args.client), + mWindowType(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0)) { mCurrentCrop.makeInvalid(); uint32_t layerFlags = 0; @@ -115,6 +118,8 @@ Layer::Layer(const LayerCreationArgs& args) mFrameEventHistory.initializeCompositorTiming(compositorTiming); mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval); + mSchedulerLayerHandle = mFlinger->mScheduler->registerLayer(mName.c_str(), mWindowType); + mFlinger->onLayerCreated(); } @@ -1298,6 +1303,7 @@ void Layer::miniDumpHeader(std::string& result) { result.append("-----------------------------\n"); result.append(" Layer name\n"); result.append(" Z | "); + result.append(" Window Type | "); result.append(" Comp Type | "); result.append(" Transform | "); result.append(" Disp Frame (LTRB) | "); @@ -1334,6 +1340,7 @@ void Layer::miniDump(std::string& result, const sp<DisplayDevice>& displayDevice } else { StringAppendF(&result, " %10d | ", layerState.z); } + StringAppendF(&result, " %10d | ", mWindowType); StringAppendF(&result, "%10s | ", toString(getCompositionType(displayDevice)).c_str()); StringAppendF(&result, "%10s | ", toString(getCompositionLayer() ? compositionState.bufferTransform @@ -1804,8 +1811,9 @@ Layer::RoundedCornerState Layer::getRoundedCornerState() const { } } const float radius = getDrawingState().cornerRadius; - return radius > 0 ? RoundedCornerState(getCrop(getDrawingState()).toFloatRect(), radius) - : RoundedCornerState(); + return radius > 0 && getCrop(getDrawingState()).isValid() + ? RoundedCornerState(getCrop(getDrawingState()).toFloatRect(), radius) + : RoundedCornerState(); } void Layer::commitChildList() { diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 8348ce1f38..f4545e0538 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -311,7 +311,10 @@ public: virtual bool setTransformToDisplayInverse(bool /*transformToDisplayInverse*/) { return false; }; virtual bool setCrop(const Rect& /*crop*/) { return false; }; virtual bool setFrame(const Rect& /*frame*/) { return false; }; - virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/) { return false; }; + virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/, nsecs_t /*postTime*/, + nsecs_t /*desiredPresentTime*/) { + return false; + } virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; }; virtual bool setDataspace(ui::Dataspace /*dataspace*/) { return false; }; virtual bool setHdrMetadata(const HdrMetadata& /*hdrMetadata*/) { return false; }; @@ -450,9 +453,6 @@ public: } virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; } - virtual void setPostTime(nsecs_t /*postTime*/) {} - virtual void setDesiredPresentTime(nsecs_t /*desiredPresentTime*/) {} - protected: virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, bool useIdentityTransform, Region& clearRegion, @@ -885,6 +885,12 @@ protected: // Can only be accessed with the SF state lock held. bool mChildrenChanged{false}; + // Window types from WindowManager.LayoutParams + const int mWindowType; + + // This is populated if the layer is registered with Scheduler for tracking purposes. + std::unique_ptr<scheduler::LayerHistory::LayerHandle> mSchedulerLayerHandle; + private: /** * Returns an unsorted vector of all layers that are part of this tree. diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp index 06e3d9c154..c60421b538 100644 --- a/services/surfaceflinger/MonitoredProducer.cpp +++ b/services/surfaceflinger/MonitoredProducer.cpp @@ -132,6 +132,10 @@ status_t MonitoredProducer::setDequeueTimeout(nsecs_t timeout) { return mProducer->setDequeueTimeout(timeout); } +status_t MonitoredProducer::setLegacyBufferDrop(bool drop) { + return mProducer->setLegacyBufferDrop(drop); +} + status_t MonitoredProducer::getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, float outTransformMatrix[16]) { return mProducer->getLastQueuedBuffer(outBuffer, outFence, diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h index 1246d142f3..d346f821d3 100644 --- a/services/surfaceflinger/MonitoredProducer.h +++ b/services/surfaceflinger/MonitoredProducer.h @@ -61,6 +61,7 @@ public: virtual status_t setGenerationNumber(uint32_t generationNumber); virtual String8 getConsumerName() const override; virtual status_t setDequeueTimeout(nsecs_t timeout) override; + virtual status_t setLegacyBufferDrop(bool drop) override; virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence, float outTransformMatrix[16]) override; virtual IBinder* onAsBinder(); diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS index ce0611c755..69d8c89b45 100644 --- a/services/surfaceflinger/OWNERS +++ b/services/surfaceflinger/OWNERS @@ -1,4 +1,6 @@ +adyabr@google.com akrulec@google.com +alecmouri@google.com chaviw@google.com lpy@google.com marissaw@google.com diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp index 35f11fc494..252ff0d611 100644 --- a/services/surfaceflinger/RegionSamplingThread.cpp +++ b/services/surfaceflinger/RegionSamplingThread.cpp @@ -392,7 +392,8 @@ void RegionSamplingThread::captureSample() { // // To avoid this, we drop the mutex while we call into SF. mMutex.unlock(); - mFlinger.captureScreenCommon(renderArea, traverseLayers, buffer, false); + bool ignored; + mFlinger.captureScreenCommon(renderArea, traverseLayers, buffer, false, ignored); mMutex.lock(); std::vector<Descriptor> activeDescriptors; diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp index f72aef1bdd..871f556988 100644 --- a/services/surfaceflinger/Scheduler/DispSync.cpp +++ b/services/surfaceflinger/Scheduler/DispSync.cpp @@ -210,14 +210,16 @@ public: const nsecs_t baseTime = now - mReferenceTime; const nsecs_t numPeriodsSinceReference = baseTime / mPeriod; const nsecs_t predictedReference = mReferenceTime + numPeriodsSinceReference * mPeriod; - const nsecs_t phaseCorrection = mPhase + listener.mPhase; - listener.mLastEventTime = predictedReference + phaseCorrection; + listener.mLastEventTime = predictedReference + mPhase + listener.mPhase; // If we're very close in time to the predicted last event time, + // and we're not very close to the next predicted last event time // then we need to back up the last event time so that we can // attempt to fire an event immediately. // - // Otherwise, keep the last event time that we predicted. - if (isShorterThanPeriod(now - listener.mLastEventTime)) { + // Otherwise, keep the last event time that we predicted so that + // we don't wake up early. + if (isShorterThanPeriod(now - listener.mLastEventTime) && + !isShorterThanPeriod(listener.mLastEventTime + mPeriod - now)) { listener.mLastEventTime -= mPeriod; } } else { @@ -279,7 +281,6 @@ public: return NO_ERROR; } } - return BAD_VALUE; } @@ -525,21 +526,40 @@ void DispSync::beginResync() { mNumResyncSamples = 0; } -bool DispSync::addResyncSample(nsecs_t timestamp) { +bool DispSync::addResyncSample(nsecs_t timestamp, bool* periodChanged) { Mutex::Autolock lock(mMutex); ALOGV("[%s] addResyncSample(%" PRId64 ")", mName, ns2us(timestamp)); - size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES; + *periodChanged = false; + const size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES; mResyncSamples[idx] = timestamp; if (mNumResyncSamples == 0) { mPhase = 0; - mReferenceTime = timestamp; ALOGV("[%s] First resync sample: mPeriod = %" PRId64 ", mPhase = 0, " "mReferenceTime = %" PRId64, - mName, ns2us(mPeriod), ns2us(mReferenceTime)); - mThread->updateModel(mPeriod, mPhase, mReferenceTime); + mName, ns2us(mPeriod), ns2us(timestamp)); + } else if (mPendingPeriod > 0) { + // mNumResyncSamples > 0, so priorIdx won't overflow + const size_t priorIdx = (mFirstResyncSample + mNumResyncSamples - 1) % MAX_RESYNC_SAMPLES; + const nsecs_t lastTimestamp = mResyncSamples[priorIdx]; + + const nsecs_t observedVsync = std::abs(timestamp - lastTimestamp); + if (std::abs(observedVsync - mPendingPeriod) < std::abs(observedVsync - mPeriod)) { + // Observed vsync is closer to the pending period, so reset the + // model and flush the pending period. + resetLocked(); + mPeriod = mPendingPeriod; + mPendingPeriod = 0; + if (mTraceDetailedInfo) { + ATRACE_INT("DispSync:PendingPeriod", mPendingPeriod); + } + *periodChanged = true; + } } + // Always update the reference time with the most recent timestamp. + mReferenceTime = timestamp; + mThread->updateModel(mPeriod, mPhase, mReferenceTime); if (mNumResyncSamples < MAX_RESYNC_SAMPLES) { mNumResyncSamples++; @@ -562,7 +582,7 @@ bool DispSync::addResyncSample(nsecs_t timestamp) { // Check against kErrorThreshold / 2 to add some hysteresis before having to // resync again - bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2); + bool modelLocked = mModelUpdated && mError < (kErrorThreshold / 2) && mPendingPeriod == 0; ALOGV("[%s] addResyncSample returning %s", mName, modelLocked ? "locked" : "unlocked"); return !modelLocked; } @@ -594,9 +614,10 @@ status_t DispSync::changePhaseOffset(Callback* callback, nsecs_t phase) { void DispSync::setPeriod(nsecs_t period) { Mutex::Autolock lock(mMutex); - mPeriod = period; - mPhase = 0; - mThread->updateModel(mPeriod, mPhase, mReferenceTime); + if (mTraceDetailedInfo) { + ATRACE_INT("DispSync:PendingPeriod", period); + } + mPendingPeriod = period; } nsecs_t DispSync::getPeriod() { diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h index de2b8749c7..8f8b8e7a99 100644 --- a/services/surfaceflinger/Scheduler/DispSync.h +++ b/services/surfaceflinger/Scheduler/DispSync.h @@ -49,7 +49,7 @@ public: virtual void reset() = 0; virtual bool addPresentFence(const std::shared_ptr<FenceTime>&) = 0; virtual void beginResync() = 0; - virtual bool addResyncSample(nsecs_t timestamp) = 0; + virtual bool addResyncSample(nsecs_t timestamp, bool* periodChanged) = 0; virtual void endResync() = 0; virtual void setPeriod(nsecs_t period) = 0; virtual nsecs_t getPeriod() = 0; @@ -119,7 +119,13 @@ public: // addPresentFence returns true indicating that the model has drifted away // from the hardware vsync events. void beginResync() override; - bool addResyncSample(nsecs_t timestamp) override; + // Adds a vsync sample to the dispsync model. The timestamp is the time + // of the vsync event that fired. periodChanged will return true if the + // vsync period was detected to have changed to mPendingPeriod. + // + // This method will return true if more vsync samples are needed to lock + // down the DispSync model, and false otherwise. + bool addResyncSample(nsecs_t timestamp, bool* periodChanged) override; void endResync() override; // The setPeriod method sets the vsync event model's period to a specific @@ -199,6 +205,12 @@ private: // nanoseconds. nsecs_t mPeriod; + // mPendingPeriod is the proposed period change in nanoseconds. + // If mPendingPeriod differs from mPeriod and is nonzero, it will + // be flushed to mPeriod when we detect that the hardware switched + // vsync frequency. + nsecs_t mPendingPeriod = 0; + // mPhase is the phase offset of the modeled vsync events. It is the // number of nanoseconds from time 0 to the first vsync event. nsecs_t mPhase; diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp index 6e89648bdd..00948aedb4 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp +++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp @@ -87,19 +87,7 @@ void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) { } } -void DispSyncSource::pauseVsyncCallback(bool pause) { - std::lock_guard lock(mVsyncMutex); - mCallbackPaused = pause; -} - void DispSyncSource::onDispSyncEvent(nsecs_t when) { - { - std::lock_guard lock(mVsyncMutex); - if (mCallbackPaused) { - return; - } - } - VSyncSource::Callback* callback; { std::lock_guard lock(mCallbackMutex); diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h index 2858678108..4759699c5e 100644 --- a/services/surfaceflinger/Scheduler/DispSyncSource.h +++ b/services/surfaceflinger/Scheduler/DispSyncSource.h @@ -33,7 +33,6 @@ public: void setVSyncEnabled(bool enable) override; void setCallback(VSyncSource::Callback* callback) override; void setPhaseOffset(nsecs_t phaseOffset) override; - void pauseVsyncCallback(bool pause) override; private: // The following method is the implementation of the DispSync::Callback. @@ -55,7 +54,6 @@ private: std::mutex mVsyncMutex; nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex); bool mEnabled GUARDED_BY(mVsyncMutex) = false; - bool mCallbackPaused GUARDED_BY(mVsyncMutex) = false; }; } // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp index a760079069..a6c7e6ce65 100644 --- a/services/surfaceflinger/Scheduler/EventThread.cpp +++ b/services/surfaceflinger/Scheduler/EventThread.cpp @@ -210,12 +210,6 @@ void EventThread::setPhaseOffset(nsecs_t phaseOffset) { mVSyncSource->setPhaseOffset(phaseOffset); } -void EventThread::pauseVsyncCallback(bool pause) { - std::lock_guard<std::mutex> lock(mMutex); - ATRACE_INT("vsyncPaused", pause); - mVSyncSource->pauseVsyncCallback(pause); -} - sp<EventThreadConnection> EventThread::createEventConnection( ResyncCallback resyncCallback, ResetIdleTimerCallback resetIdleTimerCallback) const { return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback), diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h index 67e6de9ce2..7107d6388a 100644 --- a/services/surfaceflinger/Scheduler/EventThread.h +++ b/services/surfaceflinger/Scheduler/EventThread.h @@ -66,9 +66,6 @@ public: virtual void setVSyncEnabled(bool enable) = 0; virtual void setCallback(Callback* callback) = 0; virtual void setPhaseOffset(nsecs_t phaseOffset) = 0; - - // pause/resume vsync callback generation - virtual void pauseVsyncCallback(bool pause) = 0; }; class EventThreadConnection : public BnDisplayEventConnection { @@ -125,8 +122,6 @@ public: // Requests the next vsync. If resetIdleTimer is set to true, it resets the idle timer. virtual void requestNextVsync(const sp<EventThreadConnection>& connection, bool resetIdleTimer) = 0; - - virtual void pauseVsyncCallback(bool pause) = 0; }; namespace impl { @@ -162,8 +157,6 @@ public: void setPhaseOffset(nsecs_t phaseOffset) override; - void pauseVsyncCallback(bool pause) override; - private: friend EventThreadTest; diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp index d5ccbe186b..8e36ae9dc0 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.cpp +++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp @@ -14,14 +14,18 @@ * limitations under the License. */ +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + #include "LayerHistory.h" #include <cinttypes> #include <cstdint> +#include <limits> #include <numeric> #include <string> #include <unordered_map> +#include <cutils/properties.h> #include <utils/Log.h> #include <utils/Timers.h> #include <utils/Trace.h> @@ -29,28 +33,114 @@ #include "SchedulerUtils.h" namespace android { +namespace scheduler { + +std::atomic<int64_t> LayerHistory::sNextId = 0; -LayerHistory::LayerHistory() {} +LayerHistory::LayerHistory() { + char value[PROPERTY_VALUE_MAX]; + property_get("debug.sf.layer_history_trace", value, "0"); + mTraceEnabled = bool(atoi(value)); +} LayerHistory::~LayerHistory() = default; -void LayerHistory::insert(const std::string layerName, nsecs_t presentTime) { - mElements[mCounter].insert(std::make_pair(layerName, presentTime)); +std::unique_ptr<LayerHistory::LayerHandle> LayerHistory::createLayer(const std::string name, + float maxRefreshRate) { + const int64_t id = sNextId++; + + std::lock_guard lock(mLock); + mInactiveLayerInfos.emplace(id, std::make_shared<LayerInfo>(name, maxRefreshRate)); + return std::make_unique<LayerHistory::LayerHandle>(*this, id); +} + +void LayerHistory::destroyLayer(const int64_t id) { + std::lock_guard lock(mLock); + auto it = mActiveLayerInfos.find(id); + if (it != mActiveLayerInfos.end()) { + mActiveLayerInfos.erase(it); + } + + it = mInactiveLayerInfos.find(id); + if (it != mInactiveLayerInfos.end()) { + mInactiveLayerInfos.erase(it); + } +} + +void LayerHistory::insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime) { + std::shared_ptr<LayerInfo> layerInfo; + { + std::lock_guard lock(mLock); + auto layerInfoIterator = mInactiveLayerInfos.find(layerHandle->mId); + if (layerInfoIterator != mInactiveLayerInfos.end()) { + layerInfo = layerInfoIterator->second; + mInactiveLayerInfos.erase(layerInfoIterator); + mActiveLayerInfos.insert({layerHandle->mId, layerInfo}); + } else { + layerInfoIterator = mActiveLayerInfos.find(layerHandle->mId); + if (layerInfoIterator != mActiveLayerInfos.end()) { + layerInfo = layerInfoIterator->second; + } else { + ALOGW("Inserting information about layer that is not registered: %" PRId64, + layerHandle->mId); + return; + } + } + } + layerInfo->setLastPresentTime(presentTime); } -void LayerHistory::incrementCounter() { - mCounter++; - mCounter = mCounter % scheduler::ARRAY_SIZE; - // Clear all the previous data from the history. This is a ring buffer, so we are - // reusing memory. - mElements[mCounter].clear(); +float LayerHistory::getDesiredRefreshRate() { + float newRefreshRate = 0.f; + std::lock_guard lock(mLock); + + removeIrrelevantLayers(); + + // Iterate through all layers that have been recently updated, and find the max refresh rate. + for (const auto& [layerId, layerInfo] : mActiveLayerInfos) { + const float layerRefreshRate = layerInfo->getDesiredRefreshRate(); + if (mTraceEnabled) { + // Store the refresh rate in traces for easy debugging. + std::string layerName = "LFPS " + layerInfo->getName(); + ATRACE_INT(layerName.c_str(), std::round(layerRefreshRate)); + ALOGD("%s: %f", layerName.c_str(), std::round(layerRefreshRate)); + } + if (layerInfo->isRecentlyActive() && layerRefreshRate > newRefreshRate) { + newRefreshRate = layerRefreshRate; + } + } + if (mTraceEnabled) { + ALOGD("LayerHistory DesiredRefreshRate: %.2f", newRefreshRate); + } + + return newRefreshRate; } -const std::unordered_map<std::string, nsecs_t>& LayerHistory::get(size_t index) const { - // For the purposes of the layer history, the index = 0 always needs to start at the - // current counter, and then decrement to access the layers in correct historical order. - return mElements.at((scheduler::ARRAY_SIZE + (mCounter - (index % scheduler::ARRAY_SIZE))) % - scheduler::ARRAY_SIZE); +void LayerHistory::removeIrrelevantLayers() { + const int64_t obsoleteEpsilon = systemTime() - scheduler::OBSOLETE_TIME_EPSILON_NS.count(); + // Iterator pointing to first element in map + auto it = mActiveLayerInfos.begin(); + while (it != mActiveLayerInfos.end()) { + // If last updated was before the obsolete time, remove it. + if (it->second->getLastUpdatedTime() < obsoleteEpsilon) { + // erase() function returns the iterator of the next + // to last deleted element. + if (mTraceEnabled) { + ALOGD("Layer %s obsolete", it->second->getName().c_str()); + // Make sure to update systrace to indicate that the layer was erased. + std::string layerName = "LFPS " + it->second->getName(); + ATRACE_INT(layerName.c_str(), 0); + } + auto id = it->first; + auto layerInfo = it->second; + layerInfo->clearHistory(); + mInactiveLayerInfos.insert({id, layerInfo}); + it = mActiveLayerInfos.erase(it); + } else { + ++it; + } + } } +} // namespace scheduler } // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h index c6fab07c87..39061e7fdf 100644 --- a/services/surfaceflinger/Scheduler/LayerHistory.h +++ b/services/surfaceflinger/Scheduler/LayerHistory.h @@ -25,40 +25,60 @@ #include <utils/Timers.h> +#include "LayerInfo.h" #include "SchedulerUtils.h" namespace android { +namespace scheduler { /* - * This class represents a circular buffer in which we keep layer history for - * the past ARRAY_SIZE frames. Each time, a signal for new frame comes, the counter - * gets incremented and includes all the layers that are requested to draw in that - * frame. - * - * Once the buffer reaches the end of the array, it starts overriding the elements - * at the beginning of the array. + * This class represents information about layers that are considered current. We keep an + * unordered map between layer name and LayerInfo. */ class LayerHistory { public: + // Handle for each layer we keep track of. + class LayerHandle { + public: + LayerHandle(LayerHistory& lh, int64_t id) : mId(id), mLayerHistory(lh) {} + ~LayerHandle() { mLayerHistory.destroyLayer(mId); } + + const int64_t mId; + + private: + LayerHistory& mLayerHistory; + }; + LayerHistory(); ~LayerHistory(); - // Method for inserting layers and their requested present time into the ring buffer. - // The elements are going to be inserted into an unordered_map at the position 'now'. - void insert(const std::string layerName, nsecs_t presentTime); - // Method for incrementing the current slot in the ring buffer. It also clears the - // unordered_map, if it was created previously. - void incrementCounter(); - // Returns unordered_map at the given at index. The index is decremented from 'now'. For - // example, 0 is now, 1 is previous frame. - const std::unordered_map<std::string, nsecs_t>& get(size_t index) const; - // Returns the total size of the ring buffer. The value is always the same regardless - // of how many slots we filled in. - static constexpr size_t getSize() { return scheduler::ARRAY_SIZE; } + // When the layer is first created, register it. + std::unique_ptr<LayerHandle> createLayer(const std::string name, float maxRefreshRate); + + // Method for inserting layers and their requested present time into the unordered map. + void insert(const std::unique_ptr<LayerHandle>& layerHandle, nsecs_t presentTime); + // Returns the desired refresh rate, which is a max refresh rate of all the current + // layers. See go/content-fps-detection-in-scheduler for more information. + float getDesiredRefreshRate(); + + // Removes the handle and the object from the map. + void destroyLayer(const int64_t id); private: - size_t mCounter = 0; - std::array<std::unordered_map<std::string, nsecs_t>, scheduler::ARRAY_SIZE> mElements; + // Removes the layers that have been idle for a given amount of time from mLayerInfos. + void removeIrrelevantLayers() REQUIRES(mLock); + + // Information about currently active layers. + std::mutex mLock; + std::unordered_map<int64_t, std::shared_ptr<LayerInfo>> mActiveLayerInfos GUARDED_BY(mLock); + std::unordered_map<int64_t, std::shared_ptr<LayerInfo>> mInactiveLayerInfos GUARDED_BY(mLock); + + // Each layer has it's own ID. This variable keeps track of the count. + static std::atomic<int64_t> sNextId; + + // Flag whether to log layer FPS in systrace + bool mTraceEnabled = false; }; +} // namespace scheduler } // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp new file mode 100644 index 0000000000..95d7d31564 --- /dev/null +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -0,0 +1,50 @@ +/* + * Copyright 2019 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. + */ + +#include "LayerInfo.h" + +#include <cinttypes> +#include <cstdint> +#include <numeric> +#include <string> + +namespace android { +namespace scheduler { + +LayerInfo::LayerInfo(const std::string name, float maxRefreshRate) + : mName(name), + mMinRefreshDuration(1e9f / maxRefreshRate), + mRefreshRateHistory(mMinRefreshDuration) {} + +LayerInfo::~LayerInfo() = default; + +void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime) { + std::lock_guard lock(mLock); + + // Buffers can come with a present time far in the future. That keeps them relevant. + mLastUpdatedTime = std::max(lastPresentTime, systemTime()); + mPresentTimeHistory.insertPresentTime(mLastUpdatedTime); + + const nsecs_t timeDiff = lastPresentTime - mLastPresentTime; + mLastPresentTime = lastPresentTime; + // Ignore time diff that are too high - those are stale values + if (timeDiff > TIME_EPSILON_NS.count()) return; + const nsecs_t refreshDuration = (timeDiff > 0) ? timeDiff : mMinRefreshDuration; + mRefreshRateHistory.insertRefreshRate(refreshDuration); +} + +} // namespace scheduler +} // namespace android diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h new file mode 100644 index 0000000000..1970a47701 --- /dev/null +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -0,0 +1,156 @@ +/* + * Copyright 2019 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 <cinttypes> +#include <cstdint> +#include <deque> +#include <mutex> +#include <numeric> +#include <string> + +#include <log/log.h> + +#include <utils/Mutex.h> +#include <utils/Timers.h> + +#include "SchedulerUtils.h" + +namespace android { +namespace scheduler { + +/* + * This class represents information about individial layers. + */ +class LayerInfo { + /** + * Struct that keeps the information about the refresh rate for last + * HISTORY_SIZE frames. This is used to better determine the refresh rate + * for individual layers. + */ + class RefreshRateHistory { + public: + explicit RefreshRateHistory(nsecs_t minRefreshDuration) + : mMinRefreshDuration(minRefreshDuration) {} + void insertRefreshRate(nsecs_t refreshRate) { + mElements.push_back(refreshRate); + if (mElements.size() > HISTORY_SIZE) { + mElements.pop_front(); + } + } + + float getRefreshRateAvg() const { + nsecs_t refreshDuration = mMinRefreshDuration; + if (mElements.size() == HISTORY_SIZE) { + refreshDuration = scheduler::calculate_mean(mElements); + } + + return 1e9f / refreshDuration; + } + void clearHistory() { mElements.clear(); } + + private: + std::deque<nsecs_t> mElements; + static constexpr size_t HISTORY_SIZE = 30; + const nsecs_t mMinRefreshDuration; + }; + + /** + * Struct that keeps the information about the present time for last + * HISTORY_SIZE frames. This is used to better determine whether the given layer + * is still relevant and it's refresh rate should be considered. + */ + class PresentTimeHistory { + public: + void insertPresentTime(nsecs_t presentTime) { + mElements.push_back(presentTime); + if (mElements.size() > HISTORY_SIZE) { + mElements.pop_front(); + } + } + + // Checks whether the present time that was inserted HISTORY_SIZE ago is within a + // certain threshold: TIME_EPSILON_NS. + bool isRelevant() const { + const int64_t obsoleteEpsilon = systemTime() - scheduler::TIME_EPSILON_NS.count(); + // The layer had to publish at least HISTORY_SIZE of updates, and the first + // update should not be older than TIME_EPSILON_NS nanoseconds. + if (mElements.size() == HISTORY_SIZE && + mElements.at(HISTORY_SIZE - 1) > obsoleteEpsilon) { + return true; + } + return false; + } + + void clearHistory() { mElements.clear(); } + + private: + std::deque<nsecs_t> mElements; + static constexpr size_t HISTORY_SIZE = 10; + }; + +public: + LayerInfo(const std::string name, float maxRefreshRate); + ~LayerInfo(); + + LayerInfo(const LayerInfo&) = delete; + LayerInfo& operator=(const LayerInfo&) = delete; + + // Records the last requested oresent time. It also stores information about when + // the layer was last updated. If the present time is farther in the future than the + // updated time, the updated time is the present time. + void setLastPresentTime(nsecs_t lastPresentTime); + + // Checks the present time history to see whether the layer is relevant. + bool isRecentlyActive() const { + std::lock_guard lock(mLock); + return mPresentTimeHistory.isRelevant(); + } + + // Calculate the average refresh rate. + float getDesiredRefreshRate() const { + std::lock_guard lock(mLock); + return mRefreshRateHistory.getRefreshRateAvg(); + } + + // Return the last updated time. If the present time is farther in the future than the + // updated time, the updated time is the present time. + nsecs_t getLastUpdatedTime() { + std::lock_guard lock(mLock); + return mLastUpdatedTime; + } + + std::string getName() const { return mName; } + + void clearHistory() { + std::lock_guard lock(mLock); + mRefreshRateHistory.clearHistory(); + mPresentTimeHistory.clearHistory(); + } + +private: + const std::string mName; + const nsecs_t mMinRefreshDuration; + mutable std::mutex mLock; + nsecs_t mLastUpdatedTime GUARDED_BY(mLock) = 0; + nsecs_t mLastPresentTime GUARDED_BY(mLock) = 0; + RefreshRateHistory mRefreshRateHistory GUARDED_BY(mLock); + PresentTimeHistory mPresentTimeHistory GUARDED_BY(mLock); +}; + +} // namespace scheduler +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h index cbcaade38a..a85660a718 100644 --- a/services/surfaceflinger/Scheduler/PhaseOffsets.h +++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h @@ -68,8 +68,8 @@ public: void dump(std::string& result) const override; private: - Offsets getmDefaultRefreshRateOffsets() { return mDefaultRefreshRateOffsets; } - Offsets getmHighRefreshRateOffsets() { return mHighRefreshRateOffsets; } + Offsets getDefaultRefreshRateOffsets() { return mDefaultRefreshRateOffsets; } + Offsets getHighRefreshRateOffsets() { return mHighRefreshRateOffsets; } std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType = RefreshRateConfigs::RefreshRateType::DEFAULT; diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h index 1aa6aded75..eb9ae35cec 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h +++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h @@ -51,16 +51,10 @@ public: // TODO(b/122916473): Get this information from configs prepared by vendors, instead of // baking them in. - explicit RefreshRateConfigs( - const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) { - init(configs); - } - ~RefreshRateConfigs() = default; - - const std::map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() { + const std::map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() const { return mRefreshRates; } - std::shared_ptr<RefreshRate> getRefreshRate(RefreshRateType type) { + std::shared_ptr<RefreshRate> getRefreshRate(RefreshRateType type) const { const auto& refreshRate = mRefreshRates.find(type); if (refreshRate != mRefreshRates.end()) { return refreshRate->second; @@ -68,8 +62,9 @@ public: return nullptr; } -private: - void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) { + void populate(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) { + mRefreshRates.clear(); + // This is the rate that HWC encapsulates right now when the device is in DOZE mode. mRefreshRates.emplace(RefreshRateType::POWER_SAVING, std::make_shared<RefreshRate>( @@ -120,6 +115,7 @@ private: } } +private: std::map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates; }; diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h index ff63faf029..7e7c6307a4 100644 --- a/services/surfaceflinger/Scheduler/RefreshRateStats.h +++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h @@ -41,12 +41,8 @@ class RefreshRateStats { static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR; public: - explicit RefreshRateStats(const std::shared_ptr<RefreshRateConfigs>& refreshRateConfigs, - const std::shared_ptr<TimeStats>& timeStats) - : mRefreshRateConfigs(refreshRateConfigs), - mTimeStats(timeStats), - mPreviousRecordedTime(systemTime()) {} - ~RefreshRateStats() = default; + RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats) + : mRefreshRateConfigs(refreshRateConfigs), mTimeStats(timeStats) {} // Sets power mode. We only collect the information when the power mode is not // HWC_POWER_MODE_NORMAL. When power mode is HWC_POWER_MODE_NORMAL, we collect the stats based @@ -83,7 +79,7 @@ public: flushTime(); std::unordered_map<std::string, int64_t> totalTime; - for (auto [type, config] : mRefreshRateConfigs->getRefreshRates()) { + for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) { int64_t totalTimeForConfig = 0; if (!config) { continue; @@ -98,11 +94,11 @@ public: // Traverses through the map of config modes and returns how long they've been running in easy // to read format. - std::string doDump() { + std::string doDump() const { std::ostringstream stream; stream << "+ Refresh rate: running time in seconds\n"; - for (auto stats : getTotalTimes()) { - stream << stats.first.c_str() << ": " << getDateFormatFromMs(stats.second) << "\n"; + for (const auto& [name, time] : const_cast<RefreshRateStats*>(this)->getTotalTimes()) { + stream << name << ": " << getDateFormatFromMs(time) << '\n'; } return stream.str(); } @@ -126,12 +122,12 @@ private: mPreviousRecordedTime = currentTime; mConfigModesTotalTime[mode] += timeElapsedMs; - for (const auto& [type, config] : mRefreshRateConfigs->getRefreshRates()) { + for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) { if (!config) { continue; } if (config->configId == mode) { - mTimeStats->recordRefreshRate(config->fps, timeElapsed); + mTimeStats.recordRefreshRate(config->fps, timeElapsed); } } } @@ -148,17 +144,17 @@ private: } // Keeps information about refresh rate configs that device has. - std::shared_ptr<RefreshRateConfigs> mRefreshRateConfigs; + const RefreshRateConfigs& mRefreshRateConfigs; // Aggregate refresh rate statistics for telemetry. - std::shared_ptr<TimeStats> mTimeStats; + TimeStats& mTimeStats; int64_t mCurrentConfigMode = SCREEN_OFF_CONFIG_ID; int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF; std::unordered_map<int /* power mode */, int64_t /* duration in ms */> mConfigModesTotalTime; - nsecs_t mPreviousRecordedTime; + nsecs_t mPreviousRecordedTime = systemTime(); }; } // namespace scheduler diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp index 0063c8a202..1b154a4b06 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.cpp +++ b/services/surfaceflinger/Scheduler/Scheduler.cpp @@ -28,6 +28,7 @@ #include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h> #include <configstore/Utils.h> #include <cutils/properties.h> +#include <input/InputWindow.h> #include <system/window.h> #include <ui/DisplayStatInfo.h> #include <utils/Timers.h> @@ -39,6 +40,7 @@ #include "EventThread.h" #include "IdleTimer.h" #include "InjectVSyncSource.h" +#include "LayerInfo.h" #include "SchedulerUtils.h" #include "SurfaceFlingerProperties.h" @@ -55,11 +57,13 @@ using namespace android::sysprop; std::atomic<int64_t> Scheduler::sNextId = 0; -Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function) +Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, + const scheduler::RefreshRateConfigs& refreshRateConfig) : mHasSyncFramework(running_without_sync_framework(true)), mDispSyncPresentTimeOffset(present_time_offset_from_vsync_ns(0)), mPrimaryHWVsyncEnabled(false), - mHWVsyncAvailable(false) { + mHWVsyncAvailable(false), + mRefreshRateConfigs(refreshRateConfig) { // Note: We create a local temporary with the real DispSync implementation // type temporarily so we can initialize it with the configured values, // before storing it for more generic use using the interface type. @@ -174,12 +178,6 @@ void Scheduler::setPhaseOffset(const sp<Scheduler::ConnectionHandle>& handle, ns mConnections[handle->id]->thread->setPhaseOffset(phaseOffset); } -void Scheduler::pauseVsyncCallback(const android::sp<android::Scheduler::ConnectionHandle>& handle, - bool pause) { - RETURN_IF_INVALID(); - mConnections[handle->id]->thread->pauseVsyncCallback(pause); -} - void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) { stats->vsyncTime = mPrimaryDispSync->computeNextRefresh(0); stats->vsyncPeriod = mPrimaryDispSync->getPeriod(); @@ -251,7 +249,6 @@ void Scheduler::setRefreshSkipCount(int count) { void Scheduler::setVsyncPeriod(const nsecs_t period) { std::lock_guard<std::mutex> lock(mHWVsyncLock); - mPrimaryDispSync->reset(); mPrimaryDispSync->setPeriod(period); if (!mPrimaryHWVsyncEnabled) { @@ -261,12 +258,13 @@ void Scheduler::setVsyncPeriod(const nsecs_t period) { } } -void Scheduler::addResyncSample(const nsecs_t timestamp) { +void Scheduler::addResyncSample(const nsecs_t timestamp, bool* periodChanged) { bool needsHwVsync = false; + *periodChanged = false; { // Scope for the lock std::lock_guard<std::mutex> lock(mHWVsyncLock); if (mPrimaryHWVsyncEnabled) { - needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp); + needsHwVsync = mPrimaryDispSync->addResyncSample(timestamp, periodChanged); } } @@ -297,32 +295,34 @@ void Scheduler::dumpPrimaryDispSync(std::string& result) const { mPrimaryDispSync->dump(result); } -void Scheduler::addNativeWindowApi(int apiId) { - std::lock_guard<std::mutex> lock(mWindowApiHistoryLock); - mWindowApiHistory[mApiHistoryCounter] = apiId; - mApiHistoryCounter++; - mApiHistoryCounter = mApiHistoryCounter % scheduler::ARRAY_SIZE; +std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer( + std::string const& name, int windowType) { + RefreshRateType refreshRateType = (windowType == InputWindowInfo::TYPE_WALLPAPER) + ? RefreshRateType::DEFAULT + : RefreshRateType::PERFORMANCE; + + const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType); + const uint32_t fps = (refreshRate) ? refreshRate->fps : 0; + return mLayerHistory.createLayer(name, fps); +} + +void Scheduler::addLayerPresentTime( + const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, + nsecs_t presentTime) { + mLayerHistory.insert(layerHandle, presentTime); } void Scheduler::withPrimaryDispSync(std::function<void(DispSync&)> const& fn) { fn(*mPrimaryDispSync); } -void Scheduler::updateFpsBasedOnNativeWindowApi() { - int mode; - { - std::lock_guard<std::mutex> lock(mWindowApiHistoryLock); - mode = scheduler::calculate_mode(mWindowApiHistory); - } - ATRACE_INT("NativeWindowApiMode", mode); - - if (mode == NATIVE_WINDOW_API_MEDIA) { - // TODO(b/127365162): These callback names are not accurate anymore. Update. - mediaChangeRefreshRate(MediaFeatureState::MEDIA_PLAYING); - ATRACE_INT("DetectedVideo", 1); +void Scheduler::updateFpsBasedOnContent() { + uint32_t refreshRate = std::round(mLayerHistory.getDesiredRefreshRate()); + ATRACE_INT("ContentFPS", refreshRate); + if (refreshRate > 0) { + contentChangeRefreshRate(ContentFeatureState::CONTENT_DETECTION_ON, refreshRate); } else { - mediaChangeRefreshRate(MediaFeatureState::MEDIA_OFF); - ATRACE_INT("DetectedVideo", 0); + contentChangeRefreshRate(ContentFeatureState::CONTENT_DETECTION_OFF, 0); } } @@ -365,39 +365,70 @@ std::string Scheduler::doDump() { return stream.str(); } -void Scheduler::mediaChangeRefreshRate(MediaFeatureState mediaFeatureState) { - // Default playback for media is DEFAULT when media is on. - RefreshRateType refreshRateType = RefreshRateType::DEFAULT; - ConfigEvent configEvent = ConfigEvent::None; - +void Scheduler::contentChangeRefreshRate(ContentFeatureState contentFeatureState, + uint32_t refreshRate) { + RefreshRateType newRefreshRateType; { std::lock_guard<std::mutex> lock(mFeatureStateLock); - mCurrentMediaFeatureState = mediaFeatureState; - // Only switch to PERFORMANCE if idle timer was reset, when turning - // media off. If the timer is IDLE, stay at DEFAULT. - if (mediaFeatureState == MediaFeatureState::MEDIA_OFF && - mCurrentIdleTimerState == IdleTimerState::RESET) { - refreshRateType = RefreshRateType::PERFORMANCE; - } + mCurrentContentFeatureState = contentFeatureState; + mContentRefreshRate = refreshRate; + newRefreshRateType = calculateRefreshRateType(); } - changeRefreshRate(refreshRateType, configEvent); + changeRefreshRate(newRefreshRateType, ConfigEvent::Changed); } void Scheduler::timerChangeRefreshRate(IdleTimerState idleTimerState) { - RefreshRateType refreshRateType = RefreshRateType::DEFAULT; - ConfigEvent configEvent = ConfigEvent::None; - + RefreshRateType newRefreshRateType; { std::lock_guard<std::mutex> lock(mFeatureStateLock); mCurrentIdleTimerState = idleTimerState; - // Only switch to PERFOMANCE if the idle timer was reset, and media is - // not playing. Otherwise, stay at DEFAULT. - if (idleTimerState == IdleTimerState::RESET && - mCurrentMediaFeatureState == MediaFeatureState::MEDIA_OFF) { - refreshRateType = RefreshRateType::PERFORMANCE; + newRefreshRateType = calculateRefreshRateType(); + } + changeRefreshRate(newRefreshRateType, ConfigEvent::None); +} + +Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() { + // First check if timer has expired as it means there is no new content on the screen + if (mCurrentIdleTimerState == IdleTimerState::EXPIRED) { + return RefreshRateType::DEFAULT; + } + + // If content detection is off we choose performance as we don't know the content fps + if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_OFF) { + return RefreshRateType::PERFORMANCE; + } + + // Content detection is on, find the appropriate refresh rate + // Start with the smallest refresh rate which is within a margin of the content + RefreshRateType currRefreshRateType = RefreshRateType::PERFORMANCE; + constexpr float MARGIN = 0.05f; + auto iter = mRefreshRateConfigs.getRefreshRates().cbegin(); + while (iter != mRefreshRateConfigs.getRefreshRates().cend()) { + if (iter->second->fps >= mContentRefreshRate * (1 - MARGIN)) { + currRefreshRateType = iter->first; + break; } + ++iter; } - changeRefreshRate(refreshRateType, configEvent); + + // Some content aligns better on higher refresh rate. For example for 45fps we should choose + // 90Hz config. However we should still prefer a lower refresh rate if the content doesn't + // align well with both + float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps / + float(mContentRefreshRate); + if (std::abs(std::round(ratio) - ratio) > MARGIN) { + while (iter != mRefreshRateConfigs.getRefreshRates().cend()) { + ratio = iter->second->fps / float(mContentRefreshRate); + + if (std::abs(std::round(ratio) - ratio) <= MARGIN) { + currRefreshRateType = iter->first; + break; + } + ++iter; + } + } + + return currRefreshRateType; } void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) { diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h index 73896d5763..134dc0b785 100644 --- a/services/surfaceflinger/Scheduler/Scheduler.h +++ b/services/surfaceflinger/Scheduler/Scheduler.h @@ -90,7 +90,8 @@ public: std::atomic<nsecs_t> lastResyncTime = 0; }; - explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function); + explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function, + const scheduler::RefreshRateConfigs& refreshRateConfig); virtual ~Scheduler(); @@ -130,9 +131,6 @@ public: // Offers ability to modify phase offset in the event thread. void setPhaseOffset(const sp<ConnectionHandle>& handle, nsecs_t phaseOffset); - // pause/resume vsync callback generation to avoid sending vsync callbacks during config switch - void pauseVsyncCallback(const sp<ConnectionHandle>& handle, bool pause); - void getDisplayStatInfo(DisplayStatInfo* stats); void enableHardwareVsync(); @@ -141,20 +139,28 @@ public: // Creates a callback for resyncing. ResyncCallback makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod); void setRefreshSkipCount(int count); - void addResyncSample(const nsecs_t timestamp); + // Passes a vsync sample to DispSync. periodChange will be true if DipSync + // detected that the vsync period changed, and false otherwise. + void addResyncSample(const nsecs_t timestamp, bool* periodChanged); void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime); void setIgnorePresentFences(bool ignore); nsecs_t expectedPresentTime(); - // apiId indicates the API (NATIVE_WINDOW_API_xxx) that queues the buffer. - // TODO(b/123956502): Remove this call with V1 go/content-fps-detection-in-scheduler. - void addNativeWindowApi(int apiId); - // Updates FPS based on the most occured request for Native Window API. - void updateFpsBasedOnNativeWindowApi(); + // Registers the layer in the scheduler, and returns the handle for future references. + std::unique_ptr<scheduler::LayerHistory::LayerHandle> registerLayer(std::string const& name, + int windowType); + + // Stores present time for a layer. + void addLayerPresentTime( + const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, + nsecs_t presentTime); + // Updates FPS based on the most content presented. + void updateFpsBasedOnContent(); // Callback that gets invoked when Scheduler wants to change the refresh rate. void setChangeRefreshRateCallback(const ChangeRefreshRateCallback& changeRefreshRateCallback); // Returns whether idle timer is enabled or not bool isIdleTimerEnabled() { return mSetIdleTimerMs > 0; } + // Returns relevant information about Scheduler for dumpsys purposes. std::string doDump(); @@ -171,7 +177,7 @@ private: // In order to make sure that the features don't override themselves, we need a state machine // to keep track which feature requested the config change. - enum class MediaFeatureState { MEDIA_PLAYING, MEDIA_OFF }; + enum class ContentFeatureState { CONTENT_DETECTION_ON, CONTENT_DETECTION_OFF }; enum class IdleTimerState { EXPIRED, RESET }; // Creates a connection on the given EventThread and forwards the given callbacks. @@ -188,12 +194,17 @@ private: // Sets vsync period. void setVsyncPeriod(const nsecs_t period); // Media feature's function to change the refresh rate. - void mediaChangeRefreshRate(MediaFeatureState mediaFeatureState); + void contentChangeRefreshRate(ContentFeatureState contentFeatureState, uint32_t refreshRate); // Idle timer feature's function to change the refresh rate. void timerChangeRefreshRate(IdleTimerState idleTimerState); + // Calculate the new refresh rate type + RefreshRateType calculateRefreshRateType() REQUIRES(mFeatureStateLock); // Acquires a lock and calls the ChangeRefreshRateCallback() with given parameters. void changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent); + // Helper function to calculate error frames + float getErrorFrames(float contentFps, float configFps); + // If fences from sync Framework are supported. const bool mHasSyncFramework; @@ -226,13 +237,8 @@ private: std::array<int64_t, scheduler::ARRAY_SIZE> mTimeDifferences{}; size_t mCounter = 0; - // The following few fields follow native window api bits that come with buffers. If there are - // more buffers with NATIVE_WINDOW_API_MEDIA we render at 60Hz, otherwise we render at 90Hz. - // There is not dependency on timestamp for V0. - // TODO(b/123956502): Remove this when more robust logic for content fps detection is developed. - std::mutex mWindowApiHistoryLock; - std::array<int, scheduler::ARRAY_SIZE> mWindowApiHistory GUARDED_BY(mWindowApiHistoryLock); - int64_t mApiHistoryCounter = 0; + // Historical information about individual layers. Used for predicting the refresh rate. + scheduler::LayerHistory mLayerHistory; // Timer that records time between requests for next vsync. If the time is higher than a given // interval, a callback is fired. Set this variable to >0 to use this feature. @@ -245,9 +251,12 @@ private: // In order to make sure that the features don't override themselves, we need a state machine // to keep track which feature requested the config change. std::mutex mFeatureStateLock; - MediaFeatureState mCurrentMediaFeatureState GUARDED_BY(mFeatureStateLock) = - MediaFeatureState::MEDIA_OFF; + ContentFeatureState mCurrentContentFeatureState GUARDED_BY(mFeatureStateLock) = + ContentFeatureState::CONTENT_DETECTION_OFF; IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET; + uint32_t mContentRefreshRate; + + const scheduler::RefreshRateConfigs& mRefreshRateConfigs; }; } // namespace android diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h index 9e6e8c7af6..a935cac1eb 100644 --- a/services/surfaceflinger/Scheduler/SchedulerUtils.h +++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h @@ -16,6 +16,7 @@ #pragma once +#include <chrono> #include <cinttypes> #include <numeric> #include <unordered_map> @@ -23,6 +24,8 @@ namespace android { namespace scheduler { +using namespace std::chrono_literals; + // This number is used to set the size of the arrays in scheduler that hold information // about layers. static constexpr size_t ARRAY_SIZE = 30; @@ -32,12 +35,20 @@ static constexpr size_t ARRAY_SIZE = 30; // still like to keep track of time when the device is in this config. static constexpr int SCREEN_OFF_CONFIG_ID = -1; +// This number is used when we try to determine how long does a given layer stay relevant. +// Currently it is set to 100ms, because that would indicate 10Hz rendering. +static constexpr std::chrono::nanoseconds TIME_EPSILON_NS = 100ms; + +// This number is used when we try to determine how long do we keep layer information around +// before we remove it. Currently it is set to 100ms. +static constexpr std::chrono::nanoseconds OBSOLETE_TIME_EPSILON_NS = 100ms; + // Calculates the statistical mean (average) in the data structure (array, vector). The // function does not modify the contents of the array. template <typename T> auto calculate_mean(const T& v) { using V = typename T::value_type; - V sum = std::accumulate(v.begin(), v.end(), 0); + V sum = std::accumulate(v.begin(), v.end(), static_cast<V>(0)); return sum / static_cast<V>(v.size()); } diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h index dab2003d91..1a0de081c6 100644 --- a/services/surfaceflinger/Scheduler/VSyncModulator.h +++ b/services/surfaceflinger/Scheduler/VSyncModulator.h @@ -30,9 +30,10 @@ namespace android { */ class VSyncModulator { private: - // Number of frames we'll keep the early phase offsets once they are activated. This acts as a - // low-pass filter in case the client isn't quick enough in sending new transactions. - const int MIN_EARLY_FRAME_COUNT = 2; + // Number of frames we'll keep the early phase offsets once they are activated for a + // transaction. This acts as a low-pass filter in case the client isn't quick enough in + // sending new transactions. + const int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2; public: struct Offsets { @@ -85,7 +86,7 @@ public: void setTransactionStart(Scheduler::TransactionStart transactionStart) { if (transactionStart == Scheduler::TransactionStart::EARLY) { - mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT; + mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT_TRANSACTION; } // An early transaction stays an early transaction. @@ -103,6 +104,26 @@ public: updateOffsets(); } + // Called when we send a refresh rate change to hardware composer, so that + // we can move into early offsets. + void onRefreshRateChangeInitiated() { + if (mRefreshRateChangePending) { + return; + } + mRefreshRateChangePending = true; + updateOffsets(); + } + + // Called when we detect from vsync signals that the refresh rate changed. + // This way we can move out of early offsets if no longer necessary. + void onRefreshRateChangeDetected() { + if (!mRefreshRateChangePending) { + return; + } + mRefreshRateChangePending = false; + updateOffsets(); + } + void onRefreshed(bool usedRenderEngine) { bool updateOffsetsNeeded = false; if (mRemainingEarlyFrameCount > 0) { @@ -147,8 +168,10 @@ private: } Offsets getOffsets() { + // Early offsets are used if we're in the middle of a refresh rate + // change, or if we recently begin a transaction. if (mTransactionStart == Scheduler::TransactionStart::EARLY || - mRemainingEarlyFrameCount > 0) { + mRemainingEarlyFrameCount > 0 || mRefreshRateChangePending) { return mEarlyOffsets; } else if (mLastFrameUsedRenderEngine) { return mEarlyGlOffsets; @@ -173,6 +196,7 @@ private: std::atomic<Scheduler::TransactionStart> mTransactionStart = Scheduler::TransactionStart::NORMAL; std::atomic<bool> mLastFrameUsedRenderEngine = false; + std::atomic<bool> mRefreshRateChangePending = false; std::atomic<int> mRemainingEarlyFrameCount = 0; }; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 0dc99bf41e..53c615f929 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -558,14 +558,10 @@ void SurfaceFlinger::bootFinished() mBootStage = BootStage::FINISHED; // set the refresh rate according to the policy - const auto displayId = getInternalDisplayIdLocked(); - LOG_ALWAYS_FATAL_IF(!displayId); - const auto& performanceRefreshRate = - mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE); + mRefreshRateConfigs.getRefreshRate(RefreshRateType::PERFORMANCE); - if (performanceRefreshRate && - isConfigAllowed(*displayId, performanceRefreshRate->configId)) { + if (performanceRefreshRate && isDisplayConfigAllowed(performanceRefreshRate->configId)) { setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None); } else { setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None); @@ -609,7 +605,8 @@ void SurfaceFlinger::init() { Mutex::Autolock _l(mStateLock); // start the EventThread mScheduler = - getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); }); + getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); }, + mRefreshRateConfigs); auto resyncCallback = mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this)); @@ -706,12 +703,9 @@ void SurfaceFlinger::init() { setRefreshRateTo(type, event); }); } - mRefreshRateConfigs[*display->getId()] = std::make_shared<scheduler::RefreshRateConfigs>( - getHwComposer().getConfigs(*display->getId())); - mRefreshRateStats = - std::make_unique<scheduler::RefreshRateStats>(mRefreshRateConfigs[*display->getId()], - mTimeStats); - mRefreshRateStats->setConfigMode(getHwComposer().getActiveConfigIndex(*display->getId())); + + mRefreshRateConfigs.populate(getHwComposer().getConfigs(*display->getId())); + mRefreshRateStats.setConfigMode(getHwComposer().getActiveConfigIndex(*display->getId())); ALOGV("Done initializing"); } @@ -786,12 +780,14 @@ status_t SurfaceFlinger::getSupportedFrameTimestamps( return NO_ERROR; } -status_t SurfaceFlinger::getDisplayConfigsLocked(const sp<IBinder>& displayToken, - Vector<DisplayInfo>* configs) { +status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken, + Vector<DisplayInfo>* configs) { if (!displayToken || !configs) { return BAD_VALUE; } + Mutex::Autolock lock(mStateLock); + const auto displayId = getPhysicalDisplayIdLocked(displayToken); if (!displayId) { return NAME_NOT_FOUND; @@ -917,18 +913,6 @@ int SurfaceFlinger::getActiveConfig(const sp<IBinder>& displayToken) { void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { ATRACE_CALL(); - // Lock is acquired by setRefreshRateTo. - const auto display = getDisplayDeviceLocked(info.displayToken); - if (!display) { - ALOGE("Attempt to set active config %d for invalid display token %p", info.configId, - info.displayToken.get()); - return; - } - if (display->isVirtual()) { - ALOGW("Attempt to set active config %d for virtual display", info.configId); - return; - } - // Don't check against the current mode yet. Worst case we set the desired // config twice. However event generation config might have changed so we need to update it // accordingly @@ -938,11 +922,15 @@ void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) { mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig; if (!mDesiredActiveConfigChanged) { - // This is the first time we set the desired - mScheduler->pauseVsyncCallback(mAppConnectionHandle, true); - // This will trigger HWC refresh without resetting the idle timer. repaintEverythingForHWC(); + // Start receiving vsync samples now, so that we can detect a period + // switch. + mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); + mPhaseOffsets->setRefreshRateType(info.type); + const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); + mVsyncModulator.onRefreshRateChangeInitiated(); + mVsyncModulator.setPhaseOffsets(early, gl, late); } mDesiredActiveConfigChanged = true; ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); @@ -964,23 +952,29 @@ status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mo void SurfaceFlinger::setActiveConfigInternal() { ATRACE_CALL(); + const auto display = getDefaultDisplayDeviceLocked(); + if (!display) { + return; + } + std::lock_guard<std::mutex> lock(mActiveConfigLock); - mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId); + mRefreshRateStats.setConfigMode(mUpcomingActiveConfig.configId); - const auto display = getDisplayDeviceLocked(mUpcomingActiveConfig.displayToken); display->setActiveConfig(mUpcomingActiveConfig.configId); mScheduler->resyncToHardwareVsync(true, getVsyncPeriod()); + mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type); const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets(); mVsyncModulator.setPhaseOffsets(early, gl, late); ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId); + if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) { mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, mUpcomingActiveConfig.configId); } } -bool SurfaceFlinger::performSetActiveConfig() NO_THREAD_SAFETY_ANALYSIS { +bool SurfaceFlinger::performSetActiveConfig() { ATRACE_CALL(); if (mCheckPendingFence) { if (mPreviousPresentFence != Fence::NO_FENCE && @@ -1006,13 +1000,11 @@ bool SurfaceFlinger::performSetActiveConfig() NO_THREAD_SAFETY_ANALYSIS { desiredActiveConfig = mDesiredActiveConfig; } - const auto display = getDisplayDevice(desiredActiveConfig.displayToken); + const auto display = getDefaultDisplayDeviceLocked(); if (!display || display->getActiveConfig() == desiredActiveConfig.configId) { // display is not valid or we are already in the requested mode // on both cases there is nothing left to do std::lock_guard<std::mutex> lock(mActiveConfigLock); - mScheduler->pauseVsyncCallback(mAppConnectionHandle, false); - mDesiredActiveConfig.event = Scheduler::ConfigEvent::None; mDesiredActiveConfigChanged = false; ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged); return false; @@ -1021,8 +1013,9 @@ bool SurfaceFlinger::performSetActiveConfig() NO_THREAD_SAFETY_ANALYSIS { // Desired active config was set, it is different than the config currently in use, however // allowed configs might have change by the time we process the refresh. // Make sure the desired config is still allowed - if (!isConfigAllowed(*display->getId(), desiredActiveConfig.configId)) { + if (!isDisplayConfigAllowed(desiredActiveConfig.configId)) { std::lock_guard<std::mutex> lock(mActiveConfigLock); + mDesiredActiveConfig.event = Scheduler::ConfigEvent::None; mDesiredActiveConfig.configId = display->getActiveConfig(); return false; } @@ -1414,7 +1407,11 @@ void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDispl return; } - mScheduler->addResyncSample(timestamp); + bool periodChanged = false; + mScheduler->addResyncSample(timestamp, &periodChanged); + if (periodChanged) { + mVsyncModulator.onRefreshRateChangeDetected(); + } } void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { @@ -1422,29 +1419,19 @@ void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) { *compositorTiming = getBE().mCompositorTiming; } -bool SurfaceFlinger::isConfigAllowed(const DisplayId& displayId, int32_t config) { - std::lock_guard lock(mAllowedConfigsLock); - - // if allowed configs are not set yet for this display, every config is considered allowed - if (mAllowedConfigs.find(displayId) == mAllowedConfigs.end()) { - return true; - } - - return mAllowedConfigs[displayId]->isConfigAllowed(config); +bool SurfaceFlinger::isDisplayConfigAllowed(int32_t configId) { + return mAllowedDisplayConfigs.empty() || mAllowedDisplayConfigs.count(configId); } void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::ConfigEvent event) { - if (mBootStage != BootStage::FINISHED) { + const auto display = getDefaultDisplayDeviceLocked(); + if (!display || mBootStage != BootStage::FINISHED) { return; } ATRACE_CALL(); // Don't do any updating if the current fps is the same as the new one. - const auto displayId = getInternalDisplayIdLocked(); - LOG_ALWAYS_FATAL_IF(!displayId); - const auto displayToken = getInternalDisplayTokenLocked(); - - const auto& refreshRateConfig = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate); + const auto& refreshRateConfig = mRefreshRateConfigs.getRefreshRate(refreshRate); if (!refreshRateConfig) { ALOGV("Skipping refresh rate change request for unsupported rate."); return; @@ -1452,19 +1439,16 @@ void SurfaceFlinger::setRefreshRateTo(RefreshRateType refreshRate, Scheduler::Co const int desiredConfigId = refreshRateConfig->configId; - if (!isConfigAllowed(*displayId, desiredConfigId)) { + if (!isDisplayConfigAllowed(desiredConfigId)) { ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId); return; } - mPhaseOffsets->setRefreshRateType(refreshRate); - - const auto display = getDisplayDeviceLocked(displayToken); if (desiredConfigId == display->getActiveConfig()) { return; } - setDesiredActiveConfig({refreshRate, desiredConfigId, getInternalDisplayTokenLocked(), event}); + setDesiredActiveConfig({refreshRate, desiredConfigId, event}); } void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId, @@ -1604,7 +1588,7 @@ void SurfaceFlinger::updateVrFlinger() { setTransactionFlags(eDisplayTransactionNeeded); } -void SurfaceFlinger::onMessageReceived(int32_t what) { +void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS { ATRACE_CALL(); switch (what) { case MessageQueue::INVALIDATE: { @@ -1631,7 +1615,7 @@ void SurfaceFlinger::onMessageReceived(int32_t what) { if (mUseSmart90ForVideo) { // This call is made each time SF wakes up and creates a new frame. It is part // of video detection feature. - mScheduler->updateFpsBasedOnNativeWindowApi(); + mScheduler->updateFpsBasedOnContent(); } if (performSetActiveConfig()) { @@ -2483,9 +2467,6 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { state.displayName = info->name; mCurrentState.displays.add(mPhysicalDisplayTokens[info->id], state); mInterceptor->saveDisplayCreation(state); - // TODO(b/123715322): Removes the per-display state that was added to the scheduler. - mRefreshRateConfigs[info->id] = std::make_shared<scheduler::RefreshRateConfigs>( - getHwComposer().getConfigs(info->id)); } } else { ALOGV("Removing display %s", to_string(info->id).c_str()); @@ -2497,7 +2478,6 @@ void SurfaceFlinger::processDisplayHotplugEventsLocked() { mCurrentState.displays.removeItemsAt(index); } mPhysicalDisplayTokens.erase(info->id); - mRefreshRateConfigs.erase(info->id); } processDisplayChangesLocked(); @@ -3143,6 +3123,7 @@ void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Re bool SurfaceFlinger::handlePageFlip() { + ATRACE_CALL(); ALOGV("handlePageFlip"); nsecs_t latchTime = systemTime(); @@ -3168,6 +3149,7 @@ bool SurfaceFlinger::handlePageFlip() if (layer->shouldPresentNow(expectedPresentTime)) { mLayersWithQueuedFrames.push_back(layer); } else { + ATRACE_NAME("!layer->shouldPresentNow()"); layer->useEmptyDamage(); } } else { @@ -4007,10 +3989,8 @@ uint32_t SurfaceFlinger::setClientStateLocked( buffer = s.buffer; } if (buffer) { - if (layer->setBuffer(buffer)) { + if (layer->setBuffer(buffer, postTime, desiredPresentTime)) { flags |= eTraversalNeeded; - layer->setPostTime(postTime); - layer->setDesiredPresentTime(desiredPresentTime); } } if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded; @@ -4056,7 +4036,7 @@ status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& clie if (metadata.has(METADATA_WINDOW_TYPE)) { int32_t windowType = metadata.getInt32(METADATA_WINDOW_TYPE, 0); if (windowType == 441731) { - metadata.setInt32(METADATA_WINDOW_TYPE, 2024); // TYPE_NAVIGATION_BAR_PANEL + metadata.setInt32(METADATA_WINDOW_TYPE, InputWindowInfo::TYPE_NAVIGATION_BAR_PANEL); primaryDisplayOnly = true; } } @@ -4345,10 +4325,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int if (display->isPrimary()) { mTimeStats->setPowerMode(mode); - if (mRefreshRateStats) { - // Update refresh rate stats. - mRefreshRateStats->setPowerMode(mode); - } + mRefreshRateStats.setPowerMode(mode); } ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str()); @@ -4876,7 +4853,7 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co result.append("\nScheduler state:\n"); result.append(mScheduler->doDump() + "\n"); StringAppendF(&result, "+ Smart video mode: %s\n\n", mUseSmart90ForVideo ? "on" : "off"); - result.append(mRefreshRateStats->doDump() + "\n"); + result.append(mRefreshRateStats.doDump() + "\n"); } const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) { @@ -5016,7 +4993,7 @@ status_t SurfaceFlinger::CheckTransactCodeCredentials(uint32_t code) { } // Numbers from 1000 to 1034 are currently used for backdoors. The code // in onTransact verifies that the user is root, and has access to use SF. - if (code >= 1000 && code <= 1034) { + if (code >= 1000 && code <= 1035) { ALOGV("Accessing SurfaceFlinger through backdoor code: %u", code); return OK; } @@ -5339,6 +5316,19 @@ status_t SurfaceFlinger::onTransact(uint32_t code, const Parcel& data, Parcel* r } return NO_ERROR; } + case 1035: { + n = data.readInt32(); + mDebugDisplayConfigSetByBackdoor = false; + if (n >= 0) { + const auto displayToken = getInternalDisplayToken(); + status_t result = setAllowedDisplayConfigs(displayToken, {n}); + if (result != NO_ERROR) { + return result; + } + mDebugDisplayConfigSetByBackdoor = true; + } + return NO_ERROR; + } } } return err; @@ -5368,7 +5358,8 @@ private: }; status_t SurfaceFlinger::captureScreen(const sp<IBinder>& displayToken, - sp<GraphicBuffer>* outBuffer, const Dataspace reqDataspace, + sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers, + const Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat, Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform, @@ -5401,7 +5392,7 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& displayToken, auto traverseLayers = std::bind(&SurfaceFlinger::traverseLayersInDisplay, this, display, std::placeholders::_1); return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, - useIdentityTransform); + useIdentityTransform, outCapturedSecureLayers); } status_t SurfaceFlinger::captureLayers( @@ -5563,14 +5554,18 @@ status_t SurfaceFlinger::captureLayers( visitor(layer); }); }; - return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, false); + + bool outCapturedSecureLayers = false; + return captureScreenCommon(renderArea, traverseLayers, outBuffer, reqPixelFormat, false, + outCapturedSecureLayers); } status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers, sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat, - bool useIdentityTransform) { + bool useIdentityTransform, + bool& outCapturedSecureLayers) { ATRACE_CALL(); // TODO(b/116112787) Make buffer usage a parameter. @@ -5581,13 +5576,15 @@ status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, static_cast<android_pixel_format>(reqPixelFormat), 1, usage, "screenshot"); - return captureScreenCommon(renderArea, traverseLayers, *outBuffer, useIdentityTransform); + return captureScreenCommon(renderArea, traverseLayers, *outBuffer, useIdentityTransform, + outCapturedSecureLayers); } status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers, const sp<GraphicBuffer>& buffer, - bool useIdentityTransform) { + bool useIdentityTransform, + bool& outCapturedSecureLayers) { // This mutex protects syncFd and captureResult for communication of the return values from the // main thread back to this Binder thread std::mutex captureMutex; @@ -5616,7 +5613,8 @@ status_t SurfaceFlinger::captureScreenCommon(RenderArea& renderArea, Mutex::Autolock _l(mStateLock); renderArea.render([&] { result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(), - useIdentityTransform, forSystem, &fd); + useIdentityTransform, forSystem, &fd, + outCapturedSecureLayers); }); } @@ -5756,21 +5754,19 @@ void SurfaceFlinger::renderScreenImplLocked(const RenderArea& renderArea, status_t SurfaceFlinger::captureScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers, ANativeWindowBuffer* buffer, - bool useIdentityTransform, - bool forSystem, - int* outSyncFd) { + bool useIdentityTransform, bool forSystem, + int* outSyncFd, bool& outCapturedSecureLayers) { ATRACE_CALL(); - bool secureLayerIsVisible = false; - traverseLayers([&](Layer* layer) { - secureLayerIsVisible = secureLayerIsVisible || (layer->isVisible() && layer->isSecure()); + outCapturedSecureLayers = + outCapturedSecureLayers || (layer->isVisible() && layer->isSecure()); }); // We allow the system server to take screenshots of secure layers for // use in situations like the Screen-rotation animation and place // the impetus on WindowManager to not persist them. - if (secureLayerIsVisible && !forSystem) { + if (outCapturedSecureLayers && !forSystem) { ALOGW("FB is protected: PERMISSION_DENIED"); return PERMISSION_DENIED; } @@ -5816,95 +5812,71 @@ void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& disp } } -void SurfaceFlinger::setAllowedDisplayConfigsInternal( - const android::sp<android::IBinder>& displayToken, - std::unique_ptr<const AllowedDisplayConfigs>&& allowedConfigs) { - const auto displayId = getPhysicalDisplayIdLocked(displayToken); - if (!displayId) { - ALOGE("setAllowedDisplayConfigsInternal: getPhysicalDisplayId failed"); +void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display, + const std::vector<int32_t>& allowedConfigs) { + if (!display->isPrimary()) { return; } ALOGV("Updating allowed configs"); - { - std::lock_guard lock(mAllowedConfigsLock); - mAllowedConfigs[*displayId] = std::move(allowedConfigs); - } + mAllowedDisplayConfigs = DisplayConfigs(allowedConfigs.begin(), allowedConfigs.end()); // Set the highest allowed config by iterating backwards on available refresh rates - const auto& refreshRates = mRefreshRateConfigs[*displayId]->getRefreshRates(); + const auto& refreshRates = mRefreshRateConfigs.getRefreshRates(); for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) { - if (iter->second && isConfigAllowed(*displayId, iter->second->configId)) { + if (iter->second && isDisplayConfigAllowed(iter->second->configId)) { ALOGV("switching to config %d", iter->second->configId); - setDesiredActiveConfig({iter->first, iter->second->configId, displayToken, - Scheduler::ConfigEvent::Changed}); + setDesiredActiveConfig( + {iter->first, iter->second->configId, Scheduler::ConfigEvent::Changed}); break; } } } -status_t SurfaceFlinger::setAllowedDisplayConfigs(const android::sp<android::IBinder>& displayToken, +status_t SurfaceFlinger::setAllowedDisplayConfigs(const sp<IBinder>& displayToken, const std::vector<int32_t>& allowedConfigs) { ATRACE_CALL(); - if (!displayToken) { - ALOGE("setAllowedDisplayConfigs: displayToken is null"); + if (!displayToken || allowedConfigs.empty()) { return BAD_VALUE; } - if (!allowedConfigs.size()) { - ALOGE("setAllowedDisplayConfigs: empty config set provided"); - return BAD_VALUE; + if (mDebugDisplayConfigSetByBackdoor) { + // ignore this request as config is overridden by backdoor + return NO_ERROR; } - { - ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId); - const auto displayId = getPhysicalDisplayIdLocked(displayToken); - if (!displayId) { - ALOGE("setAllowedDisplayConfigs: display not found"); - return NAME_NOT_FOUND; - } - } - - auto allowedDisplayConfigsBuilder = AllowedDisplayConfigs::Builder(); - for (int config : allowedConfigs) { - ALOGV("setAllowedDisplayConfigs: Adding config to the allowed configs = %d", config); - allowedDisplayConfigsBuilder.addConfig(config); - } - auto allowedDisplayConfigs = allowedDisplayConfigsBuilder.build(); postMessageSync(new LambdaMessage([&]() NO_THREAD_SAFETY_ANALYSIS { - setAllowedDisplayConfigsInternal(displayToken, std::move(allowedDisplayConfigs)); + const auto display = getDisplayDeviceLocked(displayToken); + if (!display) { + ALOGE("Attempt to set allowed display configs for invalid display token %p", + displayToken.get()); + } else if (display->isVirtual()) { + ALOGW("Attempt to set allowed display configs for virtual display"); + } else { + setAllowedDisplayConfigsInternal(display, allowedConfigs); + } })); + return NO_ERROR; } -status_t SurfaceFlinger::getAllowedDisplayConfigs(const android::sp<android::IBinder>& displayToken, +status_t SurfaceFlinger::getAllowedDisplayConfigs(const sp<IBinder>& displayToken, std::vector<int32_t>* outAllowedConfigs) { ATRACE_CALL(); - if (!displayToken) { - ALOGE("getAllowedDisplayConfigs: displayToken is null"); + if (!displayToken || !outAllowedConfigs) { return BAD_VALUE; } - if (!outAllowedConfigs) { - ALOGE("getAllowedDisplayConfigs: outAllowedConfigs is null"); - return BAD_VALUE; - } + Mutex::Autolock lock(mStateLock); - ConditionalLock stateLock(mStateLock, std::this_thread::get_id() != mMainThreadId); - const auto displayId = getPhysicalDisplayIdLocked(displayToken); - if (!displayId) { - ALOGE("getAllowedDisplayConfigs: display not found"); + if (displayToken != getInternalDisplayTokenLocked()) { + ALOGE("%s is only supported for the internal display", __FUNCTION__); return NAME_NOT_FOUND; } - std::lock_guard allowedConfigLock(mAllowedConfigsLock); - auto allowedConfigIterator = mAllowedConfigs.find(displayId.value()); - if (allowedConfigIterator != mAllowedConfigs.end()) { - allowedConfigIterator->second->getAllowedConfigs(outAllowedConfigs); - } - + outAllowedConfigs->assign(mAllowedDisplayConfigs.begin(), mAllowedDisplayConfigs.end()); return NO_ERROR; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 7e8e836e6a..7a7ad33d67 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -46,7 +46,6 @@ #include <utils/Trace.h> #include <utils/threads.h> -#include "AllowedDisplayConfigs.h" #include "DisplayDevice.h" #include "DisplayHardware/HWC2.h" #include "DisplayHardware/PowerAdvisor.h" @@ -74,6 +73,7 @@ #include <thread> #include <type_traits> #include <unordered_map> +#include <unordered_set> #include <utility> using namespace android::surfaceflinger; @@ -395,24 +395,20 @@ private: sp<IDisplayEventConnection> createDisplayEventConnection( ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp) override; status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer, - const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - bool useIdentityTransform, ISurfaceComposer::Rotation rotation, - bool captureSecureLayers) override; + bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace, + const ui::PixelFormat reqPixelFormat, Rect sourceCrop, + uint32_t reqWidth, uint32_t reqHeight, + bool useIdentityTransform, ISurfaceComposer::Rotation rotation, bool captureSecureLayers) override; status_t captureLayers( const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer, const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat, const Rect& sourceCrop, const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& exclude, float frameScale, bool childrenOnly) override; + status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override; status_t getDisplayConfigs(const sp<IBinder>& displayToken, - Vector<DisplayInfo>* configs) override { - Mutex::Autolock _l(mStateLock); - return getDisplayConfigsLocked(displayToken, configs); - } - status_t getDisplayConfigsLocked(const sp<IBinder>& displayToken, Vector<DisplayInfo>* configs) - REQUIRES(mStateLock); + Vector<DisplayInfo>* configs) override; int getActiveConfig(const sp<IBinder>& displayToken) override; status_t getDisplayColorModes(const sp<IBinder>& displayToken, Vector<ui::ColorMode>* configs) override; @@ -491,20 +487,10 @@ private: struct ActiveConfigInfo { RefreshRateType type; int configId; - sp<IBinder> displayToken; Scheduler::ConfigEvent event; bool operator!=(const ActiveConfigInfo& other) const { - if (type != other.type) { - return true; - } - if (configId != other.configId) { - return true; - } - if (displayToken != other.displayToken) { - return true; - } - return (event != other.event); + return type != other.type || configId != other.configId || event != other.event; } }; @@ -519,14 +505,14 @@ private: // desired config was set, HWC needs to update the panel on the next refresh, and when // we receive the fence back, we know that the process was complete. It returns whether // we need to wait for the next invalidate - bool performSetActiveConfig(); + bool performSetActiveConfig() REQUIRES(mStateLock); // called on the main thread in response to setPowerMode() void setPowerModeInternal(const sp<DisplayDevice>& display, int mode) REQUIRES(mStateLock); // called on the main thread in response to setAllowedDisplayConfigs() - void setAllowedDisplayConfigsInternal( - const sp<IBinder>& displayToken, - std::unique_ptr<const AllowedDisplayConfigs>&& allowedConfigs) REQUIRES(mStateLock); + void setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display, + const std::vector<int32_t>& allowedConfigs) + REQUIRES(mStateLock); // Returns whether the transaction actually modified any state bool handleMessageTransaction(); @@ -640,13 +626,14 @@ private: int* outSyncFd); status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers, sp<GraphicBuffer>* outBuffer, const ui::PixelFormat reqPixelFormat, - bool useIdentityTransform); + bool useIdentityTransform, bool& outCapturedSecureLayers); status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers, - const sp<GraphicBuffer>& buffer, bool useIdentityTransform); + const sp<GraphicBuffer>& buffer, bool useIdentityTransform, + bool& outCapturedSecureLayers); status_t captureScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers, ANativeWindowBuffer* buffer, bool useIdentityTransform, - bool forSystem, int* outSyncFd); + bool forSystem, int* outSyncFd, bool& outCapturedSecureLayers); void traverseLayersInDisplay(const sp<const DisplayDevice>& display, const LayerVector::Visitor& visitor); @@ -805,7 +792,7 @@ private: // the desired refresh rate. void setRefreshRateTo(RefreshRateType, Scheduler::ConfigEvent event) REQUIRES(mStateLock); - bool isConfigAllowed(const DisplayId& displayId, int32_t config); + bool isDisplayConfigAllowed(int32_t configId) REQUIRES(mStateLock); /* * Display identification @@ -1111,14 +1098,13 @@ private: std::unique_ptr<Scheduler> mScheduler; sp<Scheduler::ConnectionHandle> mAppConnectionHandle; sp<Scheduler::ConnectionHandle> mSfConnectionHandle; - std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats; - std::unordered_map<DisplayId, std::shared_ptr<scheduler::RefreshRateConfigs>> - mRefreshRateConfigs; + scheduler::RefreshRateConfigs mRefreshRateConfigs; + scheduler::RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, *mTimeStats}; - std::mutex mAllowedConfigsLock; - std::unordered_map<DisplayId, std::unique_ptr<const AllowedDisplayConfigs>> mAllowedConfigs - GUARDED_BY(mAllowedConfigsLock); + // All configs are allowed if the set is empty. + using DisplayConfigs = std::set<int32_t>; + DisplayConfigs mAllowedDisplayConfigs GUARDED_BY(mStateLock); std::mutex mActiveConfigLock; // This bit is set once we start setting the config. We read from this bit during the @@ -1156,6 +1142,9 @@ private: Hwc2::impl::PowerAdvisor mPowerAdvisor; std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay; + + // Flag used to set override allowed display configs from backdoor + bool mDebugDisplayConfigSetByBackdoor = false; }; } // namespace android diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp index 26d2c21848..e425b2a953 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.cpp +++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp @@ -73,8 +73,10 @@ sp<SurfaceFlinger> createSurfaceFlinger() { return std::make_unique<scheduler::impl::PhaseOffsets>(); } - std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)> callback) override { - return std::make_unique<Scheduler>(callback); + std::unique_ptr<Scheduler> createScheduler( + std::function<void(bool)> callback, + const scheduler::RefreshRateConfigs& refreshRateConfig) override { + return std::make_unique<Scheduler>(callback, refreshRateConfig); } std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor( diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h index fc1d0f8b7f..c2bc808c8c 100644 --- a/services/surfaceflinger/SurfaceFlingerFactory.h +++ b/services/surfaceflinger/SurfaceFlingerFactory.h @@ -71,7 +71,9 @@ public: virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0; virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0; virtual std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() = 0; - virtual std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)> callback) = 0; + virtual std::unique_ptr<Scheduler> createScheduler( + std::function<void(bool)> callback, + const scheduler::RefreshRateConfigs& refreshRateConfig) = 0; virtual std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0; virtual sp<StartPropertySetThread> createStartPropertySetThread( diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop index 830c03eee7..d3690967dc 100644 --- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop +++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop @@ -36,7 +36,7 @@ owner: Platform prop { api_name: "vsync_event_phase_offset_ns" type: Long - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.vsync_event_phase_offset_ns" } @@ -44,7 +44,7 @@ prop { prop { api_name: "vsync_sf_event_phase_offset_ns" type: Long - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.vsync_sf_event_phase_offset_ns" } @@ -53,7 +53,7 @@ prop { prop { api_name: "use_context_priority" type: Boolean - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.use_context_priority" } @@ -62,7 +62,7 @@ prop { prop { api_name: "max_frame_buffer_acquired_buffers" type: Long - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.max_frame_buffer_acquired_buffers" } @@ -80,7 +80,7 @@ prop { prop { api_name: "has_wide_color_display" type: Boolean - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.has_wide_color_display" } @@ -90,7 +90,7 @@ prop { prop { api_name: "running_without_sync_framework" type: Boolean - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.running_without_sync_framework" } @@ -108,7 +108,7 @@ prop { prop { api_name: "has_HDR_display" type: Boolean - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.has_HDR_display" } @@ -117,7 +117,7 @@ prop { prop { api_name: "present_time_offset_from_vsync_ns" type: Long - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.present_time_offset_from_vsync_ns" } @@ -129,7 +129,7 @@ prop { prop { api_name: "force_hwc_copy_for_virtual_displays" type: Boolean - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.force_hwc_copy_for_virtual_displays" } @@ -139,7 +139,7 @@ prop { prop { api_name: "max_virtual_display_dimension" type: Long - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.max_virtual_display_dimension" } @@ -151,7 +151,7 @@ prop { prop { api_name: "use_vr_flinger" type: Boolean - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.use_vr_flinger" } @@ -161,7 +161,7 @@ prop { prop { api_name: "start_graphics_allocator_service" type: Boolean - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.start_graphics_allocator_service" } @@ -171,7 +171,7 @@ prop { api_name: "primary_display_orientation" type: Enum enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270" - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.primary_display_orientation" } @@ -182,7 +182,7 @@ prop { prop { api_name: "use_color_management" type: Boolean - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.use_color_management" } @@ -209,7 +209,7 @@ prop { prop { api_name: "default_composition_dataspace" type: Long - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.default_composition_dataspace" } @@ -220,7 +220,7 @@ prop { prop { api_name: "default_composition_pixel_format" type: Integer - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.default_composition_pixel_format" } @@ -235,7 +235,7 @@ prop { prop { api_name: "wcg_composition_dataspace" type: Long - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.wcg_composition_dataspace" } @@ -246,7 +246,7 @@ prop { prop { api_name: "wcg_composition_pixel_format" type: Integer - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.wcg_composition_pixel_format" } @@ -258,7 +258,7 @@ prop { prop { api_name: "display_primary_red" type: DoubleList - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.display_primary_red" } @@ -266,7 +266,7 @@ prop { prop { api_name: "display_primary_green" type: DoubleList - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.display_primary_green" } @@ -274,7 +274,7 @@ prop { prop { api_name: "display_primary_blue" type: DoubleList - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.display_primary_blue" } @@ -282,7 +282,7 @@ prop { prop { api_name: "display_primary_white" type: DoubleList - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.display_primary_white" } @@ -293,7 +293,7 @@ prop { prop { api_name: "set_idle_timer_ms" type: Integer - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.set_idle_timer_ms" } @@ -303,7 +303,7 @@ prop { prop { api_name: "use_smart_90_for_video" type: Boolean - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.use_smart_90_for_video" } @@ -311,7 +311,7 @@ prop { prop { api_name: "enable_protected_contents" type: Boolean - scope: Internal + scope: System access: Readonly prop_name: "ro.surface_flinger.protected_contents" } diff --git a/services/surfaceflinger/sysprop/api/system-current.txt b/services/surfaceflinger/sysprop/api/system-current.txt index d802177e24..3c39b51f9b 100644 --- a/services/surfaceflinger/sysprop/api/system-current.txt +++ b/services/surfaceflinger/sysprop/api/system-current.txt @@ -1 +1,41 @@ // Signature format: 2.0 +package android.sysprop { + + public final class SurfaceFlingerProperties { + method public static java.util.Optional<java.lang.Long> default_composition_dataspace(); + method public static java.util.Optional<java.lang.Integer> default_composition_pixel_format(); + method public static java.util.List<java.lang.Double> display_primary_blue(); + method public static java.util.List<java.lang.Double> display_primary_green(); + method public static java.util.List<java.lang.Double> display_primary_red(); + method public static java.util.List<java.lang.Double> display_primary_white(); + method public static java.util.Optional<java.lang.Boolean> enable_protected_contents(); + method public static java.util.Optional<java.lang.Boolean> force_hwc_copy_for_virtual_displays(); + method public static java.util.Optional<java.lang.Boolean> has_HDR_display(); + method public static java.util.Optional<java.lang.Boolean> has_wide_color_display(); + method public static java.util.Optional<java.lang.Long> max_frame_buffer_acquired_buffers(); + method public static java.util.Optional<java.lang.Long> max_virtual_display_dimension(); + method public static java.util.Optional<java.lang.Long> present_time_offset_from_vsync_ns(); + method public static java.util.Optional<android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values> primary_display_orientation(); + method public static java.util.Optional<java.lang.Boolean> running_without_sync_framework(); + method public static java.util.Optional<java.lang.Integer> set_idle_timer_ms(); + method public static java.util.Optional<java.lang.Boolean> start_graphics_allocator_service(); + method public static java.util.Optional<java.lang.Boolean> use_color_management(); + method public static java.util.Optional<java.lang.Boolean> use_context_priority(); + method public static java.util.Optional<java.lang.Boolean> use_smart_90_for_video(); + method public static java.util.Optional<java.lang.Boolean> use_vr_flinger(); + method public static java.util.Optional<java.lang.Long> vsync_event_phase_offset_ns(); + method public static java.util.Optional<java.lang.Long> vsync_sf_event_phase_offset_ns(); + method public static java.util.Optional<java.lang.Long> wcg_composition_dataspace(); + method public static java.util.Optional<java.lang.Integer> wcg_composition_pixel_format(); + } + + public enum SurfaceFlingerProperties.primary_display_orientation_values { + method public String getPropValue(); + enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_0; + enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_180; + enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_270; + enum_constant public static final android.sysprop.SurfaceFlingerProperties.primary_display_orientation_values ORIENTATION_90; + } + +} + diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp index ba854e3f27..d03c25df70 100644 --- a/services/surfaceflinger/tests/Transaction_test.cpp +++ b/services/surfaceflinger/tests/Transaction_test.cpp @@ -1269,11 +1269,12 @@ TEST_F(LayerTransactionTest, SetFlagsSecureEUidSystem) { // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able // to receive them...we are expected to take care with the results. + bool outCapturedSecureLayers; ASSERT_EQ(NO_ERROR, - composer->captureScreen(mDisplay, &outBuffer, - ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, - Rect(), 0, 0, false, - ISurfaceComposer::eRotateNone, true)); + composer->captureScreen(mDisplay, &outBuffer, outCapturedSecureLayers, + ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), 0, + 0, false, ISurfaceComposer::eRotateNone, true)); + ASSERT_EQ(true, outCapturedSecureLayers); ScreenCapture sc(outBuffer); sc.expectColor(Rect(0, 0, 32, 32), Color::RED); } diff --git a/services/surfaceflinger/tests/unittests/AllowedDisplayConfigsTest.cpp b/services/surfaceflinger/tests/unittests/AllowedDisplayConfigsTest.cpp deleted file mode 100644 index 42742543ac..0000000000 --- a/services/surfaceflinger/tests/unittests/AllowedDisplayConfigsTest.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2019 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. - */ - -#undef LOG_TAG -#define LOG_TAG "LibSurfaceFlingerUnittests" -#define LOG_NDEBUG 0 - -#include <memory> -#include <vector> - -#include <gtest/gtest.h> - -#include <log/log.h> - -#include "AllowedDisplayConfigs.h" - -namespace android { -namespace { - -class AllowedDisplayConfigsTest : public testing::Test { -protected: - AllowedDisplayConfigsTest(); - ~AllowedDisplayConfigsTest() override; - - void buildAllowedConfigs(); - - const std::vector<int32_t> expectedConfigs = {0, 2, 7, 129}; - constexpr static int32_t notAllowedConfig = 5; - std::unique_ptr<const AllowedDisplayConfigs> mAllowedConfigs; -}; - -AllowedDisplayConfigsTest::AllowedDisplayConfigsTest() { - const ::testing::TestInfo* const test_info = - ::testing::UnitTest::GetInstance()->current_test_info(); - ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name()); -} - -AllowedDisplayConfigsTest::~AllowedDisplayConfigsTest() { - const ::testing::TestInfo* const test_info = - ::testing::UnitTest::GetInstance()->current_test_info(); - ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); -} - -void AllowedDisplayConfigsTest::buildAllowedConfigs() { - AllowedDisplayConfigs::Builder builder; - for (int config : expectedConfigs) { - builder.addConfig(config); - } - mAllowedConfigs = builder.build(); -} - -/* ------------------------------------------------------------------------ - * Test cases - */ - -TEST_F(AllowedDisplayConfigsTest, checkConfigs) { - buildAllowedConfigs(); - - // Check that all expected configs are allowed - for (int config : expectedConfigs) { - EXPECT_TRUE(mAllowedConfigs->isConfigAllowed(config)); - } - - // Check that all the allowed configs are expected - std::vector<int32_t> allowedConfigVector; - mAllowedConfigs->getAllowedConfigs(&allowedConfigVector); - EXPECT_EQ(allowedConfigVector, expectedConfigs); - - // Check that notAllowedConfig is indeed not allowed - EXPECT_TRUE(std::find(expectedConfigs.begin(), expectedConfigs.end(), notAllowedConfig) == - expectedConfigs.end()); - EXPECT_FALSE(mAllowedConfigs->isConfigAllowed(notAllowedConfig)); -} - -TEST_F(AllowedDisplayConfigsTest, getAllowedConfigsNullptr) { - buildAllowedConfigs(); - - // No other expectations rather than no crash - mAllowedConfigs->getAllowedConfigs(nullptr); -} - -} // namespace -} // namespace android diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index d4eac88ba1..85e9ce5f3f 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -35,7 +35,6 @@ cc_test { srcs: [ ":libsurfaceflinger_sources", "libsurfaceflinger_unittest_main.cpp", - "AllowedDisplayConfigsTest.cpp", "CompositionTest.cpp", "DispSyncSourceTest.cpp", "DisplayIdentificationTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp index ef3dfef38f..bebfa6c7ee 100644 --- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp +++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp @@ -125,7 +125,7 @@ public: } void setupScheduler() { - mScheduler = new TestableScheduler(); + mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs()); mScheduler->mutableEventControlThread().reset(mEventControlThread); mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync); EXPECT_CALL(*mEventThread.get(), registerDisplayEventConnection(_)); diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp index 92bdebd400..2e705dad6d 100644 --- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp +++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp @@ -142,23 +142,5 @@ TEST_F(DispSyncSourceTest, waitForCallbacksWithPhaseChange) { } } -TEST_F(DispSyncSourceTest, pauseCallbacks) { - createDispSyncSource(); - EXPECT_TRUE(mDispSyncSource); - - mDispSyncSource->setVSyncEnabled(true); - EXPECT_EQ(mDispSync->getCallbackPhase(), mPhaseOffset.count()); - mDispSync->triggerCallback(); - EXPECT_TRUE(mVSyncEventCallRecorder.waitForCall().has_value()); - - mDispSyncSource->pauseVsyncCallback(true); - mDispSync->triggerCallback(); - EXPECT_FALSE(mVSyncEventCallRecorder.waitForUnexpectedCall().has_value()); - - mDispSyncSource->pauseVsyncCallback(false); - mDispSync->triggerCallback(); - EXPECT_TRUE(mVSyncEventCallRecorder.waitForUnexpectedCall().has_value()); -} - } // namespace } // namespace android diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp index 9bf29a212f..a13b888d08 100644 --- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp +++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp @@ -179,7 +179,7 @@ DisplayTransactionTest::~DisplayTransactionTest() { } void DisplayTransactionTest::setupScheduler() { - mScheduler = new TestableScheduler(); + mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs()); mScheduler->mutableEventControlThread().reset(mEventControlThread); mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync); EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)); @@ -2830,7 +2830,6 @@ struct EventThreadIsSupportedVariant : public EventThreadBaseSupportedVariant { struct DispSyncIsSupportedVariant { static void setupBeginResyncCallExpectations(DisplayTransactionTest* test) { - EXPECT_CALL(*test->mPrimaryDispSync, reset()).Times(1); EXPECT_CALL(*test->mPrimaryDispSync, setPeriod(DEFAULT_REFRESH_RATE)).Times(1); EXPECT_CALL(*test->mPrimaryDispSync, beginResync()).Times(1); } diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp index 249c78f09c..83a92c8691 100644 --- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp +++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp @@ -73,7 +73,6 @@ protected: void expectVSyncSetEnabledCallReceived(bool expectedState); void expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset); - void expectVSyncPauseVsyncCallbackCallReceived(bool expectedPause); VSyncSource::Callback* expectVSyncSetCallbackCallReceived(); void expectInterceptCallReceived(nsecs_t expectedTimestamp); void expectVsyncEventReceivedByConnection(const char* name, @@ -88,7 +87,6 @@ protected: AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder; AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder; AsyncCallRecorder<void (*)(nsecs_t)> mVSyncSetPhaseOffsetCallRecorder; - AsyncCallRecorder<void (*)(bool)> mVSyncPauseVsyncCallbackCallRecorder; AsyncCallRecorder<void (*)()> mResyncCallRecorder; AsyncCallRecorder<void (*)()> mResetIdleTimerCallRecorder; AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder; @@ -114,9 +112,6 @@ EventThreadTest::EventThreadTest() { EXPECT_CALL(mVSyncSource, setPhaseOffset(_)) .WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable())); - EXPECT_CALL(mVSyncSource, pauseVsyncCallback(_)) - .WillRepeatedly(Invoke(mVSyncPauseVsyncCallbackCallRecorder.getInvocable())); - createThread(); mConnection = createConnection(mConnectionEventCallRecorder); @@ -166,12 +161,6 @@ void EventThreadTest::expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhas EXPECT_EQ(expectedPhaseOffset, std::get<0>(args.value())); } -void EventThreadTest::expectVSyncPauseVsyncCallbackCallReceived(bool expectedPause) { - auto args = mVSyncPauseVsyncCallbackCallRecorder.waitForCall(); - ASSERT_TRUE(args.has_value()); - EXPECT_EQ(expectedPause, std::get<0>(args.value())); -} - VSyncSource::Callback* EventThreadTest::expectVSyncSetCallbackCallReceived() { auto callbackSet = mVSyncSetCallbackCallRecorder.waitForCall(); return callbackSet.has_value() ? std::get<0>(callbackSet.value()) : nullptr; @@ -431,16 +420,6 @@ TEST_F(EventThreadTest, setPhaseOffsetForwardsToVSyncSource) { expectVSyncSetPhaseOffsetCallReceived(321); } -TEST_F(EventThreadTest, pauseVsyncCallbackForwardsToVSyncSource) { - mThread->pauseVsyncCallback(true); - expectVSyncPauseVsyncCallbackCallReceived(true); -} - -TEST_F(EventThreadTest, resumeVsyncCallbackForwardsToVSyncSource) { - mThread->pauseVsyncCallback(false); - expectVSyncPauseVsyncCallbackCallReceived(false); -} - TEST_F(EventThreadTest, postHotplugInternalDisconnect) { mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, false); expectHotplugEventReceivedByConnection(INTERNAL_DISPLAY_ID, false); diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index 3fb1a6e62a..e51121fcf7 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -7,6 +7,7 @@ #include <log/log.h> #include <mutex> +#include <thread> #include "Scheduler/LayerHistory.h" @@ -14,6 +15,7 @@ using testing::_; using testing::Return; namespace android { +namespace scheduler { class LayerHistoryTest : public testing::Test { public: @@ -22,6 +24,8 @@ public: protected: std::unique_ptr<LayerHistory> mLayerHistory; + + static constexpr float MAX_REFRESH_RATE = 90.f; }; LayerHistoryTest::LayerHistoryTest() { @@ -30,145 +34,79 @@ LayerHistoryTest::LayerHistoryTest() { LayerHistoryTest::~LayerHistoryTest() {} namespace { -TEST_F(LayerHistoryTest, simpleInsertAndGet) { - mLayerHistory->insert("TestLayer", 0); - - const std::unordered_map<std::string, nsecs_t>& testMap = mLayerHistory->get(0); - EXPECT_EQ(1, testMap.size()); - auto element = testMap.find("TestLayer"); - EXPECT_EQ("TestLayer", element->first); - EXPECT_EQ(0, element->second); - - // Testing accessing object at an empty container will return an empty map. - const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(1); - EXPECT_EQ(0, emptyMap.size()); +TEST_F(LayerHistoryTest, oneLayer) { + std::unique_ptr<LayerHistory::LayerHandle> testLayer = + mLayerHistory->createLayer("TestLayer", MAX_REFRESH_RATE); + + mLayerHistory->insert(testLayer, 0); + EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRate()); + + mLayerHistory->insert(testLayer, 0); + mLayerHistory->insert(testLayer, 0); + mLayerHistory->insert(testLayer, 0); + // This is still 0, because the layer is not considered recently active if it + // has been present in less than 10 frames. + EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRate()); + mLayerHistory->insert(testLayer, 0); + mLayerHistory->insert(testLayer, 0); + mLayerHistory->insert(testLayer, 0); + mLayerHistory->insert(testLayer, 0); + mLayerHistory->insert(testLayer, 0); + mLayerHistory->insert(testLayer, 0); + // This should be MAX_REFRESH_RATE as we have more than 10 samples + EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRate()); } -TEST_F(LayerHistoryTest, multipleInserts) { - mLayerHistory->insert("TestLayer0", 0); - mLayerHistory->insert("TestLayer1", 1); - mLayerHistory->insert("TestLayer2", 2); - mLayerHistory->insert("TestLayer3", 3); - - const std::unordered_map<std::string, nsecs_t>& testMap = mLayerHistory->get(0); - // Because the counter was not incremented, all elements were inserted into the first - // container. - EXPECT_EQ(4, testMap.size()); - auto element = testMap.find("TestLayer0"); - EXPECT_EQ("TestLayer0", element->first); - EXPECT_EQ(0, element->second); - - element = testMap.find("TestLayer1"); - EXPECT_EQ("TestLayer1", element->first); - EXPECT_EQ(1, element->second); - - element = testMap.find("TestLayer2"); - EXPECT_EQ("TestLayer2", element->first); - EXPECT_EQ(2, element->second); - - element = testMap.find("TestLayer3"); - EXPECT_EQ("TestLayer3", element->first); - EXPECT_EQ(3, element->second); - - // Testing accessing object at an empty container will return an empty map. - const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(1); - EXPECT_EQ(0, emptyMap.size()); -} +TEST_F(LayerHistoryTest, explicitTimestamp) { + std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer = + mLayerHistory->createLayer("30FpsLayer", MAX_REFRESH_RATE); -TEST_F(LayerHistoryTest, incrementingCounter) { - mLayerHistory->insert("TestLayer0", 0); - mLayerHistory->incrementCounter(); - mLayerHistory->insert("TestLayer1", 1); - mLayerHistory->insert("TestLayer2", 2); - mLayerHistory->incrementCounter(); - mLayerHistory->insert("TestLayer3", 3); - - // Because the counter was incremented, the elements were inserted into different - // containers. - // We expect the get method to access the slot at the current counter of the index - // is 0. - const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0); - EXPECT_EQ(1, testMap1.size()); - auto element = testMap1.find("TestLayer3"); - EXPECT_EQ("TestLayer3", element->first); - EXPECT_EQ(3, element->second); - - const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(1); - EXPECT_EQ(2, testMap2.size()); - element = testMap2.find("TestLayer1"); - EXPECT_EQ("TestLayer1", element->first); - EXPECT_EQ(1, element->second); - element = testMap2.find("TestLayer2"); - EXPECT_EQ("TestLayer2", element->first); - EXPECT_EQ(2, element->second); - - const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(2); - EXPECT_EQ(1, testMap3.size()); - element = testMap3.find("TestLayer0"); - EXPECT_EQ("TestLayer0", element->first); - EXPECT_EQ(0, element->second); - - // Testing accessing object at an empty container will return an empty map. - const std::unordered_map<std::string, nsecs_t>& emptyMap = mLayerHistory->get(3); - EXPECT_EQ(0, emptyMap.size()); -} + nsecs_t startTime = systemTime(); + for (int i = 0; i < 31; i++) { + mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333)); + } -TEST_F(LayerHistoryTest, clearTheMap) { - mLayerHistory->insert("TestLayer0", 0); + EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRate()); +} - const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0); - EXPECT_EQ(1, testMap1.size()); - auto element = testMap1.find("TestLayer0"); - EXPECT_EQ("TestLayer0", element->first); - EXPECT_EQ(0, element->second); +TEST_F(LayerHistoryTest, multipleLayers) { + std::unique_ptr<LayerHistory::LayerHandle> testLayer = + mLayerHistory->createLayer("TestLayer", MAX_REFRESH_RATE); + std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer = + mLayerHistory->createLayer("30FpsLayer", MAX_REFRESH_RATE); + std::unique_ptr<LayerHistory::LayerHandle> testLayer2 = + mLayerHistory->createLayer("TestLayer2", MAX_REFRESH_RATE); + + nsecs_t startTime = systemTime(); + for (int i = 0; i < 10; i++) { + mLayerHistory->insert(testLayer, 0); + } + EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRate()); - mLayerHistory->incrementCounter(); - // The array currently contains 30 elements. - for (int i = 1; i < 30; ++i) { - mLayerHistory->insert("TestLayer0", i); - mLayerHistory->incrementCounter(); + startTime = systemTime(); + for (int i = 0; i < 10; i++) { + mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333)); } - // Expect the map to be cleared. - const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(0); - EXPECT_EQ(0, testMap2.size()); - - mLayerHistory->insert("TestLayer30", 30); - const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(0); - element = testMap3.find("TestLayer30"); - EXPECT_EQ("TestLayer30", element->first); - EXPECT_EQ(30, element->second); - // The original element in this location does not exist anymore. - element = testMap3.find("TestLayer0"); - EXPECT_EQ(testMap3.end(), element); -} + EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRate()); -TEST_F(LayerHistoryTest, testingGet) { - // The array currently contains 30 elements. - for (int i = 0; i < 30; ++i) { - const auto name = "TestLayer" + std::to_string(i); - mLayerHistory->insert(name, i); - mLayerHistory->incrementCounter(); + for (int i = 10; i < 30; i++) { + mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333)); } + EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRate()); - // The counter should be set to 0, and the map at 0 should be cleared. - const std::unordered_map<std::string, nsecs_t>& testMap1 = mLayerHistory->get(0); - EXPECT_EQ(0, testMap1.size()); - - // This should return (ARRAY_SIZE + (counter - 3)) % ARRAY_SIZE - const std::unordered_map<std::string, nsecs_t>& testMap2 = mLayerHistory->get(3); - EXPECT_EQ(1, testMap2.size()); - auto element = testMap2.find("TestLayer27"); - EXPECT_EQ("TestLayer27", element->first); - EXPECT_EQ(27, element->second); - - // If the user gives an out of bound index, we should mod it with ARRAY_SIZE first, - // so requesting element 40 would be the same as requesting element 10. - const std::unordered_map<std::string, nsecs_t>& testMap3 = mLayerHistory->get(40); - EXPECT_EQ(1, testMap3.size()); - element = testMap3.find("TestLayer20"); - EXPECT_EQ("TestLayer20", element->first); - EXPECT_EQ(20, element->second); + // This frame is only around for 9 occurrences, so it doesn't throw + // anything off. + for (int i = 0; i < 9; i++) { + mLayerHistory->insert(testLayer2, 0); + } + EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRate()); + // After 100 ms frames become obsolete. + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + // Insert the 31st frame. + mLayerHistory->insert(test30FpsLayer, startTime + (30 * 33333333)); + EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRate()); } } // namespace +} // namespace scheduler } // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp index b218ad63d6..8b37c22356 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp @@ -49,6 +49,8 @@ protected: ASSERT_EQ(left.name, right.name); ASSERT_EQ(left.fps, right.fps); } + + RefreshRateConfigs mConfigs; }; RefreshRateConfigsTest::RefreshRateConfigsTest() { @@ -69,10 +71,10 @@ namespace { */ TEST_F(RefreshRateConfigsTest, zeroDeviceConfigs_storesPowerSavingConfig) { std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs; - RefreshRateConfigs configs(displayConfigs); + mConfigs.populate(displayConfigs); // We always store a configuration for screen off. - const auto& rates = configs.getRefreshRates(); + const auto& rates = mConfigs.getRefreshRates(); ASSERT_EQ(1, rates.size()); const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); ASSERT_NE(rates.end(), powerSavingRate); @@ -82,13 +84,13 @@ TEST_F(RefreshRateConfigsTest, zeroDeviceConfigs_storesPowerSavingConfig) { RefreshRate expectedConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0}; assertRatesEqual(expectedConfig, *powerSavingRate->second); - ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING)); - assertRatesEqual(expectedConfig, *configs.getRefreshRate(RefreshRateType::POWER_SAVING)); - ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE)); - ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::DEFAULT)); + ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); + assertRatesEqual(expectedConfig, *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); + ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); + ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); // Sanity check that getRefreshRate() does not modify the underlying configs. - ASSERT_EQ(1, configs.getRefreshRates().size()); + ASSERT_EQ(1, mConfigs.getRefreshRates().size()); } TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) { @@ -97,9 +99,9 @@ TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) { auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60); config60.setVsyncPeriod(VSYNC_60); displayConfigs.push_back(config60.build()); - RefreshRateConfigs configs(displayConfigs); + mConfigs.populate(displayConfigs); - const auto& rates = configs.getRefreshRates(); + const auto& rates = mConfigs.getRefreshRates(); ASSERT_EQ(2, rates.size()); const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); @@ -112,15 +114,15 @@ TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) { RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60}; assertRatesEqual(expectedDefaultConfig, *defaultRate->second); - ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING)); + ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); assertRatesEqual(expectedPowerSavingConfig, - *configs.getRefreshRate(RefreshRateType::POWER_SAVING)); - ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT)); - assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT)); - ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE)); + *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); + ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); + assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); + ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); // Sanity check that getRefreshRate() does not modify the underlying configs. - ASSERT_EQ(2, configs.getRefreshRates().size()); + ASSERT_EQ(2, mConfigs.getRefreshRates().size()); } TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) { @@ -132,9 +134,9 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) { auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90); config90.setVsyncPeriod(VSYNC_90); displayConfigs.push_back(config90.build()); - RefreshRateConfigs configs(displayConfigs); + mConfigs.populate(displayConfigs); - const auto& rates = configs.getRefreshRates(); + const auto& rates = mConfigs.getRefreshRates(); ASSERT_EQ(3, rates.size()); const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING); const auto& defaultRate = rates.find(RefreshRateType::DEFAULT); @@ -150,14 +152,14 @@ TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) { RefreshRate expectedPerformanceConfig = RefreshRate{CONFIG_ID_90, "90fps", 90}; assertRatesEqual(expectedPerformanceConfig, *performanceRate->second); - ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING)); + ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); assertRatesEqual(expectedPowerSavingConfig, - *configs.getRefreshRate(RefreshRateType::POWER_SAVING)); - ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT)); - assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT)); - ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::PERFORMANCE)); + *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING)); + ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); + assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT)); + ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); assertRatesEqual(expectedPerformanceConfig, - *configs.getRefreshRate(RefreshRateType::PERFORMANCE)); + *mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE)); } } // namespace } // namespace scheduler diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp index 10f5af8cd2..411ec61770 100644 --- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp @@ -42,11 +42,9 @@ protected: RefreshRateStatsTest(); ~RefreshRateStatsTest(); - void init(std::vector<std::shared_ptr<const HWC2::Display::Config>> configs); - - std::unique_ptr<RefreshRateStats> mRefreshRateStats; - std::shared_ptr<android::mock::TimeStats> mTimeStats; - std::shared_ptr<RefreshRateConfigs> mRefreshRateConfigs; + mock::TimeStats mTimeStats; + RefreshRateConfigs mRefreshRateConfigs; + RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, mTimeStats}; }; RefreshRateStatsTest::RefreshRateStatsTest() { @@ -61,22 +59,16 @@ RefreshRateStatsTest::~RefreshRateStatsTest() { ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name()); } -void RefreshRateStatsTest::init(std::vector<std::shared_ptr<const HWC2::Display::Config>> configs) { - mTimeStats = std::make_shared<android::mock::TimeStats>(); - mRefreshRateConfigs = std::make_shared<RefreshRateConfigs>(configs); - mRefreshRateStats = std::make_unique<RefreshRateStats>(mRefreshRateConfigs, mTimeStats); -} - namespace { /* ------------------------------------------------------------------------ * Test cases */ TEST_F(RefreshRateStatsTest, canCreateAndDestroyTest) { std::vector<std::shared_ptr<const HWC2::Display::Config>> configs; - init(configs); + mRefreshRateConfigs.populate(configs); // There is one default config, so the refresh rates should have one item. - EXPECT_EQ(1, mRefreshRateStats->getTotalTimes().size()); + EXPECT_EQ(1, mRefreshRateStats.getTotalTimes().size()); } TEST_F(RefreshRateStatsTest, oneConfigTest) { @@ -87,12 +79,12 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { std::vector<std::shared_ptr<const HWC2::Display::Config>> configs; configs.push_back(config.build()); - init(configs); + mRefreshRateConfigs.populate(configs); - EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); - EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); + EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); + EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); - std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes(); + std::unordered_map<std::string, int64_t> times = mRefreshRateStats.getTotalTimes(); EXPECT_EQ(2, times.size()); EXPECT_NE(0u, times.count("ScreenOff")); EXPECT_EQ(1u, times.count("90fps")); @@ -105,29 +97,29 @@ TEST_F(RefreshRateStatsTest, oneConfigTest) { // Screen is off by default. std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(0, times["90fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); - mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL); - screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; + mRefreshRateStats.setConfigMode(CONFIG_ID_90); + mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL); + screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_LT(ninety, times["90fps"]); - mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE); - ninety = mRefreshRateStats->getTotalTimes()["90fps"]; + mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE); + ninety = mRefreshRateStats.getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); - screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; + mRefreshRateStats.setConfigMode(CONFIG_ID_90); + screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config // does not update refresh rates that come from the config. EXPECT_LT(screenOff, times["ScreenOff"]); @@ -146,13 +138,13 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { config60.setVsyncPeriod(VSYNC_60); configs.push_back(config60.build()); - init(configs); + mRefreshRateConfigs.populate(configs); - EXPECT_CALL(*mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); - EXPECT_CALL(*mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1)); - EXPECT_CALL(*mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); + EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1)); + EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1)); + EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1)); - std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes(); + std::unordered_map<std::string, int64_t> times = mRefreshRateStats.getTotalTimes(); EXPECT_EQ(3, times.size()); EXPECT_NE(0u, times.count("ScreenOff")); EXPECT_EQ(1u, times.count("60fps")); @@ -168,60 +160,60 @@ TEST_F(RefreshRateStatsTest, twoConfigsTest) { // Screen is off by default. std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(sixty, times["60fps"]); EXPECT_EQ(ninety, times["90fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); - mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL); - screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; + mRefreshRateStats.setConfigMode(CONFIG_ID_90); + mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL); + screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_EQ(sixty, times["60fps"]); EXPECT_LT(ninety, times["90fps"]); // When power mode is normal, time for configs updates. - mRefreshRateStats->setConfigMode(CONFIG_ID_60); - ninety = mRefreshRateStats->getTotalTimes()["90fps"]; + mRefreshRateStats.setConfigMode(CONFIG_ID_60); + ninety = mRefreshRateStats.getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_LT(sixty, times["60fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); - sixty = mRefreshRateStats->getTotalTimes()["60fps"]; + mRefreshRateStats.setConfigMode(CONFIG_ID_90); + sixty = mRefreshRateStats.getTotalTimes()["60fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_LT(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_60); - ninety = mRefreshRateStats->getTotalTimes()["90fps"]; + mRefreshRateStats.setConfigMode(CONFIG_ID_60); + ninety = mRefreshRateStats.getTotalTimes()["90fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_EQ(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_LT(sixty, times["60fps"]); // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config // does not update refresh rates that come from the config. - mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE); - mRefreshRateStats->setConfigMode(CONFIG_ID_90); - sixty = mRefreshRateStats->getTotalTimes()["60fps"]; + mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE); + mRefreshRateStats.setConfigMode(CONFIG_ID_90); + sixty = mRefreshRateStats.getTotalTimes()["60fps"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); - mRefreshRateStats->setConfigMode(CONFIG_ID_60); - screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"]; + mRefreshRateStats.setConfigMode(CONFIG_ID_60); + screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"]; std::this_thread::sleep_for(std::chrono::milliseconds(2)); - times = mRefreshRateStats->getTotalTimes(); + times = mRefreshRateStats.getTotalTimes(); EXPECT_LT(screenOff, times["ScreenOff"]); EXPECT_EQ(ninety, times["90fps"]); EXPECT_EQ(sixty, times["60fps"]); diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp index ec765382b8..b960bdf3fd 100644 --- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp +++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp @@ -33,14 +33,17 @@ protected: MOCK_METHOD0(requestNextVsync, void()); }; + scheduler::RefreshRateConfigs mRefreshRateConfigs; + /** * This mock Scheduler class uses implementation of mock::EventThread but keeps everything else * the same. */ class MockScheduler : public android::Scheduler { public: - MockScheduler(std::unique_ptr<EventThread> eventThread) - : Scheduler([](bool) {}), mEventThread(std::move(eventThread)) {} + MockScheduler(const scheduler::RefreshRateConfigs& refreshRateConfigs, + std::unique_ptr<EventThread> eventThread) + : Scheduler([](bool) {}, refreshRateConfigs), mEventThread(std::move(eventThread)) {} std::unique_ptr<EventThread> makeEventThread( const char* /* connectionName */, DispSync* /* dispSync */, @@ -71,7 +74,7 @@ SchedulerTest::SchedulerTest() { std::unique_ptr<mock::EventThread> eventThread = std::make_unique<mock::EventThread>(); mEventThread = eventThread.get(); - mScheduler = std::make_unique<MockScheduler>(std::move(eventThread)); + mScheduler = std::make_unique<MockScheduler>(mRefreshRateConfigs, std::move(eventThread)); EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0)); mEventThreadConnection = new MockEventThreadConnection(mEventThread); diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h index dcbf973d2c..1c397d8443 100644 --- a/services/surfaceflinger/tests/unittests/TestableScheduler.h +++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h @@ -19,13 +19,15 @@ #include <gmock/gmock.h> #include "Scheduler/EventThread.h" +#include "Scheduler/RefreshRateConfigs.h" #include "Scheduler/Scheduler.h" namespace android { class TestableScheduler : public Scheduler { public: - TestableScheduler() : Scheduler([](bool) {}) {} + TestableScheduler(const scheduler::RefreshRateConfigs& refreshRateConfig) + : Scheduler([](bool) {}, refreshRateConfig) {} // Creates EventThreadConnection with the given eventThread. Creates Scheduler::Connection // and adds it to the list of connectins. Returns the ConnectionHandle for the diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 81235ba260..df14e7e45d 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -86,7 +86,8 @@ public: return std::make_unique<scheduler::FakePhaseOffsets>(); } - std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)>) override { + std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)>, + const scheduler::RefreshRateConfigs&) override { // TODO: Use test-fixture controlled factory return nullptr; } @@ -276,12 +277,13 @@ public: auto onMessageReceived(int32_t what) { return mFlinger->onMessageReceived(what); } - auto captureScreenImplLocked(const RenderArea& renderArea, - SurfaceFlinger::TraverseLayersFunction traverseLayers, - ANativeWindowBuffer* buffer, bool useIdentityTransform, - bool forSystem, int* outSyncFd) { + auto captureScreenImplLocked( + const RenderArea& renderArea, SurfaceFlinger::TraverseLayersFunction traverseLayers, + ANativeWindowBuffer* buffer, bool useIdentityTransform, bool forSystem, int* outSyncFd) { + bool ignored; return mFlinger->captureScreenImplLocked(renderArea, traverseLayers, buffer, - useIdentityTransform, forSystem, outSyncFd); + useIdentityTransform, forSystem, outSyncFd, + ignored); } auto traverseLayersInDisplay(const sp<const DisplayDevice>& display, @@ -339,6 +341,7 @@ public: auto& mutableScheduler() { return mFlinger->mScheduler; } auto& mutableAppConnectionHandle() { return mFlinger->mAppConnectionHandle; } auto& mutableSfConnectionHandle() { return mFlinger->mSfConnectionHandle; } + auto& mutableRefreshRateConfigs() { return mFlinger->mRefreshRateConfigs; } ~TestableSurfaceFlinger() { // All these pointer and container clears help ensure that GMock does diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h index afcda5bc47..12a349dd76 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h +++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h @@ -31,7 +31,7 @@ public: MOCK_METHOD0(reset, void()); MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr<FenceTime>&)); MOCK_METHOD0(beginResync, void()); - MOCK_METHOD1(addResyncSample, bool(nsecs_t)); + MOCK_METHOD2(addResyncSample, bool(nsecs_t, bool*)); MOCK_METHOD0(endResync, void()); MOCK_METHOD1(setPeriod, void(nsecs_t)); MOCK_METHOD0(getPeriod, nsecs_t()); |