Flesh out user locked/unlocked lifecycle.

When a user is first started, we assume that they're "locked" meaning
that credential-encrypted data is unavailable.  Once credentials have
been supplied, we can transition the user to a fully running state.

To facilitate this lifecycle, UserState now has two separate
RUNNING_LOCKED and RUNNING states.  To ensure consistent events are
sent on all devices, we always step through RUNNING_LOCKED before
arriving at RUNNING.  This consistency means that apps processing
data based on the new ACTION_LOCKED_BOOT_COMPLETED broadcast and
system services using the new onUnlockUser() event will be less
bug-prone over time.

If the user storage is unlocked (which is the case on the majority
of legacy devices), we immediately transition from the RUNNING_LOCKED
into the RUNNING state.

Add logging for all state transitions.

When we "recover" a user in the process of being shut down, return
to the last known state.

Bug: 25943941
Change-Id: I5fec980f10b0d0fb2c272a662d193dc15136f9b9
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index b5b5c1d..7b18a17 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 @@
 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 @@
         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();
     }
 }