Skip to content

Commit c72fc67

Browse files
author
Dianne Hackborn
committed
Implement multi-user PackageMonitor.
New APIs let you indicate what user(s) to monitor, and tell you what user is changing when receiving a callback. Fix package manager to only deliver package brpadcasts to the running users. (This isn't really a change in behavior, since the activity manager would not deliver to stopped users anyway). Make sure all broadcasts that package monitor receives also include user information for it to use. Update wallpaper service to (hopefully) now Really Correctly monitor package changes per user. Change-Id: Idd952dd274abcaeab452277d9160d1ae62919aa0
1 parent 4046e01 commit c72fc67

File tree

8 files changed

+160
-37
lines changed

8 files changed

+160
-37
lines changed

core/java/android/app/ActivityManagerNative.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1611,6 +1611,14 @@ public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
16111611
return true;
16121612
}
16131613

1614+
case GET_RUNNING_USER_IDS_TRANSACTION: {
1615+
data.enforceInterface(IActivityManager.descriptor);
1616+
int[] result = getRunningUserIds();
1617+
reply.writeNoException();
1618+
reply.writeIntArray(result);
1619+
return true;
1620+
}
1621+
16141622
case REMOVE_SUB_TASK_TRANSACTION:
16151623
{
16161624
data.enforceInterface(IActivityManager.descriptor);
@@ -3846,6 +3854,18 @@ public boolean isUserRunning(int userid) throws RemoteException {
38463854
return result;
38473855
}
38483856

3857+
public int[] getRunningUserIds() throws RemoteException {
3858+
Parcel data = Parcel.obtain();
3859+
Parcel reply = Parcel.obtain();
3860+
data.writeInterfaceToken(IActivityManager.descriptor);
3861+
mRemote.transact(GET_RUNNING_USER_IDS_TRANSACTION, data, reply, 0);
3862+
reply.readException();
3863+
int[] result = reply.createIntArray();
3864+
reply.recycle();
3865+
data.recycle();
3866+
return result;
3867+
}
3868+
38493869
public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException {
38503870
Parcel data = Parcel.obtain();
38513871
Parcel reply = Parcel.obtain();

core/java/android/app/IActivityManager.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ public void setPackageAskScreenCompat(String packageName, boolean ask)
327327
public int stopUser(int userid, IStopUserCallback callback) throws RemoteException;
328328
public UserInfo getCurrentUser() throws RemoteException;
329329
public boolean isUserRunning(int userid) throws RemoteException;
330+
public int[] getRunningUserIds() throws RemoteException;
330331

331332
public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException;
332333

@@ -611,4 +612,5 @@ private WaitResult(Parcel source) {
611612
int STOP_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+153;
612613
int REGISTER_USER_SWITCH_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+154;
613614
int UNREGISTER_USER_SWITCH_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+155;
615+
int GET_RUNNING_USER_IDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+156;
614616
}

core/java/android/content/Intent.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2796,6 +2796,15 @@ public static Intent createChooser(Intent target, CharSequence title) {
27962796
*/
27972797
public static final String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED";
27982798

2799+
/**
2800+
* @hide
2801+
* Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED}
2802+
* intents to indicate that at this point the package has been removed for
2803+
* all users on the device.
2804+
*/
2805+
public static final String EXTRA_REMOVED_FOR_ALL_USERS
2806+
= "android.intent.extra.REMOVED_FOR_ALL_USERS";
2807+
27992808
/**
28002809
* Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED}
28012810
* intents to indicate that this is a replacement of the package, so this

core/java/com/android/internal/content/PackageMonitor.java

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import android.os.Handler;
2525
import android.os.HandlerThread;
2626
import android.os.Looper;
27+
import android.os.UserHandle;
2728

2829
import java.util.HashSet;
2930

@@ -62,11 +63,17 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
6263
String[] mAppearingPackages;
6364
String[] mModifiedPackages;
6465
int mChangeType;
66+
int mChangeUserId = UserHandle.USER_NULL;
6567
boolean mSomePackagesChanged;
66-
68+
6769
String[] mTempArray = new String[1];
68-
70+
6971
public void register(Context context, Looper thread, boolean externalStorage) {
72+
register(context, thread, null, externalStorage);
73+
}
74+
75+
public void register(Context context, Looper thread, UserHandle user,
76+
boolean externalStorage) {
7077
if (mRegisteredContext != null) {
7178
throw new IllegalStateException("Already registered");
7279
}
@@ -84,10 +91,19 @@ public void register(Context context, Looper thread, boolean externalStorage) {
8491
} else {
8592
mRegisteredHandler = new Handler(thread);
8693
}
87-
context.registerReceiver(this, sPackageFilt, null, mRegisteredHandler);
88-
context.registerReceiver(this, sNonDataFilt, null, mRegisteredHandler);
89-
if (externalStorage) {
90-
context.registerReceiver(this, sExternalFilt, null, mRegisteredHandler);
94+
if (user != null) {
95+
context.registerReceiverAsUser(this, user, sPackageFilt, null, mRegisteredHandler);
96+
context.registerReceiverAsUser(this, user, sNonDataFilt, null, mRegisteredHandler);
97+
if (externalStorage) {
98+
context.registerReceiverAsUser(this, user, sExternalFilt, null,
99+
mRegisteredHandler);
100+
}
101+
} else {
102+
context.registerReceiver(this, sPackageFilt, null, mRegisteredHandler);
103+
context.registerReceiver(this, sNonDataFilt, null, mRegisteredHandler);
104+
if (externalStorage) {
105+
context.registerReceiver(this, sExternalFilt, null, mRegisteredHandler);
106+
}
91107
}
92108
}
93109

@@ -125,6 +141,13 @@ public void onPackageAdded(String packageName, int uid) {
125141
public void onPackageRemoved(String packageName, int uid) {
126142
}
127143

144+
/**
145+
* Called when a package is really removed (and not replaced) for
146+
* all users on the device.
147+
*/
148+
public void onPackageRemovedAllUsers(String packageName, int uid) {
149+
}
150+
128151
public void onPackageUpdateStarted(String packageName, int uid) {
129152
}
130153

@@ -220,7 +243,11 @@ public void onSomePackagesChanged() {
220243

221244
public void onFinishPackageChanges() {
222245
}
223-
246+
247+
public int getChangingUserId() {
248+
return mChangeUserId;
249+
}
250+
224251
String getPackageName(Intent intent) {
225252
Uri uri = intent.getData();
226253
String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
@@ -229,6 +256,12 @@ String getPackageName(Intent intent) {
229256

230257
@Override
231258
public void onReceive(Context context, Intent intent) {
259+
mChangeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
260+
UserHandle.USER_NULL);
261+
if (mChangeUserId == UserHandle.USER_NULL) {
262+
throw new IllegalArgumentException(
263+
"Intent broadcast does not contain user handle: " + intent);
264+
}
232265
onBeginPackageChanges();
233266

234267
mDisappearingPackages = mAppearingPackages = null;
@@ -281,6 +314,9 @@ public void onReceive(Context context, Intent intent) {
281314
// it when it is re-added.
282315
mSomePackagesChanged = true;
283316
onPackageRemoved(pkg, uid);
317+
if (intent.getBooleanExtra(Intent.EXTRA_REMOVED_FOR_ALL_USERS, false)) {
318+
onPackageRemovedAllUsers(pkg, uid);
319+
}
284320
}
285321
onPackageDisappeared(pkg, mChangeType);
286322
}
@@ -344,5 +380,6 @@ public void onReceive(Context context, Intent intent) {
344380
}
345381

346382
onFinishPackageChanges();
383+
mChangeUserId = UserHandle.USER_NULL;
347384
}
348385
}

services/java/com/android/server/WallpaperManagerService.java

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -293,17 +293,18 @@ class MyPackageMonitor extends PackageMonitor {
293293
@Override
294294
public void onPackageUpdateFinished(String packageName, int uid) {
295295
synchronized (mLock) {
296-
for (int i = 0; i < mWallpaperMap.size(); i++) {
297-
WallpaperData wallpaper = mWallpaperMap.valueAt(i);
296+
if (mCurrentUserId != getChangingUserId()) {
297+
return;
298+
}
299+
WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
300+
if (wallpaper != null) {
298301
if (wallpaper.wallpaperComponent != null
299302
&& wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
300303
wallpaper.wallpaperUpdating = false;
301304
ComponentName comp = wallpaper.wallpaperComponent;
302305
clearWallpaperComponentLocked(wallpaper);
303-
// Do this only for the current user's wallpaper
304-
if (wallpaper.userId == mCurrentUserId
305-
&& !bindWallpaperComponentLocked(comp, false, false,
306-
wallpaper, null)) {
306+
if (!bindWallpaperComponentLocked(comp, false, false,
307+
wallpaper, null)) {
307308
Slog.w(TAG, "Wallpaper no longer available; reverting to default");
308309
clearWallpaperLocked(false, wallpaper.userId, null);
309310
}
@@ -315,11 +316,14 @@ public void onPackageUpdateFinished(String packageName, int uid) {
315316
@Override
316317
public void onPackageModified(String packageName) {
317318
synchronized (mLock) {
318-
for (int i = 0; i < mWallpaperMap.size(); i++) {
319-
WallpaperData wallpaper = mWallpaperMap.valueAt(i);
319+
if (mCurrentUserId != getChangingUserId()) {
320+
return;
321+
}
322+
WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
323+
if (wallpaper != null) {
320324
if (wallpaper.wallpaperComponent == null
321325
|| !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
322-
continue;
326+
return;
323327
}
324328
doPackagesChangedLocked(true, wallpaper);
325329
}
@@ -329,8 +333,11 @@ public void onPackageModified(String packageName) {
329333
@Override
330334
public void onPackageUpdateStarted(String packageName, int uid) {
331335
synchronized (mLock) {
332-
for (int i = 0; i < mWallpaperMap.size(); i++) {
333-
WallpaperData wallpaper = mWallpaperMap.valueAt(i);
336+
if (mCurrentUserId != getChangingUserId()) {
337+
return;
338+
}
339+
WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
340+
if (wallpaper != null) {
334341
if (wallpaper.wallpaperComponent != null
335342
&& wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
336343
wallpaper.wallpaperUpdating = true;
@@ -343,8 +350,11 @@ public void onPackageUpdateStarted(String packageName, int uid) {
343350
public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
344351
synchronized (mLock) {
345352
boolean changed = false;
346-
for (int i = 0; i < mWallpaperMap.size(); i++) {
347-
WallpaperData wallpaper = mWallpaperMap.valueAt(i);
353+
if (mCurrentUserId != getChangingUserId()) {
354+
return false;
355+
}
356+
WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
357+
if (wallpaper != null) {
348358
boolean res = doPackagesChangedLocked(doit, wallpaper);
349359
changed |= res;
350360
}
@@ -355,8 +365,11 @@ public boolean onHandleForceStop(Intent intent, String[] packages, int uid, bool
355365
@Override
356366
public void onSomePackagesChanged() {
357367
synchronized (mLock) {
358-
for (int i = 0; i < mWallpaperMap.size(); i++) {
359-
WallpaperData wallpaper = mWallpaperMap.valueAt(i);
368+
if (mCurrentUserId != getChangingUserId()) {
369+
return;
370+
}
371+
WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
372+
if (wallpaper != null) {
360373
doPackagesChangedLocked(true, wallpaper);
361374
}
362375
}
@@ -416,7 +429,7 @@ public WallpaperManagerService(Context context) {
416429
ServiceManager.getService(Context.WINDOW_SERVICE));
417430
mIPackageManager = AppGlobals.getPackageManager();
418431
mMonitor = new MyPackageMonitor();
419-
mMonitor.register(context, null, true);
432+
mMonitor.register(context, null, UserHandle.ALL, true);
420433
getWallpaperDir(UserHandle.USER_OWNER).mkdirs();
421434
loadSettingsLocked(UserHandle.USER_OWNER);
422435
}

services/java/com/android/server/am/ActivityManagerService.java

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@
147147
import java.io.StringWriter;
148148
import java.lang.ref.WeakReference;
149149
import java.util.ArrayList;
150+
import java.util.Arrays;
150151
import java.util.Collections;
151152
import java.util.Comparator;
152153
import java.util.HashMap;
@@ -447,6 +448,11 @@ abstract class ForegroundToken implements IBinder.DeathRecipient {
447448
*/
448449
final ArrayList<Integer> mUserLru = new ArrayList<Integer>();
449450

451+
/**
452+
* Constant array of the users that are currently started.
453+
*/
454+
int[] mStartedUserArray = new int[] { 0 };
455+
450456
/**
451457
* Registered observers of the user switching mechanics.
452458
*/
@@ -832,7 +838,8 @@ static class ProcessChangeItem {
832838
static ActivityManagerService mSelf;
833839
static ActivityThread mSystemThread;
834840

835-
private int mCurrentUserId;
841+
private int mCurrentUserId = 0;
842+
private int[] mCurrentUserArray = new int[] { 0 };
836843
private UserManagerService mUserManager;
837844

838845
private final class AppDeathRecipient implements IBinder.DeathRecipient {
@@ -1568,6 +1575,7 @@ private ActivityManagerService() {
15681575
// User 0 is the first and only user that runs at boot.
15691576
mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true));
15701577
mUserLru.add(Integer.valueOf(0));
1578+
updateStartedUserArrayLocked();
15711579

15721580
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
15731581
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
@@ -3750,6 +3758,7 @@ private void forceStopPackageLocked(final String packageName, int uid) {
37503758
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
37513759
}
37523760
intent.putExtra(Intent.EXTRA_UID, uid);
3761+
intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
37533762
broadcastIntentLocked(null, null, intent,
37543763
null, null, 0, null, null, null,
37553764
false, false,
@@ -9311,6 +9320,9 @@ boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
93119320
pw.print(mUserLru.get(i));
93129321
}
93139322
pw.println("]");
9323+
if (dumpAll) {
9324+
pw.print(" mStartedUserArray: "); pw.println(Arrays.toString(mStartedUserArray));
9325+
}
93149326
pw.println(" mHomeProcess: " + mHomeProcess);
93159327
pw.println(" mPreviousProcess: " + mPreviousProcess);
93169328
if (dumpAll) {
@@ -11498,7 +11510,7 @@ private final int broadcastIntentLocked(ProcessRecord callerApp,
1149811510
userId = handleIncomingUserLocked(callingPid, callingUid, userId,
1149911511
true, false, "broadcast", callerPackage);
1150011512

11501-
// Make sure that the user who is receiving this broadcast is started
11513+
// Make sure that the user who is receiving this broadcast is started.
1150211514
// If not, we will just skip it.
1150311515
if (userId != UserHandle.USER_ALL && mStartedUsers.get(userId) == null) {
1150411516
if (callingUid != Process.SYSTEM_UID || (intent.getFlags()
@@ -11693,13 +11705,10 @@ private final int broadcastIntentLocked(ProcessRecord callerApp,
1169311705
int[] users;
1169411706
if (userId == UserHandle.USER_ALL) {
1169511707
// Caller wants broadcast to go to all started users.
11696-
users = new int[mStartedUsers.size()];
11697-
for (int i=0; i<mStartedUsers.size(); i++) {
11698-
users[i] = mStartedUsers.keyAt(i);
11699-
}
11708+
users = mStartedUserArray;
1170011709
} else {
1170111710
// Caller wants broadcast to go to one specific user.
11702-
users = new int[] {userId};
11711+
users = mCurrentUserArray;
1170311712
}
1170411713

1170511714
// Figure out who all will receive this broadcast.
@@ -13975,9 +13984,11 @@ public boolean switchUser(int userId) {
1397513984
// we need to start it now.
1397613985
if (mStartedUsers.get(userId) == null) {
1397713986
mStartedUsers.put(userId, new UserStartedState(new UserHandle(userId), false));
13987+
updateStartedUserArrayLocked();
1397813988
}
1397913989

1398013990
mCurrentUserId = userId;
13991+
mCurrentUserArray = new int[] { userId };
1398113992
final Integer userIdInt = Integer.valueOf(userId);
1398213993
mUserLru.remove(userIdInt);
1398313994
mUserLru.add(userIdInt);
@@ -14256,6 +14267,7 @@ void finishUserStop(UserStartedState uss) {
1425614267
// User can no longer run.
1425714268
mStartedUsers.remove(userId);
1425814269
mUserLru.remove(Integer.valueOf(userId));
14270+
updateStartedUserArrayLocked();
1425914271

1426014272
// Clean up all state and processes associated with the user.
1426114273
// Kill all the processes for the user.
@@ -14311,6 +14323,29 @@ boolean isUserRunningLocked(int userId) {
1431114323
return state != null && state.mState != UserStartedState.STATE_STOPPING;
1431214324
}
1431314325

14326+
@Override
14327+
public int[] getRunningUserIds() {
14328+
if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
14329+
!= PackageManager.PERMISSION_GRANTED) {
14330+
String msg = "Permission Denial: isUserRunning() from pid="
14331+
+ Binder.getCallingPid()
14332+
+ ", uid=" + Binder.getCallingUid()
14333+
+ " requires " + android.Manifest.permission.INTERACT_ACROSS_USERS;
14334+
Slog.w(TAG, msg);
14335+
throw new SecurityException(msg);
14336+
}
14337+
synchronized (this) {
14338+
return mStartedUserArray;
14339+
}
14340+
}
14341+
14342+
private void updateStartedUserArrayLocked() {
14343+
mStartedUserArray = new int[mStartedUsers.size()];
14344+
for (int i=0; i<mStartedUsers.size(); i++) {
14345+
mStartedUserArray[i] = mStartedUsers.keyAt(i);
14346+
}
14347+
}
14348+
1431414349
@Override
1431514350
public void registerUserSwitchObserver(IUserSwitchObserver observer) {
1431614351
if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)

0 commit comments

Comments
 (0)