Merge "SF: VSyncReactor change offsets at correct time"
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 08a31c1..402767a 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -15,6 +15,7 @@
cc_defaults {
name: "idlcli-defaults",
shared_libs: [
+ "android.hardware.vibrator-ndk_platform",
"android.hardware.vibrator@1.0",
"android.hardware.vibrator@1.1",
"android.hardware.vibrator@1.2",
@@ -24,7 +25,6 @@
"libhidlbase",
"liblog",
"libutils",
- "vintf-vibrator-ndk_platform",
],
cflags: [
"-DLOG_TAG=\"idlcli\"",
diff --git a/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-11-ratio.png b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-11-ratio.png
new file mode 100644
index 0000000..b6c0765
--- /dev/null
+++ b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-11-ratio.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-169-ratio.png b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-169-ratio.png
new file mode 100644
index 0000000..4e975e5
--- /dev/null
+++ b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-169-ratio.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-ratio.png b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-ratio.png
new file mode 100644
index 0000000..a331095
--- /dev/null
+++ b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-ratio.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-square-ratio.png b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-square-ratio.png
new file mode 100644
index 0000000..41e6668
--- /dev/null
+++ b/docs/images/camera2/metadata/android.scaler.cropRegion/crop-region-43-square-ratio.png
Binary files differ
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
index 6479109..a9c2311 100644
--- a/libs/adbd_auth/adbd_auth.cpp
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -178,6 +178,10 @@
this->callbacks_.key_authorized(arg, id);
this->dispatched_prompt_ = std::nullopt;
+
+ // We need to dispatch pending prompts here upon success as well,
+ // since we might have multiple queued prompts.
+ DispatchPendingPrompt();
} else if (packet[0] == 'N' && packet[1] == 'O') {
CHECK_EQ(2UL, packet.length());
// TODO: Do we want a callback if the key is denied?
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 54f383e..208d729 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -36,7 +36,10 @@
DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
ISurfaceComposer::VsyncSource vsyncSource,
ISurfaceComposer::ConfigChanged configChanged)
- : mLooper(looper), mReceiver(vsyncSource, configChanged), mWaitingForVsync(false) {
+ : mLooper(looper),
+ mReceiver(vsyncSource, configChanged),
+ mWaitingForVsync(false),
+ mConfigChangeFlag(configChanged) {
ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
}
@@ -86,6 +89,18 @@
return OK;
}
+void DisplayEventDispatcher::toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) {
+ if (mConfigChangeFlag == configChangeFlag) {
+ return;
+ }
+ status_t status = mReceiver.toggleConfigEvents(configChangeFlag);
+ if (status) {
+ ALOGW("Failed enable config events, status=%d", status);
+ return;
+ }
+ mConfigChangeFlag = configChangeFlag;
+}
+
int DisplayEventDispatcher::handleEvent(int, int events, void*) {
if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
ALOGE("Display event receiver pipe was closed or an error occurred. "
@@ -140,7 +155,7 @@
break;
case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
dispatchConfigChanged(ev.header.timestamp, ev.header.displayId,
- ev.config.configId);
+ ev.config.configId, ev.config.vsyncPeriod);
break;
default:
ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index b8faa2d..fd6aaf8 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -79,6 +79,14 @@
return NO_INIT;
}
+status_t DisplayEventReceiver::toggleConfigEvents(
+ ISurfaceComposer::ConfigChanged configChangeFlag) {
+ if (mEventConnection != nullptr) {
+ mEventConnection->toggleConfigEvents(configChangeFlag);
+ return NO_ERROR;
+ }
+ return NO_INIT;
+}
ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events,
size_t count) {
diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp
index c0e246f..dda5acf 100644
--- a/libs/gui/IDisplayEventConnection.cpp
+++ b/libs/gui/IDisplayEventConnection.cpp
@@ -26,7 +26,8 @@
STEAL_RECEIVE_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
SET_VSYNC_RATE,
REQUEST_NEXT_VSYNC,
- LAST = REQUEST_NEXT_VSYNC,
+ TOGGLE_CONFIG_EVENTS,
+ LAST = TOGGLE_CONFIG_EVENTS,
};
} // Anonymous namespace
@@ -53,6 +54,12 @@
callRemoteAsync<decltype(&IDisplayEventConnection::requestNextVsync)>(
Tag::REQUEST_NEXT_VSYNC);
}
+
+ void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) override {
+ callRemoteAsync<decltype(
+ &IDisplayEventConnection::toggleConfigEvents)>(Tag::TOGGLE_CONFIG_EVENTS,
+ configChangeFlag);
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this translation unit (see
@@ -74,6 +81,8 @@
return callLocal(data, reply, &IDisplayEventConnection::setVsyncRate);
case Tag::REQUEST_NEXT_VSYNC:
return callLocalAsync(data, reply, &IDisplayEventConnection::requestNextVsync);
+ case Tag::TOGGLE_CONFIG_EVENTS:
+ return callLocalAsync(data, reply, &IDisplayEventConnection::toggleConfigEvents);
}
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 1d887ea..f378fc5 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -484,14 +484,22 @@
mListenerCallbacks[listener].callbackIds.insert(std::make_move_iterator(
callbackIds.begin()),
std::make_move_iterator(callbackIds.end()));
- // register surface controls for this listener that is merging
- for (const auto& surfaceControl : surfaceControls) {
- registerSurfaceControlForCallback(surfaceControl);
- }
- mListenerCallbacks[listener]
- .surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()),
- std::make_move_iterator(surfaceControls.end()));
+ mListenerCallbacks[listener].surfaceControls.insert(surfaceControls.begin(),
+ surfaceControls.end());
+
+ auto& currentProcessCallbackInfo =
+ mListenerCallbacks[TransactionCompletedListener::getIInstance()];
+ currentProcessCallbackInfo.surfaceControls
+ .insert(std::make_move_iterator(surfaceControls.begin()),
+ std::make_move_iterator(surfaceControls.end()));
+
+ // register all surface controls for all callbackIds for this listener that is merging
+ for (const auto& surfaceControl : currentProcessCallbackInfo.surfaceControls) {
+ TransactionCompletedListener::getInstance()
+ ->addSurfaceControlToCallbacks(surfaceControl,
+ currentProcessCallbackInfo.callbackIds);
+ }
}
mInputWindowCommands.merge(other.mInputWindowCommands);
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index f0b7ff5..0b71801 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -31,6 +31,7 @@
status_t initialize();
void dispose();
status_t scheduleVsync();
+ void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag);
protected:
virtual ~DisplayEventDispatcher() = default;
@@ -39,12 +40,13 @@
sp<Looper> mLooper;
DisplayEventReceiver mReceiver;
bool mWaitingForVsync;
+ ISurfaceComposer::ConfigChanged mConfigChangeFlag;
virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0;
virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
bool connected) = 0;
virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
- int32_t configId) = 0;
+ int32_t configId, nsecs_t vsyncPeriod) = 0;
virtual int handleEvent(int receiveFd, int events, void* data);
bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index a558cf9..109e28b 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -73,6 +73,7 @@
struct Config {
int32_t configId;
+ nsecs_t vsyncPeriod;
};
Header header;
@@ -144,6 +145,11 @@
*/
status_t requestNextVsync();
+ /*
+ * toggleConfigEvents() toggles delivery of config change events.
+ */
+ status_t toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag);
+
private:
sp<IDisplayEventConnection> mEventConnection;
std::unique_ptr<gui::BitTube> mDataChannel;
diff --git a/libs/gui/include/gui/IDisplayEventConnection.h b/libs/gui/include/gui/IDisplayEventConnection.h
index d783f74..8b35ef6 100644
--- a/libs/gui/include/gui/IDisplayEventConnection.h
+++ b/libs/gui/include/gui/IDisplayEventConnection.h
@@ -18,7 +18,7 @@
#include <binder/IInterface.h>
#include <binder/SafeInterface.h>
-
+#include <gui/ISurfaceComposer.h>
#include <utils/Errors.h>
#include <cstdint>
@@ -51,6 +51,13 @@
* requestNextVsync() schedules the next vsync event. It has no effect if the vsync rate is > 0.
*/
virtual void requestNextVsync() = 0; // Asynchronous
+
+ /*
+ * togglesConfigEvents() configures whether or not display config changes
+ * should be propagated.
+ */
+ virtual void toggleConfigEvents(
+ ISurfaceComposer::ConfigChanged configChangeFlag) = 0; // Asynchronous
};
class BnDisplayEventConnection : public SafeBnInterface<IDisplayEventConnection> {
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 05ff93e..7e71ede 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -17,11 +17,7 @@
#define LOG_TAG "Choreographer"
//#define LOG_NDEBUG 0
-#include <cinttypes>
-#include <queue>
-#include <thread>
-
-#include <android/choreographer.h>
+#include <apex/choreographer.h>
#include <gui/DisplayEventDispatcher.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
@@ -29,6 +25,11 @@
#include <utils/Mutex.h>
#include <utils/Timers.h>
+#include <cinttypes>
+#include <optional>
+#include <queue>
+#include <thread>
+
namespace android {
static inline const char* toString(bool value) {
@@ -48,11 +49,17 @@
}
};
+struct RefreshRateCallback {
+ AChoreographer_refreshRateCallback callback;
+ void* data;
+};
class Choreographer : public DisplayEventDispatcher, public MessageHandler {
public:
void postFrameCallbackDelayed(AChoreographer_frameCallback cb,
AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay);
+ void registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data);
+ void unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb);
enum {
MSG_SCHEDULE_CALLBACKS = 0,
@@ -71,18 +78,23 @@
void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
- void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
- int32_t configId) override;
+ void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId,
+ nsecs_t vsyncPeriod) override;
void scheduleCallbacks();
// Protected by mLock
- std::priority_queue<FrameCallback> mCallbacks;
+ std::priority_queue<FrameCallback> mFrameCallbacks;
+
+ // Protected by mLock
+ std::vector<RefreshRateCallback> mRefreshRateCallbacks;
+ nsecs_t mVsyncPeriod = 0;
mutable Mutex mLock;
const sp<Looper> mLooper;
const std::thread::id mThreadId;
+ const std::optional<PhysicalDisplayId> mInternalDisplayId;
};
@@ -104,9 +116,11 @@
return gChoreographer;
}
-Choreographer::Choreographer(const sp<Looper>& looper) :
- DisplayEventDispatcher(looper), mLooper(looper), mThreadId(std::this_thread::get_id()) {
-}
+Choreographer::Choreographer(const sp<Looper>& looper)
+ : DisplayEventDispatcher(looper),
+ mLooper(looper),
+ mThreadId(std::this_thread::get_id()),
+ mInternalDisplayId(SurfaceComposerClient::getInternalDisplayId()) {}
void Choreographer::postFrameCallbackDelayed(
AChoreographer_frameCallback cb, AChoreographer_frameCallback64 cb64, void* data, nsecs_t delay) {
@@ -114,7 +128,7 @@
FrameCallback callback{cb, cb64, data, now + delay};
{
AutoMutex _l{mLock};
- mCallbacks.push(callback);
+ mFrameCallbacks.push(callback);
}
if (callback.dueTime <= now) {
if (std::this_thread::get_id() != mThreadId) {
@@ -129,10 +143,31 @@
}
}
+void Choreographer::registerRefreshRateCallback(AChoreographer_refreshRateCallback cb, void* data) {
+ {
+ AutoMutex _l{mLock};
+ mRefreshRateCallbacks.emplace_back(RefreshRateCallback{cb, data});
+ toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedDispatch);
+ }
+}
+
+void Choreographer::unregisterRefreshRateCallback(AChoreographer_refreshRateCallback cb) {
+ {
+ AutoMutex _l{mLock};
+ std::remove_if(mRefreshRateCallbacks.begin(), mRefreshRateCallbacks.end(),
+ [&](const RefreshRateCallback& callback) {
+ return cb == callback.callback;
+ });
+ if (mRefreshRateCallbacks.empty()) {
+ toggleConfigEvents(ISurfaceComposer::ConfigChanged::eConfigChangedSuppress);
+ }
+ }
+}
+
void Choreographer::scheduleCallbacks() {
AutoMutex _{mLock};
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- if (mCallbacks.top().dueTime <= now) {
+ if (mFrameCallbacks.top().dueTime <= now) {
ALOGV("choreographer %p ~ scheduling vsync", this);
scheduleVsync();
return;
@@ -147,9 +182,9 @@
{
AutoMutex _l{mLock};
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- while (!mCallbacks.empty() && mCallbacks.top().dueTime < now) {
- callbacks.push_back(mCallbacks.top());
- mCallbacks.pop();
+ while (!mFrameCallbacks.empty() && mFrameCallbacks.top().dueTime < now) {
+ callbacks.push_back(mFrameCallbacks.top());
+ mFrameCallbacks.pop();
}
}
for (const auto& cb : callbacks) {
@@ -167,11 +202,25 @@
this, displayId, toString(connected));
}
-void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId displayId,
- int32_t configId) {
- ALOGV("choreographer %p ~ received config changed event (displayId=%"
- ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", configId=%s), ignoring.",
- this, displayId, toString(configId));
+// TODO(b/74619554): The PhysicalDisplayId is ignored because currently
+// Choreographer only supports dispatching VSYNC events for the internal
+// display, so as such Choreographer does not support the notion of multiple
+// displays. When multi-display choreographer is properly supported, then
+// PhysicalDisplayId should no longer be ignored.
+void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId, int32_t,
+ nsecs_t vsyncPeriod) {
+ {
+ AutoMutex _l{mLock};
+ for (const auto& cb : mRefreshRateCallbacks) {
+ // Only perform the callback when the old refresh rate is different
+ // from the new refresh rate, so that we don't dispatch the callback
+ // on every single configuration change.
+ if (mVsyncPeriod != vsyncPeriod) {
+ cb.callback(vsyncPeriod, cb.data);
+ mVsyncPeriod = vsyncPeriod;
+ }
+ }
+ }
}
void Choreographer::handleMessage(const Message& message) {
@@ -223,3 +272,12 @@
AChoreographer_to_Choreographer(choreographer)->postFrameCallbackDelayed(
nullptr, callback, data, ms2ns(delayMillis));
}
+void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback callback,
+ void* data) {
+ AChoreographer_to_Choreographer(choreographer)->registerRefreshRateCallback(callback, data);
+}
+void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback callback) {
+ AChoreographer_to_Choreographer(choreographer)->unregisterRefreshRateCallback(callback);
+}
diff --git a/libs/nativedisplay/include/apex/choreographer.h b/libs/nativedisplay/include/apex/choreographer.h
new file mode 100644
index 0000000..352213e
--- /dev/null
+++ b/libs/nativedisplay/include/apex/choreographer.h
@@ -0,0 +1,43 @@
+/*
+ * 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 <android/choreographer.h>
+#include <inttypes.h>
+
+__BEGIN_DECLS
+
+/**
+ * Prototype of the function that is called when the display refresh rate
+ * changes. It's passed the new vsync period in nanoseconds, as well as the data
+ * pointer provided by the application that registered a callback.
+ */
+typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, void* data);
+
+/**
+ * Registers a callback to be run when the display refresh rate changes.
+ */
+void AChoreographer_registerRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback, void* data);
+
+/**
+ * Unregisters a callback to be run when the display refresh rate changes.
+ */
+void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
+ AChoreographer_refreshRateCallback);
+
+__END_DECLS
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 3b29c18..3b6a241 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -5,6 +5,8 @@
AChoreographer_postFrameCallbackDelayed; # apex # introduced=30
AChoreographer_postFrameCallback64; # apex # introduced=30
AChoreographer_postFrameCallbackDelayed64; # apex # introduced=30
+ AChoreographer_registerRefreshRateCallback; # apex # introduced=30
+ AChoreographer_unregisterRefreshRateCallback; # apex # introduced=30
local:
*;
};
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index c7eb9c3..6fd1629 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1930,6 +1930,11 @@
[&]() { return layerInfo->mutable_visible_region(); });
LayerProtoHelper::writeToProto(surfaceDamageRegion,
[&]() { return layerInfo->mutable_damage_region(); });
+
+ if (hasColorTransform()) {
+ LayerProtoHelper::writeToProto(getColorTransform(),
+ layerInfo->mutable_color_transform());
+ }
}
if (traceFlags & SurfaceTracing::TRACE_EXTRA) {
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index c94e439..b402270 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -155,5 +155,13 @@
}
}
+void LayerProtoHelper::writeToProto(const mat4 matrix, ColorTransformProto* colorTransformProto) {
+ for (int i = 0; i < mat4::ROW_SIZE; i++) {
+ for (int j = 0; j < mat4::COL_SIZE; j++) {
+ colorTransformProto->add_val(matrix[i][j]);
+ }
+ }
+}
+
} // namespace surfaceflinger
} // namespace android
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index 1754a3f..502238d 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -43,6 +43,7 @@
static void writeToProto(const InputWindowInfo& inputInfo,
const wp<Layer>& touchableRegionBounds,
std::function<InputWindowInfoProto*()> getInputWindowInfoProto);
+ static void writeToProto(const mat4 matrix, ColorTransformProto* colorTransformProto);
};
} // namespace surfaceflinger
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index ff800c3..5bdef58 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -103,10 +103,11 @@
}
DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId,
- HwcConfigIndexType configId) {
+ HwcConfigIndexType configId, nsecs_t vsyncPeriod) {
DisplayEventReceiver::Event event;
event.header = {DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, displayId, systemTime()};
event.config.configId = configId.value();
+ event.config.vsyncPeriod = vsyncPeriod;
return event;
}
@@ -116,7 +117,7 @@
ResyncCallback resyncCallback,
ISurfaceComposer::ConfigChanged configChanged)
: resyncCallback(std::move(resyncCallback)),
- configChanged(configChanged),
+ mConfigChanged(configChanged),
mEventThread(eventThread),
mChannel(gui::BitTube::DefaultSize) {}
@@ -145,6 +146,18 @@
mEventThread->requestNextVsync(this);
}
+void EventThreadConnection::toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) {
+ ATRACE_NAME("enableConfigEvents");
+ mConfigChanged = configChangeFlag;
+
+ // In principle it's possible for rapidly toggling config events to drop an
+ // event here, but it's unlikely in practice.
+ if (configChangeFlag == ISurfaceComposer::eConfigChangedDispatch) {
+ mForcedConfigChangeDispatch = true;
+ mEventThread->requestLatestConfig();
+ }
+}
+
status_t EventThreadConnection::postEvent(const DisplayEventReceiver::Event& event) {
ssize_t size = DisplayEventReceiver::sendEvents(&mChannel, &event, 1);
return size < 0 ? status_t(size) : status_t(NO_ERROR);
@@ -257,6 +270,24 @@
}
}
+void EventThread::requestLatestConfig() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ auto pendingConfigChange =
+ std::find_if(std::begin(mPendingEvents), std::end(mPendingEvents),
+ [&](const DisplayEventReceiver::Event& event) {
+ return event.header.type ==
+ DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED;
+ });
+
+ // If we didn't find a pending config change event, then push out the
+ // latest one we've ever seen.
+ if (pendingConfigChange == std::end(mPendingEvents)) {
+ mPendingEvents.push_back(mLastConfigChangeEvent);
+ }
+
+ mCondition.notify_all();
+}
+
void EventThread::onScreenReleased() {
std::lock_guard<std::mutex> lock(mMutex);
if (!mVSyncState || mVSyncState->synthetic) {
@@ -292,10 +323,11 @@
mCondition.notify_all();
}
-void EventThread::onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId) {
+void EventThread::onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId,
+ nsecs_t vsyncPeriod) {
std::lock_guard<std::mutex> lock(mMutex);
- mPendingEvents.push_back(makeConfigChanged(displayId, configId));
+ mPendingEvents.push_back(makeConfigChanged(displayId, configId, vsyncPeriod));
mCondition.notify_all();
}
@@ -325,6 +357,9 @@
mInterceptVSyncsCallback(event->header.timestamp);
}
break;
+ case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
+ mLastConfigChangeEvent = *event;
+ break;
}
}
@@ -398,8 +433,11 @@
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
return true;
- case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
- return connection->configChanged == ISurfaceComposer::eConfigChangedDispatch;
+ case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: {
+ const bool forcedDispatch = connection->mForcedConfigChangeDispatch.exchange(false);
+ return forcedDispatch ||
+ connection->mConfigChanged == ISurfaceComposer::eConfigChangedDispatch;
+ }
case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
switch (connection->vsyncRequest) {
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index a42546c..641b2a5 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -81,12 +81,19 @@
status_t stealReceiveChannel(gui::BitTube* outChannel) override;
status_t setVsyncRate(uint32_t rate) override;
void requestNextVsync() override; // asynchronous
+ void toggleConfigEvents(ISurfaceComposer::ConfigChanged configChangeFlag) override;
// Called in response to requestNextVsync.
const ResyncCallback resyncCallback;
VSyncRequest vsyncRequest = VSyncRequest::None;
- const ISurfaceComposer::ConfigChanged configChanged;
+ std::atomic<ISurfaceComposer::ConfigChanged> mConfigChanged =
+ ISurfaceComposer::ConfigChanged::eConfigChangedSuppress;
+ // Store whether we need to force dispatching a config change separately -
+ // if mConfigChanged ever changes before the config change is dispatched
+ // then we still need to propagate an initial config to the app if we
+ // haven't already.
+ std::atomic<bool> mForcedConfigChangeDispatch = false;
private:
virtual void onFirstRef();
@@ -110,7 +117,8 @@
virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0;
// called when SF changes the active config and apps needs to be notified about the change
- virtual void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId) = 0;
+ virtual void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId,
+ nsecs_t vsyncPeriod) = 0;
virtual void dump(std::string& result) const = 0;
@@ -121,6 +129,11 @@
virtual void setVsyncRate(uint32_t rate, 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) = 0;
+
+ // Dispatches the most recent configuration
+ // Usage of this method assumes that only the primary internal display
+ // supports multiple display configurations.
+ virtual void requestLatestConfig() = 0;
};
namespace impl {
@@ -138,6 +151,7 @@
status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
void requestNextVsync(const sp<EventThreadConnection>& connection) override;
+ void requestLatestConfig() override;
// called before the screen is turned off from main thread
void onScreenReleased() override;
@@ -147,7 +161,8 @@
void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override;
- void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId) override;
+ void onConfigChanged(PhysicalDisplayId displayId, HwcConfigIndexType configId,
+ nsecs_t vsyncPeriod) override;
void dump(std::string& result) const override;
@@ -182,6 +197,7 @@
std::vector<wp<EventThreadConnection>> mDisplayEventConnections GUARDED_BY(mMutex);
std::deque<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
+ DisplayEventReceiver::Event mLastConfigChangeEvent GUARDED_BY(mMutex);
// VSYNC state of connected display.
struct VSyncState {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index e845e8c..ff9cf86 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -222,9 +222,9 @@
}
void Scheduler::onConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
- HwcConfigIndexType configId) {
+ HwcConfigIndexType configId, nsecs_t vsyncPeriod) {
RETURN_IF_INVALID_HANDLE(handle);
- mConnections[handle].thread->onConfigChanged(displayId, configId);
+ mConnections[handle].thread->onConfigChanged(displayId, configId, vsyncPeriod);
}
void Scheduler::dump(ConnectionHandle handle, std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 2fa8b3f..2cdb757 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -74,7 +74,8 @@
sp<EventThreadConnection> getEventConnection(ConnectionHandle);
void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected);
- void onConfigChanged(ConnectionHandle, PhysicalDisplayId, HwcConfigIndexType configId);
+ void onConfigChanged(ConnectionHandle, PhysicalDisplayId, HwcConfigIndexType configId,
+ nsecs_t vsyncPeriod);
void onScreenAcquired(ConnectionHandle);
void onScreenReleased(ConnectionHandle);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index d02d783..8c1d168 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -953,8 +953,11 @@
ATRACE_INT("ActiveConfigFPS", refreshRate.fps);
if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
+ const nsecs_t vsyncPeriod =
+ mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId)
+ .vsyncPeriod;
mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
- mUpcomingActiveConfig.configId);
+ mUpcomingActiveConfig.configId, vsyncPeriod);
}
}
@@ -2688,6 +2691,17 @@
mRegionSamplingThread =
new RegionSamplingThread(*this, *mScheduler,
RegionSamplingThread::EnvironmentTimingTunables());
+ // Dispatch a config change request for the primary display on scheduler
+ // initialization, so that the EventThreads always contain a reference to a
+ // prior configuration.
+ //
+ // This is a bit hacky, but this avoids a back-pointer into the main SF
+ // classes from EventThread, and there should be no run-time binder cost
+ // anyway since there are no connected apps at this point.
+ const nsecs_t vsyncPeriod =
+ mRefreshRateConfigs->getRefreshRateFromConfigId(currentConfig).vsyncPeriod;
+ mScheduler->onConfigChanged(mAppConnectionHandle, primaryDisplayId.value, currentConfig,
+ vsyncPeriod);
}
void SurfaceFlinger::commitTransaction()
@@ -5577,7 +5591,10 @@
auto configId = HwcConfigIndexType(defaultConfig);
display->setActiveConfig(configId);
- mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, configId);
+ const nsecs_t vsyncPeriod =
+ mRefreshRateConfigs->getRefreshRateFromConfigId(configId).vsyncPeriod;
+ mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, configId,
+ vsyncPeriod);
return NO_ERROR;
}
@@ -5601,8 +5618,10 @@
// TODO(b/140204874): This hack triggers a notification that something has changed, so
// that listeners that care about a change in allowed configs can get the notification.
// Giving current ActiveConfig so that most other listeners would just drop the event
+ const nsecs_t vsyncPeriod =
+ mRefreshRateConfigs->getRefreshRateFromConfigId(display->getActiveConfig()).vsyncPeriod;
mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
- display->getActiveConfig());
+ display->getActiveConfig(), vsyncPeriod);
if (mRefreshRateConfigs->refreshRateSwitchingSupported()) {
auto configId = mScheduler->getPreferredConfigId();
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 9ad9b91..23df1bb 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -101,6 +101,7 @@
// length of the shadow to draw around the layer, it may be set on the
// layer or set by a parent layer.
float shadow_radius = 49;
+ ColorTransformProto color_transform = 50;
}
message PositionProto {
@@ -181,3 +182,8 @@
bool replace_touchable_region_with_crop = 14;
RectProto touchable_region_crop = 15;
}
+
+message ColorTransformProto {
+ // This will be a 4x4 matrix of float values
+ repeated float val = 1;
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 420fb29..d51b9a1 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -31,42 +31,40 @@
void SetUp() override { mDisplayToken = SurfaceComposerClient::getInternalDisplayToken(); }
sp<IBinder> mDisplayToken;
- int32_t defaultConfigId;
- float minRefreshRate;
- float maxRefreshRate;
};
-TEST_F(RefreshRateRangeTest, simpleSetAndGet) {
- status_t res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, 1, 45, 75);
- EXPECT_EQ(res, NO_ERROR);
+TEST_F(RefreshRateRangeTest, setAllConfigs) {
+ int32_t initialDefaultConfig;
+ float initialMin;
+ float initialMax;
+ status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken,
+ &initialDefaultConfig,
+ &initialMin, &initialMax);
+ ASSERT_EQ(res, NO_ERROR);
- res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfigId,
- &minRefreshRate, &maxRefreshRate);
- EXPECT_EQ(res, NO_ERROR);
- EXPECT_EQ(defaultConfigId, 1);
- EXPECT_EQ(minRefreshRate, 45);
- EXPECT_EQ(maxRefreshRate, 75);
+ Vector<DisplayInfo> configs;
+ res = SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &configs);
+ ASSERT_EQ(res, NO_ERROR);
+
+ for (size_t i = 0; i < configs.size(); i++) {
+ res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i, configs[i].fps,
+ configs[i].fps);
+ ASSERT_EQ(res, NO_ERROR);
+
+ int defaultConfig;
+ float minFps;
+ float maxFps;
+ res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
+ &minFps, &maxFps);
+ ASSERT_EQ(res, NO_ERROR);
+ ASSERT_EQ(defaultConfig, i);
+ ASSERT_EQ(minFps, configs[i].fps);
+ ASSERT_EQ(maxFps, configs[i].fps);
+ }
+
+ res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, initialDefaultConfig,
+ initialMin, initialMax);
+ ASSERT_EQ(res, NO_ERROR);
}
-TEST_F(RefreshRateRangeTest, complexSetAndGet) {
- status_t res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, 1, 45, 75);
- EXPECT_EQ(res, NO_ERROR);
-
- res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfigId,
- &minRefreshRate, &maxRefreshRate);
- EXPECT_EQ(res, NO_ERROR);
- EXPECT_EQ(defaultConfigId, 1);
- EXPECT_EQ(minRefreshRate, 45);
- EXPECT_EQ(maxRefreshRate, 75);
-
- // Second call overrides the first one.
- res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, 10, 145, 875);
- EXPECT_EQ(res, NO_ERROR);
- res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfigId,
- &minRefreshRate, &maxRefreshRate);
- EXPECT_EQ(res, NO_ERROR);
- EXPECT_EQ(defaultConfigId, 10);
- EXPECT_EQ(minRefreshRate, 145);
- EXPECT_EQ(maxRefreshRate, 875);
-}
} // namespace android
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 63ae3ae..7786638 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "*:-RefreshRateRangeTest.*:LayerCallbackTest.MergeBufferNoColor:LayerCallbackTest.MergeNoBufferColor:LayerCallbackTest.MergeOneBufferOneColor:LayerCallbackTest.Merge_SameCallback:LayerCallbackTest.Merge_DifferentClients:LayerCallbackTest.MultipleTransactions_Merge:LayerCallbackTest.MultipleTransactions_Merge_DifferentClients:LayerCallbackTest.MultipleTransactions_Merge_DifferentClients_NoStateChange:LayerCallbackTest.MultipleTransactions_Merge_DifferentClients_SameStateChange:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/3:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/3"
+ "filter": "*:-RefreshRateRangeTest.*:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadius/3:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/2:LayerTypeAndRenderTypeTransactionTests/LayerTypeAndRenderTypeTransactionTest.SetCornerRadiusChildCrop/3"
}
}
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 80bca02..61d4f47 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -85,7 +85,8 @@
void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
bool expectedConnected);
void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
- int32_t expectedConfigId);
+ int32_t expectedConfigId,
+ nsecs_t expectedVsyncPeriod);
AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
@@ -209,13 +210,15 @@
}
void EventThreadTest::expectConfigChangedEventReceivedByConnection(
- PhysicalDisplayId expectedDisplayId, int32_t expectedConfigId) {
+ PhysicalDisplayId expectedDisplayId, int32_t expectedConfigId,
+ nsecs_t expectedVsyncPeriod) {
auto args = mConnectionEventCallRecorder.waitForCall();
ASSERT_TRUE(args.has_value());
const auto& event = std::get<0>(args.value());
EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, event.header.type);
EXPECT_EQ(expectedDisplayId, event.header.displayId);
EXPECT_EQ(expectedConfigId, event.config.configId);
+ EXPECT_EQ(expectedVsyncPeriod, event.config.vsyncPeriod);
}
namespace {
@@ -450,18 +453,18 @@
}
TEST_F(EventThreadTest, postConfigChangedPrimary) {
- mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(7));
- expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7);
+ mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(7), 16666666);
+ expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7, 16666666);
}
TEST_F(EventThreadTest, postConfigChangedExternal) {
- mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, HwcConfigIndexType(5));
- expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5);
+ mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, HwcConfigIndexType(5), 16666666);
+ expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5, 16666666);
}
TEST_F(EventThreadTest, postConfigChangedPrimary64bit) {
- mThread->onConfigChanged(DISPLAY_ID_64BIT, HwcConfigIndexType(7));
- expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7);
+ mThread->onConfigChanged(DISPLAY_ID_64BIT, HwcConfigIndexType(7), 16666666);
+ expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7, 16666666);
}
TEST_F(EventThreadTest, suppressConfigChanged) {
@@ -470,8 +473,8 @@
createConnection(suppressConnectionEventRecorder,
ISurfaceComposer::eConfigChangedSuppress);
- mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(9));
- expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9);
+ mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(9), 16666666);
+ expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9, 16666666);
auto args = suppressConnectionEventRecorder.waitForCall();
ASSERT_FALSE(args.has_value());
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index f7c3804..9bda095 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -33,13 +33,14 @@
MOCK_METHOD0(onScreenReleased, void());
MOCK_METHOD0(onScreenAcquired, void());
MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
- MOCK_METHOD2(onConfigChanged, void(PhysicalDisplayId, HwcConfigIndexType));
+ MOCK_METHOD3(onConfigChanged, void(PhysicalDisplayId, HwcConfigIndexType, nsecs_t));
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
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_METHOD0(requestLatestConfig, void());
MOCK_METHOD1(pauseVsyncCallback, void(bool));
};