Merge "Fix bt2020 linear ext mapping issue in EGL and Vulkan." into main
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/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index f3eb4e8..afb09de 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -255,7 +255,6 @@
uint64_t frameNumber, std::shared_ptr<FenceTime>&& acquire) {
FrameEvents* frame = getFrame(frameNumber, &mAcquireOffset);
if (frame == nullptr) {
- ALOGE("updateAcquireFence: Did not find frame.");
return;
}
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 8060705..e7b2195 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -40,6 +40,80 @@
using namespace android;
// ----------------------------------------------------------------------------
+// Validate hardware_buffer.h and PixelFormat.aidl agree
+// ----------------------------------------------------------------------------
+
+static_assert(HAL_PIXEL_FORMAT_RGBA_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_RGBX_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_RGB_565 == AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_RGB_888 == AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_RGBA_FP16 == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_RGBA_1010102 == AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_BLOB == AHARDWAREBUFFER_FORMAT_BLOB,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_DEPTH_16 == AHARDWAREBUFFER_FORMAT_D16_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_DEPTH_24 == AHARDWAREBUFFER_FORMAT_D24_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_DEPTH_32F == AHARDWAREBUFFER_FORMAT_D32_FLOAT,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_STENCIL_8 == AHARDWAREBUFFER_FORMAT_S8_UINT,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_BGRA_8888 == AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_YV12 == AHARDWAREBUFFER_FORMAT_YV12,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_Y8 == AHARDWAREBUFFER_FORMAT_Y8,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_Y16 == AHARDWAREBUFFER_FORMAT_Y16,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_RAW16 == AHARDWAREBUFFER_FORMAT_RAW16,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_RAW10 == AHARDWAREBUFFER_FORMAT_RAW10,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_RAW12 == AHARDWAREBUFFER_FORMAT_RAW12,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_RAW_OPAQUE == AHARDWAREBUFFER_FORMAT_RAW_OPAQUE,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED ==
+ AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_YCBCR_420_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_YCBCR_422_SP == AHARDWAREBUFFER_FORMAT_YCbCr_422_SP,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_YCRCB_420_SP == AHARDWAREBUFFER_FORMAT_YCrCb_420_SP,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_YCBCR_422_I == AHARDWAREBUFFER_FORMAT_YCbCr_422_I,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(HAL_PIXEL_FORMAT_YCBCR_P010 == AHARDWAREBUFFER_FORMAT_YCbCr_P010,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::R_8) ==
+ AHARDWAREBUFFER_FORMAT_R8_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::R_16_UINT) ==
+ AHARDWAREBUFFER_FORMAT_R16_UINT,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(
+ static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RG_1616_UINT) ==
+ AHARDWAREBUFFER_FORMAT_R16G16_UINT,
+ "HAL and AHardwareBuffer pixel format don't match");
+static_assert(
+ static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RGBA_10101010) ==
+ AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM,
+ "HAL and AHardwareBuffer pixel format don't match");
+
+// ----------------------------------------------------------------------------
// Public functions
// ----------------------------------------------------------------------------
@@ -227,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;
}
}
@@ -487,12 +564,6 @@
return false;
}
- if (!AHardwareBuffer_isValidPixelFormat(desc->format)) {
- ALOGE_IF(log, "Invalid AHardwareBuffer pixel format %u (%#x))",
- desc->format, desc->format);
- return false;
- }
-
if (desc->rfu0 != 0 || desc->rfu1 != 0) {
ALOGE_IF(log, "AHardwareBuffer_Desc::rfu fields must be 0");
return false;
@@ -557,114 +628,6 @@
return true;
}
-bool AHardwareBuffer_isValidPixelFormat(uint32_t format) {
- static_assert(HAL_PIXEL_FORMAT_RGBA_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_RGBX_8888 == AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_RGB_565 == AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_RGB_888 == AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_RGBA_FP16 == AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_RGBA_1010102 == AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_BLOB == AHARDWAREBUFFER_FORMAT_BLOB,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_DEPTH_16 == AHARDWAREBUFFER_FORMAT_D16_UNORM,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_DEPTH_24 == AHARDWAREBUFFER_FORMAT_D24_UNORM,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_DEPTH_24_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_DEPTH_32F == AHARDWAREBUFFER_FORMAT_D32_FLOAT,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_DEPTH_32F_STENCIL_8 == AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_STENCIL_8 == AHARDWAREBUFFER_FORMAT_S8_UINT,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_BGRA_8888 == AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_YV12 == AHARDWAREBUFFER_FORMAT_YV12,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_Y8 == AHARDWAREBUFFER_FORMAT_Y8,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_Y16 == AHARDWAREBUFFER_FORMAT_Y16,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_RAW16 == AHARDWAREBUFFER_FORMAT_RAW16,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_RAW10 == AHARDWAREBUFFER_FORMAT_RAW10,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_RAW12 == AHARDWAREBUFFER_FORMAT_RAW12,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_RAW_OPAQUE == AHARDWAREBUFFER_FORMAT_RAW_OPAQUE,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED == AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_YCBCR_420_888 == AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_YCBCR_422_SP == AHARDWAREBUFFER_FORMAT_YCbCr_422_SP,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_YCRCB_420_SP == AHARDWAREBUFFER_FORMAT_YCrCb_420_SP,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_YCBCR_422_I == AHARDWAREBUFFER_FORMAT_YCbCr_422_I,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(HAL_PIXEL_FORMAT_YCBCR_P010 == AHARDWAREBUFFER_FORMAT_YCbCr_P010,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::R_8) ==
- AHARDWAREBUFFER_FORMAT_R8_UNORM,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::R_16_UINT) ==
- AHARDWAREBUFFER_FORMAT_R16_UINT,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RG_1616_UINT) ==
- AHARDWAREBUFFER_FORMAT_R16G16_UINT,
- "HAL and AHardwareBuffer pixel format don't match");
- static_assert(static_cast<int>(aidl::android::hardware::graphics::common::PixelFormat::RGBA_10101010) ==
- AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM,
- "HAL and AHardwareBuffer pixel format don't match");
-
- switch (format) {
- case AHARDWAREBUFFER_FORMAT_R8_UNORM:
- case AHARDWAREBUFFER_FORMAT_R16_UINT:
- case AHARDWAREBUFFER_FORMAT_R16G16_UINT:
- case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
- case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
- case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
- case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
- case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
- case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
- case AHARDWAREBUFFER_FORMAT_R10G10B10A10_UNORM:
- case AHARDWAREBUFFER_FORMAT_BLOB:
- case AHARDWAREBUFFER_FORMAT_D16_UNORM:
- case AHARDWAREBUFFER_FORMAT_D24_UNORM:
- case AHARDWAREBUFFER_FORMAT_D24_UNORM_S8_UINT:
- case AHARDWAREBUFFER_FORMAT_D32_FLOAT:
- case AHARDWAREBUFFER_FORMAT_D32_FLOAT_S8_UINT:
- case AHARDWAREBUFFER_FORMAT_S8_UINT:
- case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
- // VNDK formats only -- unfortunately we can't differentiate from where we're called
- case AHARDWAREBUFFER_FORMAT_B8G8R8A8_UNORM:
- case AHARDWAREBUFFER_FORMAT_YV12:
- case AHARDWAREBUFFER_FORMAT_Y8:
- case AHARDWAREBUFFER_FORMAT_Y16:
- case AHARDWAREBUFFER_FORMAT_RAW16:
- case AHARDWAREBUFFER_FORMAT_RAW10:
- case AHARDWAREBUFFER_FORMAT_RAW12:
- case AHARDWAREBUFFER_FORMAT_RAW_OPAQUE:
- case AHARDWAREBUFFER_FORMAT_IMPLEMENTATION_DEFINED:
- case AHARDWAREBUFFER_FORMAT_YCbCr_422_SP:
- case AHARDWAREBUFFER_FORMAT_YCrCb_420_SP:
- case AHARDWAREBUFFER_FORMAT_YCbCr_422_I:
- case AHARDWAREBUFFER_FORMAT_YCbCr_P010:
- return true;
-
- default:
- return false;
- }
-}
-
bool AHardwareBuffer_formatIsYuv(uint32_t format) {
switch (format) {
case AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420:
@@ -681,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/TEST_MAPPING b/libs/nativewindow/TEST_MAPPING
index 3d7f3c2..9d6425b 100644
--- a/libs/nativewindow/TEST_MAPPING
+++ b/libs/nativewindow/TEST_MAPPING
@@ -1,7 +1,13 @@
{
"presubmit": [
{
+ "name": "libnativewindow_bindgen_test"
+ },
+ {
"name": "libnativewindow_test"
+ },
+ {
+ "name": "libnativewindow_rs-internal_test"
}
]
}
diff --git a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
index 6d3d295..880c694 100644
--- a/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
+++ b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
@@ -37,15 +37,9 @@
// parameters. Note: this does not verify any platform-specific contraints.
bool AHardwareBuffer_isValidDescription(const AHardwareBuffer_Desc* desc, bool log);
-// whether this AHardwareBuffer format is valid
-bool AHardwareBuffer_isValidPixelFormat(uint32_t ahardwarebuffer_format);
-
// 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/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index c2fd6ef..dcb5068 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -65,7 +65,6 @@
LIBNATIVEWINDOW_PLATFORM {
global:
extern "C++" {
- android::AHardwareBuffer_isValidPixelFormat*;
android::AHardwareBuffer_convertFromPixelFormat*;
android::AHardwareBuffer_convertToPixelFormat*;
android::AHardwareBuffer_convertFromGrallocUsageBits*;
diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp
new file mode 100644
index 0000000..dc1575c
--- /dev/null
+++ b/libs/nativewindow/rust/Android.bp
@@ -0,0 +1,87 @@
+// 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 {
+ default_applicable_licenses: [
+ "frameworks_native_libs_nativewindow_license",
+ ],
+}
+
+rust_bindgen {
+ name: "libnativewindow_bindgen",
+ crate_name: "nativewindow_bindgen",
+ wrapper_src: "sys/nativewindow_bindings.h",
+ source_stem: "bindings",
+ bindgen_flags: [
+ "--constified-enum-module=AHardwareBuffer_Format",
+ "--bitfield-enum=AHardwareBuffer_UsageFlags",
+
+ "--allowlist-file=.*/nativewindow/include/.*\\.h",
+
+ "--with-derive-eq",
+ "--with-derive-partialeq",
+ ],
+ shared_libs: [
+ "libnativewindow",
+ ],
+
+ // Currently necessary for host builds
+ // TODO(b/31559095): bionic on host should define this
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ min_sdk_version: "VanillaIceCream",
+}
+
+rust_test {
+ name: "libnativewindow_bindgen_test",
+ srcs: [":libnativewindow_bindgen"],
+ crate_name: "nativewindow_bindgen_test",
+ test_suites: ["general-tests"],
+ auto_gen_config: true,
+ clippy_lints: "none",
+ lints: "none",
+}
+
+rust_defaults {
+ name: "libnativewindow_defaults",
+ srcs: ["src/lib.rs"],
+ rustlibs: [
+ "libnativewindow_bindgen",
+ ],
+}
+
+rust_library {
+ name: "libnativewindow_rs",
+ crate_name: "nativewindow",
+ defaults: ["libnativewindow_defaults"],
+
+ // Currently necessary for host builds
+ // TODO(b/31559095): bionic on host should define this
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+ min_sdk_version: "VanillaIceCream",
+}
+
+rust_test {
+ name: "libnativewindow_rs-internal_test",
+ crate_name: "nativewindow",
+ defaults: ["libnativewindow_defaults"],
+ test_suites: ["general-tests"],
+}
diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs
new file mode 100644
index 0000000..a5bcc62
--- /dev/null
+++ b/libs/nativewindow/rust/src/lib.rs
@@ -0,0 +1,260 @@
+// 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.
+
+//! Pleasant Rust bindings for libnativewindow, including AHardwareBuffer
+
+extern crate nativewindow_bindgen as ffi;
+
+pub use ffi::{AHardwareBuffer_Format, AHardwareBuffer_UsageFlags};
+
+use std::os::raw::c_void;
+use std::ptr;
+
+/// Wrapper around an opaque C AHardwareBuffer.
+pub struct AHardwareBuffer(*mut ffi::AHardwareBuffer);
+
+impl AHardwareBuffer {
+ /// Test whether the given format and usage flag combination is allocatable. If this function
+ /// returns true, it means that a buffer with the given description can be allocated on this
+ /// implementation, unless resource exhaustion occurs. If this function returns false, it means
+ /// that the allocation of the given description will never succeed.
+ ///
+ /// Available since API 29
+ pub fn is_supported(
+ width: u32,
+ height: u32,
+ layers: u32,
+ format: AHardwareBuffer_Format::Type,
+ usage: AHardwareBuffer_UsageFlags,
+ stride: u32,
+ ) -> bool {
+ let buffer_desc = ffi::AHardwareBuffer_Desc {
+ width,
+ height,
+ layers,
+ format,
+ usage: usage.0,
+ stride,
+ rfu0: 0,
+ rfu1: 0,
+ };
+ // SAFETY: *buffer_desc will never be null.
+ let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) };
+
+ status == 1
+ }
+
+ /// Allocates a buffer that matches the passed AHardwareBuffer_Desc. If allocation succeeds, the
+ /// buffer can be used according to the usage flags specified in its description. If a buffer is
+ /// used in ways not compatible with its usage flags, the results are undefined and may include
+ /// program termination.
+ ///
+ /// Available since API level 26.
+ pub fn new(
+ width: u32,
+ height: u32,
+ layers: u32,
+ format: AHardwareBuffer_Format::Type,
+ usage: AHardwareBuffer_UsageFlags,
+ ) -> Option<Self> {
+ let buffer_desc = ffi::AHardwareBuffer_Desc {
+ width,
+ height,
+ layers,
+ format,
+ usage: usage.0,
+ stride: 0,
+ rfu0: 0,
+ rfu1: 0,
+ };
+ let mut buffer = ptr::null_mut();
+ // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail
+ // and return a status, but we check it later.
+ let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut buffer) };
+
+ if status == 0 {
+ Some(Self(buffer))
+ } else {
+ None
+ }
+ }
+
+ /// Adopts the raw pointer and wraps it in a Rust AHardwareBuffer.
+ ///
+ /// # Errors
+ ///
+ /// Will panic if buffer_ptr is null.
+ ///
+ /// # Safety
+ ///
+ /// This function adopts the pointer but does NOT increment the refcount on the buffer. If the
+ /// caller uses the pointer after the created object is dropped it will cause a memory leak.
+ pub unsafe fn take_from_raw(buffer_ptr: *mut c_void) -> Self {
+ assert!(!buffer_ptr.is_null());
+ Self(buffer_ptr as *mut ffi::AHardwareBuffer)
+ }
+
+ /// Get the system wide unique id for an AHardwareBuffer. This function may panic in extreme
+ /// and undocumented circumstances.
+ ///
+ /// Available since API level 31.
+ pub fn id(&self) -> u64 {
+ let mut out_id = 0;
+ // SAFETY: Neither pointers can be null.
+ let status = unsafe { ffi::AHardwareBuffer_getId(self.0, &mut out_id) };
+ assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}");
+
+ out_id
+ }
+
+ /// Get the width of this buffer
+ pub fn width(&self) -> u32 {
+ self.description().width
+ }
+
+ /// Get the height of this buffer
+ pub fn height(&self) -> u32 {
+ self.description().height
+ }
+
+ /// Get the number of layers of this buffer
+ pub fn layers(&self) -> u32 {
+ self.description().layers
+ }
+
+ /// Get the format of this buffer
+ pub fn format(&self) -> AHardwareBuffer_Format::Type {
+ self.description().format
+ }
+
+ /// Get the usage bitvector of this buffer
+ pub fn usage(&self) -> AHardwareBuffer_UsageFlags {
+ AHardwareBuffer_UsageFlags(self.description().usage)
+ }
+
+ /// Get the stride of this buffer
+ pub fn stride(&self) -> u32 {
+ self.description().stride
+ }
+
+ fn description(&self) -> ffi::AHardwareBuffer_Desc {
+ let mut buffer_desc = ffi::AHardwareBuffer_Desc {
+ width: 0,
+ height: 0,
+ layers: 0,
+ format: 0,
+ usage: 0,
+ stride: 0,
+ rfu0: 0,
+ rfu1: 0,
+ };
+ // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null.
+ unsafe { ffi::AHardwareBuffer_describe(self.0, &mut buffer_desc) };
+ buffer_desc
+ }
+}
+
+impl Drop for AHardwareBuffer {
+ fn drop(&mut self) {
+ // SAFETY: self.0 will never be null. AHardwareBuffers allocated from within Rust will have
+ // a refcount of one, and there is a safety warning on taking an AHardwareBuffer from a raw
+ // pointer requiring callers to ensure the refcount is managed appropriately.
+ unsafe { ffi::AHardwareBuffer_release(self.0) }
+ }
+}
+
+#[cfg(test)]
+mod ahardwarebuffer_tests {
+ use super::*;
+
+ #[test]
+ fn create_valid_buffer_returns_ok() {
+ let buffer = AHardwareBuffer::new(
+ 512,
+ 512,
+ 1,
+ AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ );
+ assert!(buffer.is_some());
+ }
+
+ #[test]
+ fn create_invalid_buffer_returns_err() {
+ let buffer = AHardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0));
+ assert!(buffer.is_none());
+ }
+
+ #[test]
+ #[should_panic]
+ fn take_from_raw_panics_on_null() {
+ unsafe { AHardwareBuffer::take_from_raw(ptr::null_mut()) };
+ }
+
+ #[test]
+ fn take_from_raw_allows_getters() {
+ let buffer_desc = ffi::AHardwareBuffer_Desc {
+ width: 1024,
+ height: 512,
+ layers: 1,
+ format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN.0,
+ stride: 0,
+ rfu0: 0,
+ rfu1: 0,
+ };
+ let mut raw_buffer_ptr = ptr::null_mut();
+
+ let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) };
+ assert_eq!(status, 0);
+
+ let buffer = unsafe { AHardwareBuffer::take_from_raw(raw_buffer_ptr as *mut c_void) };
+ assert_eq!(buffer.width(), 1024);
+ }
+
+ #[test]
+ fn basic_getters() {
+ let buffer = AHardwareBuffer::new(
+ 1024,
+ 512,
+ 1,
+ AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ )
+ .expect("Buffer with some basic parameters was not created successfully");
+
+ assert_eq!(buffer.width(), 1024);
+ assert_eq!(buffer.height(), 512);
+ assert_eq!(buffer.layers(), 1);
+ assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM);
+ assert_eq!(
+ buffer.usage(),
+ AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN
+ );
+ }
+
+ #[test]
+ fn id_getter() {
+ let buffer = AHardwareBuffer::new(
+ 1024,
+ 512,
+ 1,
+ AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+ AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ )
+ .expect("Buffer with some basic parameters was not created successfully");
+
+ assert_ne!(0, buffer.id());
+ }
+}
diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h
new file mode 100644
index 0000000..e652aee
--- /dev/null
+++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/data_space.h>
+#include <android/hardware_buffer.h>
+#include <android/hdr_metadata.h>
+#include <android/native_window.h>
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index fd97309..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);
@@ -2554,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);
}
}
}
@@ -2706,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
@@ -2816,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.
@@ -4110,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);
@@ -5779,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/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 609e4dd..7051680 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -9015,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/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/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index 7e678b9..23cfe928 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -540,7 +540,7 @@
primaryDisplayRotationFlags);
snapshot->changes |= RequestedLayerState::Changes::Created;
}
- scheduler::LayerInfo::FrameRate oldFrameRate = snapshot->frameRate;
+
if (traversalPath.isRelative()) {
bool parentIsRelative = traversalPath.variant == LayerHierarchy::Variant::Relative;
updateRelativeState(*snapshot, parentSnapshot, parentIsRelative, args);
@@ -561,9 +561,6 @@
updateFrameRateFromChildSnapshot(*snapshot, childSnapshot, args);
}
- if (oldFrameRate == snapshot->frameRate) {
- snapshot->changes.clear(RequestedLayerState::Changes::FrameRate);
- }
return *snapshot;
}
@@ -670,8 +667,10 @@
const LayerSnapshot& childSnapshot,
const Args& args) {
if (args.forceUpdate == ForceUpdateFlags::NONE &&
- !childSnapshot.changes.any(RequestedLayerState::Changes::FrameRate |
- RequestedLayerState::Changes::Hierarchy)) {
+ !args.layerLifecycleManager.getGlobalChanges().any(
+ RequestedLayerState::Changes::Hierarchy) &&
+ !childSnapshot.changes.any(RequestedLayerState::Changes::FrameRate) &&
+ !snapshot.changes.any(RequestedLayerState::Changes::FrameRate)) {
return;
}
@@ -817,6 +816,8 @@
}
if (forceUpdate ||
+ args.layerLifecycleManager.getGlobalChanges().any(
+ RequestedLayerState::Changes::Hierarchy) ||
snapshot.changes.any(RequestedLayerState::Changes::FrameRate |
RequestedLayerState::Changes::Hierarchy)) {
snapshot.frameRate = (requested.requestedFrameRate.rate.isValid() ||
@@ -824,6 +825,7 @@
scheduler::LayerInfo::FrameRateCompatibility::NoVote))
? requested.requestedFrameRate
: parentSnapshot.frameRate;
+ snapshot.changes |= RequestedLayerState::Changes::FrameRate;
}
if (forceUpdate || snapshot.clientChanges & layer_state_t::eFrameRateSelectionPriority) {
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/RefreshRateSelector.cpp b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
index 7951c33..2529095 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateSelector.cpp
@@ -1223,10 +1223,19 @@
(supportsFrameRateOverride() || ranges.render.includes(mode.getFps()));
};
- const auto frameRateModes = createFrameRateModes(filterModes, ranges.render);
+ auto frameRateModes = createFrameRateModes(filterModes, ranges.render);
+ if (frameRateModes.empty()) {
+ ALOGW("No matching frame rate modes for %s range. policy: %s", rangeName,
+ policy->toString().c_str());
+ // TODO(b/292105422): Ideally DisplayManager should not send render ranges smaller than
+ // the min supported. See b/292047939.
+ // For not we just ignore the render ranges.
+ frameRateModes = createFrameRateModes(filterModes, {});
+ }
LOG_ALWAYS_FATAL_IF(frameRateModes.empty(),
- "No matching frame rate modes for %s range. policy: %s", rangeName,
- policy->toString().c_str());
+ "No matching frame rate modes for %s range even after ignoring the "
+ "render range. policy: %s",
+ rangeName, policy->toString().c_str());
const auto stringifyModes = [&] {
std::string str;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 198e92a..eb0f5ce 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -487,7 +487,7 @@
mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false);
mLayerLifecycleManagerEnabled =
- base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, false);
+ base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, true);
mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled ||
base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false);
}
@@ -6387,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");
}
@@ -8263,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;
}
@@ -9349,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();
@@ -9357,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 3d46239..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;
@@ -1552,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/tests/unittests/LayerHierarchyTest.h b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
index 3234483..e475b84 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.h
@@ -319,6 +319,20 @@
mLifecycleManager.applyTransactions(transactions);
}
+ void setFrameRate(uint32_t id, float frameRate, int8_t compatibility,
+ int8_t changeFrameRateStrategy) {
+ std::vector<TransactionState> transactions;
+ transactions.emplace_back();
+ transactions.back().states.push_back({});
+
+ transactions.back().states.front().state.what = layer_state_t::eFrameRateChanged;
+ transactions.back().states.front().layerId = id;
+ transactions.back().states.front().state.frameRate = frameRate;
+ transactions.back().states.front().state.frameRateCompatibility = compatibility;
+ transactions.back().states.front().state.changeFrameRateStrategy = changeFrameRateStrategy;
+ mLifecycleManager.applyTransactions(transactions);
+ }
+
LayerLifecycleManager mLifecycleManager;
};
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index d6c4b72..a581d5b 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -512,4 +512,88 @@
EXPECT_EQ(getSnapshot({.id = 1221})->frameRateSelectionPriority, 1);
}
+TEST_F(LayerSnapshotTest, framerate) {
+ setFrameRate(11, 244.f, 0, 0);
+
+ UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+ // verify parent is gets no vote
+ EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate.type,
+ scheduler::LayerInfo::FrameRateCompatibility::NoVote);
+ EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ // verify layer and children get the requested votes
+ EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate.type,
+ scheduler::LayerInfo::FrameRateCompatibility::Default);
+ EXPECT_TRUE(getSnapshot({.id = 11})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate.type,
+ scheduler::LayerInfo::FrameRateCompatibility::Default);
+ EXPECT_TRUE(getSnapshot({.id = 111})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ // reparent and verify the child gets the new parent's framerate
+ reparentLayer(122, 11);
+
+ std::vector<uint32_t> expected = {1, 11, 111, 122, 1221, 12, 121, 13, 2};
+ UPDATE_AND_VERIFY(mSnapshotBuilder, expected);
+ // verify parent is gets no vote
+ EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate.type,
+ scheduler::LayerInfo::FrameRateCompatibility::NoVote);
+
+ // verify layer and children get the requested votes
+ EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate.type,
+ scheduler::LayerInfo::FrameRateCompatibility::Default);
+
+ EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate.type,
+ scheduler::LayerInfo::FrameRateCompatibility::Default);
+
+ EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 122})->frameRate.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 122})->frameRate.type,
+ scheduler::LayerInfo::FrameRateCompatibility::Default);
+ EXPECT_TRUE(getSnapshot({.id = 122})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ // reparent and verify the new parent gets no vote
+ reparentLayer(11, 2);
+ expected = {1, 12, 121, 13, 2, 11, 111, 122, 1221};
+ UPDATE_AND_VERIFY(mSnapshotBuilder, expected);
+
+ // verify old parent has invalid framerate (default)
+ EXPECT_FALSE(getSnapshot({.id = 1})->frameRate.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 1})->frameRate.type,
+ scheduler::LayerInfo::FrameRateCompatibility::Default);
+ EXPECT_TRUE(getSnapshot({.id = 1})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ // verify new parent get no vote
+ EXPECT_FALSE(getSnapshot({.id = 2})->frameRate.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 2})->frameRate.type,
+ scheduler::LayerInfo::FrameRateCompatibility::NoVote);
+ EXPECT_TRUE(getSnapshot({.id = 2})->changes.test(RequestedLayerState::Changes::FrameRate));
+
+ // verify layer and children get the requested votes (unchanged)
+ EXPECT_TRUE(getSnapshot({.id = 11})->frameRate.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 11})->frameRate.type,
+ scheduler::LayerInfo::FrameRateCompatibility::Default);
+
+ EXPECT_TRUE(getSnapshot({.id = 111})->frameRate.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 111})->frameRate.type,
+ scheduler::LayerInfo::FrameRateCompatibility::Default);
+
+ EXPECT_TRUE(getSnapshot({.id = 122})->frameRate.rate.isValid());
+ EXPECT_EQ(getSnapshot({.id = 122})->frameRate.rate.getValue(), 244.f);
+ EXPECT_EQ(getSnapshot({.id = 122})->frameRate.type,
+ scheduler::LayerInfo::FrameRateCompatibility::Default);
+}
+
} // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
index d63e187..646d9cc 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectorTest.cpp
@@ -3042,5 +3042,20 @@
EXPECT_FRAME_RATE_MODE(kMode60, 60_Hz, selector.getBestScoredFrameRate(layers).frameRateMode);
}
+TEST_P(RefreshRateSelectorTest, frameRateIsLowerThanMinSupported) {
+ if (GetParam() != Config::FrameRateOverride::Enabled) {
+ return;
+ }
+
+ auto selector = createSelector(kModes_60_90, kModeId60);
+
+ constexpr Fps kMin = RefreshRateSelector::kMinSupportedFrameRate;
+ constexpr FpsRanges kLowerThanMin = {{60_Hz, 90_Hz}, {kMin / 2, kMin / 2}};
+
+ EXPECT_EQ(SetPolicyResult::Changed,
+ selector.setDisplayManagerPolicy(
+ {DisplayModeId(kModeId60), kLowerThanMin, kLowerThanMin}));
+}
+
} // namespace
} // namespace android::scheduler
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/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