Merge "Remove AHardwareBuffer_isValidPixelFormat" into main
diff --git a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
index 45c3a90..b268c5d 100644
--- a/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
+++ b/libs/binder/tests/parcel_fuzzer/libbinder_driver.cpp
@@ -21,6 +21,8 @@
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
+#include <private/android_filesystem_config.h>
+
namespace android {
void fuzzService(const sp<IBinder>& binder, FuzzedDataProvider&& provider) {
@@ -40,7 +42,12 @@
// Always take so that a perturbation of just the one ConsumeBool byte will always
// take the same path, but with a different UID. Without this, the fuzzer needs to
// guess both the change in value and the shift at the same time.
- int64_t maybeSetUid = provider.ConsumeIntegral<int64_t>();
+ int64_t maybeSetUid = provider.PickValueInArray<int64_t>(
+ {static_cast<int64_t>(AID_ROOT) << 32, static_cast<int64_t>(AID_SYSTEM) << 32,
+ provider.ConsumeIntegralInRange<int64_t>(static_cast<int64_t>(AID_ROOT) << 32,
+ static_cast<int64_t>(AID_USER) << 32),
+ provider.ConsumeIntegral<int64_t>()});
+
if (provider.ConsumeBool()) {
// set calling uid
IPCThreadState::self()->restoreCallingIdentity(maybeSetUid);
diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp
index 7fbf2d0..46205d7 100644
--- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp
+++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/TestServiceFuzzer.cpp
@@ -20,6 +20,8 @@
#include <binder/IPCThreadState.h>
#include <log/log.h>
+#include <private/android_filesystem_config.h>
+
using android::binder::Status;
namespace android {
@@ -29,6 +31,8 @@
ON_PLAIN,
ON_BINDER,
ON_KNOWN_UID,
+ ON_SYSTEM_AID,
+ ON_ROOT_AID,
};
// This service is to verify that fuzzService is functioning properly
@@ -48,6 +52,18 @@
}
break;
}
+ case CrashType::ON_SYSTEM_AID: {
+ if (IPCThreadState::self()->getCallingUid() == AID_SYSTEM) {
+ LOG_ALWAYS_FATAL("Expected crash, AID_SYSTEM.");
+ }
+ break;
+ }
+ case CrashType::ON_ROOT_AID: {
+ if (IPCThreadState::self()->getCallingUid() == AID_ROOT) {
+ LOG_ALWAYS_FATAL("Expected crash, AID_ROOT.");
+ }
+ break;
+ }
default:
break;
}
@@ -99,6 +115,10 @@
gCrashType = CrashType::ON_PLAIN;
} else if (arg == "KNOWN_UID") {
gCrashType = CrashType::ON_KNOWN_UID;
+ } else if (arg == "AID_SYSTEM") {
+ gCrashType = CrashType::ON_SYSTEM_AID;
+ } else if (arg == "AID_ROOT") {
+ gCrashType = CrashType::ON_ROOT_AID;
} else if (arg == "BINDER") {
gCrashType = CrashType::ON_BINDER;
} else {
diff --git a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh
index e568035..25906d8 100755
--- a/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh
+++ b/libs/binder/tests/parcel_fuzzer/test_fuzzer/run_fuzz_service_test.sh
@@ -27,7 +27,7 @@
exit 1
fi
-for CRASH_TYPE in PLAIN KNOWN_UID BINDER; do
+for CRASH_TYPE in PLAIN KNOWN_UID AID_SYSTEM AID_ROOT BINDER; do
echo "INFO: Running fuzzer : test_service_fuzzer_should_crash $CRASH_TYPE"
./test_service_fuzzer_should_crash "$CRASH_TYPE" -max_total_time=30 &>"$FUZZER_OUT"
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 342f132..d7e7eb8 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -73,6 +73,7 @@
"android/gui/FocusRequest.aidl",
"android/gui/InputApplicationInfo.aidl",
"android/gui/IWindowInfosListener.aidl",
+ "android/gui/IWindowInfosPublisher.aidl",
"android/gui/IWindowInfosReportedListener.aidl",
"android/gui/WindowInfo.aidl",
"android/gui/WindowInfosUpdate.aidl",
@@ -90,6 +91,7 @@
"android/gui/FocusRequest.aidl",
"android/gui/InputApplicationInfo.aidl",
"android/gui/IWindowInfosListener.aidl",
+ "android/gui/IWindowInfosPublisher.aidl",
"android/gui/IWindowInfosReportedListener.aidl",
"android/gui/WindowInfosUpdate.aidl",
"android/gui/WindowInfo.aidl",
@@ -136,6 +138,7 @@
"android/gui/FocusRequest.aidl",
"android/gui/InputApplicationInfo.aidl",
"android/gui/IWindowInfosListener.aidl",
+ "android/gui/IWindowInfosPublisher.aidl",
"android/gui/IWindowInfosReportedListener.aidl",
"android/gui/WindowInfo.aidl",
"android/gui/WindowInfosUpdate.aidl",
diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp
index 76e7b6e..0929b8e 100644
--- a/libs/gui/WindowInfosListenerReporter.cpp
+++ b/libs/gui/WindowInfosListenerReporter.cpp
@@ -22,7 +22,6 @@
namespace android {
using gui::DisplayInfo;
-using gui::IWindowInfosReportedListener;
using gui::WindowInfo;
using gui::WindowInfosListener;
using gui::aidl_utils::statusTFromBinderStatus;
@@ -40,8 +39,13 @@
{
std::scoped_lock lock(mListenersMutex);
if (mWindowInfosListeners.empty()) {
- binder::Status s = surfaceComposer->addWindowInfosListener(this);
+ gui::WindowInfosListenerInfo listenerInfo;
+ binder::Status s = surfaceComposer->addWindowInfosListener(this, &listenerInfo);
status = statusTFromBinderStatus(s);
+ if (status == OK) {
+ mWindowInfosPublisher = std::move(listenerInfo.windowInfosPublisher);
+ mListenerId = listenerInfo.listenerId;
+ }
}
if (status == OK) {
@@ -85,8 +89,7 @@
}
binder::Status WindowInfosListenerReporter::onWindowInfosChanged(
- const gui::WindowInfosUpdate& update,
- const sp<IWindowInfosReportedListener>& windowInfosReportedListener) {
+ const gui::WindowInfosUpdate& update) {
std::unordered_set<sp<WindowInfosListener>, gui::SpHash<WindowInfosListener>>
windowInfosListeners;
@@ -104,9 +107,7 @@
listener->onWindowInfosChanged(update);
}
- if (windowInfosReportedListener) {
- windowInfosReportedListener->onWindowInfosReported();
- }
+ mWindowInfosPublisher->ackWindowInfosReceived(update.vsyncId, mListenerId);
return binder::Status::ok();
}
@@ -114,7 +115,10 @@
void WindowInfosListenerReporter::reconnect(const sp<gui::ISurfaceComposer>& composerService) {
std::scoped_lock lock(mListenersMutex);
if (!mWindowInfosListeners.empty()) {
- composerService->addWindowInfosListener(this);
+ gui::WindowInfosListenerInfo listenerInfo;
+ composerService->addWindowInfosListener(this, &listenerInfo);
+ mWindowInfosPublisher = std::move(listenerInfo.windowInfosPublisher);
+ mListenerId = listenerInfo.listenerId;
}
}
diff --git a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
index ec3266c..539a1c1 100644
--- a/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
+++ b/libs/gui/aidl/android/gui/ISurfaceComposer.aidl
@@ -40,12 +40,14 @@
import android.gui.ISurfaceComposerClient;
import android.gui.ITunnelModeEnabledListener;
import android.gui.IWindowInfosListener;
+import android.gui.IWindowInfosPublisher;
import android.gui.LayerCaptureArgs;
import android.gui.LayerDebugInfo;
import android.gui.OverlayProperties;
import android.gui.PullAtomData;
import android.gui.ARect;
import android.gui.StaticDisplayInfo;
+import android.gui.WindowInfosListenerInfo;
/** @hide */
interface ISurfaceComposer {
@@ -500,7 +502,7 @@
*/
int getMaxAcquiredBufferCount();
- void addWindowInfosListener(IWindowInfosListener windowInfosListener);
+ WindowInfosListenerInfo addWindowInfosListener(IWindowInfosListener windowInfosListener);
void removeWindowInfosListener(IWindowInfosListener windowInfosListener);
diff --git a/libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl b/libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl
new file mode 100644
index 0000000..0ca13b7
--- /dev/null
+++ b/libs/gui/aidl/android/gui/WindowInfosListenerInfo.aidl
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 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.
+ */
+
+package android.gui;
+
+import android.gui.IWindowInfosPublisher;
+
+/** @hide */
+parcelable WindowInfosListenerInfo {
+ long listenerId;
+ IWindowInfosPublisher windowInfosPublisher;
+}
\ No newline at end of file
diff --git a/libs/gui/android/gui/IWindowInfosListener.aidl b/libs/gui/android/gui/IWindowInfosListener.aidl
index 400229d..07cb5ed 100644
--- a/libs/gui/android/gui/IWindowInfosListener.aidl
+++ b/libs/gui/android/gui/IWindowInfosListener.aidl
@@ -16,11 +16,9 @@
package android.gui;
-import android.gui.IWindowInfosReportedListener;
import android.gui.WindowInfosUpdate;
/** @hide */
oneway interface IWindowInfosListener {
- void onWindowInfosChanged(
- in WindowInfosUpdate update, in @nullable IWindowInfosReportedListener windowInfosReportedListener);
+ void onWindowInfosChanged(in WindowInfosUpdate update);
}
diff --git a/libs/gui/android/gui/IWindowInfosPublisher.aidl b/libs/gui/android/gui/IWindowInfosPublisher.aidl
new file mode 100644
index 0000000..5a9c328
--- /dev/null
+++ b/libs/gui/android/gui/IWindowInfosPublisher.aidl
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 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.
+ */
+
+package android.gui;
+
+/** @hide */
+oneway interface IWindowInfosPublisher
+{
+ void ackWindowInfosReceived(long vsyncId, long listenerId);
+}
diff --git a/libs/gui/fuzzer/libgui_fuzzer_utils.h b/libs/gui/fuzzer/libgui_fuzzer_utils.h
index 8c003d8..4c7d056 100644
--- a/libs/gui/fuzzer/libgui_fuzzer_utils.h
+++ b/libs/gui/fuzzer/libgui_fuzzer_utils.h
@@ -153,8 +153,8 @@
MOCK_METHOD(binder::Status, setOverrideFrameRate, (int32_t, float), (override));
MOCK_METHOD(binder::Status, getGpuContextPriority, (int32_t*), (override));
MOCK_METHOD(binder::Status, getMaxAcquiredBufferCount, (int32_t*), (override));
- MOCK_METHOD(binder::Status, addWindowInfosListener, (const sp<gui::IWindowInfosListener>&),
- (override));
+ MOCK_METHOD(binder::Status, addWindowInfosListener,
+ (const sp<gui::IWindowInfosListener>&, gui::WindowInfosListenerInfo*), (override));
MOCK_METHOD(binder::Status, removeWindowInfosListener, (const sp<gui::IWindowInfosListener>&),
(override));
MOCK_METHOD(binder::Status, getOverlaySupport, (gui::OverlayProperties*), (override));
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 7c150d5..3ff6735 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -26,6 +26,7 @@
#include <android/gui/IScreenCaptureListener.h>
#include <android/gui/ITunnelModeEnabledListener.h>
#include <android/gui/IWindowInfosListener.h>
+#include <android/gui/IWindowInfosPublisher.h>
#include <binder/IBinder.h>
#include <binder/IInterface.h>
#include <gui/ITransactionCompletedListener.h>
diff --git a/libs/gui/include/gui/WindowInfosListenerReporter.h b/libs/gui/include/gui/WindowInfosListenerReporter.h
index 38cb108..684e21a 100644
--- a/libs/gui/include/gui/WindowInfosListenerReporter.h
+++ b/libs/gui/include/gui/WindowInfosListenerReporter.h
@@ -18,7 +18,7 @@
#include <android/gui/BnWindowInfosListener.h>
#include <android/gui/ISurfaceComposer.h>
-#include <android/gui/IWindowInfosReportedListener.h>
+#include <android/gui/IWindowInfosPublisher.h>
#include <binder/IBinder.h>
#include <gui/SpHash.h>
#include <gui/WindowInfosListener.h>
@@ -30,8 +30,7 @@
class WindowInfosListenerReporter : public gui::BnWindowInfosListener {
public:
static sp<WindowInfosListenerReporter> getInstance();
- binder::Status onWindowInfosChanged(const gui::WindowInfosUpdate& update,
- const sp<gui::IWindowInfosReportedListener>&) override;
+ binder::Status onWindowInfosChanged(const gui::WindowInfosUpdate& update) override;
status_t addWindowInfosListener(
const sp<gui::WindowInfosListener>& windowInfosListener,
const sp<gui::ISurfaceComposer>&,
@@ -47,5 +46,8 @@
std::vector<gui::WindowInfo> mLastWindowInfos GUARDED_BY(mListenersMutex);
std::vector<gui::DisplayInfo> mLastDisplayInfos GUARDED_BY(mListenersMutex);
+
+ sp<gui::IWindowInfosPublisher> mWindowInfosPublisher;
+ int64_t mListenerId;
};
} // namespace android
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 90c0a63..567604d 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -1002,7 +1002,8 @@
}
binder::Status addWindowInfosListener(
- const sp<gui::IWindowInfosListener>& /*windowInfosListener*/) override {
+ const sp<gui::IWindowInfosListener>& /*windowInfosListener*/,
+ gui::WindowInfosListenerInfo* /*outInfo*/) override {
return binder::Status::ok();
}
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 769677c..757cde2 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -65,6 +65,10 @@
bindgen_flags: [
"--verbose",
"--allowlist-var=AMOTION_EVENT_FLAG_CANCELED",
+ "--allowlist-var=AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED",
+ "--allowlist-var=AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED",
+ "--allowlist-var=AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT",
+ "--allowlist-var=AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE",
"--allowlist-var=AMOTION_EVENT_ACTION_CANCEL",
"--allowlist-var=AMOTION_EVENT_ACTION_UP",
"--allowlist-var=AMOTION_EVENT_ACTION_POINTER_DOWN",
diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp
index 851babf..341eb6f 100644
--- a/libs/input/InputVerifier.cpp
+++ b/libs/input/InputVerifier.cpp
@@ -44,7 +44,7 @@
rust::Slice<const RustPointerProperties> properties{rpp.data(), rpp.size()};
rust::String errorMessage =
android::input::verifier::process_movement(*mVerifier, deviceId, action, properties,
- flags);
+ static_cast<uint32_t>(flags));
if (errorMessage.empty()) {
return {};
} else {
diff --git a/libs/input/rust/input.rs b/libs/input/rust/input.rs
index a308c26..9d3b386 100644
--- a/libs/input/rust/input.rs
+++ b/libs/input/rust/input.rs
@@ -119,8 +119,18 @@
bitflags! {
/// MotionEvent flags.
- pub struct MotionFlags: i32 {
+ pub struct MotionFlags: u32 {
/// FLAG_CANCELED
- const CANCELED = input_bindgen::AMOTION_EVENT_FLAG_CANCELED;
+ const CANCELED = input_bindgen::AMOTION_EVENT_FLAG_CANCELED as u32;
+ /// FLAG_WINDOW_IS_OBSCURED
+ const WINDOW_IS_OBSCURED = input_bindgen::AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
+ /// FLAG_WINDOW_IS_PARTIALLY_OBSCURED
+ const WINDOW_IS_PARTIALLY_OBSCURED =
+ input_bindgen::AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
+ /// FLAG_IS_ACCESSIBILITY_EVENT
+ const IS_ACCESSIBILITY_EVENT =
+ input_bindgen::AMOTION_EVENT_FLAG_IS_ACCESSIBILITY_EVENT;
+ /// FLAG_NO_FOCUS_CHANGE
+ const NO_FOCUS_CHANGE = input_bindgen::AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE;
}
}
diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs
index 892f558..688d941 100644
--- a/libs/input/rust/lib.rs
+++ b/libs/input/rust/lib.rs
@@ -52,7 +52,7 @@
device_id: i32,
action: u32,
pointer_properties: &[RustPointerProperties],
- flags: i32,
+ flags: u32,
) -> String;
fn reset_device(verifier: &mut InputVerifier, device_id: i32);
}
@@ -74,7 +74,7 @@
device_id: i32,
action: u32,
pointer_properties: &[RustPointerProperties],
- flags: i32,
+ flags: u32,
) -> String {
let result = verifier.process_movement(
DeviceId(device_id),
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index b7da35d..e7b2195 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -301,11 +301,14 @@
}
return result;
} else {
- const uint32_t pixelStride = AHardwareBuffer_bytesPerPixel(format);
+ int32_t bytesPerPixel;
+ int32_t bytesPerStride;
+ int result = gBuffer->lockAsync(usage, usage, bounds, &outPlanes->planes[0].data, fence,
+ &bytesPerPixel, &bytesPerStride);
outPlanes->planeCount = 1;
- outPlanes->planes[0].pixelStride = pixelStride;
- outPlanes->planes[0].rowStride = gBuffer->getStride() * pixelStride;
- return gBuffer->lockAsync(usage, usage, bounds, &outPlanes->planes[0].data, fence);
+ outPlanes->planes[0].pixelStride = bytesPerPixel;
+ outPlanes->planes[0].rowStride = bytesPerStride;
+ return result;
}
}
@@ -641,32 +644,6 @@
}
}
-uint32_t AHardwareBuffer_bytesPerPixel(uint32_t format) {
- switch (format) {
- case AHARDWAREBUFFER_FORMAT_R8_UNORM:
- return 1;
- case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
- case AHARDWAREBUFFER_FORMAT_D16_UNORM:
- case AHARDWAREBUFFER_FORMAT_R16_UINT:
- return 2;
- case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
- case AHARDWAREBUFFER_FORMAT_D24_UNORM:
- return 3;
- case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
- case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
- case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
- case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
- case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
- case AHARDWAREBUFFER_FORMAT_R16G16_UINT:
- return 4;
- case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
- case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM:
- return 8;
- default:
- return 0;
- }
-}
-
uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t hal_format) {
return hal_format;
}
diff --git a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
index 6df4ea3..880c694 100644
--- a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
+++ b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
@@ -40,9 +40,6 @@
// whether this is a YUV type format
bool AHardwareBuffer_formatIsYuv(uint32_t format);
-// number of bytes per pixel or 0 if unknown or multi-planar
-uint32_t AHardwareBuffer_bytesPerPixel(uint32_t format);
-
// convert AHardwareBuffer format to HAL format (note: this is a no-op)
uint32_t AHardwareBuffer_convertFromPixelFormat(uint32_t format);
diff --git a/libs/permission/aidl/android/content/AttributionSourceState.aidl b/libs/permission/aidl/android/content/AttributionSourceState.aidl
index ed1b37d..b3fb7a7 100644
--- a/libs/permission/aidl/android/content/AttributionSourceState.aidl
+++ b/libs/permission/aidl/android/content/AttributionSourceState.aidl
@@ -27,6 +27,10 @@
int pid = -1;
/** The UID that is accessing the permission protected data. */
int uid = -1;
+ /** The default device ID from where the permission protected data is read.
+ * @see Context#DEVICE_ID_DEFAULT
+ */
+ int deviceId = 0;
/** The package that is accessing the permission protected data. */
@nullable @utf8InCpp String packageName;
/** The attribution tag of the app accessing the permission protected data. */
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index 073da89..8675f14 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -304,6 +304,12 @@
return std::string("BGRA_8888");
case android::PIXEL_FORMAT_R_8:
return std::string("R_8");
+ case android::PIXEL_FORMAT_R_16_UINT:
+ return std::string("R_16_UINT");
+ case android::PIXEL_FORMAT_RG_1616_UINT:
+ return std::string("RG_1616_UINT");
+ case android::PIXEL_FORMAT_RGBA_10101010:
+ return std::string("RGBA_10101010");
default:
return StringPrintf("Unknown %#08x", format);
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 7611d68..619ecdc 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -119,6 +119,10 @@
return systemTime(SYSTEM_TIME_MONOTONIC);
}
+bool isEmpty(const std::stringstream& ss) {
+ return ss.rdbuf()->in_avail() == 0;
+}
+
inline const std::string binderToString(const sp<IBinder>& binder) {
if (binder == nullptr) {
return "<null>";
@@ -130,11 +134,6 @@
return uid.toString();
}
-inline int32_t getMotionEventActionPointerIndex(int32_t action) {
- return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
- AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
-}
-
Result<void> checkKeyAction(int32_t action) {
switch (action) {
case AKEY_EVENT_ACTION_DOWN:
@@ -602,7 +601,7 @@
return {entry.xCursorPosition, entry.yCursorPosition};
}
- const int32_t pointerIndex = getMotionEventActionPointerIndex(entry.action);
+ const int32_t pointerIndex = MotionEvent::getActionIndex(entry.action);
return {entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X),
entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y)};
}
@@ -2305,7 +2304,7 @@
if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
/* Case 1: New splittable pointer going down, or need target for hover or scroll. */
const auto [x, y] = resolveTouchedPosition(entry);
- const int32_t pointerIndex = getMotionEventActionPointerIndex(action);
+ const int32_t pointerIndex = MotionEvent::getActionIndex(action);
// Outside targets should be added upon first dispatched DOWN event. That means, this should
// be a pointer that would generate ACTION_DOWN, *and* touch should not already be down.
const bool isStylus = isPointerFromStylus(entry, pointerIndex);
@@ -2338,6 +2337,8 @@
} else if (isSplit) {
// New window does not support splitting but we have already split events.
// Ignore the new window.
+ LOG(INFO) << "Skipping " << newTouchedWindowHandle->getName()
+ << " because it doesn't support split touch";
newTouchedWindowHandle = nullptr;
}
} else {
@@ -2552,15 +2553,16 @@
// Update the pointerIds for non-splittable when it received pointer down.
if (!isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN) {
// If no split, we suppose all touched windows should receive pointer down.
- const int32_t pointerIndex = getMotionEventActionPointerIndex(action);
+ const int32_t pointerIndex = MotionEvent::getActionIndex(action);
for (size_t i = 0; i < tempTouchState.windows.size(); i++) {
TouchedWindow& touchedWindow = tempTouchState.windows[i];
// Ignore drag window for it should just track one pointer.
if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) {
continue;
}
- touchedWindow.addTouchingPointer(entry.deviceId,
- entry.pointerProperties[pointerIndex].id);
+ std::bitset<MAX_POINTER_ID + 1> touchingPointers;
+ touchingPointers.set(entry.pointerProperties[pointerIndex].id);
+ touchedWindow.addTouchingPointers(entry.deviceId, touchingPointers);
}
}
}
@@ -2704,18 +2706,9 @@
}
} else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
// One pointer went up.
- int32_t pointerIndex = getMotionEventActionPointerIndex(action);
- uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
-
- for (size_t i = 0; i < tempTouchState.windows.size();) {
- TouchedWindow& touchedWindow = tempTouchState.windows[i];
- touchedWindow.removeTouchingPointer(entry.deviceId, pointerId);
- if (!touchedWindow.hasTouchingPointers(entry.deviceId)) {
- tempTouchState.windows.erase(tempTouchState.windows.begin() + i);
- continue;
- }
- i += 1;
- }
+ const int32_t pointerIndex = MotionEvent::getActionIndex(action);
+ const uint32_t pointerId = entry.pointerProperties[pointerIndex].id;
+ tempTouchState.removeTouchingPointer(entry.deviceId, pointerId);
}
// Save changes unless the action was scroll in which case the temporary touch
@@ -2814,7 +2807,7 @@
}
case AMOTION_EVENT_ACTION_POINTER_UP:
- if (getMotionEventActionPointerIndex(entry.action) != pointerIndex) {
+ if (MotionEvent::getActionIndex(entry.action) != pointerIndex) {
break;
}
// The drag pointer is up.
@@ -4108,7 +4101,7 @@
int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN ||
maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
- int32_t originalPointerIndex = getMotionEventActionPointerIndex(action);
+ int32_t originalPointerIndex = MotionEvent::getActionIndex(action);
const PointerProperties& pointerProperties =
originalMotionEntry.pointerProperties[originalPointerIndex];
uint32_t pointerId = uint32_t(pointerProperties.id);
@@ -5777,6 +5770,12 @@
} else {
dump += INDENT3 "WaitQueue: <empty>\n";
}
+ std::stringstream inputStateDump;
+ inputStateDump << connection->inputState;
+ if (!isEmpty(inputStateDump)) {
+ dump += INDENT3 "InputState: ";
+ dump += inputStateDump.str() + "\n";
+ }
}
} else {
dump += INDENT "Connections: <none>\n";
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index cb87067..909c683 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -25,7 +25,6 @@
#include "InputDispatcherConfiguration.h"
#include "InputDispatcherInterface.h"
#include "InputDispatcherPolicyInterface.h"
-#include "InputState.h"
#include "InputTarget.h"
#include "InputThread.h"
#include "LatencyAggregator.h"
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index e6941ef..ccffe26 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -525,4 +525,14 @@
}
}
+std::ostream& operator<<(std::ostream& out, const InputState& state) {
+ if (!state.mMotionMementos.empty()) {
+ out << "mMotionMementos: ";
+ for (const InputState::MotionMemento& memento : state.mMotionMementos) {
+ out << "{deviceId= " << memento.deviceId << ", hovering=" << memento.hovering << "}, ";
+ }
+ }
+ return out;
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h
index e741137..32df034 100644
--- a/services/inputflinger/dispatcher/InputState.h
+++ b/services/inputflinger/dispatcher/InputState.h
@@ -128,7 +128,10 @@
std::vector<std::unique_ptr<MotionEntry>> synthesizeCancelationEventsForPointers(
const MotionMemento& memento, std::bitset<MAX_POINTER_ID + 1> pointerIds,
nsecs_t currentTime);
+ friend std::ostream& operator<<(std::ostream& out, const InputState& state);
};
+std::ostream& operator<<(std::ostream& out, const InputState& state);
+
} // namespace inputdispatcher
} // namespace android
diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp
index fc8b785..11f3413 100644
--- a/services/inputflinger/dispatcher/InputTarget.cpp
+++ b/services/inputflinger/dispatcher/InputTarget.cpp
@@ -76,4 +76,24 @@
}
return out;
}
+
+std::ostream& operator<<(std::ostream& out, const InputTarget& target) {
+ out << "{inputChannel=";
+ if (target.inputChannel != nullptr) {
+ out << target.inputChannel->getName();
+ } else {
+ out << "<null>";
+ }
+ out << ", windowHandle=";
+ if (target.windowHandle != nullptr) {
+ out << target.windowHandle->getName();
+ } else {
+ out << "<null>";
+ }
+ out << ", targetFlags=" << target.flags.string();
+ out << ", pointers=" << target.getPointerInfoString();
+ out << "}";
+ return out;
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index 3bf8b68..8b8a35a 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -139,6 +139,6 @@
std::string getPointerInfoString() const;
};
-std::string dispatchModeToString(int32_t dispatchMode);
+std::ostream& operator<<(std::ostream& out, const InputTarget& target);
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index 25b9643..39e63e5 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -38,9 +38,9 @@
void reset();
void clearWindowsWithoutPointers();
- std::set<int32_t> getActiveDeviceIds() const;
+ std::set<DeviceId> getActiveDeviceIds() const;
- bool hasTouchingPointers(int32_t device) const;
+ bool hasTouchingPointers(DeviceId deviceId) const;
void removeTouchingPointer(DeviceId deviceId, int32_t pointerId);
void removeTouchingPointerFromWindow(DeviceId deviceId, int32_t pointerId,
const sp<android::gui::WindowInfoHandle>& windowHandle);
diff --git a/services/inputflinger/dispatcher/TouchedWindow.cpp b/services/inputflinger/dispatcher/TouchedWindow.cpp
index ae16520..9807a6d 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.cpp
+++ b/services/inputflinger/dispatcher/TouchedWindow.cpp
@@ -35,7 +35,7 @@
return false;
}
-bool TouchedWindow::hasHoveringPointers(int32_t deviceId) const {
+bool TouchedWindow::hasHoveringPointers(DeviceId deviceId) const {
const auto stateIt = mDeviceStates.find(deviceId);
if (stateIt == mDeviceStates.end()) {
return false;
@@ -53,7 +53,7 @@
std::erase_if(mDeviceStates, [](const auto& pair) { return !pair.second.hasPointers(); });
}
-bool TouchedWindow::hasHoveringPointer(int32_t deviceId, int32_t pointerId) const {
+bool TouchedWindow::hasHoveringPointer(DeviceId deviceId, int32_t pointerId) const {
const auto stateIt = mDeviceStates.find(deviceId);
if (stateIt == mDeviceStates.end()) {
return false;
@@ -63,15 +63,11 @@
return state.hoveringPointerIds.test(pointerId);
}
-void TouchedWindow::addHoveringPointer(int32_t deviceId, int32_t pointerId) {
+void TouchedWindow::addHoveringPointer(DeviceId deviceId, int32_t pointerId) {
mDeviceStates[deviceId].hoveringPointerIds.set(pointerId);
}
-void TouchedWindow::addTouchingPointer(int32_t deviceId, int32_t pointerId) {
- mDeviceStates[deviceId].touchingPointerIds.set(pointerId);
-}
-
-void TouchedWindow::addTouchingPointers(int32_t deviceId,
+void TouchedWindow::addTouchingPointers(DeviceId deviceId,
std::bitset<MAX_POINTER_ID + 1> pointers) {
mDeviceStates[deviceId].touchingPointerIds |= pointers;
}
@@ -85,15 +81,15 @@
return false;
}
-bool TouchedWindow::hasTouchingPointers(int32_t deviceId) const {
+bool TouchedWindow::hasTouchingPointers(DeviceId deviceId) const {
return getTouchingPointers(deviceId).any();
}
-bool TouchedWindow::hasTouchingPointer(int32_t deviceId, int32_t pointerId) const {
+bool TouchedWindow::hasTouchingPointer(DeviceId deviceId, int32_t pointerId) const {
return getTouchingPointers(deviceId).test(pointerId);
}
-std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getTouchingPointers(int32_t deviceId) const {
+std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getTouchingPointers(DeviceId deviceId) const {
const auto stateIt = mDeviceStates.find(deviceId);
if (stateIt == mDeviceStates.end()) {
return {};
@@ -103,14 +99,14 @@
return state.touchingPointerIds;
}
-void TouchedWindow::removeTouchingPointer(int32_t deviceId, int32_t pointerId) {
+void TouchedWindow::removeTouchingPointer(DeviceId deviceId, int32_t pointerId) {
std::bitset<MAX_POINTER_ID + 1> pointerIds;
pointerIds.set(pointerId, true);
removeTouchingPointers(deviceId, pointerIds);
}
-void TouchedWindow::removeTouchingPointers(int32_t deviceId,
+void TouchedWindow::removeTouchingPointers(DeviceId deviceId,
std::bitset<MAX_POINTER_ID + 1> pointers) {
const auto stateIt = mDeviceStates.find(deviceId);
if (stateIt == mDeviceStates.end()) {
@@ -126,23 +122,23 @@
}
}
-std::set<int32_t> TouchedWindow::getTouchingDeviceIds() const {
- std::set<int32_t> deviceIds;
+std::set<DeviceId> TouchedWindow::getTouchingDeviceIds() const {
+ std::set<DeviceId> deviceIds;
for (const auto& [deviceId, _] : mDeviceStates) {
deviceIds.insert(deviceId);
}
return deviceIds;
}
-std::set<int32_t> TouchedWindow::getActiveDeviceIds() const {
- std::set<int32_t> out;
+std::set<DeviceId> TouchedWindow::getActiveDeviceIds() const {
+ std::set<DeviceId> out;
for (const auto& [deviceId, _] : mDeviceStates) {
out.emplace(deviceId);
}
return out;
}
-bool TouchedWindow::hasPilferingPointers(int32_t deviceId) const {
+bool TouchedWindow::hasPilferingPointers(DeviceId deviceId) const {
const auto stateIt = mDeviceStates.find(deviceId);
if (stateIt == mDeviceStates.end()) {
return false;
@@ -152,16 +148,16 @@
return state.pilferingPointerIds.any();
}
-void TouchedWindow::addPilferingPointers(int32_t deviceId,
+void TouchedWindow::addPilferingPointers(DeviceId deviceId,
std::bitset<MAX_POINTER_ID + 1> pointerIds) {
mDeviceStates[deviceId].pilferingPointerIds |= pointerIds;
}
-void TouchedWindow::addPilferingPointer(int32_t deviceId, int32_t pointerId) {
+void TouchedWindow::addPilferingPointer(DeviceId deviceId, int32_t pointerId) {
mDeviceStates[deviceId].pilferingPointerIds.set(pointerId);
}
-std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getPilferingPointers(int32_t deviceId) const {
+std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getPilferingPointers(DeviceId deviceId) const {
const auto stateIt = mDeviceStates.find(deviceId);
if (stateIt == mDeviceStates.end()) {
return {};
@@ -171,15 +167,15 @@
return state.pilferingPointerIds;
}
-std::map<int32_t, std::bitset<MAX_POINTER_ID + 1>> TouchedWindow::getPilferingPointers() const {
- std::map<int32_t, std::bitset<MAX_POINTER_ID + 1>> out;
+std::map<DeviceId, std::bitset<MAX_POINTER_ID + 1>> TouchedWindow::getPilferingPointers() const {
+ std::map<DeviceId, std::bitset<MAX_POINTER_ID + 1>> out;
for (const auto& [deviceId, state] : mDeviceStates) {
out.emplace(deviceId, state.pilferingPointerIds);
}
return out;
}
-std::optional<nsecs_t> TouchedWindow::getDownTimeInTarget(int32_t deviceId) const {
+std::optional<nsecs_t> TouchedWindow::getDownTimeInTarget(DeviceId deviceId) const {
const auto stateIt = mDeviceStates.find(deviceId);
if (stateIt == mDeviceStates.end()) {
return {};
@@ -188,7 +184,7 @@
return state.downTimeInTarget;
}
-void TouchedWindow::trySetDownTimeInTarget(int32_t deviceId, nsecs_t downTime) {
+void TouchedWindow::trySetDownTimeInTarget(DeviceId deviceId, nsecs_t downTime) {
auto [stateIt, _] = mDeviceStates.try_emplace(deviceId);
DeviceState& state = stateIt->second;
@@ -197,7 +193,7 @@
}
}
-void TouchedWindow::removeAllTouchingPointersForDevice(int32_t deviceId) {
+void TouchedWindow::removeAllTouchingPointersForDevice(DeviceId deviceId) {
const auto stateIt = mDeviceStates.find(deviceId);
if (stateIt == mDeviceStates.end()) {
return;
@@ -213,7 +209,7 @@
}
}
-void TouchedWindow::removeHoveringPointer(int32_t deviceId, int32_t pointerId) {
+void TouchedWindow::removeHoveringPointer(DeviceId deviceId, int32_t pointerId) {
const auto stateIt = mDeviceStates.find(deviceId);
if (stateIt == mDeviceStates.end()) {
return;
@@ -227,7 +223,7 @@
}
}
-void TouchedWindow::removeAllHoveringPointersForDevice(int32_t deviceId) {
+void TouchedWindow::removeAllHoveringPointersForDevice(DeviceId deviceId) {
const auto stateIt = mDeviceStates.find(deviceId);
if (stateIt == mDeviceStates.end()) {
return;
diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h
index 81393fc..0a38f9f 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.h
+++ b/services/inputflinger/dispatcher/TouchedWindow.h
@@ -34,43 +34,42 @@
// Hovering
bool hasHoveringPointers() const;
- bool hasHoveringPointers(int32_t deviceId) const;
- bool hasHoveringPointer(int32_t deviceId, int32_t pointerId) const;
- void addHoveringPointer(int32_t deviceId, int32_t pointerId);
- void removeHoveringPointer(int32_t deviceId, int32_t pointerId);
+ bool hasHoveringPointers(DeviceId deviceId) const;
+ bool hasHoveringPointer(DeviceId deviceId, int32_t pointerId) const;
+ void addHoveringPointer(DeviceId deviceId, int32_t pointerId);
+ void removeHoveringPointer(DeviceId deviceId, int32_t pointerId);
// Touching
- bool hasTouchingPointer(int32_t deviceId, int32_t pointerId) const;
+ bool hasTouchingPointer(DeviceId deviceId, int32_t pointerId) const;
bool hasTouchingPointers() const;
- bool hasTouchingPointers(int32_t deviceId) const;
- std::bitset<MAX_POINTER_ID + 1> getTouchingPointers(int32_t deviceId) const;
- void addTouchingPointer(int32_t deviceId, int32_t pointerId);
- void addTouchingPointers(int32_t deviceId, std::bitset<MAX_POINTER_ID + 1> pointers);
- void removeTouchingPointer(int32_t deviceId, int32_t pointerId);
- void removeTouchingPointers(int32_t deviceId, std::bitset<MAX_POINTER_ID + 1> pointers);
+ bool hasTouchingPointers(DeviceId deviceId) const;
+ std::bitset<MAX_POINTER_ID + 1> getTouchingPointers(DeviceId deviceId) const;
+ void addTouchingPointers(DeviceId deviceId, std::bitset<MAX_POINTER_ID + 1> pointers);
+ void removeTouchingPointer(DeviceId deviceId, int32_t pointerId);
+ void removeTouchingPointers(DeviceId deviceId, std::bitset<MAX_POINTER_ID + 1> pointers);
/**
* Get the currently active touching device id. If there isn't exactly 1 touching device, return
* nullopt.
*/
- std::set<int32_t> getTouchingDeviceIds() const;
+ std::set<DeviceId> getTouchingDeviceIds() const;
/**
* The ids of devices that are currently touching or hovering.
*/
- std::set<int32_t> getActiveDeviceIds() const;
+ std::set<DeviceId> getActiveDeviceIds() const;
// Pilfering pointers
- bool hasPilferingPointers(int32_t deviceId) const;
- void addPilferingPointers(int32_t deviceId, std::bitset<MAX_POINTER_ID + 1> pointerIds);
- void addPilferingPointer(int32_t deviceId, int32_t pointerId);
- std::bitset<MAX_POINTER_ID + 1> getPilferingPointers(int32_t deviceId) const;
- std::map<int32_t, std::bitset<MAX_POINTER_ID + 1>> getPilferingPointers() const;
+ bool hasPilferingPointers(DeviceId deviceId) const;
+ void addPilferingPointers(DeviceId deviceId, std::bitset<MAX_POINTER_ID + 1> pointerIds);
+ void addPilferingPointer(DeviceId deviceId, int32_t pointerId);
+ std::bitset<MAX_POINTER_ID + 1> getPilferingPointers(DeviceId deviceId) const;
+ std::map<DeviceId, std::bitset<MAX_POINTER_ID + 1>> getPilferingPointers() const;
// Down time
- std::optional<nsecs_t> getDownTimeInTarget(int32_t deviceId) const;
- void trySetDownTimeInTarget(int32_t deviceId, nsecs_t downTime);
+ std::optional<nsecs_t> getDownTimeInTarget(DeviceId deviceId) const;
+ void trySetDownTimeInTarget(DeviceId deviceId, nsecs_t downTime);
- void removeAllTouchingPointersForDevice(int32_t deviceId);
- void removeAllHoveringPointersForDevice(int32_t deviceId);
+ void removeAllTouchingPointersForDevice(DeviceId deviceId);
+ void removeAllHoveringPointersForDevice(DeviceId deviceId);
void clearHoveringPointers();
std::string dump() const;
@@ -88,7 +87,7 @@
bool hasPointers() const { return touchingPointerIds.any() || hoveringPointerIds.any(); };
};
- std::map<int32_t /*deviceId*/, DeviceState> mDeviceStates;
+ std::map<DeviceId, DeviceState> mDeviceStates;
static std::string deviceStateToString(const TouchedWindow::DeviceState& state);
};
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 4d0e13e..4e72c4c 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -538,7 +538,8 @@
associatedDevice(std::move(assocDev)),
controllerNumber(0),
enabled(true),
- isVirtual(fd < 0) {}
+ isVirtual(fd < 0),
+ currentFrameDropped(false) {}
EventHub::Device::~Device() {
close();
@@ -612,6 +613,18 @@
}
bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId);
ALOGI("usingClockIoctl=%s", toString(usingClockIoctl));
+
+ // Query the initial state of keys and switches, which is tracked by EventHub.
+ readDeviceState();
+}
+
+void EventHub::Device::readDeviceState() {
+ if (readDeviceBitMask(EVIOCGKEY(0), keyState) < 0) {
+ ALOGD("Unable to query the global key state for %s: %s", path.c_str(), strerror(errno));
+ }
+ if (readDeviceBitMask(EVIOCGSW(0), swState) < 0) {
+ ALOGD("Unable to query the global switch state for %s: %s", path.c_str(), strerror(errno));
+ }
}
bool EventHub::Device::hasKeycodeLocked(int keycode) const {
@@ -729,6 +742,48 @@
return NAME_NOT_FOUND;
}
+void EventHub::Device::trackInputEvent(const struct input_event& event) {
+ switch (event.type) {
+ case EV_KEY: {
+ LOG_ALWAYS_FATAL_IF(!currentFrameDropped &&
+ !keyState.set(static_cast<size_t>(event.code),
+ event.value != 0),
+ "%s: received invalid EV_KEY event code: %s", __func__,
+ InputEventLookup::getLinuxEvdevLabel(EV_KEY, event.code, 1)
+ .code.c_str());
+ break;
+ }
+ case EV_SW: {
+ LOG_ALWAYS_FATAL_IF(!currentFrameDropped &&
+ !swState.set(static_cast<size_t>(event.code),
+ event.value != 0),
+ "%s: received invalid EV_SW event code: %s", __func__,
+ InputEventLookup::getLinuxEvdevLabel(EV_SW, event.code, 1)
+ .code.c_str());
+ break;
+ }
+ case EV_SYN: {
+ switch (event.code) {
+ case SYN_REPORT:
+ currentFrameDropped = false;
+ break;
+ case SYN_DROPPED:
+ // When we receive SYN_DROPPED, all events in the current frame should be
+ // dropped. We query the state of the device to synchronize our device state
+ // with the kernel's to account for the dropped events.
+ currentFrameDropped = true;
+ readDeviceState();
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
/**
* Get the capabilities for the current process.
* Crashes the system if unable to create / check / destroy the capabilities object.
@@ -962,38 +1017,34 @@
}
int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const {
- if (scanCode >= 0 && scanCode <= KEY_MAX) {
- std::scoped_lock _l(mLock);
-
- Device* device = getDeviceLocked(deviceId);
- if (device != nullptr && device->hasValidFd() && device->keyBitmask.test(scanCode)) {
- if (device->readDeviceBitMask(EVIOCGKEY(0), device->keyState) >= 0) {
- return device->keyState.test(scanCode) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
- }
- }
+ if (scanCode < 0 || scanCode > KEY_MAX) {
+ return AKEY_STATE_UNKNOWN;
}
- return AKEY_STATE_UNKNOWN;
+ std::scoped_lock _l(mLock);
+ const Device* device = getDeviceLocked(deviceId);
+ if (device == nullptr || !device->hasValidFd() || !device->keyBitmask.test(scanCode)) {
+ return AKEY_STATE_UNKNOWN;
+ }
+ return device->keyState.test(scanCode) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
}
int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const {
std::scoped_lock _l(mLock);
-
- Device* device = getDeviceLocked(deviceId);
- if (device != nullptr && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
- std::vector<int32_t> scanCodes = device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode);
- if (scanCodes.size() != 0) {
- if (device->readDeviceBitMask(EVIOCGKEY(0), device->keyState) >= 0) {
- for (size_t i = 0; i < scanCodes.size(); i++) {
- int32_t sc = scanCodes[i];
- if (sc >= 0 && sc <= KEY_MAX && device->keyState.test(sc)) {
- return AKEY_STATE_DOWN;
- }
- }
- return AKEY_STATE_UP;
- }
- }
+ const Device* device = getDeviceLocked(deviceId);
+ if (device == nullptr || !device->hasValidFd() || !device->keyMap.haveKeyLayout()) {
+ return AKEY_STATE_UNKNOWN;
}
- return AKEY_STATE_UNKNOWN;
+ const std::vector<int32_t> scanCodes =
+ device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode);
+ if (scanCodes.empty()) {
+ return AKEY_STATE_UNKNOWN;
+ }
+ return std::any_of(scanCodes.begin(), scanCodes.end(),
+ [&device](const int32_t sc) {
+ return sc >= 0 && sc <= KEY_MAX && device->keyState.test(sc);
+ })
+ ? AKEY_STATE_DOWN
+ : AKEY_STATE_UP;
}
int32_t EventHub::getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const {
@@ -1037,17 +1088,15 @@
}
int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const {
- if (sw >= 0 && sw <= SW_MAX) {
- std::scoped_lock _l(mLock);
-
- Device* device = getDeviceLocked(deviceId);
- if (device != nullptr && device->hasValidFd() && device->swBitmask.test(sw)) {
- if (device->readDeviceBitMask(EVIOCGSW(0), device->swState) >= 0) {
- return device->swState.test(sw) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
- }
- }
+ if (sw < 0 || sw > SW_MAX) {
+ return AKEY_STATE_UNKNOWN;
}
- return AKEY_STATE_UNKNOWN;
+ std::scoped_lock _l(mLock);
+ const Device* device = getDeviceLocked(deviceId);
+ if (device == nullptr || !device->hasValidFd() || !device->swBitmask.test(sw)) {
+ return AKEY_STATE_UNKNOWN;
+ }
+ return device->swState.test(sw) ? AKEY_STATE_DOWN : AKEY_STATE_UP;
}
status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const {
@@ -1922,6 +1971,7 @@
const size_t count = size_t(readSize) / sizeof(struct input_event);
for (size_t i = 0; i < count; i++) {
struct input_event& iev = readBuffer[i];
+ device->trackInputEvent(iev);
events.push_back({
.when = processEventTimestamp(iev),
.readTime = systemTime(SYSTEM_TIME_MONOTONIC),
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 024187f..6e647db 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -411,7 +411,17 @@
* Note the parameter "bit" is an index to the bit, 0 <= bit < BITS.
*/
inline bool test(size_t bit) const {
- return (bit < BITS) ? mData[bit / WIDTH].test(bit % WIDTH) : false;
+ return (bit < BITS) && mData[bit / WIDTH].test(bit % WIDTH);
+ }
+ /* Sets the given bit in the bit array to given value.
+ * Returns true if the given bit is a valid index and thus was set successfully.
+ */
+ inline bool set(size_t bit, bool value) {
+ if (bit >= BITS) {
+ return false;
+ }
+ mData[bit / WIDTH].set(bit % WIDTH, value);
+ return true;
}
/* Returns total number of bytes needed for the array */
inline size_t bytes() { return (BITS + CHAR_BIT - 1) / CHAR_BIT; }
@@ -653,6 +663,10 @@
void setLedForControllerLocked();
status_t mapLed(int32_t led, int32_t* outScanCode) const;
void setLedStateLocked(int32_t led, bool on);
+
+ bool currentFrameDropped;
+ void trackInputEvent(const struct input_event& event);
+ void readDeviceState();
};
/**
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index d367cd7..7051680 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -2386,7 +2386,6 @@
const int32_t touchDeviceId = 4;
const int32_t mouseDeviceId = 6;
- NotifyMotionArgs args;
// Start hovering over the left window
mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
@@ -2462,7 +2461,6 @@
const int32_t touchDeviceId = 4;
const int32_t mouseDeviceId = 6;
- NotifyMotionArgs args;
// First touch pointer down
mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
@@ -2528,7 +2526,6 @@
mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
const int32_t touchDeviceId = 4;
- NotifyMotionArgs args;
// Pretend a test injects an ACTION_DOWN mouse event, but forgets to lift up the touch after
// completion.
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -2696,9 +2693,7 @@
MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
AINPUT_SOURCE_STYLUS)
.deviceId(stylusDeviceId)
- .pointer(PointerBuilder(0, ToolType::STYLUS)
- .x(50)
- .y(50))
+ .pointer(PointerBuilder(0, ToolType::STYLUS).x(60).y(60))
.build()));
// No event should be sent. This event should be ignored because a pointer from another device
// is already down.
@@ -2721,9 +2716,7 @@
MotionEventBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE,
AINPUT_SOURCE_STYLUS)
.deviceId(stylusDeviceId)
- .pointer(PointerBuilder(0, ToolType::STYLUS)
- .x(50)
- .y(50))
+ .pointer(PointerBuilder(0, ToolType::STYLUS).x(70).y(70))
.build()));
window->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_ENTER));
// No more events
@@ -3808,6 +3801,44 @@
EXPECT_EQ(-10, event->getY(1)); // -50 + 40
}
+/**
+ * Two windows: a splittable and a non-splittable.
+ * The non-splittable window shouldn't receive any "incomplete" gestures.
+ * Send the first pointer to the splittable window, and then touch the non-splittable window.
+ * The second pointer should be dropped because the initial window is splittable, so it won't get
+ * any pointers outside of it, and the second window is non-splittable, so it shouldn't get any
+ * "incomplete" gestures.
+ */
+TEST_F(InputDispatcherTest, SplittableAndNonSplittableWindows) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> leftWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Left splittable Window",
+ ADISPLAY_ID_DEFAULT);
+ leftWindow->setPreventSplitting(false);
+ leftWindow->setFrame(Rect(0, 0, 100, 100));
+ sp<FakeWindowHandle> rightWindow =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Right non-splittable Window",
+ ADISPLAY_ID_DEFAULT);
+ rightWindow->setPreventSplitting(true);
+ rightWindow->setFrame(Rect(100, 100, 200, 200));
+ mDispatcher->onWindowInfosChanged(
+ {{*leftWindow->getInfo(), *rightWindow->getInfo()}, {}, 0, 0});
+
+ // Touch down on left, splittable window
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(50).y(50))
+ .build());
+ leftWindow->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
+
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
+ .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(150).y(150))
+ .build());
+ leftWindow->assertNoEvents();
+ rightWindow->assertNoEvents();
+}
+
TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
sp<FakeWindowHandle> window =
@@ -8984,6 +9015,7 @@
* Adding a spy window that is not a trusted overlay causes Dispatcher to abort.
*/
TEST_F(InputDispatcherSpyWindowDeathTest, UntrustedSpy_AbortsDispatcher) {
+ testing::GTEST_FLAG(death_test_style) = "threadsafe";
ScopedSilentDeath _silentDeath;
auto spy = createSpy();
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index e751c89..477beaf 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -1886,7 +1886,7 @@
::testing::Types<UinputTouchScreen, UinputExternalStylus, UinputExternalStylusWithPressure>;
TYPED_TEST_SUITE(StylusButtonIntegrationTest, StylusButtonIntegrationTestTypes);
-TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsGenerateKeyEvents) {
+TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsGenerateKeyEvents) {
const auto stylusId = TestFixture::mStylusInfo.getId();
TestFixture::mStylus->pressKey(BTN_STYLUS);
@@ -1900,7 +1900,7 @@
WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId))));
}
-TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingTouchGesture) {
+TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsSurroundingTouchGesture) {
const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint();
const auto touchscreenId = TestFixture::mTouchscreenInfo.getId();
const auto stylusId = TestFixture::mStylusInfo.getId();
@@ -1946,7 +1946,7 @@
WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId))));
}
-TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsSurroundingHoveringTouchGesture) {
+TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsSurroundingHoveringTouchGesture) {
const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint();
const auto touchscreenId = TestFixture::mTouchscreenInfo.getId();
const auto stylusId = TestFixture::mStylusInfo.getId();
@@ -2022,7 +2022,7 @@
WithKeyCode(AKEYCODE_STYLUS_BUTTON_PRIMARY), WithDeviceId(stylusId))));
}
-TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonsWithinTouchGesture) {
+TYPED_TEST(StylusButtonIntegrationTest, StylusButtonsWithinTouchGesture) {
const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint();
const auto touchscreenId = TestFixture::mTouchscreenInfo.getId();
const auto stylusId = TestFixture::mStylusInfo.getId();
@@ -2076,7 +2076,7 @@
WithDeviceId(touchscreenId))));
}
-TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonMotionEventsDisabled) {
+TYPED_TEST(StylusButtonIntegrationTest, StylusButtonMotionEventsDisabled) {
TestFixture::mFakePolicy->setStylusButtonMotionEventsEnabled(false);
TestFixture::mReader->requestRefreshConfiguration(
InputReaderConfiguration::Change::STYLUS_BUTTON_REPORTING);
@@ -2133,7 +2133,7 @@
// ongoing stylus gesture that is being emitted by the touchscreen.
using ExternalStylusIntegrationTest = TouchIntegrationTest;
-TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureReported) {
+TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureReported) {
const Point centerPoint = mDevice->getCenterPoint();
// Create an external stylus capable of reporting pressure data that
@@ -2179,7 +2179,7 @@
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasNotCalled());
}
-TEST_F(ExternalStylusIntegrationTest, DISABLED_FusedExternalStylusPressureNotReported) {
+TEST_F(ExternalStylusIntegrationTest, FusedExternalStylusPressureNotReported) {
const Point centerPoint = mDevice->getCenterPoint();
// Create an external stylus capable of reporting pressure data that
@@ -2247,7 +2247,7 @@
ASSERT_NO_FATAL_FAILURE(mTestListener->assertNotifyKeyWasNotCalled());
}
-TEST_F(ExternalStylusIntegrationTest, DISABLED_UnfusedExternalStylus) {
+TEST_F(ExternalStylusIntegrationTest, UnfusedExternalStylus) {
const Point centerPoint = mDevice->getCenterPoint();
// Create an external stylus device that does not support pressure. It should not affect any
diff --git a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
index e93b592..af20a27 100644
--- a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
@@ -15,38 +15,47 @@
*/
#include <CursorInputMapper.h>
-#include <FuzzContainer.h>
+#include <InputDevice.h>
#include <InputReaderBase.h>
#include <MapperHelpers.h>
namespace android {
-static void addProperty(FuzzContainer& fuzzer, std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) {
+static void addProperty(FuzzEventHub& eventHub, std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) {
// Pick a random property to set for the mapper to have set.
fdp->PickValueInArray<std::function<void()>>(
- {[&]() -> void { fuzzer.addProperty("cursor.mode", "pointer"); },
- [&]() -> void { fuzzer.addProperty("cursor.mode", "navigation"); },
+ {[&]() -> void { eventHub.addProperty("cursor.mode", "pointer"); },
+ [&]() -> void { eventHub.addProperty("cursor.mode", "navigation"); },
[&]() -> void {
- fuzzer.addProperty("cursor.mode", fdp->ConsumeRandomLengthString(100).data());
+ eventHub.addProperty("cursor.mode", fdp->ConsumeRandomLengthString(100).data());
},
[&]() -> void {
- fuzzer.addProperty("cursor.orientationAware",
- fdp->ConsumeRandomLengthString(100).data());
+ eventHub.addProperty("cursor.orientationAware",
+ fdp->ConsumeRandomLengthString(100).data());
}})();
}
extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp =
std::make_shared<ThreadSafeFuzzedDataProvider>(data, size);
- FuzzContainer fuzzer(fdp);
+
+ // Create mocked objects to support the fuzzed input mapper.
+ std::shared_ptr<FuzzEventHub> eventHub = std::make_shared<FuzzEventHub>(fdp);
+ FuzzInputReaderContext context(eventHub, fdp);
+ InputDevice device = getFuzzedInputDevice(*fdp, &context);
InputReaderConfiguration policyConfig;
- CursorInputMapper& mapper = fuzzer.getMapper<CursorInputMapper>(policyConfig);
+ CursorInputMapper& mapper =
+ getMapperForDevice<ThreadSafeFuzzedDataProvider, CursorInputMapper>(*fdp.get(), device,
+ policyConfig);
// Loop through mapper operations until randomness is exhausted.
while (fdp->remaining_bytes() > 0) {
fdp->PickValueInArray<std::function<void()>>({
- [&]() -> void { addProperty(fuzzer, fdp); },
+ [&]() -> void {
+ addProperty(*eventHub.get(), fdp);
+ configureAndResetDevice(*fdp, device);
+ },
[&]() -> void {
std::string dump;
mapper.dump(dump);
diff --git a/services/inputflinger/tests/fuzzers/FuzzContainer.h b/services/inputflinger/tests/fuzzers/FuzzContainer.h
deleted file mode 100644
index ade5328..0000000
--- a/services/inputflinger/tests/fuzzers/FuzzContainer.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2022 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 <InputDevice.h>
-#include <InputMapper.h>
-#include <InputReader.h>
-#include <MapperHelpers.h>
-
-namespace android {
-
-class FuzzContainer {
- std::shared_ptr<FuzzEventHub> mFuzzEventHub;
- FuzzInputListener mFuzzListener;
- std::unique_ptr<FuzzInputReaderContext> mFuzzContext;
- std::unique_ptr<InputDevice> mFuzzDevice;
- std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp;
-
-public:
- FuzzContainer(std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) : mFdp(fdp) {
- // Setup parameters.
- std::string deviceName = mFdp->ConsumeRandomLengthString(16);
- std::string deviceLocation = mFdp->ConsumeRandomLengthString(12);
- int32_t deviceID = mFdp->ConsumeIntegralInRange<int32_t>(0, 5);
- int32_t deviceGeneration = mFdp->ConsumeIntegralInRange<int32_t>(/*from=*/0, /*to=*/5);
-
- // Create mocked objects.
- mFuzzEventHub = std::make_shared<FuzzEventHub>(mFdp);
- sp<FuzzInputReaderPolicy> policy = sp<FuzzInputReaderPolicy>::make(mFdp);
- mFuzzContext = std::make_unique<FuzzInputReaderContext>(mFuzzEventHub, policy,
- mFuzzListener, mFdp);
-
- InputDeviceIdentifier identifier;
- identifier.name = deviceName;
- identifier.location = deviceLocation;
- mFuzzDevice = std::make_unique<InputDevice>(mFuzzContext.get(), deviceID, deviceGeneration,
- identifier);
- }
-
- ~FuzzContainer() {}
-
- void configureDevice() {
- nsecs_t arbitraryTime = mFdp->ConsumeIntegral<nsecs_t>();
- std::list<NotifyArgs> out;
- out += mFuzzDevice->configure(arbitraryTime, /*readerConfig=*/{}, /*changes=*/{});
- out += mFuzzDevice->reset(arbitraryTime);
- for (const NotifyArgs& args : out) {
- mFuzzListener.notify(args);
- }
- }
-
- void addProperty(std::string key, std::string value) {
- mFuzzEventHub->addProperty(key, value);
- configureDevice();
- }
-
- void setAbsoluteAxisInfo(int axis, const RawAbsoluteAxisInfo& axisInfo) {
- mFuzzEventHub->setAbsoluteAxisInfo(mFuzzDevice->getId(), axis, axisInfo);
- }
-
- template <class T, typename... Args>
- T& getMapper(Args... args) {
- int32_t eventhubId = mFdp->ConsumeIntegral<int32_t>();
- // ensure a device entry exists for this eventHubId
- mFuzzDevice->addEmptyEventHubDevice(eventhubId);
- configureDevice();
-
- return mFuzzDevice->template constructAndAddMapper<T>(eventhubId, args...);
- }
-};
-
-} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
index 54977df..922cbdf 100644
--- a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <FuzzContainer.h>
+#include <InputDevice.h>
#include <InputReaderBase.h>
#include <KeyboardInputMapper.h>
#include <MapperHelpers.h>
@@ -23,38 +23,43 @@
const int32_t kMaxKeycodes = 100;
-static void addProperty(FuzzContainer& fuzzer, std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) {
+static void addProperty(FuzzEventHub& eventHub, std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) {
// Pick a random property to set for the mapper to have set.
fdp->PickValueInArray<std::function<void()>>(
- {[&]() -> void { fuzzer.addProperty("keyboard.orientationAware", "1"); },
+ {[&]() -> void { eventHub.addProperty("keyboard.orientationAware", "1"); },
[&]() -> void {
- fuzzer.addProperty("keyboard.orientationAware",
- fdp->ConsumeRandomLengthString(100).data());
+ eventHub.addProperty("keyboard.orientationAware",
+ fdp->ConsumeRandomLengthString(100).data());
},
[&]() -> void {
- fuzzer.addProperty("keyboard.doNotWakeByDefault",
- fdp->ConsumeRandomLengthString(100).data());
+ eventHub.addProperty("keyboard.doNotWakeByDefault",
+ fdp->ConsumeRandomLengthString(100).data());
},
[&]() -> void {
- fuzzer.addProperty("keyboard.handlesKeyRepeat",
- fdp->ConsumeRandomLengthString(100).data());
+ eventHub.addProperty("keyboard.handlesKeyRepeat",
+ fdp->ConsumeRandomLengthString(100).data());
}})();
}
extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp =
std::make_shared<ThreadSafeFuzzedDataProvider>(data, size);
- FuzzContainer fuzzer(fdp);
- KeyboardInputMapper& mapper =
- fuzzer.getMapper<KeyboardInputMapper>(InputReaderConfiguration{},
- fdp->ConsumeIntegral<uint32_t>(),
- fdp->ConsumeIntegral<int32_t>());
+ // Create mocked objects to support the fuzzed input mapper.
+ std::shared_ptr<FuzzEventHub> eventHub = std::make_shared<FuzzEventHub>(fdp);
+ FuzzInputReaderContext context(eventHub, fdp);
+ InputDevice device = getFuzzedInputDevice(*fdp, &context);
+
+ KeyboardInputMapper& mapper = getMapperForDevice<
+ ThreadSafeFuzzedDataProvider,
+ KeyboardInputMapper>(*fdp.get(), device, InputReaderConfiguration{},
+ /*source=*/fdp->ConsumeIntegral<uint32_t>(),
+ /*keyboardType=*/fdp->ConsumeIntegral<int32_t>());
// Loop through mapper operations until randomness is exhausted.
while (fdp->remaining_bytes() > 0) {
fdp->PickValueInArray<std::function<void()>>({
- [&]() -> void { addProperty(fuzzer, fdp); },
+ [&]() -> void { addProperty(*eventHub.get(), fdp); },
[&]() -> void {
std::string dump;
mapper.dump(dump);
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index 5039d1a..e88731a 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -16,6 +16,7 @@
#pragma once
#include <map>
+#include <memory>
#include <EventHub.h>
#include <InputDevice.h>
@@ -328,10 +329,8 @@
public:
FuzzInputReaderContext(std::shared_ptr<EventHubInterface> eventHub,
- const sp<InputReaderPolicyInterface>& policy,
- InputListenerInterface& listener,
- std::shared_ptr<ThreadSafeFuzzedDataProvider> mFdp)
- : mEventHub(eventHub), mPolicy(policy), mFdp(mFdp) {}
+ std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp)
+ : mEventHub(eventHub), mPolicy(sp<FuzzInputReaderPolicy>::make(fdp)), mFdp(fdp) {}
~FuzzInputReaderContext() {}
void updateGlobalMetaState() override {}
int32_t getGlobalMetaState() { return mFdp->ConsumeIntegral<int32_t>(); }
@@ -358,4 +357,32 @@
void notifyStylusGestureStarted(int32_t, nsecs_t) {}
};
+template <class Fdp>
+InputDevice getFuzzedInputDevice(Fdp& fdp, FuzzInputReaderContext* context) {
+ InputDeviceIdentifier identifier;
+ identifier.name = fdp.ConsumeRandomLengthString(16);
+ identifier.location = fdp.ConsumeRandomLengthString(12);
+ int32_t deviceID = fdp.ConsumeIntegralInRange(0, 5);
+ int32_t deviceGeneration = fdp.ConsumeIntegralInRange(0, 5);
+ return InputDevice(context, deviceID, deviceGeneration, identifier);
+}
+
+template <class Fdp>
+void configureAndResetDevice(Fdp& fdp, InputDevice& device) {
+ nsecs_t arbitraryTime = fdp.template ConsumeIntegral<nsecs_t>();
+ std::list<NotifyArgs> out;
+ out += device.configure(arbitraryTime, /*readerConfig=*/{}, /*changes=*/{});
+ out += device.reset(arbitraryTime);
+}
+
+template <class Fdp, class T, typename... Args>
+T& getMapperForDevice(Fdp& fdp, InputDevice& device, Args... args) {
+ int32_t eventhubId = fdp.template ConsumeIntegral<int32_t>();
+ // ensure a device entry exists for this eventHubId
+ device.addEmptyEventHubDevice(eventhubId);
+ configureAndResetDevice(fdp, device);
+
+ return device.template constructAndAddMapper<T>(eventhubId, args...);
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
index 569767f..d3f6690 100644
--- a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <FuzzContainer.h>
+#include <InputDevice.h>
#include <InputReaderBase.h>
#include <MapperHelpers.h>
#include <MultiTouchInputMapper.h>
@@ -23,53 +23,63 @@
const int32_t kMaxKeycodes = 100;
-static void addProperty(FuzzContainer& fuzzer, std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) {
+static void addProperty(FuzzEventHub& eventHub, std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp) {
// Pick a random property to set for the mapper to have set.
fdp->PickValueInArray<std::function<void()>>(
- {[&]() -> void { fuzzer.addProperty("touch.deviceType", "touchScreen"); },
+ {[&]() -> void { eventHub.addProperty("touch.deviceType", "touchScreen"); },
[&]() -> void {
- fuzzer.addProperty("touch.deviceType", fdp->ConsumeRandomLengthString(8).data());
+ eventHub.addProperty("touch.deviceType", fdp->ConsumeRandomLengthString(8).data());
},
[&]() -> void {
- fuzzer.addProperty("touch.size.scale", fdp->ConsumeRandomLengthString(8).data());
+ eventHub.addProperty("touch.size.scale", fdp->ConsumeRandomLengthString(8).data());
},
[&]() -> void {
- fuzzer.addProperty("touch.size.bias", fdp->ConsumeRandomLengthString(8).data());
+ eventHub.addProperty("touch.size.bias", fdp->ConsumeRandomLengthString(8).data());
},
[&]() -> void {
- fuzzer.addProperty("touch.size.isSummed",
- fdp->ConsumeRandomLengthString(8).data());
+ eventHub.addProperty("touch.size.isSummed",
+ fdp->ConsumeRandomLengthString(8).data());
},
[&]() -> void {
- fuzzer.addProperty("touch.size.calibration",
- fdp->ConsumeRandomLengthString(8).data());
+ eventHub.addProperty("touch.size.calibration",
+ fdp->ConsumeRandomLengthString(8).data());
},
[&]() -> void {
- fuzzer.addProperty("touch.pressure.scale",
- fdp->ConsumeRandomLengthString(8).data());
+ eventHub.addProperty("touch.pressure.scale",
+ fdp->ConsumeRandomLengthString(8).data());
},
[&]() -> void {
- fuzzer.addProperty("touch.size.calibration",
- fdp->ConsumeBool() ? "diameter" : "area");
+ eventHub.addProperty("touch.size.calibration",
+ fdp->ConsumeBool() ? "diameter" : "area");
},
[&]() -> void {
- fuzzer.addProperty("touch.pressure.calibration",
- fdp->ConsumeRandomLengthString(8).data());
+ eventHub.addProperty("touch.pressure.calibration",
+ fdp->ConsumeRandomLengthString(8).data());
}})();
}
extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp =
std::make_shared<ThreadSafeFuzzedDataProvider>(data, size);
- FuzzContainer fuzzer(fdp);
+
+ // Create mocked objects to support the fuzzed input mapper.
+ std::shared_ptr<FuzzEventHub> eventHub = std::make_shared<FuzzEventHub>(fdp);
+ FuzzInputReaderContext context(eventHub, fdp);
+ InputDevice device = getFuzzedInputDevice(*fdp, &context);
InputReaderConfiguration policyConfig;
- MultiTouchInputMapper& mapper = fuzzer.getMapper<MultiTouchInputMapper>(policyConfig);
+ MultiTouchInputMapper& mapper =
+ getMapperForDevice<ThreadSafeFuzzedDataProvider, MultiTouchInputMapper>(*fdp.get(),
+ device,
+ policyConfig);
// Loop through mapper operations until randomness is exhausted.
while (fdp->remaining_bytes() > 0) {
fdp->PickValueInArray<std::function<void()>>({
- [&]() -> void { addProperty(fuzzer, fdp); },
+ [&]() -> void {
+ addProperty(*eventHub.get(), fdp);
+ configureAndResetDevice(*fdp, device);
+ },
[&]() -> void {
std::string dump;
mapper.dump(dump);
diff --git a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp
index 80eebd5..ac2030a 100644
--- a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <FuzzContainer.h>
+#include <InputDevice.h>
#include <InputReaderBase.h>
#include <MapperHelpers.h>
#include <SwitchInputMapper.h>
@@ -24,9 +24,15 @@
extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp =
std::make_shared<ThreadSafeFuzzedDataProvider>(data, size);
- FuzzContainer fuzzer(fdp);
- SwitchInputMapper& mapper = fuzzer.getMapper<SwitchInputMapper>(InputReaderConfiguration{});
+ // Create mocked objects to support the fuzzed input mapper.
+ std::shared_ptr<FuzzEventHub> eventHub = std::make_shared<FuzzEventHub>(fdp);
+ FuzzInputReaderContext context(eventHub, fdp);
+ InputDevice device = getFuzzedInputDevice(*fdp, &context);
+
+ SwitchInputMapper& mapper =
+ getMapperForDevice<ThreadSafeFuzzedDataProvider,
+ SwitchInputMapper>(*fdp.get(), device, InputReaderConfiguration{});
// Loop through mapper operations until randomness is exhausted.
while (fdp->remaining_bytes() > 0) {
diff --git a/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp
index 796178a..be765cc 100644
--- a/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp
@@ -15,12 +15,13 @@
*/
#include <limits>
+#include <memory>
#include <string>
#include <vector>
#include <linux/input-event-codes.h>
-#include <FuzzContainer.h>
+#include <InputDevice.h>
#include <InputReaderBase.h>
#include <MapperHelpers.h>
#include <TouchpadInputMapper.h>
@@ -29,30 +30,30 @@
namespace {
-void setAxisInfo(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer, int axis) {
+void setAxisInfo(ThreadSafeFuzzedDataProvider& fdp, FuzzEventHub& eventHub, int32_t id, int axis) {
if (fdp.ConsumeBool()) {
- fuzzer.setAbsoluteAxisInfo(axis,
- RawAbsoluteAxisInfo{
- .valid = fdp.ConsumeBool(),
- .minValue = fdp.ConsumeIntegral<int32_t>(),
- .maxValue = fdp.ConsumeIntegral<int32_t>(),
- .flat = fdp.ConsumeIntegral<int32_t>(),
- .fuzz = fdp.ConsumeIntegral<int32_t>(),
- .resolution = fdp.ConsumeIntegral<int32_t>(),
- });
+ eventHub.setAbsoluteAxisInfo(id, axis,
+ RawAbsoluteAxisInfo{
+ .valid = fdp.ConsumeBool(),
+ .minValue = fdp.ConsumeIntegral<int32_t>(),
+ .maxValue = fdp.ConsumeIntegral<int32_t>(),
+ .flat = fdp.ConsumeIntegral<int32_t>(),
+ .fuzz = fdp.ConsumeIntegral<int32_t>(),
+ .resolution = fdp.ConsumeIntegral<int32_t>(),
+ });
}
}
-void setAxisInfos(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer) {
- setAxisInfo(fdp, fuzzer, ABS_MT_SLOT);
- setAxisInfo(fdp, fuzzer, ABS_MT_POSITION_X);
- setAxisInfo(fdp, fuzzer, ABS_MT_POSITION_Y);
- setAxisInfo(fdp, fuzzer, ABS_MT_PRESSURE);
- setAxisInfo(fdp, fuzzer, ABS_MT_ORIENTATION);
- setAxisInfo(fdp, fuzzer, ABS_MT_TOUCH_MAJOR);
- setAxisInfo(fdp, fuzzer, ABS_MT_TOUCH_MINOR);
- setAxisInfo(fdp, fuzzer, ABS_MT_WIDTH_MAJOR);
- setAxisInfo(fdp, fuzzer, ABS_MT_WIDTH_MINOR);
+void setAxisInfos(ThreadSafeFuzzedDataProvider& fdp, FuzzEventHub& eventHub, int32_t id) {
+ setAxisInfo(fdp, eventHub, id, ABS_MT_SLOT);
+ setAxisInfo(fdp, eventHub, id, ABS_MT_POSITION_X);
+ setAxisInfo(fdp, eventHub, id, ABS_MT_POSITION_Y);
+ setAxisInfo(fdp, eventHub, id, ABS_MT_PRESSURE);
+ setAxisInfo(fdp, eventHub, id, ABS_MT_ORIENTATION);
+ setAxisInfo(fdp, eventHub, id, ABS_MT_TOUCH_MAJOR);
+ setAxisInfo(fdp, eventHub, id, ABS_MT_TOUCH_MINOR);
+ setAxisInfo(fdp, eventHub, id, ABS_MT_WIDTH_MAJOR);
+ setAxisInfo(fdp, eventHub, id, ABS_MT_WIDTH_MINOR);
}
const std::vector<std::string> boolPropertiesToFuzz = {
@@ -89,32 +90,32 @@
"gestureProp.Two_Finger_Vertical_Close_Distance_Thresh",
};
-void setDeviceSpecificConfig(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer) {
+void setDeviceSpecificConfig(ThreadSafeFuzzedDataProvider& fdp, FuzzEventHub& eventHub) {
// There are a great many gesture properties offered by the Gestures library, all of which could
// potentially be set in Input Device Configuration files. Maintaining a complete list is
// impractical, so instead we only fuzz properties which are used in at least one IDC file, or
// which are likely to be used in future (e.g. ones for controlling palm rejection).
if (fdp.ConsumeBool()) {
- fuzzer.addProperty("gestureProp.Touchpad_Stack_Version",
- std::to_string(fdp.ConsumeIntegral<int>()));
+ eventHub.addProperty("gestureProp.Touchpad_Stack_Version",
+ std::to_string(fdp.ConsumeIntegral<int>()));
}
for (auto& propertyName : boolPropertiesToFuzz) {
if (fdp.ConsumeBool()) {
- fuzzer.addProperty(propertyName, fdp.ConsumeBool() ? "1" : "0");
+ eventHub.addProperty(propertyName, fdp.ConsumeBool() ? "1" : "0");
}
}
for (auto& propertyName : doublePropertiesToFuzz) {
if (fdp.ConsumeBool()) {
- fuzzer.addProperty(propertyName, std::to_string(fdp.ConsumeFloatingPoint<double>()));
+ eventHub.addProperty(propertyName, std::to_string(fdp.ConsumeFloatingPoint<double>()));
}
}
if (fdp.ConsumeBool()) {
- fuzzer.addProperty("gestureProp." + fdp.ConsumeRandomLengthString(),
- std::to_string(fdp.ConsumeIntegral<int>()));
+ eventHub.addProperty("gestureProp." + fdp.ConsumeRandomLengthString(),
+ std::to_string(fdp.ConsumeIntegral<int>()));
}
}
@@ -130,16 +131,23 @@
extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) {
std::shared_ptr<ThreadSafeFuzzedDataProvider> fdp =
std::make_shared<ThreadSafeFuzzedDataProvider>(data, size);
- FuzzContainer fuzzer(fdp);
- setAxisInfos(*fdp, fuzzer);
- setDeviceSpecificConfig(*fdp, fuzzer);
+
+ // Create mocked objects to support the fuzzed input mapper.
+ std::shared_ptr<FuzzEventHub> eventHub = std::make_shared<FuzzEventHub>(fdp);
+ FuzzInputReaderContext context(eventHub, fdp);
+ InputDevice device = getFuzzedInputDevice(*fdp, &context);
+
+ setAxisInfos(*fdp, *eventHub.get(), device.getId());
+ setDeviceSpecificConfig(*fdp, *eventHub.get());
InputReaderConfiguration policyConfig;
// Some settings are fuzzed here, as well as in the main loop, to provide randomized data to the
// TouchpadInputMapper constructor.
setTouchpadSettings(*fdp, policyConfig);
policyConfig.pointerCaptureRequest.enable = fdp->ConsumeBool();
- TouchpadInputMapper& mapper = fuzzer.getMapper<TouchpadInputMapper>(policyConfig);
+ TouchpadInputMapper& mapper =
+ getMapperForDevice<ThreadSafeFuzzedDataProvider, TouchpadInputMapper>(*fdp, device,
+ policyConfig);
// Loop through mapper operations until randomness is exhausted.
while (fdp->remaining_bytes() > 0) {
diff --git a/services/sensorservice/AidlSensorHalWrapper.cpp b/services/sensorservice/AidlSensorHalWrapper.cpp
index f5b360f..e60db93 100644
--- a/services/sensorservice/AidlSensorHalWrapper.cpp
+++ b/services/sensorservice/AidlSensorHalWrapper.cpp
@@ -308,8 +308,12 @@
}
int32_t token;
- mSensors->configDirectReport(sensorHandle, channelHandle, rate, &token);
- return token;
+ status_t status = convertToStatus(
+ mSensors->configDirectReport(sensorHandle, channelHandle, rate, &token));
+ if (status == OK && rate != ISensors::RateLevel::STOP) {
+ status = static_cast<status_t>(token);
+ }
+ return status;
}
void AidlSensorHalWrapper::writeWakeLockHandled(uint32_t count) {
diff --git a/services/surfaceflinger/BackgroundExecutor.cpp b/services/surfaceflinger/BackgroundExecutor.cpp
index 6ddf790..5a1ec6f 100644
--- a/services/surfaceflinger/BackgroundExecutor.cpp
+++ b/services/surfaceflinger/BackgroundExecutor.cpp
@@ -20,6 +20,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include <utils/Log.h>
+#include <mutex>
#include "BackgroundExecutor.h"
@@ -60,4 +61,17 @@
LOG_ALWAYS_FATAL_IF(sem_post(&mSemaphore), "sem_post failed");
}
+void BackgroundExecutor::flushQueue() {
+ std::mutex mutex;
+ std::condition_variable cv;
+ bool flushComplete = false;
+ sendCallbacks({[&]() {
+ std::scoped_lock lock{mutex};
+ flushComplete = true;
+ cv.notify_one();
+ }});
+ std::unique_lock<std::mutex> lock{mutex};
+ cv.wait(lock, [&]() { return flushComplete; });
+}
+
} // namespace android
diff --git a/services/surfaceflinger/BackgroundExecutor.h b/services/surfaceflinger/BackgroundExecutor.h
index 0fae5a5..66b7d7a 100644
--- a/services/surfaceflinger/BackgroundExecutor.h
+++ b/services/surfaceflinger/BackgroundExecutor.h
@@ -34,6 +34,7 @@
// Queues callbacks onto a work queue to be executed by a background thread.
// This is safe to call from multiple threads.
void sendCallbacks(Callbacks&& tasks);
+ void flushQueue();
private:
sem_t mSemaphore;
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index c0eb36d..311820c 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -244,14 +244,13 @@
addReader(translate<Display>(kSingleReaderKey));
// If unable to read interface version, then become backwards compatible.
- int32_t version = 1;
- const auto status = mAidlComposerClient->getInterfaceVersion(&version);
+ const auto status = mAidlComposerClient->getInterfaceVersion(&mComposerInterfaceVersion);
if (!status.isOk()) {
ALOGE("getInterfaceVersion for AidlComposer constructor failed %s",
status.getDescription().c_str());
}
- mSupportsBufferSlotsToClear = version > 1;
- if (!mSupportsBufferSlotsToClear) {
+
+ if (mComposerInterfaceVersion <= 1) {
if (sysprop::clear_slots_with_set_layer_buffer(false)) {
mClearSlotBuffer = sp<GraphicBuffer>::make(1, 1, PIXEL_FORMAT_RGBX_8888,
GraphicBuffer::USAGE_HW_COMPOSER |
@@ -281,6 +280,10 @@
}
}
+bool AidlComposer::getDisplayConfigurationsSupported() const {
+ return mComposerInterfaceVersion >= 3;
+}
+
std::vector<Capability> AidlComposer::getCapabilities() {
std::vector<Capability> capabilities;
const auto status = mAidlComposer->getCapabilities(&capabilities);
@@ -489,6 +492,18 @@
return Error::NONE;
}
+Error AidlComposer::getDisplayConfigurations(Display display,
+ std::vector<DisplayConfiguration>* outConfigs) {
+ const auto status =
+ mAidlComposerClient->getDisplayConfigurations(translate<int64_t>(display), outConfigs);
+ if (!status.isOk()) {
+ ALOGE("getDisplayConfigurations failed %s", status.getDescription().c_str());
+ return static_cast<Error>(status.getServiceSpecificError());
+ }
+
+ return Error::NONE;
+}
+
Error AidlComposer::getDisplayName(Display display, std::string* outName) {
const auto status = mAidlComposerClient->getDisplayName(translate<int64_t>(display), outName);
if (!status.isOk()) {
@@ -848,7 +863,7 @@
Error error = Error::NONE;
mMutex.lock_shared();
if (auto writer = getWriter(display)) {
- if (mSupportsBufferSlotsToClear) {
+ if (mComposerInterfaceVersion > 1) {
writer->get().setLayerBufferSlotsToClear(translate<int64_t>(display),
translate<int64_t>(layer), slotsToClear);
// Backwards compatible way of clearing buffer slots is to set the layer buffer with a
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 8d21b49..e31ff81 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -66,6 +66,7 @@
~AidlComposer() override;
bool isSupported(OptionalFeature) const;
+ bool getDisplayConfigurationsSupported() const;
std::vector<aidl::android::hardware::graphics::composer3::Capability> getCapabilities()
override;
@@ -95,6 +96,7 @@
Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute,
int32_t* outValue) override;
Error getDisplayConfigs(Display display, std::vector<Config>* outConfigs);
+ Error getDisplayConfigurations(Display, std::vector<DisplayConfiguration>*);
Error getDisplayName(Display display, std::string* outName) override;
Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
@@ -285,8 +287,8 @@
// threading annotations.
ftl::SharedMutex mMutex;
- // Whether or not explicitly clearing buffer slots is supported.
- bool mSupportsBufferSlotsToClear;
+ int32_t mComposerInterfaceVersion = 1;
+
// Buffer slots for layers are cleared by setting the slot buffer to this buffer.
sp<GraphicBuffer> mClearSlotBuffer;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index cf67795..cc60fd0 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -39,6 +39,7 @@
#include <aidl/android/hardware/graphics/composer3/Color.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
+#include <aidl/android/hardware/graphics/composer3/DisplayConfiguration.h>
#include <aidl/android/hardware/graphics/composer3/IComposerCallback.h>
#include <aidl/android/hardware/graphics/composer3/OverlayProperties.h>
@@ -85,6 +86,7 @@
using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey;
using PerFrameMetadataBlob = IComposerClient::PerFrameMetadataBlob;
using AidlTransform = ::aidl::android::hardware::graphics::common::Transform;
+using DisplayConfiguration = V3_0::DisplayConfiguration;
using aidl::android::hardware::graphics::common::Hdr;
class Composer {
@@ -103,6 +105,7 @@
};
virtual bool isSupported(OptionalFeature) const = 0;
+ virtual bool getDisplayConfigurationsSupported() const = 0;
virtual std::vector<aidl::android::hardware::graphics::composer3::Capability>
getCapabilities() = 0;
@@ -130,6 +133,9 @@
virtual Error getDisplayAttribute(Display display, Config config,
IComposerClient::Attribute attribute, int32_t* outValue) = 0;
virtual Error getDisplayConfigs(Display display, std::vector<Config>* outConfigs) = 0;
+
+ virtual Error getDisplayConfigurations(Display, std::vector<DisplayConfiguration>*) = 0;
+
virtual Error getDisplayName(Display display, std::string* outName) = 0;
virtual Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h
index 61a9a08..1810925 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayMode.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h
@@ -80,20 +80,20 @@
return *this;
}
- Builder& setDpiX(int32_t dpiX) {
- if (dpiX == -1) {
+ Builder& setDpiX(float dpiX) {
+ if (dpiX == -1.f) {
mDisplayMode->mDpi.x = getDefaultDensity();
} else {
- mDisplayMode->mDpi.x = dpiX / 1000.f;
+ mDisplayMode->mDpi.x = dpiX;
}
return *this;
}
- Builder& setDpiY(int32_t dpiY) {
- if (dpiY == -1) {
+ Builder& setDpiY(float dpiY) {
+ if (dpiY == -1.f) {
mDisplayMode->mDpi.y = getDefaultDensity();
} else {
- mDisplayMode->mDpi.y = dpiY / 1000.f;
+ mDisplayMode->mDpi.y = dpiY;
}
return *this;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index f350eba..aefa7c3 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -265,6 +265,46 @@
RETURN_IF_INVALID_DISPLAY(displayId, {});
const auto hwcDisplayId = mDisplayData.at(displayId).hwcDisplay->getId();
+
+ if (mComposer->getDisplayConfigurationsSupported()) {
+ return getModesFromDisplayConfigurations(hwcDisplayId);
+ }
+
+ return getModesFromLegacyDisplayConfigs(hwcDisplayId);
+}
+
+std::vector<HWComposer::HWCDisplayMode> HWComposer::getModesFromDisplayConfigurations(
+ uint64_t hwcDisplayId) const {
+ std::vector<hal::DisplayConfiguration> configs;
+ auto error =
+ static_cast<hal::Error>(mComposer->getDisplayConfigurations(hwcDisplayId, &configs));
+ RETURN_IF_HWC_ERROR_FOR("getDisplayConfigurations", error, *toPhysicalDisplayId(hwcDisplayId),
+ {});
+
+ std::vector<HWCDisplayMode> modes;
+ modes.reserve(configs.size());
+ for (auto config : configs) {
+ auto hwcMode = HWCDisplayMode{
+ .hwcId = static_cast<hal::HWConfigId>(config.configId),
+ .width = config.width,
+ .height = config.height,
+ .vsyncPeriod = config.vsyncPeriod,
+ .configGroup = config.configGroup,
+ };
+
+ if (config.dpi) {
+ hwcMode.dpiX = config.dpi->x;
+ hwcMode.dpiY = config.dpi->y;
+ }
+
+ modes.push_back(hwcMode);
+ }
+
+ return modes;
+}
+
+std::vector<HWComposer::HWCDisplayMode> HWComposer::getModesFromLegacyDisplayConfigs(
+ uint64_t hwcDisplayId) const {
std::vector<hal::HWConfigId> configIds;
auto error = static_cast<hal::Error>(mComposer->getDisplayConfigs(hwcDisplayId, &configIds));
RETURN_IF_HWC_ERROR_FOR("getDisplayConfigs", error, *toPhysicalDisplayId(hwcDisplayId), {});
@@ -272,17 +312,25 @@
std::vector<HWCDisplayMode> modes;
modes.reserve(configIds.size());
for (auto configId : configIds) {
- modes.push_back(HWCDisplayMode{
+ auto hwcMode = HWCDisplayMode{
.hwcId = configId,
.width = getAttribute(hwcDisplayId, configId, hal::Attribute::WIDTH),
.height = getAttribute(hwcDisplayId, configId, hal::Attribute::HEIGHT),
.vsyncPeriod = getAttribute(hwcDisplayId, configId, hal::Attribute::VSYNC_PERIOD),
- .dpiX = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X),
- .dpiY = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y),
.configGroup = getAttribute(hwcDisplayId, configId, hal::Attribute::CONFIG_GROUP),
- });
- }
+ };
+ const int32_t dpiX = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X);
+ const int32_t dpiY = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y);
+ if (dpiX != -1) {
+ hwcMode.dpiX = static_cast<float>(dpiX) / 1000.f;
+ }
+ if (dpiY != -1) {
+ hwcMode.dpiY = static_cast<float>(dpiY) / 1000.f;
+ }
+
+ modes.push_back(hwcMode);
+ }
return modes;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 3702c62..8247d97 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -99,8 +99,8 @@
int32_t width = -1;
int32_t height = -1;
nsecs_t vsyncPeriod = -1;
- int32_t dpiX = -1;
- int32_t dpiY = -1;
+ float dpiX = -1.f;
+ float dpiY = -1.f;
int32_t configGroup = -1;
friend std::ostream& operator<<(std::ostream& os, const HWCDisplayMode& mode) {
@@ -501,6 +501,9 @@
std::optional<DisplayIdentificationInfo> onHotplugDisconnect(hal::HWDisplayId);
bool shouldIgnoreHotplugConnect(hal::HWDisplayId, bool hasDisplayIdentificationData) const;
+ std::vector<HWCDisplayMode> getModesFromDisplayConfigurations(uint64_t hwcDisplayId) const;
+ std::vector<HWCDisplayMode> getModesFromLegacyDisplayConfigs(uint64_t hwcDisplayId) const;
+
int32_t getAttribute(hal::HWDisplayId hwcDisplayId, hal::HWConfigId configId,
hal::Attribute attribute) const;
diff --git a/services/surfaceflinger/DisplayHardware/Hal.h b/services/surfaceflinger/DisplayHardware/Hal.h
index bf3089f..e95ae89 100644
--- a/services/surfaceflinger/DisplayHardware/Hal.h
+++ b/services/surfaceflinger/DisplayHardware/Hal.h
@@ -23,6 +23,7 @@
#include <aidl/android/hardware/graphics/common/Hdr.h>
#include <aidl/android/hardware/graphics/composer3/Composition.h>
#include <aidl/android/hardware/graphics/composer3/DisplayCapability.h>
+#include <aidl/android/hardware/graphics/composer3/DisplayConfiguration.h>
#define ERROR_HAS_CHANGES 5
@@ -34,6 +35,7 @@
namespace V2_2 = android::hardware::graphics::composer::V2_2;
namespace V2_3 = android::hardware::graphics::composer::V2_3;
namespace V2_4 = android::hardware::graphics::composer::V2_4;
+namespace V3_0 = ::aidl::android::hardware::graphics::composer3;
using types::V1_0::ColorTransform;
using types::V1_0::Transform;
@@ -70,6 +72,7 @@
using Vsync = IComposerClient::Vsync;
using VsyncPeriodChangeConstraints = IComposerClient::VsyncPeriodChangeConstraints;
using Hdr = aidl::android::hardware::graphics::common::Hdr;
+using DisplayConfiguration = V3_0::DisplayConfiguration;
} // namespace hardware::graphics::composer::hal
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 9b41da5..0655abc 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -269,6 +269,11 @@
}
}
+bool HidlComposer::getDisplayConfigurationsSupported() const {
+ // getDisplayConfigurations is not supported on the HIDL composer.
+ return false;
+};
+
std::vector<Capability> HidlComposer::getCapabilities() {
std::vector<Capability> capabilities;
mComposer->getCapabilities([&](const auto& tmpCapabilities) {
@@ -477,6 +482,11 @@
return error;
}
+Error HidlComposer::getDisplayConfigurations(Display, std::vector<DisplayConfiguration>*) {
+ LOG_ALWAYS_FATAL("getDisplayConfigurations should not have been called on this, as "
+ "it's a HWC3 interface version 3 feature");
+}
+
Error HidlComposer::getDisplayName(Display display, std::string* outName) {
Error error = kDefaultError;
mClient->getDisplayName(display, [&](const auto& tmpError, const auto& tmpName) {
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 0521acf..ac96d9a 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -167,6 +167,7 @@
~HidlComposer() override;
bool isSupported(OptionalFeature) const;
+ bool getDisplayConfigurationsSupported() const;
std::vector<aidl::android::hardware::graphics::composer3::Capability> getCapabilities()
override;
@@ -196,6 +197,7 @@
Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute,
int32_t* outValue) override;
Error getDisplayConfigs(Display display, std::vector<Config>* outConfigs);
+ Error getDisplayConfigurations(Display, std::vector<DisplayConfiguration>*);
Error getDisplayName(Display display, std::string* outName) override;
Error getDisplayRequests(Display display, uint32_t* outDisplayRequestMask,
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.h b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
index 1416872..1afcef9 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.h
@@ -41,10 +41,6 @@
}
};
-struct ChildState {
- bool hasValidFrameRate = false;
-};
-
// LayerSnapshot stores Layer state used by CompositionEngine and RenderEngine. Composition
// Engine uses a pointer to LayerSnapshot (as LayerFECompositionState*) and the LayerSettings
// passed to Render Engine are created using properties stored on this struct.
@@ -99,7 +95,6 @@
uint32_t touchCropId;
gui::Uid uid = gui::Uid::INVALID;
gui::Pid pid = gui::Pid::INVALID;
- ChildState childState;
enum class Reachablilty : uint32_t {
// Can traverse the hierarchy from a root node and reach this snapshot
Reachable,
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 3a19d0b..7e678b9 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -558,7 +558,7 @@
const LayerSnapshot& childSnapshot =
updateSnapshotsInHierarchy(args, *childHierarchy, traversalPath, *snapshot,
depth + 1);
- updateChildState(*snapshot, childSnapshot, args);
+ updateFrameRateFromChildSnapshot(*snapshot, childSnapshot, args);
}
if (oldFrameRate == snapshot->frameRate) {
@@ -666,36 +666,40 @@
}
}
-void LayerSnapshotBuilder::updateChildState(LayerSnapshot& snapshot,
- const LayerSnapshot& childSnapshot, const Args& args) {
- if (snapshot.childState.hasValidFrameRate) {
+void LayerSnapshotBuilder::updateFrameRateFromChildSnapshot(LayerSnapshot& snapshot,
+ const LayerSnapshot& childSnapshot,
+ const Args& args) {
+ if (args.forceUpdate == ForceUpdateFlags::NONE &&
+ !childSnapshot.changes.any(RequestedLayerState::Changes::FrameRate |
+ RequestedLayerState::Changes::Hierarchy)) {
return;
}
- if (args.forceUpdate == ForceUpdateFlags::ALL ||
- childSnapshot.changes.test(RequestedLayerState::Changes::FrameRate)) {
- // We return whether this layer ot its children has a vote. We ignore ExactOrMultiple votes
- // for the same reason we are allowing touch boost for those layers. See
- // RefreshRateSelector::rankFrameRates for details.
- using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility;
- const auto layerVotedWithDefaultCompatibility = childSnapshot.frameRate.rate.isValid() &&
- childSnapshot.frameRate.type == FrameRateCompatibility::Default;
- const auto layerVotedWithNoVote =
- childSnapshot.frameRate.type == FrameRateCompatibility::NoVote;
- const auto layerVotedWithExactCompatibility = childSnapshot.frameRate.rate.isValid() &&
- childSnapshot.frameRate.type == FrameRateCompatibility::Exact;
- snapshot.childState.hasValidFrameRate |= layerVotedWithDefaultCompatibility ||
- layerVotedWithNoVote || layerVotedWithExactCompatibility;
+ using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility;
+ if (snapshot.frameRate.rate.isValid() ||
+ snapshot.frameRate.type == FrameRateCompatibility::NoVote) {
+ // we already have a valid framerate.
+ return;
+ }
- // If we don't have a valid frame rate, but the children do, we set this
- // layer as NoVote to allow the children to control the refresh rate
- if (!snapshot.frameRate.rate.isValid() &&
- snapshot.frameRate.type != FrameRateCompatibility::NoVote &&
- snapshot.childState.hasValidFrameRate) {
- snapshot.frameRate =
- scheduler::LayerInfo::FrameRate(Fps(), FrameRateCompatibility::NoVote);
- snapshot.changes |= childSnapshot.changes & RequestedLayerState::Changes::FrameRate;
- }
+ // We return whether this layer or its children has a vote. We ignore ExactOrMultiple votes
+ // for the same reason we are allowing touch boost for those layers. See
+ // RefreshRateSelector::rankFrameRates for details.
+ const auto layerVotedWithDefaultCompatibility = childSnapshot.frameRate.rate.isValid() &&
+ childSnapshot.frameRate.type == FrameRateCompatibility::Default;
+ const auto layerVotedWithNoVote =
+ childSnapshot.frameRate.type == FrameRateCompatibility::NoVote;
+ const auto layerVotedWithExactCompatibility = childSnapshot.frameRate.rate.isValid() &&
+ childSnapshot.frameRate.type == FrameRateCompatibility::Exact;
+
+ bool childHasValidFrameRate = layerVotedWithDefaultCompatibility || layerVotedWithNoVote ||
+ layerVotedWithExactCompatibility;
+
+ // If we don't have a valid frame rate, but the children do, we set this
+ // layer as NoVote to allow the children to control the refresh rate
+ if (childHasValidFrameRate) {
+ snapshot.frameRate = scheduler::LayerInfo::FrameRate(Fps(), FrameRateCompatibility::NoVote);
+ snapshot.changes |= RequestedLayerState::Changes::FrameRate;
}
}
@@ -812,7 +816,9 @@
}
}
- if (forceUpdate || snapshot.changes.any(RequestedLayerState::Changes::FrameRate)) {
+ if (forceUpdate ||
+ snapshot.changes.any(RequestedLayerState::Changes::FrameRate |
+ RequestedLayerState::Changes::Hierarchy)) {
snapshot.frameRate = (requested.requestedFrameRate.rate.isValid() ||
(requested.requestedFrameRate.type ==
scheduler::LayerInfo::FrameRateCompatibility::NoVote))
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
index c81a5d2..d361605 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.h
@@ -116,8 +116,8 @@
LayerSnapshot* createSnapshot(const LayerHierarchy::TraversalPath& id,
const RequestedLayerState& layer,
const LayerSnapshot& parentSnapshot);
- void updateChildState(LayerSnapshot& snapshot, const LayerSnapshot& childSnapshot,
- const Args& args);
+ void updateFrameRateFromChildSnapshot(LayerSnapshot& snapshot,
+ const LayerSnapshot& childSnapshot, const Args& args);
void updateTouchableRegionCrop(const Args& args);
std::unordered_map<LayerHierarchy::TraversalPath, LayerSnapshot*,
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index 4e7da82..4734097 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -1,6 +1,7 @@
adyabr@google.com
alecmouri@google.com
chaviw@google.com
+domlaskowski@google.com
lpy@google.com
pdwilliams@google.com
racarr@google.com
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 08667bf..d6d7725 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -25,6 +25,7 @@
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
+#include <ftl/concat.h>
#include <ftl/enum.h>
#include <ftl/fake_guard.h>
#include <ftl/small_map.h>
@@ -130,8 +131,8 @@
auto [pacesetterVsyncSchedule, isNew] = [&]() FTL_FAKE_GUARD(kMainThreadContext) {
std::scoped_lock lock(mDisplayLock);
const bool isNew = mDisplays
- .emplace_or_replace(displayId, std::move(selectorPtr),
- std::move(schedulePtr))
+ .emplace_or_replace(displayId, displayId, std::move(selectorPtr),
+ std::move(schedulePtr), mFeatures)
.second;
return std::make_pair(promotePacesetterDisplayLocked(), isNew);
@@ -171,21 +172,43 @@
void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId,
TimePoint expectedVsyncTime) {
- mPacesetterFrameTargeter.beginFrame({.frameBeginTime = SchedulerClock::now(),
- .vsyncId = vsyncId,
- .expectedVsyncTime = expectedVsyncTime,
- .sfWorkDuration =
- mVsyncModulator->getVsyncConfig().sfWorkDuration},
- *getVsyncSchedule());
+ const FrameTargeter::BeginFrameArgs beginFrameArgs =
+ {.frameBeginTime = SchedulerClock::now(),
+ .vsyncId = vsyncId,
+ // TODO(b/255601557): Calculate per display.
+ .expectedVsyncTime = expectedVsyncTime,
+ .sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration};
- if (!compositor.commit(mPacesetterFrameTargeter.target())) {
- return;
+ LOG_ALWAYS_FATAL_IF(!mPacesetterDisplayId);
+ const auto pacesetterId = *mPacesetterDisplayId;
+ const auto pacesetterOpt = mDisplays.get(pacesetterId);
+
+ FrameTargeter& pacesetterTargeter = *pacesetterOpt->get().targeterPtr;
+ pacesetterTargeter.beginFrame(beginFrameArgs, *pacesetterOpt->get().schedulePtr);
+
+ if (!compositor.commit(pacesetterTargeter.target())) return;
+
+ // TODO(b/256196556): Choose the frontrunner display.
+ FrameTargeters targeters;
+ targeters.try_emplace(pacesetterId, &pacesetterTargeter);
+
+ for (auto& [id, display] : mDisplays) {
+ if (id == pacesetterId) continue;
+
+ FrameTargeter& targeter = *display.targeterPtr;
+ targeter.beginFrame(beginFrameArgs, *display.schedulePtr);
+
+ targeters.try_emplace(id, &targeter);
}
- const auto compositeResult = compositor.composite(mPacesetterFrameTargeter);
+ const auto resultsPerDisplay = compositor.composite(pacesetterId, targeters);
compositor.sample();
- mPacesetterFrameTargeter.endFrame(compositeResult);
+ for (const auto& [id, targeter] : targeters) {
+ const auto resultOpt = resultsPerDisplay.get(id);
+ LOG_ALWAYS_FATAL_IF(!resultOpt);
+ targeter->endFrame(*resultOpt);
+ }
}
std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const {
@@ -539,8 +562,16 @@
}
void Scheduler::addPresentFence(PhysicalDisplayId id, std::shared_ptr<FenceTime> fence) {
- auto schedule = getVsyncSchedule(id);
- LOG_ALWAYS_FATAL_IF(!schedule);
+ const auto scheduleOpt =
+ (ftl::FakeGuard(mDisplayLock), mDisplays.get(id)).and_then([](const Display& display) {
+ return display.powerMode == hal::PowerMode::OFF
+ ? std::nullopt
+ : std::make_optional(display.schedulePtr);
+ });
+
+ if (!scheduleOpt) return;
+ const auto& schedule = scheduleOpt->get();
+
if (const bool needMoreSignals = schedule->getController().addPresentFence(std::move(fence))) {
schedule->enableHardwareVsync();
} else {
@@ -750,7 +781,23 @@
mFrameRateOverrideMappings.dump(dumper);
dumper.eol();
- mPacesetterFrameTargeter.dump(dumper);
+ {
+ utils::Dumper::Section section(dumper, "Frame Targeting"sv);
+
+ std::scoped_lock lock(mDisplayLock);
+ ftl::FakeGuard guard(kMainThreadContext);
+
+ for (const auto& [id, display] : mDisplays) {
+ utils::Dumper::Section
+ section(dumper,
+ id == mPacesetterDisplayId
+ ? ftl::Concat("Pacesetter Display ", id.value).c_str()
+ : ftl::Concat("Follower Display ", id.value).c_str());
+
+ display.targeterPtr->dump(dumper);
+ dumper.eol();
+ }
+ }
}
void Scheduler::dumpVsync(std::string& out) const {
@@ -771,6 +818,12 @@
}
bool Scheduler::updateFrameRateOverrides(GlobalSignals consideredSignals, Fps displayRefreshRate) {
+ std::scoped_lock lock(mPolicyLock);
+ return updateFrameRateOverridesLocked(consideredSignals, displayRefreshRate);
+}
+
+bool Scheduler::updateFrameRateOverridesLocked(GlobalSignals consideredSignals,
+ Fps displayRefreshRate) {
if (consideredSignals.idle) return false;
const auto frameRateOverrides =
@@ -989,7 +1042,7 @@
.emitEvent = !choice.consideredSignals.idle});
}
- frameRateOverridesChanged = updateFrameRateOverrides(consideredSignals, modeOpt->fps);
+ frameRateOverridesChanged = updateFrameRateOverridesLocked(consideredSignals, modeOpt->fps);
if (mPolicy.modeOpt != modeOpt) {
mPolicy.modeOpt = modeOpt;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 0ffa2d2..85d0f9a 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -222,7 +222,7 @@
// otherwise.
bool addResyncSample(PhysicalDisplayId, nsecs_t timestamp,
std::optional<nsecs_t> hwcVsyncPeriod);
- void addPresentFence(PhysicalDisplayId, std::shared_ptr<FenceTime>) EXCLUDES(mDisplayLock)
+ void addPresentFence(PhysicalDisplayId, std::shared_ptr<FenceTime>)
REQUIRES(kMainThreadContext);
// Layers are registered on creation, and unregistered when the weak reference expires.
@@ -254,7 +254,14 @@
return std::const_pointer_cast<VsyncSchedule>(std::as_const(*this).getVsyncSchedule(idOpt));
}
- const FrameTarget& pacesetterFrameTarget() { return mPacesetterFrameTargeter.target(); }
+ TimePoint expectedPresentTimeForPacesetter() const EXCLUDES(mDisplayLock) {
+ std::scoped_lock lock(mDisplayLock);
+ return pacesetterDisplayLocked()
+ .transform([](const Display& display) {
+ return display.targeterPtr->target().expectedPresentTime();
+ })
+ .value_or(TimePoint());
+ }
// Returns true if a given vsync timestamp is considered valid vsync
// for a given uid
@@ -300,6 +307,8 @@
return mLayerHistory.getLayerFramerate(now, id);
}
+ bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) EXCLUDES(mPolicyLock);
+
private:
friend class TestableScheduler;
@@ -308,7 +317,8 @@
enum class TouchState { Inactive, Active };
// impl::MessageQueue overrides:
- void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override;
+ void onFrameSignal(ICompositor&, VsyncId, TimePoint expectedVsyncTime) override
+ REQUIRES(kMainThreadContext, mDisplayLock);
// Create a connection on the given EventThread.
ConnectionHandle createConnection(std::unique_ptr<EventThread>);
@@ -384,7 +394,8 @@
GlobalSignals makeGlobalSignals() const REQUIRES(mPolicyLock);
- bool updateFrameRateOverrides(GlobalSignals, Fps displayRefreshRate) REQUIRES(mPolicyLock);
+ bool updateFrameRateOverridesLocked(GlobalSignals, Fps displayRefreshRate)
+ REQUIRES(mPolicyLock);
void updateAttachedChoreographers(const surfaceflinger::frontend::LayerHierarchy&,
Fps displayRefreshRate);
int updateAttachedChoreographersInternal(const surfaceflinger::frontend::LayerHierarchy&,
@@ -434,13 +445,24 @@
// must lock for writes but not reads. See also mPolicyLock for locking order.
mutable std::mutex mDisplayLock;
+ using FrameTargeterPtr = std::unique_ptr<FrameTargeter>;
+
struct Display {
- Display(RefreshRateSelectorPtr selectorPtr, VsyncSchedulePtr schedulePtr)
- : selectorPtr(std::move(selectorPtr)), schedulePtr(std::move(schedulePtr)) {}
+ Display(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
+ VsyncSchedulePtr schedulePtr, FeatureFlags features)
+ : displayId(displayId),
+ selectorPtr(std::move(selectorPtr)),
+ schedulePtr(std::move(schedulePtr)),
+ targeterPtr(std::make_unique<
+ FrameTargeter>(displayId,
+ features.test(Feature::kBackpressureGpuComposition))) {}
+
+ const PhysicalDisplayId displayId;
// Effectively const except in move constructor.
RefreshRateSelectorPtr selectorPtr;
VsyncSchedulePtr schedulePtr;
+ FrameTargeterPtr targeterPtr;
hal::PowerMode powerMode = hal::PowerMode::OFF;
};
@@ -454,8 +476,6 @@
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/VSyncDispatchTimerQueue.h b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
index 6499d69..e0fb8f9 100644
--- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
+++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h
@@ -146,13 +146,14 @@
void cancelTimer() REQUIRES(mMutex);
ScheduleResult scheduleLocked(CallbackToken, ScheduleTiming) REQUIRES(mMutex);
+ std::mutex mutable mMutex;
+
static constexpr nsecs_t kInvalidTime = std::numeric_limits<int64_t>::max();
std::unique_ptr<TimeKeeper> const mTimeKeeper;
VsyncSchedule::TrackerPtr mTracker;
nsecs_t const mTimerSlack;
nsecs_t const mMinVsyncDistance;
- std::mutex mutable mMutex;
size_t mCallbackToken GUARDED_BY(mMutex) = 0;
CallbackMap mCallbacks GUARDED_BY(mMutex);
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
index 85f2e64..ae74205 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/FrameTargeter.h
@@ -20,6 +20,7 @@
#include <atomic>
#include <memory>
+#include <ui/DisplayId.h>
#include <ui/Fence.h>
#include <ui/FenceTime.h>
@@ -75,16 +76,17 @@
bool didMissHwcFrame() const { return mHwcFrameMissed && !mGpuFrameMissed; }
protected:
+ explicit FrameTarget(const std::string& displayLabel);
~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};
+ TracedOrdinal<bool> mFramePending;
+ TracedOrdinal<bool> mFrameMissed;
+ TracedOrdinal<bool> mHwcFrameMissed;
+ TracedOrdinal<bool> mGpuFrameMissed;
struct FenceWithFenceTime {
sp<Fence> fence = Fence::NO_FENCE;
@@ -103,8 +105,9 @@
// 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) {}
+ FrameTargeter(PhysicalDisplayId displayId, bool backpressureGpuComposition)
+ : FrameTarget(to_string(displayId)),
+ mBackpressureGpuComposition(backpressureGpuComposition) {}
const FrameTarget& target() const { return *this; }
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h
index f795f1f..87c704e 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositeResult.h
@@ -16,6 +16,9 @@
#pragma once
+#include <ui/DisplayId.h>
+#include <ui/DisplayMap.h>
+
#include <scheduler/interface/CompositionCoverage.h>
namespace android {
@@ -24,4 +27,6 @@
CompositionCoverageFlags compositionCoverage;
};
+using CompositeResultsPerDisplay = ui::PhysicalDisplayMap<PhysicalDisplayId, CompositeResult>;
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h
index 3d0f1a9..767462d 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/CompositionCoverage.h
@@ -19,6 +19,8 @@
#include <cstdint>
#include <ftl/flags.h>
+#include <ui/DisplayId.h>
+#include <ui/DisplayMap.h>
namespace android {
@@ -34,4 +36,14 @@
using CompositionCoverageFlags = ftl::Flags<CompositionCoverage>;
+using CompositionCoveragePerDisplay = ui::DisplayMap<DisplayId, CompositionCoverageFlags>;
+
+inline CompositionCoverageFlags multiDisplayUnion(const CompositionCoveragePerDisplay& displays) {
+ CompositionCoverageFlags coverage;
+ for (const auto& [id, flags] : displays) {
+ coverage |= flags;
+ }
+ return coverage;
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
index 2696076..6fe813a 100644
--- a/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
+++ b/services/surfaceflinger/Scheduler/include/scheduler/interface/ICompositor.h
@@ -16,6 +16,9 @@
#pragma once
+#include <ui/DisplayId.h>
+#include <ui/DisplayMap.h>
+
#include <scheduler/Time.h>
#include <scheduler/VsyncId.h>
#include <scheduler/interface/CompositeResult.h>
@@ -26,6 +29,8 @@
class FrameTarget;
class FrameTargeter;
+using FrameTargeters = ui::PhysicalDisplayMap<PhysicalDisplayId, scheduler::FrameTargeter*>;
+
} // namespace scheduler
struct ICompositor {
@@ -38,7 +43,8 @@
// Composites a frame for each display. CompositionEngine performs GPU and/or HAL composition
// via RenderEngine and the Composer HAL, respectively.
- virtual CompositeResult composite(scheduler::FrameTargeter&) = 0;
+ virtual CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId,
+ const scheduler::FrameTargeters&) = 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
index 7138afd..7a18654 100644
--- a/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp
+++ b/services/surfaceflinger/Scheduler/src/FrameTargeter.cpp
@@ -21,6 +21,12 @@
namespace android::scheduler {
+FrameTarget::FrameTarget(const std::string& displayLabel)
+ : mFramePending("PrevFramePending " + displayLabel, false),
+ mFrameMissed("PrevFrameMissed " + displayLabel, false),
+ mHwcFrameMissed("PrevHwcFrameMissed " + displayLabel, false),
+ mGpuFrameMissed("PrevGpuFrameMissed " + displayLabel, false) {}
+
TimePoint FrameTarget::pastVsyncTime(Period vsyncPeriod) const {
// TODO(b/267315508): Generalize to N VSYNCs.
const int shift = static_cast<int>(targetsVsyncsAhead<2>(vsyncPeriod));
@@ -130,10 +136,6 @@
}
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));
diff --git a/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp
index 908f214..1e038d1 100644
--- a/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp
+++ b/services/surfaceflinger/Scheduler/tests/FrameTargeterTest.cpp
@@ -96,7 +96,7 @@
FenceToFenceTimeMap mFenceMap;
static constexpr bool kBackpressureGpuComposition = true;
- FrameTargeter mTargeter{kBackpressureGpuComposition};
+ FrameTargeter mTargeter{PhysicalDisplayId::fromPort(13), kBackpressureGpuComposition};
};
TEST_F(FrameTargeterTest, targetsFrames) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 648409c..e339978 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2181,7 +2181,7 @@
}
}
-void SurfaceFlinger::configure() FTL_FAKE_GUARD(kMainThreadContext) {
+void SurfaceFlinger::configure() {
Mutex::Autolock lock(mStateLock);
if (configureLocked()) {
setTransactionFlags(eDisplayTransactionNeeded);
@@ -2401,8 +2401,7 @@
return mustComposite;
}
-bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget)
- FTL_FAKE_GUARD(kMainThreadContext) {
+bool SurfaceFlinger::commit(const scheduler::FrameTarget& pacesetterFrameTarget) {
const VsyncId vsyncId = pacesetterFrameTarget.vsyncId();
ATRACE_NAME(ftl::Concat(__func__, ' ', ftl::to_underlying(vsyncId)).c_str());
@@ -2523,7 +2522,9 @@
}
updateCursorAsync();
- updateInputFlinger(vsyncId, pacesetterFrameTarget.frameBeginTime());
+ if (!mustComposite) {
+ updateInputFlinger(vsyncId, pacesetterFrameTarget.frameBeginTime());
+ }
if (mLayerTracingEnabled && !mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
// This will block and tracing should only be enabled for debugging.
@@ -2536,31 +2537,42 @@
return mustComposite && CC_LIKELY(mBootStage != BootStage::BOOTLOADER);
}
-CompositeResult SurfaceFlinger::composite(scheduler::FrameTargeter& pacesetterFrameTargeter)
- FTL_FAKE_GUARD(kMainThreadContext) {
- const scheduler::FrameTarget& pacesetterFrameTarget = pacesetterFrameTargeter.target();
+CompositeResultsPerDisplay SurfaceFlinger::composite(
+ PhysicalDisplayId pacesetterId, const scheduler::FrameTargeters& frameTargeters) {
+ const scheduler::FrameTarget& pacesetterTarget =
+ frameTargeters.get(pacesetterId)->get()->target();
- const VsyncId vsyncId = pacesetterFrameTarget.vsyncId();
+ const VsyncId vsyncId = pacesetterTarget.vsyncId();
ATRACE_NAME(ftl::Concat(__func__, ' ', ftl::to_underlying(vsyncId)).c_str());
compositionengine::CompositionRefreshArgs refreshArgs;
refreshArgs.powerCallback = this;
const auto& displays = FTL_FAKE_GUARD(mStateLock, mDisplays);
refreshArgs.outputs.reserve(displays.size());
+
+ // Add outputs for physical displays.
+ for (const auto& [id, targeter] : frameTargeters) {
+ ftl::FakeGuard guard(mStateLock);
+
+ if (const auto display = getCompositionDisplayLocked(id)) {
+ refreshArgs.outputs.push_back(display);
+ }
+ }
+
std::vector<DisplayId> displayIds;
for (const auto& [_, display] : displays) {
displayIds.push_back(display->getId());
display->tracePowerMode();
+ // Add outputs for virtual displays.
if (display->isVirtual()) {
const Fps refreshRate = display->getAdjustedRefreshRate();
- if (refreshRate.isValid() &&
- !mScheduler->isVsyncInPhase(pacesetterFrameTarget.frameBeginTime(), refreshRate)) {
- continue;
+
+ if (!refreshRate.isValid() ||
+ mScheduler->isVsyncInPhase(pacesetterTarget.frameBeginTime(), refreshRate)) {
+ refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
}
-
- refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
mPowerAdvisor->setDisplays(displayIds);
@@ -2620,15 +2632,16 @@
if (!getHwComposer().getComposer()->isSupported(
Hwc2::Composer::OptionalFeature::ExpectedPresentTime) &&
- pacesetterFrameTarget.wouldPresentEarly(vsyncPeriod)) {
+ pacesetterTarget.wouldPresentEarly(vsyncPeriod)) {
const auto hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration;
+ // TODO(b/255601557): Calculate and pass per-display values for each FrameTarget.
refreshArgs.earliestPresentTime =
- pacesetterFrameTarget.previousFrameVsyncTime(vsyncPeriod) - hwcMinWorkDuration;
+ pacesetterTarget.previousFrameVsyncTime(vsyncPeriod) - hwcMinWorkDuration;
}
refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime();
- refreshArgs.expectedPresentTime = pacesetterFrameTarget.expectedPresentTime().ns();
+ refreshArgs.expectedPresentTime = pacesetterTarget.expectedPresentTime().ns();
refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0;
// Store the present time just before calling to the composition engine so we could notify
@@ -2654,14 +2667,14 @@
}
}
- mTimeStats->recordFrameDuration(pacesetterFrameTarget.frameBeginTime().ns(), systemTime());
+ mTimeStats->recordFrameDuration(pacesetterTarget.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 = pacesetterFrameTarget.presentFenceForPreviousFrame();
+ const auto& previousPresentFence = pacesetterTarget.presentFenceForPreviousFrame();
mPowerAdvisor->setSfPresentTiming(TimePoint::fromNs(previousPresentFence->getSignalTime()),
TimePoint::now());
@@ -2672,23 +2685,27 @@
scheduleComposite(FrameHint::kNone);
}
- postComposition(pacesetterFrameTargeter, presentTime);
+ postComposition(pacesetterId, frameTargeters, presentTime);
- const bool hadGpuComposited = mCompositionCoverage.test(CompositionCoverage::Gpu);
+ const bool hadGpuComposited =
+ multiDisplayUnion(mCompositionCoverage).test(CompositionCoverage::Gpu);
mCompositionCoverage.clear();
TimeStats::ClientCompositionRecord clientCompositionRecord;
+
for (const auto& [_, display] : displays) {
const auto& state = display->getCompositionDisplay()->getState();
+ CompositionCoverageFlags& flags =
+ mCompositionCoverage.try_emplace(display->getId()).first->second;
if (state.usesDeviceComposition) {
- mCompositionCoverage |= CompositionCoverage::Hwc;
+ flags |= CompositionCoverage::Hwc;
}
if (state.reusedClientComposition) {
- mCompositionCoverage |= CompositionCoverage::GpuReuse;
+ flags |= CompositionCoverage::GpuReuse;
} else if (state.usesClientComposition) {
- mCompositionCoverage |= CompositionCoverage::Gpu;
+ flags |= CompositionCoverage::Gpu;
}
clientCompositionRecord.predicted |=
@@ -2697,10 +2714,11 @@
(state.strategyPrediction == CompositionStrategyPredictionState::SUCCESS);
}
- const bool hasGpuComposited = mCompositionCoverage.test(CompositionCoverage::Gpu);
+ const auto coverage = multiDisplayUnion(mCompositionCoverage);
+ const bool hasGpuComposited = coverage.test(CompositionCoverage::Gpu);
clientCompositionRecord.hadClientComposition = hasGpuComposited;
- clientCompositionRecord.reused = mCompositionCoverage.test(CompositionCoverage::GpuReuse);
+ clientCompositionRecord.reused = coverage.test(CompositionCoverage::GpuReuse);
clientCompositionRecord.changed = hadGpuComposited != hasGpuComposited;
mTimeStats->pushCompositionStrategyState(clientCompositionRecord);
@@ -2709,15 +2727,17 @@
// TODO(b/160583065): Enable skip validation when SF caches all client composition layers.
const bool hasGpuUseOrReuse =
- mCompositionCoverage.any(CompositionCoverage::Gpu | CompositionCoverage::GpuReuse);
+ coverage.any(CompositionCoverage::Gpu | CompositionCoverage::GpuReuse);
mScheduler->modulateVsync({}, &VsyncModulator::onDisplayRefresh, hasGpuUseOrReuse);
mLayersWithQueuedFrames.clear();
if (mLayerTracingEnabled && mLayerTracing.flagIsSet(LayerTracing::TRACE_COMPOSITION)) {
// This will block and should only be used for debugging.
- addToLayerTracing(mVisibleRegionsDirty, pacesetterFrameTarget.frameBeginTime(), vsyncId);
+ addToLayerTracing(mVisibleRegionsDirty, pacesetterTarget.frameBeginTime(), vsyncId);
}
+ updateInputFlinger(vsyncId, pacesetterTarget.frameBeginTime());
+
if (mVisibleRegionsDirty) mHdrLayerInfoChanged = true;
mVisibleRegionsDirty = false;
@@ -2729,7 +2749,16 @@
mPowerAdvisor->setCompositeEnd(TimePoint::now());
}
- return {mCompositionCoverage};
+ CompositeResultsPerDisplay resultsPerDisplay;
+
+ // Filter out virtual displays.
+ for (const auto& [id, coverage] : mCompositionCoverage) {
+ if (const auto idOpt = PhysicalDisplayId::tryCast(id)) {
+ resultsPerDisplay.try_emplace(*idOpt, CompositeResult{coverage});
+ }
+ }
+
+ return resultsPerDisplay;
}
void SurfaceFlinger::updateLayerGeometry() {
@@ -2813,35 +2842,56 @@
return ui::ROTATION_0;
}
-void SurfaceFlinger::postComposition(scheduler::FrameTargeter& pacesetterFrameTargeter,
+void SurfaceFlinger::postComposition(PhysicalDisplayId pacesetterId,
+ const scheduler::FrameTargeters& frameTargeters,
nsecs_t presentStartTime) {
ATRACE_CALL();
ALOGV(__func__);
- const auto* defaultDisplay = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked()).get();
+ ui::PhysicalDisplayMap<PhysicalDisplayId, std::shared_ptr<FenceTime>> presentFences;
+ ui::PhysicalDisplayMap<PhysicalDisplayId, const sp<Fence>> gpuCompositionDoneFences;
- std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
- if (defaultDisplay &&
- defaultDisplay->getCompositionDisplay()->getState().usesClientComposition) {
- glCompositionDoneFenceTime =
- std::make_shared<FenceTime>(defaultDisplay->getCompositionDisplay()
- ->getRenderSurface()
- ->getClientTargetAcquireFence());
- } else {
- glCompositionDoneFenceTime = FenceTime::NO_FENCE;
+ for (const auto& [id, targeter] : frameTargeters) {
+ auto presentFence = getHwComposer().getPresentFence(id);
+
+ if (id == pacesetterId) {
+ mTransactionCallbackInvoker.addPresentFence(presentFence);
+ }
+
+ if (auto fenceTime = targeter->setPresentFence(std::move(presentFence));
+ fenceTime->isValid()) {
+ presentFences.try_emplace(id, std::move(fenceTime));
+ }
+
+ ftl::FakeGuard guard(mStateLock);
+ if (const auto display = getCompositionDisplayLocked(id);
+ display && display->getState().usesClientComposition) {
+ gpuCompositionDoneFences
+ .try_emplace(id, display->getRenderSurface()->getClientTargetAcquireFence());
+ }
}
- auto presentFence = defaultDisplay
- ? getHwComposer().getPresentFence(defaultDisplay->getPhysicalId())
- : Fence::NO_FENCE;
+ const auto pacesetterDisplay = FTL_FAKE_GUARD(mStateLock, getDisplayDeviceLocked(pacesetterId));
- auto presentFenceTime = pacesetterFrameTargeter.setPresentFence(presentFence);
+ std::shared_ptr<FenceTime> pacesetterPresentFenceTime =
+ presentFences.get(pacesetterId)
+ .transform([](const FenceTimePtr& ptr) { return ptr; })
+ .value_or(FenceTime::NO_FENCE);
+
+ std::shared_ptr<FenceTime> pacesetterGpuCompositionDoneFenceTime =
+ gpuCompositionDoneFences.get(pacesetterId)
+ .transform([](sp<Fence> fence) {
+ return std::make_shared<FenceTime>(std::move(fence));
+ })
+ .value_or(FenceTime::NO_FENCE);
+
const TimePoint presentTime = TimePoint::now();
// Set presentation information before calling Layer::releasePendingBuffer, such that jank
// information from previous' frame classification is already available when sending jank info
// to clients, so they get jank classification as early as possible.
- mFrameTimeline->setSfPresent(presentTime.ns(), presentFenceTime, glCompositionDoneFenceTime);
+ mFrameTimeline->setSfPresent(presentTime.ns(), pacesetterPresentFenceTime,
+ pacesetterGpuCompositionDoneFenceTime);
// We use the CompositionEngine::getLastFrameRefreshTimestamp() which might
// be sampled a little later than when we started doing work for this frame,
@@ -2849,9 +2899,9 @@
const TimePoint compositeTime =
TimePoint::fromNs(mCompositionEngine->getLastFrameRefreshTimestamp());
const Duration presentLatency =
- !getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)
- ? mPresentLatencyTracker.trackPendingFrame(compositeTime, presentFenceTime)
- : Duration::zero();
+ getHwComposer().hasCapability(Capability::PRESENT_FENCE_IS_NOT_RELIABLE)
+ ? Duration::zero()
+ : mPresentLatencyTracker.trackPendingFrame(compositeTime, pacesetterPresentFenceTime);
const auto schedule = mScheduler->getVsyncSchedule();
const TimePoint vsyncDeadline = schedule->vsyncDeadlineAfter(presentTime);
@@ -2888,8 +2938,8 @@
mLayersWithBuffersRemoved.clear();
for (const auto& layer: mLayersWithQueuedFrames) {
- layer->onPostComposition(defaultDisplay, glCompositionDoneFenceTime, presentFenceTime,
- compositorTiming);
+ layer->onPostComposition(pacesetterDisplay.get(), pacesetterGpuCompositionDoneFenceTime,
+ pacesetterPresentFenceTime, compositorTiming);
layer->releasePendingBuffer(presentTime.ns());
}
@@ -2976,38 +3026,32 @@
mHdrLayerInfoChanged = false;
- mTransactionCallbackInvoker.addPresentFence(std::move(presentFence));
mTransactionCallbackInvoker.sendCallbacks(false /* onCommitOnly */);
mTransactionCallbackInvoker.clearCompletedTransactions();
mTimeStats->incrementTotalFrames();
- mTimeStats->setPresentFenceGlobal(presentFenceTime);
+ mTimeStats->setPresentFenceGlobal(pacesetterPresentFenceTime);
- {
+ for (auto&& [id, presentFence] : presentFences) {
ftl::FakeGuard guard(mStateLock);
- for (const auto& [id, physicalDisplay] : mPhysicalDisplays) {
- if (auto displayDevice = getDisplayDeviceLocked(id);
- displayDevice && displayDevice->isPoweredOn() && physicalDisplay.isInternal()) {
- auto presentFenceTimeI = defaultDisplay && defaultDisplay->getPhysicalId() == id
- ? std::move(presentFenceTime)
- : std::make_shared<FenceTime>(getHwComposer().getPresentFence(id));
- if (presentFenceTimeI->isValid()) {
- mScheduler->addPresentFence(id, std::move(presentFenceTimeI));
- }
- }
+ const bool isInternalDisplay =
+ mPhysicalDisplays.get(id).transform(&PhysicalDisplay::isInternal).value_or(false);
+
+ if (isInternalDisplay) {
+ mScheduler->addPresentFence(id, std::move(presentFence));
}
}
- const bool isDisplayConnected =
- defaultDisplay && getHwComposer().isConnected(defaultDisplay->getPhysicalId());
+ const bool hasPacesetterDisplay =
+ pacesetterDisplay && getHwComposer().isConnected(pacesetterId);
if (!hasSyncFramework) {
- if (isDisplayConnected && defaultDisplay->isPoweredOn()) {
- mScheduler->enableHardwareVsync(defaultDisplay->getPhysicalId());
+ if (hasPacesetterDisplay && pacesetterDisplay->isPoweredOn()) {
+ mScheduler->enableHardwareVsync(pacesetterId);
}
}
- if (isDisplayConnected && !defaultDisplay->isPoweredOn()) {
+ if (hasPacesetterDisplay && !pacesetterDisplay->isPoweredOn()) {
getRenderEngine().cleanupPostRender();
return;
}
@@ -4294,7 +4338,7 @@
const auto& transaction = *flushState.transaction;
const TimePoint desiredPresentTime = TimePoint::fromNs(transaction.desiredPresentTime);
- const TimePoint expectedPresentTime = mScheduler->pacesetterFrameTarget().expectedPresentTime();
+ const TimePoint expectedPresentTime = mScheduler->expectedPresentTimeForPacesetter();
using TransactionReadiness = TransactionHandler::TransactionReadiness;
@@ -6343,8 +6387,7 @@
ftl::to_underlying(windowInfosDebug.maxSendDelayVsyncId));
StringAppendF(&result, " max send delay (ns): %" PRId64 " ns\n",
windowInfosDebug.maxSendDelayDuration);
- StringAppendF(&result, " unsent messages: %" PRIu32 "\n",
- windowInfosDebug.pendingMessageCount);
+ StringAppendF(&result, " unsent messages: %zu\n", windowInfosDebug.pendingMessageCount);
result.append("\n");
}
@@ -7625,7 +7668,10 @@
renderArea->getHintForSeamlessTransition());
sdrWhitePointNits = state.sdrWhitePointNits;
displayBrightnessNits = state.displayBrightnessNits;
- if (sdrWhitePointNits > 1.0f) {
+ // Only clamp the display brightness if this is not a seamless transition. Otherwise
+ // for seamless transitions it's important to match the current display state as the
+ // buffer will be shown under these same conditions, and we want to avoid any flickers
+ if (sdrWhitePointNits > 1.0f && !renderArea->getHintForSeamlessTransition()) {
// Restrict the amount of HDR "headroom" in the screenshot to avoid over-dimming
// the SDR portion. 2.0 chosen by experimentation
constexpr float kMaxScreenshotHeadroom = 2.0f;
@@ -7876,7 +7922,13 @@
return INVALID_OPERATION;
}
- setDesiredActiveMode({std::move(preferredMode), .emitEvent = true}, force);
+ setDesiredActiveMode({preferredMode, .emitEvent = true}, force);
+
+ // Update the frameRateOverride list as the display render rate might have changed
+ if (mScheduler->updateFrameRateOverrides(/*consideredSignals*/ {}, preferredMode.fps)) {
+ triggerOnFrameRateOverridesChanged();
+ }
+
return NO_ERROR;
}
@@ -8210,9 +8262,9 @@
forceApplyPolicy);
}
-status_t SurfaceFlinger::addWindowInfosListener(
- const sp<IWindowInfosListener>& windowInfosListener) {
- mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener);
+status_t SurfaceFlinger::addWindowInfosListener(const sp<IWindowInfosListener>& windowInfosListener,
+ gui::WindowInfosListenerInfo* outInfo) {
+ mWindowInfosListenerInvoker->addWindowInfosListener(windowInfosListener, outInfo);
setTransactionFlags(eInputInfoUpdateNeeded);
return NO_ERROR;
}
@@ -9296,7 +9348,8 @@
}
binder::Status SurfaceComposerAIDL::addWindowInfosListener(
- const sp<gui::IWindowInfosListener>& windowInfosListener) {
+ const sp<gui::IWindowInfosListener>& windowInfosListener,
+ gui::WindowInfosListenerInfo* outInfo) {
status_t status;
const int pid = IPCThreadState::self()->getCallingPid();
const int uid = IPCThreadState::self()->getCallingUid();
@@ -9304,7 +9357,7 @@
// WindowInfosListeners
if (uid == AID_SYSTEM || uid == AID_GRAPHICS ||
checkPermission(sAccessSurfaceFlinger, pid, uid)) {
- status = mFlinger->addWindowInfosListener(windowInfosListener);
+ status = mFlinger->addWindowInfosListener(windowInfosListener, outInfo);
} else {
status = PERMISSION_DENIED;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index aeaeb47..d1b6660 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -617,7 +617,8 @@
status_t getMaxAcquiredBufferCount(int* buffers) const;
- status_t addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
+ status_t addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener,
+ gui::WindowInfosListenerInfo* outResult);
status_t removeWindowInfosListener(
const sp<gui::IWindowInfosListener>& windowInfosListener) const;
@@ -636,9 +637,12 @@
void onRefreshRateChangedDebug(const RefreshRateChangedDebugData&) override;
// ICompositor overrides:
- void configure() override;
- bool commit(const scheduler::FrameTarget&) override;
- CompositeResult composite(scheduler::FrameTargeter&) override;
+ void configure() override REQUIRES(kMainThreadContext);
+ bool commit(const scheduler::FrameTarget&) override REQUIRES(kMainThreadContext);
+ CompositeResultsPerDisplay composite(PhysicalDisplayId pacesetterId,
+ const scheduler::FrameTargeters&) override
+ REQUIRES(kMainThreadContext);
+
void sample() override;
// ISchedulerCallback overrides:
@@ -891,6 +895,14 @@
return findDisplay([id](const auto& display) { return display.getId() == id; });
}
+ std::shared_ptr<compositionengine::Display> getCompositionDisplayLocked(DisplayId id) const
+ REQUIRES(mStateLock) {
+ if (const auto display = getDisplayDeviceLocked(id)) {
+ return display->getCompositionDisplay();
+ }
+ return nullptr;
+ }
+
// Returns the primary display or (for foldables) the active display, assuming that the inner
// and outer displays have mutually exclusive power states.
sp<const DisplayDevice> getDefaultDisplayDeviceLocked() const REQUIRES(mStateLock) {
@@ -964,8 +976,8 @@
/*
* Compositing
*/
- void postComposition(scheduler::FrameTargeter&, nsecs_t presentStartTime)
- REQUIRES(kMainThreadContext);
+ void postComposition(PhysicalDisplayId pacesetterId, const scheduler::FrameTargeters&,
+ nsecs_t presentStartTime) REQUIRES(kMainThreadContext);
/*
* Display management
@@ -1298,7 +1310,7 @@
std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
- CompositionCoverageFlags mCompositionCoverage;
+ CompositionCoveragePerDisplay mCompositionCoverage;
// mMaxRenderTargetSize is only set once in init() so it doesn't need to be protected by
// any mutex.
@@ -1541,8 +1553,8 @@
binder::Status setOverrideFrameRate(int32_t uid, float frameRate) override;
binder::Status getGpuContextPriority(int32_t* outPriority) override;
binder::Status getMaxAcquiredBufferCount(int32_t* buffers) override;
- binder::Status addWindowInfosListener(
- const sp<gui::IWindowInfosListener>& windowInfosListener) override;
+ binder::Status addWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener,
+ gui::WindowInfosListenerInfo* outInfo) override;
binder::Status removeWindowInfosListener(
const sp<gui::IWindowInfosListener>& windowInfosListener) override;
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.cpp b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
index 20699ef..7062a4e 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.cpp
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.cpp
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-#include <ftl/small_vector.h>
+#include <android/gui/BnWindowInfosPublisher.h>
+#include <android/gui/IWindowInfosPublisher.h>
+#include <android/gui/WindowInfosListenerInfo.h>
#include <gui/ISurfaceComposer.h>
#include <gui/TraceUtils.h>
#include <gui/WindowInfosUpdate.h>
@@ -23,162 +25,130 @@
#include "BackgroundExecutor.h"
#include "WindowInfosListenerInvoker.h"
+#undef ATRACE_TAG
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
namespace android {
using gui::DisplayInfo;
using gui::IWindowInfosListener;
using gui::WindowInfo;
-using WindowInfosListenerVector = ftl::SmallVector<const sp<gui::IWindowInfosListener>, 3>;
+void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener,
+ gui::WindowInfosListenerInfo* outInfo) {
+ int64_t listenerId = mNextListenerId++;
+ outInfo->listenerId = listenerId;
+ outInfo->windowInfosPublisher = sp<gui::IWindowInfosPublisher>::fromExisting(this);
-struct WindowInfosReportedListenerInvoker : gui::BnWindowInfosReportedListener,
- IBinder::DeathRecipient {
- WindowInfosReportedListenerInvoker(WindowInfosListenerVector windowInfosListeners,
- WindowInfosReportedListenerSet windowInfosReportedListeners)
- : mCallbacksPending(windowInfosListeners.size()),
- mWindowInfosListeners(std::move(windowInfosListeners)),
- mWindowInfosReportedListeners(std::move(windowInfosReportedListeners)) {}
-
- binder::Status onWindowInfosReported() override {
- if (--mCallbacksPending == 0) {
- for (const auto& listener : mWindowInfosReportedListeners) {
+ BackgroundExecutor::getInstance().sendCallbacks(
+ {[this, listener = std::move(listener), listenerId]() {
+ ATRACE_NAME("WindowInfosListenerInvoker::addWindowInfosListener");
sp<IBinder> asBinder = IInterface::asBinder(listener);
- if (asBinder->isBinderAlive()) {
- listener->onWindowInfosReported();
- }
- }
-
- auto wpThis = wp<WindowInfosReportedListenerInvoker>::fromExisting(this);
- for (const auto& listener : mWindowInfosListeners) {
- sp<IBinder> binder = IInterface::asBinder(listener);
- binder->unlinkToDeath(wpThis);
- }
- }
- return binder::Status::ok();
- }
-
- void binderDied(const wp<IBinder>&) { onWindowInfosReported(); }
-
-private:
- std::atomic<size_t> mCallbacksPending;
- static constexpr size_t kStaticCapacity = 3;
- const WindowInfosListenerVector mWindowInfosListeners;
- WindowInfosReportedListenerSet mWindowInfosReportedListeners;
-};
-
-void WindowInfosListenerInvoker::addWindowInfosListener(sp<IWindowInfosListener> listener) {
- sp<IBinder> asBinder = IInterface::asBinder(listener);
- asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
-
- std::scoped_lock lock(mListenersMutex);
- mWindowInfosListeners.try_emplace(asBinder, std::move(listener));
+ asBinder->linkToDeath(sp<DeathRecipient>::fromExisting(this));
+ mWindowInfosListeners.try_emplace(asBinder,
+ std::make_pair(listenerId, std::move(listener)));
+ }});
}
void WindowInfosListenerInvoker::removeWindowInfosListener(
const sp<IWindowInfosListener>& listener) {
- sp<IBinder> asBinder = IInterface::asBinder(listener);
-
- std::scoped_lock lock(mListenersMutex);
- asBinder->unlinkToDeath(sp<DeathRecipient>::fromExisting(this));
- mWindowInfosListeners.erase(asBinder);
+ BackgroundExecutor::getInstance().sendCallbacks({[this, listener]() {
+ ATRACE_NAME("WindowInfosListenerInvoker::removeWindowInfosListener");
+ sp<IBinder> asBinder = IInterface::asBinder(listener);
+ asBinder->unlinkToDeath(sp<DeathRecipient>::fromExisting(this));
+ mWindowInfosListeners.erase(asBinder);
+ }});
}
void WindowInfosListenerInvoker::binderDied(const wp<IBinder>& who) {
- std::scoped_lock lock(mListenersMutex);
- mWindowInfosListeners.erase(who);
+ BackgroundExecutor::getInstance().sendCallbacks({[this, who]() {
+ ATRACE_NAME("WindowInfosListenerInvoker::binderDied");
+ auto it = mWindowInfosListeners.find(who);
+ int64_t listenerId = it->second.first;
+ mWindowInfosListeners.erase(who);
+
+ std::vector<int64_t> vsyncIds;
+ for (auto& [vsyncId, state] : mUnackedState) {
+ if (std::find(state.unackedListenerIds.begin(), state.unackedListenerIds.end(),
+ listenerId) != state.unackedListenerIds.end()) {
+ vsyncIds.push_back(vsyncId);
+ }
+ }
+
+ for (int64_t vsyncId : vsyncIds) {
+ ackWindowInfosReceived(vsyncId, listenerId);
+ }
+ }});
}
void WindowInfosListenerInvoker::windowInfosChanged(
gui::WindowInfosUpdate update, WindowInfosReportedListenerSet reportedListeners,
bool forceImmediateCall) {
- WindowInfosListenerVector listeners;
- {
- std::scoped_lock lock{mMessagesMutex};
+ if (!mDelayInfo) {
+ mDelayInfo = DelayInfo{
+ .vsyncId = update.vsyncId,
+ .frameTime = update.timestamp,
+ };
+ }
- if (!mDelayInfo) {
- mDelayInfo = DelayInfo{
- .vsyncId = update.vsyncId,
- .frameTime = update.timestamp,
- };
- }
+ // If there are unacked messages and this isn't a forced call, then return immediately.
+ // If a forced window infos change doesn't happen first, the update will be sent after
+ // the WindowInfosReportedListeners are called. If a forced window infos change happens or
+ // if there are subsequent delayed messages before this update is sent, then this message
+ // will be dropped and the listeners will only be called with the latest info. This is done
+ // to reduce the amount of binder memory used.
+ if (!mUnackedState.empty() && !forceImmediateCall) {
+ mDelayedUpdate = std::move(update);
+ mReportedListeners.merge(reportedListeners);
+ return;
+ }
- // If there are unacked messages and this isn't a forced call, then return immediately.
- // If a forced window infos change doesn't happen first, the update will be sent after
- // the WindowInfosReportedListeners are called. If a forced window infos change happens or
- // if there are subsequent delayed messages before this update is sent, then this message
- // will be dropped and the listeners will only be called with the latest info. This is done
- // to reduce the amount of binder memory used.
- if (mActiveMessageCount > 0 && !forceImmediateCall) {
- mDelayedUpdate = std::move(update);
- mReportedListeners.merge(reportedListeners);
- return;
- }
+ if (mDelayedUpdate) {
+ mDelayedUpdate.reset();
+ }
- if (mDelayedUpdate) {
- mDelayedUpdate.reset();
- }
-
- {
- std::scoped_lock lock{mListenersMutex};
- for (const auto& [_, listener] : mWindowInfosListeners) {
- listeners.push_back(listener);
- }
- }
- if (CC_UNLIKELY(listeners.empty())) {
- mReportedListeners.merge(reportedListeners);
- mDelayInfo.reset();
- return;
- }
-
- reportedListeners.insert(sp<WindowInfosListenerInvoker>::fromExisting(this));
- reportedListeners.merge(mReportedListeners);
- mReportedListeners.clear();
-
- mActiveMessageCount++;
- updateMaxSendDelay();
+ if (CC_UNLIKELY(mWindowInfosListeners.empty())) {
+ mReportedListeners.merge(reportedListeners);
mDelayInfo.reset();
+ return;
}
- auto reportedInvoker =
- sp<WindowInfosReportedListenerInvoker>::make(listeners, std::move(reportedListeners));
+ reportedListeners.merge(mReportedListeners);
+ mReportedListeners.clear();
- for (const auto& listener : listeners) {
- sp<IBinder> asBinder = IInterface::asBinder(listener);
+ // Update mUnackedState to include the message we're about to send
+ auto [it, _] = mUnackedState.try_emplace(update.vsyncId,
+ UnackedState{.reportedListeners =
+ std::move(reportedListeners)});
+ auto& unackedState = it->second;
+ for (auto& pair : mWindowInfosListeners) {
+ int64_t listenerId = pair.second.first;
+ unackedState.unackedListenerIds.push_back(listenerId);
+ }
- // linkToDeath is used here to ensure that the windowInfosReportedListeners
- // are called even if one of the windowInfosListeners dies before
- // calling onWindowInfosReported.
- asBinder->linkToDeath(reportedInvoker);
+ mDelayInfo.reset();
+ updateMaxSendDelay();
- auto status = listener->onWindowInfosChanged(update, reportedInvoker);
+ // Call the listeners
+ for (auto& pair : mWindowInfosListeners) {
+ auto& [listenerId, listener] = pair.second;
+ auto status = listener->onWindowInfosChanged(update);
if (!status.isOk()) {
- reportedInvoker->onWindowInfosReported();
+ ackWindowInfosReceived(update.vsyncId, listenerId);
}
}
}
-binder::Status WindowInfosListenerInvoker::onWindowInfosReported() {
- BackgroundExecutor::getInstance().sendCallbacks({[this]() {
- gui::WindowInfosUpdate update;
- {
- std::scoped_lock lock{mMessagesMutex};
- mActiveMessageCount--;
- if (!mDelayedUpdate || mActiveMessageCount > 0) {
- return;
- }
- update = std::move(*mDelayedUpdate);
- mDelayedUpdate.reset();
- }
- windowInfosChanged(std::move(update), {}, false);
- }});
- return binder::Status::ok();
-}
-
WindowInfosListenerInvoker::DebugInfo WindowInfosListenerInvoker::getDebugInfo() {
- std::scoped_lock lock{mMessagesMutex};
- updateMaxSendDelay();
- mDebugInfo.pendingMessageCount = mActiveMessageCount;
- return mDebugInfo;
+ DebugInfo result;
+ BackgroundExecutor::getInstance().sendCallbacks({[&, this]() {
+ ATRACE_NAME("WindowInfosListenerInvoker::getDebugInfo");
+ updateMaxSendDelay();
+ result = mDebugInfo;
+ result.pendingMessageCount = mUnackedState.size();
+ }});
+ BackgroundExecutor::getInstance().flushQueue();
+ return result;
}
void WindowInfosListenerInvoker::updateMaxSendDelay() {
@@ -192,4 +162,41 @@
}
}
+binder::Status WindowInfosListenerInvoker::ackWindowInfosReceived(int64_t vsyncId,
+ int64_t listenerId) {
+ BackgroundExecutor::getInstance().sendCallbacks({[this, vsyncId, listenerId]() {
+ ATRACE_NAME("WindowInfosListenerInvoker::ackWindowInfosReceived");
+ auto it = mUnackedState.find(vsyncId);
+ if (it == mUnackedState.end()) {
+ return;
+ }
+
+ auto& state = it->second;
+ state.unackedListenerIds.unstable_erase(std::find(state.unackedListenerIds.begin(),
+ state.unackedListenerIds.end(),
+ listenerId));
+ if (!state.unackedListenerIds.empty()) {
+ return;
+ }
+
+ WindowInfosReportedListenerSet reportedListeners{std::move(state.reportedListeners)};
+ mUnackedState.erase(vsyncId);
+
+ for (const auto& reportedListener : reportedListeners) {
+ sp<IBinder> asBinder = IInterface::asBinder(reportedListener);
+ if (asBinder->isBinderAlive()) {
+ reportedListener->onWindowInfosReported();
+ }
+ }
+
+ if (!mDelayedUpdate || !mUnackedState.empty()) {
+ return;
+ }
+ gui::WindowInfosUpdate update{std::move(*mDelayedUpdate)};
+ mDelayedUpdate.reset();
+ windowInfosChanged(std::move(update), {}, false);
+ }});
+ return binder::Status::ok();
+}
+
} // namespace android
diff --git a/services/surfaceflinger/WindowInfosListenerInvoker.h b/services/surfaceflinger/WindowInfosListenerInvoker.h
index bc465a3..f36b0ed 100644
--- a/services/surfaceflinger/WindowInfosListenerInvoker.h
+++ b/services/surfaceflinger/WindowInfosListenerInvoker.h
@@ -19,11 +19,12 @@
#include <optional>
#include <unordered_set>
-#include <android/gui/BnWindowInfosReportedListener.h>
+#include <android/gui/BnWindowInfosPublisher.h>
#include <android/gui/IWindowInfosListener.h>
#include <android/gui/IWindowInfosReportedListener.h>
#include <binder/IBinder.h>
#include <ftl/small_map.h>
+#include <ftl/small_vector.h>
#include <gui/SpHash.h>
#include <utils/Mutex.h>
@@ -35,22 +36,22 @@
std::unordered_set<sp<gui::IWindowInfosReportedListener>,
gui::SpHash<gui::IWindowInfosReportedListener>>;
-class WindowInfosListenerInvoker : public gui::BnWindowInfosReportedListener,
+class WindowInfosListenerInvoker : public gui::BnWindowInfosPublisher,
public IBinder::DeathRecipient {
public:
- void addWindowInfosListener(sp<gui::IWindowInfosListener>);
+ void addWindowInfosListener(sp<gui::IWindowInfosListener>, gui::WindowInfosListenerInfo*);
void removeWindowInfosListener(const sp<gui::IWindowInfosListener>& windowInfosListener);
void windowInfosChanged(gui::WindowInfosUpdate update,
WindowInfosReportedListenerSet windowInfosReportedListeners,
bool forceImmediateCall);
- binder::Status onWindowInfosReported() override;
+ binder::Status ackWindowInfosReceived(int64_t, int64_t) override;
struct DebugInfo {
VsyncId maxSendDelayVsyncId;
nsecs_t maxSendDelayDuration;
- uint32_t pendingMessageCount;
+ size_t pendingMessageCount;
};
DebugInfo getDebugInfo();
@@ -58,24 +59,28 @@
void binderDied(const wp<IBinder>& who) override;
private:
- std::mutex mListenersMutex;
-
static constexpr size_t kStaticCapacity = 3;
- ftl::SmallMap<wp<IBinder>, const sp<gui::IWindowInfosListener>, kStaticCapacity>
- mWindowInfosListeners GUARDED_BY(mListenersMutex);
+ std::atomic<int64_t> mNextListenerId{0};
+ ftl::SmallMap<wp<IBinder>, const std::pair<int64_t, sp<gui::IWindowInfosListener>>,
+ kStaticCapacity>
+ mWindowInfosListeners;
- std::mutex mMessagesMutex;
- uint32_t mActiveMessageCount GUARDED_BY(mMessagesMutex) = 0;
- std::optional<gui::WindowInfosUpdate> mDelayedUpdate GUARDED_BY(mMessagesMutex);
+ std::optional<gui::WindowInfosUpdate> mDelayedUpdate;
WindowInfosReportedListenerSet mReportedListeners;
- DebugInfo mDebugInfo GUARDED_BY(mMessagesMutex);
+ struct UnackedState {
+ ftl::SmallVector<int64_t, kStaticCapacity> unackedListenerIds;
+ WindowInfosReportedListenerSet reportedListeners;
+ };
+ ftl::SmallMap<int64_t /* vsyncId */, UnackedState, 5> mUnackedState;
+
+ DebugInfo mDebugInfo;
struct DelayInfo {
int64_t vsyncId;
nsecs_t frameTime;
};
- std::optional<DelayInfo> mDelayInfo GUARDED_BY(mMessagesMutex);
- void updateMaxSendDelay() REQUIRES(mMessagesMutex);
+ std::optional<DelayInfo> mDelayInfo;
+ void updateMaxSendDelay();
};
} // namespace android
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 00e92a1..28ac664 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -287,7 +287,10 @@
// ICompositor overrides:
void configure() override {}
bool commit(const scheduler::FrameTarget&) override { return false; }
- CompositeResult composite(scheduler::FrameTargeter&) override { return {}; }
+ CompositeResultsPerDisplay composite(PhysicalDisplayId,
+ const scheduler::FrameTargeters&) override {
+ return {};
+ }
void sample() override {}
// MessageQueue overrides:
@@ -474,25 +477,25 @@
&outWideColorGamutPixelFormat);
}
- void overrideHdrTypes(sp<IBinder> &display, FuzzedDataProvider *fdp) {
+ void overrideHdrTypes(const sp<IBinder>& display, FuzzedDataProvider* fdp) {
std::vector<ui::Hdr> hdrTypes;
hdrTypes.push_back(fdp->PickValueInArray(kHdrTypes));
mFlinger->overrideHdrTypes(display, hdrTypes);
}
- void getDisplayedContentSample(sp<IBinder> &display, FuzzedDataProvider *fdp) {
+ void getDisplayedContentSample(const sp<IBinder>& display, FuzzedDataProvider* fdp) {
DisplayedFrameStats outDisplayedFrameStats;
mFlinger->getDisplayedContentSample(display, fdp->ConsumeIntegral<uint64_t>(),
fdp->ConsumeIntegral<uint64_t>(),
&outDisplayedFrameStats);
}
- void getDisplayStats(sp<IBinder> &display) {
+ void getDisplayStats(const sp<IBinder>& display) {
android::DisplayStatInfo stats;
mFlinger->getDisplayStats(display, &stats);
}
- void getDisplayState(sp<IBinder> &display) {
+ void getDisplayState(const sp<IBinder>& display) {
ui::DisplayState displayState;
mFlinger->getDisplayState(display, &displayState);
}
@@ -506,12 +509,12 @@
android::ui::DynamicDisplayInfo dynamicDisplayInfo;
mFlinger->getDynamicDisplayInfoFromId(displayId, &dynamicDisplayInfo);
}
- void getDisplayNativePrimaries(sp<IBinder> &display) {
+ void getDisplayNativePrimaries(const sp<IBinder>& display) {
android::ui::DisplayPrimaries displayPrimaries;
mFlinger->getDisplayNativePrimaries(display, displayPrimaries);
}
- void getDesiredDisplayModeSpecs(sp<IBinder> &display) {
+ void getDesiredDisplayModeSpecs(const sp<IBinder>& display) {
gui::DisplayModeSpecs _;
mFlinger->getDesiredDisplayModeSpecs(display, &_);
}
@@ -523,7 +526,7 @@
return ids.front();
}
- std::pair<sp<IBinder>, int64_t> fuzzBoot(FuzzedDataProvider *fdp) {
+ std::pair<sp<IBinder>, PhysicalDisplayId> fuzzBoot(FuzzedDataProvider* fdp) {
mFlinger->callingThreadHasUnscopedSurfaceFlingerAccess(fdp->ConsumeBool());
const sp<Client> client = sp<Client>::make(mFlinger);
@@ -550,13 +553,13 @@
mFlinger->bootFinished();
- return {display, physicalDisplayId.value};
+ return {display, physicalDisplayId};
}
void fuzzSurfaceFlinger(const uint8_t *data, size_t size) {
FuzzedDataProvider mFdp(data, size);
- auto [display, displayId] = fuzzBoot(&mFdp);
+ const auto [display, displayId] = fuzzBoot(&mFdp);
sp<IGraphicBufferProducer> bufferProducer = sp<mock::GraphicBufferProducer>::make();
@@ -564,8 +567,8 @@
getDisplayStats(display);
getDisplayState(display);
- getStaticDisplayInfo(displayId);
- getDynamicDisplayInfo(displayId);
+ getStaticDisplayInfo(displayId.value);
+ getDynamicDisplayInfo(displayId.value);
getDisplayNativePrimaries(display);
mFlinger->setAutoLowLatencyMode(display, mFdp.ConsumeBool());
@@ -605,8 +608,9 @@
mFlinger->commitTransactions();
mFlinger->flushTransactionQueues(getFuzzedVsyncId(mFdp));
- scheduler::FrameTargeter frameTargeter(mFdp.ConsumeBool());
- mFlinger->postComposition(frameTargeter, mFdp.ConsumeIntegral<nsecs_t>());
+ scheduler::FrameTargeter frameTargeter(displayId, mFdp.ConsumeBool());
+ mFlinger->postComposition(displayId, ftl::init::map(displayId, &frameTargeter),
+ mFdp.ConsumeIntegral<nsecs_t>());
}
mFlinger->setTransactionFlags(mFdp.ConsumeIntegral<uint32_t>());
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index b1fd06f..4d1a5ff 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -50,7 +50,7 @@
constexpr uint16_t kRandomStringLength = 256;
constexpr std::chrono::duration kSyncPeriod(16ms);
-constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u);
+constexpr PhysicalDisplayId kDisplayId = PhysicalDisplayId::fromPort(42u);
template <typename T>
void dump(T* component, FuzzedDataProvider* fdp) {
@@ -177,9 +177,8 @@
uint16_t now = mFdp.ConsumeIntegral<uint16_t>();
uint16_t historySize = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX);
uint16_t minimumSamplesForPrediction = mFdp.ConsumeIntegralInRange<uint16_t>(1, UINT16_MAX);
- scheduler::VSyncPredictor tracker{DEFAULT_DISPLAY_ID,
- mFdp.ConsumeIntegral<uint16_t>() /*period*/, historySize,
- minimumSamplesForPrediction,
+ scheduler::VSyncPredictor tracker{kDisplayId, mFdp.ConsumeIntegral<uint16_t>() /*period*/,
+ historySize, minimumSamplesForPrediction,
mFdp.ConsumeIntegral<uint32_t>() /*outlierTolerancePercent*/};
uint16_t period = mFdp.ConsumeIntegral<uint16_t>();
tracker.setPeriod(period);
@@ -251,7 +250,7 @@
void SchedulerFuzzer::fuzzVSyncReactor() {
std::shared_ptr<FuzzImplVSyncTracker> vSyncTracker = std::make_shared<FuzzImplVSyncTracker>();
- scheduler::VSyncReactor reactor(DEFAULT_DISPLAY_ID,
+ scheduler::VSyncReactor reactor(kDisplayId,
std::make_unique<ClockWrapper>(
std::make_shared<FuzzImplClock>()),
*vSyncTracker, mFdp.ConsumeIntegral<uint8_t>() /*pendingLimit*/,
@@ -408,7 +407,7 @@
}
void SchedulerFuzzer::fuzzFrameTargeter() {
- scheduler::FrameTargeter frameTargeter(mFdp.ConsumeBool());
+ scheduler::FrameTargeter frameTargeter(kDisplayId, mFdp.ConsumeBool());
const struct VsyncSource final : scheduler::IVsyncSource {
explicit VsyncSource(FuzzedDataProvider& fuzzer) : fuzzer(fuzzer) {}
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index da00377..ec8069d 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -53,6 +53,7 @@
using Hwc2::Config;
using ::aidl::android::hardware::graphics::composer3::RefreshRateChangedDebugData;
+using hal::IComposerClient;
using ::testing::_;
using ::testing::DoAll;
using ::testing::ElementsAreArray;
@@ -119,6 +120,155 @@
}
}
+TEST_F(HWComposerTest, getModesWithLegacyDisplayConfigs) {
+ constexpr hal::HWDisplayId kHwcDisplayId = 2;
+ constexpr hal::HWConfigId kConfigId = 42;
+
+ expectHotplugConnect(kHwcDisplayId);
+ const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED);
+ ASSERT_TRUE(info);
+
+ EXPECT_CALL(*mHal, getDisplayConfigurationsSupported()).WillRepeatedly(Return(false));
+
+ {
+ EXPECT_CALL(*mHal, getDisplayConfigs(kHwcDisplayId, _))
+ .WillOnce(Return(HalError::BAD_DISPLAY));
+ EXPECT_TRUE(mHwc.getModes(info->id).empty());
+ }
+ {
+ constexpr int32_t kWidth = 480;
+ constexpr int32_t kHeight = 720;
+ constexpr int32_t kConfigGroup = 1;
+ constexpr int32_t kVsyncPeriod = 16666667;
+
+ EXPECT_CALL(*mHal,
+ getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::WIDTH,
+ _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(kWidth), Return(HalError::NONE)));
+ EXPECT_CALL(*mHal,
+ getDisplayAttribute(kHwcDisplayId, kConfigId,
+ IComposerClient::Attribute::HEIGHT, _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(kHeight), Return(HalError::NONE)));
+ EXPECT_CALL(*mHal,
+ getDisplayAttribute(kHwcDisplayId, kConfigId,
+ IComposerClient::Attribute::CONFIG_GROUP, _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(kConfigGroup), Return(HalError::NONE)));
+ EXPECT_CALL(*mHal,
+ getDisplayAttribute(kHwcDisplayId, kConfigId,
+ IComposerClient::Attribute::VSYNC_PERIOD, _))
+ .WillRepeatedly(DoAll(SetArgPointee<3>(kVsyncPeriod), Return(HalError::NONE)));
+
+ // Optional Parameters UNSUPPORTED
+ EXPECT_CALL(*mHal,
+ getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::DPI_X,
+ _))
+ .WillOnce(Return(HalError::UNSUPPORTED));
+ EXPECT_CALL(*mHal,
+ getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::DPI_Y,
+ _))
+ .WillOnce(Return(HalError::UNSUPPORTED));
+
+ EXPECT_CALL(*mHal, getDisplayConfigs(kHwcDisplayId, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(std::vector<hal::HWConfigId>{kConfigId}),
+ Return(HalError::NONE)));
+
+ auto modes = mHwc.getModes(info->id);
+ EXPECT_EQ(modes.size(), size_t{1});
+ EXPECT_EQ(modes.front().hwcId, kConfigId);
+ EXPECT_EQ(modes.front().width, kWidth);
+ EXPECT_EQ(modes.front().height, kHeight);
+ EXPECT_EQ(modes.front().configGroup, kConfigGroup);
+ EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod);
+ EXPECT_EQ(modes.front().dpiX, -1);
+ EXPECT_EQ(modes.front().dpiY, -1);
+
+ // Optional parameters are supported
+ constexpr int32_t kDpi = 320;
+ EXPECT_CALL(*mHal,
+ getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::DPI_X,
+ _))
+ .WillOnce(DoAll(SetArgPointee<3>(kDpi), Return(HalError::NONE)));
+ EXPECT_CALL(*mHal,
+ getDisplayAttribute(kHwcDisplayId, kConfigId, IComposerClient::Attribute::DPI_Y,
+ _))
+ .WillOnce(DoAll(SetArgPointee<3>(kDpi), Return(HalError::NONE)));
+
+ modes = mHwc.getModes(info->id);
+ EXPECT_EQ(modes.size(), size_t{1});
+ EXPECT_EQ(modes.front().hwcId, kConfigId);
+ EXPECT_EQ(modes.front().width, kWidth);
+ EXPECT_EQ(modes.front().height, kHeight);
+ EXPECT_EQ(modes.front().configGroup, kConfigGroup);
+ EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod);
+ // DPI values are scaled by 1000 in the legacy implementation.
+ EXPECT_EQ(modes.front().dpiX, kDpi / 1000.f);
+ EXPECT_EQ(modes.front().dpiY, kDpi / 1000.f);
+ }
+}
+
+TEST_F(HWComposerTest, getModesWithDisplayConfigurations) {
+ constexpr hal::HWDisplayId kHwcDisplayId = 2;
+ constexpr hal::HWConfigId kConfigId = 42;
+ expectHotplugConnect(kHwcDisplayId);
+ const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED);
+ ASSERT_TRUE(info);
+
+ EXPECT_CALL(*mHal, getDisplayConfigurationsSupported()).WillRepeatedly(Return(true));
+
+ {
+ EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _))
+ .WillOnce(Return(HalError::BAD_DISPLAY));
+ EXPECT_TRUE(mHwc.getModes(info->id).empty());
+ }
+ {
+ constexpr int32_t kWidth = 480;
+ constexpr int32_t kHeight = 720;
+ constexpr int32_t kConfigGroup = 1;
+ constexpr int32_t kVsyncPeriod = 16666667;
+ hal::DisplayConfiguration displayConfiguration;
+ displayConfiguration.configId = kConfigId;
+ displayConfiguration.configGroup = kConfigGroup;
+ displayConfiguration.height = kHeight;
+ displayConfiguration.width = kWidth;
+ displayConfiguration.vsyncPeriod = kVsyncPeriod;
+
+ EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<hal::DisplayConfiguration>{
+ displayConfiguration}),
+ Return(HalError::NONE)));
+
+ // Optional dpi not supported
+ auto modes = mHwc.getModes(info->id);
+ EXPECT_EQ(modes.size(), size_t{1});
+ EXPECT_EQ(modes.front().hwcId, kConfigId);
+ EXPECT_EQ(modes.front().width, kWidth);
+ EXPECT_EQ(modes.front().height, kHeight);
+ EXPECT_EQ(modes.front().configGroup, kConfigGroup);
+ EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod);
+ EXPECT_EQ(modes.front().dpiX, -1);
+ EXPECT_EQ(modes.front().dpiY, -1);
+
+ // Supports optional dpi parameter
+ constexpr int32_t kDpi = 320;
+ displayConfiguration.dpi = {kDpi, kDpi};
+
+ EXPECT_CALL(*mHal, getDisplayConfigurations(kHwcDisplayId, _))
+ .WillOnce(DoAll(SetArgPointee<1>(std::vector<hal::DisplayConfiguration>{
+ displayConfiguration}),
+ Return(HalError::NONE)));
+
+ modes = mHwc.getModes(info->id);
+ EXPECT_EQ(modes.size(), size_t{1});
+ EXPECT_EQ(modes.front().hwcId, kConfigId);
+ EXPECT_EQ(modes.front().width, kWidth);
+ EXPECT_EQ(modes.front().height, kHeight);
+ EXPECT_EQ(modes.front().configGroup, kConfigGroup);
+ EXPECT_EQ(modes.front().vsyncPeriod, kVsyncPeriod);
+ EXPECT_EQ(modes.front().dpiX, kDpi);
+ EXPECT_EQ(modes.front().dpiY, kDpi);
+ }
+}
+
TEST_F(HWComposerTest, onVsync) {
constexpr hal::HWDisplayId kHwcDisplayId = 1;
expectHotplugConnect(kHwcDisplayId);
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index 359e2ab..1dcf222 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -36,7 +36,10 @@
struct NoOpCompositor final : ICompositor {
void configure() override {}
bool commit(const scheduler::FrameTarget&) override { return false; }
- CompositeResult composite(scheduler::FrameTargeter&) override { return {}; }
+ CompositeResultsPerDisplay composite(PhysicalDisplayId,
+ const scheduler::FrameTargeters&) override {
+ return {};
+ }
void sample() override {}
} gNoOpCompositor;
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index fa7a947..f3c9d0d 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -181,7 +181,10 @@
// ICompositor overrides:
void configure() override {}
bool commit(const scheduler::FrameTarget&) override { return false; }
- CompositeResult composite(scheduler::FrameTargeter&) override { return {}; }
+ CompositeResultsPerDisplay composite(PhysicalDisplayId,
+ const scheduler::FrameTargeters&) override {
+ return {};
+ }
void sample() override {}
};
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 909b8b8..9b3a893 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -359,7 +359,10 @@
* Forwarding for functions being tested
*/
- void configure() { mFlinger->configure(); }
+ void configure() {
+ ftl::FakeGuard guard(kMainThreadContext);
+ mFlinger->configure();
+ }
void configureAndCommit() {
configure();
@@ -368,8 +371,14 @@
void commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime,
bool composite = false) {
+ ftl::FakeGuard guard(kMainThreadContext);
+
+ const auto displayIdOpt = mScheduler->pacesetterDisplayId();
+ LOG_ALWAYS_FATAL_IF(!displayIdOpt);
+ const auto displayId = *displayIdOpt;
+
constexpr bool kBackpressureGpuComposition = true;
- scheduler::FrameTargeter frameTargeter(kBackpressureGpuComposition);
+ scheduler::FrameTargeter frameTargeter(displayId, kBackpressureGpuComposition);
frameTargeter.beginFrame({.frameBeginTime = frameTime,
.vsyncId = vsyncId,
@@ -380,7 +389,7 @@
mFlinger->commit(frameTargeter.target());
if (composite) {
- mFlinger->composite(frameTargeter);
+ mFlinger->composite(displayId, ftl::init::map(displayId, &frameTargeter));
}
}
diff --git a/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp
index af4971b..c7b845e 100644
--- a/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/WindowInfosListenerInvokerTest.cpp
@@ -15,35 +15,23 @@
WindowInfosListenerInvokerTest() : mInvoker(sp<WindowInfosListenerInvoker>::make()) {}
~WindowInfosListenerInvokerTest() {
- std::mutex mutex;
- std::condition_variable cv;
- bool flushComplete = false;
// Flush the BackgroundExecutor thread to ensure any scheduled tasks are complete.
// Otherwise, references those tasks hold may go out of scope before they are done
// executing.
- BackgroundExecutor::getInstance().sendCallbacks({[&]() {
- std::scoped_lock lock{mutex};
- flushComplete = true;
- cv.notify_one();
- }});
- std::unique_lock<std::mutex> lock{mutex};
- cv.wait(lock, [&]() { return flushComplete; });
+ BackgroundExecutor::getInstance().flushQueue();
}
sp<WindowInfosListenerInvoker> mInvoker;
};
-using WindowInfosUpdateConsumer = std::function<void(const gui::WindowInfosUpdate&,
- const sp<gui::IWindowInfosReportedListener>&)>;
+using WindowInfosUpdateConsumer = std::function<void(const gui::WindowInfosUpdate&)>;
class Listener : public gui::BnWindowInfosListener {
public:
Listener(WindowInfosUpdateConsumer consumer) : mConsumer(std::move(consumer)) {}
- binder::Status onWindowInfosChanged(
- const gui::WindowInfosUpdate& update,
- const sp<gui::IWindowInfosReportedListener>& reportedListener) override {
- mConsumer(update, reportedListener);
+ binder::Status onWindowInfosChanged(const gui::WindowInfosUpdate& update) override {
+ mConsumer(update);
return binder::Status::ok();
}
@@ -58,15 +46,17 @@
int callCount = 0;
- mInvoker->addWindowInfosListener(
- sp<Listener>::make([&](const gui::WindowInfosUpdate&,
- const sp<gui::IWindowInfosReportedListener>& reportedListener) {
- std::scoped_lock lock{mutex};
- callCount++;
- cv.notify_one();
+ gui::WindowInfosListenerInfo listenerInfo;
+ mInvoker->addWindowInfosListener(sp<Listener>::make([&](const gui::WindowInfosUpdate& update) {
+ std::scoped_lock lock{mutex};
+ callCount++;
+ cv.notify_one();
- reportedListener->onWindowInfosReported();
- }));
+ listenerInfo.windowInfosPublisher
+ ->ackWindowInfosReceived(update.vsyncId,
+ listenerInfo.listenerId);
+ }),
+ &listenerInfo);
BackgroundExecutor::getInstance().sendCallbacks(
{[this]() { mInvoker->windowInfosChanged({}, {}, false); }});
@@ -81,21 +71,27 @@
std::mutex mutex;
std::condition_variable cv;
- int callCount = 0;
- const int expectedCallCount = 3;
+ size_t callCount = 0;
+ const size_t expectedCallCount = 3;
+ std::vector<gui::WindowInfosListenerInfo> listenerInfos{expectedCallCount,
+ gui::WindowInfosListenerInfo{}};
- for (int i = 0; i < expectedCallCount; i++) {
- mInvoker->addWindowInfosListener(sp<Listener>::make(
- [&](const gui::WindowInfosUpdate&,
- const sp<gui::IWindowInfosReportedListener>& reportedListener) {
- std::scoped_lock lock{mutex};
- callCount++;
- if (callCount == expectedCallCount) {
- cv.notify_one();
- }
+ for (size_t i = 0; i < expectedCallCount; i++) {
+ mInvoker->addWindowInfosListener(sp<Listener>::make([&, &listenerInfo = listenerInfos[i]](
+ const gui::WindowInfosUpdate&
+ update) {
+ std::scoped_lock lock{mutex};
+ callCount++;
+ if (callCount == expectedCallCount) {
+ cv.notify_one();
+ }
- reportedListener->onWindowInfosReported();
- }));
+ listenerInfo.windowInfosPublisher
+ ->ackWindowInfosReceived(update.vsyncId,
+ listenerInfo
+ .listenerId);
+ }),
+ &listenerInfos[i]);
}
BackgroundExecutor::getInstance().sendCallbacks(
@@ -114,17 +110,20 @@
int callCount = 0;
- // Simulate a slow ack by not calling the WindowInfosReportedListener.
- mInvoker->addWindowInfosListener(sp<Listener>::make(
- [&](const gui::WindowInfosUpdate&, const sp<gui::IWindowInfosReportedListener>&) {
- std::scoped_lock lock{mutex};
- callCount++;
- cv.notify_one();
- }));
+ // Simulate a slow ack by not calling IWindowInfosPublisher.ackWindowInfosReceived
+ gui::WindowInfosListenerInfo listenerInfo;
+ mInvoker->addWindowInfosListener(sp<Listener>::make([&](const gui::WindowInfosUpdate&) {
+ std::scoped_lock lock{mutex};
+ callCount++;
+ cv.notify_one();
+ }),
+ &listenerInfo);
BackgroundExecutor::getInstance().sendCallbacks({[&]() {
- mInvoker->windowInfosChanged({}, {}, false);
- mInvoker->windowInfosChanged({}, {}, false);
+ mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 0, 0}, {},
+ false);
+ mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 1, 0}, {},
+ false);
}});
{
@@ -134,7 +133,7 @@
EXPECT_EQ(callCount, 1);
// Ack the first message.
- mInvoker->onWindowInfosReported();
+ listenerInfo.windowInfosPublisher->ackWindowInfosReceived(0, listenerInfo.listenerId);
{
std::unique_lock lock{mutex};
@@ -152,19 +151,21 @@
int callCount = 0;
const int expectedCallCount = 2;
- // Simulate a slow ack by not calling the WindowInfosReportedListener.
- mInvoker->addWindowInfosListener(sp<Listener>::make(
- [&](const gui::WindowInfosUpdate&, const sp<gui::IWindowInfosReportedListener>&) {
- std::scoped_lock lock{mutex};
- callCount++;
- if (callCount == expectedCallCount) {
- cv.notify_one();
- }
- }));
+ // Simulate a slow ack by not calling IWindowInfosPublisher.ackWindowInfosReceived
+ gui::WindowInfosListenerInfo listenerInfo;
+ mInvoker->addWindowInfosListener(sp<Listener>::make([&](const gui::WindowInfosUpdate&) {
+ std::scoped_lock lock{mutex};
+ callCount++;
+ if (callCount == expectedCallCount) {
+ cv.notify_one();
+ }
+ }),
+ &listenerInfo);
BackgroundExecutor::getInstance().sendCallbacks({[&]() {
- mInvoker->windowInfosChanged({}, {}, false);
- mInvoker->windowInfosChanged({}, {}, true);
+ mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 0, 0}, {},
+ false);
+ mInvoker->windowInfosChanged(gui::WindowInfosUpdate{{}, {}, /* vsyncId= */ 1, 0}, {}, true);
}});
{
@@ -182,14 +183,14 @@
int64_t lastUpdateId = -1;
- // Simulate a slow ack by not calling the WindowInfosReportedListener.
- mInvoker->addWindowInfosListener(
- sp<Listener>::make([&](const gui::WindowInfosUpdate& update,
- const sp<gui::IWindowInfosReportedListener>&) {
- std::scoped_lock lock{mutex};
- lastUpdateId = update.vsyncId;
- cv.notify_one();
- }));
+ // Simulate a slow ack by not calling IWindowInfosPublisher.ackWindowInfosReceived
+ gui::WindowInfosListenerInfo listenerInfo;
+ mInvoker->addWindowInfosListener(sp<Listener>::make([&](const gui::WindowInfosUpdate& update) {
+ std::scoped_lock lock{mutex};
+ lastUpdateId = update.vsyncId;
+ cv.notify_one();
+ }),
+ &listenerInfo);
BackgroundExecutor::getInstance().sendCallbacks({[&]() {
mInvoker->windowInfosChanged({{}, {}, /* vsyncId= */ 1, 0}, {}, false);
@@ -204,7 +205,7 @@
EXPECT_EQ(lastUpdateId, 1);
// Ack the first message. The third update should be sent.
- mInvoker->onWindowInfosReported();
+ listenerInfo.windowInfosPublisher->ackWindowInfosReceived(1, listenerInfo.listenerId);
{
std::unique_lock lock{mutex};
@@ -225,14 +226,17 @@
// delayed.
BackgroundExecutor::getInstance().sendCallbacks({[&]() {
mInvoker->windowInfosChanged({}, {}, false);
- mInvoker->addWindowInfosListener(sp<Listener>::make(
- [&](const gui::WindowInfosUpdate&, const sp<gui::IWindowInfosReportedListener>&) {
- std::scoped_lock lock{mutex};
- callCount++;
- cv.notify_one();
- }));
- mInvoker->windowInfosChanged({}, {}, false);
+ gui::WindowInfosListenerInfo listenerInfo;
+ mInvoker->addWindowInfosListener(sp<Listener>::make([&](const gui::WindowInfosUpdate&) {
+ std::scoped_lock lock{mutex};
+ callCount++;
+ cv.notify_one();
+ }),
+ &listenerInfo);
}});
+ BackgroundExecutor::getInstance().flushQueue();
+ BackgroundExecutor::getInstance().sendCallbacks(
+ {[&]() { mInvoker->windowInfosChanged({}, {}, false); }});
{
std::unique_lock lock{mutex};
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index d3fb9fc..8d48940 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -51,6 +51,7 @@
~Composer() override;
MOCK_METHOD(bool, isSupported, (OptionalFeature), (const, override));
+ MOCK_METHOD(bool, getDisplayConfigurationsSupported, (), (const, override));
MOCK_METHOD0(getCapabilities,
std::vector<aidl::android::hardware::graphics::composer3::Capability>());
MOCK_METHOD0(dumpDebugInfo, std::string());
@@ -70,6 +71,7 @@
MOCK_METHOD4(getDisplayAttribute,
Error(Display, Config config, IComposerClient::Attribute, int32_t*));
MOCK_METHOD2(getDisplayConfigs, Error(Display, std::vector<Config>*));
+ MOCK_METHOD2(getDisplayConfigurations, Error(Display, std::vector<DisplayConfiguration>*));
MOCK_METHOD2(getDisplayName, Error(Display, std::string*));
MOCK_METHOD4(getDisplayRequests,
Error(Display, uint32_t*, std::vector<Layer>*, std::vector<uint32_t>*));
diff --git a/services/vibratorservice/OWNERS b/services/vibratorservice/OWNERS
index d073e2b..031b333 100644
--- a/services/vibratorservice/OWNERS
+++ b/services/vibratorservice/OWNERS
@@ -1 +1,3 @@
+# Bug component: 345036
+
include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index b73d2cb..114f863 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -16,6 +16,7 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
#include <android/hardware/graphics/common/1.0/types.h>
#include <grallocusage/GrallocUsageConversion.h>
#include <graphicsenv/GraphicsEnv.h>
@@ -25,8 +26,6 @@
#include <sync/sync.h>
#include <system/window.h>
#include <ui/BufferQueueDefs.h>
-#include <ui/DebugUtils.h>
-#include <ui/PixelFormat.h>
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
@@ -37,6 +36,7 @@
#include "driver.h"
+using PixelFormat = aidl::android::hardware::graphics::common::PixelFormat;
using android::hardware::graphics::common::V1_0::BufferUsage;
namespace vulkan {
@@ -503,27 +503,27 @@
*count = num_copied;
}
-android::PixelFormat GetNativePixelFormat(VkFormat format) {
- android::PixelFormat native_format = android::PIXEL_FORMAT_RGBA_8888;
+PixelFormat GetNativePixelFormat(VkFormat format) {
+ PixelFormat native_format = PixelFormat::RGBA_8888;
switch (format) {
case VK_FORMAT_R8G8B8A8_UNORM:
case VK_FORMAT_R8G8B8A8_SRGB:
- native_format = android::PIXEL_FORMAT_RGBA_8888;
+ native_format = PixelFormat::RGBA_8888;
break;
case VK_FORMAT_R5G6B5_UNORM_PACK16:
- native_format = android::PIXEL_FORMAT_RGB_565;
+ native_format = PixelFormat::RGB_565;
break;
case VK_FORMAT_R16G16B16A16_SFLOAT:
- native_format = android::PIXEL_FORMAT_RGBA_FP16;
+ native_format = PixelFormat::RGBA_FP16;
break;
case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
- native_format = android::PIXEL_FORMAT_RGBA_1010102;
+ native_format = PixelFormat::RGBA_1010102;
break;
case VK_FORMAT_R8_UNORM:
- native_format = android::PIXEL_FORMAT_R_8;
+ native_format = PixelFormat::R_8;
break;
case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
- native_format = android::PIXEL_FORMAT_RGBA_10101010;
+ native_format = PixelFormat::RGBA_10101010;
break;
default:
ALOGV("unsupported swapchain format %d", format);
@@ -1361,7 +1361,7 @@
if (!allocator)
allocator = &GetData(device).allocator;
- android::PixelFormat native_pixel_format =
+ PixelFormat native_pixel_format =
GetNativePixelFormat(create_info->imageFormat);
android_dataspace native_dataspace =
GetNativeDataspace(create_info->imageColorSpace);
@@ -1462,10 +1462,11 @@
const auto& dispatch = GetData(device).driver;
- err = native_window_set_buffers_format(window, native_pixel_format);
+ err = native_window_set_buffers_format(
+ window, static_cast<int>(native_pixel_format));
if (err != android::OK) {
ALOGE("native_window_set_buffers_format(%s) failed: %s (%d)",
- decodePixelFormat(native_pixel_format).c_str(), strerror(-err), err);
+ toString(native_pixel_format).c_str(), strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}