Merge "Respect buffer source crop in client composition."
diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c
index a2b4da2..cf3b172 100644
--- a/cmds/servicemanager/binder.c
+++ b/cmds/servicemanager/binder.c
@@ -154,9 +154,7 @@
// fallback to original method
if (result != 0) {
-#ifndef VENDORSERVICEMANAGER
android_errorWriteLog(0x534e4554, "121035042");
-#endif
result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index ca004e9..ec3fac5 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -77,11 +77,9 @@
ad.uid = uid;
ad.name = name;
-#ifndef VENDORSERVICEMANAGER
if (sid == NULL) {
android_errorWriteLog(0x534e4554, "121035042");
}
-#endif
int result = selinux_check_access(sid ? sid : lookup_sid, tctx, class, perm, (void *) &ad);
allowed = (result == 0);
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 72b7969..9af189a 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -3131,7 +3131,9 @@
for (size_t i = 0; i < newHandles.size(); i++) {
const sp<InputWindowHandle>& windowHandle = newHandles.itemAt(i);
- if (windowHandle->getInfo()->hasFocus && windowHandle->getInfo()->visible) {
+ // Set newFocusedWindowHandle to the top most focused window instead of the last one
+ if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus
+ && windowHandle->getInfo()->visible) {
newFocusedWindowHandle = windowHandle;
}
if (windowHandle == mLastHoverWindowHandle) {
@@ -3175,7 +3177,7 @@
}
if (mFocusedDisplayId == displayId) {
- onFocusChangedLocked(newFocusedWindowHandle);
+ onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle);
}
}
@@ -3293,7 +3295,7 @@
// Sanity check
sp<InputWindowHandle> newFocusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
- onFocusChangedLocked(newFocusedWindowHandle);
+ onFocusChangedLocked(oldFocusedWindowHandle, newFocusedWindowHandle);
if (newFocusedWindowHandle == nullptr) {
ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId);
@@ -3855,11 +3857,14 @@
commandEntry->connection = connection;
}
-void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& newFocus) {
- sp<IBinder> token = newFocus != nullptr ? newFocus->getToken() : nullptr;
+void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
+ const sp<InputWindowHandle>& newFocus) {
+ sp<IBinder> oldToken = oldFocus != nullptr ? oldFocus->getToken() : nullptr;
+ sp<IBinder> newToken = newFocus != nullptr ? newFocus->getToken() : nullptr;
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doNotifyFocusChangedLockedInterruptible);
- commandEntry->token = token;
+ commandEntry->oldToken = oldToken;
+ commandEntry->newToken = newToken;
}
void InputDispatcher::onANRLocked(
@@ -3921,9 +3926,10 @@
void InputDispatcher::doNotifyFocusChangedLockedInterruptible(
CommandEntry* commandEntry) {
- sp<IBinder> token = commandEntry->token;
+ sp<IBinder> oldToken = commandEntry->oldToken;
+ sp<IBinder> newToken = commandEntry->newToken;
mLock.unlock();
- mPolicy->notifyFocusChanged(token);
+ mPolicy->notifyFocusChanged(oldToken, newToken);
mLock.lock();
}
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 00390a7..49de6f3 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -217,7 +217,7 @@
/* Notifies the system that an input channel is unrecoverably broken. */
virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;
- virtual void notifyFocusChanged(const sp<IBinder>& token) = 0;
+ virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) = 0;
/* Gets the input dispatcher configuration. */
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;
@@ -628,7 +628,8 @@
uint32_t seq;
bool handled;
sp<InputChannel> inputChannel;
- sp<IBinder> token;
+ sp<IBinder> oldToken;
+ sp<IBinder> newToken;
};
// Generic queue implementation.
@@ -1158,7 +1159,8 @@
nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled);
void onDispatchCycleBrokenLocked(
nsecs_t currentTime, const sp<Connection>& connection);
- void onFocusChangedLocked(const sp<InputWindowHandle>& newFocus);
+ void onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
+ const sp<InputWindowHandle>& newFocus);
void onANRLocked(
nsecs_t currentTime, const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 704c13a..3edec40 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -63,7 +63,7 @@
virtual void notifyInputChannelBroken(const sp<IBinder>&) {
}
- virtual void notifyFocusChanged(const sp<IBinder>&) {
+ virtual void notifyFocusChanged(const sp<IBinder>&, const sp<IBinder>&) {
}
virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {
@@ -515,7 +515,7 @@
sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
ADISPLAY_ID_DEFAULT);
- // Set focus application.
+ // Set focused application.
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
// Expect one focus window exist in display.
@@ -533,6 +533,32 @@
windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
}
+TEST_F(InputDispatcherTest, SetInputWindow_FocusPriority) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top",
+ ADISPLAY_ID_DEFAULT);
+ sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
+ ADISPLAY_ID_DEFAULT);
+
+ // Set focused application.
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+ // Display has two focused windows. Add them to inputWindowsHandles in z-order (top most first)
+ windowTop->setFocus();
+ windowSecond->setFocus();
+ Vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.add(windowTop);
+ inputWindowHandles.add(windowSecond);
+
+ mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+
+ // Top focused window should receive event.
+ windowTop->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
+ windowSecond->assertNoEvents();
+}
+
TEST_F(InputDispatcherTest, SetInputWindow_InputWindowInfo) {
sp<FakeApplicationHandle> application = new FakeApplicationHandle();
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 6eda20d..e3b7f2f 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -167,6 +167,8 @@
// from GLES
const uint32_t mTextureName;
+ bool mRefreshPending{false};
+
private:
// Returns true if this layer requires filtering
bool needsFiltering() const;
@@ -184,8 +186,6 @@
// The texture used to draw the layer in GLES composition mode
mutable renderengine::Texture mTexture;
- bool mRefreshPending{false};
-
Rect getBufferSize(const State& s) const override;
};
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 5a61122..42021d1 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -352,6 +352,14 @@
// Interface implementation for BufferLayerConsumer::ContentsChangedListener
// -----------------------------------------------------------------------
+void BufferQueueLayer::fakeVsync() {
+ mRefreshPending = false;
+ bool ignored = false;
+ latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
+ usleep(16000);
+ releasePendingBuffer(systemTime());
+}
+
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
// Add this buffer from our internal queue tracker
{ // Autolock scope
@@ -390,10 +398,7 @@
// If this layer is orphaned, then we run a fake vsync pulse so that
// dequeueBuffer doesn't block indefinitely.
if (isRemovedFromCurrentState()) {
- bool ignored = false;
- latchBuffer(ignored, systemTime(), Fence::NO_FENCE);
- usleep(16000);
- releasePendingBuffer(systemTime());
+ fakeVsync();
} else {
mFlinger->signalLayerUpdate();
}
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index ae0b705..d7c3f6a 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -137,6 +137,8 @@
// thread-safe
std::atomic<int32_t> mQueuedFrames{0};
std::atomic<bool> mSidebandStreamChanged{false};
+
+ void fakeVsync();
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 1683982..bf925b2 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -67,7 +67,13 @@
}
void EventThreadConnection::requestNextVsync() {
- mEventThread->requestNextVsync(this);
+ ATRACE_NAME("requestNextVsync");
+ mEventThread->requestNextVsync(this, true);
+}
+
+void EventThreadConnection::requestNextVsyncForHWC() {
+ ATRACE_NAME("requestNextVsyncForHWC");
+ mEventThread->requestNextVsync(this, false);
}
status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
@@ -184,16 +190,17 @@
}
}
-void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection) {
- std::lock_guard<std::mutex> lock(mMutex);
- if (mResetIdleTimer) {
+void EventThread::requestNextVsync(const sp<EventThreadConnection>& connection, bool reset) {
+ if (mResetIdleTimer && reset) {
+ ATRACE_NAME("resetIdleTimer");
mResetIdleTimer();
}
-
if (mResyncWithRateLimitCallback) {
mResyncWithRateLimitCallback();
}
+ std::lock_guard<std::mutex> lock(mMutex);
+
if (connection->count < 0) {
connection->count = 0;
mCondition.notify_all();
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 66f54bd..e110488 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -68,6 +68,9 @@
status_t stealReceiveChannel(gui::BitTube* outChannel) override;
status_t setVsyncRate(uint32_t count) override;
void requestNextVsync() override; // asynchronous
+ // Requesting Vsync for HWC does not reset the idle timer, since HWC requires a refresh
+ // in order to update the configs.
+ void requestNextVsyncForHWC();
// count >= 1 : continuous event. count is the vsync rate
// count == 0 : one-shot event that has not fired
@@ -105,7 +108,9 @@
virtual status_t registerDisplayEventConnection(
const sp<EventThreadConnection>& connection) = 0;
virtual void setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) = 0;
- virtual void requestNextVsync(const sp<EventThreadConnection>& connection) = 0;
+ // 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;
};
namespace impl {
@@ -129,7 +134,8 @@
status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
void setVsyncRate(uint32_t count, const sp<EventThreadConnection>& connection) override;
- void requestNextVsync(const sp<EventThreadConnection>& connection) override;
+ void requestNextVsync(const sp<EventThreadConnection>& connection,
+ bool resetIdleTimer) override;
// called before the screen is turned off from main thread
void onScreenReleased() override;
@@ -166,6 +172,9 @@
// Implements VSyncSource::Callback
void onVSyncEvent(nsecs_t timestamp) override;
+ // Acquires mutex and requests next vsync.
+ void requestNextVsyncInternal(const sp<EventThreadConnection>& connection) EXCLUDES(mMutex);
+
// TODO(b/113612090): Once the Scheduler is complete this pointer will become obsolete.
VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
std::unique_ptr<VSyncSource> mVSyncSourceUnique GUARDED_BY(mMutex) = nullptr;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index 36403cc..66f42bb 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -148,6 +148,10 @@
mEvents->requestNextVsync();
}
+void MessageQueue::invalidateForHWC() {
+ mEvents->requestNextVsyncForHWC();
+}
+
void MessageQueue::refresh() {
mHandler->dispatchRefresh();
}
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 24a3834..0bf00b0 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -91,6 +91,7 @@
virtual void waitMessage() = 0;
virtual status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) = 0;
virtual void invalidate() = 0;
+ virtual void invalidateForHWC() = 0;
virtual void refresh() = 0;
};
@@ -134,6 +135,9 @@
// sends INVALIDATE message at next VSYNC
void invalidate() override;
+
+ // sends INVALIDATE message at next VSYNC, without resetting the idle timer in the Scheduler
+ void invalidateForHWC();
// sends REFRESH message at next VSYNC
void refresh() override;
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index c363ba5..fec53af 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -238,6 +238,16 @@
mLayerHistory.incrementCounter();
}
+void Scheduler::setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback) {
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ mExpiredTimerCallback = expiredTimerCallback;
+}
+
+void Scheduler::setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback) {
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ mResetTimerCallback = resetTimerCallback;
+}
+
void Scheduler::updateFrameSkipping(const int64_t skipCount) {
ATRACE_INT("FrameSkipCount", skipCount);
if (mSkipCount != skipCount) {
@@ -314,12 +324,12 @@
// TODO(b/113612090): This are current numbers from trial and error while running videos
// from YouTube at 24, 30, and 60 fps.
if (mean > 14 && mean < 18) {
- ATRACE_INT("FPS", 60);
+ ATRACE_INT("MediaFPS", 60);
} else if (mean > 31 && mean < 34) {
- ATRACE_INT("FPS", 30);
+ ATRACE_INT("MediaFPS", 30);
return;
} else if (mean > 39 && mean < 42) {
- ATRACE_INT("FPS", 24);
+ ATRACE_INT("MediaFPS", 24);
}
}
@@ -328,13 +338,19 @@
mIdleTimer->reset();
ATRACE_INT("ExpiredIdleTimer", 0);
}
+
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ if (mResetTimerCallback) {
+ mResetTimerCallback();
+ }
}
void Scheduler::expiredTimerCallback() {
- // TODO(b/113612090): Each time a timer expired, we should record the information into
- // a circular buffer. Once this has happened a given amount (TBD) of times, we can comfortably
- // say that the device is sitting in idle.
- ATRACE_INT("ExpiredIdleTimer", 1);
+ std::lock_guard<std::mutex> lock(mCallbackLock);
+ if (mExpiredTimerCallback) {
+ mExpiredTimerCallback();
+ ATRACE_INT("ExpiredIdleTimer", 1);
+ }
}
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 9d7dd4d..3538f31 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -36,6 +36,9 @@
class Scheduler {
public:
+ using ExpiredIdleTimerCallback = std::function<void()>;
+ using ResetIdleTimerCallback = std::function<void()>;
+
// Enum to indicate whether to start the transaction early, or at vsync time.
enum class TransactionStart { EARLY, NORMAL };
@@ -111,6 +114,10 @@
const std::string layerName);
// Increments counter in the layer history to indicate that SF has started a new frame.
void incrementFrameCounter();
+ // Callback that gets invoked once the idle timer expires.
+ void setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback);
+ // Callback that gets invoked once the idle timer is reset.
+ void setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback);
protected:
virtual std::unique_ptr<EventThread> makeEventThread(
@@ -173,6 +180,10 @@
// interval, a callback is fired. Set this variable to >0 to use this feature.
int64_t mSetIdleTimerMs = 0;
std::unique_ptr<scheduler::IdleTimer> mIdleTimer;
+
+ std::mutex mCallbackLock;
+ ExpiredIdleTimerCallback mExpiredTimerCallback GUARDED_BY(mCallbackLock);
+ ResetIdleTimerCallback mResetTimerCallback GUARDED_BY(mCallbackLock);
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index dc82b32..bd16d64 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -729,6 +729,11 @@
ALOGE("Run StartPropertySetThread failed!");
}
+ if (mUseScheduler) {
+ mScheduler->setExpiredIdleTimerCallback([this]() { setRefreshRateTo(60.f /* fps */); });
+ mScheduler->setResetIdleTimerCallback([this]() { setRefreshRateTo(90.f /* fps */); });
+ }
+
ALOGV("Done initializing");
}
@@ -934,14 +939,45 @@
return display->getActiveConfig();
}
-void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& display, int mode) {
+status_t SurfaceFlinger::setActiveConfigAsync(const sp<IBinder>& displayToken, int mode) {
+ ATRACE_NAME("setActiveConfigAsync");
+ postMessageAsync(new LambdaMessage([=] { setActiveConfigInternal(displayToken, mode); }));
+ return NO_ERROR;
+}
+
+status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
+ ATRACE_NAME("setActiveConfigSync");
+ postMessageSync(new LambdaMessage([&] { setActiveConfigInternal(displayToken, mode); }));
+ return NO_ERROR;
+}
+
+void SurfaceFlinger::setActiveConfigInternal(const sp<IBinder>& displayToken, int mode) {
+ Vector<DisplayInfo> configs;
+ getDisplayConfigs(displayToken, &configs);
+ if (mode < 0 || mode >= static_cast<int>(configs.size())) {
+ ALOGE("Attempt to set active config %d for display with %zu configs", mode, configs.size());
+ return;
+ }
+
+ const auto display = getDisplayDevice(displayToken);
+ if (!display) {
+ ALOGE("Attempt to set active config %d for invalid display token %p", mode,
+ displayToken.get());
+ return;
+ }
if (display->isVirtual()) {
- ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
+ ALOGW("Attempt to set active config %d for virtual display", mode);
+ return;
+ }
+ int currentDisplayPowerMode = display->getPowerMode();
+ if (currentDisplayPowerMode != HWC_POWER_MODE_NORMAL) {
+ // Don't change active config when in AoD.
return;
}
int currentMode = display->getActiveConfig();
if (mode == currentMode) {
+ // Don't update config if we are already running in the desired mode.
return;
}
@@ -950,29 +986,9 @@
display->setActiveConfig(mode);
getHwComposer().setActiveConfig(*displayId, mode);
-}
-status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
- postMessageSync(new LambdaMessage([&] {
- Vector<DisplayInfo> configs;
- getDisplayConfigs(displayToken, &configs);
- if (mode < 0 || mode >= static_cast<int>(configs.size())) {
- ALOGE("Attempt to set active config %d for display with %zu configs", mode,
- configs.size());
- return;
- }
- const auto display = getDisplayDevice(displayToken);
- if (!display) {
- ALOGE("Attempt to set active config %d for invalid display token %p", mode,
- displayToken.get());
- } else if (display->isVirtual()) {
- ALOGW("Attempt to set active config %d for virtual display", mode);
- } else {
- setActiveConfigInternal(display, mode);
- }
- }));
-
- return NO_ERROR;
+ ATRACE_INT("ActiveConfigMode", mode);
+ resyncToHardwareVsync(true);
}
status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
@@ -1382,6 +1398,49 @@
*compositorTiming = getBE().mCompositorTiming;
}
+void SurfaceFlinger::setRefreshRateTo(float newFps) {
+ const auto displayId = getInternalDisplayId();
+ if (!displayId || mBootStage != BootStage::FINISHED) {
+ return;
+ }
+ // TODO(b/113612090): There should be a message queue flush here. Because this esentially
+ // runs on a mainthread, we cannot call postMessageSync. This can be resolved in a better
+ // manner, once the setActiveConfig is synchronous, and is executed at a known time in a
+ // refresh cycle.
+
+ // Don't do any updating if the current fps is the same as the new one.
+ const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
+ const nsecs_t currentVsyncPeriod = activeConfig->getVsyncPeriod();
+ if (currentVsyncPeriod == 0) {
+ return;
+ }
+ // TODO(b/113612090): Consider having an enum value for correct refresh rates, rather than
+ // floating numbers.
+ const float currentFps = 1e9 / currentVsyncPeriod;
+ if (std::abs(currentFps - newFps) <= 1) {
+ return;
+ }
+
+ auto configs = getHwComposer().getConfigs(*displayId);
+ for (int i = 0; i < configs.size(); i++) {
+ const nsecs_t vsyncPeriod = configs.at(i)->getVsyncPeriod();
+ if (vsyncPeriod == 0) {
+ continue;
+ }
+ const float fps = 1e9 / vsyncPeriod;
+ // TODO(b/113612090): There should be a better way at determining which config
+ // has the right refresh rate.
+ if (std::abs(fps - newFps) <= 1) {
+ const auto display = getBuiltInDisplay(HWC_DISPLAY_PRIMARY);
+ if (!display) return;
+ // This is posted in async function to avoid deadlock when getDisplayDevice
+ // requires mStateLock.
+ setActiveConfigAsync(display, i);
+ ATRACE_INT("FPS", newFps);
+ }
+ }
+}
+
void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
HWC2::Connection connection) {
ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId,
@@ -1413,7 +1472,7 @@
if (sequenceId != getBE().mComposerSequenceId) {
return;
}
- repaintEverything();
+ repaintEverythingForHWC();
}
void SurfaceFlinger::setVsyncEnabled(EventThread::DisplayType /*displayType*/, bool enabled) {
@@ -5177,6 +5236,11 @@
signalTransaction();
}
+void SurfaceFlinger::repaintEverythingForHWC() {
+ mRepaintEverything = true;
+ mEventQueue->invalidateForHWC();
+}
+
// A simple RAII class to disconnect from an ANativeWindow* when it goes out of scope
class WindowDisconnector {
public:
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ac730ab..eb7127e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -311,6 +311,9 @@
// force full composition on all displays
void repaintEverything();
+ // force full composition on all displays without resetting the scheduler idle timer.
+ void repaintEverythingForHWC();
+
surfaceflinger::Factory& getFactory() { return mFactory; }
// The CompositionEngine encapsulates all composition related interfaces and actions.
@@ -502,8 +505,10 @@
// called on the main thread in response to initializeDisplays()
void onInitializeDisplays();
+ // setActiveConfigInternal() posted on a main thread for async execution
+ status_t setActiveConfigAsync(const sp<IBinder>& displayToken, int mode);
// called on the main thread in response to setActiveConfig()
- void setActiveConfigInternal(const sp<DisplayDevice>& display, int mode);
+ void setActiveConfigInternal(const sp<IBinder>& displayToken, int mode);
// called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& display, int mode);
@@ -763,6 +768,9 @@
void resyncWithRateLimit();
void getCompositorTiming(CompositorTiming* compositorTiming);
private:
+ // Sets the refresh rate to newFps by switching active configs, if they are available for
+ // the desired refresh rate.
+ void setRefreshRateTo(float newFps);
/* ------------------------------------------------------------------------
* Debugging & dumpsys
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index acbed51..2d26bb3 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -200,7 +200,7 @@
TEST_F(EventThreadTest, requestNextVsyncPostsASingleVSyncEventToTheConnection) {
// Signal that we want the next vsync event to be posted to the connection
- mThread->requestNextVsync(mConnection);
+ mThread->requestNextVsync(mConnection, false);
// EventThread should immediately request a resync.
EXPECT_TRUE(mResyncCallRecorder.waitForCall().has_value());
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index bb6e183..48d45fa 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -37,7 +37,7 @@
MOCK_METHOD1(registerDisplayEventConnection,
status_t(const sp<android::EventThreadConnection> &));
MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
- MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
+ MOCK_METHOD2(requestNextVsync, void(const sp<android::EventThreadConnection> &, bool));
};
} // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index dc8d606..8c113e2 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -35,6 +35,7 @@
MOCK_METHOD0(waitMessage, void());
MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t));
MOCK_METHOD0(invalidate, void());
+ MOCK_METHOD0(invalidateForHWC, void());
MOCK_METHOD0(refresh, void());
};