Skip to content

Commit cc55f81

Browse files
author
Christopher Tate
committed
Properly handle PACKAGE_REPLACED in addition to _ADDED and _REMOVED
Certain kinds of application update generate this broadcast regime rather than the REMOVE / ADD sequence that results from e.g. using the -r option when invoking 'adb install'. We also push the agent classname lookup to the last moment before actually running the backup, rather than caching it as part of the record of what apps need a backup pass in the future. This was causing a bug in which a package reinstall that renamed the app's agent class would wind up with a crash at backup time, trying to load the wrong class. Fixes bug 5156094 / bug 4308977 Change-Id: I4e3e12d86e6ee40809f14fd12ab762116dbee0b5
1 parent 960ba91 commit cc55f81

File tree

1 file changed

+29
-21
lines changed

1 file changed

+29
-21
lines changed

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

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -197,14 +197,14 @@ class BackupManagerService extends IBackupManager.Stub {
197197
= new SparseArray<HashSet<ApplicationInfo>>();
198198
// set of backup services that have pending changes
199199
class BackupRequest {
200-
public ApplicationInfo appInfo;
200+
public String packageName;
201201

202-
BackupRequest(ApplicationInfo app) {
203-
appInfo = app;
202+
BackupRequest(String pkgName) {
203+
packageName = pkgName;
204204
}
205205

206206
public String toString() {
207-
return "BackupRequest{app=" + appInfo + "}";
207+
return "BackupRequest{pkg=" + packageName + "}";
208208
}
209209
}
210210
// Backups that we haven't started yet. Keys are package names.
@@ -877,6 +877,7 @@ private void initPackageTracking() {
877877
IntentFilter filter = new IntentFilter();
878878
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
879879
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
880+
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
880881
filter.addDataScheme("package");
881882
mContext.registerReceiver(mBroadcastReceiver, filter);
882883
// Register for events related to sdcard installation.
@@ -1174,7 +1175,8 @@ public void onReceive(Context context, Intent intent) {
11741175
Bundle extras = intent.getExtras();
11751176
String pkgList[] = null;
11761177
if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
1177-
Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
1178+
Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
1179+
Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
11781180
Uri uri = intent.getData();
11791181
if (uri == null) {
11801182
return;
@@ -1183,15 +1185,22 @@ public void onReceive(Context context, Intent intent) {
11831185
if (pkgName != null) {
11841186
pkgList = new String[] { pkgName };
11851187
}
1186-
added = Intent.ACTION_PACKAGE_ADDED.equals(action);
1187-
replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
1188+
if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
1189+
// use the existing "add with replacement" logic
1190+
if (MORE_DEBUG) Slog.d(TAG, "PACKAGE_REPLACED, updating package " + pkgName);
1191+
added = replacing = true;
1192+
} else {
1193+
added = Intent.ACTION_PACKAGE_ADDED.equals(action);
1194+
replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false);
1195+
}
11881196
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
11891197
added = true;
11901198
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
11911199
} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
11921200
added = false;
11931201
pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
11941202
}
1203+
11951204
if (pkgList == null || pkgList.length == 0) {
11961205
return;
11971206
}
@@ -1665,9 +1674,7 @@ public void run() {
16651674
if (status == BackupConstants.TRANSPORT_OK) {
16661675
PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
16671676
mPackageManager, allAgentPackages());
1668-
BackupRequest pmRequest = new BackupRequest(new ApplicationInfo());
1669-
pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
1670-
status = processOneBackup(pmRequest,
1677+
status = processOneBackup(PACKAGE_MANAGER_SENTINEL,
16711678
IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
16721679
}
16731680

@@ -1716,7 +1723,7 @@ public void run() {
17161723
if (status != BackupConstants.TRANSPORT_OK) {
17171724
Slog.w(TAG, "Backup pass unsuccessful, restaging");
17181725
for (BackupRequest req : mQueue) {
1719-
dataChangedImpl(req.appInfo.packageName);
1726+
dataChangedImpl(req.packageName);
17201727
}
17211728

17221729
// We also want to reset the backup schedule based on whatever
@@ -1750,29 +1757,31 @@ private int doQueuedBackups(IBackupTransport transport) {
17501757
// Verify that the requested app exists; it might be something that
17511758
// requested a backup but was then uninstalled. The request was
17521759
// journalled and rather than tamper with the journal it's safer
1753-
// to sanity-check here.
1760+
// to sanity-check here. This also gives us the classname of the
1761+
// package's backup agent.
1762+
PackageInfo pkg;
17541763
try {
1755-
mPackageManager.getPackageInfo(request.appInfo.packageName, 0);
1764+
pkg = mPackageManager.getPackageInfo(request.packageName, 0);
17561765
} catch (NameNotFoundException e) {
17571766
Slog.d(TAG, "Package does not exist; skipping");
17581767
continue;
17591768
}
17601769

17611770
IBackupAgent agent = null;
17621771
try {
1763-
mWakelock.setWorkSource(new WorkSource(request.appInfo.uid));
1764-
agent = bindToAgentSynchronous(request.appInfo,
1772+
mWakelock.setWorkSource(new WorkSource(pkg.applicationInfo.uid));
1773+
agent = bindToAgentSynchronous(pkg.applicationInfo,
17651774
IApplicationThread.BACKUP_MODE_INCREMENTAL);
17661775
if (agent != null) {
1767-
int result = processOneBackup(request, agent, transport);
1776+
int result = processOneBackup(request.packageName, agent, transport);
17681777
if (result != BackupConstants.TRANSPORT_OK) return result;
17691778
}
17701779
} catch (SecurityException ex) {
17711780
// Try for the next one.
17721781
Slog.d(TAG, "error in bind/backup", ex);
17731782
} finally {
17741783
try { // unbind even on timeout, just in case
1775-
mActivityManager.unbindBackupAgent(request.appInfo);
1784+
mActivityManager.unbindBackupAgent(pkg.applicationInfo);
17761785
} catch (RemoteException e) {}
17771786
}
17781787
}
@@ -1782,9 +1791,8 @@ private int doQueuedBackups(IBackupTransport transport) {
17821791
return BackupConstants.TRANSPORT_OK;
17831792
}
17841793

1785-
private int processOneBackup(BackupRequest request, IBackupAgent agent,
1794+
private int processOneBackup(String packageName, IBackupAgent agent,
17861795
IBackupTransport transport) {
1787-
final String packageName = request.appInfo.packageName;
17881796
if (DEBUG) Slog.d(TAG, "processOneBackup doBackup() on " + packageName);
17891797

17901798
File savedStateName = new File(mStateDir, packageName);
@@ -4207,7 +4215,7 @@ private void dataChangedImpl(String packageName, HashSet<ApplicationInfo> target
42074215
if (app.packageName.equals(packageName)) {
42084216
// Add the caller to the set of pending backups. If there is
42094217
// one already there, then overwrite it, but no harm done.
4210-
BackupRequest req = new BackupRequest(app);
4218+
BackupRequest req = new BackupRequest(packageName);
42114219
if (mPendingBackups.put(app.packageName, req) == null) {
42124220
// Journal this request in case of crash. The put()
42134221
// operation returned null when this package was not already
@@ -4218,7 +4226,7 @@ private void dataChangedImpl(String packageName, HashSet<ApplicationInfo> target
42184226
int numKeys = mPendingBackups.size();
42194227
Slog.d(TAG, "Now awaiting backup for " + numKeys + " participants:");
42204228
for (BackupRequest b : mPendingBackups.values()) {
4221-
Slog.d(TAG, " + " + b + " agent=" + b.appInfo.backupAgentName);
4229+
Slog.d(TAG, " + " + b);
42224230
}
42234231
}
42244232
}

0 commit comments

Comments
 (0)