Use unordered_map for connections

Currently, keyedvector is used for keeping track of connections by file
descriptors. Instead, use supported api std::unordered_map.
Also, no longer remove raw indices into the map, because that's
implementation detail of map that should not be user-facing.

Bug: 70668286
Test: SANITIZE_TARGET=hwaddress atest libinput_tests inputflinger_tests
Change-Id: Id31b0002a7ff2310dcc506f834722b1e69a05571
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 1eb979e..c516ab7 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -262,12 +262,32 @@
  * if the entry is not found.
  * Also useful when the entries are sp<>. If an entry is not found, nullptr is returned.
  */
-template <typename T, typename U>
-static T getValueByKey(const std::unordered_map<U, T>& map, U key) {
+template <typename K, typename V>
+static V getValueByKey(const std::unordered_map<K, V>& map, K key) {
     auto it = map.find(key);
-    return it != map.end() ? it->second : T{};
+    return it != map.end() ? it->second : V{};
 }
 
+/**
+ * Find the entry in std::unordered_map by value, and remove it.
+ * If more than one entry has the same value, then all matching
+ * key-value pairs will be removed.
+ *
+ * Return true if at least one value has been removed.
+ */
+template <typename K, typename V>
+static bool removeByValue(std::unordered_map<K, V>& map, const V& value) {
+    bool removed = false;
+    for (auto it = map.begin(); it != map.end();) {
+        if (it->second == value) {
+            it = map.erase(it);
+            removed = true;
+        } else {
+            it++;
+        }
+    }
+    return removed;
+}
 
 // --- InputDispatcher ---
 
@@ -300,8 +320,9 @@
         drainInboundQueueLocked();
     }
 
-    while (mConnectionsByFd.size() != 0) {
-        unregisterInputChannel(mConnectionsByFd.valueAt(0)->inputChannel);
+    while (!mConnectionsByFd.empty()) {
+        sp<Connection> connection = mConnectionsByFd.begin()->second;
+        unregisterInputChannel(connection->inputChannel);
     }
 }
 
