Merge "Send user starting broadcast for non-automotive devices in HSUM." into udc-dev

This commit is contained in:
BK Choi
2023-02-22 02:24:11 +00:00
committed by Android (Google) Code Review
3 changed files with 129 additions and 53 deletions

View File

@@ -8613,7 +8613,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// On Automotive / Headless System User Mode, at this point the system user has already been
// started and unlocked, and some of the tasks we do here have already been done. So skip
// those in that case. The duplicate system user start is guarded in SystemServiceManager.
// TODO(b/242195409): this workaround shouldn't be necessary once we move the headless-user
// TODO(b/266158156): this workaround shouldn't be necessary once we move the headless-user
// start logic to UserManager-land.
mUserController.onSystemUserStarting();
@@ -8646,7 +8646,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Some systems - like automotive - will explicitly unlock system user then switch
// to a secondary user.
// TODO(b/242195409): this workaround shouldn't be necessary once we move
// TODO(b/266158156): this workaround shouldn't be necessary once we move
// the headless-user start logic to UserManager-land.
if (isBootingSystemUser && !UserManager.isHeadlessSystemUserMode()) {
t.traceBegin("startHomeOnAllDisplays");
@@ -8669,26 +8669,10 @@ public class ActivityManagerService extends IActivityManager.Stub
final int callingPid = Binder.getCallingPid();
final long ident = Binder.clearCallingIdentity();
try {
Intent intent = new Intent(Intent.ACTION_USER_STARTED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
broadcastIntentLocked(null, null, null, intent,
null, null, 0, null, null, null, null, null, OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
currentUserId);
intent = new Intent(Intent.ACTION_USER_STARTING);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
broadcastIntentLocked(null, null, null, intent, null,
new IIntentReceiver.Stub() {
@Override
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered, boolean sticky,
int sendingUser) {}
}, 0, null, null, new String[] {INTERACT_ACROSS_USERS}, null, null,
OP_NONE, null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
UserHandle.USER_ALL);
mUserController.sendUserStartedBroadcast(
currentUserId, callingUid, callingPid);
mUserController.sendUserStartingBroadcast(
currentUserId, callingUid, callingPid);
} catch (Throwable e) {
Slog.wtf(TAG, "Failed sending first user broadcasts", e);
} finally {

View File

@@ -365,13 +365,13 @@ class UserController implements Handler.Callback {
private volatile ArraySet<String> mCurWaitingUserSwitchCallbacks;
/**
* Messages for for switching from {@link android.os.UserHandle#SYSTEM}.
* Messages for switching from {@link android.os.UserHandle#SYSTEM}.
*/
@GuardedBy("mLock")
private String mSwitchingFromSystemUserMessage;
/**
* Messages for for switching to {@link android.os.UserHandle#SYSTEM}.
* Messages for switching to {@link android.os.UserHandle#SYSTEM}.
*/
@GuardedBy("mLock")
private String mSwitchingToSystemUserMessage;
@@ -384,6 +384,16 @@ class UserController implements Handler.Callback {
private final LockPatternUtils mLockPatternUtils;
// TODO(b/266158156): remove this once we improve/refactor the way broadcasts are sent for
// the system user in HSUM.
@GuardedBy("mLock")
private boolean mIsBroadcastSentForSystemUserStarted;
// TODO(b/266158156): remove this once we improve/refactor the way broadcasts are sent for
// the system user in HSUM.
@GuardedBy("mLock")
private boolean mIsBroadcastSentForSystemUserStarting;
volatile boolean mBootCompleted;
/**
@@ -635,7 +645,7 @@ class UserController implements Handler.Callback {
// user transitions to RUNNING_LOCKED. However, in "headless system user mode", the
// system user is explicitly started before the device has finished booting. In
// that case, we need to wait until onBootComplete() to send the broadcast.
if (!(UserManager.isHeadlessSystemUserMode() && uss.mHandle.isSystem())) {
if (!(mInjector.isHeadlessSystemUserMode() && uss.mHandle.isSystem())) {
// ACTION_LOCKED_BOOT_COMPLETED
sendLockedBootCompletedBroadcast(resultTo, userId);
}
@@ -1823,15 +1833,17 @@ class UserController implements Handler.Callback {
needStart = false;
}
if (needStart) {
// Send USER_STARTED broadcast
Intent intent = new Intent(Intent.ACTION_USER_STARTED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mInjector.broadcastIntent(intent,
null, null, 0, null, null, null, AppOpsManager.OP_NONE,
null, false, false, MY_PID, SYSTEM_UID, callingUid, callingPid, userId);
// In most cases, broadcast for the system user starting/started is sent by
// ActivityManagerService#systemReady(). However on some HSUM devices (e.g. tablets)
// the user switches from the system user to a secondary user while running
// ActivityManagerService#systemReady(), thus broadcast is not sent for the system user.
// Therefore we send the broadcast for the system user here as well in HSUM.
// TODO(b/266158156): Improve/refactor the way broadcasts are sent for the system user
// in HSUM. Ideally it'd be best to have one single place that sends this notification.
final boolean isSystemUserInHeadlessMode = (userId == UserHandle.USER_SYSTEM)
&& mInjector.isHeadlessSystemUserMode();
if (needStart || isSystemUserInHeadlessMode) {
sendUserStartedBroadcast(userId, callingUid, callingPid);
}
t.traceEnd();
@@ -1845,23 +1857,9 @@ class UserController implements Handler.Callback {
t.traceEnd();
}
if (needStart) {
if (needStart || isSystemUserInHeadlessMode) {
t.traceBegin("sendRestartBroadcast");
Intent intent = new Intent(Intent.ACTION_USER_STARTING);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mInjector.broadcastIntent(intent,
null, new IIntentReceiver.Stub() {
@Override
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
boolean sticky,
int sendingUser) throws RemoteException {
}
}, 0, null, null,
new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
null, true, false, MY_PID, SYSTEM_UID, callingUid, callingPid,
UserHandle.USER_ALL);
sendUserStartingBroadcast(userId, callingUid, callingPid);
t.traceEnd();
}
} finally {
@@ -2283,6 +2281,62 @@ class UserController implements Handler.Callback {
EventLogTags.writeAmSwitchUser(newUserId);
}
// The two methods sendUserStartedBroadcast() and sendUserStartingBroadcast()
// could be merged for better reuse. However, the params they are calling broadcastIntent()
// with are different - resultCode receiver, permissions, ordered, and userId, etc. Therefore,
// we decided to keep two separate methods for better code readability/clarity.
// TODO(b/266158156): Improve/refactor the way broadcasts are sent for the system user
// in HSUM. Ideally it'd be best to have one single place that sends this notification.
/** Sends {@code ACTION_USER_STARTED} broadcast. */
void sendUserStartedBroadcast(@UserIdInt int userId, int callingUid, int callingPid) {
if (userId == UserHandle.USER_SYSTEM) {
synchronized (mLock) {
// Make sure that the broadcast is sent only once for the system user.
if (mIsBroadcastSentForSystemUserStarted) {
return;
}
mIsBroadcastSentForSystemUserStarted = true;
}
}
final Intent intent = new Intent(Intent.ACTION_USER_STARTED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mInjector.broadcastIntent(intent, /* resolvedType= */ null, /* resultTo= */ null,
/* resultCode= */ 0, /* resultData= */ null, /* resultExtras= */ null,
/* requiredPermissions= */ null, AppOpsManager.OP_NONE, /* bOptions= */ null,
/* ordered= */ false, /* sticky= */ false, MY_PID, SYSTEM_UID,
callingUid, callingPid, userId);
}
/** Sends {@code ACTION_USER_STARTING} broadcast. */
void sendUserStartingBroadcast(@UserIdInt int userId, int callingUid, int callingPid) {
if (userId == UserHandle.USER_SYSTEM) {
synchronized (mLock) {
// Make sure that the broadcast is sent only once for the system user.
if (mIsBroadcastSentForSystemUserStarting) {
return;
}
mIsBroadcastSentForSystemUserStarting = true;
}
}
final Intent intent = new Intent(Intent.ACTION_USER_STARTING);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
mInjector.broadcastIntent(intent, /* resolvedType= */ null,
new IIntentReceiver.Stub() {
@Override
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
boolean sticky,
int sendingUser) throws RemoteException {
}
}, /* resultCode= */ 0, /* resultData= */ null, /* resultExtras= */ null,
new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE, /* bOptions= */ null,
/* ordered= */ true, /* sticky= */ false, MY_PID, SYSTEM_UID,
callingUid, callingPid, UserHandle.USER_ALL);
}
void sendUserSwitchBroadcasts(int oldUserId, int newUserId) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
@@ -2568,7 +2622,7 @@ class UserController implements Handler.Callback {
for (int i = 0; i < startedUsers.size(); i++) {
int userId = startedUsers.keyAt(i);
UserState uss = startedUsers.valueAt(i);
if (!UserManager.isHeadlessSystemUserMode()) {
if (!mInjector.isHeadlessSystemUserMode()) {
finishUserBoot(uss, resultTo);
} else {
if (userId == UserHandle.USER_SYSTEM) {
@@ -2589,9 +2643,9 @@ class UserController implements Handler.Callback {
mInjector.reportCurWakefulnessUsageEvent();
}
// TODO(b/242195409): remove this method if initial system user boot logic is refactored?
// TODO(b/266158156): remove this method if initial system user boot logic is refactored?
void onSystemUserStarting() {
if (!UserManager.isHeadlessSystemUserMode()) {
if (!mInjector.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);
@@ -3059,6 +3113,10 @@ class UserController implements Handler.Callback {
pw.println(" mMaxRunningUsers:" + mMaxRunningUsers);
pw.println(" mUserSwitchUiEnabled:" + mUserSwitchUiEnabled);
pw.println(" mInitialized:" + mInitialized);
pw.println(" mIsBroadcastSentForSystemUserStarted:"
+ mIsBroadcastSentForSystemUserStarted);
pw.println(" mIsBroadcastSentForSystemUserStarting:"
+ mIsBroadcastSentForSystemUserStarting);
if (mSwitchingFromSystemUserMessage != null) {
pw.println(" mSwitchingFromSystemUserMessage: " + mSwitchingFromSystemUserMessage);
}
@@ -3749,6 +3807,10 @@ class UserController implements Handler.Callback {
}, /* message= */ null);
}
boolean isHeadlessSystemUserMode() {
return UserManager.isHeadlessSystemUserMode();
}
boolean isUsersOnSecondaryDisplaysEnabled() {
return UserManager.isVisibleBackgroundUsersEnabled();
}

View File

@@ -133,6 +133,7 @@ public class UserControllerTest {
private static final int TEST_USER_ID1 = 101;
private static final int TEST_USER_ID2 = 102;
private static final int TEST_USER_ID3 = 103;
private static final int SYSTEM_USER_ID = UserHandle.SYSTEM.getIdentifier();
private static final int NONEXIST_USER_ID = 2;
private static final int TEST_PRE_CREATED_USER_ID = 103;
@@ -230,6 +231,31 @@ public class UserControllerTest {
verifyUserAssignedToDisplay(TEST_USER_ID, Display.DEFAULT_DISPLAY);
}
@Test
public void testStartUser_sendsNoBroadcastsForSystemUserInNonHeadlessMode() {
setUpUser(SYSTEM_USER_ID, UserInfo.FLAG_SYSTEM, /* preCreated= */ false,
UserManager.USER_TYPE_FULL_SYSTEM);
mockIsHeadlessSystemUserMode(false);
mUserController.startUser(SYSTEM_USER_ID, USER_START_MODE_FOREGROUND);
assertWithMessage("Broadcasts for starting the system user in non-headless mode")
.that(mInjector.mSentIntents).isEmpty();
}
@Test
public void testStartUser_sendsBroadcastsForSystemUserInHeadlessMode() {
setUpUser(SYSTEM_USER_ID, UserInfo.FLAG_SYSTEM, /* preCreated= */ false,
UserManager.USER_TYPE_SYSTEM_HEADLESS);
mockIsHeadlessSystemUserMode(true);
mUserController.startUser(SYSTEM_USER_ID, USER_START_MODE_FOREGROUND);
assertWithMessage("Broadcasts for starting the system user in headless mode")
.that(getActions(mInjector.mSentIntents)).containsExactly(
Intent.ACTION_USER_STARTED, Intent.ACTION_USER_STARTING);
}
@Test
public void testStartUser_displayAssignmentFailed() {
doReturn(UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE)
@@ -999,6 +1025,10 @@ public class UserControllerTest {
}
}
private void mockIsHeadlessSystemUserMode(boolean value) {
when(mInjector.isHeadlessSystemUserMode()).thenReturn(value);
}
private void mockIsUsersOnSecondaryDisplaysEnabled(boolean value) {
when(mInjector.isUsersOnSecondaryDisplaysEnabled()).thenReturn(value);
}