diff options
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); } |