Merge "InputVerifier: add panic message for source conversion" into main
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/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/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/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/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/Choreographer.cpp b/libs/gui/Choreographer.cpp
index ab747b9..fb3e0f1 100644
--- a/libs/gui/Choreographer.cpp
+++ b/libs/gui/Choreographer.cpp
@@ -69,7 +69,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,21 +86,21 @@
"()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");
return nullptr;
}
}
- return gChoreographer;
+ return gChoreographer.get();
}
Choreographer::Choreographer(const sp<Looper>& looper, const sp<IBinder>& layerHandle)
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 37ed23b..df57b27 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -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;
}
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/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/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/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/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/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/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index bed31e2..24c2c74 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,
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/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/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp
index 85f842c..21f4f2c 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) {
@@ -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);
@@ -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,
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index a77dc43..ba75071 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;
}
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..1778f6d 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,46 @@
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();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp
index d02c3d9..99db8fe 100644
--- a/services/inputflinger/tests/PointerChoreographer_test.cpp
+++ b/services/inputflinger/tests/PointerChoreographer_test.cpp
@@ -1008,6 +1008,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);
+ mChoreographer.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>;
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..a599619 100644
--- a/services/stats/OWNERS
+++ b/services/stats/OWNERS
@@ -6,4 +6,3 @@
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/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..cf2d8c2 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -619,7 +619,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 +1006,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 +1025,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/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/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f3db4c5..98abd10 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;
diff --git a/vulkan/tests/Android.bp b/vulkan/tests/Android.bp
new file mode 100644
index 0000000..551d9b7
--- /dev/null
+++ b/vulkan/tests/Android.bp
@@ -0,0 +1,56 @@
+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",
+ "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..128d640
--- /dev/null
+++ b/vulkan/tests/libvulkan_test.cpp
@@ -0,0 +1,360 @@
+/*
+ * 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 <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 {
+
+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_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) {
+ 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();
+
+ const char* extensions[] = {
+ VK_KHR_SWAPCHAIN_EXTENSION_NAME,
+ };
+ deviceInfo.enabledExtensionCount =
+ sizeof(extensions) / sizeof(extensions[0]);
+ deviceInfo.ppEnabledExtensionNames = extensions;
+
+ 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);
+ VK_CHECK(res);
+ 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);
+ }
+
+ // 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();
+}
+
+} // namespace android