Merge "Wait for dispatcher idle before asserting policy callbacks" into udc-qpr-dev
diff --git a/services/inputflinger/tests/EventBuilders.h b/include/input/EventBuilders.h
similarity index 100%
rename from services/inputflinger/tests/EventBuilders.h
rename to include/input/EventBuilders.h
diff --git a/libs/gui/WindowInfo.cpp b/libs/gui/WindowInfo.cpp
index 6df9ff1..cd9b424 100644
--- a/libs/gui/WindowInfo.cpp
+++ b/libs/gui/WindowInfo.cpp
@@ -90,8 +90,9 @@
}
parcel->writeInt32(1);
- // Ensure that the size of the flags that we use is 32 bits for writing into the parcel.
+ // Ensure that the size of custom types are what we expect for writing into the parcel.
static_assert(sizeof(inputConfig) == 4u);
+ static_assert(sizeof(ownerUid.val()) == 4u);
// clang-format off
status_t status = parcel->writeStrongBinder(token) ?:
@@ -116,7 +117,7 @@
parcel->writeFloat(transform.ty()) ?:
parcel->writeInt32(static_cast<int32_t>(touchOcclusionMode)) ?:
parcel->writeInt32(ownerPid) ?:
- parcel->writeInt32(ownerUid) ?:
+ parcel->writeInt32(ownerUid.val()) ?:
parcel->writeUtf8AsUtf16(packageName) ?:
parcel->writeInt32(inputConfig.get()) ?:
parcel->writeInt32(displayId) ?:
@@ -147,7 +148,7 @@
}
float dsdx, dtdx, tx, dtdy, dsdy, ty;
- int32_t lpFlags, lpType, touchOcclusionModeInt, inputConfigInt;
+ int32_t lpFlags, lpType, touchOcclusionModeInt, inputConfigInt, ownerUidInt;
sp<IBinder> touchableRegionCropHandleSp;
// clang-format off
@@ -168,7 +169,7 @@
parcel->readFloat(&ty) ?:
parcel->readInt32(&touchOcclusionModeInt) ?:
parcel->readInt32(&ownerPid) ?:
- parcel->readInt32(&ownerUid) ?:
+ parcel->readInt32(&ownerUidInt) ?:
parcel->readUtf8FromUtf16(&packageName) ?:
parcel->readInt32(&inputConfigInt) ?:
parcel->readInt32(&displayId) ?:
@@ -190,6 +191,7 @@
transform.set({dsdx, dtdx, tx, dtdy, dsdy, ty, 0, 0, 1});
touchOcclusionMode = static_cast<TouchOcclusionMode>(touchOcclusionModeInt);
inputConfig = ftl::Flags<InputConfig>(inputConfigInt);
+ ownerUid = Uid{static_cast<uid_t>(ownerUidInt)};
touchableRegionCropHandle = touchableRegionCropHandleSp;
return OK;
diff --git a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp
index 57720dd..7268e64 100644
--- a/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp
+++ b/libs/gui/fuzzer/libgui_surfaceComposerClient_fuzzer.cpp
@@ -187,7 +187,7 @@
windowInfo->replaceTouchableRegionWithCrop = mFdp.ConsumeBool();
windowInfo->touchOcclusionMode = mFdp.PickValueInArray(kMode);
windowInfo->ownerPid = mFdp.ConsumeIntegral<int32_t>();
- windowInfo->ownerUid = mFdp.ConsumeIntegral<int32_t>();
+ windowInfo->ownerUid = gui::Uid{mFdp.ConsumeIntegral<uid_t>()};
windowInfo->packageName = mFdp.ConsumeRandomLengthString(kRandomStringMaxBytes);
windowInfo->inputConfig = mFdp.PickValueInArray(kFeatures);
}
diff --git a/libs/gui/include/gui/Uid.h b/libs/gui/include/gui/Uid.h
new file mode 100644
index 0000000..8e45ef5
--- /dev/null
+++ b/libs/gui/include/gui/Uid.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <ftl/mixins.h>
+#include <sys/types.h>
+#include <string>
+
+namespace android::gui {
+
+// Type-safe wrapper for a UID.
+// We treat the unsigned equivalent of -1 as a singular invalid value.
+struct Uid : ftl::Constructible<Uid, uid_t>, ftl::Equatable<Uid>, ftl::Orderable<Uid> {
+ using Constructible::Constructible;
+
+ const static Uid INVALID;
+
+ constexpr auto val() const { return ftl::to_underlying(*this); }
+
+ constexpr bool isValid() const { return val() != static_cast<uid_t>(-1); }
+
+ std::string toString() const { return std::to_string(val()); }
+};
+
+const inline Uid Uid::INVALID{static_cast<uid_t>(-1)};
+
+} // namespace android::gui
diff --git a/libs/gui/include/gui/WindowInfo.h b/libs/gui/include/gui/WindowInfo.h
index 70b2ee8..666101e 100644
--- a/libs/gui/include/gui/WindowInfo.h
+++ b/libs/gui/include/gui/WindowInfo.h
@@ -21,6 +21,8 @@
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <ftl/flags.h>
+#include <ftl/mixins.h>
+#include <gui/Uid.h>
#include <gui/constants.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -224,7 +226,7 @@
TouchOcclusionMode touchOcclusionMode = TouchOcclusionMode::BLOCK_UNTRUSTED;
int32_t ownerPid = -1;
- int32_t ownerUid = -1;
+ Uid ownerUid = Uid::INVALID;
std::string packageName;
ftl::Flags<InputConfig> inputConfig;
int32_t displayId = ADISPLAY_ID_NONE;
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 4ec7a06..4d5bd5b 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -821,7 +821,7 @@
// with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED
std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
- nonTouchableSurface->mInputInfo.ownerUid = 22222;
+ nonTouchableSurface->mInputInfo.ownerUid = gui::Uid{22222};
// Overriding occlusion mode otherwise the touch would be discarded at InputDispatcher by
// the default obscured/untrusted touch filter introduced in S.
nonTouchableSurface->mInputInfo.touchOcclusionMode = TouchOcclusionMode::ALLOW;
@@ -842,8 +842,8 @@
std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
parentSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
- nonTouchableSurface->mInputInfo.ownerUid = 22222;
- parentSurface->mInputInfo.ownerUid = 22222;
+ nonTouchableSurface->mInputInfo.ownerUid = gui::Uid{22222};
+ parentSurface->mInputInfo.ownerUid = gui::Uid{22222};
nonTouchableSurface->showAt(0, 0);
parentSurface->showAt(100, 100);
@@ -866,8 +866,8 @@
std::unique_ptr<InputSurface> nonTouchableSurface = makeSurface(100, 100);
nonTouchableSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
parentSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
- nonTouchableSurface->mInputInfo.ownerUid = 22222;
- parentSurface->mInputInfo.ownerUid = 22222;
+ nonTouchableSurface->mInputInfo.ownerUid = gui::Uid{22222};
+ parentSurface->mInputInfo.ownerUid = gui::Uid{22222};
nonTouchableSurface->showAt(0, 0);
parentSurface->showAt(50, 50);
@@ -886,7 +886,7 @@
std::unique_ptr<InputSurface> bufferSurface =
InputSurface::makeBufferInputSurface(mComposerClient, 0, 0);
bufferSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
- bufferSurface->mInputInfo.ownerUid = 22222;
+ bufferSurface->mInputInfo.ownerUid = gui::Uid{22222};
surface->showAt(10, 10);
bufferSurface->showAt(50, 50, Rect::EMPTY_RECT);
@@ -901,7 +901,7 @@
std::unique_ptr<BlastInputSurface> bufferSurface =
BlastInputSurface::makeBlastInputSurface(mComposerClient, 0, 0);
bufferSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
- bufferSurface->mInputInfo.ownerUid = 22222;
+ bufferSurface->mInputInfo.ownerUid = gui::Uid{22222};
surface->showAt(10, 10);
bufferSurface->showAt(50, 50, Rect::EMPTY_RECT);
@@ -948,13 +948,13 @@
TEST_F(InputSurfacesTest, strict_unobscured_input_obscured_window) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
- surface->mInputInfo.ownerUid = 11111;
+ surface->mInputInfo.ownerUid = gui::Uid{11111};
surface->doTransaction(
[&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
surface->showAt(100, 100);
std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100);
obscuringSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
- obscuringSurface->mInputInfo.ownerUid = 22222;
+ obscuringSurface->mInputInfo.ownerUid = gui::Uid{22222};
obscuringSurface->showAt(100, 100);
injectTap(101, 101);
EXPECT_EQ(surface->consumeEvent(100), nullptr);
@@ -967,13 +967,13 @@
TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
- surface->mInputInfo.ownerUid = 11111;
+ surface->mInputInfo.ownerUid = gui::Uid{11111};
surface->doTransaction(
[&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
surface->showAt(100, 100);
std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100);
obscuringSurface->mInputInfo.setInputConfig(WindowInfo::InputConfig::NOT_TOUCHABLE, true);
- obscuringSurface->mInputInfo.ownerUid = 22222;
+ obscuringSurface->mInputInfo.ownerUid = gui::Uid{22222};
obscuringSurface->showAt(190, 190);
injectTap(101, 101);
diff --git a/libs/gui/tests/WindowInfo_test.cpp b/libs/gui/tests/WindowInfo_test.cpp
index 11b87ef..e3a629e 100644
--- a/libs/gui/tests/WindowInfo_test.cpp
+++ b/libs/gui/tests/WindowInfo_test.cpp
@@ -62,7 +62,7 @@
i.transform.set({0.4, -1, 100, 0.5, 0, 40, 0, 0, 1});
i.touchOcclusionMode = TouchOcclusionMode::ALLOW;
i.ownerPid = 19;
- i.ownerUid = 24;
+ i.ownerUid = gui::Uid{24};
i.packageName = "com.example.package";
i.inputConfig = WindowInfo::InputConfig::NOT_FOCUSABLE;
i.displayId = 34;
diff --git a/libs/ui/include/ui/FenceTime.h b/libs/ui/include/ui/FenceTime.h
index ac75f43..334106f 100644
--- a/libs/ui/include/ui/FenceTime.h
+++ b/libs/ui/include/ui/FenceTime.h
@@ -142,6 +142,8 @@
std::atomic<nsecs_t> mSignalTime{Fence::SIGNAL_TIME_INVALID};
};
+using FenceTimePtr = std::shared_ptr<FenceTime>;
+
// A queue of FenceTimes that are expected to signal in FIFO order.
// Only maintains a queue of weak pointers so it doesn't keep references
// to Fences on its own.
@@ -190,8 +192,15 @@
// before the new one is added.
class FenceToFenceTimeMap {
public:
- // Create a new FenceTime with that wraps the provided Fence.
- std::shared_ptr<FenceTime> createFenceTimeForTest(const sp<Fence>& fence);
+ using FencePair = std::pair<sp<Fence>, FenceTimePtr>;
+
+ FencePair makePendingFenceForTest() {
+ const auto fence = sp<Fence>::make();
+ return {fence, createFenceTimeForTest(fence)};
+ }
+
+ // Create a new FenceTime that wraps the provided Fence.
+ FenceTimePtr createFenceTimeForTest(const sp<Fence>&);
// Signals all FenceTimes created through this class that are wrappers
// around |fence|.
@@ -205,7 +214,6 @@
std::unordered_map<Fence*, std::vector<std::weak_ptr<FenceTime>>> mMap;
};
-
-}; // namespace android
+} // namespace android
#endif // ANDROID_FENCE_TIME_H
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 32c21f6..c787fc9 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -699,7 +699,7 @@
#ifndef EGL_EXT_gl_colorspace_bt2020_hlg
#define EGL_EXT_gl_colorspace_bt2020_hlg 1
-#define EGL_GL_COLORSPACE_BT2020_HLG_EXT 0x333E
+#define EGL_GL_COLORSPACE_BT2020_HLG_EXT 0x3540
#endif /* EGL_EXT_gl_colorspace_bt2020_hlg */
#ifndef EGL_EXT_gl_colorspace_bt2020_linear
diff --git a/services/inputflinger/InputDeviceMetricsCollector.cpp b/services/inputflinger/InputDeviceMetricsCollector.cpp
index 220de8f..999e175 100644
--- a/services/inputflinger/InputDeviceMetricsCollector.cpp
+++ b/services/inputflinger/InputDeviceMetricsCollector.cpp
@@ -81,10 +81,11 @@
std::vector<int32_t> uids;
std::vector<int32_t> durationsPerUid;
for (auto& [uid, dur] : report.uidBreakdown) {
- uids.push_back(uid);
+ uids.push_back(uid.val());
int32_t durMillis = std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
durationsPerUid.push_back(durMillis);
- ALOGD_IF(DEBUG, " - uid: %d\t duration: %dms", uid, durMillis);
+ ALOGD_IF(DEBUG, " - uid: %s\t duration: %dms", uid.toString().c_str(),
+ durMillis);
}
util::stats_write(util::INPUTDEVICE_USAGE_REPORTED, identifier.vendor, identifier.product,
identifier.version, linuxBusToInputDeviceBusEnum(identifier.bus),
@@ -260,12 +261,8 @@
}
void InputDeviceMetricsCollector::notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
- const std::set<int32_t>& uids) {
- std::set<Uid> typeSafeUids;
- for (auto uid : uids) {
- typeSafeUids.emplace(uid);
- }
- mInteractionsQueue.push(DeviceId{deviceId}, timestamp, typeSafeUids);
+ const std::set<Uid>& uids) {
+ mInteractionsQueue.push(DeviceId{deviceId}, timestamp, uids);
}
void InputDeviceMetricsCollector::dump(std::string& dump) {
diff --git a/services/inputflinger/InputDeviceMetricsCollector.h b/services/inputflinger/InputDeviceMetricsCollector.h
index 387786f..c70e6d4 100644
--- a/services/inputflinger/InputDeviceMetricsCollector.h
+++ b/services/inputflinger/InputDeviceMetricsCollector.h
@@ -21,6 +21,7 @@
#include "SyncQueue.h"
#include <ftl/mixins.h>
+#include <gui/WindowInfo.h>
#include <input/InputDevice.h>
#include <statslog.h>
#include <chrono>
@@ -43,7 +44,7 @@
* Called from the InputDispatcher thread.
*/
virtual void notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
- const std::set<int32_t>& uids) = 0;
+ const std::set<gui::Uid>& uids) = 0;
/**
* Dump the state of the interaction blocker.
* This method may be called on any thread (usually by the input manager on a binder thread).
@@ -101,7 +102,7 @@
// Describes the breakdown of an input device usage session by the UIDs that it interacted with.
using UidUsageBreakdown =
- std::vector<std::pair<int32_t /*uid*/, std::chrono::nanoseconds /*duration*/>>;
+ std::vector<std::pair<gui::Uid, std::chrono::nanoseconds /*duration*/>>;
struct DeviceUsageReport {
std::chrono::nanoseconds usageDuration;
@@ -134,7 +135,7 @@
void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override;
void notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
- const std::set<int32_t>& uids) override;
+ const std::set<gui::Uid>& uids) override;
void dump(std::string& dump) override;
private:
@@ -152,13 +153,7 @@
return std::to_string(ftl::to_underlying(id));
}
- // Type-safe wrapper for a UID.
- struct Uid : ftl::Constructible<Uid, std::int32_t>, ftl::Equatable<Uid>, ftl::Orderable<Uid> {
- using Constructible::Constructible;
- };
- static inline std::string toString(const Uid& src) {
- return std::to_string(ftl::to_underlying(src));
- }
+ using Uid = gui::Uid;
std::map<DeviceId, InputDeviceInfo> mLoggedDeviceInfos;
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 06a7352..c5cf083 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -37,7 +37,7 @@
// The default pid and uid for windows created by the test.
constexpr int32_t WINDOW_PID = 999;
-constexpr int32_t WINDOW_UID = 1001;
+constexpr gui::Uid WINDOW_UID{1001};
static constexpr std::chrono::duration INJECT_EVENT_TIMEOUT = 5s;
static constexpr std::chrono::nanoseconds DISPATCHING_TIMEOUT = 100ms;
@@ -112,7 +112,7 @@
void notifyDropWindow(const sp<IBinder>&, float x, float y) override {}
void notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
- const std::set<int32_t>& uids) override {}
+ const std::set<gui::Uid>& uids) override {}
InputDispatcherConfiguration mConfig;
};
diff --git a/services/inputflinger/dispatcher/InjectionState.cpp b/services/inputflinger/dispatcher/InjectionState.cpp
index c2d3ad6..053594b 100644
--- a/services/inputflinger/dispatcher/InjectionState.cpp
+++ b/services/inputflinger/dispatcher/InjectionState.cpp
@@ -20,7 +20,7 @@
namespace android::inputdispatcher {
-InjectionState::InjectionState(const std::optional<int32_t>& targetUid)
+InjectionState::InjectionState(const std::optional<gui::Uid>& targetUid)
: refCount(1),
targetUid(targetUid),
injectionResult(android::os::InputEventInjectionResult::PENDING),
diff --git a/services/inputflinger/dispatcher/InjectionState.h b/services/inputflinger/dispatcher/InjectionState.h
index d9e27ba..3a3f5ae 100644
--- a/services/inputflinger/dispatcher/InjectionState.h
+++ b/services/inputflinger/dispatcher/InjectionState.h
@@ -26,12 +26,12 @@
struct InjectionState {
mutable int32_t refCount;
- std::optional<int32_t> targetUid;
+ std::optional<gui::Uid> targetUid;
android::os::InputEventInjectionResult injectionResult; // initially PENDING
bool injectionIsAsync; // set to true if injection is not waiting for the result
int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress
- explicit InjectionState(const std::optional<int32_t>& targetUid);
+ explicit InjectionState(const std::optional<gui::Uid>& targetUid);
void release();
private:
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 1c1a0bb..6f0f022 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -126,6 +126,10 @@
return StringPrintf("%p", binder.get());
}
+static std::string uidString(const gui::Uid& uid) {
+ return uid.toString();
+}
+
inline int32_t getMotionEventActionPointerIndex(int32_t action) {
return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
@@ -557,7 +561,7 @@
return !info.inputConfig.test(gui::WindowInfo::InputConfig::NOT_TOUCHABLE) && !info.isSpy();
}
-bool isWindowOwnedBy(const sp<WindowInfoHandle>& windowHandle, int32_t pid, int32_t uid) {
+bool isWindowOwnedBy(const sp<WindowInfoHandle>& windowHandle, int32_t pid, gui::Uid uid) {
if (windowHandle == nullptr) {
return false;
}
@@ -577,14 +581,16 @@
// The event was not injected, or the injected event does not target a window.
return {};
}
- const int32_t uid = *entry.injectionState->targetUid;
+ const auto uid = *entry.injectionState->targetUid;
if (window == nullptr) {
- return StringPrintf("No valid window target for injection into uid %d.", uid);
+ return StringPrintf("No valid window target for injection into uid %s.",
+ uid.toString().c_str());
}
if (entry.injectionState->targetUid != window->getInfo()->ownerUid) {
- return StringPrintf("Injected event targeted at uid %d would be dispatched to window '%s' "
- "owned by uid %d.",
- uid, window->getName().c_str(), window->getInfo()->ownerUid);
+ return StringPrintf("Injected event targeted at uid %s would be dispatched to window '%s' "
+ "owned by uid %s.",
+ uid.toString().c_str(), window->getName().c_str(),
+ window->getInfo()->ownerUid.toString().c_str());
}
return {};
}
@@ -2585,8 +2591,8 @@
}
if (!errs.empty()) {
ALOGW("Dropping targeted injection: At least one touched window is not owned by uid "
- "%d:%s",
- *entry.injectionState->targetUid, errs.c_str());
+ "%s:%s",
+ entry.injectionState->targetUid->toString().c_str(), errs.c_str());
outInjectionResult = InputEventInjectionResult::TARGET_MISMATCH;
return {};
}
@@ -2598,7 +2604,7 @@
sp<WindowInfoHandle> foregroundWindowHandle =
tempTouchState.getFirstForegroundWindowHandle();
if (foregroundWindowHandle) {
- const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;
+ const auto foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;
for (InputTarget& target : targets) {
if (target.flags.test(InputTarget::Flags::DISPATCH_AS_OUTSIDE)) {
sp<WindowInfoHandle> targetWindow =
@@ -2962,8 +2968,8 @@
TouchOcclusionInfo info;
info.hasBlockingOcclusion = false;
info.obscuringOpacity = 0;
- info.obscuringUid = -1;
- std::map<int32_t, float> opacityByUid;
+ info.obscuringUid = gui::Uid::INVALID;
+ std::map<gui::Uid, float> opacityByUid;
for (const sp<WindowInfoHandle>& otherHandle : windowHandles) {
if (windowHandle == otherHandle) {
break; // All future windows are below us. Exit early.
@@ -2985,7 +2991,7 @@
break;
}
if (otherInfo->touchOcclusionMode == TouchOcclusionMode::USE_OPACITY) {
- uint32_t uid = otherInfo->ownerUid;
+ const auto uid = otherInfo->ownerUid;
float opacity =
(opacityByUid.find(uid) == opacityByUid.end()) ? 0 : opacityByUid[uid];
// Given windows A and B:
@@ -3009,29 +3015,30 @@
std::string InputDispatcher::dumpWindowForTouchOcclusion(const WindowInfo* info,
bool isTouchedWindow) const {
- return StringPrintf(INDENT2 "* %spackage=%s/%" PRId32 ", id=%" PRId32 ", mode=%s, alpha=%.2f, "
+ return StringPrintf(INDENT2 "* %spackage=%s/%s, id=%" PRId32 ", mode=%s, alpha=%.2f, "
"frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32
"], touchableRegion=%s, window={%s}, inputConfig={%s}, "
"hasToken=%s, applicationInfo.name=%s, applicationInfo.token=%s\n",
isTouchedWindow ? "[TOUCHED] " : "", info->packageName.c_str(),
- info->ownerUid, info->id, toString(info->touchOcclusionMode).c_str(),
- info->alpha, info->frameLeft, info->frameTop, info->frameRight,
- info->frameBottom, dumpRegion(info->touchableRegion).c_str(),
- info->name.c_str(), info->inputConfig.string().c_str(),
- toString(info->token != nullptr), info->applicationInfo.name.c_str(),
+ info->ownerUid.toString().c_str(), info->id,
+ toString(info->touchOcclusionMode).c_str(), info->alpha, info->frameLeft,
+ info->frameTop, info->frameRight, info->frameBottom,
+ dumpRegion(info->touchableRegion).c_str(), info->name.c_str(),
+ info->inputConfig.string().c_str(), toString(info->token != nullptr),
+ info->applicationInfo.name.c_str(),
binderToString(info->applicationInfo.token).c_str());
}
bool InputDispatcher::isTouchTrustedLocked(const TouchOcclusionInfo& occlusionInfo) const {
if (occlusionInfo.hasBlockingOcclusion) {
- ALOGW("Untrusted touch due to occlusion by %s/%d", occlusionInfo.obscuringPackage.c_str(),
- occlusionInfo.obscuringUid);
+ ALOGW("Untrusted touch due to occlusion by %s/%s", occlusionInfo.obscuringPackage.c_str(),
+ occlusionInfo.obscuringUid.toString().c_str());
return false;
}
if (occlusionInfo.obscuringOpacity > mMaximumObscuringOpacityForTouch) {
- ALOGW("Untrusted touch due to occlusion by %s/%d (obscuring opacity = "
+ ALOGW("Untrusted touch due to occlusion by %s/%s (obscuring opacity = "
"%.2f, maximum allowed = %.2f)",
- occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid,
+ occlusionInfo.obscuringPackage.c_str(), occlusionInfo.obscuringUid.toString().c_str(),
occlusionInfo.obscuringOpacity, mMaximumObscuringOpacityForTouch);
return false;
}
@@ -3453,7 +3460,7 @@
return; // Not a key or a motion
}
- std::set<int32_t> interactionUids;
+ std::set<gui::Uid> interactionUids;
std::unordered_set<sp<IBinder>, StrongPointerHash<IBinder>> newConnectionTokens;
std::vector<std::shared_ptr<Connection>> newConnections;
for (const InputTarget& target : targets) {
@@ -4532,7 +4539,7 @@
}
InputEventInjectionResult InputDispatcher::injectInputEvent(const InputEvent* event,
- std::optional<int32_t> targetUid,
+ std::optional<gui::Uid> targetUid,
InputEventInjectionSync syncMode,
std::chrono::milliseconds timeout,
uint32_t policyFlags) {
@@ -4543,7 +4550,7 @@
}
if (debugInboundEventDetails()) {
- LOG(DEBUG) << __func__ << ": targetUid=" << toString(targetUid)
+ LOG(DEBUG) << __func__ << ": targetUid=" << toString(targetUid, &uidString)
<< ", syncMode=" << ftl::enum_string(syncMode) << ", timeout=" << timeout.count()
<< "ms, policyFlags=0x" << std::hex << policyFlags << std::dec
<< ", event=" << *event;
@@ -4988,8 +4995,8 @@
ALOGD("%s", log.c_str());
}
}
- ALOGW("Dropping untrusted touch event due to %s/%d", occlusionInfo.obscuringPackage.c_str(),
- occlusionInfo.obscuringUid);
+ ALOGW("Dropping untrusted touch event due to %s/%s", occlusionInfo.obscuringPackage.c_str(),
+ occlusionInfo.obscuringUid.toString().c_str());
return false;
}
@@ -5351,15 +5358,16 @@
mLooper->wake();
}
-bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission,
- int32_t displayId) {
+bool InputDispatcher::setInTouchMode(bool inTouchMode, int32_t pid, gui::Uid uid,
+ bool hasPermission, int32_t displayId) {
bool needWake = false;
{
std::scoped_lock lock(mLock);
ALOGD_IF(DEBUG_TOUCH_MODE,
- "Request to change touch mode to %s (calling pid=%d, uid=%d, "
+ "Request to change touch mode to %s (calling pid=%d, uid=%s, "
"hasPermission=%s, target displayId=%d, mTouchModePerDisplay[displayId]=%s)",
- toString(inTouchMode), pid, uid, toString(hasPermission), displayId,
+ toString(inTouchMode), pid, uid.toString().c_str(), toString(hasPermission),
+ displayId,
mTouchModePerDisplay.count(displayId) == 0
? "not set"
: std::to_string(mTouchModePerDisplay[displayId]).c_str());
@@ -5371,9 +5379,9 @@
if (!hasPermission) {
if (!focusedWindowIsOwnedByLocked(pid, uid) &&
!recentWindowsAreOwnedByLocked(pid, uid)) {
- ALOGD("Touch mode switch rejected, caller (pid=%d, uid=%d) doesn't own the focused "
+ ALOGD("Touch mode switch rejected, caller (pid=%d, uid=%s) doesn't own the focused "
"window nor none of the previously interacted window",
- pid, uid);
+ pid, uid.toString().c_str());
return false;
}
}
@@ -5389,7 +5397,7 @@
return true;
}
-bool InputDispatcher::focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) {
+bool InputDispatcher::focusedWindowIsOwnedByLocked(int32_t pid, gui::Uid uid) {
const sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(mFocusedDisplayId);
if (focusedToken == nullptr) {
return false;
@@ -5398,7 +5406,7 @@
return isWindowOwnedBy(windowHandle, pid, uid);
}
-bool InputDispatcher::recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) {
+bool InputDispatcher::recentWindowsAreOwnedByLocked(int32_t pid, gui::Uid uid) {
return std::find_if(mInteractionConnectionTokens.begin(), mInteractionConnectionTokens.end(),
[&](const sp<IBinder>& connectionToken) REQUIRES(mLock) {
const sp<WindowInfoHandle> windowHandle =
@@ -5683,10 +5691,11 @@
windowInfo->applicationInfo.name.c_str(),
binderToString(windowInfo->applicationInfo.token).c_str());
dump += dumpRegion(windowInfo->touchableRegion);
- dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%" PRId64
+ dump += StringPrintf(", ownerPid=%d, ownerUid=%s, dispatchingTimeout=%" PRId64
"ms, hasToken=%s, "
"touchOcclusionMode=%s\n",
- windowInfo->ownerPid, windowInfo->ownerUid,
+ windowInfo->ownerPid,
+ windowInfo->ownerUid.toString().c_str(),
millis(windowInfo->dispatchingTimeout),
binderToString(windowInfo->token).c_str(),
toString(windowInfo->touchOcclusionMode).c_str());
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 96151ed..2038bb8 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -104,7 +104,7 @@
void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs& args) override;
android::os::InputEventInjectionResult injectInputEvent(
- const InputEvent* event, std::optional<int32_t> targetUid,
+ const InputEvent* event, std::optional<gui::Uid> targetUid,
android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
uint32_t policyFlags) override;
@@ -119,7 +119,7 @@
void setFocusedDisplay(int32_t displayId) override;
void setInputDispatchMode(bool enabled, bool frozen) override;
void setInputFilterEnabled(bool enabled) override;
- bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission,
+ bool setInTouchMode(bool inTouchMode, int32_t pid, gui::Uid uid, bool hasPermission,
int32_t displayId) override;
void setMaximumObscuringOpacityForTouch(float opacity) override;
@@ -574,7 +574,7 @@
bool hasBlockingOcclusion;
float obscuringOpacity;
std::string obscuringPackage;
- int32_t obscuringUid;
+ gui::Uid obscuringUid = gui::Uid::INVALID;
std::vector<std::string> debugInfo;
};
@@ -703,8 +703,8 @@
void traceWaitQueueLength(const Connection& connection);
// Check window ownership
- bool focusedWindowIsOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
- bool recentWindowsAreOwnedByLocked(int32_t pid, int32_t uid) REQUIRES(mLock);
+ bool focusedWindowIsOwnedByLocked(int32_t pid, gui::Uid uid) REQUIRES(mLock);
+ bool recentWindowsAreOwnedByLocked(int32_t pid, gui::Uid uid) REQUIRES(mLock);
sp<InputReporterInterface> mReporter;
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 627f122..e8c95c6 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -76,7 +76,7 @@
* perform all necessary permission checks prior to injecting events.
*/
virtual android::os::InputEventInjectionResult injectInputEvent(
- const InputEvent* event, std::optional<int32_t> targetUid,
+ const InputEvent* event, std::optional<gui::Uid> targetUid,
android::os::InputEventInjectionSync syncMode, std::chrono::milliseconds timeout,
uint32_t policyFlags) = 0;
@@ -134,7 +134,7 @@
*
* Returns true when changing touch mode state.
*/
- virtual bool setInTouchMode(bool inTouchMode, int32_t pid, int32_t uid, bool hasPermission,
+ virtual bool setInTouchMode(bool inTouchMode, int32_t pid, gui::Uid uid, bool hasPermission,
int32_t displayId) = 0;
/**
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index 69caa99..ec15b8d 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -140,7 +140,7 @@
/* Notifies the policy that there was an input device interaction with apps. */
virtual void notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
- const std::set<int32_t>& uids) = 0;
+ const std::set<gui::Uid>& uids) = 0;
};
} // namespace android
diff --git a/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp b/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp
index c555d95..0aa5e23 100644
--- a/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp
+++ b/services/inputflinger/tests/InputDeviceMetricsCollector_test.cpp
@@ -18,11 +18,12 @@
#include <gtest/gtest.h>
#include <gui/constants.h>
+#include <input/EventBuilders.h>
#include <linux/input.h>
+
#include <array>
#include <tuple>
-#include "EventBuilders.h"
#include "TestInputListener.h"
namespace android {
@@ -80,6 +81,14 @@
const InputDeviceInfo NON_ALPHABETIC_KEYBOARD_INFO =
generateTestDeviceInfo(DEVICE_ID, KEY_SOURCES, /*isAlphabetic=*/false);
+std::set<gui::Uid> uids(std::initializer_list<int32_t> vals) {
+ std::set<gui::Uid> set;
+ for (const auto val : vals) {
+ set.emplace(val);
+ }
+ return set;
+}
+
} // namespace
// --- InputDeviceMetricsCollectorDeviceClassificationTest ---
@@ -632,7 +641,7 @@
mMetricsCollector.notifyInputDevicesChanged({/*id=*/0, {generateTestDeviceInfo()}});
// Notify interaction with UIDs before the device is used.
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{1});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1}));
// Use the device.
setCurrentTime(TIME + 100ns);
@@ -641,12 +650,12 @@
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
// Notify interaction for the wrong device.
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID_2, currentTime(), /*uids=*/{42});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID_2, currentTime(), uids({42}));
// Notify interaction after usage session would have expired.
// This interaction should not be tracked.
setCurrentTime(TIME + 200ns + USAGE_TIMEOUT);
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{2, 3});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({2, 3}));
// Use the device again, by starting a new usage session.
setCurrentTime(TIME + 300ns + USAGE_TIMEOUT);
@@ -665,14 +674,14 @@
UidUsageBreakdown expectedUidBreakdown;
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{1});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1}));
setCurrentTime(TIME + 100ns);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{1, 2});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 2}));
setCurrentTime(TIME + 200ns);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{1, 2, 3});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 2, 3}));
expectedUidBreakdown.emplace_back(1, 200ns);
expectedUidBreakdown.emplace_back(2, 100ns);
@@ -691,39 +700,39 @@
UidUsageBreakdown expectedUidBreakdown;
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{1, 2});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 2}));
setCurrentTime(TIME + 100ns);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{1, 2});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 2}));
setCurrentTime(TIME + 200ns);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{1});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1}));
setCurrentTime(TIME + 300ns);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{1, 3});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 3}));
setCurrentTime(TIME + 400ns);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{1, 3});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 3}));
setCurrentTime(TIME + 200ns + USAGE_TIMEOUT);
expectedUidBreakdown.emplace_back(2, 100ns);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{4});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({4}));
setCurrentTime(TIME + 300ns + USAGE_TIMEOUT);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{1, 4});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 4}));
setCurrentTime(TIME + 400ns + USAGE_TIMEOUT);
expectedUidBreakdown.emplace_back(3, 100ns);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{2, 3});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({2, 3}));
setCurrentTime(TIME + 500ns + USAGE_TIMEOUT);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{3});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({3}));
// Remove the device to force the usage session to be logged.
mMetricsCollector.notifyInputDevicesChanged({});
@@ -744,17 +753,17 @@
UidUsageBreakdown expectedUidBreakdown2;
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{1, 2});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 2}));
setCurrentTime(TIME + 100ns);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID_2));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID_2, currentTime(), /*uids=*/{1, 3});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID_2, currentTime(), uids({1, 3}));
setCurrentTime(TIME + 200ns);
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), /*uids=*/{1, 2});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID, currentTime(), uids({1, 2}));
mMetricsCollector.notifyMotion(generateMotionArgs(DEVICE_ID_2));
- mMetricsCollector.notifyDeviceInteraction(DEVICE_ID_2, currentTime(), /*uids=*/{1, 3});
+ mMetricsCollector.notifyDeviceInteraction(DEVICE_ID_2, currentTime(), uids({1, 3}));
setCurrentTime(TIME + 200ns + USAGE_TIMEOUT);
expectedUidBreakdown1.emplace_back(1, 200ns);
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index adae009..499d944 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -16,7 +16,6 @@
#include "../dispatcher/InputDispatcher.h"
#include "../BlockingQueue.h"
-#include "EventBuilders.h"
#include <android-base/properties.h>
#include <android-base/silent_death_test.h>
@@ -26,6 +25,7 @@
#include <fcntl.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <input/EventBuilders.h>
#include <input/Input.h>
#include <linux/input.h>
#include <sys/epoll.h>
@@ -96,11 +96,11 @@
// The default pid and uid for windows created on the primary display by the test.
static constexpr int32_t WINDOW_PID = 999;
-static constexpr int32_t WINDOW_UID = 1001;
+static constexpr gui::Uid WINDOW_UID{1001};
// The default pid and uid for the windows created on the secondary display by the test.
static constexpr int32_t SECONDARY_WINDOW_PID = 1010;
-static constexpr int32_t SECONDARY_WINDOW_UID = 1012;
+static constexpr gui::Uid SECONDARY_WINDOW_UID{1012};
// An arbitrary pid of the gesture monitor window
static constexpr int32_t MONITOR_PID = 2001;
@@ -419,7 +419,7 @@
ASSERT_FALSE(mPokedUserActivity) << "Expected user activity not to have been poked";
}
- void assertNotifyDeviceInteractionWasCalled(int32_t deviceId, std::set<int32_t> uids) {
+ void assertNotifyDeviceInteractionWasCalled(int32_t deviceId, std::set<gui::Uid> uids) {
ASSERT_EQ(std::make_pair(deviceId, uids), mNotifiedInteractions.popWithTimeout(100ms));
}
@@ -452,7 +452,7 @@
std::chrono::milliseconds mInterceptKeyTimeout = 0ms;
- BlockingQueue<std::pair<int32_t /*deviceId*/, std::set<int32_t /*uid*/>>> mNotifiedInteractions;
+ BlockingQueue<std::pair<int32_t /*deviceId*/, std::set<gui::Uid>>> mNotifiedInteractions;
// All three ANR-related callbacks behave the same way, so we use this generic function to wait
// for a specific container to become non-empty. When the container is non-empty, return the
@@ -626,7 +626,7 @@
}
void notifyDeviceInteraction(int32_t deviceId, nsecs_t timestamp,
- const std::set<int32_t>& uids) override {
+ const std::set<gui::Uid>& uids) override {
ASSERT_TRUE(mNotifiedInteractions.emplace(deviceId, uids));
}
@@ -1445,7 +1445,7 @@
const std::string& getName() { return mName; }
- void setOwnerInfo(int32_t ownerPid, int32_t ownerUid) {
+ void setOwnerInfo(int32_t ownerPid, gui::Uid ownerUid) {
mInfo.ownerPid = ownerPid;
mInfo.ownerUid = ownerUid;
}
@@ -1471,7 +1471,7 @@
int32_t displayId = ADISPLAY_ID_NONE,
InputEventInjectionSync syncMode = InputEventInjectionSync::WAIT_FOR_RESULT,
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
- bool allowKeyRepeat = true, std::optional<int32_t> targetUid = {},
+ bool allowKeyRepeat = true, std::optional<gui::Uid> targetUid = {},
uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
KeyEvent event;
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -1512,7 +1512,7 @@
const std::unique_ptr<InputDispatcher>& dispatcher, const MotionEvent& event,
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
- std::optional<int32_t> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
+ std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
return dispatcher->injectInputEvent(&event, targetUid, injectionMode, injectionTimeout,
policyFlags);
}
@@ -1525,7 +1525,7 @@
std::chrono::milliseconds injectionTimeout = INJECT_EVENT_TIMEOUT,
InputEventInjectionSync injectionMode = InputEventInjectionSync::WAIT_FOR_RESULT,
nsecs_t eventTime = systemTime(SYSTEM_TIME_MONOTONIC),
- std::optional<int32_t> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
+ std::optional<gui::Uid> targetUid = {}, uint32_t policyFlags = DEFAULT_POLICY_FLAGS) {
MotionEventBuilder motionBuilder =
MotionEventBuilder(action, source)
.displayId(displayId)
@@ -5511,7 +5511,7 @@
*/
TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
constexpr int32_t SLIPPERY_PID = WINDOW_PID + 1;
- constexpr int32_t SLIPPERY_UID = WINDOW_UID + 1;
+ constexpr gui::Uid SLIPPERY_UID{WINDOW_UID.val() + 1};
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
@@ -5592,24 +5592,25 @@
}
TEST_F(InputDispatcherTest, NotifiesDeviceInteractionsWithMotions) {
+ using Uid = gui::Uid;
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> leftWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
leftWindow->setFrame(Rect(0, 0, 100, 100));
- leftWindow->setOwnerInfo(1, 101);
+ leftWindow->setOwnerInfo(1, Uid{101});
sp<FakeWindowHandle> rightSpy =
sp<FakeWindowHandle>::make(application, mDispatcher, "Right spy", ADISPLAY_ID_DEFAULT);
rightSpy->setFrame(Rect(100, 0, 200, 100));
- rightSpy->setOwnerInfo(2, 102);
+ rightSpy->setOwnerInfo(2, Uid{102});
rightSpy->setSpy(true);
rightSpy->setTrustedOverlay(true);
sp<FakeWindowHandle> rightWindow =
sp<FakeWindowHandle>::make(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
rightWindow->setFrame(Rect(100, 0, 200, 100));
- rightWindow->setOwnerInfo(3, 103);
+ rightWindow->setOwnerInfo(3, Uid{103});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {rightSpy, rightWindow, leftWindow}}});
@@ -5619,7 +5620,8 @@
.build());
ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionDown());
mDispatcher->waitForIdle();
- ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {101}));
+ ASSERT_NO_FATAL_FAILURE(
+ mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{101}}));
// Touch another finger over the right windows
mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
@@ -5631,7 +5633,8 @@
ASSERT_NO_FATAL_FAILURE(leftWindow->consumeMotionMove());
mDispatcher->waitForIdle();
ASSERT_NO_FATAL_FAILURE(
- mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {101, 102, 103}));
+ mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID,
+ {Uid{101}, Uid{102}, Uid{103}}));
// Release finger over left window. The UP actions are not treated as device interaction.
// The windows that did not receive the UP pointer will receive MOVE events, but since this
@@ -5654,7 +5657,7 @@
ASSERT_NO_FATAL_FAILURE(rightWindow->consumeMotionMove());
mDispatcher->waitForIdle();
ASSERT_NO_FATAL_FAILURE(
- mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {102, 103}));
+ mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {Uid{102}, Uid{103}}));
// Release all fingers
mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN)
@@ -5672,7 +5675,7 @@
sp<FakeWindowHandle> window =
sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
window->setFrame(Rect(0, 0, 100, 100));
- window->setOwnerInfo(1, 101);
+ window->setOwnerInfo(1, gui::Uid{101});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
setFocusedWindow(window);
@@ -5681,7 +5684,8 @@
mDispatcher->notifyKey(KeyArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_KEYBOARD).build());
ASSERT_NO_FATAL_FAILURE(window->consumeKeyDown(ADISPLAY_ID_DEFAULT));
mDispatcher->waitForIdle();
- ASSERT_NO_FATAL_FAILURE(mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {101}));
+ ASSERT_NO_FATAL_FAILURE(
+ mFakePolicy->assertNotifyDeviceInteractionWasCalled(DEVICE_ID, {gui::Uid{101}}));
// The UP actions are not treated as device interaction.
mDispatcher->notifyKey(KeyArgsBuilder(ACTION_UP, AINPUT_SOURCE_KEYBOARD).build());
@@ -7878,9 +7882,9 @@
static_assert(1 - (1 - OPACITY_FAR_BELOW_THRESHOLD) * (1 - OPACITY_FAR_BELOW_THRESHOLD) <
MAXIMUM_OBSCURING_OPACITY);
- static const int32_t TOUCHED_APP_UID = 10001;
- static const int32_t APP_B_UID = 10002;
- static const int32_t APP_C_UID = 10003;
+ static constexpr gui::Uid TOUCHED_APP_UID{10001};
+ static constexpr gui::Uid APP_B_UID{10002};
+ static constexpr gui::Uid APP_C_UID{10003};
sp<FakeWindowHandle> mTouchWindow;
@@ -7895,7 +7899,7 @@
mTouchWindow.clear();
}
- sp<FakeWindowHandle> getOccludingWindow(int32_t uid, std::string name, TouchOcclusionMode mode,
+ sp<FakeWindowHandle> getOccludingWindow(gui::Uid uid, std::string name, TouchOcclusionMode mode,
float alpha = 1.0f) {
sp<FakeWindowHandle> window = getWindow(uid, name);
window->setTouchable(false);
@@ -7904,12 +7908,12 @@
return window;
}
- sp<FakeWindowHandle> getWindow(int32_t uid, std::string name) {
+ sp<FakeWindowHandle> getWindow(gui::Uid uid, std::string name) {
std::shared_ptr<FakeApplicationHandle> app = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
sp<FakeWindowHandle>::make(app, mDispatcher, name, ADISPLAY_ID_DEFAULT);
// Generate an arbitrary PID based on the UID
- window->setOwnerInfo(1777 + (uid % 10000), uid);
+ window->setOwnerInfo(1777 + (uid.val() % 10000), uid);
return window;
}
@@ -8755,13 +8759,13 @@
sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
ADISPLAY_ID_DEFAULT);
obscuringWindow->setFrame(Rect(0, 0, 50, 50));
- obscuringWindow->setOwnerInfo(111, 111);
+ obscuringWindow->setOwnerInfo(111, gui::Uid{111});
obscuringWindow->setTouchable(false);
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
"Test window", ADISPLAY_ID_DEFAULT);
window->setDropInputIfObscured(true);
- window->setOwnerInfo(222, 222);
+ window->setOwnerInfo(222, gui::Uid{222});
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}});
@@ -8798,13 +8802,13 @@
sp<FakeWindowHandle>::make(obscuringApplication, mDispatcher, "obscuringWindow",
ADISPLAY_ID_DEFAULT);
obscuringWindow->setFrame(Rect(0, 0, 50, 50));
- obscuringWindow->setOwnerInfo(111, 111);
+ obscuringWindow->setOwnerInfo(111, gui::Uid{111});
obscuringWindow->setTouchable(false);
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window = sp<FakeWindowHandle>::make(application, mDispatcher,
"Test window", ADISPLAY_ID_DEFAULT);
window->setDropInputIfObscured(true);
- window->setOwnerInfo(222, 222);
+ window->setOwnerInfo(222, gui::Uid{222});
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
window->setFocusable(true);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {obscuringWindow, window}}});
@@ -8881,7 +8885,7 @@
}
}
- void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, int32_t pid, int32_t uid,
+ void changeAndVerifyTouchModeInMainDisplayOnly(bool inTouchMode, int32_t pid, gui::Uid uid,
bool hasPermission) {
ASSERT_TRUE(mDispatcher->setInTouchMode(inTouchMode, pid, uid, hasPermission,
ADISPLAY_ID_DEFAULT));
@@ -8901,8 +8905,8 @@
TEST_F(InputDispatcherTouchModeChangedTests, NonFocusedWindowOwnerCannotChangeTouchMode) {
const WindowInfo& windowInfo = *mWindow->getInfo();
int32_t ownerPid = windowInfo.ownerPid;
- int32_t ownerUid = windowInfo.ownerUid;
- mWindow->setOwnerInfo(/* pid */ -1, /* uid */ -1);
+ gui::Uid ownerUid = windowInfo.ownerUid;
+ mWindow->setOwnerInfo(/*pid=*/-1, gui::Uid::INVALID);
ASSERT_FALSE(mDispatcher->setInTouchMode(InputDispatcher::kDefaultInTouchMode, ownerPid,
ownerUid, /*hasPermission=*/false,
ADISPLAY_ID_DEFAULT));
@@ -8913,8 +8917,8 @@
TEST_F(InputDispatcherTouchModeChangedTests, NonWindowOwnerMayChangeTouchModeOnPermissionGranted) {
const WindowInfo& windowInfo = *mWindow->getInfo();
int32_t ownerPid = windowInfo.ownerPid;
- int32_t ownerUid = windowInfo.ownerUid;
- mWindow->setOwnerInfo(/* pid */ -1, /* uid */ -1);
+ gui::Uid ownerUid = windowInfo.ownerUid;
+ mWindow->setOwnerInfo(/*pid=*/-1, gui::Uid::INVALID);
changeAndVerifyTouchModeInMainDisplayOnly(!InputDispatcher::kDefaultInTouchMode, ownerPid,
ownerUid, /*hasPermission=*/true);
}
@@ -9125,10 +9129,10 @@
*/
TEST_F(InputDispatcherSpyWindowTest, WatchOutsideTouches) {
auto window = createForeground();
- window->setOwnerInfo(12, 34);
+ window->setOwnerInfo(12, gui::Uid{34});
auto spy = createSpy();
spy->setWatchOutsideTouch(true);
- spy->setOwnerInfo(56, 78);
+ spy->setOwnerInfo(56, gui::Uid{78});
spy->setFrame(Rect{0, 0, 20, 20});
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {spy, window}}});
@@ -9541,7 +9545,7 @@
sp<FakeWindowHandle>::make(overlayApplication, mDispatcher,
"Stylus interceptor window", ADISPLAY_ID_DEFAULT);
overlay->setFocusable(false);
- overlay->setOwnerInfo(111, 111);
+ overlay->setOwnerInfo(111, gui::Uid{111});
overlay->setTouchable(false);
overlay->setInterceptsStylus(true);
overlay->setTrustedOverlay(true);
@@ -9552,7 +9556,7 @@
sp<FakeWindowHandle>::make(application, mDispatcher, "Application window",
ADISPLAY_ID_DEFAULT);
window->setFocusable(true);
- window->setOwnerInfo(222, 222);
+ window->setOwnerInfo(222, gui::Uid{222});
mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {overlay, window}}});
@@ -9663,11 +9667,11 @@
struct User {
int32_t mPid;
- int32_t mUid;
+ gui::Uid mUid;
uint32_t mPolicyFlags{DEFAULT_POLICY_FLAGS};
std::unique_ptr<InputDispatcher>& mDispatcher;
- User(std::unique_ptr<InputDispatcher>& dispatcher, int32_t pid, int32_t uid)
+ User(std::unique_ptr<InputDispatcher>& dispatcher, int32_t pid, gui::Uid uid)
: mPid(pid), mUid(uid), mDispatcher(dispatcher) {}
InputEventInjectionResult injectTargetedMotion(int32_t action) const {
@@ -9700,7 +9704,7 @@
using InputDispatcherTargetedInjectionTest = InputDispatcherTest;
TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedWindow) {
- auto owner = User(mDispatcher, 10, 11);
+ auto owner = User(mDispatcher, 10, gui::Uid{11});
auto window = owner.createWindow();
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
@@ -9717,11 +9721,11 @@
}
TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedWindow) {
- auto owner = User(mDispatcher, 10, 11);
+ auto owner = User(mDispatcher, 10, gui::Uid{11});
auto window = owner.createWindow();
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
- auto rando = User(mDispatcher, 20, 21);
+ auto rando = User(mDispatcher, 20, gui::Uid{21});
EXPECT_EQ(InputEventInjectionResult::TARGET_MISMATCH,
rando.injectTargetedMotion(AMOTION_EVENT_ACTION_DOWN));
@@ -9734,7 +9738,7 @@
}
TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoOwnedSpyWindow) {
- auto owner = User(mDispatcher, 10, 11);
+ auto owner = User(mDispatcher, 10, gui::Uid{11});
auto window = owner.createWindow();
auto spy = owner.createWindow();
spy->setSpy(true);
@@ -9748,10 +9752,10 @@
}
TEST_F(InputDispatcherTargetedInjectionTest, CannotInjectIntoUnownedSpyWindow) {
- auto owner = User(mDispatcher, 10, 11);
+ auto owner = User(mDispatcher, 10, gui::Uid{11});
auto window = owner.createWindow();
- auto rando = User(mDispatcher, 20, 21);
+ auto rando = User(mDispatcher, 20, gui::Uid{21});
auto randosSpy = rando.createWindow();
randosSpy->setSpy(true);
randosSpy->setTrustedOverlay(true);
@@ -9766,10 +9770,10 @@
}
TEST_F(InputDispatcherTargetedInjectionTest, CanInjectIntoAnyWindowWhenNotTargeting) {
- auto owner = User(mDispatcher, 10, 11);
+ auto owner = User(mDispatcher, 10, gui::Uid{11});
auto window = owner.createWindow();
- auto rando = User(mDispatcher, 20, 21);
+ auto rando = User(mDispatcher, 20, gui::Uid{21});
auto randosSpy = rando.createWindow();
randosSpy->setSpy(true);
randosSpy->setTrustedOverlay(true);
@@ -9791,10 +9795,10 @@
}
TEST_F(InputDispatcherTargetedInjectionTest, CannotGenerateActionOutsideToOtherUids) {
- auto owner = User(mDispatcher, 10, 11);
+ auto owner = User(mDispatcher, 10, gui::Uid{11});
auto window = owner.createWindow();
- auto rando = User(mDispatcher, 20, 21);
+ auto rando = User(mDispatcher, 20, gui::Uid{21});
auto randosWindow = rando.createWindow();
randosWindow->setFrame(Rect{-10, -10, -5, -5});
randosWindow->setWatchOutsideTouch(true);
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index a992584..f469a1f 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -46,7 +46,7 @@
premultipliedAlpha = state.premultipliedAlpha;
inputInfo.name = state.name;
inputInfo.id = static_cast<int32_t>(uniqueSequence);
- inputInfo.ownerUid = static_cast<int32_t>(state.ownerUid);
+ inputInfo.ownerUid = gui::Uid{state.ownerUid};
inputInfo.ownerPid = state.ownerPid;
uid = state.ownerUid;
pid = state.ownerPid;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 7213ffa..806b502 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -1007,7 +1007,7 @@
snapshot.inputInfo = {};
// b/271132344 revisit this and see if we can always use the layers uid/pid
snapshot.inputInfo.name = requested.name;
- snapshot.inputInfo.ownerUid = static_cast<int32_t>(requested.ownerUid);
+ snapshot.inputInfo.ownerUid = gui::Uid{requested.ownerUid};
snapshot.inputInfo.ownerPid = requested.ownerPid;
}
snapshot.touchCropId = requested.touchCropId;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index fabcd61..a5d7ce7 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2452,7 +2452,7 @@
WindowInfo Layer::fillInputInfo(const InputDisplayArgs& displayArgs) {
if (!hasInputInfo()) {
mDrawingState.inputInfo.name = getName();
- mDrawingState.inputInfo.ownerUid = mOwnerUid;
+ mDrawingState.inputInfo.ownerUid = gui::Uid{mOwnerUid};
mDrawingState.inputInfo.ownerPid = mOwnerPid;
mDrawingState.inputInfo.inputConfig |= WindowInfo::InputConfig::NO_INPUT_CHANNEL;
mDrawingState.inputInfo.displayId = getLayerStack().id;
diff --git a/services/surfaceflinger/Scheduler/Android.bp b/services/surfaceflinger/Scheduler/Android.bp
index d5d8688..6d2586a 100644
--- a/services/surfaceflinger/Scheduler/Android.bp
+++ b/services/surfaceflinger/Scheduler/Android.bp
@@ -40,6 +40,7 @@
name: "libscheduler",
defaults: ["libscheduler_defaults"],
srcs: [
+ "src/FrameTargeter.cpp",
"src/PresentLatencyTracker.cpp",
"src/Timer.cpp",
],
@@ -52,6 +53,7 @@
test_suites: ["device-tests"],
defaults: ["libscheduler_defaults"],
srcs: [
+ "tests/FrameTargeterTest.cpp",
"tests/PresentLatencyTrackerTest.cpp",
"tests/TimerTest.cpp",
],
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 918d401..41639b6 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -171,14 +171,21 @@
void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId,
TimePoint expectedVsyncTime) {
- const TimePoint frameTime = SchedulerClock::now();
+ mPacesetterFrameTargeter.beginFrame({.frameBeginTime = SchedulerClock::now(),
+ .vsyncId = vsyncId,
+ .expectedVsyncTime = expectedVsyncTime,
+ .sfWorkDuration =
+ mVsyncModulator->getVsyncConfig().sfWorkDuration},
+ *getVsyncSchedule());
- if (!compositor.commit(frameTime, vsyncId, expectedVsyncTime)) {
+ if (!compositor.commit(mPacesetterFrameTargeter.target())) {
return;
}
- compositor.composite(frameTime, vsyncId);
+ const auto compositeResult = compositor.composite(mPacesetterFrameTargeter);
compositor.sample();
+
+ mPacesetterFrameTargeter.endFrame(compositeResult);
}
std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const {
@@ -188,23 +195,23 @@
.getFrameRateOverrideForUid(uid, supportsFrameRateOverrideByContent);
}
-bool Scheduler::isVsyncValid(TimePoint expectedVsyncTimestamp, uid_t uid) const {
+bool Scheduler::isVsyncValid(TimePoint expectedVsyncTime, uid_t uid) const {
const auto frameRate = getFrameRateOverride(uid);
if (!frameRate.has_value()) {
return true;
}
ATRACE_FORMAT("%s uid: %d frameRate: %s", __func__, uid, to_string(*frameRate).c_str());
- return getVsyncSchedule()->getTracker().isVSyncInPhase(expectedVsyncTimestamp.ns(), *frameRate);
+ return getVsyncSchedule()->getTracker().isVSyncInPhase(expectedVsyncTime.ns(), *frameRate);
}
-bool Scheduler::isVsyncInPhase(TimePoint timePoint, const Fps frameRate) const {
- return getVsyncSchedule()->getTracker().isVSyncInPhase(timePoint.ns(), frameRate);
+bool Scheduler::isVsyncInPhase(TimePoint expectedVsyncTime, Fps frameRate) const {
+ return getVsyncSchedule()->getTracker().isVSyncInPhase(expectedVsyncTime.ns(), frameRate);
}
impl::EventThread::ThrottleVsyncCallback Scheduler::makeThrottleVsyncCallback() const {
- return [this](nsecs_t expectedVsyncTimestamp, uid_t uid) {
- return !isVsyncValid(TimePoint::fromNs(expectedVsyncTimestamp), uid);
+ return [this](nsecs_t expectedVsyncTime, uid_t uid) {
+ return !isVsyncValid(TimePoint::fromNs(expectedVsyncTime), uid);
};
}
@@ -716,6 +723,8 @@
mFrameRateOverrideMappings.dump(dumper);
dumper.eol();
+
+ mPacesetterFrameTargeter.dump(dumper);
}
void Scheduler::dumpVsync(std::string& out) const {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index a1354fa..17e9cea 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -35,6 +35,7 @@
#include <ftl/fake_guard.h>
#include <ftl/optional.h>
#include <scheduler/Features.h>
+#include <scheduler/FrameTargeter.h>
#include <scheduler/Time.h>
#include <scheduler/VsyncConfig.h>
#include <ui/DisplayId.h>
@@ -249,9 +250,11 @@
return std::const_pointer_cast<VsyncSchedule>(std::as_const(*this).getVsyncSchedule(idOpt));
}
+ const FrameTarget& pacesetterFrameTarget() { return mPacesetterFrameTargeter.target(); }
+
// Returns true if a given vsync timestamp is considered valid vsync
// for a given uid
- bool isVsyncValid(TimePoint expectedVsyncTimestamp, uid_t uid) const;
+ bool isVsyncValid(TimePoint expectedVsyncTime, uid_t uid) const;
bool isVsyncInPhase(TimePoint expectedVsyncTime, Fps frameRate) const;
@@ -446,6 +449,8 @@
ftl::Optional<PhysicalDisplayId> mPacesetterDisplayId GUARDED_BY(mDisplayLock)
GUARDED_BY(kMainThreadContext);
+ FrameTargeter mPacesetterFrameTargeter{mFeatures.test(Feature::kBackpressureGpuComposition)};
+
ftl::Optional<DisplayRef> pacesetterDisplayLocked() REQUIRES(mDisplayLock) {
return static_cast<const Scheduler*>(this)->pacesetterDisplayLocked().transform(
[](const Display& display) { return std::ref(const_cast<Display&>(display)); });
diff --git a/services/surfaceflinger/Scheduler/VsyncSchedule.h b/services/surfaceflinger/Scheduler/VsyncSchedule.h
index 556ef80..c037ac8 100644
--- a/services/surfaceflinger/Scheduler/VsyncSchedule.h
+++ b/services/surfaceflinger/Scheduler/VsyncSchedule.h
@@ -20,14 +20,17 @@
#include <memory>
#include <string>
-#include <ThreadContext.h>
#include <android-base/thread_annotations.h>
#include <ftl/enum.h>
#include <ftl/optional.h>
-#include <scheduler/Features.h>
-#include <scheduler/Time.h>
#include <ui/DisplayId.h>
+#include <scheduler/Features.h>
+#include <scheduler/IVsyncSource.h>
+#include <scheduler/Time.h>
+
+#include "ThreadContext.h"
+
namespace android {
class EventThreadTest;
class VsyncScheduleTest;
@@ -48,15 +51,16 @@
using VsyncTracker = VSyncTracker;
// Schedule that synchronizes to hardware VSYNC of a physical display.
-class VsyncSchedule {
+class VsyncSchedule final : public IVsyncSource {
public:
using RequestHardwareVsync = std::function<void(PhysicalDisplayId, bool enabled)>;
VsyncSchedule(PhysicalDisplayId, FeatureFlags, RequestHardwareVsync);
~VsyncSchedule();
- Period period() const;
- TimePoint vsyncDeadlineAfter(TimePoint) const;
+ // IVsyncSource overrides:
+ Period period() const override;
+ TimePoint vsyncDeadlineAfter(TimePoint) const override;
// Inform the schedule that the period is changing and the schedule needs to recalibrate
// itself. The schedule will end the period transition internally. This will
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/Features.h b/services/surfaceflinger/Scheduler/include/scheduler/Features.h
index b3a6a60..200407d 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/Features.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/Features.h
@@ -23,10 +23,11 @@
namespace android::scheduler {
enum class Feature : std::uint8_t {
- kPresentFences = 0b1,
- kKernelIdleTimer = 0b10,
- kContentDetection = 0b100,
- kTracePredictedVsync = 0b1000,
+ kPresentFences = 1 << 0,
+ kKernelIdleTimer = 1 << 1,
+ kContentDetection = 1 << 2,
+ kTracePredictedVsync = 1 << 3,
+ kBackpressureGpuComposition = 1 << 4,
};
using FeatureFlags = ftl::Flags<Feature>;
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
new file mode 100644
index 0000000..85f2e64
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <array>
+#include <atomic>
+#include <memory>
+
+#include <ui/Fence.h>
+#include <ui/FenceTime.h>
+
+#include <scheduler/Time.h>
+#include <scheduler/VsyncId.h>
+#include <scheduler/interface/CompositeResult.h>
+
+// TODO(b/185536303): Pull to FTL.
+#include "../../../TracedOrdinal.h"
+#include "../../../Utils/Dumper.h"
+
+namespace android::scheduler {
+
+struct IVsyncSource;
+
+// Read-only interface to the metrics computed by FrameTargeter for the latest frame.
+class FrameTarget {
+public:
+ VsyncId vsyncId() const { return mVsyncId; }
+
+ // The time when the frame actually began, as opposed to when it had been scheduled to begin.
+ TimePoint frameBeginTime() const { return mFrameBeginTime; }
+
+ // Relative to when the frame actually began, as opposed to when it had been scheduled to begin.
+ Duration expectedFrameDuration() const { return mExpectedPresentTime - mFrameBeginTime; }
+
+ TimePoint expectedPresentTime() const { return mExpectedPresentTime; }
+
+ // The time of the VSYNC that preceded this frame. See `presentFenceForPastVsync` for details.
+ TimePoint pastVsyncTime(Period vsyncPeriod) const;
+
+ // Equivalent to `pastVsyncTime` unless running N VSYNCs ahead.
+ TimePoint previousFrameVsyncTime(Period vsyncPeriod) const {
+ return mExpectedPresentTime - vsyncPeriod;
+ }
+
+ // The present fence for the frame that had targeted the most recent VSYNC before this frame.
+ // If the target VSYNC for any given frame is more than `vsyncPeriod` in the future, then the
+ // VSYNC of at least one previous frame has not yet passed. In other words, this is NOT the
+ // `presentFenceForPreviousFrame` if running N VSYNCs ahead, but the one that should have been
+ // signaled by now (unless that frame missed).
+ const FenceTimePtr& presentFenceForPastVsync(Period vsyncPeriod) const;
+
+ // Equivalent to `presentFenceForPastVsync` unless running N VSYNCs ahead.
+ const FenceTimePtr& presentFenceForPreviousFrame() const {
+ return mPresentFences.front().fenceTime;
+ }
+
+ bool wouldPresentEarly(Period vsyncPeriod) const;
+
+ bool isFramePending() const { return mFramePending; }
+ bool didMissFrame() const { return mFrameMissed; }
+ bool didMissHwcFrame() const { return mHwcFrameMissed && !mGpuFrameMissed; }
+
+protected:
+ ~FrameTarget() = default;
+
+ VsyncId mVsyncId;
+ TimePoint mFrameBeginTime;
+ TimePoint mExpectedPresentTime;
+
+ TracedOrdinal<bool> mFramePending{"PrevFramePending", false};
+ TracedOrdinal<bool> mFrameMissed{"PrevFrameMissed", false};
+ TracedOrdinal<bool> mHwcFrameMissed{"PrevHwcFrameMissed", false};
+ TracedOrdinal<bool> mGpuFrameMissed{"PrevGpuFrameMissed", false};
+
+ struct FenceWithFenceTime {
+ sp<Fence> fence = Fence::NO_FENCE;
+ FenceTimePtr fenceTime = FenceTime::NO_FENCE;
+ };
+ std::array<FenceWithFenceTime, 2> mPresentFences;
+
+private:
+ template <int N>
+ inline bool targetsVsyncsAhead(Period vsyncPeriod) const {
+ static_assert(N > 1);
+ return expectedFrameDuration() > (N - 1) * vsyncPeriod;
+ }
+};
+
+// Computes a display's per-frame metrics about past/upcoming targeting of present deadlines.
+class FrameTargeter final : private FrameTarget {
+public:
+ explicit FrameTargeter(bool backpressureGpuComposition)
+ : mBackpressureGpuComposition(backpressureGpuComposition) {}
+
+ const FrameTarget& target() const { return *this; }
+
+ struct BeginFrameArgs {
+ TimePoint frameBeginTime;
+ VsyncId vsyncId;
+ TimePoint expectedVsyncTime;
+ Duration sfWorkDuration;
+ };
+
+ void beginFrame(const BeginFrameArgs&, const IVsyncSource&);
+
+ // TODO(b/241285191): Merge with FrameTargeter::endFrame.
+ FenceTimePtr setPresentFence(sp<Fence>);
+
+ void endFrame(const CompositeResult&);
+
+ void dump(utils::Dumper&) const;
+
+private:
+ friend class FrameTargeterTest;
+
+ // For tests.
+ using IsFencePendingFuncPtr = bool (*)(const FenceTimePtr&, int graceTimeMs);
+ void beginFrame(const BeginFrameArgs&, const IVsyncSource&, IsFencePendingFuncPtr);
+ FenceTimePtr setPresentFence(sp<Fence>, FenceTimePtr);
+
+ static bool isFencePending(const FenceTimePtr&, int graceTimeMs);
+
+ const bool mBackpressureGpuComposition;
+
+ TimePoint mScheduledPresentTime;
+ CompositionCoverageFlags mCompositionCoverage;
+
+ std::atomic_uint mFrameMissedCount = 0;
+ std::atomic_uint mHwcFrameMissedCount = 0;
+ std::atomic_uint mGpuFrameMissedCount = 0;
+};
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/IVsyncSource.h b/services/surfaceflinger/Scheduler/include/scheduler/IVsyncSource.h
new file mode 100644
index 0000000..bb2de75
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/include/scheduler/IVsyncSource.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <scheduler/Time.h>
+
+namespace android::scheduler {
+
+struct IVsyncSource {
+ virtual Period period() const = 0;
+ virtual TimePoint vsyncDeadlineAfter(TimePoint) const = 0;
+
+protected:
+ ~IVsyncSource() = default;
+};
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h
new file mode 100644
index 0000000..f795f1f
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <scheduler/interface/CompositionCoverage.h>
+
+namespace android {
+
+struct CompositeResult {
+ CompositionCoverageFlags compositionCoverage;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
index cc41925..2696076 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
@@ -18,8 +18,15 @@
#include <scheduler/Time.h>
#include <scheduler/VsyncId.h>
+#include <scheduler/interface/CompositeResult.h>
namespace android {
+namespace scheduler {
+
+class FrameTarget;
+class FrameTargeter;
+
+} // namespace scheduler
struct ICompositor {
// Configures physical displays, processing hotplug and/or mode setting via the Composer HAL.
@@ -27,11 +34,11 @@
// Commits transactions for layers and displays. Returns whether any state has been invalidated,
// i.e. whether a frame should be composited for each display.
- virtual bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) = 0;
+ virtual bool commit(const scheduler::FrameTarget&) = 0;
// Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition
// via RenderEngine and the Composer HAL, respectively.
- virtual void composite(TimePoint frameTime, VsyncId) = 0;
+ virtual CompositeResult composite(scheduler::FrameTargeter&) = 0;
// Samples the composited frame via RegionSamplingThread.
virtual void sample() = 0;
diff --git a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp
new file mode 100644
index 0000000..7138afd
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/TraceUtils.h>
+
+#include <scheduler/FrameTargeter.h>
+#include <scheduler/IVsyncSource.h>
+
+namespace android::scheduler {
+
+TimePoint FrameTarget::pastVsyncTime(Period vsyncPeriod) const {
+ // TODO(b/267315508): Generalize to N VSYNCs.
+ const int shift = static_cast<int>(targetsVsyncsAhead<2>(vsyncPeriod));
+ return mExpectedPresentTime - Period::fromNs(vsyncPeriod.ns() << shift);
+}
+
+const FenceTimePtr& FrameTarget::presentFenceForPastVsync(Period vsyncPeriod) const {
+ // TODO(b/267315508): Generalize to N VSYNCs.
+ const size_t i = static_cast<size_t>(targetsVsyncsAhead<2>(vsyncPeriod));
+ return mPresentFences[i].fenceTime;
+}
+
+bool FrameTarget::wouldPresentEarly(Period vsyncPeriod) const {
+ // TODO(b/241285475): Since this is called during `composite`, the calls to `targetsVsyncsAhead`
+ // should use `TimePoint::now()` in case of delays since `mFrameBeginTime`.
+
+ // TODO(b/267315508): Generalize to N VSYNCs.
+ if (targetsVsyncsAhead<3>(vsyncPeriod)) {
+ return true;
+ }
+
+ const auto fence = presentFenceForPastVsync(vsyncPeriod);
+ return fence->isValid() && fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+}
+
+void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource) {
+ return beginFrame(args, vsyncSource, &FrameTargeter::isFencePending);
+}
+
+void FrameTargeter::beginFrame(const BeginFrameArgs& args, const IVsyncSource& vsyncSource,
+ IsFencePendingFuncPtr isFencePendingFuncPtr) {
+ mVsyncId = args.vsyncId;
+ mFrameBeginTime = args.frameBeginTime;
+
+ // The `expectedVsyncTime`, which was predicted when this frame was scheduled, is normally in
+ // the future relative to `frameBeginTime`, but may not be for delayed frames. Adjust
+ // `mExpectedPresentTime` accordingly, but not `mScheduledPresentTime`.
+ const TimePoint lastScheduledPresentTime = mScheduledPresentTime;
+ mScheduledPresentTime = args.expectedVsyncTime;
+
+ const Period vsyncPeriod = vsyncSource.period();
+
+ // Calculate the expected present time once and use the cached value throughout this frame to
+ // make sure all layers are seeing this same value.
+ if (args.expectedVsyncTime >= args.frameBeginTime) {
+ mExpectedPresentTime = args.expectedVsyncTime;
+ } else {
+ mExpectedPresentTime = vsyncSource.vsyncDeadlineAfter(args.frameBeginTime);
+ if (args.sfWorkDuration > vsyncPeriod) {
+ // Inflate the expected present time if we're targeting the next VSYNC.
+ mExpectedPresentTime += vsyncPeriod;
+ }
+ }
+
+ ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, ftl::to_underlying(args.vsyncId),
+ ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()),
+ mExpectedPresentTime == args.expectedVsyncTime ? "" : " (adjusted)");
+
+ const FenceTimePtr& pastPresentFence = presentFenceForPastVsync(vsyncPeriod);
+
+ // In cases where the present fence is about to fire, give it a small grace period instead of
+ // giving up on the frame.
+ //
+ // TODO(b/280667110): The grace period should depend on `sfWorkDuration` and `vsyncPeriod` being
+ // approximately equal, not whether backpressure propagation is enabled.
+ const int graceTimeForPresentFenceMs = static_cast<int>(
+ mBackpressureGpuComposition || !mCompositionCoverage.test(CompositionCoverage::Gpu));
+
+ // Pending frames may trigger backpressure propagation.
+ const auto& isFencePending = *isFencePendingFuncPtr;
+ mFramePending = pastPresentFence != FenceTime::NO_FENCE &&
+ isFencePending(pastPresentFence, graceTimeForPresentFenceMs);
+
+ // A frame is missed if the prior frame is still pending. If no longer pending, then we still
+ // count the frame as missed if the predicted present time was further in the past than when the
+ // fence actually fired. Add some slop to correct for drift. This should generally be smaller
+ // than a typical frame duration, but should not be so small that it reports reasonable drift as
+ // a missed frame.
+ mFrameMissed = mFramePending || [&] {
+ const nsecs_t pastPresentTime = pastPresentFence->getSignalTime();
+ if (pastPresentTime < 0) return false;
+ const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2;
+ return lastScheduledPresentTime.ns() < pastPresentTime - frameMissedSlop;
+ }();
+
+ mHwcFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Hwc);
+ mGpuFrameMissed = mFrameMissed && mCompositionCoverage.test(CompositionCoverage::Gpu);
+
+ if (mFrameMissed) mFrameMissedCount++;
+ if (mHwcFrameMissed) mHwcFrameMissedCount++;
+ if (mGpuFrameMissed) mGpuFrameMissedCount++;
+}
+
+void FrameTargeter::endFrame(const CompositeResult& result) {
+ mCompositionCoverage = result.compositionCoverage;
+}
+
+FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence) {
+ auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
+ return setPresentFence(std::move(presentFence), std::move(presentFenceTime));
+}
+
+FenceTimePtr FrameTargeter::setPresentFence(sp<Fence> presentFence, FenceTimePtr presentFenceTime) {
+ mPresentFences[1] = mPresentFences[0];
+ mPresentFences[0] = {std::move(presentFence), presentFenceTime};
+ return presentFenceTime;
+}
+
+void FrameTargeter::dump(utils::Dumper& dumper) const {
+ using namespace std::string_view_literals;
+
+ utils::Dumper::Section section(dumper, "Frame Targeting"sv);
+
+ // There are scripts and tests that expect this (rather than "name=value") format.
+ dumper.dump({}, "Total missed frame count: " + std::to_string(mFrameMissedCount));
+ dumper.dump({}, "HWC missed frame count: " + std::to_string(mHwcFrameMissedCount));
+ dumper.dump({}, "GPU missed frame count: " + std::to_string(mGpuFrameMissedCount));
+}
+
+bool FrameTargeter::isFencePending(const FenceTimePtr& fence, int graceTimeMs) {
+ ATRACE_CALL();
+ const status_t status = fence->wait(graceTimeMs);
+
+ // This is the same as Fence::Status::Unsignaled, but it saves a call to getStatus,
+ // which calls wait(0) again internally.
+ return status == -ETIME;
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp
new file mode 100644
index 0000000..908f214
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ftl/optional.h>
+#include <gtest/gtest.h>
+
+#include <scheduler/Fps.h>
+#include <scheduler/FrameTargeter.h>
+#include <scheduler/IVsyncSource.h>
+
+using namespace std::chrono_literals;
+
+namespace android::scheduler {
+namespace {
+
+struct VsyncSource final : IVsyncSource {
+ VsyncSource(Period period, TimePoint deadline) : vsyncPeriod(period), vsyncDeadline(deadline) {}
+
+ const Period vsyncPeriod;
+ const TimePoint vsyncDeadline;
+
+ Period period() const override { return vsyncPeriod; }
+ TimePoint vsyncDeadlineAfter(TimePoint) const override { return vsyncDeadline; }
+};
+
+} // namespace
+
+class FrameTargeterTest : public testing::Test {
+public:
+ const auto& target() const { return mTargeter.target(); }
+
+ struct Frame {
+ Frame(FrameTargeterTest* testPtr, VsyncId vsyncId, TimePoint& frameBeginTime,
+ Duration frameDuration, Fps refreshRate,
+ FrameTargeter::IsFencePendingFuncPtr isFencePendingFuncPtr = Frame::fenceSignaled,
+ const ftl::Optional<VsyncSource>& vsyncSourceOpt = std::nullopt)
+ : testPtr(testPtr), frameBeginTime(frameBeginTime), period(refreshRate.getPeriod()) {
+ const FrameTargeter::BeginFrameArgs args{.frameBeginTime = frameBeginTime,
+ .vsyncId = vsyncId,
+ .expectedVsyncTime =
+ frameBeginTime + frameDuration,
+ .sfWorkDuration = 10ms};
+
+ testPtr->mTargeter.beginFrame(args,
+ vsyncSourceOpt
+ .or_else([&] {
+ return std::make_optional(
+ VsyncSource(period,
+ args.expectedVsyncTime));
+ })
+ .value(),
+ isFencePendingFuncPtr);
+ }
+
+ FenceTimePtr end(CompositionCoverage coverage = CompositionCoverage::Hwc) {
+ if (ended) return nullptr;
+ ended = true;
+
+ auto [fence, fenceTime] = testPtr->mFenceMap.makePendingFenceForTest();
+ testPtr->mTargeter.setPresentFence(std::move(fence), fenceTime);
+
+ testPtr->mTargeter.endFrame({.compositionCoverage = coverage});
+ return fenceTime;
+ }
+
+ ~Frame() {
+ end();
+ frameBeginTime += period;
+ }
+
+ static bool fencePending(const FenceTimePtr&, int) { return true; }
+ static bool fenceSignaled(const FenceTimePtr&, int) { return false; }
+
+ FrameTargeterTest* const testPtr;
+
+ TimePoint& frameBeginTime;
+ const Period period;
+
+ bool ended = false;
+ };
+
+private:
+ FenceToFenceTimeMap mFenceMap;
+
+ static constexpr bool kBackpressureGpuComposition = true;
+ FrameTargeter mTargeter{kBackpressureGpuComposition};
+};
+
+TEST_F(FrameTargeterTest, targetsFrames) {
+ VsyncId vsyncId{42};
+ {
+ TimePoint frameBeginTime(989ms);
+ const Frame frame(this, vsyncId++, frameBeginTime, 10ms, 60_Hz);
+
+ EXPECT_EQ(target().vsyncId(), VsyncId{42});
+ EXPECT_EQ(target().frameBeginTime(), TimePoint(989ms));
+ EXPECT_EQ(target().expectedPresentTime(), TimePoint(999ms));
+ EXPECT_EQ(target().expectedFrameDuration(), 10ms);
+ }
+ {
+ TimePoint frameBeginTime(1100ms);
+ const Frame frame(this, vsyncId++, frameBeginTime, 11ms, 60_Hz);
+
+ EXPECT_EQ(target().vsyncId(), VsyncId{43});
+ EXPECT_EQ(target().frameBeginTime(), TimePoint(1100ms));
+ EXPECT_EQ(target().expectedPresentTime(), TimePoint(1111ms));
+ EXPECT_EQ(target().expectedFrameDuration(), 11ms);
+ }
+}
+
+TEST_F(FrameTargeterTest, inflatesExpectedPresentTime) {
+ // Negative such that `expectedVsyncTime` is in the past.
+ constexpr Duration kFrameDuration = -3ms;
+ TimePoint frameBeginTime(777ms);
+
+ constexpr Fps kRefreshRate = 120_Hz;
+ const VsyncSource vsyncSource(kRefreshRate.getPeriod(), frameBeginTime + 5ms);
+ const Frame frame(this, VsyncId{123}, frameBeginTime, kFrameDuration, kRefreshRate,
+ Frame::fenceSignaled, vsyncSource);
+
+ EXPECT_EQ(target().expectedPresentTime(), vsyncSource.vsyncDeadline + vsyncSource.vsyncPeriod);
+}
+
+TEST_F(FrameTargeterTest, recallsPastVsync) {
+ VsyncId vsyncId{111};
+ TimePoint frameBeginTime(1000ms);
+ constexpr Fps kRefreshRate = 60_Hz;
+ constexpr Period kPeriod = kRefreshRate.getPeriod();
+ constexpr Duration kFrameDuration = 13ms;
+
+ for (int n = 5; n-- > 0;) {
+ Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate);
+ const auto fence = frame.end();
+
+ EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - kPeriod);
+ EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), fence);
+ }
+}
+
+TEST_F(FrameTargeterTest, recallsPastVsyncTwoVsyncsAhead) {
+ VsyncId vsyncId{222};
+ TimePoint frameBeginTime(2000ms);
+ constexpr Fps kRefreshRate = 120_Hz;
+ constexpr Period kPeriod = kRefreshRate.getPeriod();
+ constexpr Duration kFrameDuration = 10ms;
+
+ FenceTimePtr previousFence = FenceTime::NO_FENCE;
+
+ for (int n = 5; n-- > 0;) {
+ Frame frame(this, vsyncId++, frameBeginTime, kFrameDuration, kRefreshRate);
+ const auto fence = frame.end();
+
+ EXPECT_EQ(target().pastVsyncTime(kPeriod), frameBeginTime + kFrameDuration - 2 * kPeriod);
+ EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), previousFence);
+
+ previousFence = fence;
+ }
+}
+
+TEST_F(FrameTargeterTest, doesNotDetectEarlyPresentIfNoFence) {
+ constexpr Period kPeriod = (60_Hz).getPeriod();
+ EXPECT_EQ(target().presentFenceForPastVsync(kPeriod), FenceTime::NO_FENCE);
+ EXPECT_FALSE(target().wouldPresentEarly(kPeriod));
+}
+
+TEST_F(FrameTargeterTest, detectsEarlyPresent) {
+ VsyncId vsyncId{333};
+ TimePoint frameBeginTime(3000ms);
+ constexpr Fps kRefreshRate = 60_Hz;
+ constexpr Period kPeriod = kRefreshRate.getPeriod();
+
+ // The target is not early while past present fences are pending.
+ for (int n = 3; n-- > 0;) {
+ const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate);
+ EXPECT_FALSE(target().wouldPresentEarly(kPeriod));
+ }
+
+ // The target is early if the past present fence was signaled.
+ Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate);
+ const auto fence = frame.end();
+ fence->signalForTest(frameBeginTime.ns());
+
+ EXPECT_TRUE(target().wouldPresentEarly(kPeriod));
+}
+
+TEST_F(FrameTargeterTest, detectsEarlyPresentTwoVsyncsAhead) {
+ VsyncId vsyncId{444};
+ TimePoint frameBeginTime(4000ms);
+ constexpr Fps kRefreshRate = 120_Hz;
+ constexpr Period kPeriod = kRefreshRate.getPeriod();
+
+ // The target is not early while past present fences are pending.
+ for (int n = 3; n-- > 0;) {
+ const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate);
+ EXPECT_FALSE(target().wouldPresentEarly(kPeriod));
+ }
+
+ Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate);
+ const auto fence = frame.end();
+ fence->signalForTest(frameBeginTime.ns());
+
+ // The target is two VSYNCs ahead, so the past present fence is still pending.
+ EXPECT_FALSE(target().wouldPresentEarly(kPeriod));
+
+ { const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate); }
+
+ // The target is early if the past present fence was signaled.
+ EXPECT_TRUE(target().wouldPresentEarly(kPeriod));
+}
+
+TEST_F(FrameTargeterTest, detectsEarlyPresentThreeVsyncsAhead) {
+ TimePoint frameBeginTime(5000ms);
+ constexpr Fps kRefreshRate = 144_Hz;
+ constexpr Period kPeriod = kRefreshRate.getPeriod();
+
+ const Frame frame(this, VsyncId{555}, frameBeginTime, 16ms, kRefreshRate);
+
+ // The target is more than two VSYNCs ahead, but present fences are not tracked that far back.
+ EXPECT_TRUE(target().wouldPresentEarly(kPeriod));
+}
+
+TEST_F(FrameTargeterTest, detectsMissedFrames) {
+ VsyncId vsyncId{555};
+ TimePoint frameBeginTime(5000ms);
+ constexpr Fps kRefreshRate = 60_Hz;
+ constexpr Period kPeriod = kRefreshRate.getPeriod();
+
+ EXPECT_FALSE(target().isFramePending());
+ EXPECT_FALSE(target().didMissFrame());
+ EXPECT_FALSE(target().didMissHwcFrame());
+
+ {
+ const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate);
+ EXPECT_FALSE(target().isFramePending());
+
+ // The frame did not miss if the past present fence is invalid.
+ EXPECT_FALSE(target().didMissFrame());
+ EXPECT_FALSE(target().didMissHwcFrame());
+ }
+ {
+ Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, Frame::fencePending);
+ EXPECT_TRUE(target().isFramePending());
+
+ // The frame missed if the past present fence is pending.
+ EXPECT_TRUE(target().didMissFrame());
+ EXPECT_TRUE(target().didMissHwcFrame());
+
+ frame.end(CompositionCoverage::Gpu);
+ }
+ {
+ const Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate, Frame::fencePending);
+ EXPECT_TRUE(target().isFramePending());
+
+ // The GPU frame missed if the past present fence is pending.
+ EXPECT_TRUE(target().didMissFrame());
+ EXPECT_FALSE(target().didMissHwcFrame());
+ }
+ {
+ Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate);
+ EXPECT_FALSE(target().isFramePending());
+
+ const auto fence = frame.end();
+ const auto expectedPresentTime = target().expectedPresentTime();
+ fence->signalForTest(expectedPresentTime.ns() + kPeriod.ns() / 2 + 1);
+ }
+ {
+ Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate);
+ EXPECT_FALSE(target().isFramePending());
+
+ const auto fence = frame.end();
+ const auto expectedPresentTime = target().expectedPresentTime();
+ fence->signalForTest(expectedPresentTime.ns() + kPeriod.ns() / 2);
+
+ // The frame missed if the past present fence was signaled but not within slop.
+ EXPECT_TRUE(target().didMissFrame());
+ EXPECT_TRUE(target().didMissHwcFrame());
+ }
+ {
+ Frame frame(this, vsyncId++, frameBeginTime, 10ms, kRefreshRate);
+ EXPECT_FALSE(target().isFramePending());
+
+ // The frame did not miss if the past present fence was signaled within slop.
+ EXPECT_FALSE(target().didMissFrame());
+ EXPECT_FALSE(target().didMissHwcFrame());
+ }
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp b/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp
index 8952ca9..df2ea83 100644
--- a/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp
+++ b/services/surfaceflinger/Scheduler/tests/PresentLatencyTrackerTest.cpp
@@ -23,16 +23,6 @@
#include <ui/FenceTime.h>
namespace android::scheduler {
-namespace {
-
-using FencePair = std::pair<sp<Fence>, std::shared_ptr<FenceTime>>;
-
-FencePair makePendingFence(FenceToFenceTimeMap& fenceMap) {
- const auto fence = sp<Fence>::make();
- return {fence, fenceMap.createFenceTimeForTest(fence)};
-}
-
-} // namespace
TEST(PresentLatencyTrackerTest, skipsInvalidFences) {
PresentLatencyTracker tracker;
@@ -43,7 +33,7 @@
EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, FenceTime::NO_FENCE), Duration::zero());
FenceToFenceTimeMap fenceMap;
- const auto [fence, fenceTime] = makePendingFence(fenceMap);
+ const auto [fence, fenceTime] = fenceMap.makePendingFenceForTest();
EXPECT_EQ(tracker.trackPendingFrame(kCompositeTime, fenceTime), Duration::zero());
fenceTime->signalForTest(9999);
@@ -56,8 +46,9 @@
PresentLatencyTracker tracker;
FenceToFenceTimeMap fenceMap;
- std::array<FencePair, PresentLatencyTracker::kMaxPendingFrames> fences;
- std::generate(fences.begin(), fences.end(), [&fenceMap] { return makePendingFence(fenceMap); });
+ std::array<FenceToFenceTimeMap::FencePair, PresentLatencyTracker::kMaxPendingFrames> fences;
+ std::generate(fences.begin(), fences.end(),
+ [&fenceMap] { return fenceMap.makePendingFenceForTest(); });
// The present latency is 0 if all fences are pending.
const TimePoint kCompositeTime = TimePoint::fromNs(1234);
@@ -71,7 +62,7 @@
fences[i].second->signalForTest(kCompositeTime.ns() + static_cast<nsecs_t>(i));
}
- const auto fence = makePendingFence(fenceMap);
+ const auto fence = fenceMap.makePendingFenceForTest();
// ...then the present latency is measured using the latest frame.
constexpr Duration kPresentLatency = Duration::fromNs(static_cast<nsecs_t>(kPresentCount) - 1);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e0ffb6b..c6fdcfe 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -77,6 +77,7 @@
#include <processgroup/processgroup.h>
#include <renderengine/RenderEngine.h>
#include <renderengine/impl/ExternalTexture.h>
+#include <scheduler/FrameTargeter.h>
#include <sys/types.h>
#include <ui/ColorSpace.h>
#include <ui/DataspaceUtils.h>
@@ -2162,44 +2163,6 @@
}
}
-bool SurfaceFlinger::wouldPresentEarly(TimePoint frameTime, Period vsyncPeriod) const {
- const bool isThreeVsyncsAhead = mExpectedPresentTime - frameTime > 2 * vsyncPeriod;
- return isThreeVsyncsAhead ||
- getPreviousPresentFence(frameTime, vsyncPeriod)->getSignalTime() !=
- Fence::SIGNAL_TIME_PENDING;
-}
-
-auto SurfaceFlinger::getPreviousPresentFence(TimePoint frameTime, Period vsyncPeriod) const
- -> const FenceTimePtr& {
- const bool isTwoVsyncsAhead = mExpectedPresentTime - frameTime > vsyncPeriod;
- const size_t i = static_cast<size_t>(isTwoVsyncsAhead);
- return mPreviousPresentFences[i].fenceTime;
-}
-
-bool SurfaceFlinger::isFencePending(const FenceTimePtr& fence, int graceTimeMs) {
- ATRACE_CALL();
- if (fence == FenceTime::NO_FENCE) {
- return false;
- }
-
- const status_t status = fence->wait(graceTimeMs);
- // This is the same as Fence::Status::Unsignaled, but it saves a getStatus() call,
- // which calls wait(0) again internally
- return status == -ETIME;
-}
-
-TimePoint SurfaceFlinger::calculateExpectedPresentTime(TimePoint frameTime) const {
- const auto& schedule = mScheduler->getVsyncSchedule();
-
- const TimePoint vsyncDeadline = schedule->vsyncDeadlineAfter(frameTime);
- if (mScheduler->vsyncModulator().getVsyncConfig().sfOffset > 0) {
- return vsyncDeadline;
- }
-
- // Inflate the expected present time if we're targeting the next vsync.
- return vsyncDeadline + schedule->period();
-}
-
void SurfaceFlinger::configure() FTL_FAKE_GUARD(kMainThreadContext) {
Mutex::Autolock lock(mStateLock);
if (configureLocked()) {
@@ -2373,75 +2336,15 @@
return mustComposite;
}
-bool SurfaceFlinger::commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime)
+bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget)
FTL_FAKE_GUARD(kMainThreadContext) {
- // The expectedVsyncTime, which was predicted when this frame was scheduled, is normally in the
- // future relative to frameTime, but may not be for delayed frames. Adjust mExpectedPresentTime
- // accordingly, but not mScheduledPresentTime.
- const TimePoint lastScheduledPresentTime = mScheduledPresentTime;
- mScheduledPresentTime = expectedVsyncTime;
+ const VsyncId vsyncId = pacesetterFrameTarget.vsyncId();
+ ATRACE_NAME(ftl::Concat(__func__, ' ', ftl::to_underlying(vsyncId)).c_str());
- // Calculate the expected present time once and use the cached value throughout this frame to
- // make sure all layers are seeing this same value.
- mExpectedPresentTime = expectedVsyncTime >= frameTime ? expectedVsyncTime
- : calculateExpectedPresentTime(frameTime);
-
- ATRACE_FORMAT("%s %" PRId64 " vsyncIn %.2fms%s", __func__, ftl::to_underlying(vsyncId),
- ticks<std::milli, float>(mExpectedPresentTime - TimePoint::now()),
- mExpectedPresentTime == expectedVsyncTime ? "" : " (adjusted)");
-
- const Period vsyncPeriod = mScheduler->getVsyncSchedule()->period();
- const FenceTimePtr& previousPresentFence = getPreviousPresentFence(frameTime, vsyncPeriod);
-
- // When backpressure propagation is enabled, we want to give a small grace period of 1ms
- // for the present fence to fire instead of just giving up on this frame to handle cases
- // where present fence is just about to get signaled.
- const int graceTimeForPresentFenceMs = static_cast<int>(
- mBackpressureGpuComposition || !mCompositionCoverage.test(CompositionCoverage::Gpu));
-
- // Pending frames may trigger backpressure propagation.
- const TracedOrdinal<bool> framePending = {"PrevFramePending",
- isFencePending(previousPresentFence,
- graceTimeForPresentFenceMs)};
-
- // Frame missed counts for metrics tracking.
- // A frame is missed if the prior frame is still pending. If no longer pending,
- // then we still count the frame as missed if the predicted present time
- // was further in the past than when the fence actually fired.
-
- // Add some slop to correct for drift. This should generally be
- // smaller than a typical frame duration, but should not be so small
- // that it reports reasonable drift as a missed frame.
- const nsecs_t frameMissedSlop = vsyncPeriod.ns() / 2;
- const nsecs_t previousPresentTime = previousPresentFence->getSignalTime();
- const TracedOrdinal<bool> frameMissed = {"PrevFrameMissed",
- framePending ||
- (previousPresentTime >= 0 &&
- (lastScheduledPresentTime.ns() <
- previousPresentTime - frameMissedSlop))};
- const TracedOrdinal<bool> hwcFrameMissed = {"PrevHwcFrameMissed",
- frameMissed &&
- mCompositionCoverage.test(
- CompositionCoverage::Hwc)};
-
- const TracedOrdinal<bool> gpuFrameMissed = {"PrevGpuFrameMissed",
- frameMissed &&
- mCompositionCoverage.test(
- CompositionCoverage::Gpu)};
-
- if (frameMissed) {
- mFrameMissedCount++;
+ if (pacesetterFrameTarget.didMissFrame()) {
mTimeStats->incrementMissedFrames();
}
- if (hwcFrameMissed) {
- mHwcFrameMissedCount++;
- }
-
- if (gpuFrameMissed) {
- mGpuFrameMissedCount++;
- }
-
if (mTracingEnabledChanged) {
mLayerTracingEnabled = mLayerTracing.isEnabled();
mTracingEnabledChanged = false;
@@ -2450,7 +2353,7 @@
// If we are in the middle of a mode change and the fence hasn't
// fired yet just wait for the next commit.
if (mSetActiveModePending) {
- if (framePending) {
+ if (pacesetterFrameTarget.isFramePending()) {
mScheduler->scheduleFrame();
return false;
}
@@ -2464,26 +2367,29 @@
}
}
- if (framePending) {
- if (mBackpressureGpuComposition || (hwcFrameMissed && !gpuFrameMissed)) {
+ if (pacesetterFrameTarget.isFramePending()) {
+ if (mBackpressureGpuComposition || pacesetterFrameTarget.didMissHwcFrame()) {
scheduleCommit(FrameHint::kNone);
return false;
}
}
+ const Period vsyncPeriod = mScheduler->getVsyncSchedule()->period();
+
// Save this once per commit + composite to ensure consistency
// TODO (b/240619471): consider removing active display check once AOD is fixed
const auto activeDisplay = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(mActiveDisplayId));
mPowerHintSessionEnabled = mPowerAdvisor->usePowerHintSession() && activeDisplay &&
activeDisplay->getPowerMode() == hal::PowerMode::ON;
if (mPowerHintSessionEnabled) {
- mPowerAdvisor->setCommitStart(frameTime);
- mPowerAdvisor->setExpectedPresentTime(mExpectedPresentTime);
+ mPowerAdvisor->setCommitStart(pacesetterFrameTarget.frameBeginTime());
+ mPowerAdvisor->setExpectedPresentTime(pacesetterFrameTarget.expectedPresentTime());
// Frame delay is how long we should have minus how long we actually have.
const Duration idealSfWorkDuration =
mScheduler->vsyncModulator().getVsyncConfig().sfWorkDuration;
- const Duration frameDelay = idealSfWorkDuration - (mExpectedPresentTime - frameTime);
+ const Duration frameDelay =
+ idealSfWorkDuration - pacesetterFrameTarget.expectedFrameDuration();
mPowerAdvisor->setFrameDelay(frameDelay);
mPowerAdvisor->setTotalFrameTargetWorkDuration(idealSfWorkDuration);
@@ -2503,7 +2409,8 @@
// Composite if transactions were committed, or if requested by HWC.
bool mustComposite = mMustComposite.exchange(false);
{
- mFrameTimeline->setSfWakeUp(ftl::to_underlying(vsyncId), frameTime.ns(),
+ mFrameTimeline->setSfWakeUp(ftl::to_underlying(vsyncId),
+ pacesetterFrameTarget.frameBeginTime().ns(),
Fps::fromPeriodNsecs(vsyncPeriod.ns()));
const bool flushTransactions = clearTransactionFlags(eTransactionFlushNeeded);
@@ -2511,10 +2418,11 @@
if (flushTransactions) {
updates = flushLifecycleUpdates();
if (mTransactionTracing) {
- mTransactionTracing->addCommittedTransactions(ftl::to_underlying(vsyncId),
- frameTime.ns(), updates,
- mFrontEndDisplayInfos,
- mFrontEndDisplayInfosChanged);
+ mTransactionTracing
+ ->addCommittedTransactions(ftl::to_underlying(vsyncId),
+ pacesetterFrameTarget.frameBeginTime().ns(),
+ updates, mFrontEndDisplayInfos,
+ mFrontEndDisplayInfosChanged);
}
}
bool transactionsAreEmpty;
@@ -2553,11 +2461,11 @@
}
updateCursorAsync();
- updateInputFlinger(vsyncId, frameTime);
+ updateInputFlinger(vsyncId, pacesetterFrameTarget.frameBeginTime());
if (mLayerTracingEnabled && !mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
// This will block and tracing should only be enabled for debugging.
- addToLayerTracing(mVisibleRegionsDirty, frameTime, vsyncId);
+ addToLayerTracing(mVisibleRegionsDirty, pacesetterFrameTarget.frameBeginTime(), vsyncId);
}
mLastCommittedVsyncId = vsyncId;
@@ -2566,8 +2474,11 @@
return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
}
-void SurfaceFlinger::composite(TimePoint frameTime, VsyncId vsyncId)
+CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFrameTargeter)
FTL_FAKE_GUARD(kMainThreadContext) {
+ const scheduler::FrameTarget& pacesetterFrameTarget = pacesetterFrameTargeter.target();
+
+ const VsyncId vsyncId = pacesetterFrameTarget.vsyncId();
ATRACE_NAME(ftl::Concat(__func__, ' ', ftl::to_underlying(vsyncId)).c_str());
compositionengine::CompositionRefreshArgs refreshArgs;
@@ -2575,17 +2486,18 @@
refreshArgs.outputs.reserve(displays.size());
std::vector<DisplayId> displayIds;
for (const auto& [_, display] : displays) {
- bool dropFrame = false;
- if (display->isVirtual()) {
- Fps refreshRate = display->getAdjustedRefreshRate();
- using fps_approx_ops::operator>;
- dropFrame = (refreshRate > 0_Hz) && !mScheduler->isVsyncInPhase(frameTime, refreshRate);
- }
- if (!dropFrame) {
- refreshArgs.outputs.push_back(display->getCompositionDisplay());
- }
- display->tracePowerMode();
displayIds.push_back(display->getId());
+ display->tracePowerMode();
+
+ if (display->isVirtual()) {
+ const Fps refreshRate = display->getAdjustedRefreshRate();
+ if (refreshRate.isValid() &&
+ !mScheduler->isVsyncInPhase(pacesetterFrameTarget.frameBeginTime(), refreshRate)) {
+ continue;
+ }
+ }
+
+ refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
mPowerAdvisor->setDisplays(displayIds);
@@ -2645,15 +2557,15 @@
if (!getHwComposer().getComposer()->isSupported(
Hwc2::Composer::OptionalFeature::ExpectedPresentTime) &&
- wouldPresentEarly(frameTime, vsyncPeriod)) {
- const auto prevVsyncTime = mExpectedPresentTime - vsyncPeriod;
+ pacesetterFrameTarget.wouldPresentEarly(vsyncPeriod)) {
const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
- refreshArgs.earliestPresentTime = prevVsyncTime - hwcMinWorkDuration;
+ refreshArgs.earliestPresentTime =
+ pacesetterFrameTarget.previousFrameVsyncTime(vsyncPeriod) - hwcMinWorkDuration;
}
refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime();
- refreshArgs.expectedPresentTime = mExpectedPresentTime.ns();
+ refreshArgs.expectedPresentTime = pacesetterFrameTarget.expectedPresentTime().ns();
refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0;
// Store the present time just before calling to the composition engine so we could notify
@@ -2679,14 +2591,14 @@
}
}
- mTimeStats->recordFrameDuration(frameTime.ns(), systemTime());
+ mTimeStats->recordFrameDuration(pacesetterFrameTarget.frameBeginTime().ns(), systemTime());
// Send a power hint after presentation is finished.
if (mPowerHintSessionEnabled) {
// Now that the current frame has been presented above, PowerAdvisor needs the present time
// of the previous frame (whose fence is signaled by now) to determine how long the HWC had
// waited on that fence to retire before presenting.
- const auto& previousPresentFence = mPreviousPresentFences[0].fenceTime;
+ const auto& previousPresentFence = pacesetterFrameTarget.presentFenceForPreviousFrame();
mPowerAdvisor->setSfPresentTiming(TimePoint::fromNs(previousPresentFence->getSignalTime()),
TimePoint::now());
@@ -2697,7 +2609,7 @@
scheduleComposite(FrameHint::kNone);
}
- postComposition(presentTime);
+ postComposition(pacesetterFrameTargeter, presentTime);
const bool hadGpuComposited = mCompositionCoverage.test(CompositionCoverage::Gpu);
mCompositionCoverage.clear();
@@ -2740,7 +2652,7 @@
mLayersWithQueuedFrames.clear();
if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
// This will block and should only be used for debugging.
- addToLayerTracing(mVisibleRegionsDirty, frameTime, vsyncId);
+ addToLayerTracing(mVisibleRegionsDirty, pacesetterFrameTarget.frameBeginTime(), vsyncId);
}
if (mVisibleRegionsDirty) mHdrLayerInfoChanged = true;
@@ -2753,6 +2665,8 @@
if (mPowerHintSessionEnabled) {
mPowerAdvisor->setCompositeEnd(TimePoint::now());
}
+
+ return {mCompositionCoverage};
}
void SurfaceFlinger::updateLayerGeometry() {
@@ -2836,7 +2750,8 @@
return ui::ROTATION_0;
}
-void SurfaceFlinger::postComposition(nsecs_t callTime) {
+void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTargeter,
+ nsecs_t presentStartTime) {
ATRACE_CALL();
ALOGV(__func__);
@@ -2853,15 +2768,11 @@
glCompositionDoneFenceTime = FenceTime::NO_FENCE;
}
- mPreviousPresentFences[1] = mPreviousPresentFences[0];
-
auto presentFence = defaultDisplay
? getHwComposer().getPresentFence(defaultDisplay->getPhysicalId())
: Fence::NO_FENCE;
- auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
- mPreviousPresentFences[0] = {presentFence, presentFenceTime};
-
+ auto presentFenceTime = pacesetterFrameTargeter.setPresentFence(presentFence);
const TimePoint presentTime = TimePoint::now();
// Set presentation information before calling Layer::releasePendingBuffer, such that jank
@@ -3044,7 +2955,7 @@
if (!layer->hasTrustedPresentationListener()) {
return;
}
- const frontend::LayerSnapshot* snapshot = (mLayerLifecycleManagerEnabled)
+ const frontend::LayerSnapshot* snapshot = mLayerLifecycleManagerEnabled
? mLayerSnapshotBuilder.getSnapshot(layer->sequence)
: layer->getLayerSnapshot();
std::optional<const DisplayDevice*> displayOpt = std::nullopt;
@@ -3053,7 +2964,8 @@
}
const DisplayDevice* display = displayOpt.value_or(nullptr);
layer->updateTrustedPresentationState(display, snapshot,
- nanoseconds_to_milliseconds(callTime), false);
+ nanoseconds_to_milliseconds(presentStartTime),
+ false);
});
}
@@ -3964,6 +3876,9 @@
if (display->refreshRateSelector().kernelIdleTimerController()) {
features |= Feature::kKernelIdleTimer;
}
+ if (mBackpressureGpuComposition) {
+ features |= Feature::kBackpressureGpuComposition;
+ }
auto modulatorPtr = sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs());
@@ -4281,33 +4196,38 @@
TransactionHandler::TransactionReadiness SurfaceFlinger::transactionReadyTimelineCheck(
const TransactionHandler::TransactionFlushState& flushState) {
- using TransactionReadiness = TransactionHandler::TransactionReadiness;
const auto& transaction = *flushState.transaction;
- TimePoint desiredPresentTime = TimePoint::fromNs(transaction.desiredPresentTime);
+
+ const TimePoint desiredPresentTime = TimePoint::fromNs(transaction.desiredPresentTime);
+ const TimePoint expectedPresentTime = mScheduler->pacesetterFrameTarget().expectedPresentTime();
+
+ using TransactionReadiness = TransactionHandler::TransactionReadiness;
+
// Do not present if the desiredPresentTime has not passed unless it is more than
// one second in the future. We ignore timestamps more than 1 second in the future
// for stability reasons.
- if (!transaction.isAutoTimestamp && desiredPresentTime >= mExpectedPresentTime &&
- desiredPresentTime < mExpectedPresentTime + 1s) {
+ if (!transaction.isAutoTimestamp && desiredPresentTime >= expectedPresentTime &&
+ desiredPresentTime < expectedPresentTime + 1s) {
ATRACE_FORMAT("not current desiredPresentTime: %" PRId64 " expectedPresentTime: %" PRId64,
- desiredPresentTime, mExpectedPresentTime);
+ desiredPresentTime, expectedPresentTime);
return TransactionReadiness::NotReady;
}
- if (!mScheduler->isVsyncValid(mExpectedPresentTime, transaction.originUid)) {
- ATRACE_FORMAT("!isVsyncValid expectedPresentTime: %" PRId64 " uid: %d",
- mExpectedPresentTime, transaction.originUid);
+ if (!mScheduler->isVsyncValid(expectedPresentTime, transaction.originUid)) {
+ ATRACE_FORMAT("!isVsyncValid expectedPresentTime: %" PRId64 " uid: %d", expectedPresentTime,
+ transaction.originUid);
return TransactionReadiness::NotReady;
}
// If the client didn't specify desiredPresentTime, use the vsyncId to determine the
// expected present time of this transaction.
if (transaction.isAutoTimestamp &&
- frameIsEarly(mExpectedPresentTime, VsyncId{transaction.frameTimelineInfo.vsyncId})) {
+ frameIsEarly(expectedPresentTime, VsyncId{transaction.frameTimelineInfo.vsyncId})) {
ATRACE_FORMAT("frameIsEarly vsyncId: %" PRId64 " expectedPresentTime: %" PRId64,
- transaction.frameTimelineInfo.vsyncId, mExpectedPresentTime);
+ transaction.frameTimelineInfo.vsyncId, expectedPresentTime);
return TransactionReadiness::NotReady;
}
+
return TransactionReadiness::Ready;
}
@@ -6047,10 +5967,6 @@
dumpVsync(result);
result.append("\n");
- StringAppendF(&result, "Total missed frame count: %u\n", mFrameMissedCount.load());
- StringAppendF(&result, "HWC missed frame count: %u\n", mHwcFrameMissedCount.load());
- StringAppendF(&result, "GPU missed frame count: %u\n\n", mGpuFrameMissedCount.load());
-
/*
* Dump the visible layer list
*/
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b7d2047..143d57f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -632,8 +632,8 @@
// ICompositor overrides:
void configure() override;
- bool commit(TimePoint frameTime, VsyncId, TimePoint expectedVsyncTime) override;
- void composite(TimePoint frameTime, VsyncId) override;
+ bool commit(const scheduler::FrameTarget&) override;
+ CompositeResult composite(scheduler::FrameTargeter&) override;
void sample() override;
// ISchedulerCallback overrides:
@@ -952,7 +952,8 @@
/*
* Compositing
*/
- void postComposition(nsecs_t callTime) REQUIRES(kMainThreadContext);
+ void postComposition(scheduler::FrameTargeter&, nsecs_t presentStartTime)
+ REQUIRES(kMainThreadContext);
/*
* Display management
@@ -993,20 +994,6 @@
*/
nsecs_t getVsyncPeriodFromHWC() const REQUIRES(mStateLock);
- using FenceTimePtr = std::shared_ptr<FenceTime>;
-
- bool wouldPresentEarly(TimePoint frameTime, Period) const REQUIRES(kMainThreadContext);
-
- const FenceTimePtr& getPreviousPresentFence(TimePoint frameTime, Period) const
- REQUIRES(kMainThreadContext);
-
- // Blocks the thread waiting for up to graceTimeMs in case the fence is about to signal.
- static bool isFencePending(const FenceTimePtr&, int graceTimeMs);
-
- // Calculates the expected present time for this frame. For negative offsets, performs a
- // correction using the predicted vsync for the next frame instead.
- TimePoint calculateExpectedPresentTime(TimePoint frameTime) const;
-
/*
* Display identification
*/
@@ -1252,9 +1239,6 @@
// If blurs should be enabled on this device.
bool mSupportsBlur = false;
- std::atomic<uint32_t> mFrameMissedCount = 0;
- std::atomic<uint32_t> mHwcFrameMissedCount = 0;
- std::atomic<uint32_t> mGpuFrameMissedCount = 0;
TransactionCallbackInvoker mTransactionCallbackInvoker;
@@ -1322,15 +1306,6 @@
std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
scheduler::PresentLatencyTracker mPresentLatencyTracker GUARDED_BY(kMainThreadContext);
- struct FenceWithFenceTime {
- sp<Fence> fence = Fence::NO_FENCE;
- FenceTimePtr fenceTime = FenceTime::NO_FENCE;
- };
- std::array<FenceWithFenceTime, 2> mPreviousPresentFences;
-
- TimePoint mScheduledPresentTime GUARDED_BY(kMainThreadContext);
- TimePoint mExpectedPresentTime GUARDED_BY(kMainThreadContext);
-
// below flags are set by main thread only
bool mSetActiveModePending = false;
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 8e208bc..0c9a16b 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -286,8 +286,8 @@
private:
// ICompositor overrides:
void configure() override {}
- bool commit(TimePoint, VsyncId, TimePoint) override { return false; }
- void composite(TimePoint, VsyncId) override {}
+ bool commit(const scheduler::FrameTarget&) override { return false; }
+ CompositeResult composite(scheduler::FrameTargeter&) override { return {}; }
void sample() override {}
// MessageQueue overrides:
@@ -604,7 +604,9 @@
mFlinger->commitTransactions();
mFlinger->flushTransactionQueues(getFuzzedVsyncId(mFdp));
- mFlinger->postComposition(systemTime());
+
+ scheduler::FrameTargeter frameTargeter(mFdp.ConsumeBool());
+ mFlinger->postComposition(frameTargeter, mFdp.ConsumeIntegral<nsecs_t>());
}
mFlinger->setTransactionFlags(mFdp.ConsumeIntegral<uint32_t>());
@@ -622,8 +624,6 @@
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mFdp.ConsumeIntegral<uid_t>());
- mFlinger->calculateExpectedPresentTime({});
-
mFlinger->enableHalVirtualDisplays(mFdp.ConsumeBool());
fuzzDumpsysAndDebug(&mFdp);
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index f17d2e1..b1fd06f 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -19,6 +19,7 @@
#include <fuzzer/FuzzedDataProvider.h>
#include <processgroup/sched_policy.h>
+#include <scheduler/IVsyncSource.h>
#include <scheduler/PresentLatencyTracker.h>
#include "Scheduler/OneShotTimer.h"
@@ -42,6 +43,7 @@
(120_Hz).getPeriodNsecs()};
constexpr auto kLayerVoteTypes = ftl::enum_range<scheduler::RefreshRateSelector::LayerVoteType>();
+constexpr auto kCompositionCoverage = ftl::enum_range<CompositionCoverage>();
constexpr PowerMode kPowerModes[] = {PowerMode::ON, PowerMode::DOZE, PowerMode::OFF,
PowerMode::DOZE_SUSPEND, PowerMode::ON_SUSPEND};
@@ -56,6 +58,10 @@
component->dump(res);
}
+inline sp<Fence> makeFakeFence() {
+ return sp<Fence>::make(memfd_create("fd", MFD_ALLOW_SEALING));
+}
+
class SchedulerFuzzer {
public:
SchedulerFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
@@ -65,6 +71,7 @@
void fuzzRefreshRateSelection();
void fuzzRefreshRateSelector();
void fuzzPresentLatencyTracker();
+ void fuzzFrameTargeter();
void fuzzVSyncModulator();
void fuzzVSyncPredictor();
void fuzzVSyncReactor();
@@ -256,13 +263,13 @@
reactor.addHwVsyncTimestamp(0, std::nullopt, &periodFlushed);
reactor.addHwVsyncTimestamp(mFdp.ConsumeIntegral<nsecs_t>() /*newPeriod*/, std::nullopt,
&periodFlushed);
- sp<Fence> fence = sp<Fence>::make(memfd_create("fd", MFD_ALLOW_SEALING));
- std::shared_ptr<FenceTime> ft = std::make_shared<FenceTime>(fence);
+
+ const auto fence = std::make_shared<FenceTime>(makeFakeFence());
vSyncTracker->addVsyncTimestamp(mFdp.ConsumeIntegral<nsecs_t>());
FenceTime::Snapshot snap(mFdp.ConsumeIntegral<nsecs_t>());
- ft->applyTrustedSnapshot(snap);
+ fence->applyTrustedSnapshot(snap);
reactor.setIgnorePresentFences(mFdp.ConsumeBool());
- reactor.addPresentFence(ft);
+ reactor.addPresentFence(fence);
dump<scheduler::VSyncReactor>(&reactor, &mFdp);
}
@@ -392,14 +399,45 @@
void SchedulerFuzzer::fuzzPresentLatencyTracker() {
scheduler::PresentLatencyTracker tracker;
- tracker.trackPendingFrame(TimePoint::fromNs(mFdp.ConsumeIntegral<nsecs_t>()),
- FenceTime::NO_FENCE);
+
+ int i = 5;
+ while (i-- > 0) {
+ tracker.trackPendingFrame(getFuzzedTimePoint(mFdp),
+ std::make_shared<FenceTime>(makeFakeFence()));
+ }
+}
+
+void SchedulerFuzzer::fuzzFrameTargeter() {
+ scheduler::FrameTargeter frameTargeter(mFdp.ConsumeBool());
+
+ const struct VsyncSource final : scheduler::IVsyncSource {
+ explicit VsyncSource(FuzzedDataProvider& fuzzer) : fuzzer(fuzzer) {}
+ FuzzedDataProvider& fuzzer;
+
+ Period period() const { return getFuzzedDuration(fuzzer); }
+ TimePoint vsyncDeadlineAfter(TimePoint) const { return getFuzzedTimePoint(fuzzer); }
+ } vsyncSource{mFdp};
+
+ int i = 10;
+ while (i-- > 0) {
+ frameTargeter.beginFrame({.frameBeginTime = getFuzzedTimePoint(mFdp),
+ .vsyncId = getFuzzedVsyncId(mFdp),
+ .expectedVsyncTime = getFuzzedTimePoint(mFdp),
+ .sfWorkDuration = getFuzzedDuration(mFdp)},
+ vsyncSource);
+
+ frameTargeter.setPresentFence(makeFakeFence());
+
+ frameTargeter.endFrame(
+ {.compositionCoverage = mFdp.PickValueInArray(kCompositionCoverage.values)});
+ }
}
void SchedulerFuzzer::process() {
fuzzRefreshRateSelection();
fuzzRefreshRateSelector();
fuzzPresentLatencyTracker();
+ fuzzFrameTargeter();
fuzzVSyncModulator();
fuzzVSyncPredictor();
fuzzVSyncReactor();
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index 91875cc..359e2ab 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -20,9 +20,10 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include <scheduler/interface/ICompositor.h>
+
#include "FrameTimeline.h"
#include "Scheduler/MessageQueue.h"
-#include "SurfaceFlinger.h"
#include "mock/MockVSyncDispatch.h"
namespace android {
@@ -34,8 +35,8 @@
struct NoOpCompositor final : ICompositor {
void configure() override {}
- bool commit(TimePoint, VsyncId, TimePoint) override { return false; }
- void composite(TimePoint, VsyncId) override {}
+ bool commit(const scheduler::FrameTarget&) override { return false; }
+ CompositeResult composite(scheduler::FrameTargeter&) override { return {}; }
void sample() override {}
} gNoOpCompositor;
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index a30f7e0..aac11c0 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -173,8 +173,8 @@
private:
// ICompositor overrides:
void configure() override {}
- bool commit(TimePoint, VsyncId, TimePoint) override { return false; }
- void composite(TimePoint, VsyncId) override {}
+ bool commit(const scheduler::FrameTarget&) override { return false; }
+ CompositeResult composite(scheduler::FrameTargeter&) override { return {}; }
void sample() override {}
};
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 945e488..833984f 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -20,6 +20,11 @@
#include <chrono>
#include <variant>
+#include <ftl/fake_guard.h>
+#include <ftl/match.h>
+#include <gui/ScreenCaptureResults.h>
+#include <ui/DynamicDisplayInfo.h>
+
#include <compositionengine/Display.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
@@ -27,11 +32,7 @@
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/mock/DisplaySurface.h>
-#include <ftl/fake_guard.h>
-#include <ftl/match.h>
-#include <gui/ScreenCaptureResults.h>
-#include <ui/DynamicDisplayInfo.h>
#include "DisplayDevice.h"
#include "FakeVsyncConfiguration.h"
#include "FrameTracer/FrameTracer.h"
@@ -44,7 +45,6 @@
#include "Scheduler/RefreshRateSelector.h"
#include "StartPropertySetThread.h"
#include "SurfaceFlinger.h"
-#include "SurfaceFlingerDefaultFactory.h"
#include "TestableScheduler.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/DisplayHardware/MockDisplayMode.h"
@@ -360,25 +360,42 @@
commitTransactionsLocked(eDisplayTransactionNeeded);
}
- TimePoint commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime) {
- mFlinger->commit(frameTime, vsyncId, expectedVsyncTime);
- return frameTime;
+ void commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime,
+ bool composite = false) {
+ constexpr bool kBackpressureGpuComposition = true;
+ scheduler::FrameTargeter frameTargeter(kBackpressureGpuComposition);
+
+ frameTargeter.beginFrame({.frameBeginTime = frameTime,
+ .vsyncId = vsyncId,
+ .expectedVsyncTime = expectedVsyncTime,
+ .sfWorkDuration = 10ms},
+ *mScheduler->getVsyncSchedule());
+
+ mFlinger->commit(frameTargeter.target());
+
+ if (composite) {
+ mFlinger->composite(frameTargeter);
+ }
}
- TimePoint commit(TimePoint frameTime, VsyncId vsyncId) {
- return commit(frameTime, vsyncId, frameTime + Period(10ms));
+ void commit(TimePoint frameTime, VsyncId vsyncId, bool composite = false) {
+ return commit(frameTime, vsyncId, frameTime + Period(10ms), composite);
}
- TimePoint commit() {
+ void commit(bool composite = false) {
const TimePoint frameTime = scheduler::SchedulerClock::now();
- return commit(frameTime, kVsyncId);
+ commit(frameTime, kVsyncId, composite);
}
void commitAndComposite(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime) {
- mFlinger->composite(commit(frameTime, vsyncId, expectedVsyncTime), vsyncId);
+ constexpr bool kComposite = true;
+ commit(frameTime, vsyncId, expectedVsyncTime, kComposite);
}
- void commitAndComposite() { mFlinger->composite(commit(), kVsyncId); }
+ void commitAndComposite() {
+ constexpr bool kComposite = true;
+ commit(kComposite);
+ }
auto createDisplay(const String8& displayName, bool secure, float requestedRefreshRate = 0.0f) {
return mFlinger->createDisplay(displayName, secure, requestedRefreshRate);