Merge "Add multi-device tests to dispatcher" into main
diff --git a/include/input/Input.h b/include/input/Input.h
index 64ee473..567361d 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -285,6 +285,16 @@
     // This policy flag prevents key events from changing touch mode state.
     POLICY_FLAG_GESTURE = 0x00000008,
 
+    // Indicates that key usage mapping represents a fallback mapping.
+    // Fallback mappings cannot be used to definitively determine whether a device
+    // supports a key code. For example, a HID device can report a key press
+    // as a HID usage code if it is not mapped to any linux key code in the kernel.
+    // However, we cannot know which HID usage codes that device supports from
+    // userspace through the evdev. We can use fallback mappings to convert HID
+    // usage codes to Android key codes without needing to know if a device can
+    // actually report the usage code.
+    POLICY_FLAG_FALLBACK_USAGE_MAPPING = 0x00000010,
+
     POLICY_FLAG_RAW_MASK = 0x0000ffff,
 
 #ifdef __linux__
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 038764b..8a57f92 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1227,7 +1227,7 @@
         flags |= ISurfaceComposer::eEarlyWakeupEnd;
     }
 
-    sp<IBinder> applyToken = mApplyToken ? mApplyToken : sApplyToken;
+    sp<IBinder> applyToken = mApplyToken ? mApplyToken : getDefaultApplyToken();
 
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
     sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,
@@ -1249,11 +1249,15 @@
 
 sp<IBinder> SurfaceComposerClient::Transaction::sApplyToken = new BBinder();
 
