diff options
8 files changed, 160 insertions, 37 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 8436b2c0b560..b0df6603be6c 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1611,6 +1611,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case GET_RUNNING_USER_IDS_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + int[] result = getRunningUserIds(); + reply.writeNoException(); + reply.writeIntArray(result); + return true; + } + case REMOVE_SUB_TASK_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); @@ -3846,6 +3854,18 @@ class ActivityManagerProxy implements IActivityManager return result; } + public int[] getRunningUserIds() throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + mRemote.transact(GET_RUNNING_USER_IDS_TRANSACTION, data, reply, 0); + reply.readException(); + int[] result = reply.createIntArray(); + reply.recycle(); + data.recycle(); + return result; + } + public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index d6ebc9b4ffba..ed17d0e63209 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -327,6 +327,7 @@ public interface IActivityManager extends IInterface { public int stopUser(int userid, IStopUserCallback callback) throws RemoteException; public UserInfo getCurrentUser() throws RemoteException; public boolean isUserRunning(int userid) throws RemoteException; + public int[] getRunningUserIds() throws RemoteException; public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException; @@ -611,4 +612,5 @@ public interface IActivityManager extends IInterface { int STOP_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+153; int REGISTER_USER_SWITCH_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+154; int UNREGISTER_USER_SWITCH_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+155; + int GET_RUNNING_USER_IDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+156; } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 383739b7975d..b9518b891347 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2797,6 +2797,15 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED"; /** + * @hide + * Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED} + * intents to indicate that at this point the package has been removed for + * all users on the device. + */ + public static final String EXTRA_REMOVED_FOR_ALL_USERS + = "android.intent.extra.REMOVED_FOR_ALL_USERS"; + + /** * Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED} * intents to indicate that this is a replacement of the package, so this * broadcast will immediately be followed by an add broadcast for a diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java index 3477a90341d1..20ecaceade13 100644 --- a/core/java/com/android/internal/content/PackageMonitor.java +++ b/core/java/com/android/internal/content/PackageMonitor.java @@ -24,6 +24,7 @@ import android.net.Uri; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; +import android.os.UserHandle; import java.util.HashSet; @@ -62,11 +63,17 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { String[] mAppearingPackages; String[] mModifiedPackages; int mChangeType; + int mChangeUserId = UserHandle.USER_NULL; boolean mSomePackagesChanged; - + String[] mTempArray = new String[1]; - + public void register(Context context, Looper thread, boolean externalStorage) { + register(context, thread, null, externalStorage); + } + + public void register(Context context, Looper thread, UserHandle user, + boolean externalStorage) { if (mRegisteredContext != null) { throw new IllegalStateException("Already registered"); } @@ -84,10 +91,19 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { } else { mRegisteredHandler = new Handler(thread); } - context.registerReceiver(this, sPackageFilt, null, mRegisteredHandler); - context.registerReceiver(this, sNonDataFilt, null, mRegisteredHandler); - if (externalStorage) { - context.registerReceiver(this, sExternalFilt, null, mRegisteredHandler); + if (user != null) { + context.registerReceiverAsUser(this, user, sPackageFilt, null, mRegisteredHandler); + context.registerReceiverAsUser(this, user, sNonDataFilt, null, mRegisteredHandler); + if (externalStorage) { + context.registerReceiverAsUser(this, user, sExternalFilt, null, + mRegisteredHandler); + } + } else { + context.registerReceiver(this, sPackageFilt, null, mRegisteredHandler); + context.registerReceiver(this, sNonDataFilt, null, mRegisteredHandler); + if (externalStorage) { + context.registerReceiver(this, sExternalFilt, null, mRegisteredHandler); + } } } @@ -125,6 +141,13 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { public void onPackageRemoved(String packageName, int uid) { } + /** + * Called when a package is really removed (and not replaced) for + * all users on the device. + */ + public void onPackageRemovedAllUsers(String packageName, int uid) { + } + public void onPackageUpdateStarted(String packageName, int uid) { } @@ -220,7 +243,11 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { public void onFinishPackageChanges() { } - + + public int getChangingUserId() { + return mChangeUserId; + } + String getPackageName(Intent intent) { Uri uri = intent.getData(); String pkg = uri != null ? uri.getSchemeSpecificPart() : null; @@ -229,6 +256,12 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { + mChangeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, + UserHandle.USER_NULL); + if (mChangeUserId == UserHandle.USER_NULL) { + throw new IllegalArgumentException( + "Intent broadcast does not contain user handle: " + intent); + } onBeginPackageChanges(); mDisappearingPackages = mAppearingPackages = null; @@ -281,6 +314,9 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { // it when it is re-added. mSomePackagesChanged = true; onPackageRemoved(pkg, uid); + if (intent.getBooleanExtra(Intent.EXTRA_REMOVED_FOR_ALL_USERS, false)) { + onPackageRemovedAllUsers(pkg, uid); + } } onPackageDisappeared(pkg, mChangeType); } @@ -344,5 +380,6 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver { } onFinishPackageChanges(); + mChangeUserId = UserHandle.USER_NULL; } } diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java index b027c1f76a76..4225913844c9 100644 --- a/services/java/com/android/server/WallpaperManagerService.java +++ b/services/java/com/android/server/WallpaperManagerService.java @@ -293,17 +293,18 @@ class WallpaperManagerService extends IWallpaperManager.Stub { @Override public void onPackageUpdateFinished(String packageName, int uid) { synchronized (mLock) { - for (int i = 0; i < mWallpaperMap.size(); i++) { - WallpaperData wallpaper = mWallpaperMap.valueAt(i); + if (mCurrentUserId != getChangingUserId()) { + return; + } + WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); + if (wallpaper != null) { if (wallpaper.wallpaperComponent != null && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) { wallpaper.wallpaperUpdating = false; ComponentName comp = wallpaper.wallpaperComponent; clearWallpaperComponentLocked(wallpaper); - // Do this only for the current user's wallpaper - if (wallpaper.userId == mCurrentUserId - && !bindWallpaperComponentLocked(comp, false, false, - wallpaper, null)) { + if (!bindWallpaperComponentLocked(comp, false, false, + wallpaper, null)) { Slog.w(TAG, "Wallpaper no longer available; reverting to default"); clearWallpaperLocked(false, wallpaper.userId, null); } @@ -315,11 +316,14 @@ class WallpaperManagerService extends IWallpaperManager.Stub { @Override public void onPackageModified(String packageName) { synchronized (mLock) { - for (int i = 0; i < mWallpaperMap.size(); i++) { - WallpaperData wallpaper = mWallpaperMap.valueAt(i); + if (mCurrentUserId != getChangingUserId()) { + return; + } + WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); + if (wallpaper != null) { if (wallpaper.wallpaperComponent == null || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) { - continue; + return; } doPackagesChangedLocked(true, wallpaper); } @@ -329,8 +333,11 @@ class WallpaperManagerService extends IWallpaperManager.Stub { @Override public void onPackageUpdateStarted(String packageName, int uid) { synchronized (mLock) { - for (int i = 0; i < mWallpaperMap.size(); i++) { - WallpaperData wallpaper = mWallpaperMap.valueAt(i); + if (mCurrentUserId != getChangingUserId()) { + return; + } + WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); + if (wallpaper != null) { if (wallpaper.wallpaperComponent != null && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) { wallpaper.wallpaperUpdating = true; @@ -343,8 +350,11 @@ class WallpaperManagerService extends IWallpaperManager.Stub { public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) { synchronized (mLock) { boolean changed = false; - for (int i = 0; i < mWallpaperMap.size(); i++) { - WallpaperData wallpaper = mWallpaperMap.valueAt(i); + if (mCurrentUserId != getChangingUserId()) { + return false; + } + WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); + if (wallpaper != null) { boolean res = doPackagesChangedLocked(doit, wallpaper); changed |= res; } @@ -355,8 +365,11 @@ class WallpaperManagerService extends IWallpaperManager.Stub { @Override public void onSomePackagesChanged() { synchronized (mLock) { - for (int i = 0; i < mWallpaperMap.size(); i++) { - WallpaperData wallpaper = mWallpaperMap.valueAt(i); + if (mCurrentUserId != getChangingUserId()) { + return; + } + WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId); + if (wallpaper != null) { doPackagesChangedLocked(true, wallpaper); } } @@ -416,7 +429,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { ServiceManager.getService(Context.WINDOW_SERVICE)); mIPackageManager = AppGlobals.getPackageManager(); mMonitor = new MyPackageMonitor(); - mMonitor.register(context, null, true); + mMonitor.register(context, null, UserHandle.ALL, true); getWallpaperDir(UserHandle.USER_OWNER).mkdirs(); loadSettingsLocked(UserHandle.USER_OWNER); } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 1f5fa4de6c75..cd3aeff0974d 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -147,6 +147,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; @@ -448,6 +449,11 @@ public final class ActivityManagerService extends ActivityManagerNative final ArrayList<Integer> mUserLru = new ArrayList<Integer>(); /** + * Constant array of the users that are currently started. + */ + int[] mStartedUserArray = new int[] { 0 }; + + /** * Registered observers of the user switching mechanics. */ final RemoteCallbackList<IUserSwitchObserver> mUserSwitchObservers @@ -832,7 +838,8 @@ public final class ActivityManagerService extends ActivityManagerNative static ActivityManagerService mSelf; static ActivityThread mSystemThread; - private int mCurrentUserId; + private int mCurrentUserId = 0; + private int[] mCurrentUserArray = new int[] { 0 }; private UserManagerService mUserManager; private final class AppDeathRecipient implements IBinder.DeathRecipient { @@ -1568,6 +1575,7 @@ public final class ActivityManagerService extends ActivityManagerNative // User 0 is the first and only user that runs at boot. mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true)); mUserLru.add(Integer.valueOf(0)); + updateStartedUserArrayLocked(); GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", ConfigurationInfo.GL_ES_VERSION_UNDEFINED); @@ -3750,6 +3758,7 @@ public final class ActivityManagerService extends ActivityManagerNative intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); } intent.putExtra(Intent.EXTRA_UID, uid); + intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid)); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, false, false, @@ -9311,6 +9320,9 @@ public final class ActivityManagerService extends ActivityManagerNative pw.print(mUserLru.get(i)); } pw.println("]"); + if (dumpAll) { + pw.print(" mStartedUserArray: "); pw.println(Arrays.toString(mStartedUserArray)); + } pw.println(" mHomeProcess: " + mHomeProcess); pw.println(" mPreviousProcess: " + mPreviousProcess); if (dumpAll) { @@ -11498,7 +11510,7 @@ public final class ActivityManagerService extends ActivityManagerNative userId = handleIncomingUserLocked(callingPid, callingUid, userId, true, false, "broadcast", callerPackage); - // Make sure that the user who is receiving this broadcast is started + // 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) { if (callingUid != Process.SYSTEM_UID || (intent.getFlags() @@ -11693,13 +11705,10 @@ public final class ActivityManagerService extends ActivityManagerNative int[] users; if (userId == UserHandle.USER_ALL) { // Caller wants broadcast to go to all started users. - users = new int[mStartedUsers.size()]; - for (int i=0; i<mStartedUsers.size(); i++) { - users[i] = mStartedUsers.keyAt(i); - } + users = mStartedUserArray; } else { // Caller wants broadcast to go to one specific user. - users = new int[] {userId}; + users = mCurrentUserArray; } // Figure out who all will receive this broadcast. @@ -13975,9 +13984,11 @@ public final class ActivityManagerService extends ActivityManagerNative // we need to start it now. if (mStartedUsers.get(userId) == null) { mStartedUsers.put(userId, new UserStartedState(new UserHandle(userId), false)); + updateStartedUserArrayLocked(); } mCurrentUserId = userId; + mCurrentUserArray = new int[] { userId }; final Integer userIdInt = Integer.valueOf(userId); mUserLru.remove(userIdInt); mUserLru.add(userIdInt); @@ -14256,6 +14267,7 @@ public final class ActivityManagerService extends ActivityManagerNative // User can no longer run. mStartedUsers.remove(userId); mUserLru.remove(Integer.valueOf(userId)); + updateStartedUserArrayLocked(); // Clean up all state and processes associated with the user. // Kill all the processes for the user. @@ -14312,6 +14324,29 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override + public int[] getRunningUserIds() { + if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) + != PackageManager.PERMISSION_GRANTED) { + String msg = "Permission Denial: isUserRunning() from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid() + + " requires " + android.Manifest.permission.INTERACT_ACROSS_USERS; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + synchronized (this) { + return mStartedUserArray; + } + } + + private void updateStartedUserArrayLocked() { + mStartedUserArray = new int[mStartedUsers.size()]; + for (int i=0; i<mStartedUsers.size(); i++) { + mStartedUserArray[i] = mStartedUsers.keyAt(i); + } + } + + @Override public void registerUserSwitchObserver(IUserSwitchObserver observer) { if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED) { diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java index 70596748d66c..6dae4aa1754c 100644 --- a/services/java/com/android/server/am/UsageStatsService.java +++ b/services/java/com/android/server/am/UsageStatsService.java @@ -650,7 +650,7 @@ public final class UsageStatsService extends IUsageStats.Stub { public void monitorPackages() { mPackageMonitor = new PackageMonitor() { @Override - public void onPackageRemoved(String packageName, int uid) { + public void onPackageRemovedAllUsers(String packageName, int uid) { synchronized (mStatsLock) { mLastResumeTimes.remove(packageName); } diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index f0cc08396cc5..f3de8a43c703 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -719,7 +719,7 @@ public class PackageManagerService extends IPackageManager.Stub { PackageInstalledInfo res = data.res; if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { - res.removedInfo.sendBroadcast(false, true); + res.removedInfo.sendBroadcast(false, true, false); Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, res.uid); // Determine the set of users who are adding this @@ -5386,7 +5386,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (am != null) { try { if (userIds == null) { - userIds = sUserManager.getUserIds(); + userIds = am.getRunningUserIds(); } for (int id : userIds) { final Intent intent = new Intent(action, @@ -5403,6 +5403,7 @@ public class PackageManagerService extends IPackageManager.Stub { uid = UserHandle.getUid(id, UserHandle.getAppId(uid)); intent.putExtra(Intent.EXTRA_UID, uid); } + intent.putExtra(Intent.EXTRA_USER_HANDLE, id); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); if (DEBUG_BROADCASTS) { RuntimeException here = new RuntimeException("here"); @@ -8051,18 +8052,23 @@ public class PackageManagerService extends IPackageManager.Stub { } catch (RemoteException e) { } + boolean removedForAllUsers = false; + boolean systemUpdate = false; synchronized (mInstallLock) { res = deletePackageLI(packageName, (flags & PackageManager.DELETE_ALL_USERS) != 0 ? UserHandle.ALL : new UserHandle(UserHandle.getUserId(uid)), true, flags | REMOVE_CHATTY, info, true); + systemUpdate = info.isRemovedPackageSystemUpdate; + if (res && !systemUpdate && mPackages.get(packageName) == null) { + removedForAllUsers = true; + } } if (res) { - boolean systemUpdate = info.isRemovedPackageSystemUpdate; - info.sendBroadcast(true, systemUpdate); + info.sendBroadcast(true, systemUpdate, removedForAllUsers); - // If the removed package was a system update, the old system packaged + // If the removed package was a system update, the old system package // was re-enabled; we need to broadcast this information if (systemUpdate) { Bundle extras = new Bundle(1); @@ -8100,13 +8106,14 @@ public class PackageManagerService extends IPackageManager.Stub { // Clean up resources deleted packages. InstallArgs args = null; - void sendBroadcast(boolean fullRemove, boolean replacing) { + void sendBroadcast(boolean fullRemove, boolean replacing, boolean removedForAllUsers) { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid); extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove); if (replacing) { extras.putBoolean(Intent.EXTRA_REPLACING, true); } + extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers); if (removedPackage != null) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, extras, null, null, removedUsers); |