Start implementing concept of "running" users.
The activity manager now keeps track of which users are running.
Initially, only user 0 is running.
When you switch to another user, that user is started so it is
running. It is only at this point that BOOT_COMPLETED is sent
for that user and it is allowed to execute anything.
You can stop any user except user 0, which brings it back to the
same state as when you first boot the device. This is also used
to be able to more cleaning delete a user, by first stopping it
before removing its data.
There is a new broadcast ACTION_USER_STOPPED sent when a user is
stopped; system services need to handle this like they currently
handle ACTION_PACKAGE_RESTARTED when individual packages are
restarted.
Change-Id: I89adbd7cbaf4a0bb72ea201385f93477f40a4119
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index ccea41a..a389edc2 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -211,7 +211,10 @@
*/
final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible
= new ArrayList<IActivityManager.WaitResult>();
-
+
+ final ArrayList<UserStartedState> mStartingUsers
+ = new ArrayList<UserStartedState>();
+
/**
* Set when the system is going to sleep, until we have
* successfully paused the current activity and released our wake lock.
@@ -1397,7 +1400,7 @@
// Launcher...
if (mMainStack) {
ActivityOptions.abort(options);
- return mService.startHomeActivityLocked(0);
+ return mService.startHomeActivityLocked(0, null);
}
}
@@ -1427,7 +1430,16 @@
ActivityOptions.abort(options);
return false;
}
-
+
+ // Make sure that the user who owns this activity is started. If not,
+ // we will just leave it as is because someone should be bringing
+ // another user's activities to the top of the stack.
+ if (mService.mStartedUsers.get(next.userId) == null) {
+ Slog.w(TAG, "Skipping resume of top activity " + next
+ + ": user " + next.userId + " is stopped");
+ return false;
+ }
+
// The activity may be waiting for stop, but that is no longer
// appropriate for it.
mStoppingActivities.remove(next);
@@ -1494,7 +1506,7 @@
Slog.d(TAG, "no-history finish of " + last + " on new resume");
}
requestFinishActivityLocked(last.appToken, Activity.RESULT_CANCELED, null,
- "no-history");
+ "no-history");
}
}
@@ -3414,6 +3426,7 @@
ArrayList<ActivityRecord> stops = null;
ArrayList<ActivityRecord> finishes = null;
ArrayList<ActivityRecord> thumbnails = null;
+ ArrayList<UserStartedState> startingUsers = null;
int NS = 0;
int NF = 0;
int NT = 0;
@@ -3495,6 +3508,10 @@
booting = mService.mBooting;
mService.mBooting = false;
}
+ if (mStartingUsers.size() > 0) {
+ startingUsers = new ArrayList<UserStartedState>(mStartingUsers);
+ mStartingUsers.clear();
+ }
}
int i;
@@ -3539,6 +3556,10 @@
if (booting) {
mService.finishBooting();
+ } else if (startingUsers != null) {
+ for (i=0; i<startingUsers.size(); i++) {
+ mService.finishUserSwitch(startingUsers.get(i));
+ }
}
mService.trimApplications();
@@ -3556,6 +3577,10 @@
return res;
}
+ final void addStartingUserLocked(UserStartedState uss) {
+ mStartingUsers.add(uss);
+ }
+
/**
* @return Returns true if the activity is being finished, false if for
* some reason it is being left as-is.