+std::mutex SurfaceComposerClient::Transaction::sApplyTokenMutex;
+
 sp<IBinder> SurfaceComposerClient::Transaction::getDefaultApplyToken() {
+    std::scoped_lock lock{sApplyTokenMutex};
     return sApplyToken;
 }
 
 void SurfaceComposerClient::Transaction::setDefaultApplyToken(sp<IBinder> applyToken) {
+    std::scoped_lock lock{sApplyTokenMutex};
     sApplyToken = applyToken;
 }
 
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 42e3c16..26b1fbd 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -422,6 +422,7 @@
     class Transaction : public Parcelable {
     private:
         static sp<IBinder> sApplyToken;
+        static std::mutex sApplyTokenMutex;
         void releaseBufferIfOverwriting(const layer_state_t& state);
         static void mergeFrameTimelineInfo(FrameTimelineInfo& t, const FrameTimelineInfo& other);
 
diff --git a/libs/input/InputEventLabels.cpp b/libs/input/InputEventLabels.cpp
index c218e1e..0e627e5 100644
--- a/libs/input/InputEventLabels.cpp
+++ b/libs/input/InputEventLabels.cpp
@@ -430,7 +430,8 @@
     DEFINE_FLAG(VIRTUAL), \
     DEFINE_FLAG(FUNCTION), \
     DEFINE_FLAG(GESTURE), \
-    DEFINE_FLAG(WAKE)
+    DEFINE_FLAG(WAKE), \
+    DEFINE_FLAG(FALLBACK_USAGE_MAPPING)
 
 // clang-format on
 
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index ddc9ea4..3c1ae3e 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -250,7 +250,7 @@
 std::vector<int32_t> KeyLayoutMap::findUsageCodesForKey(int32_t keyCode) const {
     std::vector<int32_t> usageCodes;
     for (const auto& [usageCode, key] : mKeysByUsageCode) {
-        if (keyCode == key.keyCode) {
+        if (keyCode == key.keyCode && !(key.flags & POLICY_FLAG_FALLBACK_USAGE_MAPPING)) {
             usageCodes.push_back(usageCode);
         }
     }
diff --git a/libs/input/tests/InputDevice_test.cpp b/libs/input/tests/InputDevice_test.cpp
index a0ec6ad..fe5490c 100644
--- a/libs/input/tests/InputDevice_test.cpp
+++ b/libs/input/tests/InputDevice_test.cpp
@@ -167,6 +167,41 @@
     ASSERT_FALSE(ret.ok()) << "Should not be able to load KeyLayout at " << klPath;
 }
 
+TEST(InputDeviceKeyLayoutTest, HidUsageCodesFallbackMapping) {
+    std::string klPath = base::GetExecutableDirectory() + "/data/hid_fallback_mapping.kl";
+    base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(klPath);
+    ASSERT_TRUE(ret.ok()) << "Unable to load KeyLayout at " << klPath;
+    const std::shared_ptr<KeyLayoutMap>& keyLayoutMap = *ret;
+
+    static constexpr std::array<int32_t, 5> hidUsageCodesWithoutFallback = {0x0c0067, 0x0c0070,
+                                                                            0x0c006F, 0x0c0079,
+                                                                            0x0c007A};
+    for (int32_t hidUsageCode : hidUsageCodesWithoutFallback) {
+        int32_t outKeyCode;
+        uint32_t outFlags;
+        keyLayoutMap->mapKey(0, hidUsageCode, &outKeyCode, &outFlags);
+        ASSERT_FALSE(outFlags & POLICY_FLAG_FALLBACK_USAGE_MAPPING)
+                << "HID usage code should not be marked as fallback";
+        std::vector<int32_t> usageCodes = keyLayoutMap->findUsageCodesForKey(outKeyCode);
+        ASSERT_NE(std::find(usageCodes.begin(), usageCodes.end(), hidUsageCode), usageCodes.end())
+                << "Fallback usage code should be mapped to key";
+    }
+
+    static constexpr std::array<int32_t, 6> hidUsageCodesWithFallback = {0x0c007C, 0x0c0173,
+                                                                         0x0c019C, 0x0c01A2,
+                                                                         0x0d0044, 0x0d005a};
+    for (int32_t hidUsageCode : hidUsageCodesWithFallback) {
+        int32_t outKeyCode;
+        uint32_t outFlags;
+        keyLayoutMap->mapKey(0, hidUsageCode, &outKeyCode, &outFlags);
+        ASSERT_TRUE(outFlags & POLICY_FLAG_FALLBACK_USAGE_MAPPING)
+                << "HID usage code should be marked as fallback";
+        std::vector<int32_t> usageCodes = keyLayoutMap->findUsageCodesForKey(outKeyCode);
+        ASSERT_EQ(std::find(usageCodes.begin(), usageCodes.end(), hidUsageCode), usageCodes.end())
+                << "Fallback usage code should not be mapped to key";
+    }
+}
+
 TEST(InputDeviceKeyLayoutTest, DoesNotLoadWhenRequiredKernelConfigIsMissing) {
 #if !defined(__ANDROID__)
     GTEST_SKIP() << "Can't check kernel configs on host";
diff --git a/libs/input/tests/data/hid_fallback_mapping.kl b/libs/input/tests/data/hid_fallback_mapping.kl
new file mode 100644
index 0000000..b4ca9ef
--- /dev/null
+++ b/libs/input/tests/data/hid_fallback_mapping.kl
@@ -0,0 +1,32 @@
+# Copyright 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# test key layout file for InputDeviceKeyMapTest#HidUsageCodesUseFallbackMapping
+#
+
+# Keys defined by HID usages without fallback mapping flag
+key usage 0x0c0067 WINDOW
+key usage 0x0c006F BRIGHTNESS_UP
+key usage 0x0c0070 BRIGHTNESS_DOWN
+key usage 0x0c0079 KEYBOARD_BACKLIGHT_UP
+key usage 0x0c007A KEYBOARD_BACKLIGHT_DOWN
+
+# Keys defined by HID usages with fallback mapping flag
+key usage 0x0c007C KEYBOARD_BACKLIGHT_TOGGLE FALLBACK_USAGE_MAPPING
+key usage 0x0c0173 MEDIA_AUDIO_TRACK         FALLBACK_USAGE_MAPPING
+key usage 0x0c019C PROFILE_SWITCH            FALLBACK_USAGE_MAPPING
+key usage 0x0c01A2 ALL_APPS                  FALLBACK_USAGE_MAPPING
+key usage 0x0d0044 STYLUS_BUTTON_PRIMARY     FALLBACK_USAGE_MAPPING
+key usage 0x0d005a STYLUS_BUTTON_SECONDARY   FALLBACK_USAGE_MAPPING
\ No newline at end of file
diff --git a/libs/renderengine/tests/RenderEngineThreadedTest.cpp b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
index 475dc15..7289fe7 100644
--- a/libs/renderengine/tests/RenderEngineThreadedTest.cpp
+++ b/libs/renderengine/tests/RenderEngineThreadedTest.cpp
@@ -98,7 +98,6 @@
 }
 
 TEST_F(RenderEngineThreadedTest, PostRenderCleanup_skipped) {
-    EXPECT_CALL(*mRenderEngine, canSkipPostRenderCleanup()).WillOnce(Return(true));
     EXPECT_CALL(*mRenderEngine, cleanupPostRender()).Times(0);
     mThreadedRE->cleanupPostRender();
 
@@ -107,8 +106,25 @@
 }
 
 TEST_F(RenderEngineThreadedTest, PostRenderCleanup_notSkipped) {
-    EXPECT_CALL(*mRenderEngine, canSkipPostRenderCleanup()).WillOnce(Return(false));
+    renderengine::DisplaySettings settings;
+    std::vector<renderengine::LayerSettings> layers;
+    std::shared_ptr<renderengine::ExternalTexture> buffer = std::make_shared<
+            renderengine::impl::
+                    ExternalTexture>(sp<GraphicBuffer>::make(), *mRenderEngine,
+                                     renderengine::impl::ExternalTexture::Usage::READABLE |
+                                             renderengine::impl::ExternalTexture::Usage::WRITEABLE);
+    base::unique_fd bufferFence;
+
+    EXPECT_CALL(*mRenderEngine, useProtectedContext(false));
+    EXPECT_CALL(*mRenderEngine, drawLayersInternal)
+        .WillOnce([&](const std::shared_ptr<std::promise<FenceResult>>&& resultPromise,
+                          const renderengine::DisplaySettings&,
+                          const std::vector<renderengine::LayerSettings>&,
+                          const std::shared_ptr<renderengine::ExternalTexture>&,
+                          base::unique_fd&&) { resultPromise->set_value(Fence::NO_FENCE); });
     EXPECT_CALL(*mRenderEngine, cleanupPostRender()).WillOnce(Return());
+    ftl::Future<FenceResult> future =
+            mThreadedRE->drawLayers(settings, layers, buffer, std::move(bufferFence));
     mThreadedRE->cleanupPostRender();
 
     // call ANY synchronous function to ensure that cleanupPostRender has completed.
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.cpp b/libs/renderengine/threaded/RenderEngineThreaded.cpp
index 2cb66cb..786a6fe 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.cpp
+++ b/libs/renderengine/threaded/RenderEngineThreaded.cpp
@@ -231,13 +231,13 @@
             ATRACE_NAME("REThreaded::cleanupPostRender");
             instance.cleanupPostRender();
         });
+        mNeedsPostRenderCleanup = false;
     }
     mCondition.notify_one();
 }
 
 bool RenderEngineThreaded::canSkipPostRenderCleanup() const {
-    waitUntilInitialized();
-    return mRenderEngine->canSkipPostRenderCleanup();
+    return !mNeedsPostRenderCleanup;
 }
 
 void RenderEngineThreaded::drawLayersInternal(
@@ -257,6 +257,7 @@
     int fd = bufferFence.release();
     {
         std::lock_guard lock(mThreadMutex);
+        mNeedsPostRenderCleanup = true;
         mFunctionCalls.push(
                 [resultPromise, display, layers, buffer, fd](renderengine::RenderEngine& instance) {
                     ATRACE_NAME("REThreaded::drawLayers");
diff --git a/libs/renderengine/threaded/RenderEngineThreaded.h b/libs/renderengine/threaded/RenderEngineThreaded.h
index 43ec011..1093f5f 100644
--- a/libs/renderengine/threaded/RenderEngineThreaded.h
+++ b/libs/renderengine/threaded/RenderEngineThreaded.h
@@ -89,6 +89,7 @@
     mutable std::mutex mThreadMutex;
     std::thread mThread GUARDED_BY(mThreadMutex);
     std::atomic<bool> mRunning = true;
+    std::atomic<bool> mNeedsPostRenderCleanup = false;
 
     using Work = std::function<void(renderengine::RenderEngine&)>;
     mutable std::queue<Work> mFunctionCalls GUARDED_BY(mThreadMutex);
diff --git a/services/inputflinger/dispatcher/Connection.cpp b/services/inputflinger/dispatcher/Connection.cpp
index ed95de7..f304712 100644
--- a/services/inputflinger/dispatcher/Connection.cpp
+++ b/services/inputflinger/dispatcher/Connection.cpp
@@ -38,13 +38,4 @@
     return "?";
 }
 
-std::deque<DispatchEntry*>::iterator Connection::findWaitQueueEntry(uint32_t seq) {
-    for (std::deque<DispatchEntry*>::iterator it = waitQueue.begin(); it != waitQueue.end(); it++) {
-        if ((*it)->seq == seq) {
-            return it;
-        }
-    }
-    return waitQueue.end();
-}
-
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/Connection.h b/services/inputflinger/dispatcher/Connection.h
index 2929d61..c17baea 100644
--- a/services/inputflinger/dispatcher/Connection.h
+++ b/services/inputflinger/dispatcher/Connection.h
@@ -53,11 +53,11 @@
     bool responsive = true;
 
     // Queue of events that need to be published to the connection.
-    std::deque<DispatchEntry*> outboundQueue;
+    std::deque<std::unique_ptr<DispatchEntry>> outboundQueue;
 
     // Queue of events that have been published to the connection but that have not
     // yet received a "finished" response from the application.
-    std::deque<DispatchEntry*> waitQueue;
+    std::deque<std::unique_ptr<DispatchEntry>> waitQueue;
 
     Connection(const std::shared_ptr<InputChannel>& inputChannel, bool monitor,
                const IdGenerator& idGenerator);
@@ -65,8 +65,6 @@
     inline const std::string getInputChannelName() const { return inputChannel->getName(); }
 
     const std::string getWindowName() const;
-
-    std::deque<DispatchEntry*>::iterator findWaitQueueEntry(uint32_t seq);
 };
 
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index dd4aab8..98e2507 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -226,7 +226,7 @@
     const uint32_t seq; // unique sequence number, never 0
 
     std::shared_ptr<EventEntry> eventEntry; // the event to dispatch
-    ftl::Flags<InputTarget::Flags> targetFlags;
+    const ftl::Flags<InputTarget::Flags> targetFlags;
     ui::Transform transform;
     ui::Transform rawTransform;
     float globalScaleFactor;
@@ -244,6 +244,8 @@
     DispatchEntry(std::shared_ptr<EventEntry> eventEntry,
                   ftl::Flags<InputTarget::Flags> targetFlags, const ui::Transform& transform,
                   const ui::Transform& rawTransform, float globalScaleFactor);
+    DispatchEntry(const DispatchEntry&) = delete;
+    DispatchEntry& operator=(const DispatchEntry&) = delete;
 
     inline bool hasForegroundTarget() const {
         return targetFlags.test(InputTarget::Flags::FOREGROUND);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 8e20eaf..4251682 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -271,7 +271,8 @@
     return dump;
 }
 
-std::string dumpQueue(const std::deque<DispatchEntry*>& queue, nsecs_t currentTime) {
+std::string dumpQueue(const std::deque<std::unique_ptr<DispatchEntry>>& queue,
+                      nsecs_t currentTime) {
     constexpr size_t maxEntries = 50; // max events to print
     constexpr size_t skipBegin = maxEntries / 2;
     const size_t skipEnd = queue.size() - maxEntries / 2;
@@ -492,8 +493,8 @@
  */
 bool isConnectionResponsive(const Connection& connection) {
     const nsecs_t currentTime = now();
-    for (const DispatchEntry* entry : connection.waitQueue) {
-        if (entry->timeoutTime < currentTime) {
+    for (const auto& dispatchEntry : connection.waitQueue) {
+        if (dispatchEntry->timeoutTime < currentTime) {
             return false;
         }
     }
@@ -3415,7 +3416,7 @@
     }
 
     // Enqueue the dispatch entry.
-    connection->outboundQueue.push_back(dispatchEntry.release());
+    connection->outboundQueue.emplace_back(std::move(dispatchEntry));
     traceOutboundQueueLength(*connection);
 }
 
@@ -3584,7 +3585,7 @@
     }
 
     while (connection->status == Connection::Status::NORMAL && !connection->outboundQueue.empty()) {
-        DispatchEntry* dispatchEntry = connection->outboundQueue.front();
+        std::unique_ptr<DispatchEntry>& dispatchEntry = connection->outboundQueue.front();
         dispatchEntry->deliveryTime = currentTime;
         const std::chrono::nanoseconds timeout = getDispatchingTimeoutLocked(connection);
         dispatchEntry->timeoutTime = currentTime + timeout.count();
@@ -3699,14 +3700,12 @@
         }
 
         // Re-enqueue the event on the wait queue.
-        connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
-                                                    connection->outboundQueue.end(),
-                                                    dispatchEntry));
+        const nsecs_t timeoutTime = dispatchEntry->timeoutTime;
+        connection->waitQueue.emplace_back(std::move(dispatchEntry));
+        connection->outboundQueue.erase(connection->outboundQueue.begin());
         traceOutboundQueueLength(*connection);
-        connection->waitQueue.push_back(dispatchEntry);
         if (connection->responsive) {
-            mAnrTracker.insert(dispatchEntry->timeoutTime,
-                               connection->inputChannel->getConnectionToken());
+            mAnrTracker.insert(timeoutTime, connection->inputChannel->getConnectionToken());
         }
         traceWaitQueueLength(*connection);
     }
@@ -3805,19 +3804,17 @@
     }
 }
 