@@ -1072,9 +1093,8 @@
     pokeUserActivityLocked(eventEntry);
 
     for (const InputTarget& inputTarget : inputTargets) {
-        ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
-        if (connectionIndex >= 0) {
-            sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
+        sp<Connection> connection = getConnectionLocked(inputTarget.inputChannel);
+        if (connection != nullptr) {
             prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
         } else {
 #if DEBUG_FOCUS
@@ -1172,21 +1192,18 @@
         mInputTargetWaitTimeoutExpired = true;
 
         // Input state will not be realistic.  Mark it out of sync.
-        if (inputChannel.get()) {
-            ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
-            if (connectionIndex >= 0) {
-                sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
-                sp<IBinder> token = connection->inputChannel->getToken();
+        sp<Connection> connection = getConnectionLocked(inputChannel);
+        if (connection != nullptr) {
+            sp<IBinder> token = connection->inputChannel->getToken();
 
-                if (token != nullptr) {
-                    removeWindowByTokenLocked(token);
-                }
+            if (token != nullptr) {
+                removeWindowByTokenLocked(token);
+            }
 
-                if (connection->status == Connection::STATUS_NORMAL) {
-                    CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
-                            "application not responding");
-                    synthesizeCancelationEventsForConnectionLocked(connection, options);
-                }
+            if (connection->status == Connection::STATUS_NORMAL) {
+                CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
+                                           "application not responding");
+                synthesizeCancelationEventsForConnectionLocked(connection, options);
             }
         }
     }
@@ -1857,16 +1874,15 @@
     }
 
     // If the window's connection is not registered then keep waiting.
-    ssize_t connectionIndex = getConnectionIndexLocked(
-            getInputChannelLocked(windowHandle->getToken()));
-    if (connectionIndex < 0) {
+    sp<Connection> connection =
+            getConnectionLocked(getInputChannelLocked(windowHandle->getToken()));
+    if (connection == nullptr) {
         return StringPrintf("Waiting because the %s window's input channel is not "
                 "registered with the input dispatcher.  The window may be in the process "
                 "of being removed.", targetType);
     }
 
     // If the connection is dead then keep waiting.
-    sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
     if (connection->status != Connection::STATUS_NORMAL) {
         return StringPrintf("Waiting because the %s window's input connection is %s."
                 "The window may be in the process of being removed.", targetType,
@@ -2410,15 +2426,14 @@
     { // acquire lock
         std::scoped_lock _l(d->mLock);
 
-        ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);
-        if (connectionIndex < 0) {
+        if (d->mConnectionsByFd.find(fd) == d->mConnectionsByFd.end()) {
             ALOGE("Received spurious receive callback for unknown input channel.  "
                     "fd=%d, events=0x%x", fd, events);
             return 0; // remove the callback
         }
 
         bool notify;
-        sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);
+        sp<Connection> connection = d->mConnectionsByFd[fd];
         if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
             if (!(events & ALOOPER_EVENT_INPUT)) {
                 ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event.  "
@@ -2470,9 +2485,8 @@
 
 void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked (
         const CancelationOptions& options) {
-    for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
-        synthesizeCancelationEventsForConnectionLocked(
-                mConnectionsByFd.valueAt(i), options);
+    for (const auto& pair : mConnectionsByFd) {
+        synthesizeCancelationEventsForConnectionLocked(pair.second, options);
     }
 }
 
@@ -2495,11 +2509,12 @@
 
 void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
         const sp<InputChannel>& channel, const CancelationOptions& options) {
-    ssize_t index = getConnectionIndexLocked(channel);
-    if (index >= 0) {
-        synthesizeCancelationEventsForConnectionLocked(
-                mConnectionsByFd.valueAt(index), options);
+    sp<Connection> connection = getConnectionLocked(channel);
+    if (connection == nullptr) {
+        return;
     }
+
+    synthesizeCancelationEventsForConnectionLocked(connection, options);
 }
 
 void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
@@ -3586,15 +3601,11 @@
             return false;
         }
 
-
         sp<InputChannel> fromChannel = getInputChannelLocked(fromToken);
         sp<InputChannel> toChannel = getInputChannelLocked(toToken);
-        ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel);
-        ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel);
-        if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) {
-            sp<Connection> fromConnection = mConnectionsByFd.valueAt(fromConnectionIndex);
-            sp<Connection> toConnection = mConnectionsByFd.valueAt(toConnectionIndex);
-
+        sp<Connection> fromConnection = getConnectionLocked(fromChannel);
+        sp<Connection> toConnection = getConnectionLocked(toChannel);
+        if (fromConnection != nullptr && toConnection != nullptr) {
             fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
             CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
                     "transferring touch focus from this window to another window");
@@ -3815,16 +3826,16 @@
         dump += INDENT "ReplacedKeys: <empty>\n";
     }
 
-    if (!mConnectionsByFd.isEmpty()) {
+    if (!mConnectionsByFd.empty()) {
         dump += INDENT "Connections:\n";
-        for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
-            const sp<Connection>& connection = mConnectionsByFd.valueAt(i);
-            dump += StringPrintf(INDENT2 "%zu: channelName='%s', windowName='%s', "
-                    "status=%s, monitor=%s, inputPublisherBlocked=%s\n",
-                    i, connection->getInputChannelName().c_str(),
-                    connection->getWindowName().c_str(),
-                    connection->getStatusLabel(), toString(connection->monitor),
-                    toString(connection->inputPublisherBlocked));
+        for (const auto& pair : mConnectionsByFd) {
+            const sp<Connection>& connection = pair.second;
+            dump += StringPrintf(INDENT2 "%i: channelName='%s', windowName='%s', "
+                                         "status=%s, monitor=%s, inputPublisherBlocked=%s\n",
+                                 pair.first, connection->getInputChannelName().c_str(),
+                                 connection->getWindowName().c_str(), connection->getStatusLabel(),
+                                 toString(connection->monitor),
+                                 toString(connection->inputPublisherBlocked));
 
             if (!connection->outboundQueue.empty()) {
                 dump += StringPrintf(INDENT3 "OutboundQueue: length=%zu\n",
@@ -3893,8 +3904,8 @@
 
     { // acquire lock
         std::scoped_lock _l(mLock);
-
-        if (getConnectionIndexLocked(inputChannel) >= 0) {
+        sp<Connection> existingConnection = getConnectionLocked(inputChannel);
+        if (existingConnection != nullptr) {
             ALOGW("Attempted to register already registered input channel '%s'",
                     inputChannel->getName().c_str());
             return BAD_VALUE;
@@ -3903,7 +3914,7 @@
         sp<Connection> connection = new Connection(inputChannel, false /*monitor*/);
 
         int fd = inputChannel->getFd();
-        mConnectionsByFd.add(fd, connection);
+        mConnectionsByFd[fd] = connection;
         mInputChannelsByToken[inputChannel->getToken()] = inputChannel;
 
         mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
@@ -3932,7 +3943,7 @@
         sp<Connection> connection = new Connection(inputChannel, true /*monitor*/);
 
         const int fd = inputChannel->getFd();
-        mConnectionsByFd.add(fd, connection);
+        mConnectionsByFd[fd] = connection;
         mInputChannelsByToken[inputChannel->getToken()] = inputChannel;
 
         auto& monitorsByDisplay = isGestureMonitor
@@ -3970,16 +3981,15 @@
 
 status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& inputChannel,
         bool notify) {
-    ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
-    if (connectionIndex < 0) {
+    sp<Connection> connection = getConnectionLocked(inputChannel);
+    if (connection == nullptr) {
         ALOGW("Attempted to unregister already unregistered input channel '%s'",
                 inputChannel->getName().c_str());
         return BAD_VALUE;
     }
 
-    sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
-    mConnectionsByFd.removeItemsAt(connectionIndex);
-
+    const bool removed = removeByValue(mConnectionsByFd, connection);
+    ALOG_ASSERT(removed);
     mInputChannelsByToken.erase(inputChannel->getToken());
 
     if (connection->monitor) {
@@ -4079,19 +4089,20 @@
     return std::nullopt;
 }
 
-ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
+sp<InputDispatcher::Connection> InputDispatcher::getConnectionLocked(
+        const sp<InputChannel>& inputChannel) {
     if (inputChannel == nullptr) {
-        return -1;
+        return nullptr;
     }
 
-    for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
-        sp<Connection> connection = mConnectionsByFd.valueAt(i);
+    for (const auto& pair : mConnectionsByFd) {
+        sp<Connection> connection = pair.second;
         if (connection->inputChannel->getToken() == inputChannel->getToken()) {
-            return i;
+            return connection;
         }
     }
 
-    return -1;
+    return nullptr;
 }
 
 void InputDispatcher::onDispatchCycleFinishedLocked(