Merge "KeyboardInputMapper_test: remove unused testDPadKeyRotation parameter" into main
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 07d16f7..a4a22a0 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -22,5 +22,21 @@
{
"name": "SurfaceFlinger_test"
}
+ ],
+ "postsubmit": [
+ {
+ "name": "SurfaceFlinger_test",
+ "keywords": [ "primary-device" ],
+ "options": [
+ // TODO(b/328119950) Known to be broken.
+ {
+ "exclude-filter": "LayerCallbackTest#SetNullBuffer"
+ },
+ // TODO(b/398306512) Flaky on real device.
+ {
+ "exclude-filter": "LayerRenderTypeTransactionTests/LayerRenderTypeTransactionTest#SetRelativeZBasic_BufferQueue/*"
+ }
+ ]
+ }
]
}
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 77e7328..6e6d27d 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -202,26 +202,13 @@
}
bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h,
- sp<GLConsumer>* glConsumer, EGLSurface* surface) {
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- sp<GLConsumer> glc = new GLConsumer(name, GL_TEXTURE_EXTERNAL_OES, false, true);
+ sp<GLConsumer>* glConsumer, EGLSurface* surface) {
+ auto [glc, surf] = GLConsumer::create(name, GL_TEXTURE_EXTERNAL_OES, false, true);
glc->setDefaultBufferSize(w, h);
- glc->getSurface()->setMaxDequeuedBufferCount(2);
glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
+ surf->setMaxDequeuedBufferCount(2);
+ sp<ANativeWindow> anw = surf;
- sp<ANativeWindow> anw = glc->getSurface();
-#else
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
- sp<GLConsumer> glc = new GLConsumer(consumer, name,
- GL_TEXTURE_EXTERNAL_OES, false, true);
- glc->setDefaultBufferSize(w, h);
- producer->setMaxDequeuedBufferCount(2);
- glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
-
- sp<ANativeWindow> anw = new Surface(producer);
-#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr);
if (s == EGL_NO_SURFACE) {
fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index cd8ca89..0ac5266 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -317,6 +317,12 @@
}
prebuilt_etc {
+ name: "android.hardware.telephony.messaging.prebuilt.xml",
+ src: "android.hardware.telephony.messaging.xml",
+ defaults: ["frameworks_native_data_etc_defaults"],
+}
+
+prebuilt_etc {
name: "android.hardware.thread_network.prebuilt.xml",
src: "android.hardware.thread_network.xml",
defaults: ["frameworks_native_data_etc_defaults"],
diff --git a/data/etc/android.hardware.telephony.messaging.xml b/data/etc/android.hardware.telephony.messaging.xml
new file mode 100644
index 0000000..0e96123
--- /dev/null
+++ b/data/etc/android.hardware.telephony.messaging.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2025 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.
+-->
+
+<!-- Feature for devices with messaging. -->
+<permissions>
+ <feature name="android.hardware.telephony" />
+ <feature name="android.hardware.telephony.radio.access" />
+ <feature name="android.hardware.telephony.subscription" />
+ <feature name="android.hardware.telephony.messaging" />
+</permissions>
diff --git a/include/OWNERS b/include/OWNERS
index c98e87a..7f847e8 100644
--- a/include/OWNERS
+++ b/include/OWNERS
@@ -1,5 +1,4 @@
alecmouri@google.com
-alexeykuzmin@google.com
dangittik@google.com
jreck@google.com
lajos@google.com
diff --git a/include/android/input.h b/include/android/input.h
index 5f44550..2f6c5b5 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -862,7 +862,7 @@
AMOTION_EVENT_BUTTON_FORWARD = 1 << 4,
AMOTION_EVENT_BUTTON_STYLUS_PRIMARY = 1 << 5,
AMOTION_EVENT_BUTTON_STYLUS_SECONDARY = 1 << 6,
- // LINT.ThenChange(/frameworks/native/libs/input/rust/input.rs)
+ // LINT.ThenChange(/frameworks/native/libs/input/rust/input.rs,/frameworks/native/services/inputflinger/tests/fuzzers/FuzzedInputStream.h)
};
/**
diff --git a/include/ftl/ignore.h b/include/ftl/ignore.h
new file mode 100644
index 0000000..1468fa2
--- /dev/null
+++ b/include/ftl/ignore.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android::ftl {
+
+// An alternative to `std::ignore` that makes it easy to ignore multiple values.
+//
+// Examples:
+//
+// void ftl_ignore_multiple(int arg1, const char* arg2, std::string arg3) {
+// // When invoked, all the arguments are ignored.
+// ftl::ignore(arg1, arg2, arg3);
+// }
+//
+// void ftl_ignore_single(int arg) {
+// // It can be used like std::ignore to ignore a single value
+// ftl::ignore = arg;
+// }
+//
+inline constexpr struct {
+ // NOLINTNEXTLINE(misc-unconventional-assign-operator, readability-named-parameter)
+ constexpr auto operator=(auto&&) const -> decltype(*this) { return *this; }
+ // NOLINTNEXTLINE(readability-named-parameter)
+ constexpr void operator()(auto&&...) const {}
+} ignore;
+
+} // namespace android::ftl
\ No newline at end of file
diff --git a/include/input/Input.h b/include/input/Input.h
index e84023e..002b3a7 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -316,6 +316,19 @@
bool isStylusEvent(uint32_t source, const std::vector<PointerProperties>& properties);
+bool isStylusHoverEvent(uint32_t source, const std::vector<PointerProperties>& properties,
+ int32_t action);
+
+bool isFromMouse(uint32_t source, ToolType tooltype);
+
+bool isFromTouchpad(uint32_t source, ToolType tooltype);
+
+bool isFromDrawingTablet(uint32_t source, ToolType tooltype);
+
+bool isHoverAction(int32_t action);
+
+bool isMouseOrTouchpad(uint32_t sources);
+
/*
* Flags that flow alongside events in the input dispatch system to help with certain
* policy decisions such as waking from device sleep.
diff --git a/include/input/InputFlags.h b/include/input/InputFlags.h
index 0e194ea..4b42f77 100644
--- a/include/input/InputFlags.h
+++ b/include/input/InputFlags.h
@@ -25,6 +25,11 @@
* override.
*/
static bool connectedDisplaysCursorEnabled();
+
+ /**
+ * Check if both connectedDisplaysCursor and associatedDisplayCursorBugfix is enabled.
+ */
+ static bool connectedDisplaysCursorAndAssociatedDisplayCursorBugfixEnabled();
};
} // namespace android
diff --git a/libs/attestation/OWNERS b/libs/attestation/OWNERS
index 4dbb0ea..76811f2 100644
--- a/libs/attestation/OWNERS
+++ b/libs/attestation/OWNERS
@@ -1,2 +1 @@
-chaviw@google.com
-svv@google.com
\ No newline at end of file
+svv@google.com
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index fb00d4f..ea5343a 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -827,6 +827,7 @@
// so we restrict its visibility to the Trusty-specific packages.
visibility: [
":__subpackages__",
+ "//hardware/interfaces/security/see:__subpackages__",
"//system/core/trusty:__subpackages__",
"//vendor:__subpackages__",
],
diff --git a/libs/binder/RpcTransportTipcAndroid.cpp b/libs/binder/RpcTransportTipcAndroid.cpp
index 3819fb6..14c0bde 100644
--- a/libs/binder/RpcTransportTipcAndroid.cpp
+++ b/libs/binder/RpcTransportTipcAndroid.cpp
@@ -21,6 +21,7 @@
#include <log/log.h>
#include <poll.h>
#include <trusty/tipc.h>
+#include <type_traits>
#include "FdTrigger.h"
#include "RpcState.h"
@@ -32,6 +33,9 @@
namespace android {
+// Corresponds to IPC_MAX_MSG_HANDLES in the Trusty kernel
+constexpr size_t kMaxTipcHandles = 8;
+
// RpcTransport for writing Trusty IPC clients in Android.
class RpcTransportTipcAndroid : public RpcTransport {
public:
@@ -78,12 +82,28 @@
FdTrigger* fdTrigger, iovec* iovs, int niovs,
const std::optional<SmallFunction<status_t()>>& altPoll,
const std::vector<std::variant<unique_fd, borrowed_fd>>* ancillaryFds) override {
+ bool sentFds = false;
auto writeFn = [&](iovec* iovs, size_t niovs) -> ssize_t {
- // TODO: send ancillaryFds. For now, we just abort if anyone tries
- // to send any.
- LOG_ALWAYS_FATAL_IF(ancillaryFds != nullptr && !ancillaryFds->empty(),
- "File descriptors are not supported on Trusty yet");
- return TEMP_FAILURE_RETRY(tipc_send(mSocket.fd.get(), iovs, niovs, nullptr, 0));
+ trusty_shm shms[kMaxTipcHandles] = {{0}};
+ ssize_t shm_count = 0;
+
+ if (!sentFds && ancillaryFds != nullptr && !ancillaryFds->empty()) {
+ if (ancillaryFds->size() > kMaxTipcHandles) {
+ ALOGE("Too many file descriptors for TIPC: %zu", ancillaryFds->size());
+ errno = EINVAL;
+ return -1;
+ }
+ for (const auto& fdVariant : *ancillaryFds) {
+ shms[shm_count++] = {std::visit([](const auto& fd) { return fd.get(); },
+ fdVariant),
+ TRUSTY_SEND_SECURE_OR_SHARE};
+ }
+ }
+
+ auto ret = TEMP_FAILURE_RETRY(tipc_send(mSocket.fd.get(), iovs, niovs,
+ (shm_count == 0) ? nullptr : shms, shm_count));
+ sentFds |= ret >= 0;
+ return ret;
};
status_t status = interruptableReadOrWrite(mSocket, fdTrigger, iovs, niovs, writeFn,
diff --git a/libs/binder/aidl/android/content/pm/OWNERS b/libs/binder/aidl/android/content/pm/OWNERS
index 3100518..2617a16 100644
--- a/libs/binder/aidl/android/content/pm/OWNERS
+++ b/libs/binder/aidl/android/content/pm/OWNERS
@@ -1,5 +1,4 @@
+michaelwr@google.com
narayan@google.com
patb@google.com
-svetoslavganov@google.com
-toddke@google.com
-patb@google.com
\ No newline at end of file
+schfan@google.com
diff --git a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
index 89f21dd..783e11f 100644
--- a/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
+++ b/libs/binder/ndk/include_platform/android/binder_ibinder_platform.h
@@ -62,6 +62,8 @@
* This must be called before the object is sent to another process.
* Aborts on invalid values. Not thread safe.
*
+ * This overrides the setting in ABinderProcess_disableBackgroundScheduling.
+ *
* \param binder local server binder to set the policy for
* \param policy scheduler policy as defined in linux UAPI
* \param priority priority. [-20..19] for SCHED_NORMAL, [1..99] for RT
diff --git a/libs/binder/ndk/include_platform/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h
index 6aff994..2432099 100644
--- a/libs/binder/ndk/include_platform/android/binder_process.h
+++ b/libs/binder/ndk/include_platform/android/binder_process.h
@@ -75,6 +75,19 @@
void ABinderProcess_joinThreadPool(void);
/**
+ * Disables (or enables) background scheduling.
+ *
+ * By default, binder threads execute at a lower priority. However, this can cause
+ * priority inversion, so it is recommended to be disabled in high priority
+ * or in system processes.
+ *
+ * See also AIBinder_setMinSchedulerPolicy, which overrides this setting.
+ *
+ * \param disable whether to disable background scheduling
+ */
+void ABinderProcess_disableBackgroundScheduling(bool disable);
+
+/**
* This gives you an fd to wait on. Whenever data is available on the fd,
* ABinderProcess_handlePolledCommands can be called to handle binder queries.
* This is expected to be used in a single threaded process which waits on
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index a637165..d4eb8c7 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -229,6 +229,7 @@
AIBinder_fromPlatformBinder*;
AIBinder_toPlatformBinder*;
AParcel_viewPlatformParcel*;
+ ABinderProcess_disableBackgroundScheduling;
};
local:
*;
diff --git a/libs/binder/ndk/process.cpp b/libs/binder/ndk/process.cpp
index 0072ac3..bcdb959 100644
--- a/libs/binder/ndk/process.cpp
+++ b/libs/binder/ndk/process.cpp
@@ -36,6 +36,10 @@
IPCThreadState::self()->joinThreadPool();
}
+void ABinderProcess_disableBackgroundScheduling(bool disable) {
+ IPCThreadState::disableBackgroundScheduling(disable);
+}
+
binder_status_t ABinderProcess_setupPolling(int* fd) {
return IPCThreadState::self()->setupPolling(fd);
}
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index a9bd11e..43ee33e 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -101,7 +101,7 @@
"android.hardware.automotive.remoteaccess.IRemoteAccess",
"android.hardware.automotive.vehicle.IVehicle",
"android.hardware.biometrics.face.IBiometricsFace",
- "android.hardware.biometrics.fingerprint.IBiometricsFingerprint",
+ "android.hardware.biometrics.fingerprint.IFingerprint",
"android.hardware.camera.provider.ICameraProvider",
"android.hardware.drm.IDrmFactory",
"android.hardware.graphics.allocator.IAllocator",
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
index 08ce855..5244442 100644
--- a/libs/ftl/Android.bp
+++ b/libs/ftl/Android.bp
@@ -26,6 +26,7 @@
"function_test.cpp",
"future_test.cpp",
"hash_test.cpp",
+ "ignore_test.cpp",
"match_test.cpp",
"mixins_test.cpp",
"non_null_test.cpp",
diff --git a/libs/ftl/ignore_test.cpp b/libs/ftl/ignore_test.cpp
new file mode 100644
index 0000000..5d5c67b
--- /dev/null
+++ b/libs/ftl/ignore_test.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2025 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 <string>
+
+#include <ftl/ignore.h>
+#include <gtest/gtest.h>
+
+namespace android::test {
+namespace {
+
+// Keep in sync with the example usage in the header file.
+
+void ftl_ignore_multiple(int arg1, const char* arg2, std::string arg3) {
+ // When invoked, all the arguments are ignored.
+ ftl::ignore(arg1, arg2, arg3);
+}
+
+void ftl_ignore_single(int arg) {
+ // It can be used like std::ignore to ignore a single value
+ ftl::ignore = arg;
+}
+
+} // namespace
+
+TEST(Ignore, Example) {
+ // The real example test is that there are no compiler warnings for unused arguments above.
+
+ // Use the example functions to avoid a compiler warning about unused functions.
+ ftl_ignore_multiple(0, "a", "b");
+ ftl_ignore_single(0);
+}
+
+} // namespace android::test
diff --git a/libs/graphicsenv/FeatureOverrides.cpp b/libs/graphicsenv/FeatureOverrides.cpp
index 51afe28..9e7a4cf 100644
--- a/libs/graphicsenv/FeatureOverrides.cpp
+++ b/libs/graphicsenv/FeatureOverrides.cpp
@@ -35,6 +35,18 @@
if (status != OK) {
return status;
}
+ // Number of GPU vendor IDs.
+ status = parcel->writeVectorSize(mGpuVendorIDs);
+ if (status != OK) {
+ return status;
+ }
+ // GPU vendor IDs.
+ for (const auto& vendorID : mGpuVendorIDs) {
+ status = parcel->writeUint32(vendorID);
+ if (status != OK) {
+ return status;
+ }
+ }
return OK;
}
@@ -50,6 +62,21 @@
if (status != OK) {
return status;
}
+ // Number of GPU vendor IDs.
+ int numGpuVendorIDs;
+ status = parcel->readInt32(&numGpuVendorIDs);
+ if (status != OK) {
+ return status;
+ }
+ // GPU vendor IDs.
+ for (int i = 0; i < numGpuVendorIDs; i++) {
+ uint32_t gpuVendorIdUint;
+ status = parcel->readUint32(&gpuVendorIdUint);
+ if (status != OK) {
+ return status;
+ }
+ mGpuVendorIDs.emplace_back(gpuVendorIdUint);
+ }
return OK;
}
@@ -58,6 +85,10 @@
std::string result;
StringAppendF(&result, "Feature: %s\n", mFeatureName.c_str());
StringAppendF(&result, " Status: %s\n", mEnabled ? "enabled" : "disabled");
+ for (const auto& vendorID : mGpuVendorIDs) {
+ // vkjson outputs decimal, so print both formats.
+ StringAppendF(&result, " GPU Vendor ID: 0x%04X (%d)\n", vendorID, vendorID);
+ }
return result;
}
@@ -121,7 +152,12 @@
}
// Number of package feature overrides.
- int numPkgOverrides = parcel->readInt32();
+ int numPkgOverrides;
+ status = parcel->readInt32(&numPkgOverrides);
+ if (status != OK) {
+ return status;
+ }
+ // Package feature overrides.
for (int i = 0; i < numPkgOverrides; i++) {
// Package name.
std::string name;
@@ -131,7 +167,11 @@
}
std::vector<FeatureConfig> cfgs;
// Number of package feature configs.
- int numCfgs = parcel->readInt32();
+ int numCfgs;
+ status = parcel->readInt32(&numCfgs);
+ if (status != OK) {
+ return status;
+ }
// Package feature configs.
for (int j = 0; j < numCfgs; j++) {
FeatureConfig cfg;
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 4bc2611..626581c 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -621,6 +621,10 @@
mShouldUseAngle = true;
}
mShouldUseNativeDriver = shouldUseNativeDriver;
+
+ if (mShouldUseAngle) {
+ updateAngleFeatureOverrides();
+ }
}
std::string& GraphicsEnv::getPackageName() {
@@ -632,6 +636,22 @@
return mAngleEglFeatures;
}
+// List of ANGLE features to override (enabled or disable).
+// The list of overrides is loaded and parsed by GpuService.
+void GraphicsEnv::updateAngleFeatureOverrides() {
+ if (!graphicsenv_flags::feature_overrides()) {
+ return;
+ }
+
+ const sp<IGpuService> gpuService = getGpuService();
+ if (!gpuService) {
+ ALOGE("No GPU service");
+ return;
+ }
+
+ mFeatureOverrides = gpuService->getFeatureOverrides();
+}
+
void GraphicsEnv::getAngleFeatureOverrides(std::vector<const char*>& enabled,
std::vector<const char*>& disabled) {
if (!graphicsenv_flags::feature_overrides()) {
diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp
index 42e7c37..9a34aff 100644
--- a/libs/graphicsenv/IGpuService.cpp
+++ b/libs/graphicsenv/IGpuService.cpp
@@ -119,6 +119,21 @@
}
return driverPath;
}
+
+ FeatureOverrides getFeatureOverrides() override {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
+
+ FeatureOverrides featureOverrides;
+ status_t error =
+ remote()->transact(BnGpuService::GET_FEATURE_CONFIG_OVERRIDES, data, &reply);
+ if (error != OK) {
+ return featureOverrides;
+ }
+
+ featureOverrides.readFromParcel(&reply);
+ return featureOverrides;
+ }
};
IMPLEMENT_META_INTERFACE(GpuService, "android.graphicsenv.IGpuService");
@@ -271,6 +286,15 @@
toggleAngleAsSystemDriver(enableAngleAsSystemDriver);
return OK;
}
+ case GET_FEATURE_CONFIG_OVERRIDES: {
+ CHECK_INTERFACE(IGpuService, data, reply);
+
+ // Get the FeatureOverrides from gpuservice, which implements the IGpuService interface
+ // with GpuService::getFeatureOverrides().
+ FeatureOverrides featureOverrides = getFeatureOverrides();
+ featureOverrides.writeToParcel(reply);
+ return OK;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/graphicsenv/include/graphicsenv/FeatureOverrides.h b/libs/graphicsenv/include/graphicsenv/FeatureOverrides.h
index 450eed2..5dc613b 100644
--- a/libs/graphicsenv/include/graphicsenv/FeatureOverrides.h
+++ b/libs/graphicsenv/include/graphicsenv/FeatureOverrides.h
@@ -35,6 +35,7 @@
std::string mFeatureName;
bool mEnabled;
+ std::vector<uint32_t> mGpuVendorIDs;
};
/*
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 55fa13a..6821900 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -121,6 +121,7 @@
// Get the app package name.
std::string& getPackageName();
const std::vector<std::string>& getAngleEglFeatures();
+ void updateAngleFeatureOverrides();
void getAngleFeatureOverrides(std::vector<const char*>& enabled,
std::vector<const char*>& disabled);
// Set the persist.graphics.egl system property value.
diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h
index a0d6e37..442683a 100644
--- a/libs/graphicsenv/include/graphicsenv/IGpuService.h
+++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h
@@ -18,6 +18,7 @@
#include <binder/IInterface.h>
#include <cutils/compiler.h>
+#include <graphicsenv/FeatureOverrides.h>
#include <graphicsenv/GpuStatsInfo.h>
#include <vector>
@@ -55,6 +56,9 @@
// sets ANGLE as system GLES driver if enabled==true by setting persist.graphics.egl to true.
virtual void toggleAngleAsSystemDriver(bool enabled) = 0;
+
+ // Get the list of features to override.
+ virtual FeatureOverrides getFeatureOverrides() = 0;
};
class BnGpuService : public BnInterface<IGpuService> {
@@ -67,6 +71,7 @@
TOGGLE_ANGLE_AS_SYSTEM_DRIVER,
SET_TARGET_STATS_ARRAY,
ADD_VULKAN_ENGINE_NAME,
+ GET_FEATURE_CONFIG_OVERRIDES,
// Always append new enum to the end.
};
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 310f781..fa97142 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -197,15 +197,15 @@
mUpdateDestinationFrame(updateDestinationFrame) {
createBufferQueue(&mProducer, &mConsumer);
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- mBufferItemConsumer = new BLASTBufferItemConsumer(mProducer, mConsumer,
- GraphicBuffer::USAGE_HW_COMPOSER |
- GraphicBuffer::USAGE_HW_TEXTURE,
- 1, false, this);
+ mBufferItemConsumer = sp<BLASTBufferItemConsumer>::make(mProducer, mConsumer,
+ GraphicBuffer::USAGE_HW_COMPOSER |
+ GraphicBuffer::USAGE_HW_TEXTURE,
+ 1, false, this);
#else
- mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
- GraphicBuffer::USAGE_HW_COMPOSER |
- GraphicBuffer::USAGE_HW_TEXTURE,
- 1, false, this);
+ mBufferItemConsumer = sp<BLASTBufferItemConsumer>::make(mConsumer,
+ GraphicBuffer::USAGE_HW_COMPOSER |
+ GraphicBuffer::USAGE_HW_TEXTURE,
+ 1, false, this);
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
// since the adapter is in the client process, set dequeue timeout
// explicitly so that dequeueBuffer will block
@@ -637,7 +637,8 @@
bufferItem.mScalingMode, crop);
auto releaseBufferCallback = makeReleaseBufferCallbackThunk();
- sp<Fence> fence = bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE;
+ sp<Fence> fence =
+ bufferItem.mFence ? sp<Fence>::make(bufferItem.mFence->dup()) : Fence::NO_FENCE;
nsecs_t dequeueTime = -1;
{
@@ -1014,7 +1015,7 @@
if (includeSurfaceControlHandle && mSurfaceControl) {
scHandle = mSurfaceControl->getHandle();
}
- return new BBQSurface(mProducer, true, scHandle, this);
+ return sp<BBQSurface>::make(mProducer, true, scHandle, this);
}
void BLASTBufferQueue::mergeWithNextTransaction(SurfaceComposerClient::Transaction* t,
@@ -1120,10 +1121,10 @@
class AsyncProducerListener : public BnProducerListener {
private:
const sp<IProducerListener> mListener;
+ AsyncProducerListener(const sp<IProducerListener>& listener) : mListener(listener) {}
+ friend class sp<AsyncProducerListener>;
public:
- AsyncProducerListener(const sp<IProducerListener>& listener) : mListener(listener) {}
-
void onBufferReleased() override {
AsyncWorker::getInstance().post([listener = mListener]() { listener->onBufferReleased(); });
}
@@ -1177,7 +1178,7 @@
return BufferQueueProducer::connect(listener, api, producerControlledByApp, output);
}
- return BufferQueueProducer::connect(new AsyncProducerListener(listener), api,
+ return BufferQueueProducer::connect(sp<AsyncProducerListener>::make(listener), api,
producerControlledByApp, output);
}
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 3b2d337..9dcd5dc 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -215,14 +215,14 @@
FlattenableUtils::read(buffer, size, flags);
if (flags & 1) {
- mGraphicBuffer = new GraphicBuffer();
+ mGraphicBuffer = sp<GraphicBuffer>::make();
status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count);
if (err) return err;
size -= FlattenableUtils::align<4>(buffer);
}
if (flags & 2) {
- mFence = new Fence();
+ mFence = sp<Fence>::make();
status_t err = mFence->unflatten(buffer, size, fds, count);
if (err) return err;
size -= FlattenableUtils::align<4>(buffer);
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 8566419..1585aae 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -24,6 +24,7 @@
#include <com_android_graphics_libgui_flags.h>
#include <gui/BufferItem.h>
#include <gui/BufferItemConsumer.h>
+#include <gui/Surface.h>
#include <ui/BufferQueueDefs.h>
#include <ui/GraphicBuffer.h>
@@ -35,6 +36,30 @@
namespace android {
+std::tuple<sp<BufferItemConsumer>, sp<Surface>> BufferItemConsumer::create(
+ uint64_t consumerUsage, int bufferCount, bool controlledByApp,
+ bool isConsumerSurfaceFlinger) {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ sp<BufferItemConsumer> bufferItemConsumer =
+ sp<BufferItemConsumer>::make(consumerUsage, bufferCount, controlledByApp,
+ isConsumerSurfaceFlinger);
+ return {bufferItemConsumer, bufferItemConsumer->getSurface()};
+#else
+ sp<IGraphicBufferProducer> igbp;
+ sp<IGraphicBufferConsumer> igbc;
+ BufferQueue::createBufferQueue(&igbp, &igbc, isConsumerSurfaceFlinger);
+ sp<BufferItemConsumer> bufferItemConsumer =
+ sp<BufferItemConsumer>::make(igbc, consumerUsage, bufferCount, controlledByApp);
+ return {bufferItemConsumer, sp<Surface>::make(igbp, controlledByApp)};
+#endif
+}
+
+sp<BufferItemConsumer> BufferItemConsumer::create(const sp<IGraphicBufferConsumer>& consumer,
+ uint64_t consumerUsage, int bufferCount,
+ bool controlledByApp) {
+ return sp<BufferItemConsumer>::make(consumer, consumerUsage, bufferCount, controlledByApp);
+}
+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
BufferItemConsumer::BufferItemConsumer(uint64_t consumerUsage, int bufferCount,
bool controlledByApp, bool isConsumerSurfaceFlinger)
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index f1374e2..f21ac18 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -125,15 +125,16 @@
LOG_ALWAYS_FATAL_IF(outConsumer == nullptr,
"BufferQueue: outConsumer must not be NULL");
- sp<BufferQueueCore> core(new BufferQueueCore());
+ sp<BufferQueueCore> core = sp<BufferQueueCore>::make();
LOG_ALWAYS_FATAL_IF(core == nullptr,
"BufferQueue: failed to create BufferQueueCore");
- sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger));
+ sp<IGraphicBufferProducer> producer =
+ sp<BufferQueueProducer>::make(core, consumerIsSurfaceFlinger);
LOG_ALWAYS_FATAL_IF(producer == nullptr,
"BufferQueue: failed to create BufferQueueProducer");
- sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
+ sp<IGraphicBufferConsumer> consumer = sp<BufferQueueConsumer>::make(core);
LOG_ALWAYS_FATAL_IF(consumer == nullptr,
"BufferQueue: failed to create BufferQueueConsumer");
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index c241482..5961b41 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -693,11 +693,11 @@
.requestorName = {mConsumerName.c_str(), mConsumerName.size()},
.extras = std::move(tempOptions),
};
- sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(allocRequest);
+ sp<GraphicBuffer> graphicBuffer = sp<GraphicBuffer>::make(allocRequest);
#else
sp<GraphicBuffer> graphicBuffer =
- new GraphicBuffer(width, height, format, BQ_LAYER_COUNT, usage,
- {mConsumerName.c_str(), mConsumerName.size()});
+ sp<GraphicBuffer>::make(width, height, format, BQ_LAYER_COUNT, usage,
+ std::string{mConsumerName.c_str(), mConsumerName.size()});
#endif
status_t error = graphicBuffer->initCheck();
@@ -1464,7 +1464,7 @@
#ifndef NO_BINDER
if (IInterface::asBinder(listener)->remoteBinder() != nullptr) {
status = IInterface::asBinder(listener)->linkToDeath(
- static_cast<IBinder::DeathRecipient*>(this));
+ sp<IBinder::DeathRecipient>::fromExisting(this));
if (status != NO_ERROR) {
BQ_LOGE("connect: linkToDeath failed: %s (%d)",
strerror(-status), status);
@@ -1553,8 +1553,7 @@
IInterface::asBinder(mCore->mLinkedToDeath);
// This can fail if we're here because of the death
// notification, but we just ignore it
- token->unlinkToDeath(
- static_cast<IBinder::DeathRecipient*>(this));
+ token->unlinkToDeath(static_cast<IBinder::DeathRecipient*>(this));
}
#endif
mCore->mSharedBufferSlot =
@@ -1685,11 +1684,11 @@
#endif
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BQ_EXTENDEDALLOCATE)
- sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(allocRequest);
+ sp<GraphicBuffer> graphicBuffer = sp<GraphicBuffer>::make(allocRequest);
#else
- sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
- allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
- allocUsage, allocName);
+ sp<GraphicBuffer> graphicBuffer =
+ sp<GraphicBuffer>::make(allocWidth, allocHeight, allocFormat, BQ_LAYER_COUNT,
+ allocUsage, allocName);
#endif
status_t result = graphicBuffer->initCheck();
diff --git a/libs/gui/BufferReleaseChannel.cpp b/libs/gui/BufferReleaseChannel.cpp
index e9cb013..4f495d0 100644
--- a/libs/gui/BufferReleaseChannel.cpp
+++ b/libs/gui/BufferReleaseChannel.cpp
@@ -108,7 +108,7 @@
status_t BufferReleaseChannel::Message::unflatten(void const*& buffer, size_t& size,
int const*& fds, size_t& count) {
- releaseFence = new Fence();
+ releaseFence = sp<Fence>::make();
if (status_t err = releaseFence->unflatten(buffer, size, fds, count); err != OK) {
return err;
}
@@ -344,4 +344,4 @@
return STATUS_OK;
}
-} // namespace android::gui
\ No newline at end of file
+} // namespace android::gui
diff --git a/libs/gui/Choreographer.cpp b/libs/gui/Choreographer.cpp
index ab747b9..80a3543 100644
--- a/libs/gui/Choreographer.cpp
+++ b/libs/gui/Choreographer.cpp
@@ -20,6 +20,7 @@
#include <gui/Choreographer.h>
#include <gui/TraceUtils.h>
#include <jni.h>
+#include <utils/Looper.h>
#undef LOG_TAG
#define LOG_TAG "AChoreographer"
@@ -69,7 +70,7 @@
Choreographer::Context Choreographer::gChoreographers;
-static thread_local Choreographer* gChoreographer;
+static thread_local sp<Choreographer> gChoreographer;
void Choreographer::initJVM(JNIEnv* env) {
env->GetJavaVM(&gJni.jvm);
@@ -86,14 +87,14 @@
"()V");
}
-Choreographer* Choreographer::getForThread() {
+sp<Choreographer> Choreographer::getForThread() {
if (gChoreographer == nullptr) {
sp<Looper> looper = Looper::getForThread();
if (!looper.get()) {
ALOGW("No looper prepared for thread");
return nullptr;
}
- gChoreographer = new Choreographer(looper);
+ gChoreographer = sp<Choreographer>::make(looper);
status_t result = gChoreographer->initialize();
if (result != OK) {
ALOGW("Failed to initialize");
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 67de742..117a362 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -31,6 +31,7 @@
#include <gui/BufferItem.h>
#include <gui/BufferQueue.h>
#include <gui/ConsumerBase.h>
+#include <gui/IConsumerListener.h>
#include <gui/ISurfaceComposer.h>
#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
@@ -68,8 +69,8 @@
#endif
mAbandoned(false),
mConsumer(bufferQueue),
- mPrevFinalReleaseFence(Fence::NO_FENCE) {
- initialize(controlledByApp);
+ mPrevFinalReleaseFence(Fence::NO_FENCE),
+ mIsControlledByApp(controlledByApp) {
}
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
@@ -79,11 +80,11 @@
mSlots(BufferQueueDefs::NUM_BUFFER_SLOTS),
#endif
mAbandoned(false),
- mPrevFinalReleaseFence(Fence::NO_FENCE) {
+ mPrevFinalReleaseFence(Fence::NO_FENCE),
+ mIsControlledByApp(controlledByApp) {
sp<IGraphicBufferProducer> producer;
BufferQueue::createBufferQueue(&producer, &mConsumer, consumerIsSurfaceFlinger);
mSurface = sp<Surface>::make(producer, controlledByApp);
- initialize(controlledByApp);
}
ConsumerBase::ConsumerBase(const sp<IGraphicBufferProducer>& producer,
@@ -95,24 +96,27 @@
mAbandoned(false),
mConsumer(consumer),
mSurface(sp<Surface>::make(producer, controlledByApp)),
- mPrevFinalReleaseFence(Fence::NO_FENCE) {
- initialize(controlledByApp);
+ mPrevFinalReleaseFence(Fence::NO_FENCE),
+ mIsControlledByApp(controlledByApp) {
}
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
-void ConsumerBase::initialize(bool controlledByApp) {
+void ConsumerBase::onFirstRef() {
+ ConsumerListener::onFirstRef();
+ initialize();
+}
+
+void ConsumerBase::initialize() {
// Choose a name using the PID and a process-unique ID.
mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
- // Note that we can't create an sp<...>(this) in a ctor that will not keep a
- // reference once the ctor ends, as that would cause the refcount of 'this'
- // dropping to 0 at the end of the ctor. Since all we need is a wp<...>
- // that's what we create.
- wp<ConsumerListener> listener = static_cast<ConsumerListener*>(this);
- sp<IConsumerListener> proxy = new BufferQueue::ProxyConsumerListener(listener);
+ // Here we depend on an sp/wp having been created for `this`. For this
+ // reason, initialize() cannot be called from a ctor.
+ wp<ConsumerListener> listener = wp<ConsumerListener>::fromExisting(this);
+ sp<IConsumerListener> proxy = sp<BufferQueue::ProxyConsumerListener>::make(listener);
- status_t err = mConsumer->consumerConnect(proxy, controlledByApp);
+ status_t err = mConsumer->consumerConnect(proxy, mIsControlledByApp);
if (err != NO_ERROR) {
CB_LOGE("ConsumerBase: error connecting to BufferQueue: %s (%d)",
strerror(-err), err);
@@ -480,7 +484,6 @@
return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers);
}
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
status_t ConsumerBase::setConsumerIsProtected(bool isProtected) {
Mutex::Autolock lock(mMutex);
if (mAbandoned) {
@@ -489,7 +492,6 @@
}
return mConsumer->setConsumerIsProtected(isProtected);
}
-#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
sp<NativeHandle> ConsumerBase::getSidebandStream() const {
Mutex::Autolock _l(mMutex);
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 23b432e..ecbceb7 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -20,7 +20,11 @@
#include <com_android_graphics_libgui_flags.h>
#include <gui/BufferItem.h>
+#include <gui/BufferQueue.h>
#include <gui/CpuConsumer.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
#include <utils/Log.h>
#define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.c_str(), ##__VA_ARGS__)
@@ -31,6 +35,28 @@
namespace android {
+std::tuple<sp<CpuConsumer>, sp<Surface>> CpuConsumer::create(size_t maxLockedBuffers,
+ bool controlledByApp,
+ bool isConsumerSurfaceFlinger) {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ sp<CpuConsumer> consumer =
+ sp<CpuConsumer>::make(maxLockedBuffers, controlledByApp, isConsumerSurfaceFlinger);
+ return {consumer, consumer->getSurface()};
+#else
+ sp<IGraphicBufferProducer> igbp;
+ sp<IGraphicBufferConsumer> igbc;
+ BufferQueue::createBufferQueue(&igbp, &igbc, isConsumerSurfaceFlinger);
+
+ return {sp<CpuConsumer>::make(igbc, maxLockedBuffers, controlledByApp),
+ sp<Surface>::make(igbp, controlledByApp)};
+#endif
+}
+
+sp<CpuConsumer> CpuConsumer::create(const sp<IGraphicBufferConsumer>& bq, size_t maxLockedBuffers,
+ bool controlledByApp) {
+ return sp<CpuConsumer>::make(bq, maxLockedBuffers, controlledByApp);
+}
+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
CpuConsumer::CpuConsumer(size_t maxLockedBuffers, bool controlledByApp,
bool isConsumerSurfaceFlinger)
@@ -230,7 +256,7 @@
return err;
}
- sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+ sp<Fence> fence(fenceFd >= 0 ? sp<Fence>::make(fenceFd) : Fence::NO_FENCE);
addReleaseFenceLocked(ab.mSlot, ab.mGraphicBuffer, fence);
releaseBufferLocked(ab.mSlot, ab.mGraphicBuffer);
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 052b8ed..2c5770d 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -37,6 +37,7 @@
#include <gui/DebugEGLImageTracker.h>
#include <gui/GLConsumer.h>
#include <gui/ISurfaceComposer.h>
+#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <private/gui/ComposerService.h>
@@ -101,6 +102,50 @@
return hasIt;
}
+std::tuple<sp<GLConsumer>, sp<Surface>> GLConsumer::create(uint32_t tex, uint32_t textureTarget,
+ bool useFenceSync,
+ bool isControlledByApp) {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ sp<GLConsumer> consumer =
+ sp<GLConsumer>::make(tex, textureTarget, useFenceSync, isControlledByApp);
+ return {consumer, consumer->getSurface()};
+#else
+ sp<IGraphicBufferProducer> igbp;
+ sp<IGraphicBufferConsumer> igbc;
+ BufferQueue::createBufferQueue(&igbp, &igbc);
+
+ return {sp<GLConsumer>::make(igbc, tex, textureTarget, useFenceSync, isControlledByApp),
+ sp<Surface>::make(igbp, isControlledByApp)};
+#endif
+}
+
+std::tuple<sp<GLConsumer>, sp<Surface>> GLConsumer::create(uint32_t textureTarget,
+ bool useFenceSync,
+ bool isControlledByApp) {
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ sp<GLConsumer> consumer = sp<GLConsumer>::make(textureTarget, useFenceSync, isControlledByApp);
+ return {consumer, consumer->getSurface()};
+#else
+ sp<IGraphicBufferProducer> igbp;
+ sp<IGraphicBufferConsumer> igbc;
+ BufferQueue::createBufferQueue(&igbp, &igbc);
+
+ return {sp<GLConsumer>::make(igbc, textureTarget, useFenceSync, isControlledByApp),
+ sp<Surface>::make(igbp, isControlledByApp)};
+#endif
+}
+
+sp<GLConsumer> GLConsumer::create(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
+ uint32_t textureTarget, bool useFenceSync,
+ bool isControlledByApp) {
+ return sp<GLConsumer>::make(bq, tex, textureTarget, useFenceSync, isControlledByApp);
+}
+
+sp<GLConsumer> GLConsumer::create(const sp<IGraphicBufferConsumer>& bq, uint32_t textureTarget,
+ bool useFenceSync, bool isControlledByApp) {
+ return sp<GLConsumer>::make(bq, textureTarget, useFenceSync, isControlledByApp);
+}
+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
GLConsumer::GLConsumer(uint32_t tex, uint32_t texTarget, bool useFenceSync, bool isControlledByApp)
: ConsumerBase(isControlledByApp, /* isConsumerSurfaceFlinger */ false),
@@ -333,7 +378,7 @@
}
if (mReleasedTexImage == nullptr) {
- mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
+ mReleasedTexImage = sp<EglImage>::make(getDebugTexImageBuffer());
}
mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
@@ -365,10 +410,10 @@
if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) {
// The first time, create the debug texture in case the application
// continues to use it.
- sp<GraphicBuffer> buffer = new GraphicBuffer(
- kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
- DEFAULT_USAGE_FLAGS | GraphicBuffer::USAGE_SW_WRITE_RARELY,
- "[GLConsumer debug texture]");
+ sp<GraphicBuffer> buffer =
+ sp<GraphicBuffer>::make(kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888,
+ DEFAULT_USAGE_FLAGS | GraphicBuffer::USAGE_SW_WRITE_RARELY,
+ "[GLConsumer debug texture]");
uint32_t* bits;
buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits));
uint32_t stride = buffer->getStride();
@@ -400,7 +445,7 @@
// replaces any old EglImage with a new one (using the new buffer).
if (item->mGraphicBuffer != nullptr) {
int slot = item->mSlot;
- mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
+ mEglSlots[slot].mEglImage = sp<EglImage>::make(item->mGraphicBuffer);
}
return NO_ERROR;
@@ -737,7 +782,7 @@
"fd: %#x", eglGetError());
return UNKNOWN_ERROR;
}
- sp<Fence> fence(new Fence(fenceFd));
+ sp<Fence> fence = sp<Fence>::make(fenceFd);
status_t err = addReleaseFenceLocked(mCurrentTexture,
mCurrentTextureImage->graphicBuffer(), fence);
if (err != OK) {
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 9f71eb1..1d1910e 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -104,7 +104,7 @@
}
bool nonNull = reply.readInt32();
if (nonNull) {
- *buf = new GraphicBuffer();
+ *buf = sp<GraphicBuffer>::make();
result = reply.read(**buf);
if(result != NO_ERROR) {
(*buf).clear();
@@ -197,7 +197,7 @@
}
*buf = reply.readInt32();
- *fence = new Fence();
+ *fence = sp<Fence>::make();
result = reply.read(**fence);
if (result != NO_ERROR) {
fence->clear();
@@ -293,7 +293,7 @@
if (result == NO_ERROR) {
bool nonNull = reply.readInt32();
if (nonNull) {
- *outBuffer = new GraphicBuffer;
+ *outBuffer = sp<GraphicBuffer>::make();
result = reply.read(**outBuffer);
if (result != NO_ERROR) {
outBuffer->clear();
@@ -302,7 +302,7 @@
}
nonNull = reply.readInt32();
if (nonNull) {
- *outFence = new Fence;
+ *outFence = sp<Fence>::make();
result = reply.read(**outFence);
if (result != NO_ERROR) {
outBuffer->clear();
@@ -640,7 +640,7 @@
bool hasBuffer = reply.readBool();
sp<GraphicBuffer> buffer;
if (hasBuffer) {
- buffer = new GraphicBuffer();
+ buffer = sp<GraphicBuffer>::make();
result = reply.read(*buffer);
if (result == NO_ERROR) {
result = reply.read(outTransformMatrix, sizeof(float) * 16);
@@ -650,7 +650,7 @@
ALOGE("getLastQueuedBuffer failed to read buffer: %d", result);
return result;
}
- sp<Fence> fence(new Fence);
+ sp<Fence> fence = sp<Fence>::make();
result = reply.read(*fence);
if (result != NO_ERROR) {
ALOGE("getLastQueuedBuffer failed to read fence: %d", result);
@@ -687,7 +687,7 @@
}
sp<GraphicBuffer> buffer;
if (hasBuffer) {
- buffer = new GraphicBuffer();
+ buffer = sp<GraphicBuffer>::make();
result = reply.read(*buffer);
if (result == NO_ERROR) {
result = reply.read(*outRect);
@@ -700,7 +700,7 @@
ALOGE("getLastQueuedBuffer failed to read buffer: %d", result);
return result;
}
- sp<Fence> fence(new Fence);
+ sp<Fence> fence = sp<Fence>::make();
result = reply.read(*fence);
if (result != NO_ERROR) {
ALOGE("getLastQueuedBuffer failed to read fence: %d", result);
@@ -1232,7 +1232,7 @@
}
case ATTACH_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
- sp<GraphicBuffer> buffer = new GraphicBuffer();
+ sp<GraphicBuffer> buffer = sp<GraphicBuffer>::make();
status_t result = data.read(*buffer.get());
int slot = 0;
if (result == NO_ERROR) {
@@ -1250,7 +1250,7 @@
return result;
}
for (sp<GraphicBuffer>& buffer : buffers) {
- buffer = new GraphicBuffer();
+ buffer = sp<GraphicBuffer>::make();
result = data.read(*buffer.get());
if (result != NO_ERROR) {
return result;
@@ -1306,7 +1306,7 @@
case CANCEL_BUFFER: {
CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
int buf = data.readInt32();
- sp<Fence> fence = new Fence();
+ sp<Fence> fence = sp<Fence>::make();
status_t result = data.read(*fence.get());
if (result == NO_ERROR) {
result = cancelBuffer(buf, fence);
diff --git a/libs/gui/IGraphicBufferProducerFlattenables.cpp b/libs/gui/IGraphicBufferProducerFlattenables.cpp
index 8b2e2dd..393e1c3 100644
--- a/libs/gui/IGraphicBufferProducerFlattenables.cpp
+++ b/libs/gui/IGraphicBufferProducerFlattenables.cpp
@@ -105,7 +105,7 @@
: std::nullopt;
#endif // COM_ANDROID_GRAPHICS_LIBUI_FLAGS_APPLY_PICTURE_PROFILES
- fence = new Fence();
+ fence = sp<Fence>::make();
status_t result = fence->unflatten(buffer, size, fds, count);
if (result != NO_ERROR) {
return result;
@@ -228,7 +228,7 @@
FlattenableUtils::read(fBuffer, size, result);
int32_t isBufferNull = 0;
FlattenableUtils::read(fBuffer, size, isBufferNull);
- buffer = new GraphicBuffer();
+ buffer = sp<GraphicBuffer>::make();
if (!isBufferNull) {
status_t status = buffer->unflatten(fBuffer, size, fds, count);
if (status != NO_ERROR) {
@@ -323,7 +323,7 @@
FlattenableUtils::read(buffer, size, slot);
FlattenableUtils::read(buffer, size, bufferAge);
- fence = new Fence();
+ fence = sp<Fence>::make();
status_t status = fence->unflatten(buffer, size, fds, count);
if (status != NO_ERROR) {
return status;
@@ -395,7 +395,7 @@
FlattenableUtils::read(buffer, size, slot);
- fence = new Fence();
+ fence = sp<Fence>::make();
return fence->unflatten(buffer, size, fds, count);
}
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 83fc827..ed28e79 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -92,7 +92,7 @@
if (err != NO_ERROR) return err;
if (hasFence) {
- gpuCompositionDoneFence = new Fence();
+ gpuCompositionDoneFence = sp<Fence>::make();
err = input->read(*gpuCompositionDoneFence);
if (err != NO_ERROR) return err;
}
@@ -157,7 +157,7 @@
SAFE_PARCEL(input->readBool, &hasFence);
if (hasFence) {
- previousReleaseFence = new Fence();
+ previousReleaseFence = sp<Fence>::make();
SAFE_PARCEL(input->read, *previousReleaseFence);
}
bool hasTransformHint = false;
@@ -216,7 +216,7 @@
return err;
}
if (hasFence) {
- presentFence = new Fence();
+ presentFence = sp<Fence>::make();
err = input->read(*presentFence);
if (err != NO_ERROR) {
return err;
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index ebfc62f..43855da 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -684,7 +684,7 @@
}
if (other.what & eInputInfoChanged) {
what |= eInputInfoChanged;
- windowInfoHandle = new WindowInfoHandle(*other.windowInfoHandle);
+ windowInfoHandle = sp<WindowInfoHandle>::make(*other.windowInfoHandle);
}
if (other.what & eBackgroundColorChanged) {
what |= eBackgroundColorChanged;
@@ -1001,13 +1001,13 @@
bool tmpBool = false;
SAFE_PARCEL(input->readBool, &tmpBool);
if (tmpBool) {
- buffer = new GraphicBuffer();
+ buffer = sp<GraphicBuffer>::make();
SAFE_PARCEL(input->read, *buffer);
}
SAFE_PARCEL(input->readBool, &tmpBool);
if (tmpBool) {
- acquireFence = new Fence();
+ acquireFence = sp<Fence>::make();
SAFE_PARCEL(input->read, *acquireFence);
}
diff --git a/libs/gui/ScreenCaptureResults.cpp b/libs/gui/ScreenCaptureResults.cpp
index 2de023e..30b5785 100644
--- a/libs/gui/ScreenCaptureResults.cpp
+++ b/libs/gui/ScreenCaptureResults.cpp
@@ -18,6 +18,7 @@
#include <private/gui/ParcelUtils.h>
#include <ui/FenceResult.h>
+#include <ui/GraphicBuffer.h>
namespace android::gui {
@@ -54,7 +55,7 @@
bool hasGraphicBuffer;
SAFE_PARCEL(parcel->readBool, &hasGraphicBuffer);
if (hasGraphicBuffer) {
- buffer = new GraphicBuffer();
+ buffer = sp<GraphicBuffer>::make();
SAFE_PARCEL(parcel->read, *buffer);
}
@@ -79,7 +80,7 @@
bool hasGainmap;
SAFE_PARCEL(parcel->readBool, &hasGainmap);
if (hasGainmap) {
- optionalGainMap = new GraphicBuffer();
+ optionalGainMap = sp<GraphicBuffer>::make();
SAFE_PARCEL(parcel->read, *optionalGainMap);
}
SAFE_PARCEL(parcel->readFloat, &hdrSdrRatio);
diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp
index 653b91b..848ae7a 100644
--- a/libs/gui/StreamSplitter.cpp
+++ b/libs/gui/StreamSplitter.cpp
@@ -47,7 +47,7 @@
return BAD_VALUE;
}
- sp<StreamSplitter> splitter(new StreamSplitter(inputQueue));
+ sp<StreamSplitter> splitter = sp<StreamSplitter>::make(inputQueue);
status_t status = splitter->mInput->consumerConnect(splitter, false);
if (status == NO_ERROR) {
splitter->mInput->setConsumerName(String8("StreamSplitter"));
@@ -82,7 +82,7 @@
Mutex::Autolock lock(mMutex);
IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
- sp<OutputListener> listener(new OutputListener(this, outputQueue));
+ sp<OutputListener> listener = sp<OutputListener>::make(this, outputQueue);
IInterface::asBinder(outputQueue)->linkToDeath(listener);
status_t status = outputQueue->connect(listener, NATIVE_WINDOW_API_CPU,
/* producerControlledByApp */ false, &queueBufferOutput);
@@ -140,7 +140,7 @@
// Initialize our reference count for this buffer
mBuffers.add(bufferItem.mGraphicBuffer->getId(),
- new BufferTracker(bufferItem.mGraphicBuffer));
+ sp<BufferTracker>::make(bufferItem.mGraphicBuffer));
IGraphicBufferProducer::QueueBufferInput queueInput(
bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp,
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index ec23365..63dcfbc 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -509,7 +509,7 @@
if (result != OK) {
return result;
}
- sp<Fence> fence(new Fence(fenceFd));
+ sp<Fence> fence = sp<Fence>::make(fenceFd);
int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED");
if (waitResult != OK) {
ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d",
@@ -979,7 +979,7 @@
}
return OK;
}
- sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+ sp<Fence> fence(fenceFd >= 0 ? sp<Fence>::make(fenceFd) : Fence::NO_FENCE);
mGraphicBufferProducer->cancelBuffer(i, fence);
if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot == i) {
@@ -1017,7 +1017,7 @@
ALOGE("%s: cannot find slot number for cancelled buffer", __FUNCTION__);
badSlotResult = slot;
} else {
- sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+ sp<Fence> fence(fenceFd >= 0 ? sp<Fence>::make(fenceFd) : Fence::NO_FENCE);
cancelBufferInputs[numBuffersCancelled].slot = slot;
cancelBufferInputs[numBuffersCancelled++].fence = fence;
}
@@ -1078,7 +1078,7 @@
Rect crop(Rect::EMPTY_RECT);
mCrop.intersect(Rect(buffer->width, buffer->height), &crop);
- sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+ sp<Fence> fence(fenceFd >= 0 ? sp<Fence>::make(fenceFd) : Fence::NO_FENCE);
IGraphicBufferProducer::QueueBufferInput input(timestamp, isAutoTimestamp,
static_cast<android_dataspace>(mDataSpace), crop, mScalingMode,
mTransform ^ mStickyTransform, fence, mStickyTransform,
@@ -2092,7 +2092,7 @@
}
int Surface::connect(int api) {
- static sp<SurfaceListener> listener = new StubSurfaceListener();
+ static sp<SurfaceListener> listener = sp<StubSurfaceListener>::make();
return connect(api, listener);
}
@@ -2104,7 +2104,7 @@
mReportRemovedBuffers = reportBufferRemoval;
if (listener != nullptr) {
- mListenerProxy = new ProducerListenerProxy(this, listener);
+ mListenerProxy = sp<ProducerListenerProxy>::make(this, listener);
}
int err =
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 37ed23b..bb7184f 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -123,7 +123,7 @@
explicit DeathObserver(ComposerService& mgr) : mComposerService(mgr) { }
};
- mDeathObserver = new DeathObserver(*const_cast<ComposerService*>(this));
+ mDeathObserver = sp<DeathObserver>::make(*const_cast<ComposerService*>(this));
IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver);
return true;
}
@@ -170,7 +170,7 @@
explicit DeathObserver(ComposerServiceAIDL& mgr) : mComposerService(mgr) {}
};
- mDeathObserver = new DeathObserver(*const_cast<ComposerServiceAIDL*>(this));
+ mDeathObserver = sp<DeathObserver>::make(*const_cast<ComposerServiceAIDL*>(this));
IInterface::asBinder(mComposerService)->linkToDeath(mDeathObserver);
return true;
}
@@ -202,7 +202,7 @@
DefaultComposerClient& dc = DefaultComposerClient::getInstance();
Mutex::Autolock _l(dc.mLock);
if (dc.mClient == nullptr) {
- dc.mClient = new SurfaceComposerClient;
+ dc.mClient = sp<SurfaceComposerClient>::make();
}
return dc.mClient;
}
@@ -399,7 +399,7 @@
sp<TransactionCompletedListener> TransactionCompletedListener::getInstance() {
std::lock_guard<std::mutex> lock(sListenerInstanceMutex);
if (sInstance == nullptr) {
- sInstance = new TransactionCompletedListener;
+ sInstance = sp<TransactionCompletedListener>::make();
}
return sInstance;
}
@@ -691,7 +691,7 @@
std::scoped_lock<std::mutex> lock(mMutex);
mTrustedPresentationCallbacks[id] =
std::tuple<TrustedPresentationCallback, void*>(tpc, context);
- return new SurfaceComposerClient::PresentationCallbackRAII(this, id);
+ return sp<SurfaceComposerClient::PresentationCallbackRAII>::make(this, id);
}
void TransactionCompletedListener::clearTrustedPresentationCallback(int id) {
@@ -743,7 +743,7 @@
*/
class BufferCache : public Singleton<BufferCache> {
public:
- BufferCache() : token(new BBinder()) {}
+ BufferCache() : token(sp<BBinder>::make()) {}
sp<IBinder> getToken() {
return IInterface::asBinder(TransactionCompletedListener::getIInstance());
@@ -1357,7 +1357,7 @@
return binderStatus;
}
-sp<IBinder> SurfaceComposerClient::Transaction::sApplyToken = new BBinder();
+sp<IBinder> SurfaceComposerClient::Transaction::sApplyToken = sp<BBinder>::make();
std::mutex SurfaceComposerClient::Transaction::sApplyTokenMutex;
@@ -1953,9 +1953,9 @@
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setLuts(
- const sp<SurfaceControl>& sc, const base::unique_fd& lutFd,
- const std::vector<int32_t>& offsets, const std::vector<int32_t>& dimensions,
- const std::vector<int32_t>& sizes, const std::vector<int32_t>& samplingKeys) {
+ const sp<SurfaceControl>& sc, base::unique_fd&& lutFd, const std::vector<int32_t>& offsets,
+ const std::vector<int32_t>& dimensions, const std::vector<int32_t>& sizes,
+ const std::vector<int32_t>& samplingKeys) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
@@ -1964,8 +1964,8 @@
s->what |= layer_state_t::eLutsChanged;
if (lutFd.ok()) {
- s->luts = std::make_shared<gui::DisplayLuts>(base::unique_fd(dup(lutFd.get())), offsets,
- dimensions, sizes, samplingKeys);
+ s->luts = std::make_shared<gui::DisplayLuts>(std::move(lutFd), offsets, dimensions, sizes,
+ samplingKeys);
} else {
s->luts = nullptr;
}
@@ -2683,9 +2683,9 @@
}
ALOGE_IF(err, "SurfaceComposerClient::createSurface error %s", strerror(-err));
if (err == NO_ERROR) {
- *outSurface = new SurfaceControl(this, result.handle, result.layerId,
- toString(result.layerName), w, h, format,
- result.transformHint, flags);
+ *outSurface = sp<SurfaceControl>::make(this, result.handle, result.layerId,
+ toString(result.layerName), w, h, format,
+ result.transformHint, flags);
}
}
return err;
@@ -2701,7 +2701,8 @@
const binder::Status status = mClient->mirrorSurface(mirrorFromHandle, &result);
const status_t err = statusTFromBinderStatus(status);
if (err == NO_ERROR) {
- return new SurfaceControl(this, result.handle, result.layerId, toString(result.layerName));
+ return sp<SurfaceControl>::make(this, result.handle, result.layerId,
+ toString(result.layerName));
}
return nullptr;
}
@@ -2711,7 +2712,8 @@
const binder::Status status = mClient->mirrorDisplay(displayId.value, &result);
const status_t err = statusTFromBinderStatus(status);
if (err == NO_ERROR) {
- return new SurfaceControl(this, result.handle, result.layerId, toString(result.layerName));
+ return sp<SurfaceControl>::make(this, result.handle, result.layerId,
+ toString(result.layerName));
}
return nullptr;
}
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index b735418..1eb9b87 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -269,10 +269,11 @@
SAFE_PARCEL(parcel.readUint32, &format);
// We aren't the original owner of the surface.
- *outSurfaceControl = new SurfaceControl(new SurfaceComposerClient(
- interface_cast<ISurfaceComposerClient>(client)),
- handle.get(), layerId, layerName, width, height, format,
- transformHint);
+ *outSurfaceControl =
+ sp<SurfaceControl>::make(sp<SurfaceComposerClient>::make(
+ interface_cast<ISurfaceComposerClient>(client)),
+ handle, layerId, layerName, width, height, format,
+ transformHint);
return NO_ERROR;
}
diff --git a/libs/gui/TEST_MAPPING b/libs/gui/TEST_MAPPING
index a590c86..14d6df6 100644
--- a/libs/gui/TEST_MAPPING
+++ b/libs/gui/TEST_MAPPING
@@ -60,5 +60,34 @@
}
]
}
+ ],
+ "postsubmit": [
+ {
+ "name": "libgui_test",
+ "keywords": [ "primary-device" ],
+ "options": [
+ // TODO(b/397776630): Failing on real devices.
+ {
+ "exclude-filter": "InputSurfacesTest#input_respects_scaled_touchable_region_overflow"
+ },
+ // TODO(b/233363648): Failing on real devices.
+ {
+ "exclude-filter": "SurfaceTextureGLTest#TexturingFromCpuFilledYV12BufferNpot"
+ },
+ {
+ "exclude-filter": "SurfaceTextureGLTest#TexturingFromCpuFilledYV12BufferPow2"
+ },
+ {
+ "exclude-filter": "SurfaceTextureGLTest#TexturingFromCpuFilledYV12BufferWithCrop"
+ },
+ // TODO(b/233363648): Flaky on real devices.
+ {
+ "exclude-filter": "SurfaceTextureGLToGLTest#EglMakeCurrentBeforeConsumerDeathUnrefsBuffers"
+ },
+ {
+ "exclude-filter": "SurfaceTextureGLToGLTest#EglMakeCurrentAfterConsumerDeathUnrefsBuffers"
+ }
+ ]
+ }
]
}
diff --git a/libs/gui/WindowInfosListenerReporter.cpp b/libs/gui/WindowInfosListenerReporter.cpp
index 91c9a85..d633f9f 100644
--- a/libs/gui/WindowInfosListenerReporter.cpp
+++ b/libs/gui/WindowInfosListenerReporter.cpp
@@ -15,6 +15,7 @@
*/
#include <android/gui/ISurfaceComposer.h>
+#include <android/gui/IWindowInfosListener.h>
#include <gui/AidlUtil.h>
#include <gui/WindowInfosListenerReporter.h>
#include "gui/WindowInfosUpdate.h"
@@ -27,7 +28,7 @@
using gui::aidl_utils::statusTFromBinderStatus;
sp<WindowInfosListenerReporter> WindowInfosListenerReporter::getInstance() {
- static sp<WindowInfosListenerReporter> sInstance = new WindowInfosListenerReporter;
+ static sp<WindowInfosListenerReporter> sInstance = sp<WindowInfosListenerReporter>::make();
return sInstance;
}
@@ -116,7 +117,8 @@
std::scoped_lock lock(mListenersMutex);
if (!mWindowInfosListeners.empty()) {
gui::WindowInfosListenerInfo listenerInfo;
- composerService->addWindowInfosListener(this, &listenerInfo);
+ composerService->addWindowInfosListener(sp<gui::IWindowInfosListener>::fromExisting(this),
+ &listenerInfo);
mWindowInfosPublisher = std::move(listenerInfo.windowInfosPublisher);
mListenerId = listenerInfo.listenerId;
}
diff --git a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
index fd8ffe1..b1a23b3 100644
--- a/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/1.0/H2BGraphicBufferProducer.cpp
@@ -971,7 +971,7 @@
// H2BGraphicBufferProducer
status_t H2BGraphicBufferProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
- *buf = new GraphicBuffer();
+ *buf = sp<GraphicBuffer>::make();
status_t fnStatus;
status_t transStatus = toStatusT(mBase->requestBuffer(
static_cast<int32_t>(slot),
@@ -999,7 +999,7 @@
uint32_t h, ::android::PixelFormat format,
uint64_t usage, uint64_t* outBufferAge,
FrameEventHistoryDelta* outTimestamps) {
- *fence = new Fence();
+ *fence = sp<Fence>::make();
status_t fnStatus;
status_t transStatus = toStatusT(mBase->dequeueBuffer(
w, h, static_cast<PixelFormat>(format), uint32_t(usage),
@@ -1035,8 +1035,8 @@
status_t H2BGraphicBufferProducer::detachNextBuffer(
sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
- *outBuffer = new GraphicBuffer();
- *outFence = new Fence();
+ *outBuffer = sp<GraphicBuffer>::make();
+ *outFence = sp<Fence>::make();
status_t fnStatus;
status_t transStatus = toStatusT(mBase->detachNextBuffer(
[&fnStatus, outBuffer, outFence] (
@@ -1127,8 +1127,8 @@
status_t H2BGraphicBufferProducer::connect(
const sp<IProducerListener>& listener, int api,
bool producerControlledByApp, QueueBufferOutput* output) {
- sp<HProducerListener> tListener = listener == nullptr ?
- nullptr : new B2HProducerListener(listener);
+ sp<HProducerListener> tListener =
+ listener == nullptr ? nullptr : sp<B2HProducerListener>::make(listener);
status_t fnStatus;
status_t transStatus = toStatusT(mBase->connect(
tListener, static_cast<int32_t>(api), producerControlledByApp,
@@ -1205,13 +1205,13 @@
hidl_handle const& fence,
hidl_array<float, 16> const& transformMatrix) {
fnStatus = toStatusT(status);
- *outBuffer = new GraphicBuffer();
+ *outBuffer = sp<GraphicBuffer>::make();
if (!convertTo(outBuffer->get(), buffer)) {
ALOGE("H2BGraphicBufferProducer::getLastQueuedBuffer - "
"Invalid output buffer");
fnStatus = fnStatus == NO_ERROR ? BAD_VALUE : fnStatus;
}
- *outFence = new Fence();
+ *outFence = sp<Fence>::make();
if (!convertTo(outFence->get(), fence)) {
ALOGE("H2BGraphicBufferProducer::getLastQueuedBuffer - "
"Invalid output fence");
diff --git a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
index c76d771..4384bd5 100644
--- a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
@@ -272,7 +272,7 @@
HConnectionType hConnectionType,
bool producerControlledByApp,
connect_cb _hidl_cb) {
- sp<BProducerListener> bListener = new H2BProducerListener(hListener);
+ sp<BProducerListener> bListener = sp<H2BProducerListener>::make(hListener);
int bConnectionType{};
if (!bListener || !h2b(hConnectionType, &bConnectionType)) {
_hidl_cb(HStatus::UNKNOWN_ERROR, QueueBufferOutput{});
diff --git a/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp
index ae00a26..7121bb7 100644
--- a/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp
+++ b/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp
@@ -325,7 +325,7 @@
}
sp<HProducerListener> hListener = nullptr;
if (listener && listener->needsReleaseNotify()) {
- hListener = new B2HProducerListener(listener);
+ hListener = sp<B2HProducerListener>::make(listener);
if (!hListener) {
LOG(ERROR) << "connect: failed to wrap listener.";
return UNKNOWN_ERROR;
diff --git a/libs/gui/bufferqueue/2.0/types.cpp b/libs/gui/bufferqueue/2.0/types.cpp
index cbd6cad..c245766 100644
--- a/libs/gui/bufferqueue/2.0/types.cpp
+++ b/libs/gui/bufferqueue/2.0/types.cpp
@@ -147,13 +147,13 @@
bool h2b(native_handle_t const* from, sp<BFence>* to) {
if (!from || from->numFds == 0) {
- *to = new ::android::Fence();
+ *to = sp<::android::Fence>::make();
return true;
}
if (from->numFds != 1 || from->numInts != 0) {
return false;
}
- *to = new BFence(dup(from->data[0]));
+ *to = sp<BFence>::make(dup(from->data[0]));
return true;
}
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index cdc2150..db1b9fb 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -46,21 +46,6 @@
class BLASTBufferItemConsumer : public BufferItemConsumer {
public:
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- BLASTBufferItemConsumer(const sp<IGraphicBufferProducer>& producer,
- const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
- int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq)
- : BufferItemConsumer(producer, consumer, consumerUsage, bufferCount, controlledByApp),
-#else
- BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
- int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq)
- : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
-#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- mBLASTBufferQueue(std::move(bbq)),
- mCurrentlyConnected(false),
- mPreviouslyConnected(false) {
- }
-
void onDisconnect() override EXCLUDES(mMutex);
void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) override EXCLUDES(mMutex);
@@ -81,6 +66,23 @@
#endif
private:
+#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ BLASTBufferItemConsumer(const sp<IGraphicBufferProducer>& producer,
+ const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
+ int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq)
+ : BufferItemConsumer(producer, consumer, consumerUsage, bufferCount, controlledByApp),
+#else
+ BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
+ int bufferCount, bool controlledByApp, wp<BLASTBufferQueue> bbq)
+ : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
+#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ mBLASTBufferQueue(std::move(bbq)),
+ mCurrentlyConnected(false),
+ mPreviouslyConnected(false) {
+ }
+
+ friend class sp<BLASTBufferItemConsumer>;
+
const wp<BLASTBufferQueue> mBLASTBufferQueue;
uint64_t mCurrentFrameNumber GUARDED_BY(mMutex) = 0;
@@ -94,8 +96,6 @@
class BLASTBufferQueue : public ConsumerBase::FrameAvailableListener {
public:
- BLASTBufferQueue(const std::string& name, bool updateDestinationFrame = true);
-
sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
return mProducer;
}
@@ -158,8 +158,13 @@
void onFirstRef() override;
private:
+ // Not public to ensure construction via sp<>::make().
+ BLASTBufferQueue(const std::string& name, bool updateDestinationFrame = true);
+
+ friend class sp<BLASTBufferQueue>;
friend class BLASTBufferQueueHelper;
friend class BBQBufferQueueProducer;
+ friend class TestBLASTBufferQueue;
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(BUFFER_RELEASE_CHANNEL)
friend class BBQBufferQueueCore;
#endif
diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h
index 6810eda..0bfa7b2 100644
--- a/libs/gui/include/gui/BufferItemConsumer.h
+++ b/libs/gui/include/gui/BufferItemConsumer.h
@@ -47,6 +47,16 @@
enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT };
enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE };
+ static std::tuple<sp<BufferItemConsumer>, sp<Surface>> create(
+ uint64_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS,
+ bool controlledByApp = false, bool isConsumerSurfaceFlinger = false);
+
+ static sp<BufferItemConsumer> create(const sp<IGraphicBufferConsumer>& consumer,
+ uint64_t consumerUsage,
+ int bufferCount = DEFAULT_MAX_BUFFERS,
+ bool controlledByApp = false)
+ __attribute((deprecated("Prefer ctors that create their own surface and consumer.")));
+
// Create a new buffer item consumer. The consumerUsage parameter determines
// the consumer usage flags passed to the graphics allocator. The
// bufferCount parameter specifies how many buffers can be locked for user
diff --git a/libs/gui/include/gui/Choreographer.h b/libs/gui/include/gui/Choreographer.h
index a93ba14..5862967 100644
--- a/libs/gui/include/gui/Choreographer.h
+++ b/libs/gui/include/gui/Choreographer.h
@@ -103,7 +103,7 @@
virtual void handleMessage(const Message& message) override;
static void initJVM(JNIEnv* env);
- static Choreographer* getForThread();
+ static sp<Choreographer> getForThread();
static void signalRefreshRateCallbacks(nsecs_t vsyncPeriod) EXCLUDES(gChoreographers.lock);
static int64_t getStartTimeNanosForVsyncId(AVsyncId vsyncId) EXCLUDES(gChoreographers.lock);
virtual ~Choreographer() override EXCLUDES(gChoreographers.lock);
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index 2e347c9..fd67f09 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -123,9 +123,7 @@
// See IGraphicBufferConsumer::setMaxAcquiredBufferCount
status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
status_t setConsumerIsProtected(bool isProtected);
-#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
// See IGraphicBufferConsumer::getSidebandStream
sp<NativeHandle> getSidebandStream() const;
@@ -141,7 +139,8 @@
ConsumerBase(const ConsumerBase&);
void operator=(const ConsumerBase&);
- void initialize(bool controlledByApp);
+ // Requires `this` to be sp/wp so must not be called from ctor.
+ void initialize();
protected:
// ConsumerBase constructs a new ConsumerBase object to consume image
@@ -254,6 +253,10 @@
const sp<GraphicBuffer> graphicBuffer,
EGLDisplay display = EGL_NO_DISPLAY, EGLSyncKHR eglFence = EGL_NO_SYNC_KHR);
#endif
+ // Required to complete initialization, so `final` lest overrides forget to
+ // delegate.
+ void onFirstRef() override final;
+
// returns true iff the slot still has the graphicBuffer in it.
bool stillTracking(int slot, const sp<GraphicBuffer> graphicBuffer);
@@ -329,6 +332,8 @@
// releaseBufferLocked.
sp<Fence> mPrevFinalReleaseFence;
+ const bool mIsControlledByApp;
+
// mMutex is the mutex used to prevent concurrent access to the member
// variables of ConsumerBase objects. It must be locked whenever the
// member variables are accessed or when any of the *Locked methods are
diff --git a/libs/gui/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h
index 2bba61b..995cdfb 100644
--- a/libs/gui/include/gui/CpuConsumer.h
+++ b/libs/gui/include/gui/CpuConsumer.h
@@ -31,6 +31,7 @@
class BufferQueue;
class GraphicBuffer;
class String8;
+class Surface;
/**
* CpuConsumer is a BufferQueue consumer endpoint that allows direct CPU
@@ -92,6 +93,13 @@
// Create a new CPU consumer. The maxLockedBuffers parameter specifies
// how many buffers can be locked for user access at the same time.
+ static std::tuple<sp<CpuConsumer>, sp<Surface>> create(size_t maxLockedBuffers,
+ bool controlledByApp = false,
+ bool isConsumerSurfaceFlinger = false);
+ static sp<CpuConsumer> create(const sp<IGraphicBufferConsumer>& bq, size_t maxLockedBuffers,
+ bool controlledByApp = false)
+ __attribute((deprecated("Prefer ctors that create their own surface and consumer.")));
+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
CpuConsumer(size_t maxLockedBuffers, bool controlledByApp = false,
bool isConsumerSurfaceFlinger = false);
@@ -100,8 +108,8 @@
bool controlledByApp = false)
__attribute((deprecated("Prefer ctors that create their own surface and consumer.")));
#else
- CpuConsumer(const sp<IGraphicBufferConsumer>& bq,
- size_t maxLockedBuffers, bool controlledByApp = false);
+ CpuConsumer(const sp<IGraphicBufferConsumer>& bq, size_t maxLockedBuffers,
+ bool controlledByApp = false);
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
// Gets the next graphics buffer from the producer and locks it for CPU use,
diff --git a/libs/gui/include/gui/DisplayLuts.h b/libs/gui/include/gui/DisplayLuts.h
index ab86ac4..187381c 100644
--- a/libs/gui/include/gui/DisplayLuts.h
+++ b/libs/gui/include/gui/DisplayLuts.h
@@ -18,6 +18,10 @@
#include <android-base/unique_fd.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
+#include <cutils/ashmem.h>
+#include <sys/mman.h>
+#include <algorithm>
+#include <ostream>
#include <vector>
namespace android::gui {
@@ -62,4 +66,99 @@
base::unique_fd fd;
}; // struct DisplayLuts
+static inline void PrintTo(const std::vector<int32_t>& offsets, ::std::ostream* os) {
+ *os << "\n .offsets = {";
+ for (size_t i = 0; i < offsets.size(); i++) {
+ *os << offsets[i];
+ if (i != offsets.size() - 1) {
+ *os << ", ";
+ }
+ }
+ *os << "}";
+}
+
+static inline void PrintTo(const std::vector<DisplayLuts::Entry>& entries, ::std::ostream* os) {
+ *os << "\n .lutProperties = {\n";
+ for (auto& [dimension, size, samplingKey] : entries) {
+ *os << " Entry{"
+ << "dimension: " << dimension << ", size: " << size << ", samplingKey: " << samplingKey
+ << "}\n";
+ }
+ *os << " }";
+}
+
+static constexpr size_t kMaxPrintCount = 100;
+
+static inline void PrintTo(const std::vector<float>& buffer, size_t offset, int32_t dimension,
+ size_t size, ::std::ostream* os) {
+ size_t range = std::min(size, kMaxPrintCount);
+ *os << "{";
+ if (dimension == 1) {
+ for (size_t i = 0; i < range; i++) {
+ *os << buffer[offset + i];
+ if (i != range - 1) {
+ *os << ", ";
+ }
+ }
+ } else {
+ *os << "\n {R channel:";
+ for (size_t i = 0; i < range; i++) {
+ *os << buffer[offset + i];
+ if (i != range - 1) {
+ *os << ", ";
+ }
+ }
+ *os << "}\n {G channel:";
+ for (size_t i = 0; i < range; i++) {
+ *os << buffer[offset + size + i];
+ if (i != range - 1) {
+ *os << ", ";
+ }
+ }
+ *os << "}\n {B channel:";
+ for (size_t i = 0; i < range; i++) {
+ *os << buffer[offset + 2 * size + i];
+ if (i != range - 1) {
+ *os << ", ";
+ }
+ }
+ }
+ *os << "}";
+}
+
+static inline void PrintTo(const std::shared_ptr<DisplayLuts> luts, ::std::ostream* os) {
+ *os << "gui::DisplayLuts {";
+ auto& fd = luts->getLutFileDescriptor();
+ *os << "\n .pfd = " << fd.get();
+ if (fd.ok()) {
+ PrintTo(luts->offsets, os);
+ PrintTo(luts->lutProperties, os);
+ // decode luts
+ int32_t fullLength = luts->offsets[luts->offsets.size() - 1];
+ if (luts->lutProperties[luts->offsets.size() - 1].dimension == 1) {
+ fullLength += luts->lutProperties[luts->offsets.size() - 1].size;
+ } else {
+ fullLength += (luts->lutProperties[luts->offsets.size() - 1].size *
+ luts->lutProperties[luts->offsets.size() - 1].size *
+ luts->lutProperties[luts->offsets.size() - 1].size * 3);
+ }
+ size_t bufferSize = static_cast<size_t>(fullLength) * sizeof(float);
+ float* ptr = (float*)mmap(NULL, bufferSize, PROT_READ, MAP_SHARED, fd.get(), 0);
+ if (ptr == MAP_FAILED) {
+ *os << "\n .bufferdata cannot mmap!";
+ return;
+ }
+ std::vector<float> buffers(ptr, ptr + fullLength);
+ munmap(ptr, bufferSize);
+
+ *os << "\n .bufferdata = ";
+ for (size_t i = 0; i < luts->offsets.size(); i++) {
+ PrintTo(buffers, static_cast<size_t>(luts->offsets[i]),
+ luts->lutProperties[i].dimension,
+ static_cast<size_t>(luts->lutProperties[i].size), os);
+ }
+ }
+ *os << "\n }";
+}
+
} // namespace android::gui
\ No newline at end of file
diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
index dbf707f..254d8ac 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -83,6 +83,20 @@
// If the constructor without the tex parameter is used, the GLConsumer is
// created in a detached state, and attachToContext must be called before
// calls to updateTexImage.
+ static std::tuple<sp<GLConsumer>, sp<Surface>> create(uint32_t tex, uint32_t textureTarget,
+ bool useFenceSync,
+ bool isControlledByApp);
+ static std::tuple<sp<GLConsumer>, sp<Surface>> create(uint32_t textureTarget, bool useFenceSync,
+ bool isControlledByApp);
+ static sp<GLConsumer> create(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
+ uint32_t textureTarget, bool useFenceSync, bool isControlledByApp)
+ __attribute((deprecated(
+ "Prefer create functions that create their own surface and consumer.")));
+ static sp<GLConsumer> create(const sp<IGraphicBufferConsumer>& bq, uint32_t textureTarget,
+ bool useFenceSync, bool isControlledByApp)
+ __attribute((deprecated(
+ "Prefer create functions that create their own surface and consumer.")));
+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
GLConsumer(uint32_t tex, uint32_t textureTarget, bool useFenceSync, bool isControlledByApp);
diff --git a/libs/gui/include/gui/StreamSplitter.h b/libs/gui/include/gui/StreamSplitter.h
index 28237b6..8176f75 100644
--- a/libs/gui/include/gui/StreamSplitter.h
+++ b/libs/gui/include/gui/StreamSplitter.h
@@ -153,6 +153,8 @@
size_t mReleaseCount;
};
+ friend class sp<StreamSplitter>;
+
// Only called from createSplitter
explicit StreamSplitter(const sp<IGraphicBufferConsumer>& inputQueue);
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 10225cc..60f16ae 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -620,7 +620,7 @@
Transaction& setExtendedRangeBrightness(const sp<SurfaceControl>& sc,
float currentBufferRatio, float desiredRatio);
Transaction& setDesiredHdrHeadroom(const sp<SurfaceControl>& sc, float desiredRatio);
- Transaction& setLuts(const sp<SurfaceControl>& sc, const base::unique_fd& lutFd,
+ Transaction& setLuts(const sp<SurfaceControl>& sc, base::unique_fd&& lutFd,
const std::vector<int32_t>& offsets,
const std::vector<int32_t>& dimensions,
const std::vector<int32_t>& sizes,
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index e6ee89f..b861c6d 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -114,8 +114,8 @@
class BLASTBufferQueueHelper {
public:
BLASTBufferQueueHelper(const sp<SurfaceControl>& sc, int width, int height) {
- mBlastBufferQueueAdapter = new TestBLASTBufferQueue("TestBLASTBufferQueue", sc, width,
- height, PIXEL_FORMAT_RGBA_8888);
+ mBlastBufferQueueAdapter = sp<TestBLASTBufferQueue>::make("TestBLASTBufferQueue", sc, width,
+ height, PIXEL_FORMAT_RGBA_8888);
}
void update(const sp<SurfaceControl>& sc, int width, int height) {
diff --git a/libs/gui/tests/BufferItemConsumer_test.cpp b/libs/gui/tests/BufferItemConsumer_test.cpp
index 6453885..b980f88 100644
--- a/libs/gui/tests/BufferItemConsumer_test.cpp
+++ b/libs/gui/tests/BufferItemConsumer_test.cpp
@@ -62,14 +62,15 @@
void SetUp() override {
mBuffers.resize(BufferQueueDefs::NUM_BUFFER_SLOTS);
- mBIC = new BufferItemConsumer(kUsage, kMaxLockedBuffers, true);
+ sp<Surface> surface;
+ std::tie(mBIC, surface) = BufferItemConsumer::create(kUsage, kMaxLockedBuffers, true);
String8 name("BufferItemConsumer_Under_Test");
mBIC->setName(name);
mBFL = new BufferFreedListener(this);
mBIC->setBufferFreedListener(mBFL);
sp<IProducerListener> producerListener = new TrackingProducerListener(this);
- mProducer = mBIC->getSurface()->getIGraphicBufferProducer();
+ mProducer = surface->getIGraphicBufferProducer();
IGraphicBufferProducer::QueueBufferOutput bufferOutput;
ASSERT_EQ(NO_ERROR,
mProducer->connect(producerListener, NATIVE_WINDOW_API_CPU,
diff --git a/libs/gui/tests/Choreographer_test.cpp b/libs/gui/tests/Choreographer_test.cpp
index 8db48d2..314dea6 100644
--- a/libs/gui/tests/Choreographer_test.cpp
+++ b/libs/gui/tests/Choreographer_test.cpp
@@ -50,7 +50,7 @@
TEST_F(ChoreographerTest, InputCallbackBeforeAnimation) {
sp<Looper> looper = Looper::prepare(0);
- Choreographer* choreographer = Choreographer::getForThread();
+ sp<Choreographer> choreographer = Choreographer::getForThread();
VsyncCallback animationCb;
choreographer->postFrameCallbackDelayed(nullptr, nullptr, vsyncCallback, &animationCb, 0,
CALLBACK_ANIMATION);
@@ -83,4 +83,4 @@
animationCb.frameTime.count());
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 9476930..482cfde 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -66,10 +66,9 @@
test_info->name(),
params.width, params.height,
params.maxLockedBuffers, params.format);
- mCC = new CpuConsumer(params.maxLockedBuffers);
+ std::tie(mCC, mSTC) = CpuConsumer::create(params.maxLockedBuffers);
String8 name("CpuConsumer_Under_Test");
mCC->setName(name);
- mSTC = mCC->getSurface();
mANW = mSTC;
}
diff --git a/libs/gui/tests/MultiTextureConsumer_test.cpp b/libs/gui/tests/MultiTextureConsumer_test.cpp
index 2428bb3..7ae6f40 100644
--- a/libs/gui/tests/MultiTextureConsumer_test.cpp
+++ b/libs/gui/tests/MultiTextureConsumer_test.cpp
@@ -34,8 +34,8 @@
virtual void SetUp() {
GLTest::SetUp();
- mGlConsumer = new GLConsumer(TEX_ID, GLConsumer::TEXTURE_EXTERNAL, true, false);
- mSurface = mGlConsumer->getSurface();
+ std::tie(mGlConsumer, mSurface) =
+ GLConsumer::create(TEX_ID, GLConsumer::TEXTURE_EXTERNAL, true, false);
mANW = mSurface.get();
}
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 59d05b6..d3434ea 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -40,8 +40,7 @@
}
virtual void SetUp() {
- mST = new GLConsumer(123, GLConsumer::TEXTURE_EXTERNAL, true, false);
- mSTC = mST->getSurface();
+ std::tie(mST, mSTC) = GLConsumer::create(123, GLConsumer::TEXTURE_EXTERNAL, true, false);
mANW = mSTC;
// We need a valid GL context so we can test updateTexImage()
@@ -727,8 +726,7 @@
ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
- sp<GLConsumer> st(new GLConsumer(i, GLConsumer::TEXTURE_EXTERNAL, true, false));
- sp<Surface> stc = st->getSurface();
+ auto [st, stc] = GLConsumer::create(i, GLConsumer::TEXTURE_EXTERNAL, true, false);
mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig,
static_cast<ANativeWindow*>(stc.get()), nullptr);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
diff --git a/libs/gui/tests/SurfaceTextureGL.h b/libs/gui/tests/SurfaceTextureGL.h
index 1309635..eb31cd1 100644
--- a/libs/gui/tests/SurfaceTextureGL.h
+++ b/libs/gui/tests/SurfaceTextureGL.h
@@ -38,8 +38,7 @@
void SetUp() {
GLTest::SetUp();
- mST = new GLConsumer(TEX_ID, GLConsumer::TEXTURE_EXTERNAL, true, false);
- mSTC = mST->getSurface();
+ std::tie(mST, mSTC) = GLConsumer::create(TEX_ID, GLConsumer::TEXTURE_EXTERNAL, true, false);
mANW = mSTC;
ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(), TEST_PRODUCER_USAGE_BITS));
mTextureRenderer = new TextureRenderer(TEX_ID, mST);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 98d1329..eb55e3b 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -294,9 +294,7 @@
TEST_F(SurfaceTest, QueryConsumerUsage) {
const int TEST_USAGE_FLAGS =
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_RENDER;
- sp<BufferItemConsumer> c = new BufferItemConsumer(TEST_USAGE_FLAGS);
-
- sp<Surface> s = c->getSurface();
+ auto [c, s] = BufferItemConsumer::create(TEST_USAGE_FLAGS);
sp<ANativeWindow> anw(s);
int flags = -1;
@@ -309,10 +307,8 @@
TEST_F(SurfaceTest, QueryDefaultBuffersDataSpace) {
const android_dataspace TEST_DATASPACE = HAL_DATASPACE_V0_SRGB;
- sp<CpuConsumer> cpuConsumer = new CpuConsumer(1);
+ auto [cpuConsumer, s] = CpuConsumer::create(1);
cpuConsumer->setDefaultBufferDataSpace(TEST_DATASPACE);
-
- sp<Surface> s = cpuConsumer->getSurface();
sp<ANativeWindow> anw(s);
android_dataspace dataSpace;
@@ -325,8 +321,7 @@
}
TEST_F(SurfaceTest, SettingGenerationNumber) {
- sp<CpuConsumer> cpuConsumer = new CpuConsumer(1);
- sp<Surface> surface = cpuConsumer->getSurface();
+ auto [cpuConsumer, surface] = CpuConsumer::create(1);
sp<ANativeWindow> window(surface);
// Allocate a buffer with a generation number of 0
@@ -2180,8 +2175,7 @@
const int BUFFER_COUNT = 16;
const int BATCH_SIZE = 8;
- sp<CpuConsumer> cpuConsumer = new CpuConsumer(1);
- sp<Surface> surface = cpuConsumer->getSurface();
+ auto [cpuConsumer, surface] = CpuConsumer::create(1);
sp<ANativeWindow> window(surface);
sp<StubSurfaceListener> listener = new StubSurfaceListener();
@@ -2229,8 +2223,7 @@
const int BUFFER_COUNT = 16;
const int BATCH_SIZE = 8;
- sp<CpuConsumer> cpuConsumer = new CpuConsumer(1);
- sp<Surface> surface = cpuConsumer->getSurface();
+ auto [cpuConsumer, surface] = CpuConsumer::create(1);
sp<ANativeWindow> window(surface);
sp<StubSurfaceListener> listener = new StubSurfaceListener();
@@ -2377,8 +2370,7 @@
sp<IGraphicBufferConsumer> bqConsumer;
BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
- sp<BufferItemConsumer> consumer = sp<BufferItemConsumer>::make(bqConsumer, 3);
- sp<Surface> surface = sp<Surface>::make(bqProducer);
+ auto [consumer, surface] = BufferItemConsumer::create(3);
sp<ImmediateReleaseConsumerListener> consumerListener =
sp<ImmediateReleaseConsumerListener>::make(consumer);
consumer->setFrameAvailableListener(consumerListener);
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 65a088e..155ea00 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -284,6 +284,36 @@
return false;
}
+bool isStylusHoverEvent(uint32_t source, const std::vector<PointerProperties>& properties,
+ int32_t action) {
+ return isStylusEvent(source, properties) && isHoverAction(action);
+}
+
+bool isFromMouse(uint32_t source, ToolType toolType) {
+ return isFromSource(source, AINPUT_SOURCE_MOUSE) && toolType == ToolType::MOUSE;
+}
+
+bool isFromTouchpad(uint32_t source, ToolType toolType) {
+ return isFromSource(source, AINPUT_SOURCE_MOUSE) && toolType == ToolType::FINGER;
+}
+
+bool isFromDrawingTablet(uint32_t source, ToolType toolType) {
+ return isFromSource(source, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS) &&
+ isStylusToolType(toolType);
+}
+
+bool isHoverAction(int32_t action) {
+ return action == AMOTION_EVENT_ACTION_HOVER_ENTER ||
+ action == AMOTION_EVENT_ACTION_HOVER_MOVE || action == AMOTION_EVENT_ACTION_HOVER_EXIT;
+}
+
+bool isMouseOrTouchpad(uint32_t sources) {
+ // Check if this is a mouse or touchpad, but not a drawing tablet.
+ return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) ||
+ (isFromSource(sources, AINPUT_SOURCE_MOUSE) &&
+ !isFromSource(sources, AINPUT_SOURCE_STYLUS));
+}
+
VerifiedKeyEvent verifiedKeyEventFromKeyEvent(const KeyEvent& event) {
return {{VerifiedInputEvent::Type::KEY, event.getDeviceId(), event.getEventTime(),
event.getSource(), event.getDisplayId()},
diff --git a/libs/input/InputFlags.cpp b/libs/input/InputFlags.cpp
index 555b138..f866f9b 100644
--- a/libs/input/InputFlags.cpp
+++ b/libs/input/InputFlags.cpp
@@ -39,4 +39,9 @@
return com::android::input::flags::connected_displays_cursor();
}
+bool InputFlags::connectedDisplaysCursorAndAssociatedDisplayCursorBugfixEnabled() {
+ return connectedDisplaysCursorEnabled() &&
+ com::android::input::flags::connected_displays_associated_display_cursor_bugfix();
+}
+
} // namespace android
\ No newline at end of file
diff --git a/libs/input/input_flags.aconfig b/libs/input/input_flags.aconfig
index 5bb30db..9d387fe 100644
--- a/libs/input/input_flags.aconfig
+++ b/libs/input/input_flags.aconfig
@@ -61,13 +61,6 @@
}
flag {
- name: "report_palms_to_gestures_library"
- namespace: "input"
- description: "Report touches marked as palm by firmware to gestures library"
- bug: "302505955"
-}
-
-flag {
name: "enable_touchpad_typing_palm_rejection"
namespace: "input"
description: "Enabling additional touchpad palm rejection will disable the tap to click while the user is typing on a physical keyboard"
@@ -239,6 +232,16 @@
}
flag {
+ name: "connected_displays_associated_display_cursor_bugfix"
+ namespace: "lse_desktop_experience"
+ description: "Apply some rules to define associated display cursor behavior in connected displays"
+ bug: "396568321"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "use_cloned_screen_coordinates_as_raw"
namespace: "input"
description: "Use the cloned window's layer stack (screen) space as the raw coordinate space for input going to clones"
diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs
index 7638559..ee999f7 100644
--- a/libs/input/rust/lib.rs
+++ b/libs/input/rust/lib.rs
@@ -133,6 +133,12 @@
flags: u32,
button_state: u32,
) -> String {
+ let Some(converted_source) = Source::from_bits(source) else {
+ panic!(
+ "The conversion of source 0x{source:08x} failed, please check if some sources have not \
+ been added to Source."
+ );
+ };
let Some(motion_flags) = MotionFlags::from_bits(flags) else {
panic!(
"The conversion of flags 0x{:08x} failed, please check if some flags have not been \
@@ -167,7 +173,7 @@
}
let result = verifier.process_movement(NotifyMotionArgs {
device_id: DeviceId(device_id),
- source: Source::from_bits(source).unwrap(),
+ source: converted_source,
action: motion_action,
pointer_properties,
flags: motion_flags,
diff --git a/libs/math/OWNERS b/libs/math/OWNERS
index 82ae422..08f0c5f 100644
--- a/libs/math/OWNERS
+++ b/libs/math/OWNERS
@@ -1,5 +1,4 @@
mathias@google.com
-randolphs@google.com
romainguy@google.com
sumir@google.com
jreck@google.com
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index bed31e2..89a97de 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -142,7 +142,7 @@
}
AChoreographer* AChoreographer_getInstance() {
- return Choreographer_to_AChoreographer(Choreographer::getForThread());
+ return Choreographer_to_AChoreographer(Choreographer::getForThread().get());
}
void AChoreographer_postFrameCallback(AChoreographer* choreographer,
@@ -238,13 +238,17 @@
}
AChoreographer* AChoreographer_create() {
- Choreographer* choreographer = new Choreographer(nullptr);
+ // Increments default strongRef count on construction, will be decremented on
+ // function exit.
+ auto choreographer = sp<Choreographer>::make(nullptr);
status_t result = choreographer->initialize();
if (result != OK) {
ALOGW("Failed to initialize");
return nullptr;
}
- return Choreographer_to_AChoreographer(choreographer);
+ // Will be decremented and destroyed by AChoreographer_destroy
+ choreographer->incStrong((void*)AChoreographer_create);
+ return Choreographer_to_AChoreographer(choreographer.get());
}
void AChoreographer_destroy(AChoreographer* choreographer) {
@@ -252,7 +256,7 @@
return;
}
- delete AChoreographer_to_Choreographer(choreographer);
+ AChoreographer_to_Choreographer(choreographer)->decStrong((void*)AChoreographer_create);
}
int AChoreographer_getFd(const AChoreographer* choreographer) {
diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp
index 937ff02..51d0c81 100644
--- a/libs/nativewindow/tests/ANativeWindowTest.cpp
+++ b/libs/nativewindow/tests/ANativeWindowTest.cpp
@@ -50,14 +50,9 @@
const ::testing::TestInfo* const test_info =
::testing::UnitTest::GetInstance()->current_test_info();
ALOGV("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- mItemConsumer = new BufferItemConsumer(GRALLOC_USAGE_SW_READ_OFTEN);
- mWindow = new TestableSurface(mItemConsumer->getSurface()->getIGraphicBufferProducer());
-#else
- BufferQueue::createBufferQueue(&mProducer, &mConsumer);
- mItemConsumer = new BufferItemConsumer(mConsumer, GRALLOC_USAGE_SW_READ_OFTEN);
- mWindow = new TestableSurface(mProducer);
-#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+ sp<Surface> surface;
+ std::tie(mItemConsumer, surface) = BufferItemConsumer::create(GRALLOC_USAGE_SW_READ_OFTEN);
+ mWindow = new TestableSurface(surface->getIGraphicBufferProducer());
const int success = native_window_api_connect(mWindow.get(), NATIVE_WINDOW_API_CPU);
EXPECT_EQ(0, success);
}
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index ac43da8..ecb16b2 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -301,6 +301,10 @@
*os << "\n .edgeExtensionEffect = " << settings.edgeExtensionEffect;
}
*os << "\n .whitePointNits = " << settings.whitePointNits;
+ if (settings.luts) {
+ *os << "\n .luts = ";
+ PrintTo(settings.luts, os);
+ }
*os << "\n}";
}
diff --git a/libs/renderengine/skia/Cache.cpp b/libs/renderengine/skia/Cache.cpp
index 3b0f036..9f64d2c 100644
--- a/libs/renderengine/skia/Cache.cpp
+++ b/libs/renderengine/skia/Cache.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
#include "Cache.h"
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
#include "AutoBackendTexture.h"
#include "SkiaRenderEngine.h"
#include "android-base/unique_fd.h"
@@ -28,6 +31,7 @@
#include "utils/Timers.h"
#include <com_android_graphics_libgui_flags.h>
+#include <common/trace.h>
namespace android::renderengine::skia {
@@ -659,6 +663,7 @@
// in external/skia/src/gpu/gl/builders/GrGLShaderStringBuilder.cpp
// gPrintSKSL = true
void Cache::primeShaderCache(SkiaRenderEngine* renderengine, PrimeCacheConfig config) {
+ SFTRACE_CALL();
const int previousCount = renderengine->reportShadersCompiled();
if (previousCount) {
ALOGD("%d Shaders already compiled before Cache::primeShaderCache ran\n", previousCount);
@@ -724,24 +729,29 @@
impl::ExternalTexture::Usage::WRITEABLE);
if (config.cacheHolePunchLayer) {
+ SFTRACE_NAME("cacheHolePunchLayer");
drawHolePunchLayer(renderengine, display, dstTexture);
}
if (config.cacheSolidLayers) {
+ SFTRACE_NAME("cacheSolidLayers");
drawSolidLayers(renderengine, display, dstTexture);
drawSolidLayers(renderengine, p3Display, dstTexture);
}
if (config.cacheSolidDimmedLayers) {
+ SFTRACE_NAME("cacheSolidDimmedLayers");
drawSolidDimmedLayers(renderengine, display, dstTexture);
}
if (config.cacheShadowLayers) {
+ SFTRACE_NAME("cacheShadowLayers");
drawShadowLayers(renderengine, display, srcTexture);
drawShadowLayers(renderengine, p3Display, srcTexture);
}
if (renderengine->supportsBackgroundBlur()) {
+ SFTRACE_NAME("supportsBackgroundBlur");
drawBlurLayers(renderengine, display, dstTexture);
}
@@ -776,32 +786,38 @@
for (auto texture : textures) {
if (config.cacheImageLayers) {
+ SFTRACE_NAME("cacheImageLayers");
drawImageLayers(renderengine, display, dstTexture, texture);
}
if (config.cacheImageDimmedLayers) {
+ SFTRACE_NAME("cacheImageDimmedLayers");
drawImageDimmedLayers(renderengine, display, dstTexture, texture);
drawImageDimmedLayers(renderengine, p3Display, dstTexture, texture);
drawImageDimmedLayers(renderengine, bt2020Display, dstTexture, texture);
}
if (config.cacheClippedLayers) {
+ SFTRACE_NAME("cacheClippedLayers");
// Draw layers for b/185569240.
drawClippedLayers(renderengine, display, dstTexture, texture);
}
if (com::android::graphics::libgui::flags::edge_extension_shader() &&
config.cacheEdgeExtension) {
+ SFTRACE_NAME("cacheEdgeExtension");
drawEdgeExtensionLayers(renderengine, display, dstTexture, texture);
drawEdgeExtensionLayers(renderengine, p3Display, dstTexture, texture);
}
}
if (config.cachePIPImageLayers) {
+ SFTRACE_NAME("cachePIPImageLayers");
drawPIPImageLayer(renderengine, display, dstTexture, externalTexture);
}
if (config.cacheTransparentImageDimmedLayers) {
+ SFTRACE_NAME("cacheTransparentImageDimmedLayers");
drawTransparentImageDimmedLayers(renderengine, bt2020Display, dstTexture,
externalTexture);
drawTransparentImageDimmedLayers(renderengine, display, dstTexture, externalTexture);
@@ -811,10 +827,12 @@
}
if (config.cacheClippedDimmedImageLayers) {
+ SFTRACE_NAME("cacheClippedDimmedImageLayers");
drawClippedDimmedImageLayers(renderengine, bt2020Display, dstTexture, externalTexture);
}
if (config.cacheUltraHDR) {
+ SFTRACE_NAME("cacheUltraHDR");
drawBT2020ClippedImageLayers(renderengine, bt2020Display, dstTexture, externalTexture);
drawBT2020ImageLayers(renderengine, bt2020Display, dstTexture, externalTexture);
@@ -833,7 +851,10 @@
};
auto layers = std::vector<LayerSettings>{layer};
// call get() to make it synchronous
- renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()).get();
+ {
+ SFTRACE_NAME("finalLayer");
+ renderengine->drawLayers(display, layers, dstTexture, base::unique_fd()).get();
+ }
const nsecs_t timeAfter = systemTime();
const float compileTimeMs = static_cast<float>(timeAfter - timeBefore) / 1.0E6;
diff --git a/libs/tracing_perfetto/include/tracing_sdk.h b/libs/tracing_perfetto/include/tracing_sdk.h
index 800bf3c..271d7c8 100644
--- a/libs/tracing_perfetto/include/tracing_sdk.h
+++ b/libs/tracing_perfetto/include/tracing_sdk.h
@@ -292,13 +292,8 @@
arg_ = std::move(arg);
}
- ~DebugArg() {
- free_string_value();
- }
-
void set_value(T value) {
if constexpr (std::is_same_v<T, const char*>) {
- free_string_value();
arg_.value = value;
} else if constexpr (std::is_same_v<T, int64_t>) {
arg_.value = value;
@@ -321,16 +316,6 @@
DISALLOW_COPY_AND_ASSIGN(DebugArg);
TypeMap::type arg_;
const std::string name_;
-
- constexpr void free_string_value() {
- if constexpr (std::is_same_v<typename TypeMap::type,
- PerfettoTeHlExtraDebugArgString>) {
- if (arg_.value) {
- free((void*)arg_.value);
- arg_.value = nullptr;
- }
- }
- }
};
template <typename T>
@@ -375,10 +360,6 @@
arg_ = std::move(arg);
}
- ~ProtoField() {
- free_string_value();
- }
-
void set_value(uint32_t id, T value) {
if constexpr (std::is_same_v<T, int64_t>) {
arg_.header.id = id;
@@ -387,7 +368,6 @@
arg_.header.id = id;
arg_.value = value;
} else if constexpr (std::is_same_v<T, const char*>) {
- free_string_value();
arg_.header.id = id;
arg_.str = value;
}
@@ -404,16 +384,6 @@
private:
DISALLOW_COPY_AND_ASSIGN(ProtoField);
TypeMap::type arg_;
-
- constexpr void free_string_value() {
- if constexpr (std::is_same_v<typename TypeMap::type,
- PerfettoTeHlProtoFieldCstr>) {
- if (arg_.str) {
- free((void*)arg_.str);
- arg_.str = nullptr;
- }
- }
- }
};
class ProtoFieldNested {
diff --git a/libs/tracing_perfetto/tracing_perfetto_internal.h b/libs/tracing_perfetto/tracing_perfetto_internal.h
index 3e1ac2a..0e3fb07 100644
--- a/libs/tracing_perfetto/tracing_perfetto_internal.h
+++ b/libs/tracing_perfetto/tracing_perfetto_internal.h
@@ -25,8 +25,6 @@
namespace internal {
-bool isPerfettoRegistered();
-
struct PerfettoTeCategory* toPerfettoCategory(uint64_t category);
void registerWithPerfetto(bool test = false);
diff --git a/libs/tracing_perfetto/tracing_sdk.cpp b/libs/tracing_perfetto/tracing_sdk.cpp
index c97e900..70b8be9 100644
--- a/libs/tracing_perfetto/tracing_sdk.cpp
+++ b/libs/tracing_perfetto/tracing_sdk.cpp
@@ -38,7 +38,7 @@
PerfettoTeHlEmitImpl(perfettoTeCategory->impl, type,
type == PERFETTO_TE_TYPE_COUNTER ? nullptr : name,
extra->get());
- extra->pop_extra();
+ extra->clear_extras();
}
}
diff --git a/libs/ui/include_types/ui/HdrRenderTypeUtils.h b/libs/ui/include_types/ui/HdrRenderTypeUtils.h
index 70c50f0..98018d9 100644
--- a/libs/ui/include_types/ui/HdrRenderTypeUtils.h
+++ b/libs/ui/include_types/ui/HdrRenderTypeUtils.h
@@ -36,7 +36,7 @@
*/
inline HdrRenderType getHdrRenderType(ui::Dataspace dataspace,
std::optional<ui::PixelFormat> pixelFormat,
- float hdrSdrRatio = 1.f) {
+ float hdrSdrRatio = 1.f, bool hasHdrMetadata = false) {
const auto transfer = dataspace & HAL_DATASPACE_TRANSFER_MASK;
const auto range = dataspace & HAL_DATASPACE_RANGE_MASK;
@@ -49,7 +49,8 @@
HAL_DATASPACE_RANGE_EXTENDED);
if ((dataspace == BT2020_LINEAR_EXT || dataspace == ui::Dataspace::V0_SCRGB) &&
- pixelFormat.has_value() && pixelFormat.value() == ui::PixelFormat::RGBA_FP16) {
+ pixelFormat.has_value() && pixelFormat.value() == ui::PixelFormat::RGBA_FP16 &&
+ hasHdrMetadata) {
return HdrRenderType::GENERIC_HDR;
}
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index 62e2d1a..25ee21f 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -146,6 +146,15 @@
}
}
+FeatureOverrides GpuService::getFeatureOverrides() {
+ if (!graphicsenv_flags::feature_overrides()) {
+ FeatureOverrides featureOverrides;
+ return featureOverrides;
+ }
+
+ return mFeatureOverrideParser.getFeatureOverrides();
+}
+
void GpuService::setUpdatableDriverPath(const std::string& driverPath) {
IPCThreadState* ipc = IPCThreadState::self();
const int pid = ipc->getCallingPid();
diff --git a/services/gpuservice/include/gpuservice/GpuService.h b/services/gpuservice/include/gpuservice/GpuService.h
index 116b6d7..22be9a7 100644
--- a/services/gpuservice/include/gpuservice/GpuService.h
+++ b/services/gpuservice/include/gpuservice/GpuService.h
@@ -20,6 +20,7 @@
#include <binder/IInterface.h>
#include <cutils/compiler.h>
#include <feature_override/FeatureOverrideParser.h>
+#include <graphicsenv/FeatureOverrides.h>
#include <graphicsenv/GpuStatsInfo.h>
#include <graphicsenv/IGpuService.h>
#include <serviceutils/PriorityDumper.h>
@@ -64,6 +65,7 @@
const uint64_t* values, const uint32_t valueCount) override;
void setUpdatableDriverPath(const std::string& driverPath) override;
std::string getUpdatableDriverPath() override;
+ FeatureOverrides getFeatureOverrides() override;
void toggleAngleAsSystemDriver(bool enabled) override;
void addVulkanEngineName(const std::string& appPackageName, const uint64_t driverVersionCode,
const char *engineName) override;
diff --git a/services/gpuservice/vts/OWNERS b/services/gpuservice/vts/OWNERS
index a63de1c..13a089f 100644
--- a/services/gpuservice/vts/OWNERS
+++ b/services/gpuservice/vts/OWNERS
@@ -1,8 +1,5 @@
# Bug component: 653544
kocdemir@google.com
paulthomson@google.com
-pbaiget@google.com
-lfy@google.com
chrisforbes@google.com
-lpy@google.com
alecmouri@google.com
diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp
index 85f842c..98b514b 100644
--- a/services/inputflinger/PointerChoreographer.cpp
+++ b/services/inputflinger/PointerChoreographer.cpp
@@ -36,37 +36,6 @@
namespace {
-bool isFromMouse(const NotifyMotionArgs& args) {
- return isFromSource(args.source, AINPUT_SOURCE_MOUSE) &&
- args.pointerProperties[0].toolType == ToolType::MOUSE;
-}
-
-bool isFromTouchpad(const NotifyMotionArgs& args) {
- return isFromSource(args.source, AINPUT_SOURCE_MOUSE) &&
- args.pointerProperties[0].toolType == ToolType::FINGER;
-}
-
-bool isFromDrawingTablet(const NotifyMotionArgs& args) {
- return isFromSource(args.source, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS) &&
- isStylusToolType(args.pointerProperties[0].toolType);
-}
-
-bool isHoverAction(int32_t action) {
- return action == AMOTION_EVENT_ACTION_HOVER_ENTER ||
- action == AMOTION_EVENT_ACTION_HOVER_MOVE || action == AMOTION_EVENT_ACTION_HOVER_EXIT;
-}
-
-bool isStylusHoverEvent(const NotifyMotionArgs& args) {
- return isStylusEvent(args.source, args.pointerProperties) && isHoverAction(args.action);
-}
-
-bool isMouseOrTouchpad(uint32_t sources) {
- // Check if this is a mouse or touchpad, but not a drawing tablet.
- return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) ||
- (isFromSource(sources, AINPUT_SOURCE_MOUSE) &&
- !isFromSource(sources, AINPUT_SOURCE_STYLUS));
-}
-
inline void notifyPointerDisplayChange(std::optional<std::tuple<ui::LogicalDisplayId, vec2>> change,
PointerChoreographerPolicyInterface& policy) {
if (!change) {
@@ -163,7 +132,7 @@
}),
mNextListener(listener),
mPolicy(policy),
- mDefaultMouseDisplayId(ui::LogicalDisplayId::DEFAULT),
+ mCurrentMouseDisplayId(ui::LogicalDisplayId::INVALID),
mNotifiedPointerDisplayId(ui::LogicalDisplayId::INVALID),
mShowTouchesEnabled(false),
mStylusPointerIconEnabled(false),
@@ -239,15 +208,16 @@
PointerDisplayChange pointerDisplayChange;
{ // acquire lock
std::scoped_lock _l(getLock());
- if (isFromMouse(args)) {
+ if (isFromMouse(args.source, args.pointerProperties[0].toolType)) {
newArgs = processMouseEventLocked(args);
pointerDisplayChange = calculatePointerDisplayChangeToNotify();
- } else if (isFromTouchpad(args)) {
+ } else if (isFromTouchpad(args.source, args.pointerProperties[0].toolType)) {
newArgs = processTouchpadEventLocked(args);
pointerDisplayChange = calculatePointerDisplayChangeToNotify();
- } else if (isFromDrawingTablet(args)) {
+ } else if (isFromDrawingTablet(args.source, args.pointerProperties[0].toolType)) {
processDrawingTabletEventLocked(args);
- } else if (mStylusPointerIconEnabled && isStylusHoverEvent(args)) {
+ } else if (mStylusPointerIconEnabled &&
+ isStylusHoverEvent(args.source, args.pointerProperties, args.action)) {
processStylusHoverEventLocked(args);
} else if (isFromSource(args.source, AINPUT_SOURCE_TOUCHSCREEN)) {
processTouchscreenAndStylusEventLocked(args);
@@ -391,7 +361,7 @@
LOG(FATAL) << "A cursor already exists on destination display"
<< destinationViewport.displayId;
}
- mDefaultMouseDisplayId = destinationViewport.displayId;
+ mCurrentMouseDisplayId = destinationViewport.displayId;
auto pcNode = mMousePointersByDisplay.extract(sourceDisplayId);
pcNode.key() = destinationViewport.displayId;
mMousePointersByDisplay.insert(std::move(pcNode));
@@ -506,6 +476,14 @@
<< args.dump();
}
+ // Fade the mouse pointer on the display if there is one when the stylus starts hovering.
+ if (args.action == AMOTION_EVENT_ACTION_HOVER_ENTER) {
+ if (const auto it = mMousePointersByDisplay.find(args.displayId);
+ it != mMousePointersByDisplay.end()) {
+ it->second->fade(PointerControllerInterface::Transition::GRADUAL);
+ }
+ }
+
// Get the stylus pointer controller for the device, or create one if it doesn't exist.
auto [it, controllerAdded] =
mStylusPointersByDevice.try_emplace(args.deviceId,
@@ -624,15 +602,21 @@
}
void PointerChoreographer::setDisplayTopology(const DisplayTopologyGraph& displayTopologyGraph) {
- std::scoped_lock _l(getLock());
- mTopology = displayTopologyGraph;
+ PointerDisplayChange pointerDisplayChange;
+ { // acquire lock
+ std::scoped_lock _l(getLock());
+ mTopology = displayTopologyGraph;
- // make primary display default mouse display, if it was not set
- // or the existing display was removed
- if (mDefaultMouseDisplayId == ui::LogicalDisplayId::INVALID ||
- mTopology.graph.find(mDefaultMouseDisplayId) != mTopology.graph.end()) {
- mDefaultMouseDisplayId = mTopology.primaryDisplayId;
- }
+ // make primary display default mouse display, if it was not set or
+ // the existing display was removed
+ if (mCurrentMouseDisplayId == ui::LogicalDisplayId::INVALID ||
+ mTopology.graph.find(mCurrentMouseDisplayId) == mTopology.graph.end()) {
+ mCurrentMouseDisplayId = mTopology.primaryDisplayId;
+ pointerDisplayChange = updatePointerControllersLocked();
+ }
+ } // release lock
+
+ notifyPointerDisplayChange(pointerDisplayChange, mPolicy);
}
void PointerChoreographer::dump(std::string& dump) {
@@ -681,7 +665,19 @@
ui::LogicalDisplayId PointerChoreographer::getTargetMouseDisplayLocked(
ui::LogicalDisplayId associatedDisplayId) const {
- return associatedDisplayId.isValid() ? associatedDisplayId : mDefaultMouseDisplayId;
+ if (!InputFlags::connectedDisplaysCursorAndAssociatedDisplayCursorBugfixEnabled()) {
+ if (associatedDisplayId.isValid()) {
+ return associatedDisplayId;
+ }
+ return mCurrentMouseDisplayId.isValid() ? mCurrentMouseDisplayId
+ : ui::LogicalDisplayId::DEFAULT;
+ }
+ // Associated display is not included in the topology, return this associated display.
+ if (associatedDisplayId.isValid() &&
+ mTopology.graph.find(associatedDisplayId) == mTopology.graph.end()) {
+ return associatedDisplayId;
+ }
+ return mCurrentMouseDisplayId.isValid() ? mCurrentMouseDisplayId : mTopology.primaryDisplayId;
}
std::pair<ui::LogicalDisplayId, PointerControllerInterface&>
@@ -790,7 +786,7 @@
PointerChoreographer::calculatePointerDisplayChangeToNotify() {
ui::LogicalDisplayId displayIdToNotify = ui::LogicalDisplayId::INVALID;
vec2 cursorPosition = {0, 0};
- if (const auto it = mMousePointersByDisplay.find(mDefaultMouseDisplayId);
+ if (const auto it = mMousePointersByDisplay.find(mCurrentMouseDisplayId);
it != mMousePointersByDisplay.end()) {
const auto& pointerController = it->second;
// Use the displayId from the pointerController, because it accurately reflects whether
@@ -807,12 +803,16 @@
}
void PointerChoreographer::setDefaultMouseDisplayId(ui::LogicalDisplayId displayId) {
+ if (InputFlags::connectedDisplaysCursorEnabled()) {
+ // In connected displays scenario, default mouse display will only be updated from topology.
+ return;
+ }
PointerDisplayChange pointerDisplayChange;
{ // acquire lock
std::scoped_lock _l(getLock());
- mDefaultMouseDisplayId = displayId;
+ mCurrentMouseDisplayId = displayId;
pointerDisplayChange = updatePointerControllersLocked();
} // release lock
diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h
index 2435125..67bdca1 100644
--- a/services/inputflinger/PointerChoreographer.h
+++ b/services/inputflinger/PointerChoreographer.h
@@ -231,7 +231,12 @@
std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mDrawingTabletPointersByDevice
GUARDED_BY(getLock());
- ui::LogicalDisplayId mDefaultMouseDisplayId GUARDED_BY(getLock());
+ // In connected displays scenario, this tracks the latest display the cursor is at, within the
+ // DisplayTopology. By default, this will be set to topology primary display, and updated when
+ // mouse crossed to another display.
+ // In non-connected displays scenario, this will be treated as the default display cursor
+ // will be on, when mouse doesn't have associated display.
+ ui::LogicalDisplayId mCurrentMouseDisplayId GUARDED_BY(getLock());
ui::LogicalDisplayId mNotifiedPointerDisplayId GUARDED_BY(getLock());
std::vector<InputDeviceInfo> mInputDeviceInfos GUARDED_BY(getLock());
std::set<DeviceId> mMouseDevices GUARDED_BY(getLock());
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index a77dc43..ef50fc0 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -920,13 +920,6 @@
binderToString(info.applicationInfo.token).c_str());
}
-bool isMouseOrTouchpad(uint32_t sources) {
- // Check if this is a mouse or touchpad, but not a drawing tablet.
- return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) ||
- (isFromSource(sources, AINPUT_SOURCE_MOUSE) &&
- !isFromSource(sources, AINPUT_SOURCE_STYLUS));
-}
-
} // namespace
// --- InputDispatcher ---
@@ -943,6 +936,7 @@
mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER),
mMinTimeBetweenUserActivityPokes(DEFAULT_USER_ACTIVITY_POKE_INTERVAL),
mConnectionManager(mLooper),
+ mTouchStates(mWindowInfos, mConnectionManager),
mNextUnblockedEvent(nullptr),
mMonitorDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT),
mDispatchEnabled(false),
@@ -1473,14 +1467,13 @@
std::vector<InputTarget> InputDispatcher::DispatcherTouchState::findOutsideTargets(
ui::LogicalDisplayId displayId, const sp<gui::WindowInfoHandle>& touchedWindow,
- int32_t pointerId, const ConnectionManager& connections,
- const DispatcherWindowInfo& windowInfos, std::function<void()> dump) {
+ int32_t pointerId, std::function<void()> dump) {
if (touchedWindow == nullptr) {
return {};
}
// Traverse windows from front to back until we encounter the touched window.
std::vector<InputTarget> outsideTargets;
- const auto& windowHandles = windowInfos.getWindowHandlesForDisplay(displayId);
+ const auto& windowHandles = mWindowInfos.getWindowHandlesForDisplay(displayId);
for (const sp<WindowInfoHandle>& windowHandle : windowHandles) {
if (windowHandle == touchedWindow) {
// Stop iterating once we found a touched window. Any WATCH_OUTSIDE_TOUCH window
@@ -1495,8 +1488,7 @@
addPointerWindowTarget(windowHandle, InputTarget::DispatchMode::OUTSIDE,
ftl::Flags<InputTarget::Flags>(), pointerIds,
/*firstDownTimeInTarget=*/std::nullopt,
- /*pointerDisplayId=*/std::nullopt, connections, windowInfos,
- dump, outsideTargets);
+ /*pointerDisplayId=*/std::nullopt, dump, outsideTargets);
}
}
return outsideTargets;
@@ -2058,8 +2050,7 @@
Result<std::vector<InputTarget>, InputEventInjectionResult> result =
mTouchStates
- .findTouchedWindowTargets(currentTime, *entry, mConnectionManager,
- mWindowInfos,
+ .findTouchedWindowTargets(currentTime, *entry,
mDragState ? mDragState->dragWindow : nullptr,
std::bind_front(&InputDispatcher::
addDragEventLocked,
@@ -2379,8 +2370,7 @@
base::Result<std::vector<InputTarget>, os::InputEventInjectionResult>
InputDispatcher::DispatcherTouchState::findTouchedWindowTargets(
- nsecs_t currentTime, const MotionEntry& entry, const ConnectionManager& connections,
- const DispatcherWindowInfo& windowInfos,
+ nsecs_t currentTime, const MotionEntry& entry,
const sp<android::gui::WindowInfoHandle> dragWindow,
std::function<void(const MotionEntry&)> addDragEvent, std::function<void()> dump) {
ATRACE_CALL();
@@ -2395,7 +2385,7 @@
// Copy current touch state into tempTouchState.
// This state will be used to update saved touch state at the end of this function.
// If no state for the specified display exists, then our initial state will be empty.
- const TouchState* oldState = getTouchStateForMotionEntry(entry, windowInfos);
+ const TouchState* oldState = getTouchStateForMotionEntry(entry);
TouchState tempTouchState;
if (oldState != nullptr) {
tempTouchState = *oldState;
@@ -2441,12 +2431,10 @@
// be a pointer that would generate ACTION_DOWN, *and* touch should not already be down.
const bool isStylus = isPointerFromStylus(entry, pointerIndex);
sp<WindowInfoHandle> newTouchedWindowHandle =
- windowInfos.findTouchedWindowAt(displayId, x, y, isStylus);
+ mWindowInfos.findTouchedWindowAt(displayId, x, y, isStylus);
if (isDown) {
- targets += DispatcherTouchState::findOutsideTargets(displayId, newTouchedWindowHandle,
- pointer.id, connections,
- windowInfos, dump);
+ targets += findOutsideTargets(displayId, newTouchedWindowHandle, pointer.id, dump);
}
LOG_IF(INFO, newTouchedWindowHandle == nullptr)
<< "No new touched window at (" << std::format("{:.1f}, {:.1f}", x, y)
@@ -2459,7 +2447,7 @@
}
std::vector<sp<WindowInfoHandle>> newTouchedWindows =
- findTouchedSpyWindowsAt(displayId, x, y, isStylus, entry.deviceId, windowInfos);
+ findTouchedSpyWindowsAt(displayId, x, y, isStylus, entry.deviceId, mWindowInfos);
if (newTouchedWindowHandle != nullptr) {
// Process the foreground window first so that it is the first to receive the event.
newTouchedWindows.insert(newTouchedWindows.begin(), newTouchedWindowHandle);
@@ -2472,7 +2460,7 @@
}
for (const sp<WindowInfoHandle>& windowHandle : newTouchedWindows) {
- if (!canWindowReceiveMotion(windowHandle, entry, connections, windowInfos)) {
+ if (!canWindowReceiveMotion(windowHandle, entry)) {
continue;
}
@@ -2484,8 +2472,7 @@
// Set target flags.
ftl::Flags<InputTarget::Flags> targetFlags =
- DispatcherTouchState::getTargetFlags(windowHandle, {x, y}, isSplit,
- windowInfos);
+ getTargetFlags(windowHandle, {x, y}, isSplit);
// Update the temporary touch state.
@@ -2515,7 +2502,7 @@
windowHandle->getInfo()->inputConfig.test(
gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER)) {
sp<WindowInfoHandle> wallpaper =
- windowInfos.findWallpaperWindowBelow(windowHandle);
+ mWindowInfos.findWallpaperWindowBelow(windowHandle);
if (wallpaper != nullptr) {
ftl::Flags<InputTarget::Flags> wallpaperFlags =
InputTarget::Flags::WINDOW_IS_OBSCURED |
@@ -2584,7 +2571,7 @@
tempTouchState.getFirstForegroundWindowHandle(entry.deviceId);
LOG_ALWAYS_FATAL_IF(oldTouchedWindowHandle == nullptr);
sp<WindowInfoHandle> newTouchedWindowHandle =
- windowInfos.findTouchedWindowAt(displayId, x, y, isStylus);
+ mWindowInfos.findTouchedWindowAt(displayId, x, y, isStylus);
// Verify targeted injection.
if (const auto err = verifyTargetedInjection(newTouchedWindowHandle, entry); err) {
@@ -2594,7 +2581,7 @@
// Do not slide events to the window which can not receive motion event
if (newTouchedWindowHandle != nullptr &&
- !canWindowReceiveMotion(newTouchedWindowHandle, entry, connections, windowInfos)) {
+ !canWindowReceiveMotion(newTouchedWindowHandle, entry)) {
newTouchedWindowHandle = nullptr;
}
@@ -2615,14 +2602,12 @@
InputTarget::DispatchMode::SLIPPERY_EXIT,
ftl::Flags<InputTarget::Flags>(), pointerIds,
touchedWindow.getDownTimeInTarget(entry.deviceId),
- /*pointerDisplayId=*/std::nullopt, connections, windowInfos,
- dump, targets);
+ /*pointerDisplayId=*/std::nullopt, dump, targets);
// Make a slippery entrance into the new window.
ftl::Flags<InputTarget::Flags> targetFlags =
- DispatcherTouchState::getTargetFlags(newTouchedWindowHandle, {x, y},
- isSplit, windowInfos);
+ getTargetFlags(newTouchedWindowHandle, {x, y}, isSplit);
tempTouchState.addOrUpdateWindow(newTouchedWindowHandle,
InputTarget::DispatchMode::SLIPPERY_ENTER,
@@ -2630,10 +2615,8 @@
entry.eventTime);
// Check if the wallpaper window should deliver the corresponding event.
- DispatcherTouchState::slipWallpaperTouch(targetFlags, oldTouchedWindowHandle,
- newTouchedWindowHandle, tempTouchState,
- entry, targets, connections, windowInfos,
- dump);
+ slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle,
+ tempTouchState, entry, targets, dump);
tempTouchState.removeTouchingPointerFromWindow(entry.deviceId, pointer.id,
oldTouchedWindowHandle);
}
@@ -2668,8 +2651,7 @@
addPointerWindowTarget(touchedWindow.windowHandle, touchedWindow.dispatchMode,
touchedWindow.targetFlags, pointerIds,
touchedWindow.getDownTimeInTarget(entry.deviceId),
- /*pointerDisplayId=*/std::nullopt, connections, windowInfos,
- dump, targets);
+ /*pointerDisplayId=*/std::nullopt, dump, targets);
}
}
@@ -2698,7 +2680,7 @@
for (InputTarget& target : targets) {
if (target.dispatchMode == InputTarget::DispatchMode::OUTSIDE) {
sp<WindowInfoHandle> targetWindow =
- windowInfos.findWindowHandle(target.connection->getToken());
+ mWindowInfos.findWindowHandle(target.connection->getToken());
if (targetWindow->getInfo()->ownerUid != foregroundWindowUid) {
target.flags |= InputTarget::Flags::ZERO_COORDS;
}
@@ -2725,8 +2707,7 @@
addPointerWindowTarget(touchedWindow.windowHandle, touchedWindow.dispatchMode,
touchedWindow.targetFlags, getPointerIds(touchingPointers),
touchedWindow.getDownTimeInTarget(entry.deviceId),
- /*pointerDisplayId=*/displayId, connections, windowInfos, dump,
- targets);
+ /*pointerDisplayId=*/displayId, dump, targets);
}
// During targeted injection, only allow owned targets to receive events
@@ -2781,9 +2762,9 @@
if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) {
if (displayId >= ui::LogicalDisplayId::DEFAULT) {
tempTouchState.clearWindowsWithoutPointers();
- saveTouchStateForMotionEntry(entry, std::move(tempTouchState), windowInfos);
+ saveTouchStateForMotionEntry(entry, std::move(tempTouchState));
} else {
- eraseTouchStateForMotionEntry(entry, windowInfos);
+ eraseTouchStateForMotionEntry(entry);
}
}
@@ -2930,8 +2911,7 @@
const sp<android::gui::WindowInfoHandle>& windowHandle,
InputTarget::DispatchMode dispatchMode, ftl::Flags<InputTarget::Flags> targetFlags,
std::bitset<MAX_POINTER_ID + 1> pointerIds, std::optional<nsecs_t> firstDownTimeInTarget,
- std::optional<ui::LogicalDisplayId> pointerDisplayId, const ConnectionManager& connections,
- const DispatcherWindowInfo& windowInfos, std::function<void()> dump,
+ std::optional<ui::LogicalDisplayId> pointerDisplayId, std::function<void()> dump,
std::vector<InputTarget>& inputTargets) {
if (pointerIds.none()) {
for (const auto& target : inputTargets) {
@@ -2960,15 +2940,15 @@
const WindowInfo& windowInfo = *windowHandle->getInfo();
if (it == inputTargets.end()) {
- std::shared_ptr<Connection> connection = connections.getConnection(windowInfo.token);
+ std::shared_ptr<Connection> connection = mConnectionManager.getConnection(windowInfo.token);
if (connection == nullptr) {
ALOGW("Not creating InputTarget for %s, no input channel", windowInfo.name.c_str());
return;
}
inputTargets.push_back(
createInputTarget(connection, windowHandle, dispatchMode, targetFlags,
- windowInfos.getRawTransform(*windowHandle->getInfo(),
- pointerDisplayId),
+ mWindowInfos.getRawTransform(*windowHandle->getInfo(),
+ pointerDisplayId),
firstDownTimeInTarget));
it = inputTargets.end() - 1;
}
@@ -4168,16 +4148,15 @@
sendDropWindowCommandLocked(nullptr, /*x=*/0, /*y=*/0);
mDragState.reset();
}
- DispatcherTouchState::
- addPointerWindowTarget(window, InputTarget::DispatchMode::AS_IS,
- ftl::Flags<InputTarget::Flags>(), pointerIds,
- motionEntry.downTime,
- /*pointerDisplayId=*/std::nullopt,
- mConnectionManager, mWindowInfos,
- std::bind_front(&InputDispatcher::
- logDispatchStateLocked,
- this),
- targets);
+ mTouchStates
+ .addPointerWindowTarget(window, InputTarget::DispatchMode::AS_IS,
+ ftl::Flags<InputTarget::Flags>(), pointerIds,
+ motionEntry.downTime,
+ /*pointerDisplayId=*/std::nullopt,
+ std::bind_front(&InputDispatcher::
+ logDispatchStateLocked,
+ this),
+ targets);
} else {
targets.emplace_back(fallbackTarget);
// Since we don't have a window, use the display transform as the raw transform.
@@ -4256,15 +4235,14 @@
pointerIndex++) {
pointerIds.set(motionEntry.pointerProperties[pointerIndex].id);
}
- DispatcherTouchState::
- addPointerWindowTarget(windowHandle, InputTarget::DispatchMode::AS_IS,
- targetFlags, pointerIds, motionEntry.downTime,
- /*pointerDisplayId=*/std::nullopt,
- mConnectionManager, mWindowInfos,
- std::bind_front(&InputDispatcher::
- logDispatchStateLocked,
- this),
- targets);
+ mTouchStates
+ .addPointerWindowTarget(windowHandle, InputTarget::DispatchMode::AS_IS,
+ targetFlags, pointerIds, motionEntry.downTime,
+ /*pointerDisplayId=*/std::nullopt,
+ std::bind_front(&InputDispatcher::
+ logDispatchStateLocked,
+ this),
+ targets);
} else {
targets.emplace_back(connection, targetFlags);
// Since we don't have a window, use the display transform as the raw transform.
@@ -5089,8 +5067,19 @@
}
// Only look through the requested display.
- for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesForDisplay(*displayId)) {
- if (windowHandle->getToken() == windowHandleToken) {
+ return findWindowHandleOnDisplay(windowHandleToken, *displayId);
+}
+
+sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findWindowHandleOnConnectedDisplays(
+ const sp<IBinder>& windowHandleToken, ui::LogicalDisplayId displayId) const {
+ if (windowHandleToken == nullptr) {
+ return nullptr;
+ }
+
+ sp<WindowInfoHandle> windowHandle;
+ for (ui::LogicalDisplayId connectedDisplayId : getConnectedDisplays(displayId)) {
+ windowHandle = findWindowHandleOnDisplay(windowHandleToken, connectedDisplayId);
+ if (windowHandle != nullptr) {
return windowHandle;
}
}
@@ -5236,10 +5225,32 @@
return dump;
}
+std::vector<ui::LogicalDisplayId> InputDispatcher::DispatcherWindowInfo::getConnectedDisplays(
+ ui::LogicalDisplayId displayId) const {
+ if (!mTopology.graph.contains(displayId)) {
+ return {displayId};
+ }
+
+ std::vector<ui::LogicalDisplayId> connectedDisplays;
+ for (auto it : mTopology.graph) {
+ connectedDisplays.push_back(it.first);
+ }
+ return connectedDisplays;
+}
+
+sp<WindowInfoHandle> InputDispatcher::DispatcherWindowInfo::findWindowHandleOnDisplay(
+ const sp<IBinder>& windowHandleToken, ui::LogicalDisplayId displayId) const {
+ for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesForDisplay(displayId)) {
+ if (windowHandle->getToken() == windowHandleToken) {
+ return windowHandle;
+ }
+ }
+ return nullptr;
+}
+
bool InputDispatcher::DispatcherTouchState::canWindowReceiveMotion(
const sp<android::gui::WindowInfoHandle>& window,
- const android::inputdispatcher::MotionEntry& motionEntry,
- const ConnectionManager& connections, const DispatcherWindowInfo& windowInfos) const {
+ const android::inputdispatcher::MotionEntry& motionEntry) const {
const WindowInfo& info = *window->getInfo();
// Skip spy window targets that are not valid for targeted injection.
@@ -5258,7 +5269,7 @@
return false;
}
- std::shared_ptr<Connection> connection = connections.getConnection(window->getToken());
+ std::shared_ptr<Connection> connection = mConnectionManager.getConnection(window->getToken());
if (connection == nullptr) {
ALOGW("Not sending touch to %s because there's no corresponding connection",
window->getName().c_str());
@@ -5273,8 +5284,8 @@
// Drop events that can't be trusted due to occlusion
const auto [x, y] = resolveTouchedPosition(motionEntry);
DispatcherWindowInfo::TouchOcclusionInfo occlusionInfo =
- windowInfos.computeTouchOcclusionInfo(window, x, y);
- if (!windowInfos.isTouchTrusted(occlusionInfo)) {
+ mWindowInfos.computeTouchOcclusionInfo(window, x, y);
+ if (!mWindowInfos.isTouchTrusted(occlusionInfo)) {
if (DEBUG_TOUCH_OCCLUSION) {
ALOGD("Stack of obscuring windows during untrusted touch (%.1f, %.1f):", x, y);
for (const auto& log : occlusionInfo.debugInfo) {
@@ -5287,7 +5298,7 @@
}
// Drop touch events if requested by input feature
- if (shouldDropInput(motionEntry, window, windowInfos)) {
+ if (shouldDropInput(motionEntry, window, mWindowInfos)) {
return false;
}
@@ -5423,7 +5434,7 @@
CancelationOptions hoverCancellationOptions(CancelationOptions::Mode::CANCEL_HOVER_EVENTS,
"WindowInfo changed", traceContext.getTracker());
const std::list<DispatcherTouchState::CancellationArgs> cancellations =
- mTouchStates.updateFromWindowInfo(displayId, mWindowInfos);
+ mTouchStates.updateFromWindowInfo(displayId);
for (const auto& cancellationArgs : cancellations) {
switch (cancellationArgs.mode) {
case CancelationOptions::Mode::CANCEL_POINTER_EVENTS:
@@ -5464,14 +5475,13 @@
}
std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>
-InputDispatcher::DispatcherTouchState::updateFromWindowInfo(
- ui::LogicalDisplayId displayId, const DispatcherWindowInfo& windowInfos) {
+InputDispatcher::DispatcherTouchState::updateFromWindowInfo(ui::LogicalDisplayId displayId) {
std::list<CancellationArgs> cancellations;
forTouchAndCursorStatesOnDisplay(displayId, [&](TouchState& state) {
cancellations.splice(cancellations.end(),
- eraseRemovedWindowsFromWindowInfo(state, displayId, windowInfos));
+ eraseRemovedWindowsFromWindowInfo(state, displayId));
cancellations.splice(cancellations.end(),
- updateHoveringStateFromWindowInfo(state, displayId, windowInfos));
+ updateHoveringStateFromWindowInfo(state, displayId));
return false;
});
return cancellations;
@@ -5479,12 +5489,11 @@
std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>
InputDispatcher::DispatcherTouchState::eraseRemovedWindowsFromWindowInfo(
- TouchState& state, ui::LogicalDisplayId displayId,
- const DispatcherWindowInfo& windowInfos) {
+ TouchState& state, ui::LogicalDisplayId displayId) {
std::list<CancellationArgs> cancellations;
for (auto it = state.windows.begin(); it != state.windows.end();) {
TouchedWindow& touchedWindow = *it;
- if (windowInfos.isWindowPresent(touchedWindow.windowHandle)) {
+ if (mWindowInfos.isWindowPresent(touchedWindow.windowHandle)) {
it++;
continue;
}
@@ -5510,12 +5519,11 @@
std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>
InputDispatcher::DispatcherTouchState::updateHoveringStateFromWindowInfo(
- TouchState& state, ui::LogicalDisplayId displayId,
- const DispatcherWindowInfo& windowInfos) {
+ TouchState& state, ui::LogicalDisplayId displayId) {
std::list<CancellationArgs> cancellations;
// Check if the hovering should stop because the window is no longer eligible to receive it
// (for example, if the touchable region changed)
- ui::Transform displayTransform = windowInfos.getDisplayTransform(displayId);
+ ui::Transform displayTransform = mWindowInfos.getDisplayTransform(displayId);
for (TouchedWindow& touchedWindow : state.windows) {
std::vector<DeviceId> erasedDevices = touchedWindow.eraseHoveringPointersIf(
[&](const PointerProperties& properties, float x, float y) {
@@ -5770,8 +5778,7 @@
"transferring touch from this window to another window",
traceContext.getTracker());
- auto result = mTouchStates.transferTouchGesture(fromToken, toToken, mWindowInfos,
- mConnectionManager);
+ auto result = mTouchStates.transferTouchGesture(fromToken, toToken);
if (!result.has_value()) {
return false;
}
@@ -5815,9 +5822,7 @@
std::list<InputDispatcher::DispatcherTouchState::CancellationArgs>,
std::list<InputDispatcher::DispatcherTouchState::PointerDownArgs>>>
InputDispatcher::DispatcherTouchState::transferTouchGesture(const sp<android::IBinder>& fromToken,
- const sp<android::IBinder>& toToken,
- const DispatcherWindowInfo& windowInfos,
- const ConnectionManager& connections) {
+ const sp<android::IBinder>& toToken) {
// Find the target touch state and touched window by fromToken.
auto touchStateWindowAndDisplay = findTouchStateWindowAndDisplay(fromToken);
if (!touchStateWindowAndDisplay.has_value()) {
@@ -5835,7 +5840,10 @@
const DeviceId deviceId = *deviceIds.begin();
const sp<WindowInfoHandle> fromWindowHandle = touchedWindow.windowHandle;
- const sp<WindowInfoHandle> toWindowHandle = windowInfos.findWindowHandle(toToken, displayId);
+ // TouchState displayId may not be same as window displayId, we need to lookup for toToken on
+ // all connected displays.
+ const sp<WindowInfoHandle> toWindowHandle =
+ mWindowInfos.findWindowHandleOnConnectedDisplays(toToken, displayId);
if (!toWindowHandle) {
ALOGW("Cannot transfer touch because the transfer target window was not found.");
return std::nullopt;
@@ -5861,8 +5869,8 @@
deviceId, pointers, downTimeInTarget);
// Synthesize cancel for old window and down for new window.
- std::shared_ptr<Connection> fromConnection = connections.getConnection(fromToken);
- std::shared_ptr<Connection> toConnection = connections.getConnection(toToken);
+ std::shared_ptr<Connection> fromConnection = mConnectionManager.getConnection(fromToken);
+ std::shared_ptr<Connection> toConnection = mConnectionManager.getConnection(toToken);
std::list<CancellationArgs> cancellations;
std::list<PointerDownArgs> pointerDowns;
if (fromConnection != nullptr && toConnection != nullptr) {
@@ -5873,7 +5881,7 @@
// Check if the wallpaper window should deliver the corresponding event.
auto [wallpaperCancellations, wallpaperPointerDowns] =
transferWallpaperTouch(fromWindowHandle, toWindowHandle, state, deviceId, pointers,
- oldTargetFlags, newTargetFlags, windowInfos, connections);
+ oldTargetFlags, newTargetFlags);
cancellations.splice(cancellations.end(), wallpaperCancellations);
pointerDowns.splice(pointerDowns.end(), wallpaperPointerDowns);
@@ -7092,8 +7100,7 @@
void InputDispatcher::DispatcherTouchState::slipWallpaperTouch(
ftl::Flags<InputTarget::Flags> targetFlags, const sp<WindowInfoHandle>& oldWindowHandle,
const sp<WindowInfoHandle>& newWindowHandle, TouchState& state, const MotionEntry& entry,
- std::vector<InputTarget>& targets, const ConnectionManager& connections,
- const DispatcherWindowInfo& windowInfos, std::function<void()> dump) {
+ std::vector<InputTarget>& targets, std::function<void()> dump) {
LOG_IF(FATAL, entry.getPointerCount() != 1) << "Entry not eligible for slip: " << entry;
const DeviceId deviceId = entry.deviceId;
const PointerProperties& pointerProperties = entry.pointerProperties[0];
@@ -7106,20 +7113,17 @@
const sp<WindowInfoHandle> oldWallpaper =
oldHasWallpaper ? state.getWallpaperWindow(deviceId) : nullptr;
const sp<WindowInfoHandle> newWallpaper =
- newHasWallpaper ? windowInfos.findWallpaperWindowBelow(newWindowHandle) : nullptr;
+ newHasWallpaper ? mWindowInfos.findWallpaperWindowBelow(newWindowHandle) : nullptr;
if (oldWallpaper == newWallpaper) {
return;
}
if (oldWallpaper != nullptr) {
const TouchedWindow& oldTouchedWindow = state.getTouchedWindow(oldWallpaper);
- DispatcherTouchState::addPointerWindowTarget(oldWallpaper,
- InputTarget::DispatchMode::SLIPPERY_EXIT,
- oldTouchedWindow.targetFlags,
- getPointerIds(pointers),
- oldTouchedWindow.getDownTimeInTarget(deviceId),
- /*pointerDisplayId=*/std::nullopt, connections,
- windowInfos, dump, targets);
+ addPointerWindowTarget(oldWallpaper, InputTarget::DispatchMode::SLIPPERY_EXIT,
+ oldTouchedWindow.targetFlags, getPointerIds(pointers),
+ oldTouchedWindow.getDownTimeInTarget(deviceId),
+ /*pointerDisplayId=*/std::nullopt, dump, targets);
state.removeTouchingPointerFromWindow(deviceId, pointerProperties.id, oldWallpaper);
}
@@ -7138,8 +7142,7 @@
const sp<gui::WindowInfoHandle> toWindowHandle, TouchState& state,
android::DeviceId deviceId, const std::vector<PointerProperties>& pointers,
ftl::Flags<InputTarget::Flags> oldTargetFlags,
- ftl::Flags<InputTarget::Flags> newTargetFlags, const DispatcherWindowInfo& windowInfos,
- const ConnectionManager& connections) {
+ ftl::Flags<InputTarget::Flags> newTargetFlags) {
const bool oldHasWallpaper = oldTargetFlags.test(InputTarget::Flags::FOREGROUND) &&
fromWindowHandle->getInfo()->inputConfig.test(
gui::WindowInfo::InputConfig::DUPLICATE_TOUCH_TO_WALLPAPER);
@@ -7150,7 +7153,7 @@
const sp<WindowInfoHandle> oldWallpaper =
oldHasWallpaper ? state.getWallpaperWindow(deviceId) : nullptr;
const sp<WindowInfoHandle> newWallpaper =
- newHasWallpaper ? windowInfos.findWallpaperWindowBelow(toWindowHandle) : nullptr;
+ newHasWallpaper ? mWindowInfos.findWallpaperWindowBelow(toWindowHandle) : nullptr;
if (oldWallpaper == newWallpaper) {
return {};
}
@@ -7171,10 +7174,10 @@
state.addOrUpdateWindow(newWallpaper, InputTarget::DispatchMode::AS_IS, wallpaperFlags,
deviceId, pointers, downTimeInTarget);
std::shared_ptr<Connection> wallpaperConnection =
- connections.getConnection(newWallpaper->getToken());
+ mConnectionManager.getConnection(newWallpaper->getToken());
if (wallpaperConnection != nullptr) {
std::shared_ptr<Connection> toConnection =
- connections.getConnection(toWindowHandle->getToken());
+ mConnectionManager.getConnection(toWindowHandle->getToken());
toConnection->inputState.mergePointerStateTo(wallpaperConnection->inputState);
pointerDowns.emplace_back(downTimeInTarget, wallpaperConnection, wallpaperFlags);
}
@@ -7374,9 +7377,12 @@
mTopology = displayTopologyGraph;
}
+InputDispatcher::DispatcherTouchState::DispatcherTouchState(const DispatcherWindowInfo& windowInfos,
+ const ConnectionManager& connections)
+ : mWindowInfos(windowInfos), mConnectionManager(connections) {}
+
ftl::Flags<InputTarget::Flags> InputDispatcher::DispatcherTouchState::getTargetFlags(
- const sp<WindowInfoHandle>& targetWindow, vec2 targetPosition, bool isSplit,
- const DispatcherWindowInfo& windowInfos) {
+ const sp<WindowInfoHandle>& targetWindow, vec2 targetPosition, bool isSplit) {
ftl::Flags<InputTarget::Flags> targetFlags;
if (canReceiveForegroundTouches(*targetWindow->getInfo())) {
// There should only be one touched window that can be "foreground" for the pointer.
@@ -7385,9 +7391,9 @@
if (isSplit) {
targetFlags |= InputTarget::Flags::SPLIT;
}
- if (windowInfos.isWindowObscuredAtPoint(targetWindow, targetPosition.x, targetPosition.y)) {
+ if (mWindowInfos.isWindowObscuredAtPoint(targetWindow, targetPosition.x, targetPosition.y)) {
targetFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED;
- } else if (windowInfos.isWindowObscured(targetWindow)) {
+ } else if (mWindowInfos.isWindowObscured(targetWindow)) {
targetFlags |= InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED;
}
return targetFlags;
@@ -7500,15 +7506,14 @@
void InputDispatcher::DispatcherTouchState::saveTouchStateForMotionEntry(
const android::inputdispatcher::MotionEntry& entry,
- android::inputdispatcher::TouchState&& touchState,
- const DispatcherWindowInfo& windowInfos) {
+ android::inputdispatcher::TouchState&& touchState) {
if (touchState.windows.empty()) {
- eraseTouchStateForMotionEntry(entry, windowInfos);
+ eraseTouchStateForMotionEntry(entry);
return;
}
if (InputFlags::connectedDisplaysCursorEnabled() && isMouseOrTouchpad(entry.source)) {
- mCursorStateByDisplay[windowInfos.getPrimaryDisplayId(entry.displayId)] =
+ mCursorStateByDisplay[mWindowInfos.getPrimaryDisplayId(entry.displayId)] =
std::move(touchState);
} else {
mTouchStatesByDisplay[entry.displayId] = std::move(touchState);
@@ -7516,21 +7521,19 @@
}
void InputDispatcher::DispatcherTouchState::eraseTouchStateForMotionEntry(
- const android::inputdispatcher::MotionEntry& entry,
- const DispatcherWindowInfo& windowInfos) {
+ const android::inputdispatcher::MotionEntry& entry) {
if (InputFlags::connectedDisplaysCursorEnabled() && isMouseOrTouchpad(entry.source)) {
- mCursorStateByDisplay.erase(windowInfos.getPrimaryDisplayId(entry.displayId));
+ mCursorStateByDisplay.erase(mWindowInfos.getPrimaryDisplayId(entry.displayId));
} else {
mTouchStatesByDisplay.erase(entry.displayId);
}
}
const TouchState* InputDispatcher::DispatcherTouchState::getTouchStateForMotionEntry(
- const android::inputdispatcher::MotionEntry& entry,
- const DispatcherWindowInfo& windowInfos) const {
+ const android::inputdispatcher::MotionEntry& entry) const {
if (InputFlags::connectedDisplaysCursorEnabled() && isMouseOrTouchpad(entry.source)) {
auto touchStateIt =
- mCursorStateByDisplay.find(windowInfos.getPrimaryDisplayId(entry.displayId));
+ mCursorStateByDisplay.find(mWindowInfos.getPrimaryDisplayId(entry.displayId));
if (touchStateIt != mCursorStateByDisplay.end()) {
return &touchStateIt->second;
}
@@ -7550,9 +7553,10 @@
return;
}
- // TODO(b/383092013): This is currently not accounting for the "topology group" concept.
- // Proper implementation requires looking tghrough all the displays in the topology group.
- const auto cursorStateIt = mCursorStateByDisplay.find(displayId);
+ // DisplayId for the Cursor state may not be same as supplied displayId if display is part of
+ // topology. Instead we should to check from the topology's primary display.
+ const auto cursorStateIt =
+ mCursorStateByDisplay.find(mWindowInfos.getPrimaryDisplayId(displayId));
if (cursorStateIt != mCursorStateByDisplay.end()) {
f(cursorStateIt->second);
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 7e8e142..38f7825 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -319,6 +319,11 @@
const sp<IBinder>& windowHandleToken,
std::optional<ui::LogicalDisplayId> displayId = {}) const;
+ // Lookup for WindowInfoHandle from token and a display-id. Lookup is done for all connected
+ // displays in the topology of the queried display.
+ sp<android::gui::WindowInfoHandle> findWindowHandleOnConnectedDisplays(
+ const sp<IBinder>& windowHandleToken, ui::LogicalDisplayId displayId) const;
+
bool isWindowPresent(const sp<android::gui::WindowInfoHandle>& windowHandle) const;
// Returns the touched window at the given location, excluding the ignoreWindow if provided.
@@ -349,6 +354,12 @@
std::string dumpDisplayAndWindowInfo() const;
private:
+ std::vector<ui::LogicalDisplayId> getConnectedDisplays(
+ ui::LogicalDisplayId displayId) const;
+
+ sp<android::gui::WindowInfoHandle> findWindowHandleOnDisplay(
+ const sp<IBinder>& windowHandleToken, ui::LogicalDisplayId displayId) const;
+
std::unordered_map<ui::LogicalDisplayId /*displayId*/,
std::vector<sp<android::gui::WindowInfoHandle>>>
mWindowHandlesByDisplay;
@@ -380,21 +391,20 @@
const ftl::Flags<InputTarget::Flags> targetFlags;
};
- static void addPointerWindowTarget(const sp<android::gui::WindowInfoHandle>& windowHandle,
- InputTarget::DispatchMode dispatchMode,
- ftl::Flags<InputTarget::Flags> targetFlags,
- std::bitset<MAX_POINTER_ID + 1> pointerIds,
- std::optional<nsecs_t> firstDownTimeInTarget,
- std::optional<ui::LogicalDisplayId> pointerDisplayId,
- const ConnectionManager& connections,
- const DispatcherWindowInfo& windowInfos,
- std::function<void()> dump,
- std::vector<InputTarget>& inputTargets);
+ DispatcherTouchState(const DispatcherWindowInfo& windowInfos,
+ const ConnectionManager& connections);
+
+ void addPointerWindowTarget(const sp<android::gui::WindowInfoHandle>& windowHandle,
+ InputTarget::DispatchMode dispatchMode,
+ ftl::Flags<InputTarget::Flags> targetFlags,
+ std::bitset<MAX_POINTER_ID + 1> pointerIds,
+ std::optional<nsecs_t> firstDownTimeInTarget,
+ std::optional<ui::LogicalDisplayId> pointerDisplayId,
+ std::function<void()> dump,
+ std::vector<InputTarget>& inputTargets);
base::Result<std::vector<InputTarget>, android::os::InputEventInjectionResult>
findTouchedWindowTargets(nsecs_t currentTime, const MotionEntry& entry,
- const ConnectionManager& connections,
- const DispatcherWindowInfo& windowInfos,
const sp<android::gui::WindowInfoHandle> dragWindow,
std::function<void(const MotionEntry&)> addDragEvent,
std::function<void()> dump);
@@ -421,8 +431,7 @@
// Updates the touchState for display from WindowInfo,
// returns list of CancellationArgs for every cancelled touch
- std::list<CancellationArgs> updateFromWindowInfo(ui::LogicalDisplayId displayId,
- const DispatcherWindowInfo& windowInfos);
+ std::list<CancellationArgs> updateFromWindowInfo(ui::LogicalDisplayId displayId);
void removeAllPointersForDevice(DeviceId deviceId);
@@ -431,9 +440,7 @@
std::optional<
std::tuple<sp<gui::WindowInfoHandle>, DeviceId, std::vector<PointerProperties>,
std::list<CancellationArgs>, std::list<PointerDownArgs>>>
- transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken,
- const DispatcherWindowInfo& windowInfos,
- const ConnectionManager& connections);
+ transferTouchGesture(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
base::Result<std::list<CancellationArgs>, status_t> pilferPointers(
const sp<IBinder>& token, const Connection& requestingConnection);
@@ -474,40 +481,31 @@
const sp<gui::WindowInfoHandle> toWindowHandle, TouchState& state,
DeviceId deviceId, const std::vector<PointerProperties>& pointers,
ftl::Flags<InputTarget::Flags> oldTargetFlags,
- ftl::Flags<InputTarget::Flags> newTargetFlags,
- const DispatcherWindowInfo& windowInfos, const ConnectionManager& connections);
+ ftl::Flags<InputTarget::Flags> newTargetFlags);
- void saveTouchStateForMotionEntry(const MotionEntry& entry, TouchState&& touchState,
- const DispatcherWindowInfo& windowInfos);
+ void saveTouchStateForMotionEntry(const MotionEntry& entry, TouchState&& touchState);
- void eraseTouchStateForMotionEntry(const MotionEntry& entry,
- const DispatcherWindowInfo& windowInfos);
+ void eraseTouchStateForMotionEntry(const MotionEntry& entry);
const TouchState* getTouchStateForMotionEntry(
- const android::inputdispatcher::MotionEntry& entry,
- const DispatcherWindowInfo& windowInfos) const;
+ const android::inputdispatcher::MotionEntry& entry) const;
bool canWindowReceiveMotion(const sp<gui::WindowInfoHandle>& window,
- const MotionEntry& motionEntry,
- const ConnectionManager& connections,
- const DispatcherWindowInfo& windowInfos) const;
+ const MotionEntry& motionEntry) const;
// Return true if stylus is currently down anywhere on the specified display,
// and false otherwise.
bool isStylusActiveInDisplay(ui::LogicalDisplayId displayId) const;
- static std::list<CancellationArgs> eraseRemovedWindowsFromWindowInfo(
- TouchState& state, ui::LogicalDisplayId displayId,
- const DispatcherWindowInfo& windowInfos);
+ std::list<CancellationArgs> eraseRemovedWindowsFromWindowInfo(
+ TouchState& state, ui::LogicalDisplayId displayId);
- static std::list<CancellationArgs> updateHoveringStateFromWindowInfo(
- TouchState& state, ui::LogicalDisplayId displayId,
- const DispatcherWindowInfo& windowInfos);
+ std::list<CancellationArgs> updateHoveringStateFromWindowInfo(
+ TouchState& state, ui::LogicalDisplayId displayId);
- static std::vector<InputTarget> findOutsideTargets(
- ui::LogicalDisplayId displayId, const sp<gui::WindowInfoHandle>& touchedWindow,
- int32_t pointerId, const ConnectionManager& connections,
- const DispatcherWindowInfo& windowInfos, std::function<void()> dump);
+ std::vector<InputTarget> findOutsideTargets(ui::LogicalDisplayId displayId,
+ const sp<gui::WindowInfoHandle>& touchedWindow,
+ int32_t pointerId, std::function<void()> dump);
/**
* Slip the wallpaper touch if necessary.
@@ -522,18 +520,18 @@
* @param targets the current targets to add the walpaper ones to
* @param eventTime the new downTime for the wallpaper target
*/
- static void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags,
- const sp<android::gui::WindowInfoHandle>& oldWindowHandle,
- const sp<android::gui::WindowInfoHandle>& newWindowHandle,
- TouchState& state, const MotionEntry& entry,
- std::vector<InputTarget>& targets,
- const ConnectionManager& connections,
- const DispatcherWindowInfo& windowInfos,
- std::function<void()> dump);
+ void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags,
+ const sp<android::gui::WindowInfoHandle>& oldWindowHandle,
+ const sp<android::gui::WindowInfoHandle>& newWindowHandle,
+ TouchState& state, const MotionEntry& entry,
+ std::vector<InputTarget>& targets, std::function<void()> dump);
- static ftl::Flags<InputTarget::Flags> getTargetFlags(
+ ftl::Flags<InputTarget::Flags> getTargetFlags(
const sp<android::gui::WindowInfoHandle>& targetWindow, vec2 targetPosition,
- bool isSplit, const DispatcherWindowInfo& windowInfos);
+ bool isSplit);
+
+ const DispatcherWindowInfo& mWindowInfos;
+ const ConnectionManager& mConnectionManager;
};
DispatcherTouchState mTouchStates GUARDED_BY(mLock);
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index d21c4d7..782a54f 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -15,6 +15,7 @@
*/
#include "DebugConfig.h"
+#include "input/Input.h"
#include "input/InputDevice.h"
#include "input/InputFlags.h"
@@ -25,17 +26,6 @@
namespace android::inputdispatcher {
-namespace {
-
-bool isMouseOrTouchpad(uint32_t sources) {
- // Check if this is a mouse or touchpad, but not a drawing tablet.
- return isFromSource(sources, AINPUT_SOURCE_MOUSE_RELATIVE) ||
- (isFromSource(sources, AINPUT_SOURCE_MOUSE) &&
- !isFromSource(sources, AINPUT_SOURCE_STYLUS));
-}
-
-} // namespace
-
InputState::InputState(const IdGenerator& idGenerator) : mIdGenerator(idGenerator) {}
InputState::~InputState() {}
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index 3934e78..dc7f7c1 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -66,9 +66,10 @@
"mapper/accumulator/SingleTouchMotionAccumulator.cpp",
"mapper/accumulator/TouchButtonAccumulator.cpp",
"mapper/gestures/GestureConverter.cpp",
- "mapper/gestures/GesturesLogging.cpp",
+ "mapper/gestures/GesturesLogcatAdapter.cpp",
"mapper/gestures/HardwareProperties.cpp",
"mapper/gestures/HardwareStateConverter.cpp",
+ "mapper/gestures/Logging.cpp",
"mapper/gestures/PropertyProvider.cpp",
"mapper/gestures/TimerProvider.cpp",
],
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 5dce074..adbfdeb 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -88,6 +88,7 @@
* If any new classes are added, we need to add them in rust input side too.
*/
enum class InputDeviceClass : uint32_t {
+ // LINT.IfChange
/* The input device is a keyboard or has buttons. */
KEYBOARD = android::os::IInputConstants::DEVICE_CLASS_KEYBOARD,
@@ -144,6 +145,7 @@
/* The input device is external (not built-in). */
EXTERNAL = android::os::IInputConstants::DEVICE_CLASS_EXTERNAL,
+ // LINT.ThenChange(frameworks/native/services/inputflinger/tests/fuzzers/MapperHelpers.h)
};
enum class SysfsClass : uint32_t {
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index 18a7102..c982dab 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -40,6 +40,7 @@
#include "TouchCursorInputMapperCommon.h"
#include "TouchpadInputMapper.h"
#include "gestures/HardwareProperties.h"
+#include "gestures/Logging.h"
#include "gestures/TimerProvider.h"
#include "ui/Rotation.h"
@@ -49,15 +50,6 @@
namespace {
-/**
- * Log details of each gesture output by the gestures library.
- * Enable this via "adb shell setprop log.tag.TouchpadInputMapperGestures DEBUG" (requires
- * restarting the shell)
- */
-const bool DEBUG_TOUCHPAD_GESTURES =
- __android_log_is_loggable(ANDROID_LOG_DEBUG, "TouchpadInputMapperGestures",
- ANDROID_LOG_INFO);
-
std::vector<double> createAccelerationCurveForSensitivity(int32_t sensitivity,
bool accelerationEnabled,
size_t propertySize) {
@@ -470,7 +462,7 @@
std::list<NotifyArgs> TouchpadInputMapper::sendHardwareState(nsecs_t when, nsecs_t readTime,
SelfContainedHardwareState schs) {
- ALOGD_IF(DEBUG_TOUCHPAD_GESTURES, "New hardware state: %s", schs.state.String().c_str());
+ ALOGD_IF(debugTouchpadGestures(), "New hardware state: %s", schs.state.String().c_str());
mGestureInterpreter->PushHardwareState(&schs.state);
return processGestures(when, readTime);
}
@@ -481,7 +473,7 @@
}
void TouchpadInputMapper::consumeGesture(const Gesture* gesture) {
- ALOGD_IF(DEBUG_TOUCHPAD_GESTURES, "Gesture ready: %s", gesture->String().c_str());
+ ALOGD_IF(debugTouchpadGestures(), "Gesture ready: %s", gesture->String().c_str());
if (mResettingInterpreter) {
// We already handle tidying up fake fingers etc. in GestureConverter::reset, so we should
// ignore any gestures produced from the interpreter while we're resetting it.
diff --git a/services/inputflinger/reader/mapper/gestures/GesturesLogging.cpp b/services/inputflinger/reader/mapper/gestures/GesturesLogcatAdapter.cpp
similarity index 72%
rename from services/inputflinger/reader/mapper/gestures/GesturesLogging.cpp
rename to services/inputflinger/reader/mapper/gestures/GesturesLogcatAdapter.cpp
index 26028c5..51905f9 100644
--- a/services/inputflinger/reader/mapper/gestures/GesturesLogging.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GesturesLogcatAdapter.cpp
@@ -22,29 +22,17 @@
#include <log/log.h>
+#include "Logging.h"
#include "include/gestures.h"
extern "C" {
-namespace {
-
-/**
- * Log details of each gesture output by the gestures library.
- * Enable this via "adb shell setprop log.tag.TouchpadInputMapperGestures DEBUG" (requires
- * restarting the shell)
- */
-const bool DEBUG_TOUCHPAD_GESTURES =
- __android_log_is_loggable(ANDROID_LOG_DEBUG, "TouchpadInputMapperGestures",
- ANDROID_LOG_INFO);
-
-} // namespace
-
void gestures_log(int verb, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
if (verb == GESTURES_LOG_ERROR) {
LOG_PRI_VA(ANDROID_LOG_ERROR, LOG_TAG, fmt, args);
- } else if (DEBUG_TOUCHPAD_GESTURES) {
+ } else if (android::debugTouchpadGestures()) {
if (verb == GESTURES_LOG_INFO) {
LOG_PRI_VA(ANDROID_LOG_INFO, LOG_TAG, fmt, args);
} else {
diff --git a/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp b/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp
index 6885adb..3e62f36 100644
--- a/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/HardwareStateConverter.cpp
@@ -25,12 +25,8 @@
#include <com_android_input_flags.h>
#include <linux/input-event-codes.h>
-namespace input_flags = com::android::input::flags;
-
namespace android {
-const bool REPORT_PALMS_TO_GESTURES_LIBRARY = input_flags::report_palms_to_gestures_library();
-
HardwareStateConverter::HardwareStateConverter(const InputDeviceContext& deviceContext,
MultiTouchMotionAccumulator& motionAccumulator)
: mDeviceContext(deviceContext),
@@ -81,18 +77,11 @@
}
schs.fingers.clear();
- size_t numPalms = 0;
for (size_t i = 0; i < mMotionAccumulator.getSlotCount(); i++) {
MultiTouchMotionAccumulator::Slot slot = mMotionAccumulator.getSlot(i);
if (!slot.isInUse()) {
continue;
}
- // Some touchpads continue to report contacts even after they've identified them as palms.
- // We want to exclude these contacts from the HardwareStates.
- if (!REPORT_PALMS_TO_GESTURES_LIBRARY && slot.getToolType() == ToolType::PALM) {
- numPalms++;
- continue;
- }
FingerState& fingerState = schs.fingers.emplace_back();
fingerState = {};
@@ -105,15 +94,13 @@
fingerState.position_x = slot.getX();
fingerState.position_y = slot.getY();
fingerState.tracking_id = slot.getTrackingId();
- if (REPORT_PALMS_TO_GESTURES_LIBRARY) {
- fingerState.tool_type = slot.getToolType() == ToolType::PALM
- ? FingerState::ToolType::kPalm
- : FingerState::ToolType::kFinger;
- }
+ fingerState.tool_type = slot.getToolType() == ToolType::PALM
+ ? FingerState::ToolType::kPalm
+ : FingerState::ToolType::kFinger;
}
schs.state.fingers = schs.fingers.data();
schs.state.finger_cnt = schs.fingers.size();
- schs.state.touch_cnt = mTouchButtonAccumulator.getTouchCount() - numPalms;
+ schs.state.touch_cnt = mTouchButtonAccumulator.getTouchCount();
return schs;
}
diff --git a/services/inputflinger/reader/mapper/gestures/Logging.cpp b/services/inputflinger/reader/mapper/gestures/Logging.cpp
new file mode 100644
index 0000000..b9b97c3
--- /dev/null
+++ b/services/inputflinger/reader/mapper/gestures/Logging.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2025 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 "Logging.h"
+
+#include <android-base/properties.h>
+#include <log/log.h>
+
+namespace {
+
+const bool IS_DEBUGGABLE_BUILD =
+#if defined(__ANDROID__)
+ android::base::GetBoolProperty("ro.debuggable", false);
+#else
+ true;
+#endif
+
+} // namespace
+
+namespace android {
+
+bool debugTouchpadGestures() {
+ if (!IS_DEBUGGABLE_BUILD) {
+ static const bool DEBUG_RAW_EVENTS =
+ __android_log_is_loggable(ANDROID_LOG_DEBUG, "TouchpadInputMapperGestures",
+ ANDROID_LOG_INFO);
+ return DEBUG_RAW_EVENTS;
+ }
+ return __android_log_is_loggable(ANDROID_LOG_DEBUG, "TouchpadInputMapperGestures",
+ ANDROID_LOG_INFO);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/reader/mapper/gestures/Logging.h b/services/inputflinger/reader/mapper/gestures/Logging.h
new file mode 100644
index 0000000..db59fb3
--- /dev/null
+++ b/services/inputflinger/reader/mapper/gestures/Logging.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android {
+
+/**
+ * Log details of touchpad gesture library input, output, and processing.
+ * Enable this via "adb shell setprop log.tag.TouchpadInputMapperGestures DEBUG".
+ * This requires a restart on non-debuggable (e.g. user) builds, but should take effect immediately
+ * on debuggable builds (e.g. userdebug).
+ */
+bool debugTouchpadGestures();
+
+} // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/tests/HardwareStateConverter_test.cpp b/services/inputflinger/tests/HardwareStateConverter_test.cpp
index 34c81fc..ee125bb 100644
--- a/services/inputflinger/tests/HardwareStateConverter_test.cpp
+++ b/services/inputflinger/tests/HardwareStateConverter_test.cpp
@@ -33,13 +33,6 @@
namespace android {
-namespace {
-
-const auto REPORT_PALMS =
- ACONFIG_FLAG(com::android::input::flags, report_palms_to_gestures_library);
-
-} // namespace
-
class HardwareStateConverterTest : public testing::Test {
public:
HardwareStateConverterTest()
@@ -201,24 +194,7 @@
EXPECT_EQ(0u, finger2.flags);
}
-TEST_F_WITH_FLAGS(HardwareStateConverterTest, OnePalmDisableReportPalms,
- REQUIRES_FLAGS_DISABLED(REPORT_PALMS)) {
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_SLOT, 0);
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_TRACKING_ID, 123);
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_POSITION_X, 50);
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_POSITION_Y, 100);
-
- processAxis(ARBITRARY_TIME, EV_KEY, BTN_TOUCH, 1);
- processAxis(ARBITRARY_TIME, EV_KEY, BTN_TOOL_FINGER, 1);
- std::optional<SelfContainedHardwareState> schs = processSync(ARBITRARY_TIME);
- ASSERT_TRUE(schs.has_value());
- EXPECT_EQ(0, schs->state.touch_cnt);
- EXPECT_EQ(0, schs->state.finger_cnt);
-}
-
-TEST_F_WITH_FLAGS(HardwareStateConverterTest, OnePalmEnableReportPalms,
- REQUIRES_FLAGS_ENABLED(REPORT_PALMS)) {
+TEST_F(HardwareStateConverterTest, OnePalm) {
processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_SLOT, 0);
processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);
processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_TRACKING_ID, 123);
@@ -234,54 +210,7 @@
EXPECT_EQ(FingerState::ToolType::kPalm, schs->state.fingers[0].tool_type);
}
-TEST_F_WITH_FLAGS(HardwareStateConverterTest, OneFingerTurningIntoAPalmDisableReportPalms,
- REQUIRES_FLAGS_DISABLED(REPORT_PALMS)) {
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_SLOT, 0);
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_TRACKING_ID, 123);
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_POSITION_X, 50);
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_POSITION_Y, 100);
-
- processAxis(ARBITRARY_TIME, EV_KEY, BTN_TOUCH, 1);
- processAxis(ARBITRARY_TIME, EV_KEY, BTN_TOOL_FINGER, 1);
-
- std::optional<SelfContainedHardwareState> schs = processSync(ARBITRARY_TIME);
- ASSERT_TRUE(schs.has_value());
- EXPECT_EQ(1, schs->state.touch_cnt);
- EXPECT_EQ(1, schs->state.finger_cnt);
-
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PALM);
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_POSITION_X, 51);
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_POSITION_Y, 99);
-
- schs = processSync(ARBITRARY_TIME);
- ASSERT_TRUE(schs.has_value());
- EXPECT_EQ(0, schs->state.touch_cnt);
- ASSERT_EQ(0, schs->state.finger_cnt);
-
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_POSITION_X, 53);
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_POSITION_Y, 97);
-
- schs = processSync(ARBITRARY_TIME);
- ASSERT_TRUE(schs.has_value());
- EXPECT_EQ(0, schs->state.touch_cnt);
- EXPECT_EQ(0, schs->state.finger_cnt);
-
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_POSITION_X, 55);
- processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_POSITION_Y, 95);
- schs = processSync(ARBITRARY_TIME);
- ASSERT_TRUE(schs.has_value());
- EXPECT_EQ(1, schs->state.touch_cnt);
- ASSERT_EQ(1, schs->state.finger_cnt);
- const FingerState& newFinger = schs->state.fingers[0];
- EXPECT_EQ(123, newFinger.tracking_id);
- EXPECT_NEAR(55, newFinger.position_x, EPSILON);
- EXPECT_NEAR(95, newFinger.position_y, EPSILON);
-}
-
-TEST_F_WITH_FLAGS(HardwareStateConverterTest, OneFingerTurningIntoAPalmEnableReportPalms,
- REQUIRES_FLAGS_ENABLED(REPORT_PALMS)) {
+TEST_F(HardwareStateConverterTest, OneFingerTurningIntoAPalmEnableReportPalms) {
processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_SLOT, 0);
processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
processAxis(ARBITRARY_TIME, EV_ABS, ABS_MT_TRACKING_ID, 123);
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 6c5d94d..2b9b470 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -12414,18 +12414,22 @@
0});
}
- void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
+ void injectDown(int fromSource = AINPUT_SOURCE_TOUCHSCREEN,
+ ui::LogicalDisplayId displayId = ui::LogicalDisplayId::DEFAULT) {
bool consumeButtonPress = false;
+ const PointF location =
+ displayId == ui::LogicalDisplayId::DEFAULT ? PointF(50, 50) : PointF(50, 450);
switch (fromSource) {
case AINPUT_SOURCE_TOUCHSCREEN: {
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
- injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN,
- ui::LogicalDisplayId::DEFAULT, {50, 50}))
+ injectMotionDown(*mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, displayId,
+ location))
<< "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
break;
}
case AINPUT_SOURCE_STYLUS: {
- PointerBuilder pointer = PointerBuilder(0, ToolType::STYLUS).x(50).y(50);
+ PointerBuilder pointer =
+ PointerBuilder(0, ToolType::STYLUS).x(location.x).y(location.y);
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionEvent(*mDispatcher,
MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
@@ -12448,12 +12452,14 @@
break;
}
case AINPUT_SOURCE_MOUSE: {
- PointerBuilder pointer =
- PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50);
+ PointerBuilder pointer = PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE)
+ .x(location.x)
+ .y(location.y);
ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
injectMotionEvent(*mDispatcher,
MotionEventBuilder(AMOTION_EVENT_ACTION_DOWN,
AINPUT_SOURCE_MOUSE)
+ .displayId(displayId)
.buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
.pointer(pointer)
.build()));
@@ -12461,6 +12467,7 @@
injectMotionEvent(*mDispatcher,
MotionEventBuilder(AMOTION_EVENT_ACTION_BUTTON_PRESS,
AINPUT_SOURCE_MOUSE)
+ .displayId(displayId)
.actionButton(AMOTION_EVENT_BUTTON_PRIMARY)
.buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
.pointer(pointer)
@@ -12474,25 +12481,30 @@
}
// Window should receive motion event.
- mWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
+ sp<FakeWindowHandle>& targetWindow =
+ displayId == ui::LogicalDisplayId::DEFAULT ? mWindow : mWindowOnSecondDisplay;
+ targetWindow->consumeMotionDown(displayId);
if (consumeButtonPress) {
- mWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
+ targetWindow->consumeMotionEvent(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
}
- // Spy window should also receive motion event
- mSpyWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
+
+ // Spy window should also receive motion event if event is on the same display.
+ if (displayId == ui::LogicalDisplayId::DEFAULT) {
+ mSpyWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT);
+ }
}
// Start performing drag, we will create a drag window and transfer touch to it.
// @param sendDown : if true, send a motion down on first window before perform drag and drop.
// Returns true on success.
- bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN) {
+ bool startDrag(bool sendDown = true, int fromSource = AINPUT_SOURCE_TOUCHSCREEN,
+ ui::LogicalDisplayId dragStartDisplay = ui::LogicalDisplayId::DEFAULT) {
if (sendDown) {
- injectDown(fromSource);
+ injectDown(fromSource, dragStartDisplay);
}
// The drag window covers the entire display
- mDragWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow",
- ui::LogicalDisplayId::DEFAULT);
+ mDragWindow = sp<FakeWindowHandle>::make(mApp, mDispatcher, "DragWindow", dragStartDisplay);
mDragWindow->setTouchableRegion(Region{{0, 0, 0, 0}});
mDispatcher->onWindowInfosChanged(
{{*mDragWindow->getInfo(), *mSpyWindow->getInfo(), *mWindow->getInfo(),
@@ -12501,14 +12513,17 @@
0,
0});
+ sp<FakeWindowHandle>& targetWindow = dragStartDisplay == ui::LogicalDisplayId::DEFAULT
+ ? mWindow
+ : mWindowOnSecondDisplay;
+
// Transfer touch focus to the drag window
bool transferred =
- mDispatcher->transferTouchGesture(mWindow->getToken(), mDragWindow->getToken(),
+ mDispatcher->transferTouchGesture(targetWindow->getToken(), mDragWindow->getToken(),
/*isDragDrop=*/true);
if (transferred) {
- mWindow->consumeMotionCancel();
- mDragWindow->consumeMotionDown(ui::LogicalDisplayId::DEFAULT,
- AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
+ targetWindow->consumeMotionCancel(dragStartDisplay);
+ mDragWindow->consumeMotionDown(dragStartDisplay, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
}
return transferred;
}
@@ -15292,10 +15307,10 @@
mWindow->consumeMotionUp(SECOND_DISPLAY_ID);
}
-TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseDragAndDrop) {
+TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseDragAndDropFromPrimaryDisplay) {
SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
- startDrag(true, AINPUT_SOURCE_MOUSE);
+ EXPECT_TRUE(startDrag(true, AINPUT_SOURCE_MOUSE));
// Move on window.
mDispatcher->notifyMotion(
MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
@@ -15346,4 +15361,89 @@
mWindowOnSecondDisplay->assertNoEvents();
}
+TEST_F(InputDispatcherConnectedDisplayTest, MultiDisplayMouseDragAndDropFromNonPrimaryDisplay) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+
+ EXPECT_TRUE(startDrag(true, AINPUT_SOURCE_MOUSE, SECOND_DISPLAY_ID));
+ // Move on window.
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
+ .displayId(SECOND_DISPLAY_ID)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50))
+ .build());
+ mDragWindow->consumeMotionMove(SECOND_DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
+ mWindow->assertNoEvents();
+ mSecondWindow->assertNoEvents();
+ mWindowOnSecondDisplay->consumeDragEvent(false, 50, 50);
+
+ // Move to window on the primary display
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_MOUSE)
+ .displayId(DISPLAY_ID)
+ .buttonState(AMOTION_EVENT_BUTTON_PRIMARY)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50))
+ .build());
+ mDragWindow->consumeMotionMove(DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
+ mWindow->consumeDragEvent(false, 50, 50);
+ mSecondWindow->assertNoEvents();
+ mWindowOnSecondDisplay->consumeDragEvent(true, 50, 50);
+
+ // drop on the primary display
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_MOUSE)
+ .displayId(DISPLAY_ID)
+ .buttonState(0)
+ .pointer(PointerBuilder(MOUSE_POINTER_ID, ToolType::MOUSE).x(50).y(50))
+ .build());
+ mDragWindow->consumeMotionUp(DISPLAY_ID, AMOTION_EVENT_FLAG_NO_FOCUS_CHANGE);
+ mFakePolicy->assertDropTargetEquals(*mDispatcher, mWindow->getToken());
+ mWindow->assertNoEvents();
+ mSecondWindow->assertNoEvents();
+ mWindowOnSecondDisplay->assertNoEvents();
+}
+
+using InputDispatcherConnectedDisplayPointerInWindowTest = InputDispatcherConnectedDisplayTest;
+
+TEST_F(InputDispatcherConnectedDisplayPointerInWindowTest, MouseOnWindowOnPrimaryDisplay) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
+ .build());
+
+ mWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+ mSpyWindow->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+ mWindowOnSecondDisplay->assertNoEvents();
+
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(mWindow->getToken(), DISPLAY_ID, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(mSpyWindow->getToken(), DISPLAY_ID, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(mWindowOnSecondDisplay->getToken(),
+ SECOND_DISPLAY_ID, DEVICE_ID, /*pointerId=*/0));
+}
+
+TEST_F(InputDispatcherConnectedDisplayPointerInWindowTest, MouseOnWindowOnNonPrimaryDisplay) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+
+ mDispatcher->notifyMotion(
+ MotionArgsBuilder(ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
+ .displayId(SECOND_DISPLAY_ID)
+ .pointer(PointerBuilder(/*id=*/0, ToolType::MOUSE).x(50).y(50))
+ .build());
+
+ mWindow->assertNoEvents();
+ mSpyWindow->assertNoEvents();
+ mWindowOnSecondDisplay->consumeMotionEvent(WithMotionAction(ACTION_HOVER_ENTER));
+
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(mWindow->getToken(), DISPLAY_ID, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_FALSE(mDispatcher->isPointerInWindow(mSpyWindow->getToken(), DISPLAY_ID, DEVICE_ID,
+ /*pointerId=*/0));
+ ASSERT_TRUE(mDispatcher->isPointerInWindow(mWindowOnSecondDisplay->getToken(),
+ SECOND_DISPLAY_ID, DEVICE_ID, /*pointerId=*/0));
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp
index d02c3d9..38d0679 100644
--- a/services/inputflinger/tests/PointerChoreographer_test.cpp
+++ b/services/inputflinger/tests/PointerChoreographer_test.cpp
@@ -24,6 +24,7 @@
#include "FakePointerController.h"
#include "InterfaceMocks.h"
#include "NotifyArgsBuilders.h"
+#include "ScopedFlagOverride.h"
#include "TestEventMatchers.h"
#include "TestInputListener.h"
@@ -114,6 +115,10 @@
}) {}
class PointerChoreographerTest : public testing::Test {
+public:
+ static constexpr int DENSITY_MEDIUM = 160;
+ static constexpr int DENSITY_HIGH = 320;
+
protected:
TestInputListener mTestListener;
sp<gui::WindowInfosListener> mRegisteredWindowInfoListener;
@@ -140,6 +145,22 @@
});
}
+ void setDefaultMouseDisplayId(ui::LogicalDisplayId displayId) {
+ if (input_flags::connected_displays_cursor()) {
+ // setDefaultMouseDisplayId is no-op if connected displays are enabled, mouse display is
+ // set based on primary display of the topology.
+ // Setting topology with the primary display should have same effect as calling
+ // setDefaultMouseDisplayId without topology.
+ // For this reason in tests we mock this behavior by creating topology with a single
+ // display.
+ mChoreographer.setDisplayTopology({.primaryDisplayId = displayId,
+ .graph{{displayId, {}}},
+ .displaysDensity = {{displayId, DENSITY_MEDIUM}}});
+ } else {
+ mChoreographer.setDefaultMouseDisplayId(displayId);
+ }
+ }
+
std::shared_ptr<FakePointerController> assertPointerControllerCreated(
ControllerType expectedType) {
EXPECT_FALSE(mCreatedControllers.empty()) << "No PointerController was created";
@@ -292,7 +313,7 @@
TEST_F(PointerChoreographerTest, SetsDefaultMouseViewportForPointerController) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// For a mouse event without a target display, default viewport should be set for
// the PointerController.
@@ -309,7 +330,7 @@
WhenDefaultMouseDisplayChangesSetsDefaultMouseViewportForPointerController) {
// Set one display as a default mouse display and emit mouse event to create PointerController.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -320,7 +341,7 @@
// Change default mouse display. Existing PointerController should be removed and a new one
// should be created.
- mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
+ setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
assertPointerControllerRemoved(firstDisplayPc);
auto secondDisplayPc = assertPointerControllerCreated(ControllerType::MOUSE);
@@ -329,7 +350,7 @@
}
TEST_F(PointerChoreographerTest, CallsNotifyPointerDisplayIdChanged) {
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
@@ -341,7 +362,7 @@
}
TEST_F(PointerChoreographerTest, WhenViewportIsSetLaterCallsNotifyPointerDisplayIdChanged) {
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -354,7 +375,7 @@
}
TEST_F(PointerChoreographerTest, WhenMouseIsRemovedCallsNotifyPointerDisplayIdChanged) {
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
@@ -373,7 +394,7 @@
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
// Set one viewport as a default mouse display ID.
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -382,7 +403,7 @@
assertPointerDisplayIdNotified(DISPLAY_ID);
// Set another viewport as a default mouse display ID. The mouse is moved to the other display.
- mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
+ setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
assertPointerControllerRemoved(firstDisplayPc);
assertPointerControllerCreated(ControllerType::MOUSE);
@@ -391,7 +412,7 @@
TEST_F(PointerChoreographerTest, MouseMovesPointerAndReturnsNewArgs) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -421,7 +442,7 @@
TEST_F(PointerChoreographerTest, AbsoluteMouseMovesPointerAndReturnsNewArgs) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -457,7 +478,7 @@
AssociatedMouseMovesPointerOnAssociatedDisplayAndDoesNotMovePointerOnDefaultDisplay) {
// Add two displays and set one to default.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// Add two devices, one unassociated and the other associated with non-default mouse display.
mChoreographer.notifyInputDevicesChanged(
@@ -496,7 +517,7 @@
TEST_F(PointerChoreographerTest, DoesNotMovePointerForMouseRelativeSource) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -543,7 +564,7 @@
TEST_F(PointerChoreographerTest, WhenPointerCaptureEnabledHidesPointer) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -562,7 +583,7 @@
TEST_F(PointerChoreographerTest, MultipleMiceConnectionAndRemoval) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// A mouse is connected, and the pointer is shown.
mChoreographer.notifyInputDevicesChanged(
@@ -599,7 +620,7 @@
TEST_F(PointerChoreographerTest, UnrelatedChangeDoesNotUnfadePointer) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -628,7 +649,7 @@
TEST_F(PointerChoreographerTest, DisabledMouseConnected) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
InputDeviceInfo mouseDeviceInfo =
generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID);
// Disable this mouse device.
@@ -641,7 +662,7 @@
TEST_F(PointerChoreographerTest, MouseDeviceDisableLater) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
InputDeviceInfo mouseDeviceInfo =
generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID);
@@ -660,7 +681,7 @@
TEST_F(PointerChoreographerTest, MultipleEnabledAndDisabledMiceConnectionAndRemoval) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
InputDeviceInfo disabledMouseDeviceInfo =
generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID);
disabledMouseDeviceInfo.setEnabled(false);
@@ -1008,6 +1029,34 @@
pc->assertPointerIconSet(PointerIconStyle::TYPE_SPOT_HOVER);
}
+TEST_F(PointerChoreographerTest, StylusHoverEnterFadesMouseOnDisplay) {
+ // Make sure there are PointerControllers for a mouse and a stylus.
+ mChoreographer.setStylusPointerIconEnabled(true);
+ setDefaultMouseDisplayId(DISPLAY_ID);
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID),
+ generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}});
+ mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(MOUSE_POINTER)
+ .deviceId(DEVICE_ID)
+ .displayId(ui::LogicalDisplayId::INVALID)
+ .build());
+ auto mousePc = assertPointerControllerCreated(ControllerType::MOUSE);
+ ASSERT_TRUE(mousePc->isPointerShown());
+
+ // Start hovering with a stylus. This should fade the mouse cursor.
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+ .pointer(STYLUS_POINTER)
+ .deviceId(SECOND_DEVICE_ID)
+ .displayId(DISPLAY_ID)
+ .build());
+ ASSERT_FALSE(mousePc->isPointerShown());
+}
+
using StylusFixtureParam =
std::tuple</*name*/ std::string_view, /*source*/ uint32_t, ControllerType>;
@@ -1378,7 +1427,7 @@
TEST_F(PointerChoreographerTest, SetsDefaultTouchpadViewportForPointerController) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// For a touchpad event without a target display, default viewport should be set for
// the PointerController.
@@ -1394,7 +1443,7 @@
WhenDefaultTouchpadDisplayChangesSetsDefaultTouchpadViewportForPointerController) {
// Set one display as a default touchpad display and create PointerController.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -1403,7 +1452,7 @@
firstDisplayPc->assertViewportSet(DISPLAY_ID);
// Change default mouse display. Existing PointerController should be removed.
- mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
+ setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
assertPointerControllerRemoved(firstDisplayPc);
auto secondDisplayPc = assertPointerControllerCreated(ControllerType::MOUSE);
@@ -1411,7 +1460,7 @@
}
TEST_F(PointerChoreographerTest, TouchpadCallsNotifyPointerDisplayIdChanged) {
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
@@ -1423,7 +1472,7 @@
}
TEST_F(PointerChoreographerTest, WhenViewportIsSetLaterTouchpadCallsNotifyPointerDisplayIdChanged) {
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -1436,7 +1485,7 @@
}
TEST_F(PointerChoreographerTest, WhenTouchpadIsRemovedCallsNotifyPointerDisplayIdChanged) {
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
@@ -1456,7 +1505,7 @@
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
// Set one viewport as a default mouse display ID.
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -1466,7 +1515,7 @@
// Set another viewport as a default mouse display ID. ui::LogicalDisplayId::INVALID will be
// notified before a touchpad event.
- mChoreographer.setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
+ setDefaultMouseDisplayId(ANOTHER_DISPLAY_ID);
assertPointerControllerRemoved(firstDisplayPc);
assertPointerControllerCreated(ControllerType::MOUSE);
@@ -1475,7 +1524,7 @@
TEST_F(PointerChoreographerTest, TouchpadMovesPointerAndReturnsNewArgs) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -1505,7 +1554,7 @@
TEST_F(PointerChoreographerTest, TouchpadAddsPointerPositionToTheCoords) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -1582,7 +1631,7 @@
AssociatedTouchpadMovesPointerOnAssociatedDisplayAndDoesNotMovePointerOnDefaultDisplay) {
// Add two displays and set one to default.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// Add two devices, one unassociated and the other associated with non-default mouse display.
mChoreographer.notifyInputDevicesChanged(
@@ -1623,7 +1672,7 @@
TEST_F(PointerChoreographerTest, DoesNotMovePointerForTouchpadSource) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -1660,7 +1709,7 @@
TEST_F(PointerChoreographerTest, WhenPointerCaptureEnabledTouchpadHidesPointer) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -1680,7 +1729,7 @@
TEST_F(PointerChoreographerTest, SetsPointerIconForMouse) {
// Make sure there is a PointerController.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -1696,7 +1745,7 @@
TEST_F(PointerChoreographerTest, DoesNotSetMousePointerIconForWrongDisplayId) {
// Make sure there is a PointerController.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -1713,7 +1762,7 @@
TEST_F(PointerChoreographerTest, DoesNotSetPointerIconForWrongDeviceId) {
// Make sure there is a PointerController.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -1730,7 +1779,7 @@
TEST_F(PointerChoreographerTest, SetsCustomPointerIconForMouse) {
// Make sure there is a PointerController.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -1754,7 +1803,7 @@
TEST_F(PointerChoreographerTest, SetsPointerIconForMouseOnTwoDisplays) {
// Make sure there are two PointerControllers on different displays.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID),
@@ -1778,7 +1827,7 @@
TEST_F(PointerChoreographerTest, A11yPointerMotionFilterMouse) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
@@ -1812,7 +1861,7 @@
TEST_F(PointerChoreographerTest, A11yPointerMotionFilterTouchpad) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
@@ -2210,7 +2259,7 @@
// Make sure there are PointerControllers for a mouse and a stylus.
mChoreographer.setStylusPointerIconEnabled(true);
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID),
@@ -2245,7 +2294,7 @@
TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerOnDisplay) {
// Make sure there are two PointerControllers on different displays.
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
{generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ui::LogicalDisplayId::INVALID),
@@ -2299,7 +2348,7 @@
TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerWhenDeviceConnected) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// Hide the pointer on the display, and then connect the mouse.
mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);
@@ -2316,7 +2365,7 @@
TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForTouchpad) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// Hide the pointer on the display.
mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);
@@ -2365,7 +2414,7 @@
TEST_F(PointerChoreographerTest, DrawingTabletCanReportMouseEvent) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0,
@@ -2392,7 +2441,7 @@
TEST_F(PointerChoreographerTest, MultipleDrawingTabletsReportMouseEvents) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// First drawing tablet is added
mChoreographer.notifyInputDevicesChanged(
@@ -2440,7 +2489,7 @@
TEST_F(PointerChoreographerTest, MouseAndDrawingTabletReportMouseEvents) {
mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
- mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+ setDefaultMouseDisplayId(DISPLAY_ID);
// Mouse and drawing tablet connected
mChoreographer.notifyInputDevicesChanged(
@@ -2684,15 +2733,29 @@
metaKeyCombinationDoesNotHidePointer(*pc, AKEYCODE_A, AKEYCODE_META_RIGHT);
}
-using PointerChoreographerDisplayTopologyTestFixtureParam =
+class PointerChoreographerDisplayTopologyTests : public PointerChoreographerTest {
+protected:
+ DisplayViewport createViewport(ui::LogicalDisplayId displayId, int32_t width, int32_t height,
+ ui::Rotation orientation) {
+ DisplayViewport viewport;
+ viewport.displayId = displayId;
+ viewport.logicalRight = width;
+ viewport.logicalBottom = height;
+ viewport.orientation = orientation;
+ return viewport;
+ }
+};
+
+using PointerChoreographerDisplayTopologyCursorTestFixtureParam =
std::tuple<std::string_view /*name*/, int32_t /*source device*/,
ControllerType /*PointerController*/, ToolType /*pointer tool type*/,
vec2 /*source position*/, vec2 /*hover move X/Y*/,
ui::LogicalDisplayId /*destination display*/, vec2 /*destination position*/>;
-class PointerChoreographerDisplayTopologyTestFixture
- : public PointerChoreographerTest,
- public testing::WithParamInterface<PointerChoreographerDisplayTopologyTestFixtureParam> {
+class PointerChoreographerDisplayTopologyCursorTestFixture
+ : public PointerChoreographerDisplayTopologyTests,
+ public testing::WithParamInterface<
+ PointerChoreographerDisplayTopologyCursorTestFixtureParam> {
public:
static constexpr ui::LogicalDisplayId DISPLAY_CENTER_ID = ui::LogicalDisplayId{10};
static constexpr ui::LogicalDisplayId DISPLAY_TOP_ID = ui::LogicalDisplayId{20};
@@ -2702,13 +2765,6 @@
static constexpr ui::LogicalDisplayId DISPLAY_TOP_RIGHT_CORNER_ID = ui::LogicalDisplayId{60};
static constexpr ui::LogicalDisplayId DISPLAY_HIGH_DENSITY_ID = ui::LogicalDisplayId{70};
- static constexpr int DENSITY_MEDIUM = 160;
- static constexpr int DENSITY_HIGH = 320;
-
- PointerChoreographerDisplayTopologyTestFixture() {
- com::android::input::flags::connected_displays_cursor(true);
- }
-
protected:
// Note: viewport size is in pixels and offsets in topology are in dp
std::vector<DisplayViewport> mViewports{
@@ -2741,34 +2797,24 @@
{DISPLAY_LEFT_ID, DENSITY_MEDIUM},
{DISPLAY_TOP_RIGHT_CORNER_ID, DENSITY_MEDIUM},
{DISPLAY_HIGH_DENSITY_ID, DENSITY_HIGH}}};
-
-private:
- DisplayViewport createViewport(ui::LogicalDisplayId displayId, int32_t width, int32_t height,
- ui::Rotation orientation) {
- DisplayViewport viewport;
- viewport.displayId = displayId;
- viewport.logicalRight = width;
- viewport.logicalBottom = height;
- viewport.orientation = orientation;
- return viewport;
- }
};
-TEST_P(PointerChoreographerDisplayTopologyTestFixture, PointerChoreographerDisplayTopologyTest) {
+TEST_P(PointerChoreographerDisplayTopologyCursorTestFixture,
+ PointerChoreographerDisplayTopologyTest) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+
const auto& [_, device, pointerControllerType, pointerToolType, initialPosition, hoverMove,
destinationDisplay, destinationPosition] = GetParam();
mChoreographer.setDisplayViewports(mViewports);
- mChoreographer.setDefaultMouseDisplayId(
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID);
+ setDefaultMouseDisplayId(DISPLAY_CENTER_ID);
mChoreographer.setDisplayTopology(mTopology);
mChoreographer.notifyInputDevicesChanged(
{/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, device, ui::LogicalDisplayId::INVALID)}});
auto pc = assertPointerControllerCreated(pointerControllerType);
- ASSERT_EQ(PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
- pc->getDisplayId());
+ ASSERT_EQ(DISPLAY_CENTER_ID, pc->getDisplayId());
// Set initial position of the PointerController.
pc->setPosition(initialPosition.x, initialPosition.y);
@@ -2800,84 +2846,315 @@
}
INSTANTIATE_TEST_SUITE_P(
- PointerChoreographerTest, PointerChoreographerDisplayTopologyTestFixture,
+ PointerChoreographerTest, PointerChoreographerDisplayTopologyCursorTestFixture,
testing::Values(
// Note: Upon viewport transition cursor will be positioned at the boundary of the
// destination, as we drop any unconsumed delta.
- std::make_tuple("PrimaryDisplayIsDefault", AINPUT_SOURCE_MOUSE,
- ControllerType::MOUSE, ToolType::MOUSE,
- vec2(50, 50) /* initial x/y */, vec2(0, 0) /* delta x/y */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
- vec2(50, 50) /* destination x/y */),
- std::make_tuple("UnchangedDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
- ToolType::MOUSE, vec2(50, 50) /* initial x/y */,
- vec2(25, 25) /* delta x/y */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
- vec2(75, 75) /* destination x/y */),
- std::make_tuple("TransitionToRightDisplay", AINPUT_SOURCE_MOUSE,
- ControllerType::MOUSE, ToolType::MOUSE,
- vec2(50, 50) /* initial x/y */, vec2(100, 25) /* delta x/y */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_RIGHT_ID,
- vec2(0,
- 50 + 25 - 10) /* Left edge: (0, source + delta - offset) */),
+ std::make_tuple(
+ "PrimaryDisplayIsDefault", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
+ ToolType::MOUSE, vec2(50, 50) /* initial x/y */, vec2(0, 0) /* delta x/y */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID,
+ vec2(50, 50) /* destination x/y */),
+ std::make_tuple(
+ "UnchangedDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
+ ToolType::MOUSE, vec2(50, 50) /* initial x/y */,
+ vec2(25, 25) /* delta x/y */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID,
+ vec2(75, 75) /* destination x/y */),
+ std::make_tuple(
+ "TransitionToRightDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
+ ToolType::MOUSE, vec2(50, 50) /* initial x/y */,
+ vec2(100, 25) /* delta x/y */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_RIGHT_ID,
+ vec2(0, 50 + 25 - 10) /* Left edge: (0, source + delta - offset) */),
std::make_tuple(
"TransitionToLeftDisplay", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
ToolType::MOUSE, vec2(50, 50) /* initial x/y */,
vec2(-100, 25) /* delta x/y */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_LEFT_ID,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_LEFT_ID,
vec2(90, 50 + 25 - 10) /* Right edge: (width, source + delta - offset*/),
- std::make_tuple("TransitionToTopDisplay",
- AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
- ToolType::FINGER, vec2(50, 50) /* initial x/y */,
- vec2(25, -100) /* delta x/y */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_TOP_ID,
- vec2(50 + 25 - 50,
- 90) /* Bottom edge: (source + delta - offset, height) */),
- std::make_tuple("TransitionToBottomDisplay",
- AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
- ToolType::FINGER, vec2(50, 50) /* initial x/y */,
- vec2(25, 100) /* delta x/y */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_BOTTOM_ID,
- vec2(50 + 25 - 10, 0) /* Top edge: (source + delta - offset, 0) */),
+ std::make_tuple(
+ "TransitionToTopDisplay", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
+ ControllerType::MOUSE, ToolType::FINGER, vec2(50, 50) /* initial x/y */,
+ vec2(25, -100) /* delta x/y */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_TOP_ID,
+ vec2(50 + 25 - 50,
+ 90) /* Bottom edge: (source + delta - offset, height) */),
+ std::make_tuple(
+ "TransitionToBottomDisplay", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
+ ControllerType::MOUSE, ToolType::FINGER, vec2(50, 50) /* initial x/y */,
+ vec2(25, 100) /* delta x/y */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_BOTTOM_ID,
+ vec2(50 + 25 - 10, 0) /* Top edge: (source + delta - offset, 0) */),
// move towards 25 dp gap between DISPLAY_HIGH_DENSITY_ID and DISPLAY_TOP_ID
- std::make_tuple("NoTransitionAtTopOffset", AINPUT_SOURCE_MOUSE,
- ControllerType::MOUSE, ToolType::MOUSE,
- vec2(35, 50) /* initial x/y */, vec2(0, -100) /* Move Up */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
- vec2(35, 0) /* Top edge */),
- std::make_tuple("NoTransitionAtRightOffset", AINPUT_SOURCE_MOUSE,
- ControllerType::MOUSE, ToolType::MOUSE,
- vec2(95, 5) /* initial x/y */, vec2(100, 0) /* Move Right */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
- vec2(99, 5) /* Top edge */),
- std::make_tuple("NoTransitionAtBottomOffset",
- AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
- ToolType::FINGER, vec2(5, 95) /* initial x/y */,
- vec2(0, 100) /* Move Down */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
- vec2(5, 99) /* Bottom edge */),
- std::make_tuple("NoTransitionAtLeftOffset",
- AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
- ToolType::FINGER, vec2(5, 5) /* initial x/y */,
- vec2(-100, 0) /* Move Left */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_CENTER_ID,
- vec2(0, 5) /* Left edge */),
std::make_tuple(
- "TransitionAtTopRightCorner", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
- ControllerType::MOUSE, ToolType::FINGER, vec2(95, 5) /* initial x/y */,
- vec2(10, -10) /* Move diagonally to top right corner */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_TOP_RIGHT_CORNER_ID,
- vec2(0, 90) /* bottom left corner */),
+ "NoTransitionAtTopOffset", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
+ ToolType::MOUSE, vec2(35, 50) /* initial x/y */,
+ vec2(0, -100) /* Move Up */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID,
+ vec2(35, 0) /* Top edge */),
std::make_tuple(
- "TransitionToHighDpDisplay", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
- ControllerType::MOUSE, ToolType::MOUSE, vec2(20, 20) /* initial x/y */,
- vec2(0, -50) /* delta x/y */,
- PointerChoreographerDisplayTopologyTestFixture::DISPLAY_HIGH_DENSITY_ID,
- /* Bottom edge: ((source + delta - offset) * density, height) */
- vec2((20 + 0 + 75) * 2, 200))),
- [](const testing::TestParamInfo<PointerChoreographerDisplayTopologyTestFixtureParam>& p) {
- return std::string{std::get<0>(p.param)};
- });
+ "NoTransitionAtRightOffset", AINPUT_SOURCE_MOUSE, ControllerType::MOUSE,
+ ToolType::MOUSE, vec2(95, 5) /* initial x/y */,
+ vec2(100, 0) /* Move Right */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID,
+ vec2(99, 5) /* Top edge */),
+ std::make_tuple(
+ "NoTransitionAtBottomOffset", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
+ ControllerType::MOUSE, ToolType::FINGER, vec2(5, 95) /* initial x/y */,
+ vec2(0, 100) /* Move Down */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID,
+ vec2(5, 99) /* Bottom edge */),
+ std::make_tuple(
+ "NoTransitionAtLeftOffset", AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
+ ControllerType::MOUSE, ToolType::FINGER, vec2(5, 5) /* initial x/y */,
+ vec2(-100, 0) /* Move Left */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::DISPLAY_CENTER_ID,
+ vec2(0, 5) /* Left edge */),
+ std::make_tuple("TransitionAtTopRightCorner",
+ AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
+ ToolType::FINGER, vec2(95, 5) /* initial x/y */,
+ vec2(10, -10) /* Move diagonally to top right corner */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::
+ DISPLAY_TOP_RIGHT_CORNER_ID,
+ vec2(0, 90) /* bottom left corner */),
+ std::make_tuple("TransitionToHighDpDisplay",
+ AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD, ControllerType::MOUSE,
+ ToolType::MOUSE, vec2(20, 20) /* initial x/y */,
+ vec2(0, -50) /* delta x/y */,
+ PointerChoreographerDisplayTopologyCursorTestFixture::
+ DISPLAY_HIGH_DENSITY_ID,
+ /* Bottom edge: ((source + delta - offset) * density, height) */
+ vec2((20 + 0 + 75) * 2, 200))),
+ [](const testing::TestParamInfo<PointerChoreographerDisplayTopologyCursorTestFixtureParam>&
+ p) { return std::string{std::get<0>(p.param)}; });
+
+class PointerChoreographerDisplayTopologyDefaultMouseDisplayTests
+ : public PointerChoreographerDisplayTopologyTests {
+protected:
+ static constexpr ui::LogicalDisplayId FIRST_DISPLAY_ID = ui::LogicalDisplayId{10};
+ static constexpr ui::LogicalDisplayId SECOND_DISPLAY_ID = ui::LogicalDisplayId{20};
+ static constexpr ui::LogicalDisplayId THIRD_DISPLAY_ID = ui::LogicalDisplayId{30};
+
+ DisplayViewport createViewport(ui::LogicalDisplayId displayId) {
+ return PointerChoreographerDisplayTopologyTests::createViewport(displayId, /*width=*/100,
+ /*height=*/100,
+ ui::ROTATION_0);
+ }
+
+ void setDisplayTopologyWithDisplays(
+ ui::LogicalDisplayId primaryDisplayId,
+ const std::vector<ui::LogicalDisplayId>& adjacentDisplays = {}) {
+ // Prepare a topology with all display connected from left to right.
+ ui::LogicalDisplayId previousDisplay = primaryDisplayId;
+
+ std::unordered_map<ui::LogicalDisplayId, std::vector<DisplayTopologyAdjacentDisplay>>
+ topologyGraph;
+ topologyGraph[primaryDisplayId] = {};
+
+ std::unordered_map<ui::LogicalDisplayId, int> displaysDensity;
+ displaysDensity[primaryDisplayId] = DENSITY_MEDIUM;
+
+ for (ui::LogicalDisplayId adjacentDisplayId : adjacentDisplays) {
+ topologyGraph[previousDisplay].push_back({.displayId = adjacentDisplayId,
+ .position = DisplayTopologyPosition::RIGHT,
+ .offsetDp = 0.0f});
+ topologyGraph[adjacentDisplayId].push_back({.displayId = previousDisplay,
+ .position = DisplayTopologyPosition::LEFT,
+ .offsetDp = 0.0f});
+
+ displaysDensity[adjacentDisplayId] = DENSITY_MEDIUM;
+ }
+
+ mChoreographer.setDisplayTopology({primaryDisplayId, topologyGraph, displaysDensity});
+ }
+};
+
+TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests,
+ UnrelatedTopologyUpdatesDoNotChangeCursorDisplay) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+
+ // Set first display as primary display and emit mouse event to create PointerController.
+ mChoreographer.setDisplayViewports({createViewport(FIRST_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID);
+
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
+ ui::LogicalDisplayId::INVALID)}});
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertViewportSet(FIRST_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ // Add another display keeping the primary display unchanged
+ mChoreographer.setDisplayViewports(
+ {createViewport(FIRST_DISPLAY_ID), createViewport(SECOND_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID,
+ /*adjacentDisplays=*/{SECOND_DISPLAY_ID});
+
+ assertPointerControllerNotCreated();
+ pc->assertViewportSet(FIRST_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ // Move cursor to second display and add a third display
+ auto pointerBuilder = PointerBuilder(/*id=*/0, ToolType::MOUSE)
+ .axis(AMOTION_EVENT_AXIS_RELATIVE_X, /*x=*/100)
+ .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, /*y=*/0);
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(pointerBuilder)
+ .deviceId(DEVICE_ID)
+ .displayId(ui::LogicalDisplayId::INVALID)
+ .build());
+
+ assertPointerControllerNotCreated();
+ pc->assertViewportSet(SECOND_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ mChoreographer.setDisplayViewports({createViewport(FIRST_DISPLAY_ID),
+ createViewport(SECOND_DISPLAY_ID),
+ createViewport(THIRD_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID, /*adjacentDisplays=*/
+ {SECOND_DISPLAY_ID, THIRD_DISPLAY_ID});
+
+ assertPointerControllerNotCreated();
+ pc->assertViewportSet(SECOND_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ // Change the primary display to the third display
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/THIRD_DISPLAY_ID, /*adjacentDisplays=*/
+ {SECOND_DISPLAY_ID, THIRD_DISPLAY_ID});
+
+ assertPointerControllerNotCreated();
+ pc->assertViewportSet(SECOND_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+}
+
+TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests,
+ PrimaryDisplayIsFallbackOnPointerDisplayRemoved) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+
+ // Add two displays and move cursor to the secondary display
+ mChoreographer.setDisplayViewports(
+ {createViewport(FIRST_DISPLAY_ID), createViewport(SECOND_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID,
+ /*adjacentDisplays=*/{SECOND_DISPLAY_ID});
+
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
+ ui::LogicalDisplayId::INVALID)}});
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertViewportSet(FIRST_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ auto pointerBuilder = PointerBuilder(/*id=*/0, ToolType::MOUSE)
+ .axis(AMOTION_EVENT_AXIS_RELATIVE_X, /*x=*/100)
+ .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, /*y=*/0);
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(pointerBuilder)
+ .deviceId(DEVICE_ID)
+ .displayId(ui::LogicalDisplayId::INVALID)
+ .build());
+
+ assertPointerControllerNotCreated();
+ pc->assertViewportSet(SECOND_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ // Remove the secondary display
+ mChoreographer.setDisplayViewports({createViewport(FIRST_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID);
+
+ assertPointerControllerRemoved(pc);
+ pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertViewportSet(FIRST_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+}
+
+TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests,
+ UsePrimaryDisplayIfAssociatedDisplayIsInTopology) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+ SCOPED_FLAG_OVERRIDE(connected_displays_associated_display_cursor_bugfix, true);
+
+ // Add two displays
+ mChoreographer.setDisplayViewports(
+ {createViewport(FIRST_DISPLAY_ID), createViewport(SECOND_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/SECOND_DISPLAY_ID,
+ /*adjacentDisplays=*/{FIRST_DISPLAY_ID});
+
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, FIRST_DISPLAY_ID)}});
+
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertViewportSet(SECOND_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+}
+
+TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests,
+ AllowCrossingDisplayEvenWithAssociatedDisplaySet) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+ SCOPED_FLAG_OVERRIDE(connected_displays_associated_display_cursor_bugfix, true);
+
+ // Add two displays
+ mChoreographer.setDisplayViewports(
+ {createViewport(FIRST_DISPLAY_ID), createViewport(SECOND_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID,
+ /*adjacentDisplays=*/{SECOND_DISPLAY_ID});
+
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, SECOND_DISPLAY_ID)}});
+
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertViewportSet(FIRST_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ // Move cursor to the secondary display
+ auto pointerBuilder = PointerBuilder(/*id=*/0, ToolType::MOUSE)
+ .axis(AMOTION_EVENT_AXIS_RELATIVE_X, /*x=*/100)
+ .axis(AMOTION_EVENT_AXIS_RELATIVE_Y, /*y=*/0);
+ mChoreographer.notifyMotion(
+ MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(pointerBuilder)
+ .deviceId(DEVICE_ID)
+ .displayId(ui::LogicalDisplayId::INVALID)
+ .build());
+
+ assertPointerControllerNotCreated();
+ pc->assertViewportSet(SECOND_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+}
+
+TEST_F(PointerChoreographerDisplayTopologyDefaultMouseDisplayTests,
+ AddAssociatedDisplayCursorOutsideOfDisplayTopology) {
+ SCOPED_FLAG_OVERRIDE(connected_displays_cursor, true);
+ SCOPED_FLAG_OVERRIDE(connected_displays_associated_display_cursor_bugfix, true);
+
+ // Add three displays, with only first and second display in DisplayTopolgoy
+ mChoreographer.setDisplayViewports({createViewport(FIRST_DISPLAY_ID),
+ createViewport(SECOND_DISPLAY_ID),
+ createViewport(THIRD_DISPLAY_ID)});
+ setDisplayTopologyWithDisplays(/*primaryDisplayId=*/FIRST_DISPLAY_ID,
+ /*adjacentDisplays=*/{SECOND_DISPLAY_ID});
+
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/0,
+ {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE,
+ ui::LogicalDisplayId::INVALID)}});
+
+ auto pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertViewportSet(FIRST_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+
+ // Adds a new mouse associated with third display
+ mChoreographer.notifyInputDevicesChanged(
+ {/*id=*/1, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, THIRD_DISPLAY_ID)}});
+
+ pc = assertPointerControllerCreated(ControllerType::MOUSE);
+ pc->assertViewportSet(THIRD_DISPLAY_ID);
+ ASSERT_TRUE(pc->isPointerShown());
+}
class PointerChoreographerWindowInfoListenerTest : public testing::Test {};
diff --git a/services/inputflinger/tests/fuzzers/FuzzedInputStream.h b/services/inputflinger/tests/fuzzers/FuzzedInputStream.h
index 767f9cd..43975f0 100644
--- a/services/inputflinger/tests/fuzzers/FuzzedInputStream.h
+++ b/services/inputflinger/tests/fuzzers/FuzzedInputStream.h
@@ -21,6 +21,14 @@
static constexpr int32_t MAX_RANDOM_POINTERS = 4;
static constexpr int32_t MAX_RANDOM_DEVICES = 4;
+// The maximum value that we use for the action button field of NotifyMotionArgs. (We allow multiple
+// bits to be set for this since we're just trying to generate a fuzzed event stream that doesn't
+// cause crashes when enum values are converted to Rust — we don't necessarily want it to be valid.)
+//
+// AMOTION_EVENT_BUTTON_STYLUS_SECONDARY should be replaced with whatever AMOTION_EVENT_BUTTON_
+// value is highest if the enum is edited.
+static constexpr int8_t MAX_ACTION_BUTTON_VALUE = (AMOTION_EVENT_BUTTON_STYLUS_SECONDARY << 1) - 1;
+
int getFuzzedMotionAction(FuzzedDataProvider& fdp) {
int actionMasked = fdp.PickValueInArray<int>({
AMOTION_EVENT_ACTION_DOWN, AMOTION_EVENT_ACTION_UP, AMOTION_EVENT_ACTION_MOVE,
@@ -185,18 +193,16 @@
fdp.ConsumeIntegralInRange<nsecs_t>(currentTime - 5E9, currentTime + 5E9);
const nsecs_t readTime = downTime;
const nsecs_t eventTime = fdp.ConsumeIntegralInRange<nsecs_t>(downTime, downTime + 1E9);
+ const int32_t actionButton = fdp.ConsumeIntegralInRange<int32_t>(0, MAX_ACTION_BUTTON_VALUE);
const float cursorX = fdp.ConsumeIntegralInRange<int>(-10000, 10000);
const float cursorY = fdp.ConsumeIntegralInRange<int>(-10000, 10000);
return NotifyMotionArgs(idGenerator.nextId(), eventTime, readTime, deviceId, source, displayId,
- POLICY_FLAG_PASS_TO_USER, action,
- /*actionButton=*/fdp.ConsumeIntegral<int32_t>(),
+ POLICY_FLAG_PASS_TO_USER, action, actionButton,
getFuzzedFlags(fdp, action), AMETA_NONE, getFuzzedButtonState(fdp),
MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount,
- pointerProperties.data(), pointerCoords.data(),
- /*xPrecision=*/0,
- /*yPrecision=*/0, cursorX, cursorY, downTime,
- /*videoFrames=*/{});
+ pointerProperties.data(), pointerCoords.data(), /*xPrecision=*/0,
+ /*yPrecision=*/0, cursorX, cursorY, downTime, /*videoFrames=*/{});
}
} // namespace android
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index 846260a..bba7389 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -34,6 +34,28 @@
android::EventHubInterface::DEVICE_ADDED,
android::EventHubInterface::DEVICE_REMOVED};
+static const android::InputDeviceClass kInputDeviceClasses[] = {
+ android::InputDeviceClass::KEYBOARD,
+ android::InputDeviceClass::ALPHAKEY,
+ android::InputDeviceClass::TOUCH,
+ android::InputDeviceClass::CURSOR,
+ android::InputDeviceClass::TOUCH_MT,
+ android::InputDeviceClass::DPAD,
+ android::InputDeviceClass::GAMEPAD,
+ android::InputDeviceClass::SWITCH,
+ android::InputDeviceClass::JOYSTICK,
+ android::InputDeviceClass::VIBRATOR,
+ android::InputDeviceClass::MIC,
+ android::InputDeviceClass::EXTERNAL_STYLUS,
+ android::InputDeviceClass::ROTARY_ENCODER,
+ android::InputDeviceClass::SENSOR,
+ android::InputDeviceClass::BATTERY,
+ android::InputDeviceClass::LIGHT,
+ android::InputDeviceClass::TOUCHPAD,
+ android::InputDeviceClass::VIRTUAL,
+ android::InputDeviceClass::EXTERNAL,
+};
+
constexpr size_t kValidCodes[] = {
SYN_REPORT,
ABS_MT_SLOT,
@@ -105,7 +127,13 @@
void addProperty(std::string key, std::string value) { mFuzzConfig.addProperty(key, value); }
ftl::Flags<InputDeviceClass> getDeviceClasses(int32_t deviceId) const override {
- return ftl::Flags<InputDeviceClass>(mFdp->ConsumeIntegral<uint32_t>());
+ uint32_t flags = 0;
+ for (auto inputDeviceClass : kInputDeviceClasses) {
+ if (mFdp->ConsumeBool()) {
+ flags |= static_cast<uint32_t>(inputDeviceClass);
+ }
+ }
+ return ftl::Flags<InputDeviceClass>(flags);
}
InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override {
return mIdentifier;
@@ -367,8 +395,8 @@
template <class Fdp>
InputDevice getFuzzedInputDevice(Fdp& fdp, FuzzInputReaderContext* context) {
InputDeviceIdentifier identifier;
- identifier.name = fdp.ConsumeRandomLengthString(16);
- identifier.location = fdp.ConsumeRandomLengthString(12);
+ identifier.name = fdp.ConsumeRandomLengthUtf8String(16);
+ identifier.location = fdp.ConsumeRandomLengthUtf8String(12);
int32_t deviceID = fdp.ConsumeIntegralInRange(0, 5);
int32_t deviceGeneration = fdp.ConsumeIntegralInRange(0, 5);
return InputDevice(context, deviceID, deviceGeneration, identifier);
diff --git a/services/inputflinger/tests/fuzzers/ThreadSafeFuzzedDataProvider.h b/services/inputflinger/tests/fuzzers/ThreadSafeFuzzedDataProvider.h
index 2f76f18..b258118 100644
--- a/services/inputflinger/tests/fuzzers/ThreadSafeFuzzedDataProvider.h
+++ b/services/inputflinger/tests/fuzzers/ThreadSafeFuzzedDataProvider.h
@@ -15,7 +15,7 @@
*/
#include <fuzzer/FuzzedDataProvider.h>
-
+#include <algorithm>
/**
* A thread-safe interface to the FuzzedDataProvider
*/
@@ -60,6 +60,44 @@
return FuzzedDataProvider::ConsumeRandomLengthString();
}
+ // Converting the string to a UTF-8 string by setting the prefix bits of each
+ // byte according to UTF-8 encoding rules.
+ std::string ConsumeRandomLengthUtf8String(size_t max_length) {
+ std::scoped_lock _l(mLock);
+ std::string result = FuzzedDataProvider::ConsumeRandomLengthString(max_length);
+ size_t remaining_bytes = result.length(), idx = 0;
+ while (remaining_bytes > 0) {
+ size_t random_byte_size = FuzzedDataProvider::ConsumeIntegralInRange(1, 4);
+ size_t byte_size = std::min(random_byte_size, remaining_bytes);
+ switch (byte_size) {
+ // Prefix byte: 0xxxxxxx
+ case 1:
+ result[idx++] &= 0b01111111;
+ break;
+ // Prefix bytes: 110xxxxx 10xxxxxx
+ case 2:
+ result[idx++] = (result[idx] & 0b00011111) | 0b11000000;
+ result[idx++] = (result[idx] & 0b00111111) | 0b10000000;
+ break;
+ // Prefix bytes: 1110xxxx 10xxxxxx 10xxxxxx
+ case 3:
+ result[idx++] = (result[idx] & 0b00001111) | 0b11100000;
+ result[idx++] = (result[idx] & 0b00111111) | 0b10000000;
+ result[idx++] = (result[idx] & 0b00111111) | 0b10000000;
+ break;
+ // Prefix bytes: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ case 4:
+ result[idx++] = (result[idx] & 0b00000111) | 0b11110000;
+ result[idx++] = (result[idx] & 0b00111111) | 0b10000000;
+ result[idx++] = (result[idx] & 0b00111111) | 0b10000000;
+ result[idx++] = (result[idx] & 0b00111111) | 0b10000000;
+ break;
+ }
+ remaining_bytes -= byte_size;
+ }
+ return result;
+ }
+
std::string ConsumeRemainingBytesAsString() {
std::scoped_lock _l(mLock);
return FuzzedDataProvider::ConsumeRemainingBytesAsString();
diff --git a/services/stats/OWNERS b/services/stats/OWNERS
index a61babf..791b711 100644
--- a/services/stats/OWNERS
+++ b/services/stats/OWNERS
@@ -1,9 +1,7 @@
jeffreyhuang@google.com
joeo@google.com
-jtnguyen@google.com
muhammadq@google.com
ruchirr@google.com
singhtejinder@google.com
tsaichristine@google.com
yaochen@google.com
-yro@google.com
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index c1b864d..c0243b8 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -145,7 +145,7 @@
// Applies a HWC device layer lut
virtual void applyDeviceLayerLut(
- ndk::ScopedFileDescriptor,
+ ::android::base::unique_fd,
std::vector<std::pair<
int, aidl::android::hardware::graphics::composer3::LutProperties>>) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index a1434f2..dea3290 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -68,7 +68,7 @@
aidl::android::hardware::graphics::composer3::Composition) override;
void prepareForDeviceLayerRequests() override;
void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override;
- void applyDeviceLayerLut(ndk::ScopedFileDescriptor,
+ void applyDeviceLayerLut(::android::base::unique_fd,
std::vector<std::pair<int, LutProperties>>) override;
bool needsFiltering() const override;
std::optional<LayerFE::LayerSettings> getOverrideCompositionSettings() const override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index 09c47f0..be36db6 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -60,7 +60,7 @@
MOCK_CONST_METHOD0(needsFiltering, bool());
MOCK_CONST_METHOD0(getOverrideCompositionSettings, std::optional<LayerFE::LayerSettings>());
MOCK_METHOD(void, applyDeviceLayerLut,
- (ndk::ScopedFileDescriptor,
+ (::android::base::unique_fd,
(std::vector<std::pair<
int, aidl::android::hardware::graphics::composer3::LutProperties>>)));
MOCK_METHOD(int64_t, getPictureProfilePriority, (), (const));
diff --git a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
index d9018bc..dc84195 100644
--- a/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/ClientCompositionRequestCache.cpp
@@ -38,7 +38,8 @@
lhs.disableBlending == rhs.disableBlending && lhs.shadow == rhs.shadow &&
lhs.backgroundBlurRadius == rhs.backgroundBlurRadius &&
lhs.stretchEffect == rhs.stretchEffect &&
- lhs.edgeExtensionEffect == rhs.edgeExtensionEffect;
+ lhs.edgeExtensionEffect == rhs.edgeExtensionEffect &&
+ lhs.whitePointNits == rhs.whitePointNits;
}
inline bool equalIgnoringBuffer(const renderengine::Buffer& lhs, const renderengine::Buffer& rhs) {
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index e37ce0a..8364f4e 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -373,7 +373,7 @@
if (auto lutsIt = layerLuts.find(hwcLayer); lutsIt != layerLuts.end()) {
if (auto mapperIt = mapper.find(hwcLayer); mapperIt != mapper.end()) {
- layer->applyDeviceLayerLut(ndk::ScopedFileDescriptor(mapperIt->second.release()),
+ layer->applyDeviceLayerLut(::android::base::unique_fd(mapperIt->second.release()),
lutsIt->second);
}
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index d89b52d..b1bbcac 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -369,8 +369,11 @@
layerFEState->buffer->getPixelFormat()))
: std::nullopt;
- auto hdrRenderType =
- getHdrRenderType(outputState.dataspace, pixelFormat, layerFEState->desiredHdrSdrRatio);
+ // prefer querying this from gralloc instead to catch 2094-10 metadata
+ const bool hasHdrMetadata = layerFEState->hdrMetadata.validTypes != 0;
+
+ auto hdrRenderType = getHdrRenderType(outputState.dataspace, pixelFormat,
+ layerFEState->desiredHdrSdrRatio, hasHdrMetadata);
// Determine the output dependent dataspace for this layer. If it is
// colorspace agnostic, it just uses the dataspace chosen for the output to
@@ -393,8 +396,8 @@
}
// re-get HdrRenderType after the dataspace gets changed.
- hdrRenderType =
- getHdrRenderType(state.dataspace, pixelFormat, layerFEState->desiredHdrSdrRatio);
+ hdrRenderType = getHdrRenderType(state.dataspace, pixelFormat, layerFEState->desiredHdrSdrRatio,
+ hasHdrMetadata);
// For hdr content, treat the white point as the display brightness - HDR content should not be
// boosted or dimmed.
@@ -416,12 +419,20 @@
state.dimmingRatio = std::min(idealizedMaxHeadroom / deviceHeadroom, 1.0f);
state.whitePointNits = getOutput().getState().displayBrightnessNits * state.dimmingRatio;
} else {
+ const bool isLayerFp16 = pixelFormat && *pixelFormat == ui::PixelFormat::RGBA_FP16;
float layerBrightnessNits = getOutput().getState().sdrWhitePointNits;
// RANGE_EXTENDED can "self-promote" to HDR, but is still rendered for a particular
// range that we may need to re-adjust to the current display conditions
+ // Do NOT do this when we may render fp16 to an fp16 client target, to avoid applying
+ // and additional gain to the layer. This is because the fp16 client target should
+ // already be adapted to remap 1.0 to the SDR white point in the panel's luminance
+ // space.
if (hdrRenderType == HdrRenderType::DISPLAY_HDR) {
- layerBrightnessNits *= layerFEState->currentHdrSdrRatio;
+ if (!FlagManager::getInstance().fp16_client_target() || !isLayerFp16) {
+ layerBrightnessNits *= layerFEState->currentHdrSdrRatio;
+ }
}
+
state.dimmingRatio =
std::clamp(layerBrightnessNits / getOutput().getState().displayBrightnessNits, 0.f,
1.f);
@@ -619,7 +630,7 @@
lutProperties[i].samplingKey)}});
}
- luts.pfd = ndk::ScopedFileDescriptor(dup(lutFileDescriptor.get()));
+ luts.pfd.set(dup(lutFileDescriptor.get()));
luts.offsets = lutOffsets;
luts.lutProperties = std::move(aidlProperties);
}
@@ -1006,7 +1017,7 @@
}
void OutputLayer::applyDeviceLayerLut(
- ndk::ScopedFileDescriptor lutFileDescriptor,
+ ::android::base::unique_fd lutFd,
std::vector<std::pair<int, LutProperties>> lutOffsetsAndProperties) {
auto& state = editState();
LOG_FATAL_IF(!state.hwc);
@@ -1025,9 +1036,9 @@
samplingKeys.emplace_back(static_cast<int32_t>(properties.samplingKeys[0]));
}
}
- hwcState.luts = std::make_shared<gui::DisplayLuts>(base::unique_fd(lutFileDescriptor.release()),
- std::move(offsets), std::move(dimensions),
- std::move(sizes), std::move(samplingKeys));
+ hwcState.luts = std::make_shared<gui::DisplayLuts>(std::move(lutFd), std::move(offsets),
+ std::move(dimensions), std::move(sizes),
+ std::move(samplingKeys));
}
bool OutputLayer::needsFiltering() const {
diff --git a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
index 783209c..b290823 100644
--- a/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/planner/Flattener.cpp
@@ -325,6 +325,7 @@
priorBlurLayer == (*incomingLayerIter)->getOutputLayer();
OutputLayer::CompositionState& state =
(*incomingLayerIter)->getOutputLayer()->editState();
+
state.overrideInfo = {
.buffer = mNewCachedSet->getBuffer(),
.acquireFence = mNewCachedSet->getDrawFence(),
@@ -378,6 +379,7 @@
};
++incomingLayerIter;
}
+ priorBlurLayer = currentLayerIter->getBlurLayer();
} else if (currentLayerIter->getLayerCount() > 1) {
// Break the current layer into its constituent layers
++mInvalidatedCachedSetAges[currentLayerIter->getAge()];
@@ -400,8 +402,8 @@
currentLayerIter->updateAge(now);
merged.emplace_back(*currentLayerIter);
++incomingLayerIter;
+ priorBlurLayer = currentLayerIter->getBlurLayer();
}
- priorBlurLayer = currentLayerIter->getBlurLayer();
++currentLayerIter;
}
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 252c6b6..01f382f 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -638,7 +638,7 @@
[](int32_t i, LutProperties j) { return std::make_pair(i, j); });
outLuts->emplace_or_replace(layer.get(), lutOffsetsAndProperties);
lutFileDescriptorMapper.emplace_or_replace(layer.get(),
- ndk::ScopedFileDescriptor(
+ ::android::base::unique_fd(
layerLut.luts.pfd.release()));
} else {
ALOGE("getRequestedLuts: invalid luts on layer %" PRIu64 " found"
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index c3deb84..7c1f8e3 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -115,7 +115,7 @@
using LayerLuts =
ftl::SmallMap<HWC2::Layer*, LutOffsetAndProperties, kLutFileDescriptorMapperSize>;
using LutFileDescriptorMapper =
- ftl::SmallMap<HWC2::Layer*, ndk::ScopedFileDescriptor, kLutFileDescriptorMapperSize>;
+ ftl::SmallMap<HWC2::Layer*, ::android::base::unique_fd, kLutFileDescriptorMapperSize>;
[[nodiscard]] virtual hal::Error acceptChanges() = 0;
[[nodiscard]] virtual base::expected<std::shared_ptr<HWC2::Layer>, hal::Error>
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index db41b9b..545ed19 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -1068,7 +1068,7 @@
return mSupportedLayerGenericMetadata;
}
-ftl::SmallMap<HWC2::Layer*, ndk::ScopedFileDescriptor, 20>&
+ftl::SmallMap<HWC2::Layer*, ::android::base::unique_fd, 20>&
HWComposer::getLutFileDescriptorMapper() {
return mLutFileDescriptorMapper;
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e1bba44..95a7170 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -362,7 +362,7 @@
// transaction
// ----------------------------------------------------------------------------
-void Layer::commitTransaction() {
+void Layer::commitTransaction() REQUIRES(mFlinger->mStateLock) {
// Set the present state for all bufferlessSurfaceFramesTX to Presented. The
// bufferSurfaceFrameTX will be presented in latchBuffer.
for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) {
@@ -394,7 +394,8 @@
};
void Layer::setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info,
- nsecs_t postTime, gui::GameMode gameMode) {
+ nsecs_t postTime, gui::GameMode gameMode)
+ REQUIRES(mFlinger->mStateLock) {
mDrawingState.postTime = postTime;
// Check if one of the bufferlessSurfaceFramesTX contains the same vsyncId. This can happen if
@@ -458,7 +459,7 @@
void Layer::addSurfaceFramePresentedForBuffer(
std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame, nsecs_t acquireFenceTime,
- nsecs_t currentLatchTime) {
+ nsecs_t currentLatchTime) REQUIRES(mFlinger->mStateLock) {
surfaceFrame->setAcquireFenceTime(acquireFenceTime);
surfaceFrame->setPresentState(PresentState::Presented, mLastLatchTime);
mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame);
@@ -466,7 +467,8 @@
}
std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForTransaction(
- const FrameTimelineInfo& info, nsecs_t postTime, gui::GameMode gameMode) {
+ const FrameTimelineInfo& info, nsecs_t postTime, gui::GameMode gameMode)
+ REQUIRES(mFlinger->mStateLock) {
auto surfaceFrame =
mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid,
getSequence(), mName,
@@ -488,7 +490,7 @@
std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForBuffer(
const FrameTimelineInfo& info, nsecs_t queueTime, std::string debugName,
- gui::GameMode gameMode) {
+ gui::GameMode gameMode) REQUIRES(mFlinger->mStateLock) {
auto surfaceFrame =
mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid,
getSequence(), mName, debugName,
@@ -506,7 +508,8 @@
}
void Layer::setFrameTimelineVsyncForSkippedFrames(const FrameTimelineInfo& info, nsecs_t postTime,
- std::string debugName, gui::GameMode gameMode) {
+ std::string debugName, gui::GameMode gameMode)
+ REQUIRES(mFlinger->mStateLock) {
if (info.skippedFrameVsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) {
return;
}
@@ -842,7 +845,7 @@
return true;
}
-void Layer::releasePreviousBuffer() {
+void Layer::releasePreviousBuffer() REQUIRES(mFlinger->mStateLock) {
mReleasePreviousBuffer = true;
if (!mBufferInfo.mBuffer ||
(!mDrawingState.buffer->hasSameBuffer(*mBufferInfo.mBuffer) ||
@@ -884,7 +887,8 @@
bool Layer::setBuffer(std::shared_ptr<renderengine::ExternalTexture>& buffer,
const BufferData& bufferData, nsecs_t postTime, nsecs_t desiredPresentTime,
- bool isAutoTimestamp, const FrameTimelineInfo& info, gui::GameMode gameMode) {
+ bool isAutoTimestamp, const FrameTimelineInfo& info, gui::GameMode gameMode)
+ REQUIRES(mFlinger->mStateLock) {
SFTRACE_FORMAT("setBuffer %s - hasBuffer=%s", getDebugName(), (buffer ? "true" : "false"));
const bool frameNumberChanged =
@@ -1074,7 +1078,8 @@
}
bool Layer::setSidebandStream(const sp<NativeHandle>& sidebandStream, const FrameTimelineInfo& info,
- nsecs_t postTime, gui::GameMode gameMode) {
+ nsecs_t postTime, gui::GameMode gameMode)
+ REQUIRES(mFlinger->mStateLock) {
if (mDrawingState.sidebandStream == sidebandStream) return false;
if (mDrawingState.sidebandStream != nullptr && sidebandStream == nullptr) {
@@ -1207,7 +1212,7 @@
return false;
}
-void Layer::updateTexImage(nsecs_t latchTime, bool bgColorOnly) {
+void Layer::updateTexImage(nsecs_t latchTime, bool bgColorOnly) REQUIRES(mFlinger->mStateLock) {
const State& s(getDrawingState());
if (!s.buffer) {
@@ -1457,7 +1462,8 @@
mBufferInfo.mFrameLatencyNeeded = false;
}
-bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bool bgColorOnly) {
+bool Layer::latchBufferImpl(bool& recomputeVisibleRegions, nsecs_t latchTime, bool bgColorOnly)
+ REQUIRES(mFlinger->mStateLock) {
SFTRACE_FORMAT_INSTANT("latchBuffer %s - %" PRIu64, getDebugName(),
getDrawingState().frameNumber);
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index ff360b7..b9c79df 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -206,7 +206,11 @@
// Normalizing to the oldest timestamp cuts down on error in calculating the intercept.
const auto oldestTS = *std::min_element(mTimestamps.begin(), mTimestamps.end());
auto it = mRateMap.find(idealPeriod());
- auto const currentPeriod = it->second.slope;
+ // Calculated slope over the period of time can become outdated as the new timestamps are
+ // stored. Using idealPeriod instead provides a rate which is valid at all the times.
+ auto const currentPeriod = FlagManager::getInstance().vsync_predictor_recovery()
+ ? idealPeriod()
+ : it->second.slope;
// The mean of the ordinals must be precise for the intercept calculation, so scale them up for
// fixed-point arithmetic.
diff --git a/services/surfaceflinger/ScreenCaptureOutput.cpp b/services/surfaceflinger/ScreenCaptureOutput.cpp
index 7123905..af6d4d3 100644
--- a/services/surfaceflinger/ScreenCaptureOutput.cpp
+++ b/services/surfaceflinger/ScreenCaptureOutput.cpp
@@ -209,6 +209,7 @@
}
compositionengine::LayerFE::LayerSettings fillLayer;
+ fillLayer.name = "ScreenCaptureFillLayer";
fillLayer.source.buffer.buffer = nullptr;
fillLayer.source.solidColor = half3(0.0f, 0.0f, 0.0f);
fillLayer.geometry.boundaries =
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f3db4c5..35cb63e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2483,7 +2483,8 @@
}
bool SurfaceFlinger::updateLayerSnapshots(VsyncId vsyncId, nsecs_t frameTimeNs,
- bool flushTransactions, bool& outTransactionsAreEmpty) {
+ bool flushTransactions, bool& outTransactionsAreEmpty)
+ EXCLUDES(mStateLock) {
using Changes = frontend::RequestedLayerState::Changes;
SFTRACE_CALL();
SFTRACE_NAME_FOR_TRACK(WorkloadTracer::TRACK_NAME, "Transaction Handling");
@@ -2680,7 +2681,7 @@
}
bool SurfaceFlinger::commit(PhysicalDisplayId pacesetterId,
- const scheduler::FrameTargets& frameTargets) {
+ const scheduler::FrameTargets& frameTargets) EXCLUDES(mStateLock) {
const scheduler::FrameTarget& pacesetterFrameTarget = *frameTargets.get(pacesetterId)->get();
const VsyncId vsyncId = pacesetterFrameTarget.vsyncId();
@@ -2855,18 +2856,20 @@
// Tracks layer stacks of displays that are added to CompositionEngine output.
ui::DisplayMap<ui::LayerStack, ftl::Unit> outputLayerStacks;
- auto isOutputLayerStack = [&outputLayerStacks](DisplayId id, ui::LayerStack layerStack) {
- if (FlagManager::getInstance().reject_dupe_layerstacks() &&
- outputLayerStacks.contains(layerStack)) {
- // TODO: remove log and DisplayId from params once reject_dupe_layerstacks flag is
- // removed
- ALOGD("Existing layer stack ID %d output to another display %" PRIu64
- ", dropping display from outputs",
- layerStack.id, id.value);
- return true;
+ auto isUniqueOutputLayerStack = [&outputLayerStacks](DisplayId id, ui::LayerStack layerStack) {
+ if (FlagManager::getInstance().reject_dupe_layerstacks()) {
+ if (layerStack != ui::INVALID_LAYER_STACK && outputLayerStacks.contains(layerStack)) {
+ // TODO: remove log and DisplayId from params once reject_dupe_layerstacks flag is
+ // removed
+ ALOGD("Existing layer stack ID %d output to another display %" PRIu64
+ ", dropping display from outputs",
+ layerStack.id, id.value);
+ return false;
+ }
}
+
outputLayerStacks.try_emplace(layerStack);
- return false;
+ return true;
};
// Add outputs for physical displays.
@@ -2875,7 +2878,7 @@
if (const auto display = getCompositionDisplayLocked(id)) {
const auto layerStack = physicalDisplayLayerStacks.get(id)->get();
- if (!isOutputLayerStack(display->getId(), layerStack)) {
+ if (isUniqueOutputLayerStack(display->getId(), layerStack)) {
refreshArgs.outputs.push_back(display);
}
}
@@ -2894,7 +2897,7 @@
if (!refreshRate.isValid() ||
mScheduler->isVsyncInPhase(pacesetterTarget.frameBeginTime(), refreshRate)) {
- if (!isOutputLayerStack(display->getId(), display->getLayerStack())) {
+ if (isUniqueOutputLayerStack(display->getId(), display->getLayerStack())) {
refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
}
@@ -4893,12 +4896,14 @@
return applyTransactions(transactions);
}
-bool SurfaceFlinger::applyTransactions(std::vector<QueuedTransactionState>& transactions) {
+bool SurfaceFlinger::applyTransactions(std::vector<QueuedTransactionState>& transactions)
+ EXCLUDES(mStateLock) {
Mutex::Autolock lock(mStateLock);
return applyTransactionsLocked(transactions);
}
-bool SurfaceFlinger::applyTransactionsLocked(std::vector<QueuedTransactionState>& transactions) {
+bool SurfaceFlinger::applyTransactionsLocked(std::vector<QueuedTransactionState>& transactions)
+ REQUIRES(mStateLock) {
bool needsTraversal = false;
// Now apply all transactions.
for (auto& transaction : transactions) {
@@ -5115,15 +5120,13 @@
return NO_ERROR;
}
-bool SurfaceFlinger::applyTransactionState(const FrameTimelineInfo& frameTimelineInfo,
- std::vector<ResolvedComposerState>& states,
- Vector<DisplayState>& displays, uint32_t flags,
- const InputWindowCommands& inputWindowCommands,
- const int64_t desiredPresentTime, bool isAutoTimestamp,
- const std::vector<uint64_t>& uncacheBufferIds,
- const int64_t postTime, bool hasListenerCallbacks,
- const std::vector<ListenerCallbacks>& listenerCallbacks,
- int originPid, int originUid, uint64_t transactionId) {
+bool SurfaceFlinger::applyTransactionState(
+ const FrameTimelineInfo& frameTimelineInfo, std::vector<ResolvedComposerState>& states,
+ Vector<DisplayState>& displays, uint32_t flags,
+ const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime,
+ bool isAutoTimestamp, const std::vector<uint64_t>& uncacheBufferIds, const int64_t postTime,
+ bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks,
+ int originPid, int originUid, uint64_t transactionId) REQUIRES(mStateLock) {
uint32_t transactionFlags = 0;
// start and end registration for listeners w/ no surface so they can get their callback. Note
@@ -5275,7 +5278,7 @@
ResolvedComposerState& composerState,
int64_t desiredPresentTime,
bool isAutoTimestamp, int64_t postTime,
- uint64_t transactionId) {
+ uint64_t transactionId) REQUIRES(mStateLock) {
layer_state_t& s = composerState.state;
std::vector<ListenerCallbacks> filteredListeners;
@@ -7820,15 +7823,16 @@
// Otherwise for seamless transitions it's important to match the current
// display state as the buffer will be shown under these same conditions, and we
// want to avoid any flickers.
- if (captureResults.capturedHdrLayers && !enableLocalTonemapping &&
- args.sdrWhitePointNits > 1.0f && !args.seamlessTransition) {
- // Restrict the amount of HDR "headroom" in the screenshot to avoid
- // over-dimming the SDR portion. 2.0 chosen by experimentation
- constexpr float kMaxScreenshotHeadroom = 2.0f;
- // TODO: Aim to update displayBrightnessNits earlier in screenshot
- // path so ScreenshotArgs can be passed as const
- args.displayBrightnessNits = std::min(args.sdrWhitePointNits * kMaxScreenshotHeadroom,
- args.displayBrightnessNits);
+ if (captureResults.capturedHdrLayers) {
+ if (!enableLocalTonemapping && args.sdrWhitePointNits > 1.0f && !args.seamlessTransition) {
+ // Restrict the amount of HDR "headroom" in the screenshot to avoid
+ // over-dimming the SDR portion. 2.0 chosen by experimentation
+ constexpr float kMaxScreenshotHeadroom = 2.0f;
+ // TODO: Aim to update displayBrightnessNits earlier in screenshot
+ // path so ScreenshotArgs can be passed as const
+ args.displayBrightnessNits = std::min(args.sdrWhitePointNits * kMaxScreenshotHeadroom,
+ args.displayBrightnessNits);
+ }
} else {
args.displayBrightnessNits = args.sdrWhitePointNits;
}
diff --git a/services/surfaceflinger/common/FlagManager.cpp b/services/surfaceflinger/common/FlagManager.cpp
index f9aba9f..abde524 100644
--- a/services/surfaceflinger/common/FlagManager.cpp
+++ b/services/surfaceflinger/common/FlagManager.cpp
@@ -128,6 +128,7 @@
DUMP_ACONFIG_FLAG(graphite_renderengine_preview_rollout);
DUMP_ACONFIG_FLAG(increase_missed_frame_jank_threshold);
DUMP_ACONFIG_FLAG(refresh_rate_overlay_on_external_display);
+ DUMP_ACONFIG_FLAG(vsync_predictor_recovery);
/// Trunk stable readonly flags ///
/// IMPORTANT - please keep alphabetize to reduce merge conflicts
@@ -304,6 +305,7 @@
FLAG_MANAGER_ACONFIG_FLAG(adpf_native_session_manager, "");
FLAG_MANAGER_ACONFIG_FLAG(graphite_renderengine_preview_rollout, "");
FLAG_MANAGER_ACONFIG_FLAG(increase_missed_frame_jank_threshold, "");
+FLAG_MANAGER_ACONFIG_FLAG(vsync_predictor_recovery, "");
/// Trunk stable server (R/W) flags from outside SurfaceFlinger ///
FLAG_MANAGER_ACONFIG_FLAG_IMPORTED(adpf_use_fmq_channel, "", android::os)
diff --git a/services/surfaceflinger/common/include/common/FlagManager.h b/services/surfaceflinger/common/include/common/FlagManager.h
index de3f359..6295c5b 100644
--- a/services/surfaceflinger/common/include/common/FlagManager.h
+++ b/services/surfaceflinger/common/include/common/FlagManager.h
@@ -63,6 +63,7 @@
bool graphite_renderengine_preview_rollout() const;
bool increase_missed_frame_jank_threshold() const;
bool refresh_rate_overlay_on_external_display() const;
+ bool vsync_predictor_recovery() const;
/// Trunk stable readonly flags ///
/// IMPORTANT - please keep alphabetize to reduce merge conflicts
diff --git a/services/surfaceflinger/surfaceflinger_flags_new.aconfig b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
index fa1da45..d8f51fe 100644
--- a/services/surfaceflinger/surfaceflinger_flags_new.aconfig
+++ b/services/surfaceflinger/surfaceflinger_flags_new.aconfig
@@ -321,6 +321,16 @@
} # vrr_bugfix_dropped_frame
flag {
+ name: "vsync_predictor_recovery"
+ namespace: "core_graphics"
+ description: "Recover the vsync predictor from bad vsync model"
+ bug: "385059265"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+ } # vsync_predictor_recovery
+
+flag {
name: "window_blur_kawase2"
namespace: "core_graphics"
description: "Flag for using Kawase2 algorithm for window blur"
diff --git a/services/surfaceflinger/tests/AndroidTest.xml b/services/surfaceflinger/tests/AndroidTest.xml
index 000628f..ad43cdc 100644
--- a/services/surfaceflinger/tests/AndroidTest.xml
+++ b/services/surfaceflinger/tests/AndroidTest.xml
@@ -19,6 +19,9 @@
<option name="push" value="SurfaceFlinger_test->/data/local/tmp/SurfaceFlinger_test" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="screen-always-on" value="on" />
+ </target_preparer>
<option name="test-suite-tag" value="apct" />
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index c95c875..c91f1ea 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -48,7 +48,11 @@
ui::DisplayMode displayMode;
SurfaceComposerClient::getActiveDisplayMode(displayToken, &displayMode);
- const ui::Size& resolution = displayMode.resolution;
+ ui::Size resolution = displayMode.resolution;
+ if (displayState.orientation == ui::Rotation::Rotation90 ||
+ displayState.orientation == ui::Rotation::Rotation270) {
+ std::swap(resolution.width, resolution.height);
+ }
sp<IBinder> vDisplay;
@@ -93,8 +97,8 @@
#else
t.setDisplaySurface(vDisplay, producer);
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- t.setDisplayProjection(vDisplay, displayState.orientation,
- Rect(displayState.layerStackSpaceRect), Rect(resolution));
+ t.setDisplayProjection(vDisplay, ui::Rotation::Rotation0, Rect(resolution),
+ Rect(resolution));
t.setDisplayLayerStack(vDisplay, layerStack);
t.setLayerStack(mirrorSc, layerStack);
t.apply();
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 7f9296f..4322af7 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -114,7 +114,11 @@
// Test instances
TestableSurfaceFlinger mFlinger;
+
sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make();
+ sp<compositionengine::mock::DisplaySurface> mDisplaySurface =
+ sp<compositionengine::mock::DisplaySurface>::make();
+
sp<GraphicBuffer> mBuffer =
sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_8888,
GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN);
@@ -294,6 +298,7 @@
injector.setSecure(static_cast<bool>(SECURE));
injector.setNativeWindow(test->mNativeWindow);
+ injector.setDisplaySurface(test->mDisplaySurface);
// Creating a DisplayDevice requires getting default dimensions from the
// native window along with some other initial setup.
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index a506873..62f1a52 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -171,16 +171,22 @@
static constexpr DisplayModeId kModeId90{1};
static constexpr DisplayModeId kModeId120{2};
static constexpr DisplayModeId kModeId90_4K{3};
+ static constexpr DisplayModeId kModeId60_8K{4};
static inline const DisplayModePtr kMode60 = createDisplayMode(kModeId60, 60_Hz, 0);
static inline const DisplayModePtr kMode90 = createDisplayMode(kModeId90, 90_Hz, 1);
static inline const DisplayModePtr kMode120 = createDisplayMode(kModeId120, 120_Hz, 2);
static constexpr ui::Size kResolution4K{3840, 2160};
+ static constexpr ui::Size kResolution8K{7680, 4320};
+
static inline const DisplayModePtr kMode90_4K =
createDisplayMode(kModeId90_4K, 90_Hz, 3, kResolution4K);
+ static inline const DisplayModePtr kMode60_8K =
+ createDisplayMode(kModeId60_8K, 60_Hz, 4, kResolution8K);
- static inline const DisplayModes kModes = makeModes(kMode60, kMode90, kMode120, kMode90_4K);
+ static inline const DisplayModes kModes =
+ makeModes(kMode60, kMode90, kMode120, kMode90_4K, kMode60_8K);
};
void DisplayModeSwitchingTest::setupScheduler(
@@ -326,6 +332,8 @@
}
TEST_F(DisplayModeSwitchingTest, changeResolutionWithoutRefreshRequired) {
+ SET_FLAG_FOR_TEST(flags::synced_resolution_switch, false);
+
EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId60));
EXPECT_EQ(NO_ERROR,
@@ -360,6 +368,44 @@
EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId90_4K));
}
+TEST_F(DisplayModeSwitchingTest, changeResolutionSynced) {
+ SET_FLAG_FOR_TEST(flags::synced_resolution_switch, true);
+
+ EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId60));
+
+ // PrimaryDisplayVariant has a 4K size, so switch to 8K.
+ EXPECT_EQ(NO_ERROR,
+ mFlinger.setDesiredDisplayModeSpecs(mDisplay->getDisplayToken().promote(),
+ mock::createDisplayModeSpecs(kModeId60_8K,
+ 60_Hz)));
+
+ EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId60_8K));
+
+ // The mode should not be set until the commit that resizes the display.
+ mFlinger.commit();
+ EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId60_8K));
+ mFlinger.commit();
+ EXPECT_THAT(mDisplay, ModeSwitchingTo(&mFlinger, kModeId60_8K));
+
+ // Set the display size to match the resolution.
+ DisplayState state;
+ state.what = DisplayState::eDisplaySizeChanged;
+ state.token = mDisplay->getDisplayToken().promote();
+ state.width = static_cast<uint32_t>(kResolution8K.width);
+ state.height = static_cast<uint32_t>(kResolution8K.height);
+
+ // The next commit should set the mode and resize the framebuffer.
+ const VsyncPeriodChangeTimeline timeline{.refreshRequired = false};
+ EXPECT_CALL(*mDisplaySurface, resizeBuffers(kResolution8K));
+ EXPECT_SET_ACTIVE_CONFIG(kInnerDisplayHwcId, kModeId60_8K);
+
+ constexpr bool kModeset = true;
+ mFlinger.setDisplayStateLocked(state);
+ mFlinger.configureAndCommit(kModeset);
+
+ EXPECT_THAT(mDisplay, ModeSettledTo(&dmc(), kModeId60_8K));
+}
+
TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) {
SET_FLAG_FOR_TEST(flags::connected_display, true);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 41f2b6e..8084450 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -337,9 +337,9 @@
mFlinger->configure();
}
- void configureAndCommit() {
+ void configureAndCommit(bool modeset = false) {
configure();
- commitTransactionsLocked(eDisplayTransactionNeeded);
+ commitTransactionsLocked(eDisplayTransactionNeeded, modeset);
}
void commit(TimePoint frameTime, VsyncId vsyncId, TimePoint expectedVsyncTime,
@@ -429,11 +429,14 @@
dispSurface, producer);
}
- void commitTransactionsLocked(uint32_t transactionFlags) {
+ void commitTransactionsLocked(uint32_t transactionFlags, bool modeset = false) {
Mutex::Autolock lock(mFlinger->mStateLock);
ftl::FakeGuard guard(kMainThreadContext);
mFlinger->processDisplayChangesLocked();
mFlinger->commitTransactionsLocked(transactionFlags);
+ if (modeset) {
+ mFlinger->initiateDisplayModeChanges();
+ }
}
void onComposerHalHotplugEvent(hal::HWDisplayId hwcDisplayId, DisplayHotplugEvent event) {
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 918107d..a221d5e 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -304,6 +304,53 @@
EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
}
+TEST_F(VSyncPredictorTest, recoverAfterDriftedVSyncAreReplacedWithCorrectVSync) {
+ SET_FLAG_FOR_TEST(flags::vsync_predictor_recovery, true);
+ auto constexpr idealPeriodNs = 4166666;
+ auto constexpr minFrameIntervalNs = 8333333;
+ auto constexpr idealPeriod = Fps::fromPeriodNsecs(idealPeriodNs);
+ auto constexpr minFrameRate = Fps::fromPeriodNsecs(minFrameIntervalNs);
+ hal::VrrConfig vrrConfig{.minFrameIntervalNs = minFrameIntervalNs};
+ ftl::NonNull<DisplayModePtr> mode =
+ ftl::as_non_null(createVrrDisplayMode(DisplayModeId(0), idealPeriod, vrrConfig));
+ VSyncPredictor vrrTracker{std::make_unique<ClockWrapper>(mClock), mode, kHistorySize,
+ kMinimumSamplesForPrediction, kOutlierTolerancePercent};
+ vrrTracker.setRenderRate(minFrameRate, /*applyImmediately*/ true);
+ // Curated list of VSyncs that causes the VSync drift.
+ std::vector<nsecs_t> const simulatedVsyncs{74473665741, 74481774375, 74489911818, 74497993491,
+ 74506000833, 74510002150, 74513904390, 74517748707,
+ 74521550947, 74525383187, 74529165427, 74533067667,
+ 74536751484, 74540653724, 74544282649, 74548084889,
+ 74551917129, 74555699369, 74559601609, 74563601611,
+ 74567503851, 74571358168, 74575260408, 74578889333,
+ 74582691573, 74586523813, 74590306053, 74593589870,
+ 74597492110, 74601121035, 74604923275, 74608755515,
+ 74612537755, 74616166680, 74619795605, 74623424530,
+ 74627043455, 74630645695, 74634245935, 74637778175,
+ 74641291992, 74644794232, 74648275157, 74651575397,
+ 74654807637, 74658007877, 74661176117, 74664345357};
+ for (auto const& timestamp : simulatedVsyncs) {
+ vrrTracker.addVsyncTimestamp(timestamp);
+ }
+ auto slope = vrrTracker.getVSyncPredictionModel().slope;
+ // Without using the idealPeriod for the calculation of the VSync predictor mode the
+ // the slope would be 3343031
+ EXPECT_THAT(slope, IsCloseTo(4347805, mMaxRoundingError));
+ EXPECT_FALSE(vrrTracker.needsMoreSamples());
+
+ auto lastVsync = 74664345357;
+ // Add valid VSyncs to replace the drifted VSyncs
+ for (int i = 0; i <= kHistorySize; i++) {
+ lastVsync += minFrameIntervalNs;
+ EXPECT_TRUE(vrrTracker.addVsyncTimestamp(lastVsync));
+ }
+ EXPECT_FALSE(vrrTracker.needsMoreSamples());
+ slope = vrrTracker.getVSyncPredictionModel().slope;
+ // Corrected slop is closer to the idealPeriod
+ // when valid vsync are inserted otherwise this would still be 3349673
+ EXPECT_THAT(slope, IsCloseTo(idealPeriodNs, mMaxRoundingError));
+}
+
TEST_F(VSyncPredictorTest, handlesVsyncChange) {
auto const fastPeriod = 100;
auto const fastTimeBase = 100;
@@ -397,8 +444,8 @@
}
}
-// See b/145667109, and comment in prod code under test.
-TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) {
+TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept_withPredictorRecovery) {
+ SET_FLAG_FOR_TEST(flags::vsync_predictor_recovery, true);
std::vector<nsecs_t> const simulatedVsyncs{
158929578733000,
158929306806205, // oldest TS in ringbuffer
@@ -409,6 +456,34 @@
158929706370359,
};
auto const idealPeriod = 11111111;
+ auto const expectedPeriod = 11079563;
+ auto const expectedIntercept = 1335662;
+
+ tracker.setDisplayModePtr(displayMode(idealPeriod));
+ for (auto const& timestamp : simulatedVsyncs) {
+ tracker.addVsyncTimestamp(timestamp);
+ }
+
+ auto [slope, intercept] = tracker.getVSyncPredictionModel();
+ EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
+ EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
+
+ // (timePoint - oldestTS) % expectedPeriod works out to be: 894272
+ // (timePoint - oldestTS) / expectedPeriod works out to be: 38.08
+ auto const timePoint = 158929728723871;
+ auto const prediction = tracker.nextAnticipatedVSyncTimeFrom(timePoint);
+ EXPECT_THAT(prediction, Ge(timePoint));
+}
+
+// See b/145667109, and comment in prod code under test.
+TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) {
+ SET_FLAG_FOR_TEST(flags::vsync_predictor_recovery, false);
+ std::vector<nsecs_t> const simulatedVsyncs{
+ 158929578733000,
+ 158929306806205, // oldest TS in ringbuffer
+ 158929650879052, 158929661969209, 158929684198847, 158929695268171, 158929706370359,
+ };
+ auto const idealPeriod = 11111111;
auto const expectedPeriod = 11113919;
auto const expectedIntercept = -1195945;
@@ -421,9 +496,9 @@
EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
- // (timePoint - oldestTS) % expectedPeriod works out to be: 395334
- // (timePoint - oldestTS) / expectedPeriod works out to be: 38.96
- // so failure to account for the offset will floor the ordinal to 38, which was in the past.
+ // (timePoint - oldestTS) % expectedPeriod works out to be: 10702663
+ // (timePoint - oldestTS) / expectedPeriod works out to be: 37.96
+ // so failure to account for the offset will floor the ordinal to 37, which was in the past.
auto const timePoint = 158929728723871;
auto const prediction = tracker.nextAnticipatedVSyncTimeFrom(timePoint);
EXPECT_THAT(prediction, Ge(timePoint));
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index 879d2d0..be8fb3e 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -22,6 +22,13 @@
default_applicable_licenses: ["frameworks_native_license"],
}
+// Expose internal header files to test testing binary
+cc_library_headers {
+ name: "libvulkanprivate_headers-testing",
+ export_include_dirs: ["."],
+ visibility: ["//frameworks/native/vulkan/tests"],
+}
+
ndk_library {
name: "libvulkan",
symbol_file: "libvulkan.map.txt",
diff --git a/vulkan/libvulkan/TEST_MAPPING b/vulkan/libvulkan/TEST_MAPPING
new file mode 100644
index 0000000..16e342b7
--- /dev/null
+++ b/vulkan/libvulkan/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "libvulkan_test"
+ }
+ ]
+}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 09b0a14..5e2b55e 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -1413,6 +1413,119 @@
allocator->pfnFree(allocator->pUserData, swapchain);
}
+static VkResult getProducerUsageGPDIFP2(
+ const VkPhysicalDevice& pdev,
+ const VkSwapchainCreateInfoKHR* create_info,
+ const VkSwapchainImageUsageFlagsANDROID swapchain_image_usage,
+ bool create_protected_swapchain,
+ uint64_t* producer_usage) {
+ // Look through the create_info pNext chain passed to createSwapchainKHR
+ // for an image compression control struct.
+ // if one is found AND the appropriate extensions are enabled, create a
+ // VkImageCompressionControlEXT structure to pass on to
+ // GetPhysicalDeviceImageFormatProperties2
+ void* compression_control_pNext = nullptr;
+ VkImageCompressionControlEXT image_compression = {};
+ const VkSwapchainCreateInfoKHR* create_infos = create_info;
+ while (create_infos->pNext) {
+ create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(
+ create_infos->pNext);
+ switch (create_infos->sType) {
+ case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
+ const VkImageCompressionControlEXT* compression_infos =
+ reinterpret_cast<const VkImageCompressionControlEXT*>(
+ create_infos);
+ image_compression = *compression_infos;
+ image_compression.pNext = nullptr;
+ compression_control_pNext = &image_compression;
+ } break;
+ default:
+ // Ignore all other info structs
+ break;
+ }
+ }
+
+ // call GetPhysicalDeviceImageFormatProperties2KHR
+ VkPhysicalDeviceExternalImageFormatInfo external_image_format_info = {
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
+ .pNext = compression_control_pNext,
+ .handleType =
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
+ };
+
+ // AHB does not have an sRGB format so we can't pass it to GPDIFP
+ // We need to convert the format to unorm if it is srgb
+ VkFormat format = create_info->imageFormat;
+ if (format == VK_FORMAT_R8G8B8A8_SRGB) {
+ format = VK_FORMAT_R8G8B8A8_UNORM;
+ }
+
+ VkPhysicalDeviceImageFormatInfo2 image_format_info = {
+ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
+ .pNext = &external_image_format_info,
+ .format = format,
+ .type = VK_IMAGE_TYPE_2D,
+ .tiling = VK_IMAGE_TILING_OPTIMAL,
+ .usage = create_info->imageUsage,
+ .flags =
+ create_protected_swapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
+ };
+
+ // If supporting mutable format swapchain add the mutable format flag
+ if (create_info->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) {
+ image_format_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
+ image_format_info.flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR;
+ }
+
+ VkAndroidHardwareBufferUsageANDROID ahb_usage;
+ ahb_usage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
+ ahb_usage.pNext = nullptr;
+
+ VkImageFormatProperties2 image_format_properties;
+ image_format_properties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
+ image_format_properties.pNext = &ahb_usage;
+
+ VkResult result = GetPhysicalDeviceImageFormatProperties2(
+ pdev, &image_format_info, &image_format_properties);
+ if (result != VK_SUCCESS) {
+ ALOGE(
+ "VkGetPhysicalDeviceImageFormatProperties2 for AHB usage "
+ "failed: %d",
+ result);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+ // Determine if USAGE_FRONT_BUFFER is needed.
+ // GPDIFP2 has no means of using VkSwapchainImageUsageFlagsANDROID when
+ // querying for producer_usage. So androidHardwareBufferUsage will not
+ // contain USAGE_FRONT_BUFFER. We need to manually check for usage here.
+ if (!(swapchain_image_usage &
+ VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID)) {
+ *producer_usage = ahb_usage.androidHardwareBufferUsage;
+ return VK_SUCCESS;
+ }
+
+ // Check if USAGE_FRONT_BUFFER is supported for this swapchain
+ AHardwareBuffer_Desc ahb_desc = {
+ .width = create_info->imageExtent.width,
+ .height = create_info->imageExtent.height,
+ .layers = create_info->imageArrayLayers,
+ .format = create_info->imageFormat,
+ .usage = ahb_usage.androidHardwareBufferUsage |
+ AHARDWAREBUFFER_USAGE_FRONT_BUFFER,
+ .stride = 0, // stride is always ignored when calling isSupported()
+ };
+
+ // If FRONT_BUFFER is not supported in the GPDIFP2 path
+ // then we need to fallback to GetSwapchainGrallocUsageXAndroid
+ if (AHardwareBuffer_isSupported(&ahb_desc)) {
+ *producer_usage = ahb_usage.androidHardwareBufferUsage;
+ *producer_usage |= AHARDWAREBUFFER_USAGE_FRONT_BUFFER;
+ return VK_SUCCESS;
+ }
+
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+}
+
static VkResult getProducerUsage(const VkDevice& device,
const VkSwapchainCreateInfoKHR* create_info,
const VkSwapchainImageUsageFlagsANDROID swapchain_image_usage,
@@ -1422,106 +1535,16 @@
const VkPhysicalDevice& pdev = GetData(device).driver_physical_device;
const InstanceData& instance_data = GetData(pdev);
const InstanceDriverTable& instance_dispatch = instance_data.driver;
+
if (instance_dispatch.GetPhysicalDeviceImageFormatProperties2 ||
instance_dispatch.GetPhysicalDeviceImageFormatProperties2KHR) {
- // Look through the create_info pNext chain passed to createSwapchainKHR
- // for an image compression control struct.
- // if one is found AND the appropriate extensions are enabled, create a
- // VkImageCompressionControlEXT structure to pass on to
- // GetPhysicalDeviceImageFormatProperties2
- void* compression_control_pNext = nullptr;
- VkImageCompressionControlEXT image_compression = {};
- const VkSwapchainCreateInfoKHR* create_infos = create_info;
- while (create_infos->pNext) {
- create_infos = reinterpret_cast<const VkSwapchainCreateInfoKHR*>(create_infos->pNext);
- switch (create_infos->sType) {
- case VK_STRUCTURE_TYPE_IMAGE_COMPRESSION_CONTROL_EXT: {
- const VkImageCompressionControlEXT* compression_infos =
- reinterpret_cast<const VkImageCompressionControlEXT*>(create_infos);
- image_compression = *compression_infos;
- image_compression.pNext = nullptr;
- compression_control_pNext = &image_compression;
- } break;
- default:
- // Ignore all other info structs
- break;
- }
- }
-
- // call GetPhysicalDeviceImageFormatProperties2KHR
- VkPhysicalDeviceExternalImageFormatInfo external_image_format_info = {
- .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
- .pNext = compression_control_pNext,
- .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID,
- };
-
- // AHB does not have an sRGB format so we can't pass it to GPDIFP
- // We need to convert the format to unorm if it is srgb
- VkFormat format = create_info->imageFormat;
- if (format == VK_FORMAT_R8G8B8A8_SRGB) {
- format = VK_FORMAT_R8G8B8A8_UNORM;
- }
-
- VkPhysicalDeviceImageFormatInfo2 image_format_info = {
- .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
- .pNext = &external_image_format_info,
- .format = format,
- .type = VK_IMAGE_TYPE_2D,
- .tiling = VK_IMAGE_TILING_OPTIMAL,
- .usage = create_info->imageUsage,
- .flags = create_protected_swapchain ? VK_IMAGE_CREATE_PROTECTED_BIT : 0u,
- };
-
- // If supporting mutable format swapchain add the mutable format flag
- if (create_info->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) {
- image_format_info.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT;
- image_format_info.flags |= VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR;
- }
-
- VkAndroidHardwareBufferUsageANDROID ahb_usage;
- ahb_usage.sType = VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID;
- ahb_usage.pNext = nullptr;
-
- VkImageFormatProperties2 image_format_properties;
- image_format_properties.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2;
- image_format_properties.pNext = &ahb_usage;
-
- VkResult result = GetPhysicalDeviceImageFormatProperties2(
- pdev, &image_format_info, &image_format_properties);
- if (result != VK_SUCCESS) {
- ALOGE(
- "VkGetPhysicalDeviceImageFormatProperties2 for AHB usage "
- "failed: %d",
- result);
- return VK_ERROR_SURFACE_LOST_KHR;
- }
-
- // Determine if USAGE_FRONT_BUFFER is needed.
- // GPDIFP2 has no means of using VkSwapchainImageUsageFlagsANDROID when
- // querying for producer_usage. So androidHardwareBufferUsage will not
- // contain USAGE_FRONT_BUFFER. We need to manually check for usage here.
- if (!(swapchain_image_usage & VK_SWAPCHAIN_IMAGE_USAGE_SHARED_BIT_ANDROID)) {
- *producer_usage = ahb_usage.androidHardwareBufferUsage;
+ VkResult result =
+ getProducerUsageGPDIFP2(pdev, create_info, swapchain_image_usage,
+ create_protected_swapchain, producer_usage);
+ if (result == VK_SUCCESS) {
return VK_SUCCESS;
}
-
- // Check if USAGE_FRONT_BUFFER is supported for this swapchain
- AHardwareBuffer_Desc ahb_desc = {
- .width = create_info->imageExtent.width,
- .height = create_info->imageExtent.height,
- .layers = create_info->imageArrayLayers,
- .format = create_info->imageFormat,
- .usage = ahb_usage.androidHardwareBufferUsage | AHARDWAREBUFFER_USAGE_FRONT_BUFFER,
- .stride = 0, // stride is always ignored when calling isSupported()
- };
-
- // If FRONT_BUFFER is not supported,
- // then we need to call GetSwapchainGrallocUsageXAndroid below
- if (AHardwareBuffer_isSupported(&ahb_desc)) {
- *producer_usage = ahb_usage.androidHardwareBufferUsage;
- *producer_usage |= AHARDWAREBUFFER_USAGE_FRONT_BUFFER;
- return VK_SUCCESS;
- }
+ // Fall through to gralloc path on error
}
uint64_t native_usage = 0;
diff --git a/vulkan/tests/Android.bp b/vulkan/tests/Android.bp
new file mode 100644
index 0000000..db218c1
--- /dev/null
+++ b/vulkan/tests/Android.bp
@@ -0,0 +1,57 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_native_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_native_license"],
+}
+
+cc_test {
+ name: "libvulkan_test",
+ test_suites: ["general-tests"],
+
+ srcs: [
+ "libvulkan_test.cpp",
+ ],
+
+ strip: {
+ none: true,
+ },
+
+ cflags: [
+ "-DVK_USE_PLATFORM_ANDROID_KHR",
+ "-Wall",
+ "-Werror",
+ ],
+
+ header_libs: [
+ "hwvulkan_headers",
+ "libvulkanprivate_headers-testing",
+ "vulkan_headers",
+ ],
+
+ cppflags: [
+ "-Wno-c++98-compat-pedantic",
+ "-Wno-c99-extensions",
+ "-Wno-exit-time-destructors",
+ "-Wno-float-equal",
+ "-Wno-global-constructors",
+ "-Wno-zero-length-array",
+ ],
+
+ shared_libs: [
+ "libbase",
+ "libgraphicsenv",
+ "liblog",
+ "libmediandk",
+ "libvulkan",
+ ],
+
+ static_libs: [
+ "libgmock",
+ "libgtest",
+ "liblog",
+ ],
+
+}
diff --git a/vulkan/tests/README.md b/vulkan/tests/README.md
new file mode 100644
index 0000000..3c9b66c
--- /dev/null
+++ b/vulkan/tests/README.md
@@ -0,0 +1,24 @@
+#libvulkan_test
+
+This binary contains the unit tests for testing libvulkan (The Vulkan Loader).
+
+These tests rely on the underlying GPU driver to be able to successfully create a valid
+swapchain. These tests are design to run on an Android emulator to give us a consistent GPU
+driver to test against. YMMV when running this on a physical device with an arbitrary GPU
+driver.
+
+To run these tests run:
+```
+atest libvulkan_test
+```
+
+If using an acloud device the full command list for the root of a freshly cloned repo would be:
+```
+source build/envsetup.sh
+lunch aosp_cf_x86_64_phone-trunk_staging-eng
+m
+acloud create --local-image
+atest libvulkan_test
+```
+
+
diff --git a/vulkan/tests/libvulkan_test.cpp b/vulkan/tests/libvulkan_test.cpp
new file mode 100644
index 0000000..7e4bfd8
--- /dev/null
+++ b/vulkan/tests/libvulkan_test.cpp
@@ -0,0 +1,607 @@
+/*
+ * Copyright (C) 2011 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/log.h>
+#include <driver.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <media/NdkImageReader.h>
+#include <vulkan/vulkan.h>
+
+#define LOGI(...) \
+ __android_log_print(ANDROID_LOG_INFO, "libvulkan_test", __VA_ARGS__)
+#define LOGE(...) \
+ __android_log_print(ANDROID_LOG_ERROR, "libvulkan_test", __VA_ARGS__)
+
+#define VK_CHECK(result) ASSERT_EQ(VK_SUCCESS, result)
+
+namespace android {
+
+namespace libvulkantest {
+
+class AImageReaderVulkanSwapchainTest : public ::testing::Test {
+ public:
+ AImageReaderVulkanSwapchainTest() {}
+
+ AImageReader* mReader = nullptr;
+ ANativeWindow* mWindow = nullptr;
+ VkInstance mVkInstance = VK_NULL_HANDLE;
+ VkPhysicalDevice mPhysicalDev = VK_NULL_HANDLE;
+ VkDevice mDevice = VK_NULL_HANDLE;
+ VkSurfaceKHR mSurface = VK_NULL_HANDLE;
+ VkQueue mPresentQueue = VK_NULL_HANDLE;
+ uint32_t mPresentQueueFamily = UINT32_MAX;
+ VkSwapchainKHR mSwapchain = VK_NULL_HANDLE;
+
+ void SetUp() override {}
+
+ void TearDown() override {}
+
+ // ------------------------------------------------------
+ // Helper methods
+ // ------------------------------------------------------
+
+ void createVulkanInstance(std::vector<const char*>& layers) {
+ const char* extensions[] = {
+ VK_KHR_SURFACE_EXTENSION_NAME,
+ VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
+ VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
+ VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
+ };
+
+ VkApplicationInfo appInfo{};
+ appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
+ appInfo.pApplicationName = "AImageReader Vulkan Swapchain Test";
+ appInfo.applicationVersion = 1;
+ appInfo.pEngineName = "TestEngine";
+ appInfo.engineVersion = 1;
+ appInfo.apiVersion = VK_API_VERSION_1_0;
+
+ VkInstanceCreateInfo instInfo{};
+ instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
+ instInfo.pApplicationInfo = &appInfo;
+ instInfo.enabledExtensionCount =
+ sizeof(extensions) / sizeof(extensions[0]);
+ instInfo.ppEnabledExtensionNames = extensions;
+ instInfo.enabledLayerCount = layers.size();
+ instInfo.ppEnabledLayerNames = layers.data();
+ VkResult res = vkCreateInstance(&instInfo, nullptr, &mVkInstance);
+ VK_CHECK(res);
+ LOGE("Vulkan instance created");
+ }
+
+ void createAImageReader(int width, int height, int format, int maxImages) {
+ media_status_t status =
+ AImageReader_new(width, height, format, maxImages, &mReader);
+ ASSERT_EQ(AMEDIA_OK, status) << "Failed to create AImageReader";
+ ASSERT_NE(nullptr, mReader) << "AImageReader is null";
+
+ // Optionally set a listener
+ AImageReader_ImageListener listener{};
+ listener.context = this;
+ listener.onImageAvailable =
+ &AImageReaderVulkanSwapchainTest::onImageAvailable;
+ AImageReader_setImageListener(mReader, &listener);
+
+ LOGI("AImageReader created with %dx%d, format=%d", width, height,
+ format);
+ }
+
+ void getANativeWindowFromReader() {
+ ASSERT_NE(nullptr, mReader);
+
+ media_status_t status = AImageReader_getWindow(mReader, &mWindow);
+ ASSERT_EQ(AMEDIA_OK, status)
+ << "Failed to get ANativeWindow from AImageReader";
+ ASSERT_NE(nullptr, mWindow) << "ANativeWindow is null";
+ LOGI("ANativeWindow obtained from AImageReader");
+ }
+
+ void createVulkanSurface() {
+ ASSERT_NE((VkInstance)VK_NULL_HANDLE, mVkInstance);
+ ASSERT_NE((ANativeWindow*)nullptr, mWindow);
+
+ VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo{};
+ surfaceCreateInfo.sType =
+ VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
+ surfaceCreateInfo.window = mWindow;
+
+ VkResult res = vkCreateAndroidSurfaceKHR(
+ mVkInstance, &surfaceCreateInfo, nullptr, &mSurface);
+ VK_CHECK(res);
+ LOGI("Vulkan surface created from ANativeWindow");
+ }
+
+ void pickPhysicalDeviceAndQueueFamily() {
+ ASSERT_NE((VkInstance)VK_NULL_HANDLE, mVkInstance);
+
+ uint32_t deviceCount = 0;
+ vkEnumeratePhysicalDevices(mVkInstance, &deviceCount, nullptr);
+ ASSERT_GT(deviceCount, 0U) << "No Vulkan physical devices found!";
+
+ std::vector<VkPhysicalDevice> devices(deviceCount);
+ vkEnumeratePhysicalDevices(mVkInstance, &deviceCount, devices.data());
+
+ for (auto& dev : devices) {
+ uint32_t queueFamilyCount = 0;
+ vkGetPhysicalDeviceQueueFamilyProperties(dev, &queueFamilyCount,
+ nullptr);
+ std::vector<VkQueueFamilyProperties> queueProps(queueFamilyCount);
+ vkGetPhysicalDeviceQueueFamilyProperties(dev, &queueFamilyCount,
+ queueProps.data());
+
+ for (uint32_t i = 0; i < queueFamilyCount; i++) {
+ VkBool32 support = VK_FALSE;
+ vkGetPhysicalDeviceSurfaceSupportKHR(dev, i, mSurface,
+ &support);
+ if (support == VK_TRUE) {
+ // Found a queue family that can present
+ mPhysicalDev = dev;
+ mPresentQueueFamily = i;
+
+ LOGI(
+ "Physical device found with queue family %u supporting "
+ "present",
+ i);
+ return;
+ }
+ }
+ }
+
+ FAIL()
+ << "No physical device found that supports present to the surface!";
+ }
+
+ void createDeviceAndGetQueue(std::vector<const char*>& layers,
+ std::vector<const char*> inExtensions = {}) {
+ ASSERT_NE((void*)VK_NULL_HANDLE, mPhysicalDev);
+ ASSERT_NE(UINT32_MAX, mPresentQueueFamily);
+
+ float queuePriority = 1.0f;
+ VkDeviceQueueCreateInfo queueInfo{};
+ queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
+ queueInfo.queueFamilyIndex = mPresentQueueFamily;
+ queueInfo.queueCount = 1;
+ queueInfo.pQueuePriorities = &queuePriority;
+
+ VkDeviceCreateInfo deviceInfo{};
+ deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
+ deviceInfo.queueCreateInfoCount = 1;
+ deviceInfo.pQueueCreateInfos = &queueInfo;
+ deviceInfo.enabledLayerCount = layers.size();
+ deviceInfo.ppEnabledLayerNames = layers.data();
+
+ std::vector<const char*> extensions = {
+ VK_KHR_SWAPCHAIN_EXTENSION_NAME,
+ };
+ for (auto extension : inExtensions) {
+ extensions.push_back(extension);
+ }
+ deviceInfo.enabledExtensionCount = extensions.size();
+ deviceInfo.ppEnabledExtensionNames = extensions.data();
+
+ VkResult res =
+ vkCreateDevice(mPhysicalDev, &deviceInfo, nullptr, &mDevice);
+ VK_CHECK(res);
+ LOGI("Logical device created");
+
+ vkGetDeviceQueue(mDevice, mPresentQueueFamily, 0, &mPresentQueue);
+ ASSERT_NE((VkQueue)VK_NULL_HANDLE, mPresentQueue);
+ LOGI("Acquired present-capable queue");
+ }
+
+ void createSwapchain() {
+ ASSERT_NE((VkDevice)VK_NULL_HANDLE, mDevice);
+ ASSERT_NE((VkSurfaceKHR)VK_NULL_HANDLE, mSurface);
+
+ VkSurfaceCapabilitiesKHR surfaceCaps{};
+ VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
+ mPhysicalDev, mSurface, &surfaceCaps));
+
+ uint32_t formatCount = 0;
+ vkGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDev, mSurface,
+ &formatCount, nullptr);
+ ASSERT_GT(formatCount, 0U);
+ std::vector<VkSurfaceFormatKHR> formats(formatCount);
+ vkGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDev, mSurface,
+ &formatCount, formats.data());
+
+ VkSurfaceFormatKHR chosenFormat = formats[0];
+ LOGI("Chosen surface format: %d", chosenFormat.format);
+
+ uint32_t presentModeCount = 0;
+ vkGetPhysicalDeviceSurfacePresentModesKHR(mPhysicalDev, mSurface,
+ &presentModeCount, nullptr);
+ ASSERT_GT(presentModeCount, 0U);
+ std::vector<VkPresentModeKHR> presentModes(presentModeCount);
+ vkGetPhysicalDeviceSurfacePresentModesKHR(
+ mPhysicalDev, mSurface, &presentModeCount, presentModes.data());
+
+ VkPresentModeKHR chosenPresentMode = VK_PRESENT_MODE_FIFO_KHR;
+ for (auto mode : presentModes) {
+ if (mode == VK_PRESENT_MODE_FIFO_KHR) {
+ chosenPresentMode = mode;
+ break;
+ }
+ }
+ LOGI("Chosen present mode: %d", chosenPresentMode);
+
+ VkExtent2D swapchainExtent{};
+ if (surfaceCaps.currentExtent.width == 0xFFFFFFFF) {
+ swapchainExtent.width = 640; // fallback
+ swapchainExtent.height = 480; // fallback
+ } else {
+ swapchainExtent = surfaceCaps.currentExtent;
+ }
+ LOGI("Swapchain extent: %d x %d", swapchainExtent.width,
+ swapchainExtent.height);
+
+ uint32_t desiredImageCount = surfaceCaps.minImageCount + 1;
+ if (surfaceCaps.maxImageCount > 0 &&
+ desiredImageCount > surfaceCaps.maxImageCount) {
+ desiredImageCount = surfaceCaps.maxImageCount;
+ }
+
+ VkSwapchainCreateInfoKHR swapchainInfo{};
+ swapchainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+ swapchainInfo.surface = mSurface;
+ swapchainInfo.minImageCount = desiredImageCount;
+ swapchainInfo.imageFormat = chosenFormat.format;
+ swapchainInfo.imageColorSpace = chosenFormat.colorSpace;
+ swapchainInfo.imageExtent = swapchainExtent;
+ swapchainInfo.imageArrayLayers = 1;
+ swapchainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ swapchainInfo.preTransform = surfaceCaps.currentTransform;
+ swapchainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
+ swapchainInfo.presentMode = chosenPresentMode;
+ swapchainInfo.clipped = VK_TRUE;
+ swapchainInfo.oldSwapchain = VK_NULL_HANDLE;
+
+ uint32_t queueFamilyIndices[] = {mPresentQueueFamily};
+ swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ swapchainInfo.queueFamilyIndexCount = 1;
+ swapchainInfo.pQueueFamilyIndices = queueFamilyIndices;
+
+ VkResult res =
+ vkCreateSwapchainKHR(mDevice, &swapchainInfo, nullptr, &mSwapchain);
+ if (res == VK_SUCCESS) {
+ LOGI("Swapchain created successfully");
+
+ uint32_t swapchainImageCount = 0;
+ vkGetSwapchainImagesKHR(mDevice, mSwapchain, &swapchainImageCount,
+ nullptr);
+ std::vector<VkImage> swapchainImages(swapchainImageCount);
+ vkGetSwapchainImagesKHR(mDevice, mSwapchain, &swapchainImageCount,
+ swapchainImages.data());
+
+ LOGI("Swapchain has %u images", swapchainImageCount);
+ } else {
+ LOGI("Swapchain creation failed");
+ }
+ }
+
+ // Image available callback (AImageReader)
+ static void onImageAvailable(void*, AImageReader* reader) {
+ LOGI("onImageAvailable callback triggered");
+ AImage* image = nullptr;
+ media_status_t status = AImageReader_acquireLatestImage(reader, &image);
+ if (status != AMEDIA_OK || !image) {
+ LOGE("Failed to acquire latest image");
+ return;
+ }
+ AImage_delete(image);
+ LOGI("Released acquired image");
+ }
+
+ void cleanUpSwapchainForTest() {
+ if (mSwapchain != VK_NULL_HANDLE) {
+ vkDestroySwapchainKHR(mDevice, mSwapchain, nullptr);
+ mSwapchain = VK_NULL_HANDLE;
+ }
+ if (mDevice != VK_NULL_HANDLE) {
+ vkDestroyDevice(mDevice, nullptr);
+ mDevice = VK_NULL_HANDLE;
+ }
+ if (mSurface != VK_NULL_HANDLE) {
+ vkDestroySurfaceKHR(mVkInstance, mSurface, nullptr);
+ mSurface = VK_NULL_HANDLE;
+ }
+ if (mVkInstance != VK_NULL_HANDLE) {
+ vkDestroyInstance(mVkInstance, nullptr);
+ mVkInstance = VK_NULL_HANDLE;
+ }
+ if (mReader) {
+ // AImageReader_delete(mReader);
+ mReader = nullptr;
+ }
+ // Note: The ANativeWindow from AImageReader is implicitly
+ // managed by the reader, so we don't explicitly delete it.
+ mWindow = nullptr;
+ }
+
+ void buildSwapchianForTest(std::vector<const char*>& instanceLayers,
+ std::vector<const char*>& deviceLayers) {
+ createVulkanInstance(instanceLayers);
+
+ // the "atest libvulkan_test" command will execute this test as a binary
+ // (not apk) on the device. Consequently we can't render to the screen
+ // and need to work around this by using AImageReader*
+ createAImageReader(640, 480, AIMAGE_FORMAT_PRIVATE, 3);
+ getANativeWindowFromReader();
+ createVulkanSurface();
+ pickPhysicalDeviceAndQueueFamily();
+
+ createDeviceAndGetQueue(deviceLayers);
+ createSwapchain();
+ }
+};
+
+TEST_F(AImageReaderVulkanSwapchainTest, TestHelperMethods) {
+ // Verify that the basic plumbing/helper functions of these tests is
+ // working. This doesn't directly test any of the layer code. It only
+ // verifies that we can successfully create a swapchain with an AImageReader
+
+ std::vector<const char*> instanceLayers;
+ std::vector<const char*> deviceLayers;
+ buildSwapchianForTest(deviceLayers, instanceLayers);
+
+ ASSERT_NE(mVkInstance, (VkInstance)VK_NULL_HANDLE);
+ ASSERT_NE(mPhysicalDev, (VkPhysicalDevice)VK_NULL_HANDLE);
+ ASSERT_NE(mDevice, (VkDevice)VK_NULL_HANDLE);
+ ASSERT_NE(mSurface, (VkSurfaceKHR)VK_NULL_HANDLE);
+ ASSERT_NE(mSwapchain, (VkSwapchainKHR)VK_NULL_HANDLE);
+ cleanUpSwapchainForTest();
+}
+
+// Passing state in these tests requires global state. Wrap each test in an
+// anonymous namespace to prevent conflicting names.
+namespace {
+
+VKAPI_ATTR VkResult VKAPI_CALL hookedGetPhysicalDeviceImageFormatProperties2KHR(
+ VkPhysicalDevice,
+ const VkPhysicalDeviceImageFormatInfo2*,
+ VkImageFormatProperties2*) {
+ return VK_ERROR_SURFACE_LOST_KHR;
+}
+
+static PFN_vkGetSwapchainGrallocUsage2ANDROID
+ pfnNextGetSwapchainGrallocUsage2ANDROID = nullptr;
+
+static bool g_grallocCalled = false;
+
+VKAPI_ATTR VkResult VKAPI_CALL hookGetSwapchainGrallocUsage2ANDROID(
+ VkDevice device,
+ VkFormat format,
+ VkImageUsageFlags imageUsage,
+ VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,
+ uint64_t* grallocConsumerUsage,
+ uint64_t* grallocProducerUsage) {
+ g_grallocCalled = true;
+ if (pfnNextGetSwapchainGrallocUsage2ANDROID) {
+ return pfnNextGetSwapchainGrallocUsage2ANDROID(
+ device, format, imageUsage, swapchainImageUsage,
+ grallocConsumerUsage, grallocProducerUsage);
+ }
+
+ return VK_ERROR_INITIALIZATION_FAILED;
+}
+
+TEST_F(AImageReaderVulkanSwapchainTest, getProducerUsageFallbackTest1) {
+ // BUG: 379230826
+ // Verify that getProducerUsage falls back to
+ // GetSwapchainGrallocUsage*ANDROID if GPDIFP2 fails
+ std::vector<const char*> instanceLayers = {};
+ std::vector<const char*> deviceLayers = {};
+ createVulkanInstance(instanceLayers);
+
+ createAImageReader(640, 480, AIMAGE_FORMAT_PRIVATE, 3);
+ getANativeWindowFromReader();
+ createVulkanSurface();
+ pickPhysicalDeviceAndQueueFamily();
+
+ createDeviceAndGetQueue(deviceLayers);
+ auto& pdev = vulkan::driver::GetData(mDevice).driver_physical_device;
+ auto& pdevDispatchTable = vulkan::driver::GetData(pdev).driver;
+ auto& deviceDispatchTable = vulkan::driver::GetData(mDevice).driver;
+
+ ASSERT_NE(deviceDispatchTable.GetSwapchainGrallocUsage2ANDROID, nullptr);
+
+ pdevDispatchTable.GetPhysicalDeviceImageFormatProperties2 =
+ hookedGetPhysicalDeviceImageFormatProperties2KHR;
+ deviceDispatchTable.GetSwapchainGrallocUsage2ANDROID =
+ hookGetSwapchainGrallocUsage2ANDROID;
+
+ ASSERT_FALSE(g_grallocCalled);
+
+ createSwapchain();
+
+ ASSERT_TRUE(g_grallocCalled);
+
+ ASSERT_NE(mVkInstance, (VkInstance)VK_NULL_HANDLE);
+ ASSERT_NE(mPhysicalDev, (VkPhysicalDevice)VK_NULL_HANDLE);
+ ASSERT_NE(mDevice, (VkDevice)VK_NULL_HANDLE);
+ ASSERT_NE(mSurface, (VkSurfaceKHR)VK_NULL_HANDLE);
+ cleanUpSwapchainForTest();
+}
+
+} // namespace
+
+// Passing state in these tests requires global state. Wrap each test in an
+// anonymous namespace to prevent conflicting names.
+namespace {
+
+static bool g_returnNotSupportedOnce = true;
+
+VKAPI_ATTR VkResult VKAPI_CALL
+Hook_GetPhysicalDeviceImageFormatProperties2_NotSupportedOnce(
+ VkPhysicalDevice /*physicalDevice*/,
+ const VkPhysicalDeviceImageFormatInfo2* /*pImageFormatInfo*/,
+ VkImageFormatProperties2* /*pImageFormatProperties*/) {
+ if (g_returnNotSupportedOnce) {
+ g_returnNotSupportedOnce = false;
+ return VK_ERROR_FORMAT_NOT_SUPPORTED;
+ }
+ return VK_SUCCESS;
+}
+
+TEST_F(AImageReaderVulkanSwapchainTest, SurfaceFormats2KHR_IgnoreNotSupported) {
+ // BUG: 357903074
+ // Verify that vkGetPhysicalDeviceSurfaceFormats2KHR properly
+ // ignores VK_ERROR_FORMAT_NOT_SUPPORTED and continues enumerating formats.
+ std::vector<const char*> instanceLayers;
+ createVulkanInstance(instanceLayers);
+ createAImageReader(640, 480, AIMAGE_FORMAT_PRIVATE, 3);
+ getANativeWindowFromReader();
+ createVulkanSurface();
+ pickPhysicalDeviceAndQueueFamily();
+
+ auto& pdevDispatchTable = vulkan::driver::GetData(mPhysicalDev).driver;
+ pdevDispatchTable.GetPhysicalDeviceImageFormatProperties2 =
+ Hook_GetPhysicalDeviceImageFormatProperties2_NotSupportedOnce;
+
+ PFN_vkGetPhysicalDeviceSurfaceFormats2KHR
+ pfnGetPhysicalDeviceSurfaceFormats2KHR =
+ reinterpret_cast<PFN_vkGetPhysicalDeviceSurfaceFormats2KHR>(
+ vkGetInstanceProcAddr(mVkInstance,
+ "vkGetPhysicalDeviceSurfaceFormats2KHR"));
+ ASSERT_NE(nullptr, pfnGetPhysicalDeviceSurfaceFormats2KHR)
+ << "Could not get pointer to vkGetPhysicalDeviceSurfaceFormats2KHR";
+
+ VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo2{};
+ surfaceInfo2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
+ surfaceInfo2.pNext = nullptr;
+ surfaceInfo2.surface = mSurface;
+
+ uint32_t formatCount = 0;
+ VkResult res = pfnGetPhysicalDeviceSurfaceFormats2KHR(
+ mPhysicalDev, &surfaceInfo2, &formatCount, nullptr);
+
+ // If the loader never tries a second format, it might fail or 0-out the
+ // formatCount. The patch ensures it continues to the next format rather
+ // than bailing out on the first NOT_SUPPORTED.
+ ASSERT_EQ(VK_SUCCESS, res)
+ << "vkGetPhysicalDeviceSurfaceFormats2KHR failed unexpectedly";
+ ASSERT_GT(formatCount, 0U)
+ << "No surface formats found; the loader may have bailed early.";
+
+ std::vector<VkSurfaceFormat2KHR> formats(formatCount);
+ for (auto& f : formats) {
+ f.sType = VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR;
+ f.pNext = nullptr;
+ }
+ res = pfnGetPhysicalDeviceSurfaceFormats2KHR(mPhysicalDev, &surfaceInfo2,
+ &formatCount, formats.data());
+ ASSERT_EQ(VK_SUCCESS, res) << "Failed to retrieve surface formats";
+
+ LOGI(
+ "SurfaceFormats2KHR_IgnoreNotSupported test: found %u formats after "
+ "ignoring NOT_SUPPORTED",
+ formatCount);
+
+ cleanUpSwapchainForTest();
+}
+
+} // namespace
+
+namespace {
+
+TEST_F(AImageReaderVulkanSwapchainTest, MutableFormatSwapchainTest) {
+ // Test swapchain with mutable format extension
+ std::vector<const char*> instanceLayers;
+ std::vector<const char*> deviceLayers;
+ std::vector<const char*> deviceExtensions = {
+ VK_KHR_SWAPCHAIN_EXTENSION_NAME,
+ VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME,
+ VK_KHR_MAINTENANCE2_EXTENSION_NAME,
+ VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME};
+
+ createVulkanInstance(instanceLayers);
+ createAImageReader(640, 480, AIMAGE_FORMAT_PRIVATE, 3);
+ getANativeWindowFromReader();
+ createVulkanSurface();
+ pickPhysicalDeviceAndQueueFamily();
+ createDeviceAndGetQueue(deviceLayers, deviceExtensions);
+
+ ASSERT_NE((VkDevice)VK_NULL_HANDLE, mDevice);
+ ASSERT_NE((VkSurfaceKHR)VK_NULL_HANDLE, mSurface);
+
+ VkSurfaceCapabilitiesKHR surfaceCaps{};
+ VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(mPhysicalDev, mSurface,
+ &surfaceCaps));
+
+ uint32_t formatCount = 0;
+ vkGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDev, mSurface, &formatCount,
+ nullptr);
+ ASSERT_GT(formatCount, 0U);
+ std::vector<VkSurfaceFormatKHR> formats(formatCount);
+ vkGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDev, mSurface, &formatCount,
+ formats.data());
+
+ VkFormat viewFormats[2] = {formats[0].format, formats[0].format};
+ if (formatCount > 1) {
+ viewFormats[1] = formats[1].format;
+ }
+
+ VkImageFormatListCreateInfoKHR formatList{};
+ formatList.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR;
+ formatList.viewFormatCount = 2;
+ formatList.pViewFormats = viewFormats;
+
+ VkSwapchainCreateInfoKHR swapchainInfo{};
+ swapchainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
+ swapchainInfo.pNext = &formatList;
+ swapchainInfo.surface = mSurface;
+ swapchainInfo.minImageCount = surfaceCaps.minImageCount + 1;
+ swapchainInfo.imageFormat = formats[0].format;
+ swapchainInfo.imageColorSpace = formats[0].colorSpace;
+ swapchainInfo.imageExtent = surfaceCaps.currentExtent;
+ swapchainInfo.imageArrayLayers = 1;
+ swapchainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+ swapchainInfo.preTransform = surfaceCaps.currentTransform;
+ swapchainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
+ swapchainInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR;
+ swapchainInfo.clipped = VK_TRUE;
+
+ swapchainInfo.flags = VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR;
+
+ uint32_t queueFamilyIndices[] = {mPresentQueueFamily};
+ swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ swapchainInfo.queueFamilyIndexCount = 1;
+ swapchainInfo.pQueueFamilyIndices = queueFamilyIndices;
+
+ VkResult res =
+ vkCreateSwapchainKHR(mDevice, &swapchainInfo, nullptr, &mSwapchain);
+ if (res == VK_SUCCESS) {
+ LOGI("Mutable format swapchain created successfully");
+
+ uint32_t imageCount = 0;
+ vkGetSwapchainImagesKHR(mDevice, mSwapchain, &imageCount, nullptr);
+ ASSERT_GT(imageCount, 0U);
+ } else {
+ LOGI(
+ "Mutable format swapchain creation failed (extension may not be "
+ "supported)");
+ }
+
+ cleanUpSwapchainForTest();
+}
+
+} // namespace
+
+} // namespace libvulkantest
+
+} // namespace android
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index 8c0cce2..18fef2b 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -986,6 +986,13 @@
template <typename Visitor>
inline bool Iterate(Visitor* visitor,
+ VkJsonExtImage2DViewOf3DFeatures* features) {
+ return visitor->Visit("image2DViewOf3DFeaturesEXT",
+ &features->image_2D_view_of_3D_features_EXT);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
VkJsonExtShaderFloat16Int8Features* features) {
return visitor->Visit("shaderFloat16Int8FeaturesKHR",
&features->shader_float16_int8_features_khr);
@@ -1093,6 +1100,13 @@
template <typename Visitor>
inline bool Iterate(Visitor* visitor,
+ VkPhysicalDeviceImage2DViewOf3DFeaturesEXT* features) {
+ return visitor->Visit("image2DViewOf3D", &features->image2DViewOf3D) &&
+ visitor->Visit("sampler2DViewOf3D", &features->sampler2DViewOf3D);
+}
+
+template <typename Visitor>
+inline bool Iterate(Visitor* visitor,
VkPhysicalDeviceShaderFloat16Int8FeaturesKHR* features) {
return visitor->Visit("shaderFloat16", &features->shaderFloat16) &&
visitor->Visit("shaderInt8", &features->shaderInt8);
@@ -1241,6 +1255,10 @@
ret &= visitor->Visit("VK_KHR_variable_pointers",
&device->ext_variable_pointer_features);
}
+ if (device->ext_image_2d_view_of_3d_features.reported) {
+ ret &= visitor->Visit("VK_EXT_image_2d_view_of_3d",
+ &device->ext_image_2d_view_of_3d_features);
+ }
if (device->ext_shader_float16_int8_features.reported) {
ret &= visitor->Visit("VK_KHR_shader_float16_int8",
&device->ext_shader_float16_int8_features);
diff --git a/vulkan/vkjson/vkjson.h b/vulkan/vkjson/vkjson.h
index 5818c73..87a76c1 100644
--- a/vulkan/vkjson/vkjson.h
+++ b/vulkan/vkjson/vkjson.h
@@ -58,6 +58,16 @@
VkPhysicalDeviceVariablePointerFeaturesKHR variable_pointer_features_khr;
};
+struct VkJsonExtImage2DViewOf3DFeatures {
+ VkJsonExtImage2DViewOf3DFeatures() {
+ reported = false;
+ memset(&image_2D_view_of_3D_features_EXT, 0,
+ sizeof(VkPhysicalDeviceImage2DViewOf3DFeaturesEXT));
+ }
+ bool reported;
+ VkPhysicalDeviceImage2DViewOf3DFeaturesEXT image_2D_view_of_3D_features_EXT;
+};
+
struct VkJsonExtShaderFloat16Int8Features {
VkJsonExtShaderFloat16Int8Features() {
reported = false;
@@ -115,6 +125,7 @@
VkPhysicalDeviceFeatures features;
VkJsonExtDriverProperties ext_driver_properties;
VkJsonExtVariablePointerFeatures ext_variable_pointer_features;
+ VkJsonExtImage2DViewOf3DFeatures ext_image_2d_view_of_3d_features;
VkJsonExtShaderFloat16Int8Features ext_shader_float16_int8_features;
VkPhysicalDeviceMemoryProperties memory;
std::vector<VkQueueFamilyProperties> queues;
diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc
index 32bc50b..04bb446 100644
--- a/vulkan/vkjson/vkjson_instance.cc
+++ b/vulkan/vkjson/vkjson_instance.cc
@@ -103,6 +103,16 @@
features.pNext =
&device.ext_variable_pointer_features.variable_pointer_features_khr;
}
+ if (HasExtension("VK_EXT_image_2d_view_of_3d", device.extensions)) {
+ device.ext_image_2d_view_of_3d_features.reported = true;
+ device.ext_image_2d_view_of_3d_features.image_2D_view_of_3D_features_EXT
+ .sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_2D_VIEW_OF_3D_FEATURES_EXT;
+ device.ext_image_2d_view_of_3d_features.image_2D_view_of_3D_features_EXT
+ .pNext = features.pNext;
+ features.pNext = &device.ext_image_2d_view_of_3d_features
+ .image_2D_view_of_3D_features_EXT;
+ }
if (HasExtension("VK_KHR_shader_float16_int8", device.extensions)) {
device.ext_shader_float16_int8_features.reported = true;
device.ext_shader_float16_int8_features.shader_float16_int8_features_khr