-void InputDispatcher::drainDispatchQueue(std::deque<DispatchEntry*>& queue) {
+void InputDispatcher::drainDispatchQueue(std::deque<std::unique_ptr<DispatchEntry>>& queue) {
     while (!queue.empty()) {
-        DispatchEntry* dispatchEntry = queue.front();
+        releaseDispatchEntry(std::move(queue.front()));
         queue.pop_front();
-        releaseDispatchEntry(dispatchEntry);
     }
 }
 
-void InputDispatcher::releaseDispatchEntry(DispatchEntry* dispatchEntry) {
+void InputDispatcher::releaseDispatchEntry(std::unique_ptr<DispatchEntry> dispatchEntry) {
     if (dispatchEntry->hasForegroundTarget()) {
         decrementPendingForegroundDispatches(*(dispatchEntry->eventEntry));
     }
-    delete dispatchEntry;
 }
 
 int InputDispatcher::handleReceiveCallback(int events, sp<IBinder> connectionToken) {
@@ -6065,43 +6062,52 @@
                                                      uint32_t seq, bool handled,
                                                      nsecs_t consumeTime) {
     // Handle post-event policy actions.
-    std::deque<DispatchEntry*>::iterator dispatchEntryIt = connection->findWaitQueueEntry(seq);
-    if (dispatchEntryIt == connection->waitQueue.end()) {
-        return;
-    }
-    DispatchEntry* dispatchEntry = *dispatchEntryIt;
-    const nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
-    if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
-        ALOGI("%s spent %" PRId64 "ms processing %s", connection->getWindowName().c_str(),
-              ns2ms(eventDuration), dispatchEntry->eventEntry->getDescription().c_str());
-    }
-    if (shouldReportFinishedEvent(*dispatchEntry, *connection)) {
-        mLatencyTracker.trackFinishedEvent(dispatchEntry->eventEntry->id,
-                                           connection->inputChannel->getConnectionToken(),
-                                           dispatchEntry->deliveryTime, consumeTime, finishTime);
-    }
-
     bool restartEvent;
-    if (dispatchEntry->eventEntry->type == EventEntry::Type::KEY) {
-        KeyEntry& keyEntry = static_cast<KeyEntry&>(*(dispatchEntry->eventEntry));
-        restartEvent =
-                afterKeyEventLockedInterruptable(connection, dispatchEntry, keyEntry, handled);
-    } else if (dispatchEntry->eventEntry->type == EventEntry::Type::MOTION) {
-        MotionEntry& motionEntry = static_cast<MotionEntry&>(*(dispatchEntry->eventEntry));
-        restartEvent = afterMotionEventLockedInterruptable(connection, dispatchEntry, motionEntry,
-                                                           handled);
-    } else {
-        restartEvent = false;
-    }
+
+    { // Start critical section
+        auto dispatchEntryIt =
+                std::find_if(connection->waitQueue.begin(), connection->waitQueue.end(),
+                             [seq](auto& e) { return e->seq == seq; });
+        if (dispatchEntryIt == connection->waitQueue.end()) {
+            return;
+        }
+
+        DispatchEntry& dispatchEntry = **dispatchEntryIt;
+
+        const nsecs_t eventDuration = finishTime - dispatchEntry.deliveryTime;
+        if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
+            ALOGI("%s spent %" PRId64 "ms processing %s", connection->getWindowName().c_str(),
+                  ns2ms(eventDuration), dispatchEntry.eventEntry->getDescription().c_str());
+        }
+        if (shouldReportFinishedEvent(dispatchEntry, *connection)) {
+            mLatencyTracker.trackFinishedEvent(dispatchEntry.eventEntry->id,
+                                               connection->inputChannel->getConnectionToken(),
+                                               dispatchEntry.deliveryTime, consumeTime, finishTime);
+        }
+
+        if (dispatchEntry.eventEntry->type == EventEntry::Type::KEY) {
+            KeyEntry& keyEntry = static_cast<KeyEntry&>(*(dispatchEntry.eventEntry));
+            restartEvent =
+                    afterKeyEventLockedInterruptable(connection, dispatchEntry, keyEntry, handled);
+        } else if (dispatchEntry.eventEntry->type == EventEntry::Type::MOTION) {
+            MotionEntry& motionEntry = static_cast<MotionEntry&>(*(dispatchEntry.eventEntry));
+            restartEvent = afterMotionEventLockedInterruptable(connection, dispatchEntry,
+                                                               motionEntry, handled);
+        } else {
+            restartEvent = false;
+        }
+    } // End critical section: The -LockedInterruptable methods may have released the lock.
 
     // Dequeue the event and start the next cycle.
     // Because the lock might have been released, it is possible that the
     // contents of the wait queue to have been drained, so we need to double-check
     // a few things.
-    dispatchEntryIt = connection->findWaitQueueEntry(seq);
-    if (dispatchEntryIt != connection->waitQueue.end()) {
-        dispatchEntry = *dispatchEntryIt;
-        connection->waitQueue.erase(dispatchEntryIt);
+    auto entryIt = std::find_if(connection->waitQueue.begin(), connection->waitQueue.end(),
+                                [seq](auto& e) { return e->seq == seq; });
+    if (entryIt != connection->waitQueue.end()) {
+        std::unique_ptr<DispatchEntry> dispatchEntry = std::move(*entryIt);
+        connection->waitQueue.erase(entryIt);
+
         const sp<IBinder>& connectionToken = connection->inputChannel->getConnectionToken();
         mAnrTracker.erase(dispatchEntry->timeoutTime, connectionToken);
         if (!connection->responsive) {
@@ -6113,10 +6119,10 @@
         }
         traceWaitQueueLength(*connection);
         if (restartEvent && connection->status == Connection::Status::NORMAL) {
-            connection->outboundQueue.push_front(dispatchEntry);
+            connection->outboundQueue.emplace_front(std::move(dispatchEntry));
             traceOutboundQueueLength(*connection);
         } else {
-            releaseDispatchEntry(dispatchEntry);
+            releaseDispatchEntry(std::move(dispatchEntry));
         }
     }
 
@@ -6160,13 +6166,13 @@
      * processes the events linearly. So providing information about the oldest entry seems to be
      * most useful.
      */
-    DispatchEntry* oldestEntry = *connection->waitQueue.begin();
-    const nsecs_t currentWait = now() - oldestEntry->deliveryTime;
+    DispatchEntry& oldestEntry = *connection->waitQueue.front();
+    const nsecs_t currentWait = now() - oldestEntry.deliveryTime;
     std::string reason =
             android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s",
                                         connection->inputChannel->getName().c_str(),
                                         ns2ms(currentWait),
-                                        oldestEntry->eventEntry->getDescription().c_str());
+                                        oldestEntry.eventEntry->getDescription().c_str());
     sp<IBinder> connectionToken = connection->inputChannel->getConnectionToken();
     updateLastAnrStateLocked(getWindowHandleLocked(connectionToken), reason);
 
