Loading core/java/android/content/Intent.java +58 −14 Original line number Diff line number Diff line Loading @@ -2327,7 +2327,9 @@ public class Intent implements Parcelable, Cloneable { * party applications because a newly initialized user does not have any * third party applications installed for it.) This is sent early in * starting the user, around the time the home app is started, before * {@link #ACTION_BOOT_COMPLETED} is sent. * {@link #ACTION_BOOT_COMPLETED} is sent. This is sent as a foreground * broadcast, since it is part of a visible user interaction; be as quick * as possible when handling it. */ public static final String ACTION_USER_INITIALIZE = "android.intent.action.USER_INITIALIZE"; Loading @@ -2337,7 +2339,9 @@ public class Intent implements Parcelable, Cloneable { * brought to the foreground. This is only sent to receivers registered * through {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) * Context.registerReceiver}. It is sent to the user that is going to the * foreground. * foreground. This is sent as a foreground * broadcast, since it is part of a visible user interaction; be as quick * as possible when handling it. */ public static final String ACTION_USER_FOREGROUND = "android.intent.action.USER_FOREGROUND"; Loading @@ -2347,14 +2351,17 @@ public class Intent implements Parcelable, Cloneable { * sent to the background. This is only sent to receivers registered * through {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) * Context.registerReceiver}. It is sent to the user that is going to the * background. * background. This is sent as a foreground * broadcast, since it is part of a visible user interaction; be as quick * as possible when handling it. */ public static final String ACTION_USER_BACKGROUND = "android.intent.action.USER_BACKGROUND"; /** * Broadcast sent to the system when a user is added. Carries an extra EXTRA_USER_HANDLE that has the * userHandle of the new user. It is sent to all running users. You must hold * Broadcast sent to the system when a user is added. Carries an extra * EXTRA_USER_HANDLE that has the userHandle of the new user. It is sent to * all running users. You must hold * {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast. * @hide */ Loading @@ -2362,22 +2369,59 @@ public class Intent implements Parcelable, Cloneable { "android.intent.action.USER_ADDED"; /** * Broadcast sent to the system when a user is started. Carries an extra EXTRA_USER_HANDLE that has * the userHandle of the user. This is only sent to * Broadcast sent by the system when a user is started. Carries an extra * EXTRA_USER_HANDLE that has the userHandle of the user. This is only sent to * registered receivers, not manifest receivers. It is sent to the user * that has been started. * that has been started. This is sent as a foreground * broadcast, since it is part of a visible user interaction; be as quick * as possible when handling it. * @hide */ public static final String ACTION_USER_STARTED = "android.intent.action.USER_STARTED"; /** * Broadcast sent to the system when a user is stopped. Carries an extra EXTRA_USER_HANDLE that has * the userHandle of the user. This is similar to {@link #ACTION_PACKAGE_RESTARTED}, * but for an entire user instead of a specific package. This is only sent to * registered receivers, not manifest receivers. It is sent to all running * users <em>except</em> the one that has just been stopped (which is no * longer running). * Broadcast sent when a user is in the process of starting. Carries an extra * EXTRA_USER_HANDLE that has the userHandle of the user. This is only * sent to registered receivers, not manifest receivers. It is sent to all * users (including the one that is being started). You must hold * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} to receive * this broadcast. This is sent as a background broadcast, since * its result is not part of the primary UX flow; to safely keep track of * started/stopped state of a user you can use this in conjunction with * {@link #ACTION_USER_STOPPING}. It is <b>not</b> generally safe to use with * other user state broadcasts since those are foreground broadcasts so can * execute in a different order. * @hide */ public static final String ACTION_USER_STARTING = "android.intent.action.USER_STARTING"; /** * Broadcast sent when a user is going to be stopped. Carries an extra * EXTRA_USER_HANDLE that has the userHandle of the user. This is only * sent to registered receivers, not manifest receivers. It is sent to all * users (including the one that is being stopped). You must hold * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} to receive * this broadcast. The user will not stop until all receivers have * handled the broadcast. This is sent as a background broadcast, since * its result is not part of the primary UX flow; to safely keep track of * started/stopped state of a user you can use this in conjunction with * {@link #ACTION_USER_STARTING}. It is <b>not</b> generally safe to use with * other user state broadcasts since those are foreground broadcasts so can * execute in a different order. * @hide */ public static final String ACTION_USER_STOPPING = "android.intent.action.USER_STOPPING"; /** * Broadcast sent to the system when a user is stopped. Carries an extra * EXTRA_USER_HANDLE that has the userHandle of the user. This is similar to * {@link #ACTION_PACKAGE_RESTARTED}, but for an entire user instead of a * specific package. This is only sent to registered receivers, not manifest * receivers. It is sent to all running users <em>except</em> the one that * has just been stopped (which is no longer running). * @hide */ public static final String ACTION_USER_STOPPED = Loading core/res/res/anim/wallpaper_enter.xml +2 −0 Original line number Diff line number Diff line Loading @@ -19,10 +19,12 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@interpolator/decelerate_quad"> <!-- Having trouble avoiding this when switching users, so simple fade for now <scale android:fromXScale="3.0" android:toXScale="1.0" android:fromYScale="3.0" android:toYScale="1.0" android:pivotX="50%" android:pivotY="50%" android:duration="@android:integer/config_longAnimTime" /> --> <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="@android:integer/config_longAnimTime" /> </set> No newline at end of file core/res/res/anim/wallpaper_exit.xml +2 −0 Original line number Diff line number Diff line Loading @@ -19,10 +19,12 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@interpolator/accelerate_quad"> <!-- Having trouble avoiding this when switching users, so simple fade for now <scale android:fromXScale="1.0" android:toXScale="3.0" android:fromYScale="1.0" android:toYScale="3.0" android:pivotX="50%" android:pivotY="50%" android:duration="@android:integer/config_longAnimTime" /> --> <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="@android:integer/config_longAnimTime"/> </set> No newline at end of file services/java/com/android/server/am/ActivityManagerService.java +70 −14 Original line number Diff line number Diff line Loading @@ -3741,8 +3741,7 @@ public final class ActivityManagerService extends ActivityManagerNative private void forceStopUserLocked(int userId) { forceStopPackageLocked(null, -1, false, false, true, false, userId); Intent intent = new Intent(Intent.ACTION_USER_STOPPED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, Loading Loading @@ -14130,6 +14129,19 @@ public final class ActivityManagerService extends ActivityManagerNative final UserStartedState uss = mStartedUsers.get(userId); // Make sure user is in the started state. If it is currently // stopping, we need to knock that off. if (uss.mState == UserStartedState.STATE_STOPPING) { // If we are stopping, we haven't sent ACTION_SHUTDOWN, // so we can just fairly silently bring the user back from // the almost-dead. uss.mState = UserStartedState.STATE_RUNNING; } else if (uss.mState == UserStartedState.STATE_SHUTDOWN) { // This means ACTION_SHUTDOWN has been sent, so we will // need to treat this as a new boot of the user. uss.mState = UserStartedState.STATE_BOOTING; } mHandler.removeMessages(REPORT_USER_SWITCH_MSG); mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG); mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG, Loading Loading @@ -14207,6 +14219,19 @@ public final class ActivityManagerService extends ActivityManagerNative null, null, 0, null, null, android.Manifest.permission.MANAGE_USERS, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); intent = new Intent(Intent.ACTION_USER_STARTING); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId); broadcastIntentLocked(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) throws RemoteException { } }, 0, null, null, android.Manifest.permission.INTERACT_ACROSS_USERS, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } } finally { Binder.restoreCallingIdentity(ident); Loading Loading @@ -14295,7 +14320,8 @@ public final class ActivityManagerService extends ActivityManagerNative void finishUserSwitch(UserStartedState uss) { synchronized (this) { if (uss.mState == UserStartedState.STATE_BOOTING if ((uss.mState == UserStartedState.STATE_BOOTING || uss.mState == UserStartedState.STATE_SHUTDOWN) && mStartedUsers.get(uss.mHandle.getIdentifier()) == uss) { uss.mState = UserStartedState.STATE_RUNNING; final int userId = uss.mHandle.getIdentifier(); Loading @@ -14317,7 +14343,8 @@ public final class ActivityManagerService extends ActivityManagerNative num--; continue; } if (oldUss.mState == UserStartedState.STATE_STOPPING) { if (oldUss.mState == UserStartedState.STATE_STOPPING || oldUss.mState == UserStartedState.STATE_SHUTDOWN) { // This user is already stopping, doesn't count. num--; i++; Loading Loading @@ -14382,23 +14409,50 @@ public final class ActivityManagerService extends ActivityManagerNative uss.mStopCallbacks.add(callback); } if (uss.mState != UserStartedState.STATE_STOPPING) { if (uss.mState != UserStartedState.STATE_STOPPING && uss.mState != UserStartedState.STATE_SHUTDOWN) { uss.mState = UserStartedState.STATE_STOPPING; long ident = Binder.clearCallingIdentity(); try { // Inform of user switch Intent intent = new Intent(Intent.ACTION_SHUTDOWN); final IIntentReceiver resultReceiver = new IIntentReceiver.Stub() { // We are going to broadcast ACTION_USER_STOPPING and then // once that is down send a final ACTION_SHUTDOWN and then // stop the user. final Intent stoppingIntent = new Intent(Intent.ACTION_USER_STOPPING); stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); stoppingIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN); // This is the result receiver for the final shutdown broadcast. final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() { @Override public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { finishUserStop(uss); } }; broadcastIntentLocked(null, null, intent, null, resultReceiver, 0, null, null, null, // This is the result receiver for the initial stopping broadcast. final IIntentReceiver stoppingReceiver = new IIntentReceiver.Stub() { @Override public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { // On to the next. synchronized (ActivityManagerService.this) { if (uss.mState != UserStartedState.STATE_STOPPING) { // Whoops, we are being started back up. Abort, abort! return; } uss.mState = UserStartedState.STATE_SHUTDOWN; } broadcastIntentLocked(null, null, shutdownIntent, null, shutdownReceiver, 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID, userId); } }; // Kick things off. broadcastIntentLocked(null, null, stoppingIntent, null, stoppingReceiver, 0, null, null, android.Manifest.permission.INTERACT_ACROSS_USERS, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } finally { Binder.restoreCallingIdentity(ident); } Loading @@ -14413,8 +14467,9 @@ public final class ActivityManagerService extends ActivityManagerNative ArrayList<IStopUserCallback> callbacks; synchronized (this) { callbacks = new ArrayList<IStopUserCallback>(uss.mStopCallbacks); if (uss.mState != UserStartedState.STATE_STOPPING || mStartedUsers.get(userId) != uss) { if (mStartedUsers.get(userId) != uss) { stopped = false; } else if (uss.mState != UserStartedState.STATE_SHUTDOWN) { stopped = false; } else { stopped = true; Loading Loading @@ -14478,7 +14533,8 @@ public final class ActivityManagerService extends ActivityManagerNative boolean isUserRunningLocked(int userId) { UserStartedState state = mStartedUsers.get(userId); return state != null && state.mState != UserStartedState.STATE_STOPPING; return state != null && state.mState != UserStartedState.STATE_STOPPING && state.mState != UserStartedState.STATE_SHUTDOWN; } @Override services/java/com/android/server/am/UserStartedState.java +13 −1 Original line number Diff line number Diff line Loading @@ -23,9 +23,14 @@ import android.app.IStopUserCallback; import android.os.UserHandle; public class UserStartedState { // User is first coming up. public final static int STATE_BOOTING = 0; // User is in the normal running state. public final static int STATE_RUNNING = 1; // User is in the initial process of being stopped. public final static int STATE_STOPPING = 2; // User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN. public final static int STATE_SHUTDOWN = 3; public final UserHandle mHandle; public final ArrayList<IStopUserCallback> mStopCallbacks Loading @@ -40,7 +45,14 @@ public class UserStartedState { } void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("mState="); pw.print(mState); pw.print(prefix); pw.print("mState="); switch (mState) { case STATE_BOOTING: pw.print("BOOTING"); break; case STATE_RUNNING: pw.print("RUNNING"); break; case STATE_STOPPING: pw.print("STOPPING"); break; case STATE_SHUTDOWN: pw.print("SHUTDOWN"); break; default: pw.print(mState); break; } if (switching) pw.print(" SWITCHING"); if (initializing) pw.print(" INITIALIZING"); pw.println(); Loading Loading
core/java/android/content/Intent.java +58 −14 Original line number Diff line number Diff line Loading @@ -2327,7 +2327,9 @@ public class Intent implements Parcelable, Cloneable { * party applications because a newly initialized user does not have any * third party applications installed for it.) This is sent early in * starting the user, around the time the home app is started, before * {@link #ACTION_BOOT_COMPLETED} is sent. * {@link #ACTION_BOOT_COMPLETED} is sent. This is sent as a foreground * broadcast, since it is part of a visible user interaction; be as quick * as possible when handling it. */ public static final String ACTION_USER_INITIALIZE = "android.intent.action.USER_INITIALIZE"; Loading @@ -2337,7 +2339,9 @@ public class Intent implements Parcelable, Cloneable { * brought to the foreground. This is only sent to receivers registered * through {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) * Context.registerReceiver}. It is sent to the user that is going to the * foreground. * foreground. This is sent as a foreground * broadcast, since it is part of a visible user interaction; be as quick * as possible when handling it. */ public static final String ACTION_USER_FOREGROUND = "android.intent.action.USER_FOREGROUND"; Loading @@ -2347,14 +2351,17 @@ public class Intent implements Parcelable, Cloneable { * sent to the background. This is only sent to receivers registered * through {@link Context#registerReceiver(BroadcastReceiver, IntentFilter) * Context.registerReceiver}. It is sent to the user that is going to the * background. * background. This is sent as a foreground * broadcast, since it is part of a visible user interaction; be as quick * as possible when handling it. */ public static final String ACTION_USER_BACKGROUND = "android.intent.action.USER_BACKGROUND"; /** * Broadcast sent to the system when a user is added. Carries an extra EXTRA_USER_HANDLE that has the * userHandle of the new user. It is sent to all running users. You must hold * Broadcast sent to the system when a user is added. Carries an extra * EXTRA_USER_HANDLE that has the userHandle of the new user. It is sent to * all running users. You must hold * {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast. * @hide */ Loading @@ -2362,22 +2369,59 @@ public class Intent implements Parcelable, Cloneable { "android.intent.action.USER_ADDED"; /** * Broadcast sent to the system when a user is started. Carries an extra EXTRA_USER_HANDLE that has * the userHandle of the user. This is only sent to * Broadcast sent by the system when a user is started. Carries an extra * EXTRA_USER_HANDLE that has the userHandle of the user. This is only sent to * registered receivers, not manifest receivers. It is sent to the user * that has been started. * that has been started. This is sent as a foreground * broadcast, since it is part of a visible user interaction; be as quick * as possible when handling it. * @hide */ public static final String ACTION_USER_STARTED = "android.intent.action.USER_STARTED"; /** * Broadcast sent to the system when a user is stopped. Carries an extra EXTRA_USER_HANDLE that has * the userHandle of the user. This is similar to {@link #ACTION_PACKAGE_RESTARTED}, * but for an entire user instead of a specific package. This is only sent to * registered receivers, not manifest receivers. It is sent to all running * users <em>except</em> the one that has just been stopped (which is no * longer running). * Broadcast sent when a user is in the process of starting. Carries an extra * EXTRA_USER_HANDLE that has the userHandle of the user. This is only * sent to registered receivers, not manifest receivers. It is sent to all * users (including the one that is being started). You must hold * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} to receive * this broadcast. This is sent as a background broadcast, since * its result is not part of the primary UX flow; to safely keep track of * started/stopped state of a user you can use this in conjunction with * {@link #ACTION_USER_STOPPING}. It is <b>not</b> generally safe to use with * other user state broadcasts since those are foreground broadcasts so can * execute in a different order. * @hide */ public static final String ACTION_USER_STARTING = "android.intent.action.USER_STARTING"; /** * Broadcast sent when a user is going to be stopped. Carries an extra * EXTRA_USER_HANDLE that has the userHandle of the user. This is only * sent to registered receivers, not manifest receivers. It is sent to all * users (including the one that is being stopped). You must hold * {@link android.Manifest.permission#INTERACT_ACROSS_USERS} to receive * this broadcast. The user will not stop until all receivers have * handled the broadcast. This is sent as a background broadcast, since * its result is not part of the primary UX flow; to safely keep track of * started/stopped state of a user you can use this in conjunction with * {@link #ACTION_USER_STARTING}. It is <b>not</b> generally safe to use with * other user state broadcasts since those are foreground broadcasts so can * execute in a different order. * @hide */ public static final String ACTION_USER_STOPPING = "android.intent.action.USER_STOPPING"; /** * Broadcast sent to the system when a user is stopped. Carries an extra * EXTRA_USER_HANDLE that has the userHandle of the user. This is similar to * {@link #ACTION_PACKAGE_RESTARTED}, but for an entire user instead of a * specific package. This is only sent to registered receivers, not manifest * receivers. It is sent to all running users <em>except</em> the one that * has just been stopped (which is no longer running). * @hide */ public static final String ACTION_USER_STOPPED = Loading
core/res/res/anim/wallpaper_enter.xml +2 −0 Original line number Diff line number Diff line Loading @@ -19,10 +19,12 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@interpolator/decelerate_quad"> <!-- Having trouble avoiding this when switching users, so simple fade for now <scale android:fromXScale="3.0" android:toXScale="1.0" android:fromYScale="3.0" android:toYScale="1.0" android:pivotX="50%" android:pivotY="50%" android:duration="@android:integer/config_longAnimTime" /> --> <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="@android:integer/config_longAnimTime" /> </set> No newline at end of file
core/res/res/anim/wallpaper_exit.xml +2 −0 Original line number Diff line number Diff line Loading @@ -19,10 +19,12 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@interpolator/accelerate_quad"> <!-- Having trouble avoiding this when switching users, so simple fade for now <scale android:fromXScale="1.0" android:toXScale="3.0" android:fromYScale="1.0" android:toYScale="3.0" android:pivotX="50%" android:pivotY="50%" android:duration="@android:integer/config_longAnimTime" /> --> <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="@android:integer/config_longAnimTime"/> </set> No newline at end of file
services/java/com/android/server/am/ActivityManagerService.java +70 −14 Original line number Diff line number Diff line Loading @@ -3741,8 +3741,7 @@ public final class ActivityManagerService extends ActivityManagerNative private void forceStopUserLocked(int userId) { forceStopPackageLocked(null, -1, false, false, true, false, userId); Intent intent = new Intent(Intent.ACTION_USER_STOPPED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, Loading Loading @@ -14130,6 +14129,19 @@ public final class ActivityManagerService extends ActivityManagerNative final UserStartedState uss = mStartedUsers.get(userId); // Make sure user is in the started state. If it is currently // stopping, we need to knock that off. if (uss.mState == UserStartedState.STATE_STOPPING) { // If we are stopping, we haven't sent ACTION_SHUTDOWN, // so we can just fairly silently bring the user back from // the almost-dead. uss.mState = UserStartedState.STATE_RUNNING; } else if (uss.mState == UserStartedState.STATE_SHUTDOWN) { // This means ACTION_SHUTDOWN has been sent, so we will // need to treat this as a new boot of the user. uss.mState = UserStartedState.STATE_BOOTING; } mHandler.removeMessages(REPORT_USER_SWITCH_MSG); mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG); mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG, Loading Loading @@ -14207,6 +14219,19 @@ public final class ActivityManagerService extends ActivityManagerNative null, null, 0, null, null, android.Manifest.permission.MANAGE_USERS, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); intent = new Intent(Intent.ACTION_USER_STARTING); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId); broadcastIntentLocked(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) throws RemoteException { } }, 0, null, null, android.Manifest.permission.INTERACT_ACROSS_USERS, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } } finally { Binder.restoreCallingIdentity(ident); Loading Loading @@ -14295,7 +14320,8 @@ public final class ActivityManagerService extends ActivityManagerNative void finishUserSwitch(UserStartedState uss) { synchronized (this) { if (uss.mState == UserStartedState.STATE_BOOTING if ((uss.mState == UserStartedState.STATE_BOOTING || uss.mState == UserStartedState.STATE_SHUTDOWN) && mStartedUsers.get(uss.mHandle.getIdentifier()) == uss) { uss.mState = UserStartedState.STATE_RUNNING; final int userId = uss.mHandle.getIdentifier(); Loading @@ -14317,7 +14343,8 @@ public final class ActivityManagerService extends ActivityManagerNative num--; continue; } if (oldUss.mState == UserStartedState.STATE_STOPPING) { if (oldUss.mState == UserStartedState.STATE_STOPPING || oldUss.mState == UserStartedState.STATE_SHUTDOWN) { // This user is already stopping, doesn't count. num--; i++; Loading Loading @@ -14382,23 +14409,50 @@ public final class ActivityManagerService extends ActivityManagerNative uss.mStopCallbacks.add(callback); } if (uss.mState != UserStartedState.STATE_STOPPING) { if (uss.mState != UserStartedState.STATE_STOPPING && uss.mState != UserStartedState.STATE_SHUTDOWN) { uss.mState = UserStartedState.STATE_STOPPING; long ident = Binder.clearCallingIdentity(); try { // Inform of user switch Intent intent = new Intent(Intent.ACTION_SHUTDOWN); final IIntentReceiver resultReceiver = new IIntentReceiver.Stub() { // We are going to broadcast ACTION_USER_STOPPING and then // once that is down send a final ACTION_SHUTDOWN and then // stop the user. final Intent stoppingIntent = new Intent(Intent.ACTION_USER_STOPPING); stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); stoppingIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN); // This is the result receiver for the final shutdown broadcast. final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() { @Override public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { finishUserStop(uss); } }; broadcastIntentLocked(null, null, intent, null, resultReceiver, 0, null, null, null, // This is the result receiver for the initial stopping broadcast. final IIntentReceiver stoppingReceiver = new IIntentReceiver.Stub() { @Override public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { // On to the next. synchronized (ActivityManagerService.this) { if (uss.mState != UserStartedState.STATE_STOPPING) { // Whoops, we are being started back up. Abort, abort! return; } uss.mState = UserStartedState.STATE_SHUTDOWN; } broadcastIntentLocked(null, null, shutdownIntent, null, shutdownReceiver, 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID, userId); } }; // Kick things off. broadcastIntentLocked(null, null, stoppingIntent, null, stoppingReceiver, 0, null, null, android.Manifest.permission.INTERACT_ACROSS_USERS, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } finally { Binder.restoreCallingIdentity(ident); } Loading @@ -14413,8 +14467,9 @@ public final class ActivityManagerService extends ActivityManagerNative ArrayList<IStopUserCallback> callbacks; synchronized (this) { callbacks = new ArrayList<IStopUserCallback>(uss.mStopCallbacks); if (uss.mState != UserStartedState.STATE_STOPPING || mStartedUsers.get(userId) != uss) { if (mStartedUsers.get(userId) != uss) { stopped = false; } else if (uss.mState != UserStartedState.STATE_SHUTDOWN) { stopped = false; } else { stopped = true; Loading Loading @@ -14478,7 +14533,8 @@ public final class ActivityManagerService extends ActivityManagerNative boolean isUserRunningLocked(int userId) { UserStartedState state = mStartedUsers.get(userId); return state != null && state.mState != UserStartedState.STATE_STOPPING; return state != null && state.mState != UserStartedState.STATE_STOPPING && state.mState != UserStartedState.STATE_SHUTDOWN; } @Override
services/java/com/android/server/am/UserStartedState.java +13 −1 Original line number Diff line number Diff line Loading @@ -23,9 +23,14 @@ import android.app.IStopUserCallback; import android.os.UserHandle; public class UserStartedState { // User is first coming up. public final static int STATE_BOOTING = 0; // User is in the normal running state. public final static int STATE_RUNNING = 1; // User is in the initial process of being stopped. public final static int STATE_STOPPING = 2; // User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN. public final static int STATE_SHUTDOWN = 3; public final UserHandle mHandle; public final ArrayList<IStopUserCallback> mStopCallbacks Loading @@ -40,7 +45,14 @@ public class UserStartedState { } void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("mState="); pw.print(mState); pw.print(prefix); pw.print("mState="); switch (mState) { case STATE_BOOTING: pw.print("BOOTING"); break; case STATE_RUNNING: pw.print("RUNNING"); break; case STATE_STOPPING: pw.print("STOPPING"); break; case STATE_SHUTDOWN: pw.print("SHUTDOWN"); break; default: pw.print(mState); break; } if (switching) pw.print(" SWITCHING"); if (initializing) pw.print(" INITIALIZING"); pw.println(); Loading