Merge "Make sure GL version string is correct" into qt-dev
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 04884bb..180fd97 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -31,6 +31,7 @@
"/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 @@
"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 776c6e6..e226136 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -190,6 +190,7 @@
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 96c55ac..e0e3431 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -73,6 +73,8 @@
mActiveBuffers(),
mDequeueCondition(),
mDequeueBufferCannotBlock(false),
+ mQueueBufferCanDrop(false),
+ mLegacyBufferDrop(true),
mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
mDefaultWidth(1),
mDefaultHeight(1),
@@ -117,6 +119,8 @@
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 72ae375..4ff69c5 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -889,7 +889,8 @@
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 @@
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 @@
}
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 bf44121..0e03b7d 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -72,6 +72,7 @@
GET_FRAME_TIMESTAMPS,
GET_UNIQUE_ID,
GET_CONSUMER_USAGE,
+ SET_LEGACY_BUFFER_DROP,
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -437,6 +438,20 @@
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 @@
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 @@
// ----------------------------------------------------------------------
+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 @@
}
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 8d7baf3..a3165dd 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -109,7 +109,7 @@
}
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 @@
*outBuffer = new GraphicBuffer();
reply.read(**outBuffer);
+ outCapturedSecureLayers = reply.readBool();
return result;
}
@@ -1027,12 +1028,17 @@
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 0e61702..611da89 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1542,13 +1542,15 @@
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 @@
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 0e80283..9c0ee99 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -226,6 +226,16 @@
// 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 415e2a6..d2a47a6 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -174,6 +174,9 @@
// 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 9f7e22b..3dde8c8 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -592,12 +592,20 @@
// 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 14d92bf..415b2d5 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -212,7 +212,7 @@
* 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 @@
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 f64fb61..9d34468 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -509,7 +509,8 @@
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 fa2e97f..d5bdd74 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -126,7 +126,7 @@
}
// 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 @@
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 @@
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 @@
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 a6ed75f..6570704 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -579,10 +579,9 @@
}
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 @@
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 71b918f..e8685c2 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -165,6 +165,9 @@
// 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 7ca62ea..0000000
--- 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 52c68df..9080d29 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -147,6 +147,7 @@
"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 1b2b180..a08ae8c 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -413,6 +413,7 @@
// 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 b623991..ff5f271 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -398,8 +398,8 @@
// 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 64dfdc3..2cbb917 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -209,7 +209,8 @@
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 @@
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 @@
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 668830a..864a15d 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -63,7 +63,8 @@
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 @@
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 1142df8..2bbac72 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -70,7 +70,10 @@
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 @@
mFrameEventHistory.initializeCompositorTiming(compositorTiming);
mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval);
+ mSchedulerLayerHandle = mFlinger->mScheduler->registerLayer(mName.c_str(), mWindowType);
+
mFlinger->onLayerCreated();
}
@@ -1298,6 +1303,7 @@
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 @@
} 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 @@
}
}
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 8348ce1..f4545e0 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -311,7 +311,10 @@
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 @@
}
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 @@
// 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 06e3d9c..c60421b 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -132,6 +132,10 @@
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 1246d14..d346f82 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -61,6 +61,7 @@
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 ce0611c..69d8c89 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 35f11fc..252ff0d 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -392,7 +392,8 @@
//
// 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 f72aef1..871f556 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -210,14 +210,16 @@
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 @@
return NO_ERROR;
}
}
-
return BAD_VALUE;
}
@@ -525,21 +526,40 @@
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 @@
// 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 @@
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 de2b874..8f8b8e7 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -49,7 +49,7 @@
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 @@
// 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 @@
// 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 6e89648..00948ae 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -87,19 +87,7 @@
}
}
-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 2858678..4759699 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -33,7 +33,6 @@
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 @@
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 a760079..a6c7e6c 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -210,12 +210,6 @@
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 67e6de9..7107d63 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -66,9 +66,6 @@
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 @@
// 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 @@
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 d5ccbe1..8e36ae9 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 {
-LayerHistory::LayerHistory() {}
+std::atomic<int64_t> LayerHistory::sNextId = 0;
+
+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::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();
+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);
+ }
}
-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::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);
}
+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;
+}
+
+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 c6fab07..39061e7 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 0000000..95d7d31
--- /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 0000000..1970a47
--- /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 cbcaade..a85660a 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -68,8 +68,8 @@
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 1aa6ade..eb9ae35 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -51,16 +51,10 @@
// 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 @@
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:
std::map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates;
};
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index ff63faf..7e7c630 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -41,12 +41,8 @@
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 @@
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 @@
// 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 @@
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 @@
}
// 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 0063c8a..1b154a4 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 @@
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 @@
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::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::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 @@
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 @@
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;
+ }
+
+ // 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;
}
}
- changeRefreshRate(refreshRateType, configEvent);
+
+ return currRefreshRateType;
}
void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 73896d5..134dc0b 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -90,7 +90,8 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
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 @@
// 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 9e6e8c7..a935cac 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 @@
// 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 dab2003..1a0de08 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -30,9 +30,10 @@
*/
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 @@
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 @@
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 @@
}
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 @@
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 0dc99bf..53c615f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -558,14 +558,10 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
void SurfaceFlinger::setActiveConfigInternal() {
ATRACE_CALL();
- std::lock_guard<std::mutex> lock(mActiveConfigLock);
- mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId);
+ const auto display = getDefaultDisplayDeviceLocked();
+ if (!display) {
+ return;
+ }
- const auto display = getDisplayDeviceLocked(mUpcomingActiveConfig.displayToken);
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ mRefreshRateStats.setConfigMode(mUpcomingActiveConfig.configId);
+
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 @@
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 @@
// 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 @@
return;
}
- mScheduler->addResyncSample(timestamp);
+ bool periodChanged = false;
+ mScheduler->addResyncSample(timestamp, &periodChanged);
+ if (periodChanged) {
+ mVsyncModulator.onRefreshRateChangeDetected();
+ }
}
void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
@@ -1422,29 +1419,19 @@
*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 @@
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 @@
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 @@
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 @@
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 @@
mCurrentState.displays.removeItemsAt(index);
}
mPhysicalDisplayTokens.erase(info->id);
- mRefreshRateConfigs.erase(info->id);
}
processDisplayChangesLocked();
@@ -3143,6 +3123,7 @@
bool SurfaceFlinger::handlePageFlip()
{
+ ATRACE_CALL();
ALOGV("handlePageFlip");
nsecs_t latchTime = systemTime();
@@ -3168,6 +3149,7 @@
if (layer->shouldPresentNow(expectedPresentTime)) {
mLayersWithQueuedFrames.push_back(layer);
} else {
+ ATRACE_NAME("!layer->shouldPresentNow()");
layer->useEmptyDamage();
}
} else {
@@ -4007,10 +3989,8 @@
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 @@
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 @@
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 @@
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 @@
}
// 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 @@
}
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 @@
};
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 @@
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 @@
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 @@
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 @@
Mutex::Autolock _l(mStateLock);
renderArea.render([&] {
result = captureScreenImplLocked(renderArea, traverseLayers, buffer.get(),
- useIdentityTransform, forSystem, &fd);
+ useIdentityTransform, forSystem, &fd,
+ outCapturedSecureLayers);
});
}
@@ -5756,21 +5754,19 @@
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::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 7e8e836..7a7ad33 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 @@
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 @@
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 @@
// 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 @@
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 @@
// 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 @@
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 @@
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 26d2c21..e425b2a 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -73,8 +73,10 @@
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 fc1d0f8..c2bc808 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -71,7 +71,9 @@
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 830c03e..d369096 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -36,7 +36,7 @@
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 @@
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 {
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 d802177..3c39b51 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 ba854e3..d03c25d 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -1269,11 +1269,12 @@
// 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 4274254..0000000
--- 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 d4eac88..85e9ce5 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -35,7 +35,6 @@
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 ef3dfef..bebfa6c 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -125,7 +125,7 @@
}
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 92bdebd..2e705da 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -142,23 +142,5 @@
}
}
-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 9bf29a2..a13b888 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -179,7 +179,7 @@
}
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 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 249c78f..83a92c8 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -73,7 +73,6 @@
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 @@
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 @@
EXPECT_CALL(mVSyncSource, setPhaseOffset(_))
.WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable()));
- EXPECT_CALL(mVSyncSource, pauseVsyncCallback(_))
- .WillRepeatedly(Invoke(mVSyncPauseVsyncCallbackCallRecorder.getInvocable()));
-
createThread();
mConnection = createConnection(mConnectionEventCallRecorder);
@@ -166,12 +161,6 @@
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 @@
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 3fb1a6e..e51121f 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::Return;
namespace android {
+namespace scheduler {
class LayerHistoryTest : public testing::Test {
public:
@@ -22,6 +24,8 @@
protected:
std::unique_ptr<LayerHistory> mLayerHistory;
+
+ static constexpr float MAX_REFRESH_RATE = 90.f;
};
LayerHistoryTest::LayerHistoryTest() {
@@ -30,145 +34,79 @@
LayerHistoryTest::~LayerHistoryTest() {}
namespace {
-TEST_F(LayerHistoryTest, simpleInsertAndGet) {
- mLayerHistory->insert("TestLayer", 0);
+TEST_F(LayerHistoryTest, oneLayer) {
+ std::unique_ptr<LayerHistory::LayerHandle> testLayer =
+ mLayerHistory->createLayer("TestLayer", MAX_REFRESH_RATE);
- 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);
+ mLayerHistory->insert(testLayer, 0);
+ EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRate());
- // 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());
+ 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);
+TEST_F(LayerHistoryTest, explicitTimestamp) {
+ std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer =
+ mLayerHistory->createLayer("30FpsLayer", MAX_REFRESH_RATE);
- 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, 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());
-}
-
-TEST_F(LayerHistoryTest, clearTheMap) {
- mLayerHistory->insert("TestLayer0", 0);
-
- 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);
-
- mLayerHistory->incrementCounter();
- // The array currently contains 30 elements.
- for (int i = 1; i < 30; ++i) {
- mLayerHistory->insert("TestLayer0", i);
- mLayerHistory->incrementCounter();
- }
- // 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);
-}
-
-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();
+ nsecs_t startTime = systemTime();
+ for (int i = 0; i < 31; i++) {
+ mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333));
}
- // 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());
+ EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRate());
+}
- // 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);
+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);
- // 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);
+ nsecs_t startTime = systemTime();
+ for (int i = 0; i < 10; i++) {
+ mLayerHistory->insert(testLayer, 0);
+ }
+ EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRate());
+
+ startTime = systemTime();
+ for (int i = 0; i < 10; i++) {
+ mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333));
+ }
+ EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRate());
+
+ for (int i = 10; i < 30; i++) {
+ mLayerHistory->insert(test30FpsLayer, startTime + (i * 33333333));
+ }
+ EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRate());
+
+ // 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 b218ad6..8b37c22 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -49,6 +49,8 @@
ASSERT_EQ(left.name, right.name);
ASSERT_EQ(left.fps, right.fps);
}
+
+ RefreshRateConfigs mConfigs;
};
RefreshRateConfigsTest::RefreshRateConfigsTest() {
@@ -69,10 +71,10 @@
*/
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 @@
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 @@
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 @@
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 @@
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 @@
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 10f5af8..411ec61 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -42,11 +42,9 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
// 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 ec76538..b960bdf 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -33,14 +33,17 @@
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 @@
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 dcbf973..1c397d8 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 81235ba..df14e7e 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -86,7 +86,8 @@
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 @@
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 @@
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 afcda5b..12a349d 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -31,7 +31,7 @@
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());