diff options
| author | 2015-12-03 21:05:17 +0000 | |
|---|---|---|
| committer | 2015-12-03 21:05:17 +0000 | |
| commit | 8b4fce4bac9daf813a990cf0c199d39e655b3f9c (patch) | |
| tree | a63b164b1e3607fa6ca9abd685198b81c44978bc | |
| parent | 07c289d183b64cb38312b3c4bebf5d5fb25b951b (diff) | |
| parent | bedbaa9ea6e41eaa34a35098c913c096ddf2ce0f (diff) | |
Merge "Flesh out user locked/unlocked lifecycle."
| -rw-r--r-- | api/current.txt | 1 | ||||
| -rw-r--r-- | api/system-current.txt | 1 | ||||
| -rw-r--r-- | api/test-current.txt | 1 | ||||
| -rw-r--r-- | core/java/android/content/Intent.java | 19 | ||||
| -rw-r--r-- | services/core/java/com/android/server/SystemService.java | 9 | ||||
| -rw-r--r-- | services/core/java/com/android/server/SystemServiceManager.java | 13 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/ActivityManagerService.java | 5 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/UserController.java | 170 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/UserState.java | 55 |
9 files changed, 195 insertions, 79 deletions
diff --git a/api/current.txt b/api/current.txt index 851cf4dd6c9e..8cd6fd7eacba 100644 --- a/api/current.txt +++ b/api/current.txt @@ -8286,6 +8286,7 @@ package android.content { field public static final java.lang.String ACTION_INSERT_OR_EDIT = "android.intent.action.INSERT_OR_EDIT"; field public static final java.lang.String ACTION_INSTALL_PACKAGE = "android.intent.action.INSTALL_PACKAGE"; field public static final java.lang.String ACTION_LOCALE_CHANGED = "android.intent.action.LOCALE_CHANGED"; + field public static final java.lang.String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED"; field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN"; field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED"; field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED"; diff --git a/api/system-current.txt b/api/system-current.txt index 77a5c920b958..3f8738f2d747 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -8543,6 +8543,7 @@ package android.content { field public static final java.lang.String ACTION_INSTALL_PACKAGE = "android.intent.action.INSTALL_PACKAGE"; field public static final java.lang.String ACTION_INTENT_FILTER_NEEDS_VERIFICATION = "android.intent.action.INTENT_FILTER_NEEDS_VERIFICATION"; field public static final java.lang.String ACTION_LOCALE_CHANGED = "android.intent.action.LOCALE_CHANGED"; + field public static final java.lang.String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED"; field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN"; field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED"; field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED"; diff --git a/api/test-current.txt b/api/test-current.txt index af9270420182..8b5e646d43a3 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -8286,6 +8286,7 @@ package android.content { field public static final java.lang.String ACTION_INSERT_OR_EDIT = "android.intent.action.INSERT_OR_EDIT"; field public static final java.lang.String ACTION_INSTALL_PACKAGE = "android.intent.action.INSTALL_PACKAGE"; field public static final java.lang.String ACTION_LOCALE_CHANGED = "android.intent.action.LOCALE_CHANGED"; + field public static final java.lang.String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED"; field public static final java.lang.String ACTION_MAIN = "android.intent.action.MAIN"; field public static final java.lang.String ACTION_MANAGED_PROFILE_ADDED = "android.intent.action.MANAGED_PROFILE_ADDED"; field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED"; diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 2178c38efd44..b65d825b70a9 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1926,6 +1926,24 @@ public class Intent implements Parcelable, Cloneable { */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_ALARM_CHANGED = "android.intent.action.ALARM_CHANGED"; + + /** + * Broadcast Action: This is broadcast once, after the system has finished + * booting and the user is in a "locked" state. A user is locked when their + * credential-encrypted private app data storage is unavailable. Once the + * user has entered their credentials (such as a lock pattern or PIN) for + * the first time, the {@link #ACTION_BOOT_COMPLETED} broadcast will be + * sent. + * <p> + * You must hold the + * {@link android.Manifest.permission#RECEIVE_BOOT_COMPLETED} permission in + * order to receive this broadcast. + * <p class="note"> + * This is a protected intent that can only be sent by the system. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_LOCKED_BOOT_COMPLETED = "android.intent.action.LOCKED_BOOT_COMPLETED"; + /** * Broadcast Action: This is broadcast once, after the system has finished * booting. It can be used to perform application-specific initialization, @@ -1938,6 +1956,7 @@ public class Intent implements Parcelable, Cloneable { */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; + /** * Broadcast Action: This is broadcast when a user action should request a * temporary system dialog to dismiss. Some examples of temporary system diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java index e0a9ab443450..ce3166d006f9 100644 --- a/services/core/java/com/android/server/SystemService.java +++ b/services/core/java/com/android/server/SystemService.java @@ -133,6 +133,15 @@ public abstract class SystemService { public void onStartUser(int userHandle) {} /** + * Called when an existing user is unlocked. This means the + * credential-encrypted storage for that user is now available, and + * encryption-aware component filtering is no longer in effect. + * + * @param userHandle The identifier of the user. + */ + public void onUnlockUser(int userHandle) {} + + /** * Called when switching to a different foreground user, for system services that have * special behavior for whichever user is currently in the foreground. This is called * before any application processes are aware of the new user. diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java index 92e6814c42d1..ecc69e90b7a3 100644 --- a/services/core/java/com/android/server/SystemServiceManager.java +++ b/services/core/java/com/android/server/SystemServiceManager.java @@ -165,6 +165,19 @@ public class SystemServiceManager { } } + public void unlockUser(final int userHandle) { + final int serviceLen = mServices.size(); + for (int i = 0; i < serviceLen; i++) { + final SystemService service = mServices.get(i); + try { + service.onUnlockUser(userHandle); + } catch (Exception ex) { + Slog.wtf(TAG, "Failure reporting unlock of user " + userHandle + + " to service " + service.getClass().getName(), ex); + } + } + } + public void switchUser(final int userHandle) { final int serviceLen = mServices.size(); for (int i = 0; i < serviceLen; i++) { diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index ef623ebfb57d..b769d39b8e53 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1487,6 +1487,7 @@ public final class ActivityManagerService extends ActivityManagerNative static final int APP_BOOST_DEACTIVATE_MSG = 58; static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG = 59; static final int IDLE_UIDS_MSG = 60; + static final int SYSTEM_USER_UNLOCK_MSG = 61; static final int FIRST_ACTIVITY_STACK_MSG = 100; static final int FIRST_BROADCAST_QUEUE_MSG = 200; @@ -1989,6 +1990,10 @@ public final class ActivityManagerService extends ActivityManagerNative mSystemServiceManager.startUser(msg.arg1); break; } + case SYSTEM_USER_UNLOCK_MSG: { + mSystemServiceManager.unlockUser(msg.arg1); + break; + } case SYSTEM_USER_CURRENT_MSG: { mBatteryStatsService.noteEvent( BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_FINISH, diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 3e0ae1785faa..195465c96a31 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -34,6 +34,7 @@ import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_CO import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_MSG; import static com.android.server.am.ActivityManagerService.SYSTEM_USER_CURRENT_MSG; import static com.android.server.am.ActivityManagerService.SYSTEM_USER_START_MSG; +import static com.android.server.am.ActivityManagerService.SYSTEM_USER_UNLOCK_MSG; import static com.android.server.am.ActivityManagerService.USER_SWITCH_TIMEOUT_MSG; import android.annotation.NonNull; @@ -147,7 +148,6 @@ final class UserController { // User 0 is the first and only user that runs at boot. final UserState uss = new UserState(UserHandle.SYSTEM); mStartedUsers.put(UserHandle.USER_SYSTEM, uss); - updateUserUnlockedState(uss); mUserLru.add(UserHandle.USER_SYSTEM); updateStartedUserArrayLocked(); } @@ -173,8 +173,8 @@ final class UserController { num--; continue; } - if (oldUss.mState == UserState.STATE_STOPPING - || oldUss.mState == UserState.STATE_SHUTDOWN) { + if (oldUss.state == UserState.STATE_STOPPING + || oldUss.state == UserState.STATE_SHUTDOWN) { // This user is already stopping, doesn't count. num--; i++; @@ -199,17 +199,65 @@ final class UserController { } void finishUserBoot(UserState uss) { + finishUserBoot(uss, null); + } + + void finishUserBoot(UserState uss, IIntentReceiver resultTo) { + final int userId = uss.mHandle.getIdentifier(); synchronized (mService) { - if (uss.mState == UserState.STATE_BOOTING - && mStartedUsers.get(uss.mHandle.getIdentifier()) == uss) { - uss.mState = UserState.STATE_RUNNING; - final int userId = uss.mHandle.getIdentifier(); - Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null); + // Bail if we ended up with a stale user + if (mStartedUsers.get(userId) != uss) return; + + // We always walk through all the user lifecycle states to send + // consistent developer events. We step into RUNNING_LOCKED here, + // but we might immediately step into RUNNING below if the user + // storage is already unlocked. + if (uss.state == UserState.STATE_BOOTING) { + uss.setState(UserState.STATE_RUNNING_LOCKED); + + Intent intent = new Intent(Intent.ACTION_LOCKED_BOOT_COMPLETED, null); intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); - mService.broadcastIntentLocked(null, null, intent, - null, null, 0, null, null, - new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED}, + mService.broadcastIntentLocked(null, null, intent, null, resultTo, 0, null, null, + new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED }, + AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId); + } + + maybeFinishUserUnlock(uss); + } + } + + /** + * Consider stepping from {@link UserState#STATE_RUNNING_LOCKED} into + * {@link UserState#STATE_RUNNING}, which only occurs if the user storage is + * actually unlocked. + */ + void maybeFinishUserUnlock(UserState uss) { + final int userId = uss.mHandle.getIdentifier(); + synchronized (mService) { + // Bail if we ended up with a stale user + if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return; + + // Only keep marching forward if user is actually unlocked + if (!isUserKeyUnlocked(userId)) return; + + if (uss.state == UserState.STATE_RUNNING_LOCKED) { + uss.setState(UserState.STATE_RUNNING); + + mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0)); + + final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED); + unlockedIntent.addFlags( + Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); + mService.broadcastIntentLocked(null, null, unlockedIntent, null, null, 0, null, + null, null, AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID, + userId); + + final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null); + bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); + mService.broadcastIntentLocked(null, null, bootIntent, null, null, 0, null, null, + new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED }, AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId); } } @@ -291,9 +339,9 @@ final class UserController { uss.mStopCallbacks.add(callback); } - if (uss.mState != UserState.STATE_STOPPING - && uss.mState != UserState.STATE_SHUTDOWN) { - uss.mState = UserState.STATE_STOPPING; + if (uss.state != UserState.STATE_STOPPING + && uss.state != UserState.STATE_SHUTDOWN) { + uss.setState(UserState.STATE_STOPPING); updateStartedUserArrayLocked(); long ident = Binder.clearCallingIdentity(); @@ -321,11 +369,11 @@ final class UserController { Bundle extras, boolean ordered, boolean sticky, int sendingUser) { // On to the next. synchronized (mService) { - if (uss.mState != UserState.STATE_STOPPING) { + if (uss.state != UserState.STATE_STOPPING) { // Whoops, we are being started back up. Abort, abort! return; } - uss.mState = UserState.STATE_SHUTDOWN; + uss.setState(UserState.STATE_SHUTDOWN); } mService.mBatteryStatsService.noteEvent( BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH, @@ -355,7 +403,7 @@ final class UserController { callbacks = new ArrayList<>(uss.mStopCallbacks); if (mStartedUsers.get(userId) != uss) { stopped = false; - } else if (uss.mState != UserState.STATE_SHUTDOWN) { + } else if (uss.state != UserState.STATE_SHUTDOWN) { stopped = false; } else { stopped = true; @@ -438,8 +486,8 @@ final class UserController { Integer oldUserId = mUserLru.get(i); UserState oldUss = mStartedUsers.get(oldUserId); if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId - || oldUss.mState == UserState.STATE_STOPPING - || oldUss.mState == UserState.STATE_SHUTDOWN) { + || oldUss.state == UserState.STATE_STOPPING + || oldUss.state == UserState.STATE_SHUTDOWN) { continue; } UserInfo userInfo = getUserInfo(oldUserId); @@ -482,18 +530,18 @@ final class UserController { return userManager; } - private void updateUserUnlockedState(UserState uss) { + private boolean isUserKeyUnlocked(int userId) { final IMountService mountService = IMountService.Stub .asInterface(ServiceManager.getService("mount")); if (mountService != null) { try { - uss.unlocked = mountService.isUserKeyUnlocked(uss.mHandle.getIdentifier()); + return mountService.isUserKeyUnlocked(userId); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } } else { - // System isn't fully booted yet, so guess based on property - uss.unlocked = !StorageManager.isFileBasedEncryptionEnabled(); + Slog.w(TAG, "Mount service not published; guessing locked state based on property"); + return !StorageManager.isFileBasedEncryptionEnabled(); } } @@ -547,8 +595,6 @@ final class UserController { } final UserState uss = mStartedUsers.get(userId); - updateUserUnlockedState(uss); - final Integer userIdInt = userId; mUserLru.remove(userIdInt); mUserLru.add(userIdInt); @@ -572,22 +618,22 @@ final class UserController { // Make sure user is in the started state. If it is currently // stopping, we need to knock that off. - if (uss.mState == UserState.STATE_STOPPING) { + if (uss.state == UserState.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 = UserState.STATE_RUNNING; + uss.setState(uss.lastState); updateStartedUserArrayLocked(); needStart = true; - } else if (uss.mState == UserState.STATE_SHUTDOWN) { + } else if (uss.state == UserState.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 = UserState.STATE_BOOTING; + uss.setState(UserState.STATE_BOOTING); updateStartedUserArrayLocked(); needStart = true; } - if (uss.mState == UserState.STATE_BOOTING) { + if (uss.state == UserState.STATE_BOOTING) { // Let user manager propagate user restrictions to other services. getUserManager().onBeforeStartUser(userId); @@ -699,11 +745,9 @@ final class UserController { boolean unlockUserCleared(final int userId, byte[] token) { synchronized (mService) { + // Bail if already running unlocked final UserState uss = mStartedUsers.get(userId); - if (uss.unlocked) { - // Bail early when already unlocked - return true; - } + if (uss.state == UserState.STATE_RUNNING) return true; } final UserInfo userInfo = getUserInfo(userId); @@ -718,14 +762,9 @@ final class UserController { synchronized (mService) { final UserState uss = mStartedUsers.get(userId); - updateUserUnlockedState(uss); + maybeFinishUserUnlock(uss); } - final Intent intent = new Intent(Intent.ACTION_USER_UNLOCKED); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND); - mService.broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, - AppOpsManager.OP_NONE, null, false, false, MY_PID, SYSTEM_UID, userId); - return true; } @@ -1045,8 +1084,8 @@ final class UserController { for (int i = 0; i < mStartedUsers.size(); i++) { UserState uss = mStartedUsers.valueAt(i); // This list does not include stopping users. - if (uss.mState != UserState.STATE_STOPPING - && uss.mState != UserState.STATE_SHUTDOWN) { + if (uss.state != UserState.STATE_STOPPING + && uss.state != UserState.STATE_SHUTDOWN) { num++; } } @@ -1054,8 +1093,8 @@ final class UserController { num = 0; for (int i = 0; i < mStartedUsers.size(); i++) { UserState uss = mStartedUsers.valueAt(i); - if (uss.mState != UserState.STATE_STOPPING - && uss.mState != UserState.STATE_SHUTDOWN) { + if (uss.state != UserState.STATE_STOPPING + && uss.state != UserState.STATE_SHUTDOWN) { mStartedUserArray[num] = mStartedUsers.keyAt(i); num++; } @@ -1065,17 +1104,7 @@ final class UserController { void sendBootCompletedLocked(IIntentReceiver resultTo) { for (int i = 0; i < mStartedUsers.size(); i++) { UserState uss = mStartedUsers.valueAt(i); - if (uss.mState == UserState.STATE_BOOTING) { - uss.mState = UserState.STATE_RUNNING; - final int userId = mStartedUsers.keyAt(i); - Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null); - intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); - intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); - mService.broadcastIntentLocked(null, null, intent, null, - resultTo, 0, null, null, - new String[] {android.Manifest.permission.RECEIVE_BOOT_COMPLETED}, - AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId); - } + finishUserBoot(uss, resultTo); } } @@ -1117,14 +1146,33 @@ final class UserController { if ((flags & ActivityManager.FLAG_OR_STOPPED) != 0) { return true; } - if ((flags & ActivityManager.FLAG_AND_LOCKED) != 0 && state.unlocked) { - return false; + + final boolean unlocked; + switch (state.state) { + case UserState.STATE_STOPPING: + case UserState.STATE_SHUTDOWN: + default: + return false; + + case UserState.STATE_BOOTING: + case UserState.STATE_RUNNING_LOCKED: + unlocked = false; + break; + + case UserState.STATE_RUNNING: + unlocked = true; + break; } - if ((flags & ActivityManager.FLAG_AND_UNLOCKED) != 0 && !state.unlocked) { - return false; + + if ((flags & ActivityManager.FLAG_AND_LOCKED) != 0) { + return !unlocked; + } + if ((flags & ActivityManager.FLAG_AND_UNLOCKED) != 0) { + return unlocked; } - return state.mState != UserState.STATE_STOPPING - && state.mState != UserState.STATE_SHUTDOWN; + + // One way or another, we're running! + return true; } UserInfo getCurrentUser() { diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java index b5b5c1d06f6f..7b18a1783aae 100644 --- a/services/core/java/com/android/server/am/UserState.java +++ b/services/core/java/com/android/server/am/UserState.java @@ -19,28 +19,37 @@ package com.android.server.am; import java.io.PrintWriter; import java.util.ArrayList; +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; + import android.app.IStopUserCallback; import android.os.UserHandle; import android.util.ArrayMap; +import android.util.Slog; public final class UserState { + private static final String TAG = TAG_WITH_CLASS_NAME ? "UserState" : TAG_AM; + // User is first coming up. public final static int STATE_BOOTING = 0; + // User is in the locked running state. + public final static int STATE_RUNNING_LOCKED = 1; // User is in the normal running state. - public final static int STATE_RUNNING = 1; + public final static int STATE_RUNNING = 2; // User is in the initial process of being stopped. - public final static int STATE_STOPPING = 2; + public final static int STATE_STOPPING = 3; // User is in the final phase of stopping, sending Intent.ACTION_SHUTDOWN. - public final static int STATE_SHUTDOWN = 3; + public final static int STATE_SHUTDOWN = 4; public final UserHandle mHandle; public final ArrayList<IStopUserCallback> mStopCallbacks = new ArrayList<IStopUserCallback>(); - public int mState = STATE_BOOTING; + public int state = STATE_BOOTING; + public int lastState = STATE_BOOTING; public boolean switching; public boolean initializing; - public boolean unlocked; /** * The last time that a provider was reported to usage stats as being brought to important @@ -52,22 +61,32 @@ public final class UserState { mHandle = handle; } - void dump(String prefix, PrintWriter pw) { - 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; + public void setState(int newState) { + if (DEBUG_MU) { + Slog.i(TAG, "User " + mHandle.getIdentifier() + " state changed from " + + stateToString(state) + " to " + stateToString(newState)); + } + lastState = state; + state = newState; + } + + private static String stateToString(int state) { + switch (state) { + case STATE_BOOTING: return "BOOTING"; + case STATE_RUNNING_LOCKED: return "RUNNING_LOCKED"; + case STATE_RUNNING: return "RUNNING"; + case STATE_STOPPING: return "STOPPING"; + case STATE_SHUTDOWN: return "SHUTDOWN"; + default: return Integer.toString(state); } + } + + void dump(String prefix, PrintWriter pw) { + pw.print(prefix); + pw.print("state="); pw.print(stateToString(state)); + pw.print(" lastState="); pw.print(stateToString(lastState)); if (switching) pw.print(" SWITCHING"); if (initializing) pw.print(" INITIALIZING"); - if (unlocked) { - pw.print(" UNLOCKED"); - } else { - pw.print(" LOCKED"); - } pw.println(); } } |