diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java index e40f001f27d5b..933d2596aed8a 100644 --- a/services/core/java/com/android/server/SystemService.java +++ b/services/core/java/com/android/server/SystemService.java @@ -472,18 +472,6 @@ public abstract class SystemService { public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) { } - /** - * The {@link UserManager#isUserVisible() user visibility} changed. - * - *
This callback is called before the user starts or is switched to (or after it stops), when - * its visibility changed because of that action. - * - * @hide - */ - // NOTE: change visible to int if this method becomes a @SystemApi - public void onUserVisibilityChanged(@NonNull TargetUser user, boolean visible) { - } - /** * Called when an existing user is stopping, for system services to finalize any per-user * state they maintain for running users. This is called prior to sending the SHUTDOWN diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java index 953e85014535f..c3cd1359cd5fd 100644 --- a/services/core/java/com/android/server/SystemServiceManager.java +++ b/services/core/java/com/android/server/SystemServiceManager.java @@ -82,10 +82,6 @@ public final class SystemServiceManager implements Dumpable { private static final String USER_STOPPING = "Stop"; // Logged as onUserStopping() private static final String USER_STOPPED = "Cleanup"; // Logged as onUserStopped() private static final String USER_COMPLETED_EVENT = "CompletedEvent"; // onUserCompletedEvent() - private static final String USER_VISIBLE = "Visible"; // Logged on onUserVisible() and - // onUserStarting() (when visible is true) - private static final String USER_INVISIBLE = "Invisible"; // Logged on onUserStopping() - // (when visibilityChanged is true) // The default number of threads to use if lifecycle thread pool is enabled. private static final int DEFAULT_MAX_USER_POOL_THREADS = 3; @@ -354,57 +350,16 @@ public final class SystemServiceManager implements Dumpable { /** * Starts the given user. */ - public void onUserStarting(@NonNull TimingsTraceAndSlog t, @UserIdInt int userId, - boolean visible) { - EventLog.writeEvent(EventLogTags.SSM_USER_STARTING, userId, visible ? 1 : 0); + public void onUserStarting(@NonNull TimingsTraceAndSlog t, @UserIdInt int userId) { + EventLog.writeEvent(EventLogTags.SSM_USER_STARTING, userId); final TargetUser targetUser = newTargetUser(userId); synchronized (mTargetUsers) { mTargetUsers.put(userId, targetUser); } - - if (visible) { - // Must send the user visiiblity change first, for 2 reasons: - // 1. Automotive need to update the user-zone mapping ASAP and it's one of the few - // services listening to this event (OTOH, there are manyy listeners to USER_STARTING - // and some can take a while to process it) - // 2. When a user is switched from bg to fg, the onUserVisibilityChanged() callback is - // called onUserSwitching(), so calling it before onUserStarting() make it more - // consistent with that - EventLog.writeEvent(EventLogTags.SSM_USER_VISIBILITY_CHANGED, userId, /* visible= */ 1); - onUser(t, USER_VISIBLE, /* prevUser= */ null, targetUser); - } onUser(t, USER_STARTING, /* prevUser= */ null, targetUser); } - /** - * Updates the user visibility. - * - *
NOTE: this method should only be called when a user that is already running become - * visible; if the user is starting visible, callers should call - * {@link #onUserStarting(TimingsTraceAndSlog, int, boolean)} instead. - */ - public void onUserVisible(@UserIdInt int userId) { - EventLog.writeEvent(EventLogTags.SSM_USER_VISIBILITY_CHANGED, userId, /* visible= */ 1); - onUser(USER_VISIBLE, userId); - } - - /** - * Updates the visibility of the system user. - * - *
Since the system user never stops, this method must be called when it's switched from / to - * foreground. - */ - public void onSystemUserVisibilityChanged(boolean visible) { - int userId = UserHandle.USER_SYSTEM; - EventLog.writeEvent(EventLogTags.SSM_USER_VISIBILITY_CHANGED, userId, visible ? 1 : 0); - if (visible) { - onUser(USER_VISIBLE, userId); - } else { - onUser(USER_INVISIBLE, userId); - } - } - /** * Unlocks the given user. */ @@ -452,12 +407,9 @@ public final class SystemServiceManager implements Dumpable { /** * Stops the given user. */ - public void onUserStopping(@UserIdInt int userId, boolean visibilityChanged) { - EventLog.writeEvent(EventLogTags.SSM_USER_STOPPING, userId, visibilityChanged ? 1 : 0); + public void onUserStopping(@UserIdInt int userId) { + EventLog.writeEvent(EventLogTags.SSM_USER_STOPPING, userId); onUser(USER_STOPPING, userId); - if (visibilityChanged) { - onUser(USER_INVISIBLE, userId); - } } /** @@ -580,12 +532,6 @@ public final class SystemServiceManager implements Dumpable { threadPool.submit(getOnUserCompletedEventRunnable( t, service, serviceName, curUser, completedEventType)); break; - case USER_VISIBLE: - service.onUserVisibilityChanged(curUser, /* visible= */ true); - break; - case USER_INVISIBLE: - service.onUserVisibilityChanged(curUser, /* visible= */ false); - break; default: throw new IllegalArgumentException(onWhat + " what?"); } diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags index 60e6754f4b6f7..ea3c8dc1fa90f 100644 --- a/services/core/java/com/android/server/am/EventLogTags.logtags +++ b/services/core/java/com/android/server/am/EventLogTags.logtags @@ -107,21 +107,21 @@ option java_package com.android.server.am 30079 uc_dispatch_user_switch (oldUserId|1|5),(newUserId|1|5) 30080 uc_continue_user_switch (oldUserId|1|5),(newUserId|1|5) 30081 uc_send_user_broadcast (userId|1|5),(IntentAction|3) + # Tags below are used by SystemServiceManager - although it's technically part of am, these are # also user switch events and useful to be analyzed together with events above. -30082 ssm_user_starting (userId|1|5),(visible|1) +30082 ssm_user_starting (userId|1|5) 30083 ssm_user_switching (oldUserId|1|5),(newUserId|1|5) 30084 ssm_user_unlocking (userId|1|5) 30085 ssm_user_unlocked (userId|1|5) -30086 ssm_user_stopping (userId|1|5),(visibilityChanged|1) +30086 ssm_user_stopping (userId|1|5) 30087 ssm_user_stopped (userId|1|5) 30088 ssm_user_completed_event (userId|1|5),(eventFlag|1|5) -30089 ssm_user_visibility_changed (userId|1|5),(visible|1) + +# Similarly, tags below are used by UserManagerService +30091 um_user_visibility_changed (userId|1|5),(visible|1) # Foreground service start/stop events. 30100 am_foreground_service_start (User|1|5),(Component Name|3),(allowWhileInUse|1),(startReasonCode|3),(targetSdk|1|1),(callerTargetSdk|1|1),(notificationWasDeferred|1),(notificationShown|1),(durationMs|1|3),(startForegroundCount|1|1),(stopReason|3) 30101 am_foreground_service_denied (User|1|5),(Component Name|3),(allowWhileInUse|1),(startReasonCode|3),(targetSdk|1|1),(callerTargetSdk|1|1),(notificationWasDeferred|1),(notificationShown|1),(durationMs|1|3),(startForegroundCount|1|1),(stopReason|3) 30102 am_foreground_service_stop (User|1|5),(Component Name|3),(allowWhileInUse|1),(startReasonCode|3),(targetSdk|1|1),(callerTargetSdk|1|1),(notificationWasDeferred|1),(notificationShown|1),(durationMs|1|3),(startForegroundCount|1|1),(stopReason|3) - - - diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index af559808d880f..f3e7e41d30fe0 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -176,9 +176,7 @@ class UserController implements Handler.Callback { static final int START_USER_SWITCH_FG_MSG = 120; static final int COMPLETE_USER_SWITCH_MSG = 130; static final int USER_COMPLETED_EVENT_MSG = 140; - static final int USER_VISIBLE_MSG = 150; - - private static final int NO_ARG2 = 0; + static final int USER_VISIBILITY_CHANGED_MSG = 150; // Message constant to clear {@link UserJourneySession} from {@link mUserIdToUserJourneyMap} if // the user journey, defined in the UserLifecycleJourneyReported atom for statsd, is not @@ -430,10 +428,13 @@ class UserController implements Handler.Callback { /** @see #getLastUserUnlockingUptime */ private volatile long mLastUserUnlockingUptime = 0; + // TODO(b/244333150) remove this array and let UserVisibilityMediator call the listeners + // directly, as that class should be responsible for all user visibility logic (for example, + // when the foreground user is switched out, its profiles also become invisible) /** * List of visible users (as defined by {@link UserManager#isUserVisible()}). * - *
It's only used to call {@link SystemServiceManager} when the visibility is changed upon + *
It's only used to call {@link UserManagerInternal} when the visibility is changed upon * the user starting or stopping. * *
Note: only the key is used, not the value. @@ -1087,10 +1088,7 @@ class UserController implements Handler.Callback { synchronized (mLock) { visibleBefore = mVisibleUsers.get(userId); if (visibleBefore) { - if (DEBUG_MU) { - Slogf.d(TAG, "Removing %d from mVisibleUsers", userId); - } - mVisibleUsers.delete(userId); + deleteVisibleUserLocked(userId); visibilityChanged = true; } else { visibilityChanged = false; @@ -1139,6 +1137,20 @@ class UserController implements Handler.Callback { } } + private void addVisibleUserLocked(@UserIdInt int userId) { + if (DEBUG_MU) { + Slogf.d(TAG, "adding %d to mVisibleUsers", userId); + } + mVisibleUsers.put(userId, true); + } + + private void deleteVisibleUserLocked(@UserIdInt int userId) { + if (DEBUG_MU) { + Slogf.d(TAG, "deleting %d from mVisibleUsers", userId); + } + mVisibleUsers.delete(userId); + } + private void finishUserStopping(final int userId, final UserState uss, final boolean allowDelayedLocking, final boolean visibilityChanged) { EventLog.writeEvent(EventLogTags.UC_FINISH_USER_STOPPING, userId); @@ -1157,7 +1169,10 @@ class UserController implements Handler.Callback { mInjector.batteryStatsServiceNoteEvent( BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH, Integer.toString(userId), userId); - mInjector.getSystemServiceManager().onUserStopping(userId, visibilityChanged); + mInjector.getSystemServiceManager().onUserStopping(userId); + if (visibilityChanged) { + mInjector.onUserVisibilityChanged(userId, /* visible= */ false); + } Runnable finishUserStoppedAsync = () -> mHandler.post(() -> finishUserStopped(uss, allowDelayedLocking)); @@ -1678,7 +1693,15 @@ class UserController implements Handler.Callback { // Make sure the old user is no longer considering the display to be on. mInjector.reportGlobalUsageEvent(UsageEvents.Event.SCREEN_NON_INTERACTIVE); boolean userSwitchUiEnabled; + // TODO(b/244333150): temporary state until the callback logic is moved to + // UserVisibilityManager + int previousCurrentUserId; boolean notifyPreviousCurrentUserId; synchronized (mLock) { + previousCurrentUserId = mCurrentUserId; + notifyPreviousCurrentUserId = mVisibleUsers.get(previousCurrentUserId); + if (notifyPreviousCurrentUserId) { + deleteVisibleUserLocked(previousCurrentUserId); + } mCurrentUserId = userId; mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up userSwitchUiEnabled = mUserSwitchUiEnabled; @@ -1696,6 +1719,11 @@ class UserController implements Handler.Callback { mInjector.getWindowManager().lockNow(null); } } + if (notifyPreviousCurrentUserId) { + mHandler.sendMessage(mHandler.obtainMessage(USER_VISIBILITY_CHANGED_MSG, + previousCurrentUserId, 0)); + } + } else { final Integer currentUserIdInt = mCurrentUserId; updateProfileRelatedCaches(); @@ -1721,10 +1749,7 @@ class UserController implements Handler.Callback { && mInjector.getUserManagerInternal().isUserVisible(userId); if (visible) { synchronized (mLock) { - if (DEBUG_MU) { - Slogf.d(TAG, "Adding %d to mVisibleUsers", userId); - } - mVisibleUsers.put(userId, true); + addVisibleUserLocked(userId); } } @@ -1767,12 +1792,15 @@ class UserController implements Handler.Callback { mHandler.sendMessage(mHandler.obtainMessage(USER_START_MSG, userId, visible ? 1 : 0)); t.traceEnd(); - } else if (visible) { + } + + if (visible) { // User was already running and became visible (for example, when switching to a // user that was started in the background before), so it's necessary to explicitly // notify the services (while when the user starts from BOOTING, USER_START_MSG // takes care of that. - mHandler.sendMessage(mHandler.obtainMessage(USER_VISIBLE_MSG, userId, NO_ARG2)); + mHandler.sendMessage(mHandler.obtainMessage(USER_VISIBILITY_CHANGED_MSG, userId, + visible ? 1 : 0)); } t.traceBegin("sendMessages"); @@ -2552,7 +2580,8 @@ class UserController implements Handler.Callback { if (!UserManager.isHeadlessSystemUserMode()) { // Don't need to call on HSUM because it will be called when the system user is // restarted on background - mInjector.onUserStarting(UserHandle.USER_SYSTEM, /* visible= */ true); + mInjector.onUserStarting(UserHandle.USER_SYSTEM); + mInjector.onUserVisibilityChanged(UserHandle.USER_SYSTEM, /* visible= */ true); } } @@ -2564,12 +2593,12 @@ class UserController implements Handler.Callback { int userId = UserHandle.USER_SYSTEM; synchronized (mLock) { if (visible) { - mVisibleUsers.put(userId, true); + addVisibleUserLocked(userId); } else { - mVisibleUsers.delete(userId); + deleteVisibleUserLocked(userId); } } - mInjector.notifySystemUserVisibilityChanged(visible); + mInjector.onUserVisibilityChanged(userId, visible); t.traceEnd(); } @@ -3069,7 +3098,7 @@ class UserController implements Handler.Callback { logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_START_USER, USER_LIFECYCLE_EVENT_STATE_BEGIN); - mInjector.onUserStarting(/* userId= */ msg.arg1, /* visible= */ msg.arg2 == 1); + mInjector.onUserStarting(/* userId= */ msg.arg1); scheduleOnUserCompletedEvent(msg.arg1, UserCompletedEventType.EVENT_TYPE_USER_STARTING, USER_COMPLETED_EVENT_DELAY_MS); @@ -3150,8 +3179,9 @@ class UserController implements Handler.Callback { case COMPLETE_USER_SWITCH_MSG: completeUserSwitch(msg.arg1); break; - case USER_VISIBLE_MSG: - mInjector.getSystemServiceManager().onUserVisible(/* userId= */ msg.arg1); + case USER_VISIBILITY_CHANGED_MSG: + mInjector.onUserVisibilityChanged(/* userId= */ msg.arg1, + /* visible= */ msg.arg2 == 1); break; } return false; @@ -3675,12 +3705,12 @@ class UserController implements Handler.Callback { return UserManager.isUsersOnSecondaryDisplaysEnabled(); } - void onUserStarting(int userId, boolean visible) { - getSystemServiceManager().onUserStarting(TimingsTraceAndSlog.newAsyncLog(), userId, - visible); + void onUserStarting(@UserIdInt int userId) { + getSystemServiceManager().onUserStarting(TimingsTraceAndSlog.newAsyncLog(), userId); } - void notifySystemUserVisibilityChanged(boolean visible) { - getSystemServiceManager().onSystemUserVisibilityChanged(visible); + + void onUserVisibilityChanged(@UserIdInt int userId, boolean visible) { + getUserManagerInternal().onUserVisibilityChanged(userId, visible); } } } diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java index dcec0aaf93581..2669d217120fe 100644 --- a/services/core/java/com/android/server/location/LocationManagerService.java +++ b/services/core/java/com/android/server/location/LocationManagerService.java @@ -140,7 +140,9 @@ import com.android.server.location.provider.StationaryThrottlingLocationProvider import com.android.server.location.provider.proxy.ProxyLocationProvider; import com.android.server.location.settings.LocationSettings; import com.android.server.location.settings.LocationUserSettings; +import com.android.server.pm.UserManagerInternal; import com.android.server.pm.permission.LegacyPermissionManagerInternal; +import com.android.server.utils.Slogf; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -308,6 +310,10 @@ public class LocationManagerService extends ILocationManager.Stub implements permissionManagerInternal.setLocationExtraPackagesProvider( userId -> mContext.getResources().getStringArray( com.android.internal.R.array.config_locationExtraPackageNames)); + + // TODO(b/241604546): properly handle this callback + LocalServices.getService(UserManagerInternal.class).addUserVisibilityListener( + (u, v) -> Slogf.i(TAG, "onUserVisibilityChanged(): %d -> %b", u, v)); } @Nullable diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java index 56ec8e46291d9..a8d31f580c1ca 100644 --- a/services/core/java/com/android/server/pm/UserManagerInternal.java +++ b/services/core/java/com/android/server/pm/UserManagerInternal.java @@ -76,6 +76,23 @@ public abstract class UserManagerInternal { default void onUserRemoved(UserInfo user) {} } + /** + * Listener for {@link UserManager#isUserVisible() user visibility} changes. + */ + public interface UserVisibilityListener { + + /** + * Called when the {@link UserManager#isUserVisible() user visibility} changed. + * + *
Note: this method is called independently of
+ * {@link com.android.server.SystemService} callbacks; for example, the call with
+ * {@code visible} {@code true} might be called before the
+ * {@link com.android.server.SystemService#onUserStarting(com.android.server.SystemService.TargetUser)}
+ * call.
+ */
+ void onUserVisibilityChanged(@UserIdInt int userId, boolean visible);
+ }
+
/**
* Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to set
* restrictions enforced by the user.
@@ -390,4 +407,13 @@ public abstract class UserManagerInternal {
* would make such call).
*/
public abstract @UserIdInt int getUserAssignedToDisplay(int displayId);
+
+ /** Adds a {@link UserVisibilityListener}. */
+ public abstract void addUserVisibilityListener(UserVisibilityListener listener);
+
+ /** Removes a {@link UserVisibilityListener}. */
+ public abstract void removeUserVisibilityListener(UserVisibilityListener listener);
+
+ /** TODO(b/244333150): temporary method until UserVisibilityMediator handles that logic */
+ public abstract void onUserVisibilityChanged(@UserIdInt int userId, boolean visible);
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index f85b11da252ea..2a01b1a4e9485 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -96,6 +96,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.EventLog;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
import android.util.Slog;
@@ -124,9 +125,11 @@ import com.android.server.BundleUtils;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.SystemService;
+import com.android.server.am.EventLogTags;
import com.android.server.am.UserState;
import com.android.server.pm.UserManagerInternal.UserLifecycleListener;
import com.android.server.pm.UserManagerInternal.UserRestrictionsListener;
+import com.android.server.pm.UserManagerInternal.UserVisibilityListener;
import com.android.server.storage.DeviceStorageMonitorInternal;
import com.android.server.utils.Slogf;
import com.android.server.utils.TimingsTraceAndSlog;
@@ -504,6 +507,10 @@ public class UserManagerService extends IUserManager.Stub {
@GuardedBy("mUserLifecycleListeners")
private final ArrayList