summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/gui/BufferQueueCore.cpp8
-rw-r--r--opengl/libs/Android.bp1
-rw-r--r--opengl/libs/EGL/BlobCache.cpp20
-rw-r--r--opengl/libs/EGL/Loader.cpp12
-rw-r--r--opengl/libs/EGL/egl.cpp10
-rw-r--r--opengl/libs/EGL/egl_angle_platform.cpp1
-rw-r--r--opengl/libs/EGL/egl_display.cpp20
-rw-r--r--opengl/libs/EGL/egl_layers.cpp6
-rw-r--r--opengl/libs/EGL/egl_platform_entries.cpp9
-rw-r--r--opengl/libs/EGL/egl_tls.cpp6
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp212
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.h4
-rw-r--r--services/inputflinger/reader/EventHub.cpp2
-rw-r--r--services/inputflinger/reader/mapper/KeyboardInputMapper.cpp2
-rw-r--r--services/inputflinger/tests/InputReader_test.cpp22
-rw-r--r--services/inputflinger/tests/UinputDevice.cpp3
-rw-r--r--services/inputflinger/tests/UinputDevice.h10
-rw-r--r--services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp30
-rw-r--r--services/surfaceflinger/DisplayDevice.cpp48
-rw-r--r--services/surfaceflinger/Scheduler/LayerHistoryV2.cpp2
-rw-r--r--services/surfaceflinger/Scheduler/LayerInfoV2.cpp55
-rw-r--r--services/surfaceflinger/Scheduler/LayerInfoV2.h14
-rw-r--r--services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp17
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.cpp40
-rw-r--r--services/surfaceflinger/Scheduler/Scheduler.h5
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp230
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h60
-rw-r--r--services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp44
-rw-r--r--services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h4
29 files changed, 432 insertions, 465 deletions
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 8d80833ebe..5023b6bb81 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -75,10 +75,12 @@ static status_t getProcessName(int pid, String8& name) {
if (NULL != fp) {
const size_t size = 64;
char proc_name[size];
- fgets(proc_name, size, fp);
+ char* result = fgets(proc_name, size, fp);
fclose(fp);
- name = proc_name;
- return NO_ERROR;
+ if (result != nullptr) {
+ name = proc_name;
+ return NO_ERROR;
+ }
}
return INVALID_OPERATION;
}
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 3997134f47..e8d3684e4e 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -100,6 +100,7 @@ cc_defaults {
"libgraphicsenv",
"libnativewindow",
"libbacktrace",
+ "libbase",
],
target: {
vendor: {
diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp
index 74c4d7d07a..74fb0194f9 100644
--- a/opengl/libs/EGL/BlobCache.cpp
+++ b/opengl/libs/EGL/BlobCache.cpp
@@ -21,7 +21,7 @@
#include <errno.h>
#include <inttypes.h>
-#include <cutils/properties.h>
+#include <android-base/properties.h>
#include <log/log.h>
#include <chrono>
@@ -165,7 +165,8 @@ static inline size_t align4(size_t size) {
}
size_t BlobCache::getFlattenedSize() const {
- size_t size = align4(sizeof(Header) + PROPERTY_VALUE_MAX);
+ auto buildId = base::GetProperty("ro.build.id", "");
+ size_t size = align4(sizeof(Header) + buildId.size());
for (const CacheEntry& e : mCacheEntries) {
std::shared_ptr<Blob> const& keyBlob = e.getKey();
std::shared_ptr<Blob> const& valueBlob = e.getValue();
@@ -185,9 +186,9 @@ int BlobCache::flatten(void* buffer, size_t size) const {
header->mBlobCacheVersion = blobCacheVersion;
header->mDeviceVersion = blobCacheDeviceVersion;
header->mNumEntries = mCacheEntries.size();
- char buildId[PROPERTY_VALUE_MAX];
- header->mBuildIdLength = property_get("ro.build.id", buildId, "");
- memcpy(header->mBuildId, buildId, header->mBuildIdLength);
+ auto buildId = base::GetProperty("ro.build.id", "");
+ header->mBuildIdLength = buildId.size();
+ memcpy(header->mBuildId, buildId.c_str(), header->mBuildIdLength);
// Write cache entries
uint8_t* byteBuffer = reinterpret_cast<uint8_t*>(buffer);
@@ -238,12 +239,11 @@ int BlobCache::unflatten(void const* buffer, size_t size) {
ALOGE("unflatten: bad magic number: %" PRIu32, header->mMagicNumber);
return -EINVAL;
}
- char buildId[PROPERTY_VALUE_MAX];
- int len = property_get("ro.build.id", buildId, "");
+ auto buildId = base::GetProperty("ro.build.id", "");
if (header->mBlobCacheVersion != blobCacheVersion ||
- header->mDeviceVersion != blobCacheDeviceVersion ||
- len != header->mBuildIdLength ||
- strncmp(buildId, header->mBuildId, len)) {
+ header->mDeviceVersion != blobCacheDeviceVersion ||
+ buildId.size() != header->mBuildIdLength ||
+ strncmp(buildId.c_str(), header->mBuildId, buildId.size())) {
// We treat version mismatches as an empty cache.
return 0;
}
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index d664e4db97..d66ef2b969 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -24,8 +24,8 @@
#include <dirent.h>
#include <dlfcn.h>
+#include <android-base/properties.h>
#include <android/dlext.h>
-#include <cutils/properties.h>
#include <log/log.h>
#include <utils/Timers.h>
@@ -241,12 +241,12 @@ void* Loader::open(egl_connection_t* cnx)
// i.e.:
// libGLES_${prop}.so, or:
// libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so
- char prop[PROPERTY_VALUE_MAX + 1];
for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
- if (property_get(key, prop, nullptr) <= 0) {
+ auto prop = base::GetProperty(key, "");
+ if (prop.empty()) {
continue;
}
- hnd = attempt_to_load_system_driver(cnx, prop, true);
+ hnd = attempt_to_load_system_driver(cnx, prop.c_str(), true);
if (hnd) {
break;
} else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) {
@@ -510,9 +510,9 @@ static void* load_updated_driver(const char* kind, android_namespace_t* ns) {
.library_namespace = ns,
};
void* so = nullptr;
- char prop[PROPERTY_VALUE_MAX + 1];
for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
- if (property_get(key, prop, nullptr) <= 0) {
+ auto prop = base::GetProperty(key, "");
+ if (prop.empty()) {
continue;
}
std::string name = std::string("lib") + kind + "_" + prop + ".so";
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index d5d57d7c9a..43f7a075a7 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -18,7 +18,7 @@
#include <EGL/egl.h>
-#include <cutils/properties.h>
+#include <android-base/properties.h>
#include <log/log.h>
@@ -58,9 +58,7 @@ static int gl_no_context() {
} else {
LOG_ALWAYS_FATAL(error);
}
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.egl.callstack", value, "0");
- if (atoi(value)) {
+ if (base::GetBoolProperty("debug.egl.callstack", false)) {
CallStack::log(LOG_TAG);
}
}
@@ -224,9 +222,7 @@ void gl_unimplemented() {
pthread_mutex_unlock(&sLogPrintMutex);
if (printLog) {
ALOGE("called unimplemented OpenGL ES API");
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.egl.callstack", value, "0");
- if (atoi(value)) {
+ if (base::GetBoolProperty("debug.egl.callstack", false)) {
CallStack::log(LOG_TAG);
}
}
diff --git a/opengl/libs/EGL/egl_angle_platform.cpp b/opengl/libs/EGL/egl_angle_platform.cpp
index 00caff222b..97dc0f1370 100644
--- a/opengl/libs/EGL/egl_angle_platform.cpp
+++ b/opengl/libs/EGL/egl_angle_platform.cpp
@@ -16,7 +16,6 @@
#if defined(__ANDROID__)
-#include <cutils/properties.h>
#include "Loader.h"
#include "egl_angle_platform.h"
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 6af7cd260b..3b1cf712a2 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -24,7 +24,6 @@
#include <EGL/eglext_angle.h>
#include <private/EGL/display.h>
-#include <cutils/properties.h>
#include "Loader.h"
#include "egl_angle_platform.h"
#include "egl_cache.h"
@@ -32,6 +31,7 @@
#include "egl_tls.h"
#include <SurfaceFlingerProperties.h>
+#include <android-base/properties.h>
#include <android/dlext.h>
#include <dlfcn.h>
#include <graphicsenv/GraphicsEnv.h>
@@ -73,7 +73,7 @@ bool findExtension(const char* exts, const char* name, size_t nameLen) {
}
bool needsAndroidPEglMitigation() {
- static const int32_t vndk_version = property_get_int32("ro.vndk.version", -1);
+ static const int32_t vndk_version = base::GetIntProperty("ro.vndk.version", -1);
return vndk_version <= 28;
}
@@ -151,10 +151,8 @@ static EGLDisplay getPlatformDisplayAngle(EGLNativeDisplayType display, egl_conn
attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
attrs.push_back(EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE);
- char prop[PROPERTY_VALUE_MAX];
- property_get("debug.angle.validation", prop, "0");
attrs.push_back(EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE);
- attrs.push_back(atoi(prop));
+ attrs.push_back(base::GetBoolProperty("debug.angle.validation", false));
attrs.push_back(EGL_NONE);
@@ -372,16 +370,8 @@ EGLBoolean egl_display_t::initialize(EGLint *major, EGLint *minor) {
egl_cache_t::get()->initialize(this);
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.egl.finish", value, "0");
- if (atoi(value)) {
- finishOnSwap = true;
- }
-
- property_get("debug.egl.traceGpuCompletion", value, "0");
- if (atoi(value)) {
- traceGpuCompletion = true;
- }
+ finishOnSwap = base::GetBoolProperty("debug.egl.finish", false);
+ traceGpuCompletion = base::GetBoolProperty("debug.egl.traceGpuCompletion", false);
// TODO: If device doesn't provide 1.4 or 1.5 then we'll be
// changing the behavior from the past where we always advertise
diff --git a/opengl/libs/EGL/egl_layers.cpp b/opengl/libs/EGL/egl_layers.cpp
index 44a1c0bcd3..ea86c9a05b 100644
--- a/opengl/libs/EGL/egl_layers.cpp
+++ b/opengl/libs/EGL/egl_layers.cpp
@@ -18,9 +18,9 @@
#include <EGL/egl.h>
#include <android-base/file.h>
+#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android/dlext.h>
-#include <cutils/properties.h>
#include <dlfcn.h>
#include <graphicsenv/GraphicsEnv.h>
#include <log/log.h>
@@ -157,9 +157,7 @@ std::string LayerLoader::GetDebugLayers() {
if (debug_layers.empty()) {
// Only check system properties if Java settings are empty
- char prop[PROPERTY_VALUE_MAX];
- property_get("debug.gles.layers", prop, "");
- debug_layers = prop;
+ debug_layers = base::GetProperty("debug.gles.layers", "");
}
return debug_layers;
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index c976c609b7..99283be6e1 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -27,13 +27,13 @@
#include <EGL/eglext.h>
#include <EGL/eglext_angle.h>
-#include <android/hardware_buffer.h>
+#include <android-base/properties.h>
#include <android-base/strings.h>
+#include <android/hardware_buffer.h>
#include <graphicsenv/GraphicsEnv.h>
#include <private/android/AHardwareBufferHelpers.h>
#include <cutils/compiler.h>
-#include <cutils/properties.h>
#include <log/log.h>
#include <condition_variable>
@@ -381,10 +381,7 @@ EGLBoolean eglChooseConfigImpl( EGLDisplay dpy, const EGLint *attrib_list,
egl_connection_t* const cnx = &gEGLImpl;
if (cnx->dso) {
if (attrib_list) {
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.egl.force_msaa", value, "false");
-
- if (!strcmp(value, "true")) {
+ if (base::GetBoolProperty("debug.egl.force_msaa", false)) {
size_t attribCount = 0;
EGLint attrib = attrib_list[0];
diff --git a/opengl/libs/EGL/egl_tls.cpp b/opengl/libs/EGL/egl_tls.cpp
index aaecb62194..8d118e07ed 100644
--- a/opengl/libs/EGL/egl_tls.cpp
+++ b/opengl/libs/EGL/egl_tls.cpp
@@ -18,7 +18,7 @@
#include <stdlib.h>
-#include <cutils/properties.h>
+#include <android-base/properties.h>
#include <log/log.h>
#include "CallStack.h"
#include "egl_platform_entries.h"
@@ -96,9 +96,7 @@ void egl_tls_t::setErrorEtcImpl(
if (!quiet) {
ALOGE("%s:%d error %x (%s)",
caller, line, error, egl_strerror(error));
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.egl.callstack", value, "0");
- if (atoi(value)) {
+ if (base::GetBoolProperty("debug.egl.callstack", false)) {
CallStack::log(LOG_TAG);
}
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 1dbcf98652..a239723652 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1152,14 +1152,16 @@ bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* ent
}
setInjectionResult(entry, injectionResult);
+ if (injectionResult == INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
+ ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent));
+ return true;
+ }
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
- if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {
- CancelationOptions::Mode mode(isPointerEvent
- ? CancelationOptions::CANCEL_POINTER_EVENTS
- : CancelationOptions::CANCEL_NON_POINTER_EVENTS);
- CancelationOptions options(mode, "input event injection failed");
- synthesizeCancelationEventsForMonitorsLocked(options);
- }
+ CancelationOptions::Mode mode(isPointerEvent
+ ? CancelationOptions::CANCEL_POINTER_EVENTS
+ : CancelationOptions::CANCEL_NON_POINTER_EVENTS);
+ CancelationOptions options(mode, "input event injection failed");
+ synthesizeCancelationEventsForMonitorsLocked(options);
return true;
}
@@ -1345,13 +1347,6 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(
}
}
-nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime) {
- if (mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
- return currentTime - mInputTargetWaitStartTime;
- }
- return 0;
-}
-
void InputDispatcher::resetAnrTimeoutsLocked() {
if (DEBUG_FOCUS) {
ALOGD("Resetting ANR timeouts.");
@@ -1394,7 +1389,6 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
const EventEntry& entry,
std::vector<InputTarget>& inputTargets,
nsecs_t* nextWakeupTime) {
- int32_t injectionResult;
std::string reason;
int32_t displayId = getTargetDisplayId(entry);
@@ -1407,54 +1401,38 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
// then drop the event.
if (focusedWindowHandle == nullptr) {
if (focusedApplicationHandle != nullptr) {
- injectionResult =
- handleTargetsNotReadyLocked(currentTime, entry, focusedApplicationHandle,
- nullptr, nextWakeupTime,
- "Waiting because no window has focus but there is "
- "a focused application that may eventually add a "
- "window when it finishes starting up.");
- goto Unresponsive;
+ return handleTargetsNotReadyLocked(currentTime, entry, focusedApplicationHandle,
+ nullptr, nextWakeupTime,
+ "Waiting because no window has focus but there is "
+ "a focused application that may eventually add a "
+ "window when it finishes starting up.");
}
ALOGI("Dropping event because there is no focused window or focused application in display "
"%" PRId32 ".",
displayId);
- injectionResult = INPUT_EVENT_INJECTION_FAILED;
- goto Failed;
+ return INPUT_EVENT_INJECTION_FAILED;
}
// Check permissions.
if (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) {
- injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
- goto Failed;
+ return INPUT_EVENT_INJECTION_PERMISSION_DENIED;
}
// Check whether the window is ready for more input.
reason = checkWindowReadyForMoreInputLocked(currentTime, focusedWindowHandle, entry, "focused");
if (!reason.empty()) {
- injectionResult =
- handleTargetsNotReadyLocked(currentTime, entry, focusedApplicationHandle,
- focusedWindowHandle, nextWakeupTime, reason.c_str());
- goto Unresponsive;
+ return handleTargetsNotReadyLocked(currentTime, entry, focusedApplicationHandle,
+ focusedWindowHandle, nextWakeupTime, reason.c_str());
}
// Success! Output targets.
- injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
addWindowTargetLocked(focusedWindowHandle,
InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS,
BitSet32(0), inputTargets);
// Done.
-Failed:
-Unresponsive:
- nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
- updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication);
- if (DEBUG_FOCUS) {
- ALOGD("findFocusedWindow finished: injectionResult=%d, "
- "timeSpentWaitingForApplication=%0.1fms",
- injectionResult, timeSpentWaitingForApplication / 1000000.0);
- }
- return injectionResult;
+ return INPUT_EVENT_INJECTION_SUCCEEDED;
}
int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
@@ -1751,10 +1729,9 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
checkWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle,
entry, "touched");
if (!reason.empty()) {
- injectionResult = handleTargetsNotReadyLocked(currentTime, entry, nullptr,
- touchedWindow.windowHandle,
- nextWakeupTime, reason.c_str());
- goto Unresponsive;
+ return handleTargetsNotReadyLocked(currentTime, entry, nullptr,
+ touchedWindow.windowHandle, nextWakeupTime,
+ reason.c_str());
}
}
}
@@ -1814,98 +1791,85 @@ Failed:
}
}
+ if (injectionPermission != INJECTION_PERMISSION_GRANTED) {
+ return injectionResult;
+ }
+
// Update final pieces of touch state if the injector had permission.
- if (injectionPermission == INJECTION_PERMISSION_GRANTED) {
- if (!wrongDevice) {
- if (switchedDevice) {
+ if (!wrongDevice) {
+ if (switchedDevice) {
+ if (DEBUG_FOCUS) {
+ ALOGD("Conflicting pointer actions: Switched to a different device.");
+ }
+ *outConflictingPointerActions = true;
+ }
+
+ if (isHoverAction) {
+ // Started hovering, therefore no longer down.
+ if (oldState && oldState->down) {
if (DEBUG_FOCUS) {
- ALOGD("Conflicting pointer actions: Switched to a different device.");
+ ALOGD("Conflicting pointer actions: Hover received while pointer was "
+ "down.");
}
*outConflictingPointerActions = true;
}
-
- if (isHoverAction) {
- // Started hovering, therefore no longer down.
- if (oldState && oldState->down) {
- if (DEBUG_FOCUS) {
- ALOGD("Conflicting pointer actions: Hover received while pointer was "
- "down.");
- }
- *outConflictingPointerActions = true;
- }
- mTempTouchState.reset();
- if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||
- maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
- mTempTouchState.deviceId = entry.deviceId;
- mTempTouchState.source = entry.source;
- mTempTouchState.displayId = displayId;
- }
- } else if (maskedAction == AMOTION_EVENT_ACTION_UP ||
- maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
- // All pointers up or canceled.
- mTempTouchState.reset();
- } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
- // First pointer went down.
- if (oldState && oldState->down) {
- if (DEBUG_FOCUS) {
- ALOGD("Conflicting pointer actions: Down received while already down.");
- }
- *outConflictingPointerActions = true;
+ mTempTouchState.reset();
+ if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||
+ maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
+ mTempTouchState.deviceId = entry.deviceId;
+ mTempTouchState.source = entry.source;
+ mTempTouchState.displayId = displayId;
+ }
+ } else if (maskedAction == AMOTION_EVENT_ACTION_UP ||
+ maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
+ // All pointers up or canceled.
+ mTempTouchState.reset();
+ } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
+ // First pointer went down.
+ if (oldState && oldState->down) {
+ if (DEBUG_FOCUS) {
+ ALOGD("Conflicting pointer actions: Down received while already down.");
}
- } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
- // One pointer went up.
- if (isSplit) {
- int32_t pointerIndex = getMotionEventActionPointerIndex(action);
- uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
-
- for (size_t i = 0; i < mTempTouchState.windows.size();) {
- TouchedWindow& touchedWindow = mTempTouchState.windows[i];
- if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) {
- touchedWindow.pointerIds.clearBit(pointerId);
- if (touchedWindow.pointerIds.isEmpty()) {
- mTempTouchState.windows.erase(mTempTouchState.windows.begin() + i);
- continue;
- }
+ *outConflictingPointerActions = true;
+ }
+ } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
+ // One pointer went up.
+ if (isSplit) {
+ int32_t pointerIndex = getMotionEventActionPointerIndex(action);
+ uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
+
+ for (size_t i = 0; i < mTempTouchState.windows.size();) {
+ TouchedWindow& touchedWindow = mTempTouchState.windows[i];
+ if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) {
+ touchedWindow.pointerIds.clearBit(pointerId);
+ if (touchedWindow.pointerIds.isEmpty()) {
+ mTempTouchState.windows.erase(mTempTouchState.windows.begin() + i);
+ continue;
}
- i += 1;
}
+ i += 1;
}
}
+ }
- // Save changes unless the action was scroll in which case the temporary touch
- // state was only valid for this one action.
- if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) {
- if (mTempTouchState.displayId >= 0) {
- if (oldStateIndex >= 0) {
- mTouchStatesByDisplay.editValueAt(oldStateIndex).copyFrom(mTempTouchState);
- } else {
- mTouchStatesByDisplay.add(displayId, mTempTouchState);
- }
- } else if (oldStateIndex >= 0) {
- mTouchStatesByDisplay.removeItemsAt(oldStateIndex);
+ // Save changes unless the action was scroll in which case the temporary touch
+ // state was only valid for this one action.
+ if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) {
+ if (mTempTouchState.displayId >= 0) {
+ if (oldStateIndex >= 0) {
+ mTouchStatesByDisplay.editValueAt(oldStateIndex).copyFrom(mTempTouchState);
+ } else {
+ mTouchStatesByDisplay.add(displayId, mTempTouchState);
}
+ } else if (oldStateIndex >= 0) {
+ mTouchStatesByDisplay.removeItemsAt(oldStateIndex);
}
-
- // Update hover state.
- mLastHoverWindowHandle = newHoverWindowHandle;
- }
- } else {
- if (DEBUG_FOCUS) {
- ALOGD("Not updating touch focus because injection was denied.");
}
- }
-Unresponsive:
- // Reset temporary touch state to ensure we release unnecessary references to input channels.
- mTempTouchState.reset();
-
- nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
- updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication);
- if (DEBUG_FOCUS) {
- ALOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, "
- "timeSpentWaitingForApplication=%0.1fms",
- injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0);
+ // Update hover state.
+ mLastHoverWindowHandle = newHoverWindowHandle;
}
+
return injectionResult;
}
@@ -4664,6 +4628,7 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* c
dispatchEntry->eventEntry->appendDescription(msg);
ALOGI("%s", msg.c_str());
}
+ reportDispatchStatistics(std::chrono::nanoseconds(eventDuration), *connection, handled);
bool restartEvent;
if (dispatchEntry->eventEntry->type == EventEntry::Type::KEY) {
@@ -4898,9 +4863,8 @@ KeyEvent InputDispatcher::createKeyEvent(const KeyEntry& entry) {
return event;
}
-void InputDispatcher::updateDispatchStatistics(nsecs_t currentTime, const EventEntry& entry,
- int32_t injectionResult,
- nsecs_t timeSpentWaitingForApplication) {
+void InputDispatcher::reportDispatchStatistics(std::chrono::nanoseconds eventDuration,
+ const Connection& connection, bool handled) {
// TODO Write some statistics about how long we spend waiting.
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 670d0e1c96..d122282fbe 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -497,8 +497,8 @@ private:
LatencyStatistics mTouchStatistics{TOUCH_STATS_REPORT_PERIOD};
void reportTouchEventForStatistics(const MotionEntry& entry);
- void updateDispatchStatistics(nsecs_t currentTime, const EventEntry& entry,
- int32_t injectionResult, nsecs_t timeSpentWaitingForApplication);
+ void reportDispatchStatistics(std::chrono::nanoseconds eventDuration,
+ const Connection& connection, bool handled);
void traceInboundQueueLengthLocked() REQUIRES(mLock);
void traceOutboundQueueLength(const sp<Connection>& connection);
void traceWaitQueueLength(const sp<Connection>& connection);
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 264d2879e4..a1514af668 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -1318,7 +1318,7 @@ status_t EventHub::openDeviceLocked(const char* devicePath) {
// joystick and gamepad buttons which are handled like keyboards for the most part.
bool haveKeyboardKeys =
containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) ||
- containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK),
+ containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_WHEEL),
sizeof_bit_array(KEY_MAX + 1));
bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC),
sizeof_bit_array(BTN_MOUSE)) ||
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 7be4a58cc3..e0092210a0 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -233,7 +233,7 @@ void KeyboardInputMapper::process(const RawEvent* rawEvent) {
}
bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) {
- return scanCode < BTN_MOUSE || scanCode >= KEY_OK ||
+ return scanCode < BTN_MOUSE || scanCode >= BTN_WHEEL ||
(scanCode >= BTN_MISC && scanCode < BTN_MOUSE) ||
(scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
}
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 109edfe582..c457a1525f 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1848,6 +1848,28 @@ TEST_F(InputReaderIntegrationTest, SendsEventsToInputListener) {
ASSERT_LE(prevTimestamp, keyArgs.eventTime);
}
+/**
+ * The Steam controller sends BTN_GEAR_DOWN and BTN_GEAR_UP for the two "paddle" buttons
+ * on the back. In this test, we make sure that BTN_GEAR_DOWN / BTN_WHEEL and BTN_GEAR_UP
+ * are passed to the listener.
+ */
+static_assert(BTN_GEAR_DOWN == BTN_WHEEL);
+TEST_F(InputReaderIntegrationTest, SendsGearDownAndUpToInputListener) {
+ std::unique_ptr<UinputSteamController> controller = createUinputDevice<UinputSteamController>();
+ ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertInputDevicesChanged());
+ NotifyKeyArgs keyArgs;
+
+ controller->pressAndReleaseKey(BTN_GEAR_DOWN);
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(&keyArgs)); // ACTION_DOWN
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(&keyArgs)); // ACTION_UP
+ ASSERT_EQ(BTN_GEAR_DOWN, keyArgs.scanCode);
+
+ controller->pressAndReleaseKey(BTN_GEAR_UP);
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(&keyArgs)); // ACTION_DOWN
+ ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasCalled(&keyArgs)); // ACTION_UP
+ ASSERT_EQ(BTN_GEAR_UP, keyArgs.scanCode);
+}
+
// --- TouchProcessTest ---
class TouchIntegrationTest : public InputReaderIntegrationTest {
protected:
diff --git a/services/inputflinger/tests/UinputDevice.cpp b/services/inputflinger/tests/UinputDevice.cpp
index 10e7293770..0659511d25 100644
--- a/services/inputflinger/tests/UinputDevice.cpp
+++ b/services/inputflinger/tests/UinputDevice.cpp
@@ -125,6 +125,9 @@ void UinputHomeKey::pressAndReleaseHomeKey() {
pressAndReleaseKey(KEY_HOME);
}
+// --- UinputSteamController
+UinputSteamController::UinputSteamController() : UinputKeyboard({BTN_GEAR_DOWN, BTN_GEAR_UP}) {}
+
// --- UinputTouchScreen ---
UinputTouchScreen::UinputTouchScreen(const Rect* size)
: UinputDevice(UinputTouchScreen::DEVICE_NAME), mSize(*size) {}
diff --git a/services/inputflinger/tests/UinputDevice.h b/services/inputflinger/tests/UinputDevice.h
index ec3cd9fdba..22d1f630fc 100644
--- a/services/inputflinger/tests/UinputDevice.h
+++ b/services/inputflinger/tests/UinputDevice.h
@@ -108,6 +108,16 @@ private:
UinputHomeKey();
};
+// A joystick device that sends a BTN_GEAR_DOWN / BTN_WHEEL key.
+class UinputSteamController : public UinputKeyboard {
+public:
+ template <class D, class... Ts>
+ friend std::unique_ptr<D> createUinputDevice(Ts... args);
+
+private:
+ UinputSteamController();
+};
+
// --- UinputTouchScreen ---
// A touch screen device with specific size.
class UinputTouchScreen : public UinputDevice {
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 81f2dd1e08..1faf775ed3 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -149,9 +149,9 @@ FloatRect OutputLayer::calculateOutputSourceCrop() const {
// a modification of the axes of rotation. To account for this we
// need to reorient the inverse rotation in terms of the current
// axes of rotation.
- bool is_h_flipped = (invTransform & HAL_TRANSFORM_FLIP_H) != 0;
- bool is_v_flipped = (invTransform & HAL_TRANSFORM_FLIP_V) != 0;
- if (is_h_flipped == is_v_flipped) {
+ bool isHFlipped = (invTransform & HAL_TRANSFORM_FLIP_H) != 0;
+ bool isVFlipped = (invTransform & HAL_TRANSFORM_FLIP_V) != 0;
+ if (isHFlipped == isVFlipped) {
invTransform ^= HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_FLIP_H;
}
std::swap(winWidth, winHeight);
@@ -160,18 +160,18 @@ FloatRect OutputLayer::calculateOutputSourceCrop() const {
activeCrop.transform(invTransform, bufferSize.getWidth(), bufferSize.getHeight());
// below, crop is intersected with winCrop expressed in crop's coordinate space
- float xScale = crop.getWidth() / float(winWidth);
- float yScale = crop.getHeight() / float(winHeight);
-
- float insetL = winCrop.left * xScale;
- float insetT = winCrop.top * yScale;
- float insetR = (winWidth - winCrop.right) * xScale;
- float insetB = (winHeight - winCrop.bottom) * yScale;
-
- crop.left += insetL;
- crop.top += insetT;
- crop.right -= insetR;
- crop.bottom -= insetB;
+ const float xScale = crop.getWidth() / float(winWidth);
+ const float yScale = crop.getHeight() / float(winHeight);
+
+ const float insetLeft = winCrop.left * xScale;
+ const float insetTop = winCrop.top * yScale;
+ const float insetRight = (winWidth - winCrop.right) * xScale;
+ const float insetBottom = (winHeight - winCrop.bottom) * yScale;
+
+ crop.left += insetLeft;
+ crop.top += insetTop;
+ crop.right -= insetRight;
+ crop.bottom -= insetBottom;
return crop;
}
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 9af9cad099..0c8aafc70f 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -158,19 +158,19 @@ void DisplayDevice::setProjection(ui::Rotation orientation, Rect viewport, Rect
mOrientation = orientation;
const Rect& displayBounds = getCompositionDisplay()->getState().bounds;
- const int w = displayBounds.width();
- const int h = displayBounds.height();
+ const int displayWidth = displayBounds.width();
+ const int displayHeight = displayBounds.height();
- ui::Transform R;
+ ui::Transform rotation;
if (const auto flags = ui::Transform::toRotationFlags(orientation);
flags != ui::Transform::ROT_INVALID) {
- R.set(flags, w, h);
+ rotation.set(flags, displayWidth, displayHeight);
}
if (!frame.isValid()) {
// the destination frame can be invalid if it has never been set,
// in that case we assume the whole display frame.
- frame = Rect(w, h);
+ frame = Rect(displayWidth, displayHeight);
}
if (viewport.isEmpty()) {
@@ -178,45 +178,45 @@ void DisplayDevice::setProjection(ui::Rotation orientation, Rect viewport, Rect
// we assume the whole display size.
// it's also invalid to have an empty viewport, so we handle that
// case in the same way.
- viewport = Rect(w, h);
- if (R.getOrientation() & ui::Transform::ROT_90) {
+ viewport = Rect(displayWidth, displayHeight);
+ if (rotation.getOrientation() & ui::Transform::ROT_90) {
// viewport is always specified in the logical orientation
// of the display (ie: post-rotation).
std::swap(viewport.right, viewport.bottom);
}
}
- ui::Transform TL, TP, S;
- float src_width = viewport.width();
- float src_height = viewport.height();
- float dst_width = frame.width();
- float dst_height = frame.height();
- if (src_width != dst_width || src_height != dst_height) {
- float sx = dst_width / src_width;
- float sy = dst_height / src_height;
- S.set(sx, 0, 0, sy);
+ ui::Transform logicalTranslation, physicalTranslation, scale;
+ const float sourceWidth = viewport.width();
+ const float sourceHeight = viewport.height();
+ const float destWidth = frame.width();
+ const float destHeight = frame.height();
+ if (sourceWidth != destWidth || sourceHeight != destHeight) {
+ const float scaleX = destWidth / sourceWidth;
+ const float scaleY = destHeight / sourceHeight;
+ scale.set(scaleX, 0, 0, scaleY);
}
- float src_x = viewport.left;
- float src_y = viewport.top;
- float dst_x = frame.left;
- float dst_y = frame.top;
- TL.set(-src_x, -src_y);
- TP.set(dst_x, dst_y);
+ const float sourceX = viewport.left;
+ const float sourceY = viewport.top;
+ const float destX = frame.left;
+ const float destY = frame.top;
+ logicalTranslation.set(-sourceX, -sourceY);
+ physicalTranslation.set(destX, destY);
// need to take care of primary display rotation for globalTransform
// for case if the panel is not installed aligned with device orientation
if (isPrimary()) {
if (const auto flags = ui::Transform::toRotationFlags(orientation + mPhysicalOrientation);
flags != ui::Transform::ROT_INVALID) {
- R.set(flags, w, h);
+ rotation.set(flags, displayWidth, displayHeight);
}
}
// The viewport and frame are both in the logical orientation.
// Apply the logical translation, scale to physical size, apply the
// physical translation and finally rotate to the physical orientation.
- ui::Transform globalTransform = R * TP * S * TL;
+ ui::Transform globalTransform = rotation * physicalTranslation * scale * logicalTranslation;
const uint8_t type = globalTransform.getType();
const bool needsFiltering =
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
index e6c5cc9700..120a60f8d8 100644
--- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -90,7 +90,7 @@ LayerHistoryV2::~LayerHistoryV2() = default;
void LayerHistoryV2::registerLayer(Layer* layer, float /*lowRefreshRate*/, float highRefreshRate,
LayerVoteType type) {
const nsecs_t highRefreshRatePeriod = static_cast<nsecs_t>(1e9f / highRefreshRate);
- auto info = std::make_unique<LayerInfoV2>(highRefreshRatePeriod, type);
+ auto info = std::make_unique<LayerInfoV2>(layer->getName(), highRefreshRatePeriod, type);
std::lock_guard lock(mLock);
mLayerInfos.emplace_back(layer, std::move(info));
}
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
index b7d0bdd101..255eac6efc 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp
@@ -27,8 +27,10 @@
namespace android::scheduler {
-LayerInfoV2::LayerInfoV2(nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote)
- : mHighRefreshRatePeriod(highRefreshRatePeriod),
+LayerInfoV2::LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod,
+ LayerHistory::LayerVoteType defaultVote)
+ : mName(name),
+ mHighRefreshRatePeriod(highRefreshRatePeriod),
mDefaultVote(defaultVote),
mLayerVote({defaultVote, 0.0f}) {}
@@ -45,42 +47,23 @@ void LayerInfoV2::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now) {
}
}
-bool LayerInfoV2::isFrameTimeValid(const FrameTimeData& frameTime) const {
- return frameTime.queueTime >= std::chrono::duration_cast<std::chrono::nanoseconds>(
- mFrameTimeValidSince.time_since_epoch())
- .count();
-}
-
bool LayerInfoV2::isFrequent(nsecs_t now) const {
- // Find the first valid frame time
- auto it = mFrameTimes.begin();
- for (; it != mFrameTimes.end(); ++it) {
- if (isFrameTimeValid(*it)) {
- break;
+ for (auto it = mFrameTimes.crbegin(); it != mFrameTimes.crend(); ++it) {
+ if (now - it->queueTime >= MAX_FREQUENT_LAYER_PERIOD_NS.count()) {
+ ALOGV("%s infrequent (last frame is %.2fms ago", mName.c_str(),
+ (now - mFrameTimes.back().queueTime) / 1e6f);
+ return false;
}
- }
- // If we know nothing about this layer we consider it as frequent as it might be the start
- // of an animation.
- if (std::distance(it, mFrameTimes.end()) < FREQUENT_LAYER_WINDOW_SIZE) {
- return true;
- }
-
- // Find the first active frame
- for (; it != mFrameTimes.end(); ++it) {
- if (it->queueTime >= getActiveLayerThreshold(now)) {
- break;
+ const auto numFrames = std::distance(mFrameTimes.crbegin(), it + 1);
+ if (numFrames >= FREQUENT_LAYER_WINDOW_SIZE) {
+ ALOGV("%s frequent (burst of %zu frames", mName.c_str(), numFrames);
+ return true;
}
}
- const auto numFrames = std::distance(it, mFrameTimes.end());
- if (numFrames < FREQUENT_LAYER_WINDOW_SIZE) {
- return false;
- }
-
- // Layer is considered frequent if the average frame rate is higher than the threshold
- const auto totalTime = mFrameTimes.back().queueTime - it->queueTime;
- return (1e9f * (numFrames - 1)) / totalTime >= MIN_FPS_FOR_FREQUENT_LAYER;
+ ALOGV("%s infrequent (not enough frames %zu)", mName.c_str(), mFrameTimes.size());
+ return false;
}
bool LayerInfoV2::hasEnoughDataForHeuristic() const {
@@ -89,10 +72,6 @@ bool LayerInfoV2::hasEnoughDataForHeuristic() const {
return false;
}
- if (!isFrameTimeValid(mFrameTimes.front())) {
- return false;
- }
-
if (mFrameTimes.size() < HISTORY_SIZE &&
mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) {
return false;
@@ -167,18 +146,22 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() {
std::pair<LayerHistory::LayerVoteType, float> LayerInfoV2::getRefreshRate(nsecs_t now) {
if (mLayerVote.type != LayerHistory::LayerVoteType::Heuristic) {
+ ALOGV("%s voted %d ", mName.c_str(), static_cast<int>(mLayerVote.type));
return {mLayerVote.type, mLayerVote.fps};
}
if (!isFrequent(now)) {
+ ALOGV("%s is infrequent", mName.c_str());
return {LayerHistory::LayerVoteType::Min, 0};
}
auto refreshRate = calculateRefreshRateIfPossible();
if (refreshRate.has_value()) {
+ ALOGV("%s calculated refresh rate: %.2f", mName.c_str(), refreshRate.value());
return {LayerHistory::LayerVoteType::Heuristic, refreshRate.value()};
}
+ ALOGV("%s Max (can't resolve refresh rate", mName.c_str());
return {LayerHistory::LayerVoteType::Max, 0};
}
diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h
index e36b7f709e..97c7017648 100644
--- a/services/surfaceflinger/Scheduler/LayerInfoV2.h
+++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h
@@ -54,7 +54,8 @@ class LayerInfoV2 {
friend class LayerHistoryTestV2;
public:
- LayerInfoV2(nsecs_t highRefreshRatePeriod, LayerHistory::LayerVoteType defaultVote);
+ LayerInfoV2(const std::string& name, nsecs_t highRefreshRatePeriod,
+ LayerHistory::LayerVoteType defaultVote);
LayerInfoV2(const LayerInfo&) = delete;
LayerInfoV2& operator=(const LayerInfoV2&) = delete;
@@ -83,11 +84,7 @@ public:
nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; }
void clearHistory() {
- // Mark mFrameTimeValidSince to now to ignore all previous frame times.
- // We are not deleting the old frame to keep track of whether we should treat the first
- // buffer as Max as we don't know anything about this layer or Min as this layer is
- // posting infrequent updates.
- mFrameTimeValidSince = std::chrono::steady_clock::now();
+ mFrameTimes.clear();
mLastReportedRefreshRate = 0.0f;
}
@@ -101,7 +98,8 @@ private:
bool isFrequent(nsecs_t now) const;
bool hasEnoughDataForHeuristic() const;
std::optional<float> calculateRefreshRateIfPossible();
- bool isFrameTimeValid(const FrameTimeData&) const;
+
+ const std::string mName;
// Used for sanitizing the heuristic data
const nsecs_t mHighRefreshRatePeriod;
@@ -118,8 +116,6 @@ private:
} mLayerVote;
std::deque<FrameTimeData> mFrameTimes;
- std::chrono::time_point<std::chrono::steady_clock> mFrameTimeValidSince =
- std::chrono::steady_clock::now();
static constexpr size_t HISTORY_SIZE = 90;
static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s;
};
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 8d958df572..69b1a3c261 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -103,7 +103,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
ATRACE_CALL();
ALOGV("getRefreshRateForContent %zu layers", layers.size());
- *touchConsidered = false;
+ if (touchConsidered) *touchConsidered = false;
std::lock_guard lock(mLock);
int noVoteLayers = 0;
@@ -131,7 +131,8 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
// Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
// selected a refresh rate to see if we should apply touch boost.
if (touchActive && explicitDefaultVoteLayers == 0 && explicitExactOrMultipleVoteLayers == 0) {
- *touchConsidered = true;
+ ALOGV("TouchBoost - choose %s", getMaxRefreshRateByPolicyLocked().getName().c_str());
+ if (touchConsidered) *touchConsidered = true;
return getMaxRefreshRateByPolicyLocked();
}
@@ -145,6 +146,7 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
// Only if all layers want Min we should return Min
if (noVoteLayers + minVoteLayers == layers.size()) {
+ ALOGV("all layers Min - choose %s", getMinRefreshRateByPolicyLocked().getName().c_str());
return getMinRefreshRateByPolicyLocked();
}
@@ -243,9 +245,11 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
return 1.0f / iter;
}();
- ALOGV("%s (ExplicitExactOrMultiple, weight %.2f) %.2fHz gives %s score of %.2f",
- layer.name.c_str(), weight, 1e9f / layerPeriod, scores[i].first->name.c_str(),
- layerScore);
+ ALOGV("%s (%s, weight %.2f) %.2fHz gives %s score of %.2f", layer.name.c_str(),
+ layer.vote == LayerVoteType::ExplicitExactOrMultiple
+ ? "ExplicitExactOrMultiple"
+ : "Heuristic",
+ weight, 1e9f / layerPeriod, scores[i].first->name.c_str(), layerScore);
scores[i].second += weight * layerScore;
continue;
}
@@ -266,7 +270,8 @@ const RefreshRate& RefreshRateConfigs::getBestRefreshRate(
const RefreshRate& touchRefreshRate = getMaxRefreshRateByPolicyLocked();
if (touchActive && explicitDefaultVoteLayers == 0 &&
bestRefreshRate->fps < touchRefreshRate.fps) {
- *touchConsidered = true;
+ if (touchConsidered) *touchConsidered = true;
+ ALOGV("TouchBoost - choose %s", touchRefreshRate.getName().c_str());
return touchRefreshRate;
}
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index d73fd8bee5..00f87bbf59 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -66,15 +66,15 @@ std::unique_ptr<DispSync> createDispSync() {
// TODO (140302863) remove this and use the vsync_reactor system.
if (property_get_bool("debug.sf.vsync_reactor", true)) {
// TODO (144707443) tune Predictor tunables.
- static constexpr int default_rate = 60;
- static constexpr auto initial_period =
- std::chrono::duration<nsecs_t, std::ratio<1, default_rate>>(1);
+ static constexpr int defaultRate = 60;
+ static constexpr auto initialPeriod =
+ std::chrono::duration<nsecs_t, std::ratio<1, defaultRate>>(1);
static constexpr size_t vsyncTimestampHistorySize = 20;
static constexpr size_t minimumSamplesForPrediction = 6;
static constexpr uint32_t discardOutlierPercent = 20;
auto tracker = std::make_unique<
scheduler::VSyncPredictor>(std::chrono::duration_cast<std::chrono::nanoseconds>(
- initial_period)
+ initialPeriod)
.count(),
vsyncTimestampHistorySize, minimumSamplesForPrediction,
discardOutlierPercent);
@@ -526,7 +526,9 @@ void Scheduler::idleTimerCallback(TimerState state) {
void Scheduler::touchTimerCallback(TimerState state) {
const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive;
- handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */);
+ if (handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */)) {
+ mLayerHistory->clear();
+ }
ATRACE_INT("TouchState", static_cast<int>(touch));
}
@@ -549,18 +551,19 @@ void Scheduler::dump(std::string& result) const {
}
template <class T>
-void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) {
+bool Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection) {
ConfigEvent event = ConfigEvent::None;
HwcConfigIndexType newConfigId;
+ bool touchConsidered = false;
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
if (*currentState == newState) {
- return;
+ return touchConsidered;
}
*currentState = newState;
- newConfigId = calculateRefreshRateConfigIndexType();
+ newConfigId = calculateRefreshRateConfigIndexType(&touchConsidered);
if (mFeatures.configId == newConfigId) {
- return;
+ return touchConsidered;
}
mFeatures.configId = newConfigId;
if (eventOnContentDetection && !mFeatures.contentRequirements.empty()) {
@@ -569,10 +572,12 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO
}
const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
mSchedulerCallback.changeRefreshRate(newRefreshRate, event);
+ return touchConsidered;
}
-HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() {
+HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType(bool* touchConsidered) {
ATRACE_CALL();
+ if (touchConsidered) *touchConsidered = false;
// If Display Power is not in normal operation we want to be in performance mode. When coming
// back to normal mode, a grace period is given with DisplayPowerTimer.
@@ -607,18 +612,9 @@ HwcConfigIndexType Scheduler::calculateRefreshRateConfigIndexType() {
.getConfigId();
}
- bool touchConsidered;
- const auto& ret = mRefreshRateConfigs
- .getBestRefreshRate(mFeatures.contentRequirements, touchActive, idle,
- &touchConsidered)
- .getConfigId();
- if (touchConsidered) {
- // Clear layer history if refresh rate was selected based on touch to allow
- // the hueristic to pick up with the new rate.
- mLayerHistory->clear();
- }
-
- return ret;
+ return mRefreshRateConfigs
+ .getBestRefreshRate(mFeatures.contentRequirements, touchActive, idle, touchConsidered)
+ .getConfigId();
}
std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 4a0280fe1e..6eabfd2e47 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -177,14 +177,15 @@ private:
// handles various timer features to change the refresh rate.
template <class T>
- void handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection);
+ bool handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection);
void setVsyncPeriod(nsecs_t period);
// This function checks whether individual features that are affecting the refresh rate
// selection were initialized, prioritizes them, and calculates the HwcConfigIndexType
// for the suggested refresh rate.
- HwcConfigIndexType calculateRefreshRateConfigIndexType() REQUIRES(mFeatureStateLock);
+ HwcConfigIndexType calculateRefreshRateConfigIndexType(bool* touchConsidered = nullptr)
+ REQUIRES(mFeatureStateLock);
// Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
struct Connection {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ddda21d28d..18f789eacc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -125,6 +125,19 @@
#include "android-base/parseint.h"
#include "android-base/stringprintf.h"
+#define MAIN_THREAD ACQUIRE(mStateLock) RELEASE(mStateLock)
+
+#define ON_MAIN_THREAD(expr) \
+ [&] { \
+ LOG_FATAL_IF(std::this_thread::get_id() != mMainThreadId); \
+ UnnecessaryLock lock(mStateLock); \
+ return (expr); \
+ }()
+
+#undef NO_THREAD_SAFETY_ANALYSIS
+#define NO_THREAD_SAFETY_ANALYSIS \
+ _Pragma("GCC error \"Prefer MAIN_THREAD macros or {Conditional,Timed,Unnecessary}Lock.\"")
+
namespace android {
using namespace std::string_literals;
@@ -173,12 +186,12 @@ bool isWideColorMode(const ColorMode colorMode) {
#pragma clang diagnostic pop
template <typename Mutex>
-struct ConditionalLockGuard {
- ConditionalLockGuard(Mutex& mutex, bool lock) : mutex(mutex), lock(lock) {
+struct SCOPED_CAPABILITY ConditionalLockGuard {
+ ConditionalLockGuard(Mutex& mutex, bool lock) ACQUIRE(mutex) : mutex(mutex), lock(lock) {
if (lock) mutex.lock();
}
- ~ConditionalLockGuard() {
+ ~ConditionalLockGuard() RELEASE() {
if (lock) mutex.unlock();
}
@@ -188,6 +201,27 @@ struct ConditionalLockGuard {
using ConditionalLock = ConditionalLockGuard<Mutex>;
+struct SCOPED_CAPABILITY TimedLock {
+ TimedLock(Mutex& mutex, nsecs_t timeout, const char* whence) ACQUIRE(mutex)
+ : mutex(mutex), status(mutex.timedLock(timeout)) {
+ ALOGE_IF(!locked(), "%s timed out locking: %s (%d)", whence, strerror(-status), status);
+ }
+
+ ~TimedLock() RELEASE() {
+ if (locked()) mutex.unlock();
+ }
+
+ bool locked() const { return status == NO_ERROR; }
+
+ Mutex& mutex;
+ const status_t status;
+};
+
+struct SCOPED_CAPABILITY UnnecessaryLock {
+ explicit UnnecessaryLock(Mutex& mutex) ACQUIRE(mutex) {}
+ ~UnnecessaryLock() RELEASE() {}
+};
+
// TODO(b/141333600): Consolidate with HWC2::Display::Config::Builder::getDefaultDensity.
constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV;
@@ -991,7 +1025,7 @@ status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mo
}
auto future = schedule([=]() -> status_t {
- const auto display = getDisplayDeviceLocked(displayToken);
+ const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken));
if (!display) {
ALOGE("Attempt to set allowed display configs for invalid display token %p",
displayToken.get());
@@ -1176,7 +1210,7 @@ ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& displayToken) {
}
status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
- schedule([=] {
+ schedule([=]() MAIN_THREAD {
Vector<ColorMode> modes;
getDisplayColorModes(displayToken, &modes);
bool exists = std::find(std::begin(modes), std::end(modes), mode) != std::end(modes);
@@ -1222,7 +1256,7 @@ status_t SurfaceFlinger::getAutoLowLatencyModeSupport(const sp<IBinder>& display
}
void SurfaceFlinger::setAutoLowLatencyMode(const sp<IBinder>& displayToken, bool on) {
- static_cast<void>(schedule([=] {
+ static_cast<void>(schedule([=]() MAIN_THREAD {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
getHwComposer().setAutoLowLatencyMode(*displayId, on);
} else {
@@ -1253,7 +1287,7 @@ status_t SurfaceFlinger::getGameContentTypeSupport(const sp<IBinder>& displayTok
}
void SurfaceFlinger::setGameContentType(const sp<IBinder>& displayToken, bool on) {
- static_cast<void>(schedule([=] {
+ static_cast<void>(schedule([=]() MAIN_THREAD {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
const auto type = on ? hal::ContentType::GAME : hal::ContentType::NONE;
getHwComposer().setContentType(*displayId, type);
@@ -1343,7 +1377,7 @@ status_t SurfaceFlinger::getDisplayedContentSamplingAttributes(const sp<IBinder>
status_t SurfaceFlinger::setDisplayContentSamplingEnabled(const sp<IBinder>& displayToken,
bool enable, uint8_t componentMask,
uint64_t maxFrames) {
- return schedule([=]() -> status_t {
+ return schedule([=]() MAIN_THREAD -> status_t {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
return getHwComposer().setDisplayContentSamplingEnabled(*displayId, enable,
componentMask,
@@ -1412,13 +1446,9 @@ status_t SurfaceFlinger::injectVSync(nsecs_t when) {
return mScheduler->injectVSync(when, calculateExpectedPresentTime(when)) ? NO_ERROR : BAD_VALUE;
}
-status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const
- NO_THREAD_SAFETY_ANALYSIS {
- // Try to acquire a lock for 1s, fail gracefully
- const status_t err = mStateLock.timedLock(s2ns(1));
- const bool locked = (err == NO_ERROR);
- if (!locked) {
- ALOGE("LayerDebugInfo: SurfaceFlinger unresponsive (%s [%d]) - exit", strerror(-err), err);
+status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const {
+ TimedLock lock(mStateLock, s2ns(1), __FUNCTION__);
+ if (!lock.locked()) {
return TIMED_OUT;
}
@@ -1427,7 +1457,6 @@ status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayer
mCurrentState.traverseInZOrder(
[&](Layer* layer) { outLayers->push_back(layer->getLayerDebugInfo(display.get())); });
- mStateLock.unlock();
return NO_ERROR;
}
@@ -1484,7 +1513,7 @@ status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken, f
return BAD_VALUE;
}
- return promise::chain(schedule([=] {
+ return promise::chain(schedule([=]() MAIN_THREAD {
if (const auto displayId = getPhysicalDisplayIdLocked(displayToken)) {
return getHwComposer().setDisplayBrightness(*displayId, brightness);
} else {
@@ -1597,7 +1626,7 @@ void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate,
}
void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId,
- hal::Connection connection) NO_THREAD_SAFETY_ANALYSIS {
+ hal::Connection connection) {
ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId,
connection == hal::Connection::CONNECTED ? "connected" : "disconnected");
@@ -1650,8 +1679,7 @@ void SurfaceFlinger::setPrimaryVsyncEnabled(bool enabled) {
// Enable / Disable HWVsync from the main thread to avoid race conditions with
// display power state.
- static_cast<void>(
- schedule([=]() NO_THREAD_SAFETY_ANALYSIS { setPrimaryVsyncEnabledInternal(enabled); }));
+ static_cast<void>(schedule([=]() MAIN_THREAD { setPrimaryVsyncEnabledInternal(enabled); }));
}
void SurfaceFlinger::setPrimaryVsyncEnabledInternal(bool enabled) {
@@ -1667,7 +1695,6 @@ void SurfaceFlinger::setPrimaryVsyncEnabledInternal(bool enabled) {
}
}
-// Note: it is assumed the caller holds |mStateLock| when this is called
void SurfaceFlinger::resetDisplayState() {
mScheduler->disableHardwareVsync(true);
// Clear the drawing state so that the logic inside of
@@ -1760,7 +1787,7 @@ void SurfaceFlinger::updateVrFlinger() {
setTransactionFlags(eDisplayTransactionNeeded);
}
-sp<Fence> SurfaceFlinger::previousFrameFence() NO_THREAD_SAFETY_ANALYSIS {
+sp<Fence> SurfaceFlinger::previousFrameFence() {
// We are storing the last 2 present fences. If sf's phase offset is to be
// woken up before the actual vsync but targeting the next vsync, we need to check
// fence N-2
@@ -1768,7 +1795,7 @@ sp<Fence> SurfaceFlinger::previousFrameFence() NO_THREAD_SAFETY_ANALYSIS {
: mPreviousPresentFences[1];
}
-bool SurfaceFlinger::previousFramePending(int graceTimeMs) NO_THREAD_SAFETY_ANALYSIS {
+bool SurfaceFlinger::previousFramePending(int graceTimeMs) {
ATRACE_CALL();
const sp<Fence>& fence = previousFrameFence();
@@ -1782,7 +1809,7 @@ bool SurfaceFlinger::previousFramePending(int graceTimeMs) NO_THREAD_SAFETY_ANAL
return status == -ETIME;
}
-nsecs_t SurfaceFlinger::previousFramePresentTime() NO_THREAD_SAFETY_ANALYSIS {
+nsecs_t SurfaceFlinger::previousFramePresentTime() {
const sp<Fence>& fence = previousFrameFence();
if (fence == Fence::NO_FENCE) {
@@ -1800,8 +1827,7 @@ nsecs_t SurfaceFlinger::calculateExpectedPresentTime(nsecs_t now) const {
return mVSyncModulator->getOffsets().sf > 0 ? presentTime : presentTime + stats.vsyncPeriod;
}
-void SurfaceFlinger::onMessageReceived(int32_t what,
- nsecs_t expectedVSyncTime) NO_THREAD_SAFETY_ANALYSIS {
+void SurfaceFlinger::onMessageReceived(int32_t what, nsecs_t expectedVSyncTime) {
ATRACE_CALL();
switch (what) {
case MessageQueue::INVALIDATE: {
@@ -1815,7 +1841,7 @@ void SurfaceFlinger::onMessageReceived(int32_t what,
}
}
-void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) NO_THREAD_SAFETY_ANALYSIS {
+void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) {
ATRACE_CALL();
const nsecs_t frameStart = systemTime();
@@ -1888,7 +1914,7 @@ void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) NO_THREAD_SA
// We received the present fence from the HWC, so we assume it successfully updated
// the config, hence we update SF.
mSetActiveConfigPending = false;
- setActiveConfigInternal();
+ ON_MAIN_THREAD(setActiveConfigInternal());
}
if (framePending && mPropagateBackpressure) {
@@ -1907,12 +1933,12 @@ void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) NO_THREAD_SA
std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
// If we're in a user build then don't push any atoms
if (!mIsUserBuild && mMissedFrameJankCount > 0) {
- const auto displayDevice = getDefaultDisplayDeviceLocked();
+ const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
// Only report jank when the display is on, as displays in DOZE
// power mode may operate at a different frame rate than is
// reported in their config, which causes noticeable (but less
// severe) jank.
- if (displayDevice && displayDevice->getPowerMode() == hal::PowerMode::ON) {
+ if (display && display->getPowerMode() == hal::PowerMode::ON) {
const nsecs_t currentTime = systemTime();
const nsecs_t jankDuration = currentTime - mMissedFrameJankStart;
if (jankDuration > kMinJankyDuration && jankDuration < kMaxJankyDuration) {
@@ -1965,7 +1991,7 @@ void SurfaceFlinger::onMessageInvalidate(nsecs_t expectedVSyncTime) NO_THREAD_SA
mScheduler->chooseRefreshRateForContent();
}
- performSetActiveConfig();
+ ON_MAIN_THREAD(performSetActiveConfig());
updateCursorAsync();
updateInputFlinger();
@@ -2014,8 +2040,9 @@ void SurfaceFlinger::onMessageRefresh() {
mRefreshPending = false;
compositionengine::CompositionRefreshArgs refreshArgs;
- refreshArgs.outputs.reserve(mDisplays.size());
- for (const auto& [_, display] : mDisplays) {
+ const auto& displays = ON_MAIN_THREAD(mDisplays);
+ refreshArgs.outputs.reserve(displays.size());
+ for (const auto& [_, display] : displays) {
refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) {
@@ -2070,21 +2097,18 @@ void SurfaceFlinger::onMessageRefresh() {
const bool prevFrameHadDeviceComposition = mHadDeviceComposition;
- mHadClientComposition =
- std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
- auto& displayDevice = tokenDisplayPair.second;
- return displayDevice->getCompositionDisplay()->getState().usesClientComposition &&
- !displayDevice->getCompositionDisplay()->getState().reusedClientComposition;
- });
- mHadDeviceComposition =
- std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
- auto& displayDevice = tokenDisplayPair.second;
- return displayDevice->getCompositionDisplay()->getState().usesDeviceComposition;
- });
+ mHadClientComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
+ const auto& state = pair.second->getCompositionDisplay()->getState();
+ return state.usesClientComposition && !state.reusedClientComposition;
+ });
+ mHadDeviceComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
+ const auto& state = pair.second->getCompositionDisplay()->getState();
+ return state.usesDeviceComposition;
+ });
mReusedClientComposition =
- std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
- auto& displayDevice = tokenDisplayPair.second;
- return displayDevice->getCompositionDisplay()->getState().reusedClientComposition;
+ std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
+ const auto& state = pair.second->getCompositionDisplay()->getState();
+ return state.reusedClientComposition;
});
// Only report a strategy change if we move in and out of composition with hw overlays
@@ -2190,14 +2214,14 @@ void SurfaceFlinger::postComposition()
for (auto& layer : mLayersWithQueuedFrames) {
layer->releasePendingBuffer(dequeueReadyTime);
}
- // |mStateLock| not needed as we are on the main thread
- const auto displayDevice = getDefaultDisplayDeviceLocked();
+
+ const auto* display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked()).get();
getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
- if (displayDevice && displayDevice->getCompositionDisplay()->getState().usesClientComposition) {
+ if (display && display->getCompositionDisplay()->getState().usesClientComposition) {
glCompositionDoneFenceTime =
- std::make_shared<FenceTime>(displayDevice->getCompositionDisplay()
+ std::make_shared<FenceTime>(display->getCompositionDisplay()
->getRenderSurface()
->getClientTargetAcquireFence());
getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
@@ -2207,9 +2231,8 @@ void SurfaceFlinger::postComposition()
getBE().mDisplayTimeline.updateSignalTimes();
mPreviousPresentFences[1] = mPreviousPresentFences[0];
- mPreviousPresentFences[0] = displayDevice
- ? getHwComposer().getPresentFence(*displayDevice->getId())
- : Fence::NO_FENCE;
+ mPreviousPresentFences[0] =
+ display ? getHwComposer().getPresentFence(*display->getId()) : Fence::NO_FENCE;
auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0]);
getBE().mDisplayTimeline.push(presentFenceTime);
@@ -2228,9 +2251,8 @@ void SurfaceFlinger::postComposition()
}
mDrawingState.traverse([&](Layer* layer) {
- const bool frameLatched =
- layer->onPostComposition(displayDevice.get(), glCompositionDoneFenceTime,
- presentFenceTime, compositorTiming);
+ const bool frameLatched = layer->onPostComposition(display, glCompositionDoneFenceTime,
+ presentFenceTime, compositorTiming);
if (frameLatched) {
recordBufferingStats(layer->getName(), layer->getOccupancyHistory(false));
}
@@ -2239,14 +2261,15 @@ void SurfaceFlinger::postComposition()
mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]);
mTransactionCompletedThread.sendCallbacks();
- if (displayDevice && displayDevice->isPrimary() &&
- displayDevice->getPowerMode() == hal::PowerMode::ON && presentFenceTime->isValid()) {
+ if (display && display->isPrimary() && display->getPowerMode() == hal::PowerMode::ON &&
+ presentFenceTime->isValid()) {
mScheduler->addPresentFence(presentFenceTime);
}
+ const bool isDisplayConnected = display && getHwComposer().isConnected(*display->getId());
+
if (!hasSyncFramework) {
- if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
- displayDevice->isPoweredOn()) {
+ if (isDisplayConnected && display->isPoweredOn()) {
mScheduler->enableHardwareVsync();
}
}
@@ -2257,11 +2280,10 @@ void SurfaceFlinger::postComposition()
if (presentFenceTime->isValid()) {
mAnimFrameTracker.setActualPresentFence(
std::move(presentFenceTime));
- } else if (displayDevice && getHwComposer().isConnected(*displayDevice->getId())) {
+ } else if (isDisplayConnected) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
- const nsecs_t presentTime =
- getHwComposer().getRefreshTimestamp(*displayDevice->getId());
+ const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(*display->getId());
mAnimFrameTracker.setActualPresentTime(presentTime);
}
mAnimFrameTracker.advanceFrame();
@@ -2282,8 +2304,7 @@ void SurfaceFlinger::postComposition()
const size_t appConnections = mScheduler->getEventThreadConnectionCount(mAppConnectionHandle);
mTimeStats->recordDisplayEventConnectionCount(sfConnections + appConnections);
- if (displayDevice && getHwComposer().isConnected(*displayDevice->getId()) &&
- !displayDevice->isPoweredOn()) {
+ if (isDisplayConnected && !display->isPoweredOn()) {
return;
}
@@ -2339,7 +2360,7 @@ FloatRect SurfaceFlinger::getLayerClipBoundsForDisplay(const DisplayDevice& disp
}
void SurfaceFlinger::computeLayerBounds() {
- for (const auto& pair : mDisplays) {
+ for (const auto& pair : ON_MAIN_THREAD(mDisplays)) {
const auto& displayDevice = pair.second;
const auto display = displayDevice->getCompositionDisplay();
for (const auto& layer : mDrawingState.layersSortedByZ) {
@@ -2354,10 +2375,8 @@ void SurfaceFlinger::computeLayerBounds() {
}
}
-void SurfaceFlinger::postFrame()
-{
- // |mStateLock| not needed as we are on the main thread
- const auto display = getDefaultDisplayDeviceLocked();
+void SurfaceFlinger::postFrame() {
+ const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
if (display && getHwComposer().isConnected(*display->getId())) {
uint32_t flipCount = display->getPageFlipCount();
if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
@@ -2785,7 +2804,7 @@ void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
sp<const DisplayDevice> hintDisplay;
uint32_t currentlayerStack = 0;
bool first = true;
- mCurrentState.traverse([&](Layer* layer) {
+ mCurrentState.traverse([&](Layer* layer) REQUIRES(mStateLock) {
// NOTE: we rely on the fact that layers are sorted by
// layerStack first (so we don't have to traverse the list
// of displays for every layer).
@@ -2898,10 +2917,9 @@ void SurfaceFlinger::commitInputWindowCommands() {
mPendingInputWindowCommands.clear();
}
-void SurfaceFlinger::updateCursorAsync()
-{
+void SurfaceFlinger::updateCursorAsync() {
compositionengine::CompositionRefreshArgs refreshArgs;
- for (const auto& [_, display] : mDisplays) {
+ for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
if (display->getId()) {
refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
@@ -2911,7 +2929,7 @@ void SurfaceFlinger::updateCursorAsync()
}
void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate,
- Scheduler::ConfigEvent event) NO_THREAD_SAFETY_ANALYSIS {
+ Scheduler::ConfigEvent event) {
// If this is called from the main thread mStateLock must be locked before
// Currently the only way to call this function from the main thread is from
// Sheduler::chooseRefreshRateForContent
@@ -3037,7 +3055,7 @@ void SurfaceFlinger::commitOffscreenLayers() {
}
void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
- for (const auto& [token, displayDevice] : mDisplays) {
+ for (const auto& [token, displayDevice] : ON_MAIN_THREAD(mDisplays)) {
auto display = displayDevice->getCompositionDisplay();
if (display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
display->editState().dirtyRegion.orSelf(dirty);
@@ -4133,7 +4151,7 @@ void SurfaceFlinger::onInitializeDisplays() {
void SurfaceFlinger::initializeDisplays() {
// Async since we may be called from the main thread.
- static_cast<void>(schedule([this]() NO_THREAD_SAFETY_ANALYSIS { onInitializeDisplays(); }));
+ static_cast<void>(schedule([this]() MAIN_THREAD { onInitializeDisplays(); }));
}
void SurfaceFlinger::setVsyncEnabledInHWC(DisplayId displayId, hal::Vsync enabled) {
@@ -4224,7 +4242,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal:
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
- schedule([=]() NO_THREAD_SAFETY_ANALYSIS {
+ schedule([=]() MAIN_THREAD {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
@@ -4237,8 +4255,7 @@ void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
}).wait();
}
-status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args,
- bool asProto) NO_THREAD_SAFETY_ANALYSIS {
+status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args, bool asProto) {
std::string result;
IPCThreadState* ipc = IPCThreadState::self();
@@ -4250,18 +4267,6 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args,
StringAppendF(&result, "Permission Denial: can't dump SurfaceFlinger from pid=%d, uid=%d\n",
pid, uid);
} else {
- // Try to get the main lock, but give up after one second
- // (this would indicate SF is stuck, but we want to be able to
- // print something in dumpsys).
- status_t err = mStateLock.timedLock(s2ns(1));
- bool locked = (err == NO_ERROR);
- if (!locked) {
- StringAppendF(&result,
- "SurfaceFlinger appears to be unresponsive (%s [%d]), dumping anyways "
- "(no locks held)\n",
- strerror(-err), err);
- }
-
static const std::unordered_map<std::string, Dumper> dumpers = {
{"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
{"--dispsync"s,
@@ -4279,18 +4284,23 @@ status_t SurfaceFlinger::doDump(int fd, const DumpArgs& args,
const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
- const auto it = dumpers.find(flag);
- if (it != dumpers.end()) {
- (it->second)(args, asProto, result);
- } else if (!asProto) {
- dumpAllLocked(args, result);
- }
+ bool dumpLayers = true;
+ {
+ TimedLock lock(mStateLock, s2ns(1), __FUNCTION__);
+ if (!lock.locked()) {
+ StringAppendF(&result, "Dumping without lock after timeout: %s (%d)\n",
+ strerror(-lock.status), lock.status);
+ }
- if (locked) {
- mStateLock.unlock();
+ if (const auto it = dumpers.find(flag); it != dumpers.end()) {
+ (it->second)(args, asProto, result);
+ dumpLayers = false;
+ } else if (!asProto) {
+ dumpAllLocked(args, result);
+ }
}
- if (it == dumpers.end()) {
+ if (dumpLayers) {
const LayersProto layersProto = dumpProtoFromMainThread();
if (asProto) {
result.append(layersProto.SerializeAsString());
@@ -4564,7 +4574,7 @@ void SurfaceFlinger::dumpWideColorInfo(std::string& result) const {
LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
// If context is SurfaceTracing thread, mTracingLock blocks display transactions on main thread.
- const auto display = getDefaultDisplayDeviceLocked();
+ const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
LayersProto layersProto;
for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) {
@@ -5400,7 +5410,7 @@ status_t SurfaceFlinger::setSchedFifo(bool enabled) {
return NO_ERROR;
}
-const sp<DisplayDevice> SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) {
+sp<DisplayDevice> SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) {
const sp<IBinder> displayToken = getPhysicalDisplayTokenLocked(DisplayId{displayOrLayerStack});
if (displayToken) {
return getDisplayDeviceLocked(displayToken);
@@ -5410,7 +5420,7 @@ const sp<DisplayDevice> SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t disp
return getDisplayByLayerStack(displayOrLayerStack);
}
-const sp<DisplayDevice> SurfaceFlinger::getDisplayByLayerStack(uint64_t layerStack) {
+sp<DisplayDevice> SurfaceFlinger::getDisplayByLayerStack(uint64_t layerStack) {
for (const auto& [token, display] : mDisplays) {
if (display->getLayerStack() == layerStack) {
return display;
@@ -5985,7 +5995,7 @@ status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& display
}
auto future = schedule([=]() -> status_t {
- const auto display = getDisplayDeviceLocked(displayToken);
+ const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken));
if (!display) {
ALOGE("Attempt to set desired display configs for invalid display token %p",
displayToken.get());
@@ -6140,7 +6150,7 @@ status_t SurfaceFlinger::setFrameRate(const sp<IGraphicBufferProducer>& surface,
return BAD_VALUE;
}
- static_cast<void>(schedule([=]() NO_THREAD_SAFETY_ANALYSIS {
+ static_cast<void>(schedule([=] {
Mutex::Autolock lock(mStateLock);
if (authenticateSurfaceTextureLocked(surface)) {
sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
@@ -6169,8 +6179,7 @@ status_t SurfaceFlinger::acquireFrameRateFlexibilityToken(sp<IBinder>* outToken)
sp<IBinder> token;
if (mFrameRateFlexibilityTokenCount == 0) {
- // |mStateLock| not needed as we are on the main thread
- const auto display = getDefaultDisplayDeviceLocked();
+ const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
// This is a little racy, but not in a way that hurts anything. As we grab the
// defaultConfig from the display manager policy, we could be setting a new display
@@ -6220,8 +6229,7 @@ void SurfaceFlinger::onFrameRateFlexibilityTokenReleased() {
mFrameRateFlexibilityTokenCount--;
ALOGD("Frame rate flexibility token released. count=%d", mFrameRateFlexibilityTokenCount);
if (mFrameRateFlexibilityTokenCount == 0) {
- // |mStateLock| not needed as we are on the main thread
- const auto display = getDefaultDisplayDeviceLocked();
+ const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
constexpr bool kOverridePolicy = true;
status_t result = setDesiredDisplayConfigSpecsInternal(display, {}, kOverridePolicy);
LOG_ALWAYS_FATAL_IF(result < 0, "Failed releasing frame rate flexibility token");
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 509de0fb18..4cfbdddc31 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -289,12 +289,6 @@ public:
// The CompositionEngine encapsulates all composition related interfaces and actions.
compositionengine::CompositionEngine& getCompositionEngine() const;
- // returns the default Display
- sp<const DisplayDevice> getDefaultDisplayDevice() {
- Mutex::Autolock _l(mStateLock);
- return getDefaultDisplayDeviceLocked();
- }
-
// Obtains a name from the texture pool, or, if the pool is empty, posts a
// synchronous message to the main thread to obtain one on the fly
uint32_t getNewTexture();
@@ -307,7 +301,7 @@ public:
void setPrimaryVsyncEnabled(bool enabled);
// main thread function to enable/disable h/w composer event
- void setPrimaryVsyncEnabledInternal(bool enabled);
+ void setPrimaryVsyncEnabledInternal(bool enabled) REQUIRES(mStateLock);
void setVsyncEnabledInHWC(DisplayId displayId, hal::Vsync enabled);
// called on the main thread by MessageQueue when an internal message
@@ -722,8 +716,8 @@ private:
status_t captureScreenCommon(RenderArea& renderArea, TraverseLayersFunction traverseLayers,
const sp<GraphicBuffer>& buffer, bool useIdentityTransform,
bool regionSampling, bool& outCapturedSecureLayers);
- const sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack);
- const sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack);
+ sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock);
+ sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock);
status_t captureScreenImplLocked(const RenderArea& renderArea,
TraverseLayersFunction traverseLayers,
ANativeWindowBuffer* buffer, bool useIdentityTransform,
@@ -751,28 +745,32 @@ private:
// called when starting, or restarting after system_server death
void initializeDisplays();
- // NOTE: can only be called from the main thread or with mStateLock held
- sp<const DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) const {
+ sp<const DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) const
+ REQUIRES(mStateLock) {
return const_cast<SurfaceFlinger*>(this)->getDisplayDeviceLocked(displayToken);
}
- // NOTE: can only be called from the main thread or with mStateLock held
- sp<DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) {
+ sp<DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) REQUIRES(mStateLock) {
const auto it = mDisplays.find(displayToken);
return it == mDisplays.end() ? nullptr : it->second;
}
- sp<const DisplayDevice> getDefaultDisplayDeviceLocked() const {
+ sp<const DisplayDevice> getDefaultDisplayDeviceLocked() const REQUIRES(mStateLock) {
return const_cast<SurfaceFlinger*>(this)->getDefaultDisplayDeviceLocked();
}
- sp<DisplayDevice> getDefaultDisplayDeviceLocked() {
+ sp<DisplayDevice> getDefaultDisplayDeviceLocked() REQUIRES(mStateLock) {
if (const auto token = getInternalDisplayTokenLocked()) {
return getDisplayDeviceLocked(token);
}
return nullptr;
}
+ sp<const DisplayDevice> getDefaultDisplayDevice() EXCLUDES(mStateLock) {
+ Mutex::Autolock lock(mStateLock);
+ return getDefaultDisplayDeviceLocked();
+ }
+
std::optional<DeviceProductInfo> getDeviceProductInfoLocked(const DisplayDevice&) const;
// mark a region of a layer stack dirty. this updates the dirty
@@ -827,10 +825,11 @@ private:
std::shared_ptr<compositionengine::Display> compositionDisplay,
const DisplayDeviceState& state,
const sp<compositionengine::DisplaySurface>& displaySurface,
- const sp<IGraphicBufferProducer>& producer);
+ const sp<IGraphicBufferProducer>& producer) REQUIRES(mStateLock);
void processDisplayChangesLocked() REQUIRES(mStateLock);
- void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState& state);
- void processDisplayRemoved(const wp<IBinder>& displayToken);
+ void processDisplayAdded(const wp<IBinder>& displayToken, const DisplayDeviceState&)
+ REQUIRES(mStateLock);
+ void processDisplayRemoved(const wp<IBinder>& displayToken) REQUIRES(mStateLock);
void processDisplayChanged(const wp<IBinder>& displayToken,
const DisplayDeviceState& currentState,
const DisplayDeviceState& drawingState) REQUIRES(mStateLock);
@@ -873,12 +872,13 @@ private:
/*
* Display identification
*/
- sp<IBinder> getPhysicalDisplayTokenLocked(DisplayId displayId) const {
+ sp<IBinder> getPhysicalDisplayTokenLocked(DisplayId displayId) const REQUIRES(mStateLock) {
const auto it = mPhysicalDisplayTokens.find(displayId);
return it != mPhysicalDisplayTokens.end() ? it->second : nullptr;
}
- std::optional<DisplayId> getPhysicalDisplayIdLocked(const sp<IBinder>& displayToken) const {
+ std::optional<DisplayId> getPhysicalDisplayIdLocked(const sp<IBinder>& displayToken) const
+ REQUIRES(mStateLock) {
for (const auto& [id, token] : mPhysicalDisplayTokens) {
if (token == displayToken) {
return id;
@@ -888,12 +888,12 @@ private:
}
// TODO(b/74619554): Remove special cases for primary display.
- sp<IBinder> getInternalDisplayTokenLocked() const {
+ sp<IBinder> getInternalDisplayTokenLocked() const REQUIRES(mStateLock) {
const auto displayId = getInternalDisplayIdLocked();
return displayId ? getPhysicalDisplayTokenLocked(*displayId) : nullptr;
}
- std::optional<DisplayId> getInternalDisplayIdLocked() const {
+ std::optional<DisplayId> getInternalDisplayIdLocked() const REQUIRES(mStateLock) {
const auto hwcDisplayId = getHwComposer().getInternalHwcDisplayId();
return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
}
@@ -945,9 +945,9 @@ private:
void recordBufferingStats(const std::string& layerName,
std::vector<OccupancyTracker::Segment>&& history);
void dumpBufferingStats(std::string& result) const;
- void dumpDisplayIdentificationData(std::string& result) const;
+ void dumpDisplayIdentificationData(std::string& result) const REQUIRES(mStateLock);
void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const;
- void dumpWideColorInfo(std::string& result) const;
+ void dumpWideColorInfo(std::string& result) const REQUIRES(mStateLock);
LayersProto dumpDrawingStateProto(uint32_t traceFlags) const;
void dumpOffscreenLayersProto(LayersProto& layersProto,
uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
@@ -974,7 +974,7 @@ private:
/* ------------------------------------------------------------------------
* VrFlinger
*/
- void resetDisplayState();
+ void resetDisplayState() REQUIRES(mStateLock);
// Check to see if we should handoff to vr flinger.
void updateVrFlinger();
@@ -1053,16 +1053,14 @@ private:
hal::HWDisplayId hwcDisplayId;
hal::Connection connection = hal::Connection::INVALID;
};
- // protected by mStateLock
- std::vector<HotplugEvent> mPendingHotplugEvents;
+ std::vector<HotplugEvent> mPendingHotplugEvents GUARDED_BY(mStateLock);
// this may only be written from the main thread with mStateLock held
// it may be read from other threads with mStateLock held
- std::map<wp<IBinder>, sp<DisplayDevice>> mDisplays;
- std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
+ std::map<wp<IBinder>, sp<DisplayDevice>> mDisplays GUARDED_BY(mStateLock);
+ std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens GUARDED_BY(mStateLock);
- // protected by mStateLock
- std::unordered_map<BBinder*, wp<Layer>> mLayersByLocalBinderToken;
+ std::unordered_map<BBinder*, wp<Layer>> mLayersByLocalBinderToken GUARDED_BY(mStateLock);
// don't use a lock for these, we don't care
int mDebugRegion = 0;
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
index 431cf0f4b3..d55648ae34 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -103,12 +103,22 @@ TEST_F(LayerHistoryTestV2, oneLayer) {
EXPECT_TRUE(history().summarize(time).empty());
EXPECT_EQ(0, activeLayerCount());
+ // The first few updates are considered infrequent
+ for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
+ history().record(layer.get(), 0, time);
+ ASSERT_EQ(1, history().summarize(time).size());
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+ EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(0, frequentLayerCount(time));
+ }
+
// Max returned if active layers have insufficient history.
- for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+ for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
history().record(layer.get(), 0, time);
ASSERT_EQ(1, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
}
// Max is returned since we have enough history but there is no timestamp votes.
@@ -117,6 +127,7 @@ TEST_F(LayerHistoryTestV2, oneLayer) {
ASSERT_EQ(1, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
+ EXPECT_EQ(1, frequentLayerCount(time));
}
}
@@ -134,7 +145,7 @@ TEST_F(LayerHistoryTestV2, oneInvisibleLayer) {
auto summary = history().summarize(time);
ASSERT_EQ(1, history().summarize(time).size());
// Layer is still considered inactive so we expect to get Min
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false));
@@ -464,28 +475,15 @@ TEST_F(LayerHistoryTestV2, inactiveLayers) {
nsecs_t time = systemTime();
- // the very first updates makes the layer frequent
+ // The first few updates are considered infrequent
for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
- history().record(layer.get(), time, time);
- time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
-
- EXPECT_EQ(1, layerCount());
+ history().record(layer.get(), 0, time);
ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+ EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(1, frequentLayerCount(time));
+ EXPECT_EQ(0, frequentLayerCount(time));
}
- // the next update with the MAX_FREQUENT_LAYER_PERIOD_NS will get us to infrequent
- history().record(layer.get(), time, time);
- time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
-
- EXPECT_EQ(1, layerCount());
- ASSERT_EQ(1, history().summarize(time).size());
- EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
- EXPECT_EQ(1, activeLayerCount());
- EXPECT_EQ(0, frequentLayerCount(time));
-
// advance the time for the previous frame to be inactive
time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
@@ -528,9 +526,11 @@ TEST_F(LayerHistoryTestV2, invisibleExplicitLayer) {
nsecs_t time = systemTime();
- // Post a buffer to the layers to make them active
- history().record(explicitVisiblelayer.get(), time, time);
- history().record(explicitInvisiblelayer.get(), time, time);
+ // Post a few buffers to the layers to make them active
+ for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE; i++) {
+ history().record(explicitVisiblelayer.get(), time, time);
+ history().record(explicitInvisiblelayer.get(), time, time);
+ }
EXPECT_EQ(2, layerCount());
ASSERT_EQ(1, history().summarize(time).size());
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 1c067cbae9..38bc8a19cf 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -289,14 +289,14 @@ public:
return mFlinger->destroyDisplay(displayToken);
}
- auto resetDisplayState() { return mFlinger->resetDisplayState(); }
+ auto resetDisplayState() NO_THREAD_SAFETY_ANALYSIS { return mFlinger->resetDisplayState(); }
auto setupNewDisplayDeviceInternal(
const wp<IBinder>& displayToken,
std::shared_ptr<compositionengine::Display> compositionDisplay,
const DisplayDeviceState& state,
const sp<compositionengine::DisplaySurface>& dispSurface,
- const sp<IGraphicBufferProducer>& producer) {
+ const sp<IGraphicBufferProducer>& producer) NO_THREAD_SAFETY_ANALYSIS {
return mFlinger->setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state,
dispSurface, producer);
}