Merge "SurfaceFlinger: get present time from SF and not from Scheduler" into qt-r1-dev
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 7ac0eb7..a4b00f8 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -890,6 +890,7 @@
setTagsProperty(0);
clearAppProperties();
pokeBinderServices();
+ pokeHalServices();
if (g_tracePdx) {
ServiceUtility::PokeServices();
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 5427ff8..afa3d33 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -2086,8 +2086,8 @@
const char* Parcel::readCString() const
{
- const size_t avail = mDataSize-mDataPos;
- if (avail > 0) {
+ if (mDataPos < mDataSize) {
+ const size_t avail = mDataSize-mDataPos;
const char* str = reinterpret_cast<const char*>(mData+mDataPos);
// is the string's trailing NUL within the parcel's valid bounds?
const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail));
@@ -2835,10 +2835,16 @@
}
release_object(proc, *flat, this, &mOpenAshmemSize);
}
- binder_size_t* objects =
- (binder_size_t*)realloc(mObjects, objectsSize*sizeof(binder_size_t));
- if (objects) {
- mObjects = objects;
+
+ if (objectsSize == 0) {
+ free(mObjects);
+ mObjects = nullptr;
+ } else {
+ binder_size_t* objects =
+ (binder_size_t*)realloc(mObjects, objectsSize*sizeof(binder_size_t));
+ if (objects) {
+ mObjects = objects;
+ }
}
mObjectsSize = objectsSize;
mNextObjectHint = 0;
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index 8b33a56..0ad99ce 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -102,13 +102,23 @@
// Skip over fat response headers. Not used (or propagated) in native code.
if (mException == EX_HAS_REPLY_HEADER) {
// Note that the header size includes the 4 byte size field.
- const int32_t header_start = parcel.dataPosition();
+ const size_t header_start = parcel.dataPosition();
+ // Get available size before reading more
+ const size_t header_avail = parcel.dataAvail();
+
int32_t header_size;
status = parcel.readInt32(&header_size);
if (status != OK) {
setFromStatusT(status);
return status;
}
+
+ if (header_size < 0 || static_cast<size_t>(header_size) > header_avail) {
+ android_errorWriteLog(0x534e4554, "132650049");
+ setFromStatusT(UNKNOWN_ERROR);
+ return UNKNOWN_ERROR;
+ }
+
parcel.setDataPosition(header_start + header_size);
// And fat response headers are currently only used when there are no
// exceptions, so act like there was no error.
@@ -135,19 +145,36 @@
setFromStatusT(status);
return status;
}
+ if (remote_stack_trace_header_size < 0 ||
+ static_cast<size_t>(remote_stack_trace_header_size) > parcel.dataAvail()) {
+
+ android_errorWriteLog(0x534e4554, "132650049");
+ setFromStatusT(UNKNOWN_ERROR);
+ return UNKNOWN_ERROR;
+ }
parcel.setDataPosition(parcel.dataPosition() + remote_stack_trace_header_size);
if (mException == EX_SERVICE_SPECIFIC) {
status = parcel.readInt32(&mErrorCode);
} else if (mException == EX_PARCELABLE) {
// Skip over the blob of Parcelable data
- const int32_t header_start = parcel.dataPosition();
+ const size_t header_start = parcel.dataPosition();
+ // Get available size before reading more
+ const size_t header_avail = parcel.dataAvail();
+
int32_t header_size;
status = parcel.readInt32(&header_size);
if (status != OK) {
setFromStatusT(status);
return status;
}
+
+ if (header_size < 0 || static_cast<size_t>(header_size) > header_avail) {
+ android_errorWriteLog(0x534e4554, "132650049");
+ setFromStatusT(UNKNOWN_ERROR);
+ return UNKNOWN_ERROR;
+ }
+
parcel.setDataPosition(header_start + header_size);
}
if (status != OK) {
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 407f77d..1c5fa52 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -534,60 +534,73 @@
mDebugLayersGLES = layers;
}
+// Return true if all the required libraries from vndk and sphal namespace are
+// linked to the Game Driver namespace correctly.
+bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace) {
+ const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK);
+ if (llndkLibraries.empty()) {
+ return false;
+ }
+ if (!android_link_namespaces(mDriverNamespace, nullptr, llndkLibraries.c_str())) {
+ ALOGE("Failed to link default namespace[%s]", dlerror());
+ return false;
+ }
+
+ const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP);
+ if (vndkspLibraries.empty()) {
+ return false;
+ }
+ if (!android_link_namespaces(mDriverNamespace, vndkNamespace, vndkspLibraries.c_str())) {
+ ALOGE("Failed to link vndk namespace[%s]", dlerror());
+ return false;
+ }
+
+ if (mSphalLibraries.empty()) {
+ return true;
+ }
+
+ // Make additional libraries in sphal to be accessible
+ auto sphalNamespace = android_get_exported_namespace("sphal");
+ if (!sphalNamespace) {
+ ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace",
+ mSphalLibraries.c_str());
+ return false;
+ }
+
+ if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) {
+ ALOGE("Failed to link sphal namespace[%s]", dlerror());
+ return false;
+ }
+
+ return true;
+}
+
android_namespace_t* GraphicsEnv::getDriverNamespace() {
- static std::once_flag once;
- std::call_once(once, [this]() {
- if (mDriverPath.empty()) return;
+ std::lock_guard<std::mutex> lock(mNamespaceMutex);
- auto vndkNamespace = android_get_exported_namespace("vndk");
- if (!vndkNamespace) return;
+ if (mDriverNamespace) {
+ return mDriverNamespace;
+ }
- mDriverNamespace = android_create_namespace("gfx driver",
- mDriverPath.c_str(), // ld_library_path
- mDriverPath.c_str(), // default_library_path
- ANDROID_NAMESPACE_TYPE_ISOLATED,
- nullptr, // permitted_when_isolated_path
- nullptr);
+ if (mDriverPath.empty()) {
+ return nullptr;
+ }
- const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK);
- if (llndkLibraries.empty()) {
- mDriverNamespace = nullptr;
- return;
- }
- if (!android_link_namespaces(mDriverNamespace, nullptr, llndkLibraries.c_str())) {
- ALOGE("Failed to link default namespace[%s]", dlerror());
- mDriverNamespace = nullptr;
- return;
- }
+ auto vndkNamespace = android_get_exported_namespace("vndk");
+ if (!vndkNamespace) {
+ return nullptr;
+ }
- const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP);
- if (vndkspLibraries.empty()) {
- mDriverNamespace = nullptr;
- return;
- }
- if (!android_link_namespaces(mDriverNamespace, vndkNamespace, vndkspLibraries.c_str())) {
- ALOGE("Failed to link vndk namespace[%s]", dlerror());
- mDriverNamespace = nullptr;
- return;
- }
+ mDriverNamespace = android_create_namespace("gfx driver",
+ mDriverPath.c_str(), // ld_library_path
+ mDriverPath.c_str(), // default_library_path
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr, // permitted_when_isolated_path
+ nullptr);
- if (mSphalLibraries.empty()) return;
-
- // Make additional libraries in sphal to be accessible
- auto sphalNamespace = android_get_exported_namespace("sphal");
- if (!sphalNamespace) {
- ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace",
- mSphalLibraries.c_str());
- mDriverNamespace = nullptr;
- return;
- }
-
- if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) {
- ALOGE("Failed to link sphal namespace[%s]", dlerror());
- mDriverNamespace = nullptr;
- return;
- }
- });
+ if (!linkDriverNamespaceLocked(vndkNamespace)) {
+ mDriverNamespace = nullptr;
+ }
return mDriverNamespace;
}
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 7d62750..f5d19db 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -129,6 +129,7 @@
void* loadLibrary(std::string name);
bool checkAngleRules(void* so);
void updateUseAngle();
+ bool linkDriverNamespaceLocked(android_namespace_t* vndkNamespace);
GraphicsEnv() = default;
std::string mDriverPath;
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index f5cf1c4..b8faa2d 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -32,10 +32,11 @@
// ---------------------------------------------------------------------------
-DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
+DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource,
+ ISurfaceComposer::ConfigChanged configChanged) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
if (sf != nullptr) {
- mEventConnection = sf->createDisplayEventConnection(vsyncSource);
+ mEventConnection = sf->createDisplayEventConnection(vsyncSource, configChanged);
if (mEventConnection != nullptr) {
mDataChannel = std::make_unique<gui::BitTube>();
mEventConnection->stealReceiveChannel(mDataChannel.get());
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 6c9d81a..e487792 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -278,8 +278,8 @@
return NO_ERROR;
}
- virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource)
- {
+ virtual sp<IDisplayEventConnection> createDisplayEventConnection(VsyncSource vsyncSource,
+ ConfigChanged configChanged) {
Parcel data, reply;
sp<IDisplayEventConnection> result;
int err = data.writeInterfaceToken(
@@ -288,6 +288,7 @@
return result;
}
data.writeInt32(static_cast<int32_t>(vsyncSource));
+ data.writeInt32(static_cast<int32_t>(configChanged));
err = remote()->transact(
BnSurfaceComposer::CREATE_DISPLAY_EVENT_CONNECTION,
data, &reply);
@@ -1155,8 +1156,11 @@
}
case CREATE_DISPLAY_EVENT_CONNECTION: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- sp<IDisplayEventConnection> connection(createDisplayEventConnection(
- static_cast<ISurfaceComposer::VsyncSource>(data.readInt32())));
+ auto vsyncSource = static_cast<ISurfaceComposer::VsyncSource>(data.readInt32());
+ auto configChanged = static_cast<ISurfaceComposer::ConfigChanged>(data.readInt32());
+
+ sp<IDisplayEventConnection> connection(
+ createDisplayEventConnection(vsyncSource, configChanged));
reply->writeStrongBinder(IInterface::asBinder(connection));
return NO_ERROR;
}
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 22de751..a558cf9 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -88,10 +88,13 @@
* DisplayEventReceiver creates and registers an event connection with
* SurfaceFlinger. VSync events are disabled by default. Call setVSyncRate
* or requestNextVsync to receive them.
+ * To receive Config Changed events specify this in the constructor.
* Other events start being delivered immediately.
*/
explicit DisplayEventReceiver(
- ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp);
+ ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp,
+ ISurfaceComposer::ConfigChanged configChanged =
+ ISurfaceComposer::eConfigChangedSuppress);
/*
* ~DisplayEventReceiver severs the connection with SurfaceFlinger, new events
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index e2f7736..c84910b 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -90,6 +90,8 @@
eVsyncSourceSurfaceFlinger = 1
};
+ enum ConfigChanged { eConfigChangedSuppress = 0, eConfigChangedDispatch = 1 };
+
/*
* Create a connection with SurfaceFlinger.
*/
@@ -97,7 +99,8 @@
/* return an IDisplayEventConnection */
virtual sp<IDisplayEventConnection> createDisplayEventConnection(
- VsyncSource vsyncSource = eVsyncSourceApp) = 0;
+ VsyncSource vsyncSource = eVsyncSourceApp,
+ ConfigChanged configChanged = eConfigChangedSuppress) = 0;
/* create a virtual display
* requires ACCESS_SURFACE_FLINGER permission.
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 960cf18..d370858 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -548,8 +548,8 @@
}
sp<ISurfaceComposerClient> createConnection() override { return nullptr; }
- sp<IDisplayEventConnection> createDisplayEventConnection(ISurfaceComposer::VsyncSource)
- override {
+ sp<IDisplayEventConnection> createDisplayEventConnection(
+ ISurfaceComposer::VsyncSource, ISurfaceComposer::ConfigChanged) override {
return nullptr;
}
sp<IBinder> createDisplay(const String8& /*displayName*/,
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index c0bace8..abc7a72 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -208,6 +208,10 @@
defaults: ["gles_libs_defaults"],
srcs: ["GLES2/gl2.cpp"],
cflags: ["-DLOG_TAG=\"libGLESv2\""],
+
+ // Bug: http://b/133874658 Disable native_coverage as we investigate a
+ // crash in surfaceflinger on coverage-enabled cuttlefish builds.
+ native_coverage: false,
}
//##############################################################################
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index d5c46c6..038a432 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -84,6 +84,11 @@
return android_load_sphal_library(path, mode);
}
+static int do_android_unload_sphal_library(void* dso) {
+ ATRACE_CALL();
+ return android_unload_sphal_library(dso);
+}
+
Loader::driver_t::driver_t(void* gles)
{
dso[0] = gles;
@@ -180,11 +185,81 @@
"ro.board.platform",
};
+static bool should_unload_system_driver(egl_connection_t* cnx) {
+ // Return false if the system driver has been unloaded once.
+ if (cnx->systemDriverUnloaded) {
+ return false;
+ }
+
+ // Return true if Angle namespace is set.
+ android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
+ if (ns) {
+ return true;
+ }
+
+#ifndef __ANDROID_VNDK__
+ // Return true if updated driver namespace is set.
+ ns = android::GraphicsEnv::getInstance().getDriverNamespace();
+ if (ns) {
+ return true;
+ }
+#endif
+
+ return false;
+}
+
+static void uninit_api(char const* const* api, __eglMustCastToProperFunctionPointerType* curr) {
+ while (*api) {
+ *curr++ = nullptr;
+ api++;
+ }
+}
+
+void Loader::unload_system_driver(egl_connection_t* cnx) {
+ ATRACE_CALL();
+
+ uninit_api(gl_names,
+ (__eglMustCastToProperFunctionPointerType*)&cnx
+ ->hooks[egl_connection_t::GLESv2_INDEX]
+ ->gl);
+ uninit_api(gl_names,
+ (__eglMustCastToProperFunctionPointerType*)&cnx
+ ->hooks[egl_connection_t::GLESv1_INDEX]
+ ->gl);
+ uninit_api(egl_names, (__eglMustCastToProperFunctionPointerType*)&cnx->egl);
+
+ if (cnx->dso) {
+ ALOGD("Unload system gl driver.");
+ driver_t* hnd = (driver_t*)cnx->dso;
+ if (hnd->dso[2]) {
+ do_android_unload_sphal_library(hnd->dso[2]);
+ }
+ if (hnd->dso[1]) {
+ do_android_unload_sphal_library(hnd->dso[1]);
+ }
+ if (hnd->dso[0]) {
+ do_android_unload_sphal_library(hnd->dso[0]);
+ }
+ cnx->dso = nullptr;
+ }
+
+ cnx->systemDriverUnloaded = true;
+}
+
void* Loader::open(egl_connection_t* cnx)
{
ATRACE_CALL();
const nsecs_t openTime = systemTime();
+ if (should_unload_system_driver(cnx)) {
+ unload_system_driver(cnx);
+ }
+
+ // If a driver has been loaded, return the driver directly.
+ if (cnx->dso) {
+ return cnx->dso;
+ }
+
setEmulatorGlesValue();
// Check if we should use ANGLE early, so loading each driver doesn't require repeated queries.
@@ -244,9 +319,15 @@
"couldn't find an OpenGL ES implementation, make sure you set %s or %s",
HAL_SUBNAME_KEY_PROPERTIES[0], HAL_SUBNAME_KEY_PROPERTIES[1]);
- cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so");
- cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
- cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
+ if (!cnx->libEgl) {
+ cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so");
+ }
+ if (!cnx->libGles1) {
+ cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
+ }
+ if (!cnx->libGles2) {
+ cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
+ }
if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) {
android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL,
@@ -584,6 +665,7 @@
return nullptr;
}
+ ALOGD("Load updated gl driver.");
android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL_UPDATED);
driver_t* hnd = nullptr;
void* dso = load_updated_driver("GLES", ns);
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 0292d02..6f31ab4 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -58,6 +58,7 @@
driver_t* attempt_to_load_angle(egl_connection_t* cnx);
driver_t* attempt_to_load_updated_driver(egl_connection_t* cnx);
driver_t* attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix, const bool exact);
+ void unload_system_driver(egl_connection_t* cnx);
void initialize_api(void* dso, egl_connection_t* cnx, uint32_t mask);
static __attribute__((noinline))
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 8870d5f..25b1009 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -187,13 +187,9 @@
// dynamically load our EGL implementation
egl_connection_t* cnx = &gEGLImpl;
- if (cnx->dso == nullptr) {
- cnx->hooks[egl_connection_t::GLESv1_INDEX] =
- &gHooks[egl_connection_t::GLESv1_INDEX];
- cnx->hooks[egl_connection_t::GLESv2_INDEX] =
- &gHooks[egl_connection_t::GLESv2_INDEX];
- cnx->dso = loader.open(cnx);
- }
+ cnx->hooks[egl_connection_t::GLESv1_INDEX] = &gHooks[egl_connection_t::GLESv1_INDEX];
+ cnx->hooks[egl_connection_t::GLESv2_INDEX] = &gHooks[egl_connection_t::GLESv2_INDEX];
+ cnx->dso = loader.open(cnx);
// Check to see if any layers are enabled and route functions through them
if (cnx->dso) {
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 8841a3b..67d69b4 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -217,7 +217,7 @@
Loader& loader(Loader::getInstance());
egl_connection_t* const cnx = &gEGLImpl;
- if (cnx->dso && disp.dpy == EGL_NO_DISPLAY) {
+ if (cnx->dso) {
EGLDisplay dpy = EGL_NO_DISPLAY;
if (cnx->useAngle) {
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 9e112cc..7bb9b59 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -44,7 +44,11 @@
GLESv2_INDEX = 1
};
- inline egl_connection_t() : dso(nullptr) {
+ inline egl_connection_t() : dso(nullptr),
+ libEgl(nullptr),
+ libGles1(nullptr),
+ libGles2(nullptr),
+ systemDriverUnloaded(false) {
char const* const* entries = platform_names;
EGLFuncPointer* curr = reinterpret_cast<EGLFuncPointer*>(&platform);
@@ -76,6 +80,7 @@
void* libGles1;
void* libGles2;
+ bool systemDriverUnloaded;
bool shouldUseAngle; // Should we attempt to load ANGLE
bool angleDecided; // Have we tried to load ANGLE
bool useAngle; // Was ANGLE successfully loaded
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index ef1a224..6a7f279 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -82,7 +82,7 @@
// Check if the "deep touch" feature is on.
static bool deepPressEnabled() {
std::string flag_value = server_configurable_flags::GetServerConfigurableFlag(
- INPUT_NATIVE_BOOT, DEEP_PRESS_ENABLED, "true");
+ INPUT_NATIVE_BOOT, DEEP_PRESS_ENABLED, "false");
std::transform(flag_value.begin(), flag_value.end(), flag_value.begin(), ::tolower);
if (flag_value == "1" || flag_value == "true") {
ALOGI("Deep press feature enabled.");
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 31a2dab..c2ff4c9 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -2172,9 +2172,8 @@
return;
}
- int32_t displayId = inputWindowHandle->getInfo()->displayId;
sp<InputWindowHandle> focusedWindowHandle =
- getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+ getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId);
bool hasFocusChanged = !focusedWindowHandle || focusedWindowHandle->getToken() != newToken;
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index fcd4f29..717f317 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -45,7 +45,9 @@
ANDROID_SINGLETON_STATIC_INSTANCE(SensorDevice)
-static status_t StatusFromResult(Result result) {
+namespace {
+
+status_t statusFromResult(Result result) {
switch (result) {
case Result::OK:
return OK;
@@ -71,6 +73,8 @@
INTERNAL_WAKE = 1 << 16,
};
+} // anonymous namespace
+
void SensorsHalDeathReceivier::serviceDied(
uint64_t /* cookie */,
const wp<::android::hidl::base::V1_0::IBase>& /* service */) {
@@ -105,7 +109,7 @@
initializeSensorList();
mIsDirectReportSupported =
- (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);
+ (checkReturnAndGetStatus(mSensors->unregisterDirectChannel(-1)) != INVALID_OPERATION);
}
void SensorDevice::initializeSensorList() {
@@ -122,7 +126,7 @@
convertToSensor(list[i], &sensor);
// Sanity check and clamp power if it is 0 (or close)
if (sensor.power < minPowerMa) {
- ALOGE("Reported power %f not deemed sane, clamping to %f",
+ ALOGI("Reported power %f not deemed sane, clamping to %f",
sensor.power, minPowerMa);
sensor.power = minPowerMa;
}
@@ -217,10 +221,10 @@
mWakeLockQueue != nullptr && mEventQueueFlag != nullptr &&
mWakeLockQueueFlag != nullptr);
- status_t status = StatusFromResult(checkReturn(mSensors->initialize(
+ status_t status = checkReturnAndGetStatus(mSensors->initialize(
*mEventQueue->getDesc(),
*mWakeLockQueue->getDesc(),
- new SensorsCallback())));
+ new SensorsCallback()));
if (status != NO_ERROR) {
connectionStatus = HalConnectionStatus::FAILED_TO_CONNECT;
@@ -270,6 +274,8 @@
bool didChange = false;
if (oldSensorList.size() != newSensorList.size()) {
+ ALOGI("Sensor list size changed from %zu to %zu", oldSensorList.size(),
+ newSensorList.size());
didChange = true;
}
@@ -281,6 +287,7 @@
if (prevSensor.handle == newSensor.handle) {
found = true;
if (!sensorIsEquivalent(prevSensor, newSensor)) {
+ ALOGI("Sensor %s not equivalent to previous version", newSensor.name);
didChange = true;
}
}
@@ -289,6 +296,7 @@
if (!found) {
// Could not find the new sensor in the old list of sensors, the lists must
// have changed.
+ ALOGI("Sensor %s (handle %d) did not exist before", newSensor.name, newSensor.handle);
didChange = true;
}
}
@@ -423,7 +431,7 @@
convertToSensorEvents(events, dynamicSensorsAdded, buffer);
err = (ssize_t)events.size();
} else {
- err = StatusFromResult(result);
+ err = statusFromResult(result);
}
});
@@ -621,7 +629,7 @@
if (actuateHardware) {
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle,
enabled);
- err = StatusFromResult(checkReturn(mSensors->activate(handle, enabled)));
+ err = checkReturnAndGetStatus(mSensors->activate(handle, enabled));
ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle,
strerror(-err));
@@ -694,9 +702,8 @@
if (prevBestBatchParams != info.bestBatchParams) {
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH 0x%08x %" PRId64 " %" PRId64, handle,
info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch);
- err = StatusFromResult(
- checkReturn(mSensors->batch(
- handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch)));
+ err = checkReturnAndGetStatus(mSensors->batch(
+ handle, info.bestBatchParams.mTSample, info.bestBatchParams.mTBatch));
if (err != NO_ERROR) {
ALOGE("sensor batch failed %p 0x%08x %" PRId64 " %" PRId64 " err=%s",
mSensors.get(), handle, info.bestBatchParams.mTSample,
@@ -720,7 +727,7 @@
if (mSensors == nullptr) return NO_INIT;
if (isClientDisabled(ident)) return INVALID_OPERATION;
ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle);
- return StatusFromResult(checkReturn(mSensors->flush(handle)));
+ return checkReturnAndGetStatus(mSensors->flush(handle));
}
bool SensorDevice::isClientDisabled(void* ident) {
@@ -753,16 +760,14 @@
const int sensor_handle = mActivationCount.keyAt(i);
ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ",
sensor_handle);
- status_t err = StatusFromResult(
- checkReturn(mSensors->batch(
- sensor_handle,
- info.bestBatchParams.mTSample,
- info.bestBatchParams.mTBatch)));
+ status_t err = checkReturnAndGetStatus(mSensors->batch(
+ sensor_handle,
+ info.bestBatchParams.mTSample,
+ info.bestBatchParams.mTBatch));
ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err));
if (err == NO_ERROR) {
- err = StatusFromResult(
- checkReturn(mSensors->activate(sensor_handle, 1 /* enabled */)));
+ err = checkReturnAndGetStatus(mSensors->activate(sensor_handle, 1 /* enabled */));
ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err));
}
@@ -810,14 +815,13 @@
Event ev;
convertFromSensorEvent(*injected_sensor_event, &ev);
- return StatusFromResult(checkReturn(mSensors->injectSensorData(ev)));
+ return checkReturnAndGetStatus(mSensors->injectSensorData(ev));
}
status_t SensorDevice::setMode(uint32_t mode) {
if (mSensors == nullptr) return NO_INIT;
- return StatusFromResult(
- checkReturn(mSensors->setOperationMode(
- static_cast<hardware::sensors::V1_0::OperationMode>(mode))));
+ return checkReturnAndGetStatus(mSensors->setOperationMode(
+ static_cast<hardware::sensors::V1_0::OperationMode>(mode)));
}
int32_t SensorDevice::registerDirectChannel(const sensors_direct_mem_t* memory) {
@@ -855,7 +859,7 @@
if (result == Result::OK) {
ret = channelHandle;
} else {
- ret = StatusFromResult(result);
+ ret = statusFromResult(result);
}
}));
return ret;
@@ -894,12 +898,12 @@
checkReturn(mSensors->configDirectReport(sensorHandle, channelHandle, rate,
[&ret, rate] (auto result, auto token) {
if (rate == RateLevel::STOP) {
- ret = StatusFromResult(result);
+ ret = statusFromResult(result);
} else {
if (result == Result::OK) {
ret = token;
} else {
- ret = StatusFromResult(result);
+ ret = statusFromResult(result);
}
}
}));
@@ -1008,7 +1012,7 @@
}
void SensorDevice::handleHidlDeath(const std::string & detail) {
- if (!SensorDevice::getInstance().mSensors->supportsMessageQueues()) {
+ if (!mSensors->supportsMessageQueues()) {
// restart is the only option at present.
LOG_ALWAYS_FATAL("Abort due to ISensors hidl service failure, detail: %s.", detail.c_str());
} else {
@@ -1016,5 +1020,10 @@
}
}
+status_t SensorDevice::checkReturnAndGetStatus(const Return<Result>& ret) {
+ checkReturn(ret);
+ return (!ret.isOk()) ? DEAD_OBJECT : statusFromResult(ret);
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index e8685c2..d2c6994 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -211,14 +211,14 @@
status_t batchLocked(void* ident, int handle, int flags, int64_t samplingPeriodNs,
int64_t maxBatchReportLatencyNs);
- static void handleHidlDeath(const std::string &detail);
+ void handleHidlDeath(const std::string &detail);
template<typename T>
- static Return<T> checkReturn(Return<T> &&ret) {
+ void checkReturn(const Return<T>& ret) {
if (!ret.isOk()) {
handleHidlDeath(ret.description());
}
- return std::move(ret);
}
+ status_t checkReturnAndGetStatus(const Return<Result>& ret);
//TODO(b/67425500): remove waiter after bug is resolved.
sp<SensorDeviceUtils::HidlServiceRegistrationWaiter> mRestartWaiter;
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index a2b6ab6..9d72399 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -545,6 +545,12 @@
if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled &&
presentTimeIsCurrent) {
point->setFrameAvailable();
+ sp<Layer> requestedSyncLayer = point->getRequestedSyncLayer();
+ if (requestedSyncLayer) {
+ // Need to update the transaction flag to ensure the layer's pending transaction
+ // gets applied.
+ requestedSyncLayer->setTransactionFlags(eTransactionNeeded);
+ }
}
}
}
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 203bd72..2abc1a7 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -50,12 +50,6 @@
mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
mCurrentState.dataspace = ui::Dataspace::V0_SRGB;
}
-BufferStateLayer::~BufferStateLayer() {
- if (mActiveBuffer != nullptr) {
- auto& engine(mFlinger->getRenderEngine());
- engine.unbindExternalTextureBuffer(mActiveBuffer->getId());
- }
-}
// -----------------------------------------------------------------------
// Interface implementation for Layer
@@ -571,11 +565,6 @@
return BAD_VALUE;
}
- if (mActiveBuffer != nullptr) {
- // todo: get this to work with BufferStateLayerCache
- auto& engine(mFlinger->getRenderEngine());
- engine.unbindExternalTextureBuffer(mActiveBuffer->getId());
- }
mActiveBuffer = s.buffer;
mActiveBufferFence = s.acquireFence;
auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
@@ -621,6 +610,10 @@
}
}
+void BufferStateLayer::bufferErased(const client_cache_t& clientCacheId) {
+ mFlinger->getRenderEngine().unbindExternalTextureBuffer(clientCacheId.id);
+}
+
void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) {
std::lock_guard lock(mMutex);
if (!clientCacheId.isValid()) {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 4e2bc45..db8ae0d 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -34,7 +34,6 @@
class BufferStateLayer : public BufferLayer {
public:
explicit BufferStateLayer(const LayerCreationArgs&);
- ~BufferStateLayer() override;
// -----------------------------------------------------------------------
// Interface implementation for Layer
@@ -103,6 +102,9 @@
bool fenceHasSignaled() const override;
bool framePresentTimeIsCurrent() const override;
+ // Inherit from ClientCache::ErasedRecipient
+ void bufferErased(const client_cache_t& clientCacheId) override;
+
private:
nsecs_t getDesiredPresentTime() override;
std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index cc5a5b5..7f47a2e 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -24,6 +24,7 @@
#include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
#include <gui/BufferQueue.h>
+#include <hidl/HidlTransportSupport.h>
#include <hidl/HidlTransportUtils.h>
namespace android {
@@ -229,6 +230,7 @@
void Composer::registerCallback(const sp<IComposerCallback>& callback)
{
+ android::hardware::setMinSchedulerPolicy(callback, SCHED_FIFO, 2);
auto ret = mClient->registerCallback(callback);
if (!ret.isOk()) {
ALOGE("failed to register IComposerCallback");
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 379b004..898f3bc 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -144,28 +144,47 @@
*/
void Layer::onLayerDisplayed(const sp<Fence>& /*releaseFence*/) {}
-void Layer::onRemovedFromCurrentState() {
- mRemovedFromCurrentState = true;
+void Layer::removeRemoteSyncPoints() {
+ for (auto& point : mRemoteSyncPoints) {
+ point->setTransactionApplied();
+ }
+ mRemoteSyncPoints.clear();
- // the layer is removed from SF mCurrentState to mLayersPendingRemoval
- if (mCurrentState.zOrderRelativeOf != nullptr) {
- sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
- if (strongRelative != nullptr) {
- strongRelative->removeZOrderRelative(this);
- mFlinger->setTransactionFlags(eTraversalNeeded);
+ {
+ Mutex::Autolock pendingStateLock(mPendingStateMutex);
+ for (State pendingState : mPendingStates) {
+ pendingState.barrierLayer_legacy = nullptr;
}
+ }
+}
+
+void Layer::removeRelativeZ(const std::vector<Layer*>& layersInTree) {
+ if (mCurrentState.zOrderRelativeOf == nullptr) {
+ return;
+ }
+
+ sp<Layer> strongRelative = mCurrentState.zOrderRelativeOf.promote();
+ if (strongRelative == nullptr) {
+ setZOrderRelativeOf(nullptr);
+ return;
+ }
+
+ if (!std::binary_search(layersInTree.begin(), layersInTree.end(), strongRelative.get())) {
+ strongRelative->removeZOrderRelative(this);
+ mFlinger->setTransactionFlags(eTraversalNeeded);
setZOrderRelativeOf(nullptr);
}
+}
+
+void Layer::removeFromCurrentState() {
+ mRemovedFromCurrentState = true;
// Since we are no longer reachable from CurrentState SurfaceFlinger
// will no longer invoke doTransaction for us, and so we will
// never finish applying transactions. We signal the sync point
// now so that another layer will not become indefinitely
// blocked.
- for (auto& point: mRemoteSyncPoints) {
- point->setTransactionApplied();
- }
- mRemoteSyncPoints.clear();
+ removeRemoteSyncPoints();
{
Mutex::Autolock syncLock(mLocalSyncPointMutex);
@@ -175,13 +194,18 @@
mLocalSyncPoints.clear();
}
- for (const auto& child : mCurrentChildren) {
- child->onRemovedFromCurrentState();
- }
-
mFlinger->markLayerPendingRemovalLocked(this);
}
+void Layer::onRemovedFromCurrentState() {
+ auto layersInTree = getLayersInTree(LayerVector::StateSet::Current);
+ std::sort(layersInTree.begin(), layersInTree.end());
+ for (const auto& layer : layersInTree) {
+ layer->removeFromCurrentState();
+ layer->removeRelativeZ(layersInTree);
+ }
+}
+
void Layer::addToCurrentState() {
mRemovedFromCurrentState = false;
@@ -667,7 +691,7 @@
// to be applied as per normal (no synchronization).
mCurrentState.barrierLayer_legacy = nullptr;
} else {
- auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber_legacy);
+ auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber_legacy, this);
if (barrierLayer->addSyncPoint(syncPoint)) {
mRemoteSyncPoints.push_back(std::move(syncPoint));
} else {
@@ -1510,6 +1534,7 @@
if (client != nullptr && parentClient != client) {
child->mLayerDetached = true;
child->detachChildren();
+ child->removeRemoteSyncPoints();
}
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3712b2a..6db6beb 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -17,8 +17,6 @@
#ifndef ANDROID_LAYER_H
#define ANDROID_LAYER_H
-#include <sys/types.h>
-
#include <compositionengine/LayerFE.h>
#include <gui/BufferQueue.h>
#include <gui/ISurfaceComposerClient.h>
@@ -28,6 +26,7 @@
#include <math/vec4.h>
#include <renderengine/Mesh.h>
#include <renderengine/Texture.h>
+#include <sys/types.h>
#include <ui/FloatRect.h>
#include <ui/FrameStats.h>
#include <ui/GraphicBuffer.h>
@@ -44,16 +43,16 @@
#include <vector>
#include "Client.h"
+#include "ClientCache.h"
+#include "DisplayHardware/ComposerHal.h"
+#include "DisplayHardware/HWComposer.h"
#include "FrameTracker.h"
#include "LayerVector.h"
#include "MonitoredProducer.h"
+#include "RenderArea.h"
#include "SurfaceFlinger.h"
#include "TransactionCompletedThread.h"
-#include "DisplayHardware/ComposerHal.h"
-#include "DisplayHardware/HWComposer.h"
-#include "RenderArea.h"
-
using namespace android::surfaceflinger;
namespace android {
@@ -94,7 +93,7 @@
LayerMetadata metadata;
};
-class Layer : public virtual compositionengine::LayerFE {
+class Layer : public virtual compositionengine::LayerFE, public ClientCache::ErasedRecipient {
static std::atomic<int32_t> sSequence;
public:
@@ -571,6 +570,17 @@
virtual bool isBufferLatched() const { return false; }
/*
+ * Remove relative z for the layer if its relative parent is not part of the
+ * provided layer tree.
+ */
+ void removeRelativeZ(const std::vector<Layer*>& layersInTree);
+
+ /*
+ * Remove from current state and mark for removal.
+ */
+ void removeFromCurrentState();
+
+ /*
* called with the state lock from a binder thread when the layer is
* removed from the current list to the pending removal list
*/
@@ -690,6 +700,9 @@
compositionengine::OutputLayer* findOutputLayerForDisplay(
const sp<const DisplayDevice>& display) const;
+ // Inherit from ClientCache::ErasedRecipient
+ void bufferErased(const client_cache_t& /*clientCacheId*/) override {}
+
protected:
// constant
sp<SurfaceFlinger> mFlinger;
@@ -733,8 +746,11 @@
class SyncPoint {
public:
- explicit SyncPoint(uint64_t frameNumber)
- : mFrameNumber(frameNumber), mFrameIsAvailable(false), mTransactionIsApplied(false) {}
+ explicit SyncPoint(uint64_t frameNumber, wp<Layer> requestedSyncLayer)
+ : mFrameNumber(frameNumber),
+ mFrameIsAvailable(false),
+ mTransactionIsApplied(false),
+ mRequestedSyncLayer(requestedSyncLayer) {}
uint64_t getFrameNumber() const { return mFrameNumber; }
@@ -746,10 +762,13 @@
void setTransactionApplied() { mTransactionIsApplied = true; }
+ sp<Layer> getRequestedSyncLayer() { return mRequestedSyncLayer.promote(); }
+
private:
const uint64_t mFrameNumber;
std::atomic<bool> mFrameIsAvailable;
std::atomic<bool> mTransactionIsApplied;
+ wp<Layer> mRequestedSyncLayer;
};
// SyncPoints which will be signaled when the correct frame is at the head
@@ -928,6 +947,8 @@
void setZOrderRelativeOf(const wp<Layer>& relativeOf);
bool mGetHandleCalled = false;
+
+ void removeRemoteSyncPoints();
};
} // namespace android
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 3684260..66906e9 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -26,6 +26,8 @@
#include <utils/Trace.h>
#include <string>
+#include <compositionengine/Display.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include "DisplayDevice.h"
#include "Layer.h"
#include "SurfaceFlinger.h"
@@ -264,7 +266,26 @@
}
} // anonymous namespace
-float sampleArea(const uint32_t* data, int32_t stride, const Rect& area) {
+float sampleArea(const uint32_t* data, int32_t width, int32_t height, int32_t stride,
+ uint32_t orientation, const Rect& sample_area) {
+ if (!sample_area.isValid() || (sample_area.getWidth() > width) ||
+ (sample_area.getHeight() > height)) {
+ ALOGE("invalid sampling region requested");
+ return 0.0f;
+ }
+
+ // (b/133849373) ROT_90 screencap images produced upside down
+ auto area = sample_area;
+ if (orientation & ui::Transform::ROT_90) {
+ area.top = height - area.top;
+ area.bottom = height - area.bottom;
+ std::swap(area.top, area.bottom);
+
+ area.left = width - area.left;
+ area.right = width - area.right;
+ std::swap(area.left, area.right);
+ }
+
std::array<int32_t, 256> brightnessBuckets = {};
const int32_t majoritySampleNum = area.getWidth() * area.getHeight() / 2;
@@ -293,18 +314,21 @@
std::vector<float> RegionSamplingThread::sampleBuffer(
const sp<GraphicBuffer>& buffer, const Point& leftTop,
- const std::vector<RegionSamplingThread::Descriptor>& descriptors) {
+ const std::vector<RegionSamplingThread::Descriptor>& descriptors, uint32_t orientation) {
void* data_raw = nullptr;
buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, &data_raw);
std::shared_ptr<uint32_t> data(reinterpret_cast<uint32_t*>(data_raw),
[&buffer](auto) { buffer->unlock(); });
if (!data) return {};
+ const int32_t width = buffer->getWidth();
+ const int32_t height = buffer->getHeight();
const int32_t stride = buffer->getStride();
std::vector<float> lumas(descriptors.size());
std::transform(descriptors.begin(), descriptors.end(), lumas.begin(),
[&](auto const& descriptor) {
- return sampleArea(data.get(), stride, descriptor.area - leftTop);
+ return sampleArea(data.get(), width, height, stride, orientation,
+ descriptor.area - leftTop);
});
return lumas;
}
@@ -317,6 +341,11 @@
return;
}
+ const auto device = mFlinger.getDefaultDisplayDevice();
+ const auto display = device->getCompositionDisplay();
+ const auto state = display->getState();
+ const auto orientation = static_cast<ui::Transform::orientation_flags>(state.orientation);
+
std::vector<RegionSamplingThread::Descriptor> descriptors;
Region sampleRegion;
for (const auto& [listener, descriptor] : mDescriptors) {
@@ -326,10 +355,28 @@
const Rect sampledArea = sampleRegion.bounds();
- sp<const DisplayDevice> device = mFlinger.getDefaultDisplayDevice();
- DisplayRenderArea renderArea(device, sampledArea, sampledArea.getWidth(),
- sampledArea.getHeight(), ui::Dataspace::V0_SRGB,
- ui::Transform::ROT_0);
+ auto dx = 0;
+ auto dy = 0;
+ switch (orientation) {
+ case ui::Transform::ROT_90:
+ dx = device->getWidth();
+ break;
+ case ui::Transform::ROT_180:
+ dx = device->getWidth();
+ dy = device->getHeight();
+ break;
+ case ui::Transform::ROT_270:
+ dy = device->getHeight();
+ break;
+ default:
+ break;
+ }
+
+ ui::Transform t(orientation);
+ auto screencapRegion = t.transform(sampleRegion);
+ screencapRegion = screencapRegion.translate(dx, dy);
+ DisplayRenderArea renderArea(device, screencapRegion.bounds(), sampledArea.getWidth(),
+ sampledArea.getHeight(), ui::Dataspace::V0_SRGB, orientation);
std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
@@ -395,8 +442,8 @@
}
ALOGV("Sampling %zu descriptors", activeDescriptors.size());
- std::vector<float> lumas = sampleBuffer(buffer, sampledArea.leftTop(), activeDescriptors);
-
+ std::vector<float> lumas =
+ sampleBuffer(buffer, sampledArea.leftTop(), activeDescriptors, orientation);
if (lumas.size() != activeDescriptors.size()) {
ALOGW("collected %zu median luma values for %zu descriptors", lumas.size(),
activeDescriptors.size());
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index 08134e6..3c6fcf3 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -37,7 +37,8 @@
class SurfaceFlinger;
struct SamplingOffsetCallback;
-float sampleArea(const uint32_t* data, int32_t stride, const Rect& area);
+float sampleArea(const uint32_t* data, int32_t width, int32_t height, int32_t stride,
+ uint32_t orientation, const Rect& area);
class RegionSamplingThread : public IBinder::DeathRecipient {
public:
@@ -94,7 +95,7 @@
};
std::vector<float> sampleBuffer(
const sp<GraphicBuffer>& buffer, const Point& leftTop,
- const std::vector<RegionSamplingThread::Descriptor>& descriptors);
+ const std::vector<RegionSamplingThread::Descriptor>& descriptors, uint32_t orientation);
void doSample();
void binderDied(const wp<IBinder>& who) override;
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 95ff9d0..e59d459 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -92,7 +92,6 @@
mPeriod = period;
if (!mModelLocked && referenceTimeChanged) {
for (auto& eventListener : mEventListeners) {
- eventListener.mHasFired = false;
eventListener.mLastEventTime =
mReferenceTime - mPeriod + mPhase + eventListener.mPhase;
}
@@ -123,13 +122,6 @@
void unlockModel() {
Mutex::Autolock lock(mMutex);
- if (mModelLocked) {
- for (auto& eventListener : mEventListeners) {
- if (eventListener.mLastEventTime > mReferenceTime) {
- eventListener.mHasFired = true;
- }
- }
- }
mModelLocked = false;
ATRACE_INT("DispSync:ModelLocked", mModelLocked);
}
@@ -259,10 +251,6 @@
listener.mLastCallbackTime = lastCallbackTime;
}
- if (!mModelLocked && listener.mLastEventTime > mReferenceTime) {
- listener.mHasFired = true;
- }
-
mEventListeners.push_back(listener);
mCond.signal();
@@ -305,7 +293,14 @@
} else if (diff < -mPeriod / 2) {
diff += mPeriod;
}
+
+ if (phase < 0 && oldPhase > 0) {
+ diff += mPeriod;
+ } else if (phase > 0 && oldPhase < 0) {
+ diff -= mPeriod;
+ }
eventListener.mLastEventTime -= diff;
+ eventListener.mLastCallbackTime -= diff;
mCond.signal();
return NO_ERROR;
}
@@ -320,7 +315,6 @@
nsecs_t mLastEventTime;
nsecs_t mLastCallbackTime;
DispSync::Callback* mCallback;
- bool mHasFired = false;
};
struct CallbackInvocation {
@@ -368,12 +362,7 @@
eventListener.mName);
continue;
}
- if (eventListener.mHasFired && !mModelLocked) {
- eventListener.mLastEventTime = t;
- ALOGV("[%s] [%s] Skipping event due to already firing", mName,
- eventListener.mName);
- continue;
- }
+
CallbackInvocation ci;
ci.mCallback = eventListener.mCallback;
ci.mEventTime = t;
@@ -382,7 +371,6 @@
callbackInvocations.push_back(ci);
eventListener.mLastEventTime = t;
eventListener.mLastCallbackTime = now;
- eventListener.mHasFired = true;
}
}
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 00948ae..265b8aa 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -27,14 +27,16 @@
namespace android {
-DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync,
+DispSyncSource::DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset,
+ nsecs_t offsetThresholdForNextVsync, bool traceVsync,
const char* name)
: mName(name),
mTraceVsync(traceVsync),
mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)),
mDispSync(dispSync),
- mPhaseOffset(phaseOffset) {}
+ mPhaseOffset(phaseOffset),
+ mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {}
void DispSyncSource::setVSyncEnabled(bool enable) {
std::lock_guard lock(mVsyncMutex);
@@ -64,15 +66,15 @@
void DispSyncSource::setPhaseOffset(nsecs_t phaseOffset) {
std::lock_guard lock(mVsyncMutex);
-
- // Normalize phaseOffset to [0, period)
- auto period = mDispSync->getPeriod();
- phaseOffset %= period;
- if (phaseOffset < 0) {
- // If we're here, then phaseOffset is in (-period, 0). After this
- // operation, it will be in (0, period)
- phaseOffset += period;
+ const nsecs_t period = mDispSync->getPeriod();
+ // Check if offset should be handled as negative
+ if (phaseOffset >= mOffsetThresholdForNextVsync) {
+ phaseOffset -= period;
}
+
+ // Normalize phaseOffset to [-period, period)
+ const int numPeriods = phaseOffset / period;
+ phaseOffset -= numPeriods * period;
mPhaseOffset = phaseOffset;
// If we're not enabled, we don't need to mess with the listeners
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 4759699..b6785c5 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -25,7 +25,8 @@
class DispSyncSource final : public VSyncSource, private DispSync::Callback {
public:
- DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, bool traceVsync, const char* name);
+ DispSyncSource(DispSync* dispSync, nsecs_t phaseOffset, nsecs_t offsetThresholdForNextVsync,
+ bool traceVsync, const char* name);
~DispSyncSource() override = default;
@@ -53,6 +54,7 @@
std::mutex mVsyncMutex;
nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex);
+ const nsecs_t mOffsetThresholdForNextVsync;
bool mEnabled GUARDED_BY(mVsyncMutex) = false;
};
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 05bad4d..9d1f777 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -76,6 +76,10 @@
return StringPrintf("VSync{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
", count=%u}",
event.header.displayId, event.vsync.count);
+ case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
+ return StringPrintf("ConfigChanged{displayId=%" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
+ ", configId=%u}",
+ event.header.displayId, event.config.configId);
default:
return "Event{}";
}
@@ -107,8 +111,10 @@
} // namespace
EventThreadConnection::EventThreadConnection(EventThread* eventThread,
- ResyncCallback resyncCallback)
+ ResyncCallback resyncCallback,
+ ISurfaceComposer::ConfigChanged configChanged)
: resyncCallback(std::move(resyncCallback)),
+ configChanged(configChanged),
mEventThread(eventThread),
mChannel(gui::BitTube::DefaultSize) {}
@@ -203,8 +209,10 @@
mVSyncSource->setPhaseOffset(phaseOffset);
}
-sp<EventThreadConnection> EventThread::createEventConnection(ResyncCallback resyncCallback) const {
- return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback));
+sp<EventThreadConnection> EventThread::createEventConnection(
+ ResyncCallback resyncCallback, ISurfaceComposer::ConfigChanged configChanged) const {
+ return new EventThreadConnection(const_cast<EventThread*>(this), std::move(resyncCallback),
+ configChanged);
}
status_t EventThread::registerDisplayEventConnection(const sp<EventThreadConnection>& connection) {
@@ -398,9 +406,11 @@
const sp<EventThreadConnection>& connection) const {
switch (event.header.type) {
case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
- case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
return true;
+ case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
+ return connection->configChanged == ISurfaceComposer::eConfigChangedDispatch;
+
case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
switch (connection->vsyncRequest) {
case VSyncRequest::None:
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 61530c6..dd23b88 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -69,7 +69,8 @@
class EventThreadConnection : public BnDisplayEventConnection {
public:
- EventThreadConnection(EventThread*, ResyncCallback);
+ EventThreadConnection(EventThread*, ResyncCallback,
+ ISurfaceComposer::ConfigChanged configChanged);
virtual ~EventThreadConnection();
virtual status_t postEvent(const DisplayEventReceiver::Event& event);
@@ -82,6 +83,7 @@
const ResyncCallback resyncCallback;
VSyncRequest vsyncRequest = VSyncRequest::None;
+ const ISurfaceComposer::ConfigChanged configChanged;
private:
virtual void onFirstRef();
@@ -93,7 +95,8 @@
public:
virtual ~EventThread();
- virtual sp<EventThreadConnection> createEventConnection(ResyncCallback) const = 0;
+ virtual sp<EventThreadConnection> createEventConnection(
+ ResyncCallback, ISurfaceComposer::ConfigChanged configChanged) const = 0;
// called before the screen is turned off from main thread
virtual void onScreenReleased() = 0;
@@ -128,7 +131,8 @@
EventThread(std::unique_ptr<VSyncSource>, InterceptVSyncsCallback, const char* threadName);
~EventThread();
- sp<EventThreadConnection> createEventConnection(ResyncCallback) const override;
+ sp<EventThreadConnection> createEventConnection(
+ ResyncCallback, ISurfaceComposer::ConfigChanged configChanged) const override;
status_t registerDisplayEventConnection(const sp<EventThreadConnection>& connection) override;
void setVsyncRate(uint32_t rate, const sp<EventThreadConnection>& connection) override;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 1db43a3..e762af3 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -173,5 +173,18 @@
}
}
+void LayerHistory::clearHistory() {
+ std::lock_guard lock(mLock);
+
+ auto it = mActiveLayerInfos.begin();
+ while (it != mActiveLayerInfos.end()) {
+ auto id = it->first;
+ auto layerInfo = it->second;
+ layerInfo->clearHistory();
+ mInactiveLayerInfos.insert({id, layerInfo});
+ it = mActiveLayerInfos.erase(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 adc5ce5..2569b46 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -64,6 +64,9 @@
// layers. See go/content-fps-detection-in-scheduler for more information.
std::pair<float, bool> getDesiredRefreshRateAndHDR();
+ // Clears all layer history.
+ void clearHistory();
+
// Removes the handle and the object from the map.
void destroyLayer(const int64_t id);
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index baf900d..fcb307f 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -96,7 +96,8 @@
}
mEventThread = eventThread;
- mEvents = eventThread->createEventConnection(std::move(resyncCallback));
+ mEvents = eventThread->createEventConnection(std::move(resyncCallback),
+ ISurfaceComposer::eConfigChangedSuppress);
mEvents->stealReceiveChannel(&mEventTube);
mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
this);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 1d899df..bb24f73 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -119,17 +119,19 @@
}
sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
- const char* connectionName, int64_t phaseOffsetNs, ResyncCallback resyncCallback,
+ const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
+ ResyncCallback resyncCallback,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
const int64_t id = sNextId++;
ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
std::unique_ptr<EventThread> eventThread =
makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
- std::move(interceptCallback));
+ offsetThresholdForNextVsync, std::move(interceptCallback));
auto eventThreadConnection =
- createConnectionInternal(eventThread.get(), std::move(resyncCallback));
+ createConnectionInternal(eventThread.get(), std::move(resyncCallback),
+ ISurfaceComposer::eConfigChangedSuppress);
mConnections.emplace(id,
std::make_unique<Connection>(new ConnectionHandle(id),
eventThreadConnection,
@@ -138,24 +140,28 @@
}
std::unique_ptr<EventThread> Scheduler::makeEventThread(
- const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
+ nsecs_t offsetThresholdForNextVsync,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
std::unique_ptr<VSyncSource> eventThreadSource =
- std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName);
+ std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, offsetThresholdForNextVsync,
+ true, connectionName);
return std::make_unique<impl::EventThread>(std::move(eventThreadSource),
std::move(interceptCallback), connectionName);
}
-sp<EventThreadConnection> Scheduler::createConnectionInternal(EventThread* eventThread,
- ResyncCallback&& resyncCallback) {
- return eventThread->createEventConnection(std::move(resyncCallback));
+sp<EventThreadConnection> Scheduler::createConnectionInternal(
+ EventThread* eventThread, ResyncCallback&& resyncCallback,
+ ISurfaceComposer::ConfigChanged configChanged) {
+ return eventThread->createEventConnection(std::move(resyncCallback), configChanged);
}
sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
- const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback) {
+ const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback,
+ ISurfaceComposer::ConfigChanged configChanged) {
RETURN_VALUE_IF_INVALID(nullptr);
return createConnectionInternal(mConnections[handle->id]->thread.get(),
- std::move(resyncCallback));
+ std::move(resyncCallback), configChanged);
}
EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
@@ -404,6 +410,10 @@
if (mSupportKernelTimer) {
resetIdleTimer();
}
+
+ // Touch event will boost the refresh rate to performance.
+ // Clear Layer History to get fresh FPS detection
+ mLayerHistory.clearHistory();
}
void Scheduler::resetTimerCallback() {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index a32bd41..eaad37c 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -96,12 +96,13 @@
virtual ~Scheduler();
/** Creates an EventThread connection. */
- sp<ConnectionHandle> createConnection(const char* connectionName, int64_t phaseOffsetNs,
- ResyncCallback,
+ sp<ConnectionHandle> createConnection(const char* connectionName, nsecs_t phaseOffsetNs,
+ nsecs_t offsetThresholdForNextVsync, ResyncCallback,
impl::EventThread::InterceptVSyncsCallback);
- sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle,
- ResyncCallback);
+ sp<IDisplayEventConnection> createDisplayEventConnection(
+ const sp<ConnectionHandle>& handle, ResyncCallback,
+ ISurfaceComposer::ConfigChanged configChanged);
// Getter methods.
EventThread* getEventThread(const sp<ConnectionHandle>& handle);
@@ -184,7 +185,8 @@
protected:
virtual std::unique_ptr<EventThread> makeEventThread(
- const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+ const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
+ nsecs_t offsetThresholdForNextVsync,
impl::EventThread::InterceptVSyncsCallback interceptCallback);
private:
@@ -197,7 +199,8 @@
enum class TouchState { INACTIVE, ACTIVE };
// Creates a connection on the given EventThread and forwards the given callbacks.
- sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&);
+ sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&,
+ ISurfaceComposer::ConfigChanged);
nsecs_t calculateAverage() const;
void updateFrameSkipping(const int64_t skipCount);
@@ -297,7 +300,7 @@
const scheduler::RefreshRateConfigs& mRefreshRateConfigs;
// Global config to force HDR content to work on DEFAULT refreshRate
- static constexpr bool mForceHDRContentToDefaultRefreshRate = true;
+ static constexpr bool mForceHDRContentToDefaultRefreshRate = false;
};
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index 41c3a3a..73a1fb9 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -56,10 +56,12 @@
// appEarly: Like sfEarly, but for the app-vsync
// appEarlyGl: Like sfEarlyGl, but for the app-vsync.
// appLate: The regular app vsync phase offset.
- void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late) {
+ void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
+ nsecs_t thresholdForNextVsync) {
mEarlyOffsets = early;
mEarlyGlOffsets = earlyGl;
mLateOffsets = late;
+ mThresholdForNextVsync = thresholdForNextVsync;
if (mSfConnectionHandle && late.sf != mOffsets.load().sf) {
mScheduler->setPhaseOffset(mSfConnectionHandle, late.sf);
@@ -192,6 +194,7 @@
Offsets mLateOffsets;
Offsets mEarlyOffsets;
Offsets mEarlyGlOffsets;
+ nsecs_t mThresholdForNextVsync;
EventThread* mSfEventThread = nullptr;
EventThread* mAppEventThread = nullptr;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cd4f69a..a96305e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -377,7 +377,8 @@
mLumaSampling = atoi(value);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late);
+ mVsyncModulator.setPhaseOffsets(early, gl, late,
+ mPhaseOffsets->getOffsetThresholdForNextVsync());
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
@@ -616,13 +617,16 @@
mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
mAppConnectionHandle =
- mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
+ mScheduler->createConnection("app", mVsyncModulator.getOffsets().app,
+ mPhaseOffsets->getOffsetThresholdForNextVsync(),
resyncCallback,
impl::EventThread::InterceptVSyncsCallback());
- mSfConnectionHandle = mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(),
- resyncCallback, [this](nsecs_t timestamp) {
- mInterceptor->saveVSyncEvent(timestamp);
- });
+ mSfConnectionHandle =
+ mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf,
+ mPhaseOffsets->getOffsetThresholdForNextVsync(),
+ resyncCallback, [this](nsecs_t timestamp) {
+ mInterceptor->saveVSyncEvent(timestamp);
+ });
mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
@@ -940,7 +944,8 @@
mVsyncModulator.onRefreshRateChangeInitiated();
mPhaseOffsets->setRefreshRateType(info.type);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late);
+ mVsyncModulator.setPhaseOffsets(early, gl, late,
+ mPhaseOffsets->getOffsetThresholdForNextVsync());
}
mDesiredActiveConfigChanged = true;
ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
@@ -974,7 +979,8 @@
mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late);
+ mVsyncModulator.setPhaseOffsets(early, gl, late,
+ mPhaseOffsets->getOffsetThresholdForNextVsync());
ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
@@ -992,7 +998,8 @@
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late);
+ mVsyncModulator.setPhaseOffsets(early, gl, late,
+ mPhaseOffsets->getOffsetThresholdForNextVsync());
}
bool SurfaceFlinger::performSetActiveConfig() {
@@ -1372,7 +1379,7 @@
// ----------------------------------------------------------------------------
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
- ISurfaceComposer::VsyncSource vsyncSource) {
+ ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) {
auto resyncCallback = mScheduler->makeResyncCallback([this] {
Mutex::Autolock lock(mStateLock);
return getVsyncPeriod();
@@ -1381,7 +1388,8 @@
const auto& handle =
vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle;
- return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback));
+ return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback),
+ configChanged);
}
// ----------------------------------------------------------------------------
@@ -1530,10 +1538,23 @@
void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) {
ATRACE_CALL();
- Mutex::Autolock lock(mStateLock);
+
+ // Enable / Disable HWVsync from the main thread to avoid race conditions with
+ // display power state.
+ postMessageAsync(new LambdaMessage(
+ [=]() NO_THREAD_SAFETY_ANALYSIS { setPrimaryVsyncEnabledInternal(enabled); }));
+}
+
+void SurfaceFlinger::setPrimaryVsyncEnabledInternal(bool enabled) {
+ ATRACE_CALL();
+
+ mHWCVsyncPendingState = enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable;
+
if (const auto displayId = getInternalDisplayIdLocked()) {
- getHwComposer().setVsyncEnabled(*displayId,
- enabled ? HWC2::Vsync::Enable : HWC2::Vsync::Disable);
+ sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
+ if (display && display->isPoweredOn()) {
+ setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
+ }
}
}
@@ -2151,7 +2172,14 @@
}
mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]);
- mTransactionCompletedThread.sendCallbacks();
+
+ // Lock the mStateLock in case SurfaceFlinger is in the middle of applying a transaction.
+ // If we do not lock here, a callback could be sent without all of its SurfaceControls and
+ // metrics.
+ {
+ Mutex::Autolock _l(mStateLock);
+ mTransactionCompletedThread.sendCallbacks();
+ }
if (mLumaSampling && mRegionSamplingThread) {
mRegionSamplingThread->notifyNewContent();
@@ -4133,6 +4161,9 @@
sp<GraphicBuffer> buffer;
if (bufferChanged && cacheIdChanged) {
ClientCache::getInstance().add(s.cachedBuffer, s.buffer);
+ ClientCache::getInstance().registerErasedRecipient(s.cachedBuffer,
+ wp<ClientCache::ErasedRecipient>(layer));
+ getRenderEngine().cacheExternalTextureBuffer(s.buffer);
buffer = s.buffer;
} else if (cacheIdChanged) {
buffer = ClientCache::getInstance().get(s.cachedBuffer);
@@ -4416,6 +4447,13 @@
new LambdaMessage([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); }));
}
+void SurfaceFlinger::setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled) {
+ if (mHWCVsyncState != enabled) {
+ getHwComposer().setVsyncEnabled(displayId, enabled);
+ mHWCVsyncState = enabled;
+ }
+}
+
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode) {
if (display->isVirtual()) {
ALOGE("%s: Invalid operation on virtual display", __FUNCTION__);
@@ -4442,6 +4480,7 @@
// Turn on the display
getHwComposer().setPowerMode(*displayId, mode);
if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
+ setVsyncEnabledInHWC(*displayId, mHWCVsyncPendingState);
mScheduler->onScreenAcquired(mAppConnectionHandle);
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
}
@@ -4467,6 +4506,9 @@
mScheduler->onScreenReleased(mAppConnectionHandle);
}
+ // Make sure HWVsync is disabled before turning off the display
+ setVsyncEnabledInHWC(*displayId, HWC2::Vsync::Disable);
+
getHwComposer().setPowerMode(*displayId, mode);
mVisibleRegionsDirty = true;
// from this point on, SF will stop drawing on this display
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3d98ec1..6d4b2d7 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -293,6 +293,9 @@
// TODO: this should be made accessible only to EventThread
void setPrimaryVsyncEnabled(bool enabled);
+ // main thread function to enable/disable h/w composer event
+ void setPrimaryVsyncEnabledInternal(bool enabled);
+
// called on the main thread by MessageQueue when an internal message
// is received
// TODO: this should be made accessible only to MessageQueue
@@ -404,7 +407,9 @@
const sp<IGraphicBufferProducer>& bufferProducer) const override;
status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const override;
sp<IDisplayEventConnection> createDisplayEventConnection(
- ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp) override;
+ ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp,
+ ISurfaceComposer::ConfigChanged configChanged =
+ ISurfaceComposer::eConfigChangedSuppress) override;
status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer,
bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace,
const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
@@ -840,6 +845,7 @@
}
bool previousFrameMissed();
+ void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled);
/*
* Debugging & dumpsys
@@ -1173,6 +1179,10 @@
// The Layer pointer is removed from the set when the destructor is called so there shouldn't
// be any issues with a raw pointer referencing an invalid object.
std::unordered_set<Layer*> mOffscreenLayers;
+
+ // Flags to capture the state of Vsync in HWC
+ HWC2::Vsync mHWCVsyncState = HWC2::Vsync::Disable;
+ HWC2::Vsync mHWCVsyncPendingState = HWC2::Vsync::Disable;
};
} // namespace android
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 5ebae1e..6b4634a 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*:MultiDisplayLayerBoundsTest.*:InvalidHandleTest.*:VirtualDisplayTest.*"
+ "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*:MultiDisplayLayerBoundsTest.*:InvalidHandleTest.*:VirtualDisplayTest.*:RelativeZTest.*"
}
}
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index ec1ac4b..f83b3ea 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -385,6 +385,18 @@
return createLayer(mClient, name, width, height, flags, parent);
}
+ sp<SurfaceControl> createColorLayer(const char* name, const Color& color,
+ SurfaceControl* parent = nullptr) {
+ auto colorLayer = createSurface(mClient, name, 0 /* buffer width */, 0 /* buffer height */,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, parent);
+ asTransaction([&](Transaction& t) {
+ t.setColor(colorLayer, half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f});
+ t.setAlpha(colorLayer, color.a / 255.0f);
+ });
+ return colorLayer;
+ }
+
ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
// wait for previous transactions (such as setSize) to complete
Transaction().apply(true);
@@ -4725,6 +4737,48 @@
mCapture->expectColor(Rect(20, 20, 52, 52), Color::RED);
}
}
+TEST_F(ChildLayerTest, DetachChildrenWithDeferredTransaction) {
+ sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> childNewClient =
+ newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+
+ ASSERT_TRUE(childNewClient != nullptr);
+ ASSERT_TRUE(childNewClient->isValid());
+
+ fillSurfaceRGBA8(childNewClient, 200, 200, 200);
+
+ Transaction()
+ .hide(mChild)
+ .show(childNewClient)
+ .setPosition(childNewClient, 10, 10)
+ .setPosition(mFGSurfaceControl, 64, 64)
+ .apply();
+
+ {
+ mCapture = screenshot();
+ Rect rect = Rect(74, 74, 84, 84);
+ mCapture->expectBorder(rect, Color{195, 63, 63, 255});
+ mCapture->expectColor(rect, Color{200, 200, 200, 255});
+ }
+
+ Transaction()
+ .deferTransactionUntil_legacy(childNewClient, mFGSurfaceControl->getHandle(),
+ mFGSurfaceControl->getSurface()->getNextFrameNumber())
+ .apply();
+ Transaction().detachChildren(mFGSurfaceControl).apply();
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(mFGSurfaceControl, Color::RED, 32, 32));
+
+ // BufferLayer can still dequeue buffers even though there's a detached layer with a
+ // deferred transaction.
+ {
+ SCOPED_TRACE("new buffer");
+ mCapture = screenshot();
+ Rect rect = Rect(74, 74, 84, 84);
+ mCapture->expectBorder(rect, Color::RED);
+ mCapture->expectColor(rect, Color{200, 200, 200, 255});
+ }
+}
TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) {
asTransaction([&](Transaction& t) {
@@ -5833,4 +5887,126 @@
allowedConfigs.end());
}
+class RelativeZTest : public LayerTransactionTest {
+protected:
+ virtual void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
+ // Back layer
+ mBackgroundLayer = createColorLayer("Background layer", Color::RED);
+
+ // Front layer
+ mForegroundLayer = createColorLayer("Foreground layer", Color::GREEN);
+
+ asTransaction([&](Transaction& t) {
+ t.setDisplayLayerStack(display, 0);
+ t.setLayer(mBackgroundLayer, INT32_MAX - 2).show(mBackgroundLayer);
+ t.setLayer(mForegroundLayer, INT32_MAX - 1).show(mForegroundLayer);
+ });
+ }
+
+ virtual void TearDown() {
+ LayerTransactionTest::TearDown();
+ mBackgroundLayer = 0;
+ mForegroundLayer = 0;
+ }
+
+ sp<SurfaceControl> mBackgroundLayer;
+ sp<SurfaceControl> mForegroundLayer;
+};
+
+// When a layer is reparented offscreen, remove relative z order if the relative parent
+// is still onscreen so that the layer is not drawn.
+TEST_F(RelativeZTest, LayerRemoved) {
+ std::unique_ptr<ScreenCapture> sc;
+
+ // Background layer (RED)
+ // Child layer (WHITE) (relative to foregroud layer)
+ // Foregroud layer (GREEN)
+ sp<SurfaceControl> childLayer =
+ createColorLayer("Child layer", Color::BLUE, mBackgroundLayer.get());
+
+ Transaction{}
+ .setRelativeLayer(childLayer, mForegroundLayer->getHandle(), 1)
+ .show(childLayer)
+ .apply();
+
+ {
+ // The childLayer should be in front of the FG control.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::BLUE.r, Color::BLUE.g, Color::BLUE.b);
+ }
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ Transaction{}.reparent(childLayer, nullptr).apply();
+
+ // Background layer (RED)
+ // Child layer (WHITE)
+ // Foregroud layer (GREEN)
+ Transaction{}.reparent(childLayer, mBackgroundLayer->getHandle()).apply();
+
+ {
+ // The relative z info for child layer should be reset, leaving FG control on top.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+ }
+}
+
+// When a layer is reparented offscreen, preseve relative z order if the relative parent
+// is also offscreen. Regression test b/132613412
+TEST_F(RelativeZTest, LayerRemovedOffscreenRelativeParent) {
+ std::unique_ptr<ScreenCapture> sc;
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ // child level 1 (WHITE)
+ // child level 2a (BLUE)
+ // child level 3 (GREEN) (relative to child level 2b)
+ // child level 2b (BLACK)
+ sp<SurfaceControl> childLevel1 =
+ createColorLayer("child level 1", Color::WHITE, mForegroundLayer.get());
+ sp<SurfaceControl> childLevel2a =
+ createColorLayer("child level 2a", Color::BLUE, childLevel1.get());
+ sp<SurfaceControl> childLevel2b =
+ createColorLayer("child level 2b", Color::BLACK, childLevel1.get());
+ sp<SurfaceControl> childLevel3 =
+ createColorLayer("child level 3", Color::GREEN, childLevel2a.get());
+
+ Transaction{}
+ .setRelativeLayer(childLevel3, childLevel2b->getHandle(), 1)
+ .show(childLevel2a)
+ .show(childLevel2b)
+ .show(childLevel3)
+ .apply();
+
+ {
+ // The childLevel3 should be in front of childLevel2b.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+ }
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ Transaction{}.reparent(childLevel1, nullptr).apply();
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ // child level 1 (WHITE)
+ // child level 2 back (BLUE)
+ // child level 3 (GREEN) (relative to child level 2b)
+ // child level 2 front (BLACK)
+ Transaction{}.reparent(childLevel1, mForegroundLayer->getHandle()).apply();
+
+ {
+ // Nothing should change at this point since relative z info was preserved.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+ }
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index 2e705da..0aa8cf5 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -51,6 +51,7 @@
AsyncCallRecorder<void (*)(nsecs_t)> mVSyncEventCallRecorder;
static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms;
+ static constexpr std::chrono::nanoseconds mOffsetThresholdForNextVsync = 16ms;
static constexpr int mIterations = 100;
};
@@ -78,7 +79,8 @@
void DispSyncSourceTest::createDispSyncSource() {
createDispSync();
- mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), true,
+ mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(),
+ mOffsetThresholdForNextVsync.count(), true,
"DispSyncSourceTest");
mDispSyncSource->setCallback(this);
}
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index ea908a9..dbd9b84 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -55,8 +55,9 @@
class MockEventThreadConnection : public EventThreadConnection {
public:
MockEventThreadConnection(android::impl::EventThread* eventThread,
- ResyncCallback&& resyncCallback)
- : EventThreadConnection(eventThread, std::move(resyncCallback)) {}
+ ResyncCallback&& resyncCallback,
+ ISurfaceComposer::ConfigChanged configChanged)
+ : EventThreadConnection(eventThread, std::move(resyncCallback), configChanged) {}
MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event));
};
@@ -67,7 +68,8 @@
~EventThreadTest() override;
void createThread();
- sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder);
+ sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder,
+ ISurfaceComposer::ConfigChanged configChanged);
void expectVSyncSetEnabledCallReceived(bool expectedState);
void expectVSyncSetPhaseOffsetCallReceived(nsecs_t expectedPhaseOffset);
@@ -110,7 +112,8 @@
.WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable()));
createThread();
- mConnection = createConnection(mConnectionEventCallRecorder);
+ mConnection = createConnection(mConnectionEventCallRecorder,
+ ISurfaceComposer::eConfigChangedDispatch);
// A display must be connected for VSYNC events to be delivered.
mThread->onHotplugReceived(INTERNAL_DISPLAY_ID, true);
@@ -138,9 +141,10 @@
}
sp<EventThreadTest::MockEventThreadConnection> EventThreadTest::createConnection(
- ConnectionEventRecorder& recorder) {
+ ConnectionEventRecorder& recorder, ISurfaceComposer::ConfigChanged configChanged) {
sp<MockEventThreadConnection> connection =
- new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable());
+ new MockEventThreadConnection(mThread.get(), mResyncCallRecorder.getInvocable(),
+ configChanged);
EXPECT_CALL(*connection, postEvent(_)).WillRepeatedly(Invoke(recorder.getInvocable()));
return connection;
}
@@ -267,7 +271,9 @@
TEST_F(EventThreadTest, setVsyncRateZeroPostsNoVSyncEventsToThatConnection) {
// Create a first connection, register it, and request a vsync rate of zero.
ConnectionEventRecorder firstConnectionEventRecorder{0};
- sp<MockEventThreadConnection> firstConnection = createConnection(firstConnectionEventRecorder);
+ sp<MockEventThreadConnection> firstConnection =
+ createConnection(firstConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
mThread->setVsyncRate(0, firstConnection);
// By itself, this should not enable vsync events
@@ -277,7 +283,8 @@
// However if there is another connection which wants events at a nonzero rate.....
ConnectionEventRecorder secondConnectionEventRecorder{0};
sp<MockEventThreadConnection> secondConnection =
- createConnection(secondConnectionEventRecorder);
+ createConnection(secondConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
mThread->setVsyncRate(1, secondConnection);
// EventThread should enable vsync callbacks.
@@ -363,7 +370,9 @@
TEST_F(EventThreadTest, connectionsRemovedIfEventDeliveryError) {
ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY};
- sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
+ sp<MockEventThreadConnection> errorConnection =
+ createConnection(errorConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
mThread->setVsyncRate(1, errorConnection);
// EventThread should enable vsync callbacks.
@@ -387,7 +396,9 @@
TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) {
ConnectionEventRecorder errorConnectionEventRecorder{WOULD_BLOCK};
- sp<MockEventThreadConnection> errorConnection = createConnection(errorConnectionEventRecorder);
+ sp<MockEventThreadConnection> errorConnection =
+ createConnection(errorConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
mThread->setVsyncRate(1, errorConnection);
// EventThread should enable vsync callbacks.
@@ -449,5 +460,18 @@
expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7);
}
+TEST_F(EventThreadTest, suppressConfigChanged) {
+ ConnectionEventRecorder suppressConnectionEventRecorder{0};
+ sp<MockEventThreadConnection> suppressConnection =
+ createConnection(suppressConnectionEventRecorder,
+ ISurfaceComposer::eConfigChangedSuppress);
+
+ mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 9);
+ expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9);
+
+ auto args = suppressConnectionEventRecorder.waitForCall();
+ ASSERT_FALSE(args.has_value());
+}
+
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
index 51d6d7e..160f041 100644
--- a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
@@ -17,6 +17,8 @@
#undef LOG_TAG
#define LOG_TAG "RegionSamplingTest"
+#include <ui/Transform.h>
+
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <array>
@@ -33,18 +35,21 @@
static int constexpr kWidth = 98;
static int constexpr kStride = 100;
static int constexpr kHeight = 29;
+ static int constexpr kOrientation = ui::Transform::ROT_0;
std::array<uint32_t, kHeight * kStride> buffer;
Rect const whole_area{0, 0, kWidth, kHeight};
};
TEST_F(RegionSamplingTest, calculate_mean_white) {
std::fill(buffer.begin(), buffer.end(), kWhite);
- EXPECT_THAT(sampleArea(buffer.data(), kStride, whole_area), testing::FloatEq(1.0f));
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, whole_area),
+ testing::FloatEq(1.0f));
}
TEST_F(RegionSamplingTest, calculate_mean_black) {
std::fill(buffer.begin(), buffer.end(), kBlack);
- EXPECT_THAT(sampleArea(buffer.data(), kStride, whole_area), testing::FloatEq(0.0f));
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, whole_area),
+ testing::FloatEq(0.0f));
}
TEST_F(RegionSamplingTest, calculate_mean_partial_region) {
@@ -54,7 +59,8 @@
whole_area.top + halfway_down};
std::fill(buffer.begin(), buffer.begin() + half, 0);
std::fill(buffer.begin() + half, buffer.end(), kWhite);
- EXPECT_THAT(sampleArea(buffer.data(), kStride, partial_region), testing::FloatEq(0.0f));
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, partial_region),
+ testing::FloatEq(0.0f));
}
TEST_F(RegionSamplingTest, calculate_mean_mixed_values) {
@@ -63,15 +69,71 @@
n++;
return pixel;
});
- EXPECT_THAT(sampleArea(buffer.data(), kStride, whole_area), testing::FloatNear(0.083f, 0.01f));
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, whole_area),
+ testing::FloatNear(0.083f, 0.01f));
}
TEST_F(RegionSamplingTest, bimodal_tiebreaker) {
std::generate(buffer.begin(), buffer.end(),
[n = 0]() mutable { return (n++ % 2) ? kBlack : kWhite; });
// presently there's no tiebreaking strategy in place, accept either of the means
- EXPECT_THAT(sampleArea(buffer.data(), kStride, whole_area),
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, whole_area),
testing::AnyOf(testing::FloatEq(1.0), testing::FloatEq(0.0f)));
}
+TEST_F(RegionSamplingTest, bounds_checking) {
+ std::generate(buffer.begin(), buffer.end(),
+ [n = 0]() mutable { return (n++ > (kStride * kHeight >> 1)) ? kBlack : kWhite; });
+
+ Rect invalid_region{0, 0, 4, kHeight + 1};
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, invalid_region),
+ testing::Eq(0.0));
+
+ invalid_region = Rect{0, 0, -4, kHeight};
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, invalid_region),
+ testing::Eq(0.0));
+
+ invalid_region = Rect{3, 0, 2, 0};
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, invalid_region),
+ testing::Eq(0.0));
+
+ invalid_region = Rect{0, 3, 0, 2};
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, invalid_region),
+ testing::Eq(0.0));
+}
+
+// workaround for b/133849373
+TEST_F(RegionSamplingTest, orientation_90) {
+ std::generate(buffer.begin(), buffer.end(),
+ [n = 0]() mutable { return (n++ > (kStride * kHeight >> 1)) ? kBlack : kWhite; });
+
+ Rect tl_region{0, 0, 4, 4};
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_0,
+ tl_region),
+ testing::Eq(1.0));
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_180,
+ tl_region),
+ testing::Eq(1.0));
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_90,
+ tl_region),
+ testing::Eq(0.0));
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_270,
+ tl_region),
+ testing::Eq(0.0));
+
+ Rect br_region{kWidth - 4, kHeight - 4, kWidth, kHeight};
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_0,
+ br_region),
+ testing::Eq(0.0));
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_180,
+ br_region),
+ testing::Eq(0.0));
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_90,
+ br_region),
+ testing::Eq(1.0));
+ EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, ui::Transform::ROT_270,
+ br_region),
+ testing::Eq(1.0));
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 1f8b111..740115e 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -25,7 +25,8 @@
class MockEventThreadConnection : public android::EventThreadConnection {
public:
explicit MockEventThreadConnection(EventThread* eventThread)
- : EventThreadConnection(eventThread, ResyncCallback()) {}
+ : EventThreadConnection(eventThread, ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress) {}
~MockEventThreadConnection() = default;
MOCK_METHOD1(stealReceiveChannel, status_t(gui::BitTube* outChannel));
@@ -47,7 +48,7 @@
std::unique_ptr<EventThread> makeEventThread(
const char* /* connectionName */, DispSync* /* dispSync */,
- nsecs_t /* phaseOffsetNs */,
+ nsecs_t /* phaseOffsetNs */, nsecs_t /* offsetThresholdForNextVsync */,
impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override {
return std::move(mEventThread);
}
@@ -81,10 +82,10 @@
// createConnection call to scheduler makes a createEventConnection call to EventThread. Make
// sure that call gets executed and returns an EventThread::Connection object.
- EXPECT_CALL(*mEventThread, createEventConnection(_))
+ EXPECT_CALL(*mEventThread, createEventConnection(_, _))
.WillRepeatedly(Return(mEventThreadConnection));
- mConnectionHandle = mScheduler->createConnection("appConnection", 16, ResyncCallback(),
+ mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16, ResyncCallback(),
impl::EventThread::InterceptVSyncsCallback());
EXPECT_TRUE(mConnectionHandle != nullptr);
}
@@ -105,7 +106,10 @@
// exceptions, just gracefully continues.
sp<IDisplayEventConnection> returnedValue;
ASSERT_NO_FATAL_FAILURE(
- returnedValue = mScheduler->createDisplayEventConnection(nullptr, ResyncCallback()));
+ returnedValue =
+ mScheduler->createDisplayEventConnection(nullptr, ResyncCallback(),
+ ISurfaceComposer::
+ eConfigChangedSuppress));
EXPECT_TRUE(returnedValue == nullptr);
EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
@@ -126,7 +130,9 @@
sp<IDisplayEventConnection> returnedValue;
ASSERT_NO_FATAL_FAILURE(
returnedValue =
- mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback()));
+ mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback(),
+ ISurfaceComposer::
+ eConfigChangedSuppress));
EXPECT_TRUE(returnedValue == nullptr);
EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr);
EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr);
@@ -155,7 +161,9 @@
sp<IDisplayEventConnection> returnedValue;
ASSERT_NO_FATAL_FAILURE(
returnedValue =
- mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback()));
+ mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback(),
+ ISurfaceComposer::
+ eConfigChangedSuppress));
EXPECT_TRUE(returnedValue != nullptr);
ASSERT_EQ(returnedValue, mEventThreadConnection);
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index c3d2b8d..cb6980e 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -17,6 +17,7 @@
#pragma once
#include <gmock/gmock.h>
+#include <gui/ISurfaceComposer.h>
#include "Scheduler/EventThread.h"
#include "Scheduler/RefreshRateConfigs.h"
@@ -34,7 +35,8 @@
// Scheduler::Connection. This allows plugging in mock::EventThread.
sp<Scheduler::ConnectionHandle> addConnection(std::unique_ptr<EventThread> eventThread) {
sp<EventThreadConnection> eventThreadConnection =
- new EventThreadConnection(eventThread.get(), ResyncCallback());
+ new EventThreadConnection(eventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress);
const int64_t id = sNextId++;
mConnections.emplace(id,
std::make_unique<Scheduler::Connection>(new ConnectionHandle(id),
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 5b5f8e7..ed35ebf 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -28,7 +28,8 @@
EventThread();
~EventThread() override;
- MOCK_CONST_METHOD1(createEventConnection, sp<EventThreadConnection>(ResyncCallback));
+ MOCK_CONST_METHOD2(createEventConnection,
+ sp<EventThreadConnection>(ResyncCallback, ISurfaceComposer::ConfigChanged));
MOCK_METHOD0(onScreenReleased, void());
MOCK_METHOD0(onScreenAcquired, void());
MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));