Skip to content

Commit a3d5534

Browse files
author
Christopher Tate
committed
Fix uninstallation tracking in the Backup Manager
This never worked properly; now it does. We also no longer do a redundant pair of remove/add operations when a package is updated. Bonus memory savings: we were keeping sets of ApplicationInfo objects as part of the ongoing bookkeeping, but those were no longer being used for anything other than the package names. That's been tossed out now and only the name strings are now used; hooray for memory savings! Change-Id: I4c6e592a1680e28550bcb4f76789260ded22280d
1 parent b3e2e24 commit a3d5534

File tree

1 file changed

+82
-138
lines changed

1 file changed

+82
-138
lines changed

services/java/com/android/server/BackupManagerService.java

Lines changed: 82 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,9 @@ class BackupManagerService extends IBackupManager.Stub {
201201
BackupHandler mBackupHandler;
202202
PendingIntent mRunBackupIntent, mRunInitIntent;
203203
BroadcastReceiver mRunBackupReceiver, mRunInitReceiver;
204-
// map UIDs to the set of backup client services within that UID's app set
205-
final SparseArray<HashSet<ApplicationInfo>> mBackupParticipants
206-
= new SparseArray<HashSet<ApplicationInfo>>();
204+
// map UIDs to the set of participating packages under that UID
205+
final SparseArray<HashSet<String>> mBackupParticipants
206+
= new SparseArray<HashSet<String>>();
207207
// set of backup services that have pending changes
208208
class BackupRequest {
209209
public String packageName;
@@ -960,7 +960,6 @@ private void initPackageTracking() {
960960
IntentFilter filter = new IntentFilter();
961961
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
962962
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
963-
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
964963
filter.addDataScheme("package");
965964
mContext.registerReceiver(mBroadcastReceiver, filter);
966965
// Register for events related to sdcard installation.
@@ -1239,12 +1238,13 @@ void resetBackupState(File stateFileDir) {
12391238

12401239
// Enqueue a new backup of every participant
12411240
synchronized (mBackupParticipants) {
1242-
int N = mBackupParticipants.size();
1241+
final int N = mBackupParticipants.size();
12431242
for (int i=0; i<N; i++) {
1244-
int uid = mBackupParticipants.keyAt(i);
1245-
HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i);
1246-
for (ApplicationInfo app: participants) {
1247-
dataChangedImpl(app.packageName);
1243+
HashSet<String> participants = mBackupParticipants.valueAt(i);
1244+
if (participants != null) {
1245+
for (String packageName : participants) {
1246+
dataChangedImpl(packageName);
1247+
}
12481248
}
12491249
}
12501250
}
@@ -1302,8 +1302,7 @@ public void onReceive(Context context, Intent intent) {
13021302
Bundle extras = intent.getExtras();
13031303
String pkgList[] = null;
13041304
if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
1305-
Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
1306-
Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
1305+
Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
13071306
Uri uri = intent.getData();
13081307
if (uri == null) {
13091308
return;
@@ -1312,14 +1311,8 @@ public void onReceive(Context context, Intent intent) {
13121311
if (pkgName != null) {
13131312
pkgList = new String[] { pkgName };
13141313
}
1315-
if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
1316-
// use the existing "add with replacement" logic
1317-
if (MORE_DEBUG) Slog.d(TAG, "PACKAGE_REPLACED, updating package " + pkgName);
1318-
added = replacing = true;
1319-
} else {
1320-
added = Intent.ACTION_PACKAGE_ADDED.equals(action);
1321-
replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
1322-
}
1314+
added = Intent.ACTION_PACKAGE_ADDED.equals(action);
1315+
replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
13231316
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
13241317
added = true;
13251318
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
@@ -1331,20 +1324,23 @@ public void onReceive(Context context, Intent intent) {
13311324
if (pkgList == null || pkgList.length == 0) {
13321325
return;
13331326
}
1327+
1328+
final int uid = extras.getInt(Intent.EXTRA_UID);
13341329
if (added) {
13351330
synchronized (mBackupParticipants) {
13361331
if (replacing) {
1337-
updatePackageParticipantsLocked(pkgList);
1338-
} else {
1339-
addPackageParticipantsLocked(pkgList);
1332+
// This is the package-replaced case; we just remove the entry
1333+
// under the old uid and fall through to re-add.
1334+
removePackageParticipantsLocked(pkgList, uid);
13401335
}
1336+
addPackageParticipantsLocked(pkgList);
13411337
}
13421338
} else {
13431339
if (replacing) {
13441340
// The package is being updated. We'll receive a PACKAGE_ADDED shortly.
13451341
} else {
13461342
synchronized (mBackupParticipants) {
1347-
removePackageParticipantsLocked(pkgList);
1343+
removePackageParticipantsLocked(pkgList, uid);
13481344
}
13491345
}
13501346
}
@@ -1391,12 +1387,12 @@ private void addPackageParticipantsLockedInner(String packageName,
13911387
for (PackageInfo pkg : targetPkgs) {
13921388
if (packageName == null || pkg.packageName.equals(packageName)) {
13931389
int uid = pkg.applicationInfo.uid;
1394-
HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
1390+
HashSet<String> set = mBackupParticipants.get(uid);
13951391
if (set == null) {
1396-
set = new HashSet<ApplicationInfo>();
1392+
set = new HashSet<String>();
13971393
mBackupParticipants.put(uid, set);
13981394
}
1399-
set.add(pkg.applicationInfo);
1395+
set.add(pkg.packageName);
14001396
if (MORE_DEBUG) Slog.v(TAG, "Agent found; added");
14011397

14021398
// If we've never seen this app before, schedule a backup for it
@@ -1410,63 +1406,36 @@ private void addPackageParticipantsLockedInner(String packageName,
14101406
}
14111407

14121408
// Remove the given packages' entries from our known active set.
1413-
void removePackageParticipantsLocked(String[] packageNames) {
1409+
void removePackageParticipantsLocked(String[] packageNames, int oldUid) {
14141410
if (packageNames == null) {
14151411
Slog.w(TAG, "removePackageParticipants with null list");
14161412
return;
14171413
}
14181414

1419-
if (DEBUG) Slog.v(TAG, "removePackageParticipantsLocked: #" + packageNames.length);
1420-
List<PackageInfo> knownPackages = allAgentPackages();
1415+
if (DEBUG) Slog.v(TAG, "removePackageParticipantsLocked: uid=" + oldUid
1416+
+ " #" + packageNames.length);
14211417
for (String pkg : packageNames) {
1422-
removePackageParticipantsLockedInner(pkg, knownPackages);
1418+
// Known previous UID, so we know which package set to check
1419+
HashSet<String> set = mBackupParticipants.get(oldUid);
1420+
if (set != null && set.contains(pkg)) {
1421+
removePackageFromSetLocked(set, pkg);
1422+
if (set.isEmpty()) {
1423+
if (MORE_DEBUG) Slog.v(TAG, " last one of this uid; purging set");
1424+
mBackupParticipants.remove(oldUid);
1425+
}
1426+
}
14231427
}
14241428
}
14251429

1426-
private void removePackageParticipantsLockedInner(String packageName,
1427-
List<PackageInfo> allPackages) {
1428-
if (MORE_DEBUG) {
1429-
Slog.v(TAG, "removePackageParticipantsLockedInner (" + packageName
1430-
+ ") removing from " + allPackages.size() + " entries");
1431-
for (PackageInfo p : allPackages) {
1432-
Slog.v(TAG, " - " + p.packageName);
1433-
}
1434-
}
1435-
for (PackageInfo pkg : allPackages) {
1436-
if (packageName == null || pkg.packageName.equals(packageName)) {
1437-
/*
1438-
int uid = -1;
1439-
try {
1440-
PackageInfo info = mPackageManager.getPackageInfo(packageName, 0);
1441-
uid = info.applicationInfo.uid;
1442-
} catch (NameNotFoundException e) {
1443-
// we don't know this package name, so just skip it for now
1444-
continue;
1445-
}
1446-
*/
1447-
final int uid = pkg.applicationInfo.uid;
1448-
if (MORE_DEBUG) Slog.i(TAG, " found pkg " + packageName + " uid=" + uid);
1449-
1450-
HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
1451-
if (set != null) {
1452-
// Find the existing entry with the same package name, and remove it.
1453-
// We can't just remove(app) because the instances are different.
1454-
for (ApplicationInfo entry: set) {
1455-
if (MORE_DEBUG) Slog.i(TAG, " checking against " + entry.packageName);
1456-
if (entry.packageName.equals(pkg)) {
1457-
if (MORE_DEBUG) Slog.v(TAG, " removing participant " + pkg);
1458-
set.remove(entry);
1459-
removeEverBackedUp(pkg.packageName);
1460-
break;
1461-
}
1462-
}
1463-
if (set.size() == 0) {
1464-
mBackupParticipants.delete(uid);
1465-
}
1466-
} else {
1467-
if (MORE_DEBUG) Slog.i(TAG, " ... not found in uid mapping");
1468-
}
1469-
}
1430+
private void removePackageFromSetLocked(final HashSet<String> set,
1431+
final String packageName) {
1432+
if (set.contains(packageName)) {
1433+
// Found it. Remove this one package from the bookkeeping, and
1434+
// if it's the last participating app under this uid we drop the
1435+
// (now-empty) set as well.
1436+
if (MORE_DEBUG) Slog.v(TAG, " removing participant " + packageName);
1437+
removeEverBackedUp(packageName);
1438+
set.remove(packageName);
14701439
}
14711440
}
14721441

@@ -1497,24 +1466,6 @@ List<PackageInfo> allAgentPackages() {
14971466
return packages;
14981467
}
14991468

1500-
// Reset the given package's known backup participants. Unlike add/remove, the update
1501-
// action cannot be passed a null package name.
1502-
void updatePackageParticipantsLocked(String[] packageNames) {
1503-
if (packageNames == null) {
1504-
Slog.e(TAG, "updatePackageParticipants called with null package list");
1505-
return;
1506-
}
1507-
if (DEBUG) Slog.v(TAG, "updatePackageParticipantsLocked: #" + packageNames.length);
1508-
1509-
if (packageNames.length > 0) {
1510-
List<PackageInfo> allApps = allAgentPackages();
1511-
for (String packageName : packageNames) {
1512-
removePackageParticipantsLockedInner(packageName, allApps);
1513-
addPackageParticipantsLockedInner(packageName, allApps);
1514-
}
1515-
}
1516-
}
1517-
15181469
// Called from the backup task: record that the given app has been successfully
15191470
// backed up at least once
15201471
void logBackupComplete(String packageName) {
@@ -4772,11 +4723,11 @@ public void run() {
47724723
}
47734724

47744725
private void dataChangedImpl(String packageName) {
4775-
HashSet<ApplicationInfo> targets = dataChangedTargets(packageName);
4726+
HashSet<String> targets = dataChangedTargets(packageName);
47764727
dataChangedImpl(packageName, targets);
47774728
}
47784729

4779-
private void dataChangedImpl(String packageName, HashSet<ApplicationInfo> targets) {
4730+
private void dataChangedImpl(String packageName, HashSet<String> targets) {
47804731
// Record that we need a backup pass for the caller. Since multiple callers
47814732
// may share a uid, we need to note all candidates within that uid and schedule
47824733
// a backup pass for each of them.
@@ -4790,27 +4741,23 @@ private void dataChangedImpl(String packageName, HashSet<ApplicationInfo> target
47904741

47914742
synchronized (mQueueLock) {
47924743
// Note that this client has made data changes that need to be backed up
4793-
for (ApplicationInfo app : targets) {
4794-
// validate the caller-supplied package name against the known set of
4795-
// packages associated with this uid
4796-
if (app.packageName.equals(packageName)) {
4797-
// Add the caller to the set of pending backups. If there is
4798-
// one already there, then overwrite it, but no harm done.
4799-
BackupRequest req = new BackupRequest(packageName);
4800-
if (mPendingBackups.put(app.packageName, req) == null) {
4801-
if (DEBUG) Slog.d(TAG, "Now staging backup of " + packageName);
4802-
4803-
// Journal this request in case of crash. The put()
4804-
// operation returned null when this package was not already
4805-
// in the set; we want to avoid touching the disk redundantly.
4806-
writeToJournalLocked(packageName);
4744+
if (targets.contains(packageName)) {
4745+
// Add the caller to the set of pending backups. If there is
4746+
// one already there, then overwrite it, but no harm done.
4747+
BackupRequest req = new BackupRequest(packageName);
4748+
if (mPendingBackups.put(packageName, req) == null) {
4749+
if (DEBUG) Slog.d(TAG, "Now staging backup of " + packageName);
4750+
4751+
// Journal this request in case of crash. The put()
4752+
// operation returned null when this package was not already
4753+
// in the set; we want to avoid touching the disk redundantly.
4754+
writeToJournalLocked(packageName);
48074755

4808-
if (MORE_DEBUG) {
4809-
int numKeys = mPendingBackups.size();
4810-
Slog.d(TAG, "Now awaiting backup for " + numKeys + " participants:");
4811-
for (BackupRequest b : mPendingBackups.values()) {
4812-
Slog.d(TAG, " + " + b);
4813-
}
4756+
if (MORE_DEBUG) {
4757+
int numKeys = mPendingBackups.size();
4758+
Slog.d(TAG, "Now awaiting backup for " + numKeys + " participants:");
4759+
for (BackupRequest b : mPendingBackups.values()) {
4760+
Slog.d(TAG, " + " + b);
48144761
}
48154762
}
48164763
}
@@ -4819,7 +4766,7 @@ private void dataChangedImpl(String packageName, HashSet<ApplicationInfo> target
48194766
}
48204767

48214768
// Note: packageName is currently unused, but may be in the future
4822-
private HashSet<ApplicationInfo> dataChangedTargets(String packageName) {
4769+
private HashSet<String> dataChangedTargets(String packageName) {
48234770
// If the caller does not hold the BACKUP permission, it can only request a
48244771
// backup of its own data.
48254772
if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
@@ -4831,11 +4778,11 @@ private HashSet<ApplicationInfo> dataChangedTargets(String packageName) {
48314778

48324779
// a caller with full permission can ask to back up any participating app
48334780
// !!! TODO: allow backup of ANY app?
4834-
HashSet<ApplicationInfo> targets = new HashSet<ApplicationInfo>();
4781+
HashSet<String> targets = new HashSet<String>();
48354782
synchronized (mBackupParticipants) {
48364783
int N = mBackupParticipants.size();
48374784
for (int i = 0; i < N; i++) {
4838-
HashSet<ApplicationInfo> s = mBackupParticipants.valueAt(i);
4785+
HashSet<String> s = mBackupParticipants.valueAt(i);
48394786
if (s != null) {
48404787
targets.addAll(s);
48414788
}
@@ -4862,7 +4809,7 @@ private void writeToJournalLocked(String str) {
48624809
// ----- IBackupManager binder interface -----
48634810

48644811
public void dataChanged(final String packageName) {
4865-
final HashSet<ApplicationInfo> targets = dataChangedTargets(packageName);
4812+
final HashSet<String> targets = dataChangedTargets(packageName);
48664813
if (targets == null) {
48674814
Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"
48684815
+ " uid=" + Binder.getCallingUid());
@@ -4889,38 +4836,35 @@ public void clearBackupData(String packageName) {
48894836

48904837
// If the caller does not hold the BACKUP permission, it can only request a
48914838
// wipe of its own backed-up data.
4892-
HashSet<ApplicationInfo> apps;
4839+
HashSet<String> apps;
48934840
if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(),
48944841
Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
48954842
apps = mBackupParticipants.get(Binder.getCallingUid());
48964843
} else {
48974844
// a caller with full permission can ask to back up any participating app
48984845
// !!! TODO: allow data-clear of ANY app?
48994846
if (DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps");
4900-
apps = new HashSet<ApplicationInfo>();
4847+
apps = new HashSet<String>();
49014848
int N = mBackupParticipants.size();
49024849
for (int i = 0; i < N; i++) {
4903-
HashSet<ApplicationInfo> s = mBackupParticipants.valueAt(i);
4850+
HashSet<String> s = mBackupParticipants.valueAt(i);
49044851
if (s != null) {
49054852
apps.addAll(s);
49064853
}
49074854
}
49084855
}
49094856

4910-
// now find the given package in the set of candidate apps
4911-
for (ApplicationInfo app : apps) {
4912-
if (app.packageName.equals(packageName)) {
4913-
if (DEBUG) Slog.v(TAG, "Found the app - running clear process");
4914-
// found it; fire off the clear request
4915-
synchronized (mQueueLock) {
4916-
long oldId = Binder.clearCallingIdentity();
4917-
mWakelock.acquire();
4918-
Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
4919-
new ClearParams(getTransport(mCurrentTransport), info));
4920-
mBackupHandler.sendMessage(msg);
4921-
Binder.restoreCallingIdentity(oldId);
4922-
}
4923-
break;
4857+
// Is the given app an available participant?
4858+
if (apps.contains(packageName)) {
4859+
if (DEBUG) Slog.v(TAG, "Found the app - running clear process");
4860+
// found it; fire off the clear request
4861+
synchronized (mQueueLock) {
4862+
long oldId = Binder.clearCallingIdentity();
4863+
mWakelock.acquire();
4864+
Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR,
4865+
new ClearParams(getTransport(mCurrentTransport), info));
4866+
mBackupHandler.sendMessage(msg);
4867+
Binder.restoreCallingIdentity(oldId);
49244868
}
49254869
}
49264870
}
@@ -5838,9 +5782,9 @@ private void dumpInternal(PrintWriter pw) {
58385782
int uid = mBackupParticipants.keyAt(i);
58395783
pw.print(" uid: ");
58405784
pw.println(uid);
5841-
HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i);
5842-
for (ApplicationInfo app: participants) {
5843-
pw.println(" " + app.packageName);
5785+
HashSet<String> participants = mBackupParticipants.valueAt(i);
5786+
for (String app: participants) {
5787+
pw.println(" " + app);
58445788
}
58455789
}
58465790

0 commit comments

Comments
 (0)