Merge "Unified layer capture functions into one function"
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 55dbcd1..b215756 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -176,7 +176,12 @@
sidebandStream = NativeHandle::create(input.readNativeHandle(), true);
}
- colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float))));
+ const void* color_transform_data = input.readInplace(16 * sizeof(float));
+ if (color_transform_data) {
+ colorTransform = mat4(static_cast<const float*>(color_transform_data));
+ } else {
+ return BAD_VALUE;
+ }
cornerRadius = input.readFloat();
backgroundBlurRadius = input.readUint32();
cachedBuffer.token = input.readStrongBinder();
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 6c9ac4e..3464b8f 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1687,15 +1687,11 @@
newTouchedWindowHandle = nullptr;
}
+ // Ensure the window has a connection and the connection is responsive
if (newTouchedWindowHandle != nullptr) {
- sp<Connection> connection = getConnectionLocked(newTouchedWindowHandle->getToken());
- if (connection == nullptr) {
- ALOGI("Could not find connection for %s",
- newTouchedWindowHandle->getName().c_str());
- newTouchedWindowHandle = nullptr;
- } else if (!connection->responsive) {
- // don't send the new touch to an unresponsive window
- ALOGW("Unresponsive window %s will not get the new gesture at %" PRIu64,
+ const bool isResponsive = hasResponsiveConnectionLocked(*newTouchedWindowHandle);
+ if (!isResponsive) {
+ ALOGW("%s will not receive the new gesture at %" PRIu64,
newTouchedWindowHandle->getName().c_str(), entry.eventTime);
newTouchedWindowHandle = nullptr;
}
@@ -3678,6 +3674,29 @@
return false;
}
+bool InputDispatcher::hasResponsiveConnectionLocked(InputWindowHandle& windowHandle) const {
+ sp<Connection> connection = getConnectionLocked(windowHandle.getToken());
+ const bool noInputChannel =
+ windowHandle.getInfo()->inputFeatures.test(InputWindowInfo::Feature::NO_INPUT_CHANNEL);
+ if (connection != nullptr && noInputChannel) {
+ ALOGW("%s has feature NO_INPUT_CHANNEL, but it matched to connection %s",
+ windowHandle.getName().c_str(), connection->inputChannel->getName().c_str());
+ return false;
+ }
+
+ if (connection == nullptr) {
+ if (!noInputChannel) {
+ ALOGI("Could not find connection for %s", windowHandle.getName().c_str());
+ }
+ return false;
+ }
+ if (!connection->responsive) {
+ ALOGW("Window %s is not responsive", windowHandle.getName().c_str());
+ return false;
+ }
+ return true;
+}
+
std::shared_ptr<InputChannel> InputDispatcher::getInputChannelLocked(
const sp<IBinder>& token) const {
size_t count = mInputChannelsByToken.count(token);
@@ -3773,6 +3792,17 @@
ALOGD("setInputWindows displayId=%" PRId32 " %s", displayId, windowList.c_str());
}
+ // Ensure all tokens are null if the window has feature NO_INPUT_CHANNEL
+ for (const sp<InputWindowHandle>& window : inputWindowHandles) {
+ const bool noInputWindow =
+ window->getInfo()->inputFeatures.test(InputWindowInfo::Feature::NO_INPUT_CHANNEL);
+ if (noInputWindow && window->getToken() != nullptr) {
+ ALOGE("%s has feature NO_INPUT_WINDOW, but a non-null token. Clearing",
+ window->getName().c_str());
+ window->releaseChannel();
+ }
+ }
+
// Copy old handles for release if they are no longer present.
const std::vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 982f6af..0ff914f 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -307,6 +307,7 @@
std::shared_ptr<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const
REQUIRES(mLock);
bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
+ bool hasResponsiveConnectionLocked(InputWindowHandle& windowHandle) const REQUIRES(mLock);
/*
* Validate and update InputWindowHandles for a given display.
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index afbec99..fe0f214 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -3842,9 +3842,9 @@
#if DEBUG_POINTER_ASSIGNMENT
ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize);
- for (size_t i = 0; i < heapSize; i++) {
- ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64, i,
- heap[i].currentPointerIndex, heap[i].lastPointerIndex, heap[i].distance);
+ for (size_t j = 0; j < heapSize; j++) {
+ ALOGD(" heap[%zu]: cur=%" PRIu32 ", last=%" PRIu32 ", distance=%" PRIu64, j,
+ heap[j].currentPointerIndex, heap[j].lastPointerIndex, heap[j].distance);
}
#endif
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 7c4bf77..cc19cb1 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -749,9 +749,9 @@
FakeWindowHandle(const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle,
const sp<InputDispatcher>& dispatcher, const std::string name,
- int32_t displayId, sp<IBinder> token = nullptr)
+ int32_t displayId, std::optional<sp<IBinder>> token = std::nullopt)
: mName(name) {
- if (token == nullptr) {
+ if (token == std::nullopt) {
std::unique_ptr<InputChannel> serverChannel, clientChannel;
InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(clientChannel), name);
@@ -762,7 +762,7 @@
inputApplicationHandle->updateInfo();
mInfo.applicationInfo = *inputApplicationHandle->getInfo();
- mInfo.token = token;
+ mInfo.token = *token;
mInfo.id = sId++;
mInfo.name = name;
mInfo.type = InputWindowInfo::Type::APPLICATION;
@@ -807,6 +807,8 @@
void setFlags(Flags<InputWindowInfo::Flag> flags) { mInfo.flags = flags; }
+ void setInputFeatures(InputWindowInfo::Feature features) { mInfo.inputFeatures = features; }
+
void setWindowTransform(float dsdx, float dtdx, float dtdy, float dsdy) {
mInfo.transform.set(dsdx, dtdx, dtdy, dsdy);
}
@@ -894,8 +896,12 @@
}
void assertNoEvents() {
- ASSERT_NE(mInputReceiver, nullptr)
- << "Call 'assertNoEvents' on a window with an InputReceiver";
+ if (mInputReceiver == nullptr &&
+ mInfo.inputFeatures.test(InputWindowInfo::Feature::NO_INPUT_CHANNEL)) {
+ return; // Can't receive events if the window does not have input channel
+ }
+ ASSERT_NE(nullptr, mInputReceiver)
+ << "Window without InputReceiver must specify feature NO_INPUT_CHANNEL";
mInputReceiver->assertNoEvents();
}
@@ -3307,4 +3313,77 @@
mFocusedWindow->assertNoEvents();
}
+// These tests ensure we cannot send touch events to a window that's positioned behind a window
+// that has feature NO_INPUT_CHANNEL.
+// Layout:
+// Top (closest to user)
+// mNoInputWindow (above all windows)
+// mBottomWindow
+// Bottom (furthest from user)
+class InputDispatcherMultiWindowOcclusionTests : public InputDispatcherTest {
+ virtual void SetUp() override {
+ InputDispatcherTest::SetUp();
+
+ mApplication = std::make_shared<FakeApplicationHandle>();
+ mNoInputWindow = new FakeWindowHandle(mApplication, mDispatcher,
+ "Window without input channel", ADISPLAY_ID_DEFAULT,
+ std::make_optional<sp<IBinder>>(nullptr) /*token*/);
+
+ mNoInputWindow->setInputFeatures(InputWindowInfo::Feature::NO_INPUT_CHANNEL);
+ mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
+ // It's perfectly valid for this window to not have an associated input channel
+
+ mBottomWindow = new FakeWindowHandle(mApplication, mDispatcher, "Bottom window",
+ ADISPLAY_ID_DEFAULT);
+ mBottomWindow->setFrame(Rect(0, 0, 100, 100));
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mNoInputWindow, mBottomWindow}}});
+ }
+
+protected:
+ std::shared_ptr<FakeApplicationHandle> mApplication;
+ sp<FakeWindowHandle> mNoInputWindow;
+ sp<FakeWindowHandle> mBottomWindow;
+};
+
+TEST_F(InputDispatcherMultiWindowOcclusionTests, NoInputChannelFeature_DropsTouches) {
+ PointF touchedPoint = {10, 10};
+
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {touchedPoint});
+ mDispatcher->notifyMotion(&motionArgs);
+
+ mNoInputWindow->assertNoEvents();
+ // Even though the window 'mNoInputWindow' positioned above 'mBottomWindow' does not have
+ // an input channel, it is not marked as FLAG_NOT_TOUCHABLE,
+ // and therefore should prevent mBottomWindow from receiving touches
+ mBottomWindow->assertNoEvents();
+}
+
+/**
+ * If a window has feature NO_INPUT_CHANNEL, and somehow (by mistake) still has an input channel,
+ * ensure that this window does not receive any touches, and blocks touches to windows underneath.
+ */
+TEST_F(InputDispatcherMultiWindowOcclusionTests,
+ NoInputChannelFeature_DropsTouchesWithValidChannel) {
+ mNoInputWindow = new FakeWindowHandle(mApplication, mDispatcher,
+ "Window with input channel and NO_INPUT_CHANNEL",
+ ADISPLAY_ID_DEFAULT);
+
+ mNoInputWindow->setInputFeatures(InputWindowInfo::Feature::NO_INPUT_CHANNEL);
+ mNoInputWindow->setFrame(Rect(0, 0, 100, 100));
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mNoInputWindow, mBottomWindow}}});
+
+ PointF touchedPoint = {10, 10};
+
+ NotifyMotionArgs motionArgs =
+ generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+ ADISPLAY_ID_DEFAULT, {touchedPoint});
+ mDispatcher->notifyMotion(&motionArgs);
+
+ mNoInputWindow->assertNoEvents();
+ mBottomWindow->assertNoEvents();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index ff91bf7..46112f5 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -340,7 +340,7 @@
return nextEventTime;
}
- // Sanity check that the duration is close enough in length to a period without
+ // Check that the duration is close enough in length to a period without
// falling into double-rate vsyncs.
bool isCloseToPeriod(nsecs_t duration) {
// Ratio of 3/5 is arbitrary, but it must be greater than 1/2.
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index 832f08e..6fb5654 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -227,7 +227,7 @@
// mZeroErrSamplesCount keeps track of how many times in a row there were
// zero timestamps available in the mPresentFences array.
- // Used to sanity check that we are able to calculate the model error.
+ // Used to check that we are able to calculate the model error.
size_t mZeroErrSamplesCount;
// Whether we have updated the vsync event model since the last resync.
diff --git a/vulkan/include/hardware/hwvulkan.h b/vulkan/include/hardware/hwvulkan.h
index 9e9a14d..98bc8e3 100644
--- a/vulkan/include/hardware/hwvulkan.h
+++ b/vulkan/include/hardware/hwvulkan.h
@@ -54,8 +54,9 @@
/* A hwvulkan_device_t corresponds to an ICD on other systems. Currently there
* can only be one on a system (HWVULKAN_DEVICE_0). It is opened once per
* process when the Vulkan API is first used; the hw_device_t::close() function
- * is never called. Any non-trivial resource allocation should be done when
- * the VkInstance is created rather than when the hwvulkan_device_t is opened.
+ * is called upon driver unloading. Any non-trivial resource allocation should
+ * be done when the VkInstance is created rather than when the hwvulkan_device_t
+ * is opened.
*/
typedef struct hwvulkan_device_t {
struct hw_device_t common;
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index 80166c8..2d4690a 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -1174,23 +1174,18 @@
// ----------------------------------------------------------------------------
bool EnsureInitialized() {
- static std::once_flag once_flag;
- static bool initialized;
+ static bool initialized = false;
+ static pid_t init_attempted_for_pid = 0;
+ static std::mutex init_lock;
- std::call_once(once_flag, []() {
- if (driver::OpenHAL()) {
- initialized = true;
- }
- });
+ std::lock_guard<std::mutex> lock(init_lock);
+ if (init_attempted_for_pid == getpid())
+ return initialized;
- {
- static pid_t pid = getpid() + 1;
- static std::mutex layer_lock;
- std::lock_guard<std::mutex> lock(layer_lock);
- if (pid != getpid()) {
- pid = getpid();
- DiscoverLayers();
- }
+ init_attempted_for_pid = getpid();
+ if (driver::OpenHAL()) {
+ DiscoverLayers();
+ initialized = true;
}
return initialized;
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index e3fc67e..8deca47 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -84,6 +84,8 @@
Hal(const Hal&) = delete;
Hal& operator=(const Hal&) = delete;
+ bool ShouldUnloadBuiltinDriver();
+ void UnloadBuiltinDriver();
bool InitDebugReportIndex();
static Hal hal_;
@@ -243,7 +245,12 @@
const nsecs_t openTime = systemTime();
- ALOG_ASSERT(!hal_.dev_, "OpenHAL called more than once");
+ if (hal_.ShouldUnloadBuiltinDriver()) {
+ hal_.UnloadBuiltinDriver();
+ }
+
+ if (hal_.dev_)
+ return true;
// Use a stub device unless we successfully open a real HAL device.
hal_.dev_ = &stubhal::kDevice;
@@ -288,6 +295,38 @@
return true;
}
+bool Hal::ShouldUnloadBuiltinDriver() {
+ // Should not unload since the driver was not loaded
+ if (!hal_.dev_)
+ return false;
+
+ // Should not unload if stubhal is used on the device
+ if (hal_.dev_ == &stubhal::kDevice)
+ return false;
+
+ // Unload the driver if updated driver is chosen
+ if (android::GraphicsEnv::getInstance().getDriverNamespace())
+ return true;
+
+ return false;
+}
+
+void Hal::UnloadBuiltinDriver() {
+ ATRACE_CALL();
+
+ ALOGD("Unload builtin Vulkan driver.");
+
+ // Close the opened device
+ ALOG_ASSERT(!hal_.dev_->common.close(hal_.dev_->common),
+ "hw_device_t::close() failed.");
+
+ // Close the opened shared library in the hw_module_t
+ dlclose(hal_.dev_->common.module->dso);
+
+ hal_.dev_ = nullptr;
+ hal_.debug_report_index_ = -1;
+}
+
bool Hal::InitDebugReportIndex() {
ATRACE_CALL();