summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server')
-rw-r--r--services/java/com/android/server/WallpaperManagerService.java168
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java329
-rwxr-xr-xservices/java/com/android/server/am/ActivityStack.java59
-rw-r--r--services/java/com/android/server/pm/UserManagerService.java84
-rwxr-xr-xservices/java/com/android/server/wm/WindowManagerService.java1
5 files changed, 459 insertions, 182 deletions
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index a807f4c..b027c1f 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -16,10 +16,11 @@
package com.android.server;
-import static android.os.FileObserver.*;
import static android.os.ParcelFileDescriptor.*;
+import android.app.ActivityManagerNative;
import android.app.AppGlobals;
+import android.app.IUserSwitchObserver;
import android.app.IWallpaperManager;
import android.app.IWallpaperManagerCallback;
import android.app.PendingIntent;
@@ -43,6 +44,7 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
import android.os.IBinder;
+import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.os.FileObserver;
import android.os.ParcelFileDescriptor;
@@ -79,7 +81,6 @@ import org.xmlpull.v1.XmlSerializer;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
-import com.android.server.am.ActivityManagerService;
class WallpaperManagerService extends IWallpaperManager.Stub {
static final String TAG = "WallpaperService";
@@ -136,7 +137,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
mWallpaper.imageWallpaperPending = false;
}
bindWallpaperComponentLocked(mWallpaper.imageWallpaperComponent, true,
- false, mWallpaper);
+ false, mWallpaper, null);
saveSettingsLocked(mWallpaper);
}
}
@@ -214,12 +215,14 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
IWallpaperService mService;
IWallpaperEngine mEngine;
WallpaperData mWallpaper;
+ IRemoteCallback mReply;
public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
mInfo = info;
mWallpaper = wallpaper;
}
-
+
+ @Override
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mLock) {
if (mWallpaper.connection == this) {
@@ -235,6 +238,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
+ @Override
public void onServiceDisconnected(ComponentName name) {
synchronized (mLock) {
mService = null;
@@ -246,16 +250,35 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
> SystemClock.uptimeMillis()
&& mWallpaper.userId == mCurrentUserId) {
Slog.w(TAG, "Reverting to built-in wallpaper!");
- clearWallpaperLocked(true, mWallpaper.userId);
+ clearWallpaperLocked(true, mWallpaper.userId, null);
}
}
}
}
+ @Override
public void attachEngine(IWallpaperEngine engine) {
- mEngine = engine;
+ synchronized (mLock) {
+ mEngine = engine;
+ }
+ }
+
+ @Override
+ public void engineShown(IWallpaperEngine engine) {
+ synchronized (mLock) {
+ if (mReply != null) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ mReply.sendResult(null);
+ } catch (RemoteException e) {
+ Binder.restoreCallingIdentity(ident);
+ }
+ mReply = null;
+ }
+ }
}
+ @Override
public ParcelFileDescriptor setWallpaper(String name) {
synchronized (mLock) {
if (mWallpaper.connection == this) {
@@ -279,9 +302,10 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
clearWallpaperComponentLocked(wallpaper);
// Do this only for the current user's wallpaper
if (wallpaper.userId == mCurrentUserId
- && !bindWallpaperComponentLocked(comp, false, false, wallpaper)) {
+ && !bindWallpaperComponentLocked(comp, false, false,
+ wallpaper, null)) {
Slog.w(TAG, "Wallpaper no longer available; reverting to default");
- clearWallpaperLocked(false, wallpaper.userId);
+ clearWallpaperLocked(false, wallpaper.userId, null);
}
}
}
@@ -349,7 +373,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
if (doit) {
Slog.w(TAG, "Wallpaper uninstalled, removing: "
+ wallpaper.wallpaperComponent);
- clearWallpaperLocked(false, wallpaper.userId);
+ clearWallpaperLocked(false, wallpaper.userId, null);
}
}
}
@@ -369,7 +393,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
} catch (NameNotFoundException e) {
Slog.w(TAG, "Wallpaper component gone, removing: "
+ wallpaper.wallpaperComponent);
- clearWallpaperLocked(false, wallpaper.userId);
+ clearWallpaperLocked(false, wallpaper.userId, null);
}
}
if (wallpaper.nextWallpaperComponent != null
@@ -413,28 +437,43 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
public void systemReady() {
if (DEBUG) Slog.v(TAG, "systemReady");
WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_OWNER);
- switchWallpaper(wallpaper);
+ switchWallpaper(wallpaper, null);
wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
wallpaper.wallpaperObserver.startWatching();
IntentFilter userFilter = new IntentFilter();
- userFilter.addAction(Intent.ACTION_USER_SWITCHED);
userFilter.addAction(Intent.ACTION_USER_REMOVED);
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- if (Intent.ACTION_USER_SWITCHED.equals(action)) {
- switchUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
- } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+ if (Intent.ACTION_USER_REMOVED.equals(action)) {
removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
}
}
}, userFilter);
+ try {
+ ActivityManagerNative.getDefault().registerUserSwitchObserver(
+ new IUserSwitchObserver.Stub() {
+ @Override
+ public void onUserSwitching(int newUserId, IRemoteCallback reply) {
+ switchUser(newUserId, reply);
+ }
+
+ @Override
+ public void onUserSwitchComplete(int newUserId) throws RemoteException {
+ }
+ });
+ } catch (RemoteException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
}
String getName() {
- return mWallpaperMap.get(0).name;
+ synchronized (mLock) {
+ return mWallpaperMap.get(0).name;
+ }
}
void removeUser(int userId) {
@@ -451,7 +490,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
- void switchUser(int userId) {
+ void switchUser(int userId, IRemoteCallback reply) {
synchronized (mLock) {
mCurrentUserId = userId;
WallpaperData wallpaper = mWallpaperMap.get(userId);
@@ -462,35 +501,35 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
wallpaper.wallpaperObserver.startWatching();
}
- switchWallpaper(wallpaper);
+ switchWallpaper(wallpaper, reply);
}
}
- void switchWallpaper(WallpaperData wallpaper) {
+ void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) {
synchronized (mLock) {
RuntimeException e = null;
try {
ComponentName cname = wallpaper.wallpaperComponent != null ?
wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
- if (bindWallpaperComponentLocked(cname, true, false, wallpaper)) {
+ if (bindWallpaperComponentLocked(cname, true, false, wallpaper, reply)) {
return;
}
} catch (RuntimeException e1) {
e = e1;
}
Slog.w(TAG, "Failure starting previous wallpaper", e);
- clearWallpaperLocked(false, wallpaper.userId);
+ clearWallpaperLocked(false, wallpaper.userId, reply);
}
}
public void clearWallpaper() {
if (DEBUG) Slog.v(TAG, "clearWallpaper");
synchronized (mLock) {
- clearWallpaperLocked(false, UserHandle.getCallingUserId());
+ clearWallpaperLocked(false, UserHandle.getCallingUserId(), null);
}
}
- void clearWallpaperLocked(boolean defaultFailed, int userId) {
+ void clearWallpaperLocked(boolean defaultFailed, int userId, IRemoteCallback reply) {
WallpaperData wallpaper = mWallpaperMap.get(userId);
File f = new File(getWallpaperDir(userId), WALLPAPER);
if (f.exists()) {
@@ -503,7 +542,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
if (userId != mCurrentUserId) return;
if (bindWallpaperComponentLocked(defaultFailed
? wallpaper.imageWallpaperComponent
- : null, true, false, wallpaper)) {
+ : null, true, false, wallpaper, reply)) {
return;
}
} catch (IllegalArgumentException e1) {
@@ -518,21 +557,38 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
// wallpaper.
Slog.e(TAG, "Default wallpaper component not found!", e);
clearWallpaperComponentLocked(wallpaper);
+ if (reply != null) {
+ try {
+ reply.sendResult(null);
+ } catch (RemoteException e1) {
+ }
+ }
}
- public void setDimensionHints(int width, int height) throws RemoteException {
- checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
-
- int userId = UserHandle.getCallingUserId();
- WallpaperData wallpaper = mWallpaperMap.get(userId);
- if (wallpaper == null) {
- throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
- }
- if (width <= 0 || height <= 0) {
- throw new IllegalArgumentException("width and height must be > 0");
+ public boolean hasNamedWallpaper(String name) {
+ synchronized (mLock) {
+ for (int i=0; i<mWallpaperMap.size(); i++) {
+ WallpaperData wd = mWallpaperMap.valueAt(i);
+ if (name.equals(wd.name)) {
+ return true;
+ }
+ }
}
+ return false;
+ }
+ public void setDimensionHints(int width, int height) throws RemoteException {
+ checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
synchronized (mLock) {
+ int userId = UserHandle.getCallingUserId();
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+ }
+ if (width <= 0 || height <= 0) {
+ throw new IllegalArgumentException("width and height must be > 0");
+ }
+
if (width != wallpaper.width || height != wallpaper.height) {
wallpaper.width = width;
wallpaper.height = height;
@@ -610,14 +666,14 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
public ParcelFileDescriptor setWallpaper(String name) {
- if (DEBUG) Slog.v(TAG, "setWallpaper");
- int userId = UserHandle.getCallingUserId();
- WallpaperData wallpaper = mWallpaperMap.get(userId);
- if (wallpaper == null) {
- throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
- }
checkPermission(android.Manifest.permission.SET_WALLPAPER);
synchronized (mLock) {
+ if (DEBUG) Slog.v(TAG, "setWallpaper");
+ int userId = UserHandle.getCallingUserId();
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+ }
final long ident = Binder.clearCallingIdentity();
try {
ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper);
@@ -657,18 +713,18 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
public void setWallpaperComponent(ComponentName name) {
- if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
- int userId = UserHandle.getCallingUserId();
- WallpaperData wallpaper = mWallpaperMap.get(userId);
- if (wallpaper == null) {
- throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
- }
checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
synchronized (mLock) {
+ if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
+ int userId = UserHandle.getCallingUserId();
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+ }
final long ident = Binder.clearCallingIdentity();
try {
wallpaper.imageWallpaperPending = false;
- bindWallpaperComponentLocked(name, false, true, wallpaper);
+ bindWallpaperComponentLocked(name, false, true, wallpaper, null);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -676,7 +732,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
- boolean fromUser, WallpaperData wallpaper) {
+ boolean fromUser, WallpaperData wallpaper, IRemoteCallback reply) {
if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
// Has the component changed?
if (!force) {
@@ -794,6 +850,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
wallpaper.wallpaperComponent = componentName;
wallpaper.connection = newConn;
wallpaper.lastDiedTime = SystemClock.uptimeMillis();
+ newConn.mReply = reply;
try {
if (wallpaper.userId == mCurrentUserId) {
if (DEBUG)
@@ -817,6 +874,13 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
void detachWallpaperLocked(WallpaperData wallpaper) {
if (wallpaper.connection != null) {
+ if (wallpaper.connection.mReply != null) {
+ try {
+ wallpaper.connection.mReply.sendResult(null);
+ } catch (RemoteException e) {
+ }
+ wallpaper.connection.mReply = null;
+ }
if (wallpaper.connection.mEngine != null) {
try {
wallpaper.connection.mEngine.destroy();
@@ -849,7 +913,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
} catch (RemoteException e) {
Slog.w(TAG, "Failed attaching wallpaper; clearing", e);
if (!wallpaper.wallpaperUpdating) {
- bindWallpaperComponentLocked(null, false, false, wallpaper);
+ bindWallpaperComponentLocked(null, false, false, wallpaper, null);
}
}
}
@@ -1032,11 +1096,11 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
if (wallpaper.nextWallpaperComponent != null
&& !wallpaper.nextWallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
- wallpaper)) {
+ wallpaper, null)) {
// No such live wallpaper or other failure; fall back to the default
// live wallpaper (since the profile being restored indicated that the
// user had selected a live rather than static one).
- bindWallpaperComponentLocked(null, false, false, wallpaper);
+ bindWallpaperComponentLocked(null, false, false, wallpaper, null);
}
success = true;
} else {
@@ -1052,7 +1116,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success);
if (success) {
bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
- wallpaper);
+ wallpaper, null);
}
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 1c5a8a5..b8072b3 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -49,6 +49,7 @@ import android.app.IProcessObserver;
import android.app.IServiceConnection;
import android.app.IStopUserCallback;
import android.app.IThumbnailReceiver;
+import android.app.IUserSwitchObserver;
import android.app.Instrumentation;
import android.app.Notification;
import android.app.NotificationManager;
@@ -100,6 +101,7 @@ import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
import android.os.IPermissionController;
+import android.os.IRemoteCallback;
import android.os.IUserManager;
import android.os.Looper;
import android.os.Message;
@@ -247,6 +249,10 @@ public final class ActivityManagerService extends ActivityManagerNative
// How long we wait until we timeout on key dispatching during instrumentation.
static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
+ // Amount of time we wait for observers to handle a user switch before
+ // giving up on them and unfreezing the screen.
+ static final int USER_SWITCH_TIMEOUT = 2*1000;
+
static final int MY_PID = Process.myPid();
static final String[] EMPTY_STRING_ARRAY = new String[0];
@@ -438,6 +444,17 @@ public final class ActivityManagerService extends ActivityManagerNative
final ArrayList<Integer> mUserLru = new ArrayList<Integer>();
/**
+ * Registered observers of the user switching mechanics.
+ */
+ final RemoteCallbackList<IUserSwitchObserver> mUserSwitchObservers
+ = new RemoteCallbackList<IUserSwitchObserver>();
+
+ /**
+ * Currently active user switch.
+ */
+ Object mCurUserSwitchCallback;
+
+ /**
* Packages that the user has asked to have run in screen size
* compatibility mode instead of filling the screen.
*/
@@ -863,6 +880,9 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int DISPATCH_PROCESSES_CHANGED = 31;
static final int DISPATCH_PROCESS_DIED = 32;
static final int REPORT_MEM_USAGE = 33;
+ static final int REPORT_USER_SWITCH_MSG = 34;
+ static final int CONTINUE_USER_SWITCH_MSG = 35;
+ static final int USER_SWITCH_TIMEOUT_MSG = 36;
static final int FIRST_ACTIVITY_STACK_MSG = 100;
static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1293,6 +1313,18 @@ public final class ActivityManagerService extends ActivityManagerNative
thread.start();
break;
}
+ case REPORT_USER_SWITCH_MSG: {
+ dispatchUserSwitch((UserStartedState)msg.obj, msg.arg1, msg.arg2);
+ break;
+ }
+ case CONTINUE_USER_SWITCH_MSG: {
+ continueUserSwitch((UserStartedState)msg.obj, msg.arg1, msg.arg2);
+ break;
+ }
+ case USER_SWITCH_TIMEOUT_MSG: {
+ timeoutUserSwitch((UserStartedState)msg.obj, msg.arg1, msg.arg2);
+ break;
+ }
}
}
};
@@ -2142,7 +2174,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- boolean startHomeActivityLocked(int userId, UserStartedState startingUser) {
+ boolean startHomeActivityLocked(int userId) {
if (mHeadless) {
// Added because none of the other calls to ensureBootCompleted seem to fire
// when running headless.
@@ -2181,9 +2213,6 @@ public final class ActivityManagerService extends ActivityManagerNative
null, null, 0, 0, 0, 0, null, false, null);
}
}
- if (startingUser != null) {
- mMainStack.addStartingUserLocked(startingUser);
- }
return true;
}
@@ -3731,7 +3760,7 @@ public final class ActivityManagerService extends ActivityManagerNative
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null,
false, false,
- MY_PID, Process.SYSTEM_UID, userId);
+ MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
}
private final boolean killPackageProcessesLocked(String packageName, int appId,
@@ -7660,42 +7689,45 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ final int[] users = getUsersLocked();
for (int i=0; i<ris.size(); i++) {
ActivityInfo ai = ris.get(i).activityInfo;
ComponentName comp = new ComponentName(ai.packageName, ai.name);
doneReceivers.add(comp);
intent.setComponent(comp);
- IIntentReceiver finisher = null;
- if (i == ris.size()-1) {
- finisher = new IIntentReceiver.Stub() {
- public void performReceive(Intent intent, int resultCode,
- String data, Bundle extras, boolean ordered,
- boolean sticky, int sendingUser) {
- // The raw IIntentReceiver interface is called
- // with the AM lock held, so redispatch to
- // execute our code without the lock.
- mHandler.post(new Runnable() {
- public void run() {
- synchronized (ActivityManagerService.this) {
- mDidUpdate = true;
+ for (int j=0; j<users.length; j++) {
+ IIntentReceiver finisher = null;
+ if (i == ris.size()-1 && j == users.length-1) {
+ finisher = new IIntentReceiver.Stub() {
+ public void performReceive(Intent intent, int resultCode,
+ String data, Bundle extras, boolean ordered,
+ boolean sticky, int sendingUser) {
+ // The raw IIntentReceiver interface is called
+ // with the AM lock held, so redispatch to
+ // execute our code without the lock.
+ mHandler.post(new Runnable() {
+ public void run() {
+ synchronized (ActivityManagerService.this) {
+ mDidUpdate = true;
+ }
+ writeLastDonePreBootReceivers(doneReceivers);
+ showBootMessage(mContext.getText(
+ R.string.android_upgrading_complete),
+ false);
+ systemReady(goingCallback);
}
- writeLastDonePreBootReceivers(doneReceivers);
- showBootMessage(mContext.getText(
- R.string.android_upgrading_complete),
- false);
- systemReady(goingCallback);
- }
- });
- }
- };
- }
- Slog.i(TAG, "Sending system update to: " + intent.getComponent());
- // XXX also need to send this to stopped users(!!!)
- broadcastIntentLocked(null, null, intent, null, finisher,
- 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID,
- UserHandle.USER_ALL);
- if (finisher != null) {
- mWaitingUpdate = true;
+ });
+ }
+ };
+ }
+ Slog.i(TAG, "Sending system update to " + intent.getComponent()
+ + " for user " + users[j]);
+ broadcastIntentLocked(null, null, intent, null, finisher,
+ 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID,
+ users[j]);
+ if (finisher != null) {
+ mWaitingUpdate = true;
+ }
}
}
}
@@ -7817,7 +7849,19 @@ public final class ActivityManagerService extends ActivityManagerNative
} catch (RemoteException e) {
}
+ long ident = Binder.clearCallingIdentity();
+ try {
+ Intent intent = new Intent(Intent.ACTION_USER_STARTED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
+ broadcastIntentLocked(null, null, intent,
+ null, null, 0, null, null, null,
+ false, false, MY_PID, Process.SYSTEM_UID, mCurrentUserId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
mMainStack.resumeTopActivityLocked(null);
+ sendUserSwitchBroadcastsLocked(-1, mCurrentUserId);
}
}
@@ -11435,9 +11479,12 @@ public final class ActivityManagerService extends ActivityManagerNative
// Make sure that the user who is receiving this broadcast is started
// If not, we will just skip it.
if (userId != UserHandle.USER_ALL && mStartedUsers.get(userId) == null) {
- Slog.w(TAG, "Skipping broadcast of " + intent
- + ": user " + userId + " is stopped");
- return ActivityManager.BROADCAST_SUCCESS;
+ if (callingUid != Process.SYSTEM_UID || (intent.getFlags()
+ & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
+ Slog.w(TAG, "Skipping broadcast of " + intent
+ + ": user " + userId + " is stopped");
+ return ActivityManager.BROADCAST_SUCCESS;
+ }
}
/*
@@ -13884,44 +13931,177 @@ public final class ActivityManagerService extends ActivityManagerNative
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
- synchronized (this) {
- if (mCurrentUserId == userId) {
- return true;
- }
- mWindowManager.startFreezingScreen(R.anim.screen_user_exit,
- R.anim.screen_user_enter);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (this) {
+ final int oldUserId = mCurrentUserId;
+ if (oldUserId == userId) {
+ return true;
+ }
- // If the user we are switching to is not currently started, then
- // we need to start it now.
- if (mStartedUsers.get(userId) == null) {
- mStartedUsers.put(userId, new UserStartedState(new UserHandle(userId), false));
- }
+ final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
+ if (userInfo == null) {
+ Slog.w(TAG, "No user info for user #" + userId);
+ return false;
+ }
- mCurrentUserId = userId;
- Integer userIdInt = Integer.valueOf(userId);
- mUserLru.remove(userIdInt);
- mUserLru.add(userIdInt);
- boolean haveActivities = mMainStack.switchUser(userId);
- if (!haveActivities) {
- startHomeActivityLocked(userId, mStartedUsers.get(userId));
- } else {
- mMainStack.addStartingUserLocked(mStartedUsers.get(userId));
+ mWindowManager.startFreezingScreen(R.anim.screen_user_exit,
+ R.anim.screen_user_enter);
+
+ // If the user we are switching to is not currently started, then
+ // we need to start it now.
+ if (mStartedUsers.get(userId) == null) {
+ mStartedUsers.put(userId, new UserStartedState(new UserHandle(userId), false));
+ }
+
+ mCurrentUserId = userId;
+ final Integer userIdInt = Integer.valueOf(userId);
+ mUserLru.remove(userIdInt);
+ mUserLru.add(userIdInt);
+
+ final UserStartedState uss = mStartedUsers.get(userId);
+
+ mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
+ mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
+ mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
+ oldUserId, userId, uss));
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
+ oldUserId, userId, uss), USER_SWITCH_TIMEOUT);
+ Intent intent = new Intent(Intent.ACTION_USER_STARTED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+ broadcastIntentLocked(null, null, intent,
+ null, null, 0, null, null, null,
+ false, false, MY_PID, Process.SYSTEM_UID, userId);
+
+ if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
+ if (userId != 0) {
+ intent = new Intent(Intent.ACTION_USER_INITIALIZE);
+ broadcastIntentLocked(null, null, intent, null,
+ new IIntentReceiver.Stub() {
+ public void performReceive(Intent intent, int resultCode,
+ String data, Bundle extras, boolean ordered,
+ boolean sticky, int sendingUser) {
+ synchronized (ActivityManagerService.this) {
+ getUserManagerLocked().makeInitialized(userInfo.id);
+ }
+ }
+ }, 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID,
+ userId);
+ } else {
+ getUserManagerLocked().makeInitialized(userInfo.id);
+ }
+ }
+
+ boolean haveActivities = mMainStack.switchUserLocked(userId, uss);
+ if (!haveActivities) {
+ startHomeActivityLocked(userId);
+ }
+
+ sendUserSwitchBroadcastsLocked(oldUserId, userId);
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
+ return true;
+ }
+
+ void sendUserSwitchBroadcastsLocked(int oldUserId, int newUserId) {
long ident = Binder.clearCallingIdentity();
try {
- // Inform of user switch
- Intent addedIntent = new Intent(Intent.ACTION_USER_SWITCHED);
- addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
- mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
- android.Manifest.permission.MANAGE_USERS);
+ Intent intent;
+ if (oldUserId >= 0) {
+ intent = new Intent(Intent.ACTION_USER_BACKGROUND);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, oldUserId);
+ broadcastIntentLocked(null, null, intent,
+ null, null, 0, null, null, null,
+ false, false, MY_PID, Process.SYSTEM_UID, oldUserId);
+ }
+ if (newUserId >= 0) {
+ intent = new Intent(Intent.ACTION_USER_FOREGROUND);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId);
+ broadcastIntentLocked(null, null, intent,
+ null, null, 0, null, null, null,
+ false, false, MY_PID, Process.SYSTEM_UID, newUserId);
+ intent = new Intent(Intent.ACTION_USER_SWITCHED);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, newUserId);
+ broadcastIntentLocked(null, null, intent,
+ null, null, 0, null, null,
+ android.Manifest.permission.MANAGE_USERS,
+ false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
+ }
- return true;
+ void dispatchUserSwitch(final UserStartedState uss, final int oldUserId,
+ final int newUserId) {
+ final int N = mUserSwitchObservers.beginBroadcast();
+ if (N > 0) {
+ final IRemoteCallback callback = new IRemoteCallback.Stub() {
+ int mCount = 0;
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ synchronized (ActivityManagerService.this) {
+ if (mCurUserSwitchCallback == this) {
+ mCount++;
+ if (mCount == N) {
+ sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
+ }
+ }
+ }
+ }
+ };
+ synchronized (this) {
+ mCurUserSwitchCallback = callback;
+ }
+ for (int i=0; i<N; i++) {
+ try {
+ mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(
+ newUserId, callback);
+ } catch (RemoteException e) {
+ }
+ }
+ } else {
+ synchronized (this) {
+ sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
+ }
+ }
+ mUserSwitchObservers.finishBroadcast();
+ }
+
+ void timeoutUserSwitch(UserStartedState uss, int oldUserId, int newUserId) {
+ synchronized (this) {
+ Slog.w(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);
+ sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
+ }
+ }
+
+ void sendContinueUserSwitchLocked(UserStartedState uss, int oldUserId, int newUserId) {
+ mCurUserSwitchCallback = null;
+ mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
+ mHandler.sendMessage(mHandler.obtainMessage(CONTINUE_USER_SWITCH_MSG,
+ oldUserId, newUserId, uss));
+ }
+
+ void continueUserSwitch(UserStartedState uss, int oldUserId, int newUserId) {
+ final int N = mUserSwitchObservers.beginBroadcast();
+ for (int i=0; i<N; i++) {
+ try {
+ mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(newUserId);
+ } catch (RemoteException e) {
+ }
+ }
+ mUserSwitchObservers.finishBroadcast();
+ synchronized (this) {
+ mWindowManager.stopFreezingScreen();
+ }
}
void finishUserSwitch(UserStartedState uss) {
@@ -13937,7 +14117,6 @@ public final class ActivityManagerService extends ActivityManagerNative
android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
false, false, MY_PID, Process.SYSTEM_UID, userId);
}
- mWindowManager.stopFreezingScreen();
}
}
@@ -14074,6 +14253,26 @@ public final class ActivityManagerService extends ActivityManagerNative
return state != null && state.mState != UserStartedState.STATE_STOPPING;
}
+ @Override
+ public void registerUserSwitchObserver(IUserSwitchObserver observer) {
+ if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: registerUserSwitchObserver() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+
+ mUserSwitchObservers.register(observer);
+ }
+
+ @Override
+ public void unregisterUserSwitchObserver(IUserSwitchObserver observer) {
+ mUserSwitchObservers.unregister(observer);
+ }
+
private boolean userExists(int userId) {
if (userId == 0) {
return true;
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index bc835b6..f72d318 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -575,37 +575,36 @@ final class ActivityStack {
* Move the activities around in the stack to bring a user to the foreground.
* @return whether there are any activities for the specified user.
*/
- final boolean switchUser(int userId) {
- synchronized (mService) {
- mCurrentUser = userId;
+ final boolean switchUserLocked(int userId, UserStartedState uss) {
+ mCurrentUser = userId;
+ mStartingUsers.add(uss);
- // Only one activity? Nothing to do...
- if (mHistory.size() < 2)
- return false;
+ // Only one activity? Nothing to do...
+ if (mHistory.size() < 2)
+ return false;
- boolean haveActivities = false;
- // Check if the top activity is from the new user.
- ActivityRecord top = mHistory.get(mHistory.size() - 1);
- if (top.userId == userId) return true;
- // Otherwise, move the user's activities to the top.
- int N = mHistory.size();
- int i = 0;
- while (i < N) {
- ActivityRecord r = mHistory.get(i);
- if (r.userId == userId) {
- ActivityRecord moveToTop = mHistory.remove(i);
- mHistory.add(moveToTop);
- // No need to check the top one now
- N--;
- haveActivities = true;
- } else {
- i++;
- }
+ boolean haveActivities = false;
+ // Check if the top activity is from the new user.
+ ActivityRecord top = mHistory.get(mHistory.size() - 1);
+ if (top.userId == userId) return true;
+ // Otherwise, move the user's activities to the top.
+ int N = mHistory.size();
+ int i = 0;
+ while (i < N) {
+ ActivityRecord r = mHistory.get(i);
+ if (r.userId == userId) {
+ ActivityRecord moveToTop = mHistory.remove(i);
+ mHistory.add(moveToTop);
+ // No need to check the top one now
+ N--;
+ haveActivities = true;
+ } else {
+ i++;
}
- // Transition from the old top to the new top
- resumeTopActivityLocked(top);
- return haveActivities;
}
+ // Transition from the old top to the new top
+ resumeTopActivityLocked(top);
+ return haveActivities;
}
final boolean realStartActivityLocked(ActivityRecord r,
@@ -1398,7 +1397,7 @@ final class ActivityStack {
// Launcher...
if (mMainStack) {
ActivityOptions.abort(options);
- return mService.startHomeActivityLocked(mCurrentUser, null);
+ return mService.startHomeActivityLocked(mCurrentUser);
}
}
@@ -3577,10 +3576,6 @@ final class ActivityStack {
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.
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index fc01f60..a58c4ea 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -83,6 +83,8 @@ public class UserManagerService extends IUserManager.Stub {
private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
+ private final int mUserLimit;
+
private int[] mUserIds;
private boolean mGuestEnabled;
private int mNextSerialNumber;
@@ -125,6 +127,8 @@ public class UserManagerService extends IUserManager.Stub {
mPm = pm;
mInstallLock = installLock;
mPackagesLock = packagesLock;
+ mUserLimit = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_multiuserMaximumUsers);
mUsersDir = new File(dataDir, USER_INFO_DIR);
mUsersDir.mkdirs();
// Make zeroth user directory, for services to migrate their files to that location
@@ -237,16 +241,23 @@ public class UserManagerService extends IUserManager.Stub {
// TODO:
}
+ public void makeInitialized(int userId) {
+ checkManageUsersPermission("makeInitialized");
+ synchronized (mPackagesLock) {
+ UserInfo info = mUsers.get(userId);
+ if (info != null && (info.flags&UserInfo.FLAG_INITIALIZED) == 0) {
+ info.flags |= UserInfo.FLAG_INITIALIZED;
+ writeUserLocked(info);
+ }
+ }
+ }
+
/**
* Check if we've hit the limit of how many users can be created.
*/
- private boolean isUserLimitReached() {
- synchronized (mInstallLock) {
- int nUsers = mUsers.size();
- int userLimit = mContext.getResources().getInteger(
- com.android.internal.R.integer.config_multiuserMaximumUsers);
- return nUsers >= userLimit;
- }
+ private boolean isUserLimitReachedLocked() {
+ int nUsers = mUsers.size();
+ return nUsers >= mUserLimit;
}
/**
@@ -535,28 +546,31 @@ public class UserManagerService extends IUserManager.Stub {
public UserInfo createUser(String name, int flags) {
checkManageUsersPermission("Only the system can create users");
- if (isUserLimitReached()) return null;
-
- int userId = getNextAvailableId();
- UserInfo userInfo = new UserInfo(userId, name, null, flags);
- File userPath = new File(mBaseUserPath, Integer.toString(userId));
- synchronized (mInstallLock) {
- synchronized (mPackagesLock) {
- userInfo.serialNumber = mNextSerialNumber++;
- mUsers.put(userId, userInfo);
- writeUserListLocked();
- writeUserLocked(userInfo);
- updateUserIdsLocked();
- mPm.createNewUserLILPw(userId, userPath);
+ final long ident = Binder.clearCallingIdentity();
+ final UserInfo userInfo;
+ try {
+ synchronized (mInstallLock) {
+ synchronized (mPackagesLock) {
+ if (isUserLimitReachedLocked()) return null;
+ int userId = getNextAvailableIdLocked();
+ userInfo = new UserInfo(userId, name, null, flags);
+ File userPath = new File(mBaseUserPath, Integer.toString(userId));
+ userInfo.serialNumber = mNextSerialNumber++;
+ mUsers.put(userId, userInfo);
+ writeUserListLocked();
+ writeUserLocked(userInfo);
+ updateUserIdsLocked();
+ mPm.createNewUserLILPw(userId, userPath);
+ }
}
- }
- if (userInfo != null) {
- Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
- addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);
- mContext.sendBroadcastAsUser(new Intent(Intent.ACTION_BOOT_COMPLETED),
- new UserHandle(userInfo.id));
- mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
- android.Manifest.permission.MANAGE_USERS);
+ if (userInfo != null) {
+ Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED);
+ addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id);
+ mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
+ android.Manifest.permission.MANAGE_USERS);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
return userInfo;
}
@@ -614,9 +628,15 @@ public class UserManagerService extends IUserManager.Stub {
}
// Let other services shutdown any activity
- Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
- addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
- mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_USERS);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
+ addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
+ mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
+ android.Manifest.permission.MANAGE_USERS);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
private void removeDirectoryRecursive(File parent) {
@@ -666,7 +686,7 @@ public class UserManagerService extends IUserManager.Stub {
* for data and battery stats collection, or unexpected cross-talk.
* @return
*/
- private int getNextAvailableId() {
+ private int getNextAvailableIdLocked() {
synchronized (mPackagesLock) {
int i = 0;
while (i < Integer.MAX_VALUE) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 1a101ad..556613e 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -294,7 +294,6 @@ public class WindowManagerService extends IWindowManager.Stub
KeyguardDisableHandler.KEYGUARD_POLICY_CHANGED);
} else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
final int newUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
- Slog.v(TAG, "Switching user from " + mCurrentUserId + " to " + newUserId);
mCurrentUserId = newUserId;
}
}