From f02ea24f60e9b383388db3d8623a92578c74f896 Mon Sep 17 00:00:00 2001 From: Kenneth Ford Date: Fri, 18 Aug 2023 19:28:18 +0000 Subject: Posts DeviceStateManager notifications to a handler Instead of showing the DeviceStateManager notifications synchronously while holding a lock, we post them to a handler. This should resolve any deadlock contentions that occur when showing a notification permission dialog, while holding the DeviceStateManagerService lock. Bug: 292444664 Test: DeviceStateNotificationControllerTest Change-Id: I498d494852a04027ac0b47a9e179003f04c028ca --- .../devicestate/DeviceStateNotificationController.java | 9 ++++++--- .../DeviceStateNotificationControllerTest.java | 17 ++++++++++++++++- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/devicestate/DeviceStateNotificationController.java b/services/core/java/com/android/server/devicestate/DeviceStateNotificationController.java index f4c84e7fe464..f9aefd0535d0 100644 --- a/services/core/java/com/android/server/devicestate/DeviceStateNotificationController.java +++ b/services/core/java/com/android/server/devicestate/DeviceStateNotificationController.java @@ -109,6 +109,7 @@ class DeviceStateNotificationController extends BroadcastReceiver { .setPackage(mContext.getPackageName()); final PendingIntent pendingIntent = PendingIntent.getBroadcast( mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE); + showNotification( info.name, info.activeNotificationTitle, String.format(info.activeNotificationContent, requesterApplicationLabel), @@ -175,7 +176,7 @@ class DeviceStateNotificationController extends BroadcastReceiver { if (getNotificationInfos().get(state) == null) { return; } - mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID); + mHandler.post(() -> mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID)); } @Override @@ -219,8 +220,10 @@ class DeviceStateNotificationController extends BroadcastReceiver { builder.addAction(action); } - mNotificationManager.createNotificationChannel(channel); - mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build()); + mHandler.post(() -> { + mNotificationManager.createNotificationChannel(channel); + mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build()); + }); } private SparseArray getNotificationInfos() { diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateNotificationControllerTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateNotificationControllerTest.java index 728606f9f628..bb0de032d987 100644 --- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateNotificationControllerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateNotificationControllerTest.java @@ -33,6 +33,8 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.platform.test.annotations.Presubmit; import android.util.SparseArray; @@ -89,11 +91,12 @@ public class DeviceStateNotificationControllerTest { @Before public void setup() throws Exception { Context context = InstrumentationRegistry.getInstrumentation().getContext(); - Handler handler = mock(Handler.class); PackageManager packageManager = mock(PackageManager.class); Runnable cancelStateRunnable = mock(Runnable.class); ApplicationInfo applicationInfo = mock(ApplicationInfo.class); + Handler handler = new DeviceStateNotificationControllerTestHandler(Looper.getMainLooper()); + final SparseArray notificationInfos = new SparseArray<>(); notificationInfos.put(STATE_WITH_ACTIVE_NOTIFICATION, @@ -259,4 +262,16 @@ public class DeviceStateNotificationControllerTest { assertEquals(Locale.ITALY, mNotificationInfoProvider.getCachedLocale()); clearInvocations(mNotificationInfoProvider); } + + private static class DeviceStateNotificationControllerTestHandler extends Handler { + DeviceStateNotificationControllerTestHandler(Looper looper) { + super(looper); + } + + @Override + public boolean sendMessageAtTime(Message msg, long uptimeMillis) { + msg.getCallback().run(); + return true; + } + } } -- cgit v1.2.3-59-g8ed1b