From 2ec961dad3eae53c7d3d674cc0540d1f5add6a26 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Fri, 27 Jul 2018 16:48:37 -0700 Subject: Send widget registration broadcasts before BOOT_COMPLETE Widget presence in the home app is important for usability, but it depends on a broadcast-based handshake at boot time. This handshake occurring after the BOOT_COMPLETED broadcast was initiated means that in practice widgets may not become available for literal minutes following unlock, as it can take this long for the boot-complete broadcast to clear and let the systen proceed with dispatch of the widget handshakes. We address this by hoisting the widget setup broadcast to occur just *before* the boot-completed broadcast, rather than as part of general listener reaction to the global "this user has been unlocked" notification. Bug: 76154638 Test: manual (note broadcast ordering following boot) Change-Id: I7c1a9f7a84fee71f71d2dcd52362a29c2436b01d Merged-In: Ibd97268f995ec673f21d8f5df257041cf61a058d --- .../java/android/appwidget/AppWidgetManagerInternal.java | 12 +++++++++--- .../com/android/server/appwidget/AppWidgetService.java | 5 ----- .../android/server/appwidget/AppWidgetServiceImpl.java | 16 +++++++++++++--- .../core/java/com/android/server/am/UserController.java | 14 ++++++++++++-- 4 files changed, 34 insertions(+), 13 deletions(-) diff --git a/core/java/android/appwidget/AppWidgetManagerInternal.java b/core/java/android/appwidget/AppWidgetManagerInternal.java index 7ab3d8bdd857..5694ca860453 100644 --- a/core/java/android/appwidget/AppWidgetManagerInternal.java +++ b/core/java/android/appwidget/AppWidgetManagerInternal.java @@ -16,12 +16,9 @@ package android.appwidget; -import android.annotation.NonNull; import android.annotation.Nullable; import android.util.ArraySet; -import java.util.Set; - /** * App widget manager local system service interface. * @@ -36,4 +33,13 @@ public abstract class AppWidgetManagerInternal { * @return Whether the UID hosts widgets from the package. */ public abstract @Nullable ArraySet getHostedWidgetPackages(int uid); + + /** + * Execute the widget-related work of unlocking a user. This is intentionally + * invoked just before the boot-completed broadcast is issued, after + * the data-related work of unlock has completed. + * + * @param userId The user that is being unlocked. + */ + public abstract void unlockUser(int userId); } diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java index c9c7adc45697..f69b6387a605 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java @@ -47,11 +47,6 @@ public class AppWidgetService extends SystemService { } } - @Override - public void onUnlockUser(int userHandle) { - FgThread.getHandler().post(() -> mImpl.onUserUnlocked(userHandle)); - } - @Override public void onStopUser(int userHandle) { mImpl.onUserStopped(userHandle); diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index db8ad12cfdf8..b71d7a726b28 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -19,7 +19,6 @@ package com.android.server.appwidget; import static android.content.Context.KEYGUARD_SERVICE; import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; - import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; import android.annotation.UserIdInt; @@ -2697,7 +2696,12 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } - void onUserUnlocked(int userId) { + /** + * This does not use the usual onUserUnlocked() listener mechanism because it is + * invoked at a choreographed point in the middle of the user unlock sequence, + * before the boot-completed broadcast is issued and the listeners notified. + */ + void handleUserUnlocked(int userId) { if (isProfileWithLockedParent(userId)) { return; } @@ -2734,7 +2738,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } } } - Slog.i(TAG, "Async processing of onUserUnlocked u" + userId + " took " + Slog.i(TAG, "Processing of handleUserUnlocked u" + userId + " took " + (SystemClock.elapsedRealtime() - time) + " ms"); } @@ -4801,5 +4805,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku return widgetPackages; } } + + @Override + public void unlockUser(int userId) { + handleUserUnlocked(userId); + } + } } diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 18c095725b09..415a822e3160 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -24,7 +24,6 @@ import static android.app.ActivityManager.USER_OP_IS_CURRENT; import static android.app.ActivityManager.USER_OP_SUCCESS; import static android.os.Process.SHELL_UID; import static android.os.Process.SYSTEM_UID; - import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; @@ -48,6 +47,7 @@ import android.app.IStopUserCallback; import android.app.IUserSwitchObserver; import android.app.KeyguardManager; import android.app.usage.UsageEvents; +import android.appwidget.AppWidgetManagerInternal; import android.content.Context; import android.content.IIntentReceiver; import android.content.Intent; @@ -87,8 +87,8 @@ import android.util.SparseArray; import android.util.SparseIntArray; import android.util.TimingsTraceLog; import android.util.proto.ProtoOutputStream; - import android.view.Window; + import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -533,6 +533,9 @@ 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); // Do not report secondary users, runtime restarts or first boot/upgrade if (userId == UserHandle.USER_SYSTEM @@ -2173,6 +2176,13 @@ class UserController implements Handler.Callback { } } + void startUserWidgets(int userId) { + AppWidgetManagerInternal awm = LocalServices.getService(AppWidgetManagerInternal.class); + if (awm != null) { + awm.unlockUser(userId); + } + } + void updateUserConfiguration() { synchronized (mService) { mService.updateUserConfigurationLocked(); -- cgit v1.2.3-59-g8ed1b