Invoke service connection consumer outside the object lock

The consumer may contain arbitrary operations which may
acquire the local lock again and lead to dead lock.

Currently forEachConnection is only called from
disconnectActivityFromServices which is very rare to be called
(activity destroyed without unbind service). So a local copy
should be fine.

Bug: 275277537
Test: atest ActivityRecordTests#testActivityServiceConnectionsHolder
Change-Id: If26a0cb9970cf5318cd0477adcc0fe07e98aaed9
This commit is contained in:
Riddle Hsu
2023-04-17 15:20:30 +08:00
parent 0bb91e1d18
commit 78fe2d8e42
2 changed files with 9 additions and 4 deletions

View File

@@ -99,13 +99,15 @@ public class ActivityServiceConnectionsHolder<T> {
}
public void forEachConnection(Consumer<T> consumer) {
final ArraySet<T> connections;
synchronized (mActivity) {
if (mConnections == null || mConnections.isEmpty()) {
return;
}
for (int i = mConnections.size() - 1; i >= 0; i--) {
consumer.accept(mConnections.valueAt(i));
}
connections = new ArraySet<>(mConnections);
}
for (int i = connections.size() - 1; i >= 0; i--) {
consumer.accept(connections.valueAt(i));
}
}

View File

@@ -2399,7 +2399,10 @@ public class ActivityRecordTests extends WindowTestsBase {
holder.addConnection(connection);
assertTrue(holder.isActivityVisible());
final int[] count = new int[1];
final Consumer<Object> c = conn -> count[0]++;
final Consumer<Object> c = conn -> {
count[0]++;
assertFalse(Thread.holdsLock(activity));
};
holder.forEachConnection(c);
assertEquals(1, count[0]);