Merge "Moved user visibility callback to its own listener."

This commit is contained in:
Felipe Leme
2022-11-10 17:32:05 +00:00
committed by Android (Google) Code Review
8 changed files with 147 additions and 108 deletions

View File

@@ -472,18 +472,6 @@ public abstract class SystemService {
public void onUserSwitching(@Nullable TargetUser from, @NonNull TargetUser to) {
}
/**
* The {@link UserManager#isUserVisible() user visibility} changed.
*
* <p>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

View File

@@ -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.
*
* <p><b>NOTE: </b>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.
*
* <p>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?");
}

View File

@@ -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)

View File

@@ -177,9 +177,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
@@ -439,10 +437,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()}).
*
* <p>It's only used to call {@link SystemServiceManager} when the visibility is changed upon
* <p>It's only used to call {@link UserManagerInternal} when the visibility is changed upon
* the user starting or stopping.
*
* <p>Note: only the key is used, not the value.
@@ -1096,10 +1097,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;
@@ -1148,6 +1146,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);
@@ -1166,7 +1178,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));
@@ -1687,7 +1702,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;
@@ -1705,6 +1728,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();
@@ -1730,10 +1758,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);
}
}
@@ -1776,12 +1801,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");
@@ -2573,7 +2601,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);
}
}
@@ -2585,12 +2614,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();
}
@@ -3090,7 +3119,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);
@@ -3171,8 +3200,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;
@@ -3704,12 +3734,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);
}
}
}

View File

@@ -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

View File

@@ -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.
*
* <p><b>Note:</b> 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);
}

View File

@@ -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<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
// TODO(b/244333150): temporary array, should belong to UserVisibilityMediator
@GuardedBy("mUserVisibilityListeners")
private final ArrayList<UserVisibilityListener> mUserVisibilityListeners = new ArrayList<>();
private final LockPatternUtils mLockPatternUtils;
private final String ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK =
@@ -6250,6 +6257,9 @@ public class UserManagerService extends IUserManager.Stub {
synchronized (mUserLifecycleListeners) {
pw.println(" user lifecycle events: " + mUserLifecycleListeners.size());
}
synchronized (mUserVisibilityListeners) {
pw.println(" user visibility events: " + mUserVisibilityListeners.size());
}
// Dump UserTypes
pw.println();
@@ -6817,8 +6827,39 @@ public class UserManagerService extends IUserManager.Stub {
public @UserIdInt int getUserAssignedToDisplay(int displayId) {
return mUserVisibilityMediator.getUserAssignedToDisplay(displayId);
}
@Override
public void addUserVisibilityListener(UserVisibilityListener listener) {
synchronized (mUserVisibilityListeners) {
mUserVisibilityListeners.add(listener);
}
}
@Override
public void removeUserVisibilityListener(UserVisibilityListener listener) {
synchronized (mUserVisibilityListeners) {
mUserVisibilityListeners.remove(listener);
}
}
@Override
public void onUserVisibilityChanged(@UserIdInt int userId, boolean visible) {
EventLog.writeEvent(EventLogTags.UM_USER_VISIBILITY_CHANGED, userId, visible ? 1 : 0);
mHandler.post(() -> {
UserVisibilityListener[] listeners;
synchronized (mUserVisibilityListeners) {
listeners = new UserVisibilityListener[mUserVisibilityListeners.size()];
mUserVisibilityListeners.toArray(listeners);
}
for (UserVisibilityListener listener : listeners) {
listener.onUserVisibilityChanged(userId, visible);
}
});
}
} // class LocalService
/**
* Check if user has restrictions
* @param restriction restrictions to check

View File

@@ -38,6 +38,7 @@ import static com.android.server.am.UserController.USER_COMPLETED_EVENT_MSG;
import static com.android.server.am.UserController.USER_CURRENT_MSG;
import static com.android.server.am.UserController.USER_START_MSG;
import static com.android.server.am.UserController.USER_SWITCH_TIMEOUT_MSG;
import static com.android.server.am.UserController.USER_VISIBILITY_CHANGED_MSG;
import static com.google.android.collect.Lists.newArrayList;
import static com.google.android.collect.Sets.newHashSet;
@@ -158,6 +159,7 @@ public class UserControllerTest {
REPORT_USER_SWITCH_MSG,
USER_SWITCH_TIMEOUT_MSG,
USER_START_MSG,
USER_VISIBILITY_CHANGED_MSG,
USER_CURRENT_MSG);
private static final Set<Integer> START_BACKGROUND_USER_MESSAGE_CODES = newHashSet(
@@ -964,7 +966,7 @@ public class UserControllerTest {
}
private void verifySystemUserVisibilityChangedNotified(boolean visible) {
verify(mInjector).notifySystemUserVisibilityChanged(visible);
verify(mInjector).onUserVisibilityChanged(UserHandle.USER_SYSTEM, visible);
}
// Should be public to allow mocking
@@ -1104,13 +1106,13 @@ public class UserControllerTest {
}
@Override
void onUserStarting(@UserIdInt int userId, boolean visible) {
Log.i(TAG, "onUserStarting(" + userId + ", " + visible + ")");
void onUserStarting(@UserIdInt int userId) {
Log.i(TAG, "onUserStarting(" + userId + ")");
}
@Override
void notifySystemUserVisibilityChanged(boolean visible) {
Log.i(TAG, "notifySystemUserVisibilityChanged(" + visible + ")");
void onUserVisibilityChanged(@UserIdInt int userId, boolean visible) {
Log.i(TAG, "onUserVisibilityChanged(" + userId + ", " + visible + ")");
}
}