From 74e5b7dea45c76a7acc87c4282ffa7ee6e1cb431 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Fri, 7 Jun 2019 17:55:43 -0700 Subject: [PATCH] Correct sequencing of widget vs boot-complete broadcasts Past fixes to lock-management issues inadvertently altered the intended sequencing of the widget-lifecyle and boot-completed broadcasts. It's correct now, with the order guaranteed by thread-of-issuance affinity. Along the way, add the one missing bit of state reporting to the plaintext broadcast queue dumpsys infrastructure. Fixes: 131409711 Test: manual - boot and unlock device when widgets are being hosted by the home app, and observe the timings & broadcast history. Change-Id: Iaee75d4f9f85565eab95976633460fc0abd0fa16 --- .../server/am/BroadcastDispatcher.java | 8 +++++ .../com/android/server/am/UserController.java | 34 ++++++++++++------- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/services/core/java/com/android/server/am/BroadcastDispatcher.java b/services/core/java/com/android/server/am/BroadcastDispatcher.java index d029482ac5288..f8a3d1eefd50a 100644 --- a/services/core/java/com/android/server/am/BroadcastDispatcher.java +++ b/services/core/java/com/android/server/am/BroadcastDispatcher.java @@ -725,6 +725,14 @@ public class BroadcastDispatcher { final Dumper dumper = new Dumper(pw, queueName, dumpPackage, sdf); boolean printed = false; + dumper.setHeading("Currently in flight"); + dumper.setLabel("In-Flight Ordered Broadcast"); + if (mCurrentBroadcast != null) { + dumper.dump(mCurrentBroadcast); + } else { + pw.println(" (null)"); + } + dumper.setHeading("Active ordered broadcasts"); dumper.setLabel("Active Ordered Broadcast"); for (Deferrals d : mAlarmBroadcasts) { diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 2399d0525cc4d..b311233694ce3 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -559,7 +559,7 @@ class UserController implements Handler.Callback { // Spin up app widgets prior to boot-complete, so they can be ready promptly mInjector.startUserWidgets(userId); - Slog.i(TAG, "Sending BOOT_COMPLETE user #" + userId); + Slog.i(TAG, "Posting BOOT_COMPLETED user #" + userId); // Do not report secondary users, runtime restarts or first boot/upgrade if (userId == UserHandle.USER_SYSTEM && !mInjector.isRuntimeRestarted() && !mInjector.isFirstBootOrUpgrade()) { @@ -572,18 +572,26 @@ class UserController implements Handler.Callback { bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND | Intent.FLAG_RECEIVER_OFFLOAD); - mInjector.broadcastIntent(bootIntent, null, new IIntentReceiver.Stub() { - @Override - public void performReceive(Intent intent, int resultCode, String data, - Bundle extras, boolean ordered, boolean sticky, int sendingUser) - throws RemoteException { - Slog.i(UserController.TAG, "Finished processing BOOT_COMPLETED for u" + userId); - mBootCompleted = true; - } - }, 0, null, null, - new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED}, - AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, - Binder.getCallingUid(), Binder.getCallingPid(), userId); + // Widget broadcasts are outbound via FgThread, so to guarantee sequencing + // we also send the boot_completed broadcast from that thread. + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); + FgThread.getHandler().post(() -> { + mInjector.broadcastIntent(bootIntent, null, + new IIntentReceiver.Stub() { + @Override + public void performReceive(Intent intent, int resultCode, String data, + Bundle extras, boolean ordered, boolean sticky, int sendingUser) + throws RemoteException { + Slog.i(UserController.TAG, "Finished processing BOOT_COMPLETED for u" + + userId); + mBootCompleted = true; + } + }, 0, null, null, + new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED}, + AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, + callingUid, callingPid, userId); + }); } int restartUser(final int userId, final boolean foreground) {