diff options
| author | 2019-01-09 17:52:22 +0000 | |
|---|---|---|
| committer | 2019-01-10 14:25:47 +0000 | |
| commit | 4f98512cc5eb420ef55ed32b73e04632034d98cd (patch) | |
| tree | 85c1c78e4e24fb05a5062160920c3dccd1ee4e5e | |
| parent | e714a7eaa9e45485be9f29aa58efe41ffa313839 (diff) | |
[Multi-user] Make package changes receiver per-user
Makes the BroadcastReceiver that receives changes to installed packages
and sdcards tied to a specific user.
Bug: 121198607
Test: 1) atest RunBackupFrameworksServicesRoboTests
2) Manual testing with user 0 and 11:
- User started -> receiver registered for correct user;
- Package changed -> correct receiver;
- Package added -> correct receiver, updates bookkeeping for correct user;
- Package removed -> correct receiver, updates bookkeeping for correct user;
Change-Id: I68c034da6ec775a4d0489a2d09fc32854dcf11dc
| -rw-r--r-- | services/backup/java/com/android/server/backup/UserBackupManagerService.java | 105 | ||||
| -rw-r--r-- | services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java | 33 |
2 files changed, 91 insertions, 47 deletions
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index b01117c438f0..d51eac386083 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -830,19 +830,29 @@ public class UserBackupManagerService { mFullBackupQueue = readFullBackupSchedule(); } - // Register for broadcasts about package install, etc., so we can - // update the provider list. + // Register for broadcasts about package changes. IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addAction(Intent.ACTION_PACKAGE_CHANGED); filter.addDataScheme("package"); - mContext.registerReceiver(mBroadcastReceiver, filter); + mContext.registerReceiverAsUser( + mBroadcastReceiver, + UserHandle.of(mUserId), + filter, + /* broadcastPermission */ null, + /* scheduler */ null); + // Register for events related to sdcard installation. IntentFilter sdFilter = new IntentFilter(); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); - mContext.registerReceiver(mBroadcastReceiver, sdFilter); + mContext.registerReceiverAsUser( + mBroadcastReceiver, + UserHandle.of(mUserId), + sdFilter, + /* broadcastPermission */ null, + /* scheduler */ null); } private ArrayList<FullBackupEntry> readFullBackupSchedule() { @@ -1107,17 +1117,23 @@ public class UserBackupManagerService { } } - // ----- Track installation/removal of packages ----- + /** + * A {@link BroadcastReceiver} tracking changes to packages and sd cards in order to update our + * internal bookkeeping. + */ private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { - if (MORE_DEBUG) Slog.d(TAG, "Received broadcast " + intent); + if (MORE_DEBUG) { + Slog.d(TAG, "Received broadcast " + intent); + } String action = intent.getAction(); boolean replacing = false; boolean added = false; boolean changed = false; Bundle extras = intent.getExtras(); - String[] pkgList = null; + String[] packageList = null; + if (Intent.ACTION_PACKAGE_ADDED.equals(action) || Intent.ACTION_PACKAGE_REMOVED.equals(action) || Intent.ACTION_PACKAGE_CHANGED.equals(action)) { @@ -1125,69 +1141,70 @@ public class UserBackupManagerService { if (uri == null) { return; } - final String pkgName = uri.getSchemeSpecificPart(); - if (pkgName != null) { - pkgList = new String[]{pkgName}; + + String packageName = uri.getSchemeSpecificPart(); + if (packageName != null) { + packageList = new String[]{packageName}; } - changed = Intent.ACTION_PACKAGE_CHANGED.equals(action); - // At package-changed we only care about looking at new transport states + changed = Intent.ACTION_PACKAGE_CHANGED.equals(action); if (changed) { - final String[] components = + // Look at new transport states for package changed events. + String[] components = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); if (MORE_DEBUG) { - Slog.i(TAG, "Package " + pkgName + " changed; rechecking"); + Slog.i(TAG, "Package " + packageName + " changed"); for (int i = 0; i < components.length; i++) { Slog.i(TAG, " * " + components[i]); } } mBackupHandler.post( - () -> mTransportManager.onPackageChanged(pkgName, components)); - return; // nothing more to do in the PACKAGE_CHANGED case + () -> mTransportManager.onPackageChanged(packageName, components)); + return; } added = Intent.ACTION_PACKAGE_ADDED.equals(action); replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false); } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { added = true; - pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + packageList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { added = false; - pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + packageList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } - if (pkgList == null || pkgList.length == 0) { + if (packageList == null || packageList.length == 0) { return; } - final int uid = extras.getInt(Intent.EXTRA_UID); + int uid = extras.getInt(Intent.EXTRA_UID); if (added) { synchronized (mBackupParticipants) { if (replacing) { - // This is the package-replaced case; we just remove the entry - // under the old uid and fall through to re-add. If an app - // just added key/value backup participation, this picks it up - // as a known participant. - removePackageParticipantsLocked(pkgList, uid); + // Remove the entry under the old uid and fall through to re-add. If an app + // just opted into key/value backup, add it as a known participant. + removePackageParticipantsLocked(packageList, uid); } - addPackageParticipantsLocked(pkgList); + addPackageParticipantsLocked(packageList); } - // If they're full-backup candidates, add them there instead - final long now = System.currentTimeMillis(); - for (final String packageName : pkgList) { + + long now = System.currentTimeMillis(); + for (String packageName : packageList) { try { - PackageInfo app = mPackageManager.getPackageInfo(packageName, 0); + PackageInfo app = + mPackageManager.getPackageInfoAsUser( + packageName, /* flags */ 0, mUserId); if (AppBackupUtils.appGetsFullBackup(app) && AppBackupUtils.appIsEligibleForBackup( app.applicationInfo, mPackageManager)) { enqueueFullBackup(packageName, now); scheduleNextFullBackupJob(0); } else { - // The app might have just transitioned out of full-data into - // doing key/value backups, or might have just disabled backups - // entirely. Make sure it is no longer in the full-data queue. + // The app might have just transitioned out of full-data into doing + // key/value backups, or might have just disabled backups entirely. Make + // sure it is no longer in the full-data queue. synchronized (mQueueLock) { dequeueFullBackupLocked(packageName); } @@ -1196,32 +1213,28 @@ public class UserBackupManagerService { mBackupHandler.post( () -> mTransportManager.onPackageAdded(packageName)); - } catch (NameNotFoundException e) { - // doesn't really exist; ignore it if (DEBUG) { Slog.w(TAG, "Can't resolve new app " + packageName); } } } - // Whenever a package is added or updated we need to update - // the package metadata bookkeeping. + // Whenever a package is added or updated we need to update the package metadata + // bookkeeping. dataChangedImpl(PACKAGE_MANAGER_SENTINEL); } else { - if (replacing) { - // The package is being updated. We'll receive a PACKAGE_ADDED shortly. - } else { - // Outright removal. In the full-data case, the app will be dropped - // from the queue when its (now obsolete) name comes up again for - // backup. + if (!replacing) { + // Outright removal. In the full-data case, the app will be dropped from the + // queue when its (now obsolete) name comes up again for backup. synchronized (mBackupParticipants) { - removePackageParticipantsLocked(pkgList, uid); + removePackageParticipantsLocked(packageList, uid); } } - for (final String pkgName : pkgList) { + + for (String packageName : packageList) { mBackupHandler.post( - () -> mTransportManager.onPackageRemoved(pkgName)); + () -> mTransportManager.onPackageRemoved(packageName)); } } } diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java index 5e84ab0d66f7..7dac79599ac6 100644 --- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java +++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java @@ -71,6 +71,7 @@ import static java.util.stream.Collectors.toList; import android.annotation.Nullable; import android.app.Application; +import android.app.ApplicationPackageManager; import android.app.IBackupAgent; import android.app.backup.BackupAgent; import android.app.backup.BackupDataInput; @@ -134,6 +135,8 @@ import org.mockito.stubbing.Answer; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import org.robolectric.annotation.Implements; +import org.robolectric.annotation.Resetter; import org.robolectric.shadows.ShadowLooper; import org.robolectric.shadows.ShadowPackageManager; import org.robolectric.shadows.ShadowQueuedWork; @@ -157,6 +160,7 @@ import java.util.stream.Stream; @Config( shadows = { FrameworkShadowLooper.class, + KeyValueBackupTaskTest.ShadowApplicationPackageManager.class, ShadowBackupDataInput.class, ShadowBackupDataOutput.class, ShadowEventLog.class, @@ -244,6 +248,7 @@ public class KeyValueBackupTaskTest { @After public void tearDown() throws Exception { ShadowBackupDataInput.reset(); + ShadowApplicationPackageManager.reset(); } @Test @@ -2435,7 +2440,8 @@ public class KeyValueBackupTaskTest { mPackageManager.setApplicationEnabledSetting( packageData.packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0); PackageInfo packageInfo = getPackageInfo(packageData); - mShadowPackageManager.addPackage(packageInfo); + mShadowPackageManager.installPackage(packageInfo); + ShadowApplicationPackageManager.setPackageInfo(packageInfo); mContext.sendBroadcast(getPackageAddedIntent(packageData)); // Run the backup looper because on the receiver we post MSG_SCHEDULE_BACKUP_PACKAGE mShadowBackupLooper.runToEndOfTasks(); @@ -2848,4 +2854,29 @@ public class KeyValueBackupTaskTest { throw mException; } } + + /** + * Extends {@link org.robolectric.shadows.ShadowApplicationPackageManager} to return the correct + * package in user-specific invocations. + */ + @Implements(value = ApplicationPackageManager.class) + public static class ShadowApplicationPackageManager + extends org.robolectric.shadows.ShadowApplicationPackageManager { + private static PackageInfo sPackageInfo; + + static void setPackageInfo(PackageInfo packageInfo) { + sPackageInfo = packageInfo; + } + + @Override + protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId) { + return sPackageInfo; + } + + /** Clear {@link #sPackageInfo}. */ + @Resetter + public static void reset() { + sPackageInfo = null; + } + } } |