summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Tate <ctate@google.com>2009-06-18 18:35:32 -0700
committerChristopher Tate <ctate@google.com>2009-06-18 18:38:02 -0700
commitabce4e8714bed26a2b37b20ad3f02cf619d71c9a (patch)
tree274cf438fcda8dca4b13a056bc73fea61ba4dd77
parent2810f681991d1beb5ceb3515159f9fad3cc341d5 (diff)
downloadframeworks_base-abce4e8714bed26a2b37b20ad3f02cf619d71c9a.zip
frameworks_base-abce4e8714bed26a2b37b20ad3f02cf619d71c9a.tar.gz
frameworks_base-abce4e8714bed26a2b37b20ad3f02cf619d71c9a.tar.bz2
Use signatures on restore
On restore now, the backup manager gets the signature blocks corresponding to the restore set from the transport. It then validates those signatures against the on-device app signatures, and refuses to restore data to an app whose on-device sig block does not match the backup image's. Also actually implement 'bmgr transport N' so that we can select the local transport easily during runtime.
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java21
-rw-r--r--services/java/com/android/server/BackupManagerService.java60
2 files changed, 78 insertions, 3 deletions
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 3af80fa..841e3df 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -80,6 +80,14 @@ public final class Bmgr {
doRestore();
return;
}
+
+ if ("transport".equals(op)) {
+ doTransport();
+ return;
+ }
+
+ System.err.println("Unknown command");
+ showUsage();
}
private void doRun() {
@@ -113,6 +121,19 @@ public final class Bmgr {
}
}
+ private void doTransport() {
+ try {
+ int which = Integer.parseInt(nextArg());
+ int old = mBmgr.selectBackupTransport(which);
+ System.out.println("Selected transport " + which + " (formerly " + old + ")");
+ } catch (NumberFormatException e) {
+ showUsage();
+ } catch (RemoteException e) {
+ System.err.println(e.toString());
+ System.err.println(BMGR_NOT_RUNNING_ERR);
+ }
+ }
+
private void doList() {
String arg = nextArg(); // sets, transports, packages set#
if ("transports".equals(arg)) {
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index f9a6f5b..6ee8260 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -31,6 +31,7 @@ import android.content.pm.IPackageDataObserver;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager;
+import android.content.pm.Signature;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -153,7 +154,9 @@ class BackupManagerService extends IBackupManager.Stub {
mJournalDir.mkdirs();
makeJournalLocked(); // okay because no other threads are running yet
- // Build our mapping of uid to backup client services
+ // Build our mapping of uid to backup client services. This implicitly
+ // schedules a backup pass on the Package Manager metadata the first
+ // time anything needs to be backed up.
synchronized (mBackupParticipants) {
addPackageParticipantsLocked(null);
}
@@ -656,8 +659,15 @@ class BackupManagerService extends IBackupManager.Stub {
// Look up the package info & signatures. This is first so that if it
// throws an exception, there's no file setup yet that would need to
// be unraveled.
- PackageInfo packInfo = mPackageManager.getPackageInfo(packageName,
+ PackageInfo packInfo;
+ if (packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
+ // The metadata 'package' is synthetic
+ packInfo = new PackageInfo();
+ packInfo.packageName = packageName;
+ } else {
+ packInfo = mPackageManager.getPackageInfo(packageName,
PackageManager.GET_SIGNATURES);
+ }
// !!! TODO: get the state file dir from the transport
File savedStateName = new File(mStateDir, packageName);
@@ -745,6 +755,28 @@ class BackupManagerService extends IBackupManager.Stub {
return null;
}
+ private boolean signaturesMatch(Signature[] storedSigs, Signature[] deviceSigs) {
+ // !!! TODO: this demands that every stored signature match one
+ // that is present on device, and does not demand the converse.
+ // Is this this right policy?
+ int nStored = storedSigs.length;
+ int nDevice = deviceSigs.length;
+
+ for (int i=0; i < nStored; i++) {
+ boolean match = false;
+ for (int j=0; j < nDevice; j++) {
+ if (storedSigs[i].equals(deviceSigs[j])) {
+ match = true;
+ break;
+ }
+ }
+ if (!match) {
+ return false;
+ }
+ }
+ return true;
+ }
+
class PerformRestoreThread extends Thread {
private IBackupTransport mTransport;
private int mToken;
@@ -791,6 +823,13 @@ class BackupManagerService extends IBackupManager.Stub {
// !!! TODO: pick out the set for this token
mImage = images[0];
+ // Pull the Package Manager metadata from the restore set first
+ PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+ mPackageManager, allAgentApps());
+ PackageInfo pmApp = new PackageInfo();
+ pmApp.packageName = PACKAGE_MANAGER_SENTINEL;
+ processOneRestore(pmApp, IBackupAgent.Stub.asInterface(pmAgent.onBind()));
+
// build the set of apps we will attempt to restore
PackageInfo[] packages = mTransport.getAppSet(mImage.token);
HashSet<PackageInfo> appsToRestore = new HashSet<PackageInfo>();
@@ -798,7 +837,20 @@ class BackupManagerService extends IBackupManager.Stub {
// get the real PackageManager idea of the package
PackageInfo app = isRestorable(pkg);
if (app != null) {
- appsToRestore.add(app);
+ // Validate against the backed-up signature block, too
+ Signature[] storedSigs
+ = pmAgent.getRestoredSignatures(app.packageName);
+ if (storedSigs != null) {
+ // !!! TODO: check app version here as well
+ if (signaturesMatch(storedSigs, app.signatures)) {
+ appsToRestore.add(app);
+ } else {
+ Log.w(TAG, "Sig mismatch on restore of " + app.packageName);
+ }
+ } else {
+ Log.i(TAG, "No stored sigs for " + app.packageName
+ + " so not restoring");
+ }
}
}
@@ -1002,6 +1054,7 @@ class BackupManagerService extends IBackupManager.Stub {
// Report the currently active transport
public int getCurrentTransport() {
mContext.enforceCallingPermission("android.permission.BACKUP", "selectBackupTransport");
+ Log.v(TAG, "getCurrentTransport() returning " + mTransportId);
return mTransportId;
}
@@ -1011,6 +1064,7 @@ class BackupManagerService extends IBackupManager.Stub {
int prevTransport = mTransportId;
mTransportId = transportId;
+ Log.v(TAG, "selectBackupTransport() set " + mTransportId + " returning " + prevTransport);
return prevTransport;
}