@@ -6303,7 +6309,7 @@
 }
 
 bool InputDispatcher::afterKeyEventLockedInterruptable(
-        const std::shared_ptr<Connection>& connection, DispatchEntry* dispatchEntry,
+        const std::shared_ptr<Connection>& connection, DispatchEntry& dispatchEntry,
         KeyEntry& keyEntry, bool handled) {
     if (keyEntry.flags & AKEY_EVENT_FLAG_FALLBACK) {
         if (!handled) {
@@ -6321,7 +6327,7 @@
         connection->inputState.removeFallbackKey(originalKeyCode);
     }
 
-    if (handled || !dispatchEntry->hasForegroundTarget()) {
+    if (handled || !dispatchEntry.hasForegroundTarget()) {
         // If the application handles the original key for which we previously
         // generated a fallback or if the window is not a foreground window,
         // then cancel the associated fallback key, if any.
@@ -6488,7 +6494,7 @@
 }
 
 bool InputDispatcher::afterMotionEventLockedInterruptable(
-        const std::shared_ptr<Connection>& connection, DispatchEntry* dispatchEntry,
+        const std::shared_ptr<Connection>& connection, DispatchEntry& dispatchEntry,
         MotionEntry& motionEntry, bool handled) {
     return false;
 }
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 67705b9..62e2d58 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -598,8 +598,8 @@
     void abortBrokenDispatchCycleLocked(nsecs_t currentTime,
                                         const std::shared_ptr<Connection>& connection, bool notify)
             REQUIRES(mLock);
-    void drainDispatchQueue(std::deque<DispatchEntry*>& queue);
-    void releaseDispatchEntry(DispatchEntry* dispatchEntry);
+    void drainDispatchQueue(std::deque<std::unique_ptr<DispatchEntry>>& queue);
+    void releaseDispatchEntry(std::unique_ptr<DispatchEntry> dispatchEntry);
     int handleReceiveCallback(int events, sp<IBinder> connectionToken);
     // The action sent should only be of type AMOTION_EVENT_*
     void dispatchPointerDownOutsideFocus(uint32_t source, int32_t action,
@@ -664,10 +664,10 @@
             REQUIRES(mLock);
     std::map<int32_t /*displayId*/, InputVerifier> mVerifiersByDisplay;
     bool afterKeyEventLockedInterruptable(const std::shared_ptr<Connection>& connection,
-                                          DispatchEntry* dispatchEntry, KeyEntry& keyEntry,
+                                          DispatchEntry& dispatchEntry, KeyEntry& keyEntry,
                                           bool handled) REQUIRES(mLock);
     bool afterMotionEventLockedInterruptable(const std::shared_ptr<Connection>& connection,
-                                             DispatchEntry* dispatchEntry, MotionEntry& motionEntry,
+                                             DispatchEntry& dispatchEntry, MotionEntry& motionEntry,
                                              bool handled) REQUIRES(mLock);
 
     // Find touched state and touched window by token.
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index d059f8f..c073579 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -74,6 +74,7 @@
           filename_(filename),
           dlhandle_(nullptr),
           native_bridge_(false),
+          opened_with_native_loader_(false),
           refcount_(0) {}
 
     LayerLibrary(LayerLibrary&& other) noexcept
@@ -81,6 +82,7 @@
           filename_(std::move(other.filename_)),
           dlhandle_(other.dlhandle_),
           native_bridge_(other.native_bridge_),
+          opened_with_native_loader_(other.opened_with_native_loader_),
           refcount_(other.refcount_) {
         other.dlhandle_ = nullptr;
         other.refcount_ = 0;
@@ -120,6 +122,7 @@
     std::mutex mutex_;
     void* dlhandle_;
     bool native_bridge_;
+    bool opened_with_native_loader_;
     size_t refcount_;
 };
 
@@ -136,7 +139,7 @@
         if (app_namespace &&
             !android::base::StartsWith(path_, kSystemLayerLibraryDir)) {
             char* error_msg = nullptr;
-            dlhandle_ = OpenNativeLibraryInNamespace(
+            dlhandle_ = android::OpenNativeLibraryInNamespace(
                 app_namespace, path_.c_str(), &native_bridge_, &error_msg);
             if (!dlhandle_) {
                 ALOGE("failed to load layer library '%s': %s", path_.c_str(), error_msg);
@@ -144,14 +147,16 @@
                 refcount_ = 0;
                 return false;
             }
+            opened_with_native_loader_ = true;
         } else {
-          dlhandle_ = dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL);
+            dlhandle_ = dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL);
             if (!dlhandle_) {
                 ALOGE("failed to load layer library '%s': %s", path_.c_str(),
                       dlerror());
                 refcount_ = 0;
                 return false;
             }
+            opened_with_native_loader_ = false;
         }
     }
     return true;
@@ -161,14 +166,25 @@
     std::lock_guard<std::mutex> lock(mutex_);
     if (--refcount_ == 0) {
         ALOGV("closing layer library '%s'", path_.c_str());
-        char* error_msg = nullptr;
-        if (!android::CloseNativeLibrary(dlhandle_, native_bridge_, &error_msg)) {
-            ALOGE("failed to unload library '%s': %s", path_.c_str(), error_msg);
-            android::NativeLoaderFreeErrorMessage(error_msg);
-            refcount_++;
+        // we close the .so same way as we opened. It's importain, because
+        // android::CloseNativeLibrary lives in libnativeloader.so, which is
+        // not accessible for early loaded services like SurfaceFlinger
+        if (opened_with_native_loader_) {
+            char* error_msg = nullptr;
+            if (!android::CloseNativeLibrary(dlhandle_, native_bridge_, &error_msg)) {
+                ALOGE("failed to unload library '%s': %s", path_.c_str(), error_msg);
+                android::NativeLoaderFreeErrorMessage(error_msg);
+                refcount_++;
+                return;
+            }
         } else {
-           dlhandle_ = nullptr;
+            if (dlclose(dlhandle_) != 0) {
+                ALOGE("failed to unload library '%s': %s", path_.c_str(), dlerror());
+                refcount_++;
+                return;
+            }
         }
+        dlhandle_ = nullptr;
     }
 }