summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server/PackageManagerBackupAgent.java
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server/PackageManagerBackupAgent.java')
-rw-r--r--services/java/com/android/server/PackageManagerBackupAgent.java425
1 files changed, 0 insertions, 425 deletions
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/PackageManagerBackupAgent.java
deleted file mode 100644
index 77bddb0..0000000
--- a/services/java/com/android/server/PackageManagerBackupAgent.java
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.app.backup.BackupAgent;
-import android.app.backup.BackupDataInput;
-import android.app.backup.BackupDataOutput;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.Signature;
-import android.os.Build;
-import android.os.ParcelFileDescriptor;
-import android.util.Slog;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.EOFException;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * We back up the signatures of each package so that during a system restore,
- * we can verify that the app whose data we think we have matches the app
- * actually resident on the device.
- *
- * Since the Package Manager isn't a proper "application" we just provide a
- * direct IBackupAgent implementation and hand-construct it at need.
- */
-public class PackageManagerBackupAgent extends BackupAgent {
- private static final String TAG = "PMBA";
- private static final boolean DEBUG = false;
-
- // key under which we store global metadata (individual app metadata
- // is stored using the package name as a key)
- private static final String GLOBAL_METADATA_KEY = "@meta@";
-
- private List<PackageInfo> mAllPackages;
- private PackageManager mPackageManager;
- // version & signature info of each app in a restore set
- private HashMap<String, Metadata> mRestoredSignatures;
- // The version info of each backed-up app as read from the state file
- private HashMap<String, Metadata> mStateVersions = new HashMap<String, Metadata>();
-
- private final HashSet<String> mExisting = new HashSet<String>();
- private int mStoredSdkVersion;
- private String mStoredIncrementalVersion;
- private boolean mHasMetadata;
-
- public class Metadata {
- public int versionCode;
- public Signature[] signatures;
-
- Metadata(int version, Signature[] sigs) {
- versionCode = version;
- signatures = sigs;
- }
- }
-
- // We're constructed with the set of applications that are participating
- // in backup. This set changes as apps are installed & removed.
- PackageManagerBackupAgent(PackageManager packageMgr, List<PackageInfo> packages) {
- mPackageManager = packageMgr;
- mAllPackages = packages;
- mRestoredSignatures = null;
- mHasMetadata = false;
- }
-
- public boolean hasMetadata() {
- return mHasMetadata;
- }
-
- public Metadata getRestoredMetadata(String packageName) {
- if (mRestoredSignatures == null) {
- Slog.w(TAG, "getRestoredMetadata() before metadata read!");
- return null;
- }
-
- return mRestoredSignatures.get(packageName);
- }
-
- public Set<String> getRestoredPackages() {
- if (mRestoredSignatures == null) {
- Slog.w(TAG, "getRestoredPackages() before metadata read!");
- return null;
- }
-
- // This is technically the set of packages on the originating handset
- // that had backup agents at all, not limited to the set of packages
- // that had actually contributed a restore dataset, but it's a
- // close enough approximation for our purposes and does not require any
- // additional involvement by the transport to obtain.
- return mRestoredSignatures.keySet();
- }
-
- // The backed up data is the signature block for each app, keyed by
- // the package name.
- public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
- ParcelFileDescriptor newState) {
- if (DEBUG) Slog.v(TAG, "onBackup()");
-
- ByteArrayOutputStream outputBuffer = new ByteArrayOutputStream(); // we'll reuse these
- DataOutputStream outputBufferStream = new DataOutputStream(outputBuffer);
- parseStateFile(oldState);
-
- // If the stored version string differs, we need to re-backup all
- // of the metadata. We force this by removing everything from the
- // "already backed up" map built by parseStateFile().
- if (mStoredIncrementalVersion == null
- || !mStoredIncrementalVersion.equals(Build.VERSION.INCREMENTAL)) {
- Slog.i(TAG, "Previous metadata " + mStoredIncrementalVersion + " mismatch vs "
- + Build.VERSION.INCREMENTAL + " - rewriting");
- mExisting.clear();
- }
-
- try {
- /*
- * Global metadata:
- *
- * int SDKversion -- the SDK version of the OS itself on the device
- * that produced this backup set. Used to reject
- * backups from later OSes onto earlier ones.
- * String incremental -- the incremental release name of the OS stored in
- * the backup set.
- */
- if (!mExisting.contains(GLOBAL_METADATA_KEY)) {
- if (DEBUG) Slog.v(TAG, "Storing global metadata key");
- outputBufferStream.writeInt(Build.VERSION.SDK_INT);
- outputBufferStream.writeUTF(Build.VERSION.INCREMENTAL);
- writeEntity(data, GLOBAL_METADATA_KEY, outputBuffer.toByteArray());
- } else {
- if (DEBUG) Slog.v(TAG, "Global metadata key already stored");
- // don't consider it to have been skipped/deleted
- mExisting.remove(GLOBAL_METADATA_KEY);
- }
-
- // For each app we have on device, see if we've backed it up yet. If not,
- // write its signature block to the output, keyed on the package name.
- for (PackageInfo pkg : mAllPackages) {
- String packName = pkg.packageName;
- if (packName.equals(GLOBAL_METADATA_KEY)) {
- // We've already handled the metadata key; skip it here
- continue;
- } else {
- PackageInfo info = null;
- try {
- info = mPackageManager.getPackageInfo(packName,
- PackageManager.GET_SIGNATURES);
- } catch (NameNotFoundException e) {
- // Weird; we just found it, and now are told it doesn't exist.
- // Treat it as having been removed from the device.
- mExisting.add(packName);
- continue;
- }
-
- if (mExisting.contains(packName)) {
- // We have backed up this app before. Check whether the version
- // of the backup matches the version of the current app; if they
- // don't match, the app has been updated and we need to store its
- // metadata again. In either case, take it out of mExisting so that
- // we don't consider it deleted later.
- mExisting.remove(packName);
- if (info.versionCode == mStateVersions.get(packName).versionCode) {
- continue;
- }
- }
-
- if (info.signatures == null || info.signatures.length == 0)
- {
- Slog.w(TAG, "Not backing up package " + packName
- + " since it appears to have no signatures.");
- continue;
- }
-
- // We need to store this app's metadata
- /*
- * Metadata for each package:
- *
- * int version -- [4] the package's versionCode
- * byte[] signatures -- [len] flattened Signature[] of the package
- */
-
- // marshal the version code in a canonical form
- outputBuffer.reset();
- outputBufferStream.writeInt(info.versionCode);
- writeSignatureArray(outputBufferStream, info.signatures);
-
- if (DEBUG) {
- Slog.v(TAG, "+ writing metadata for " + packName
- + " version=" + info.versionCode
- + " entityLen=" + outputBuffer.size());
- }
-
- // Now we can write the backup entity for this package
- writeEntity(data, packName, outputBuffer.toByteArray());
- }
- }
-
- // At this point, the only entries in 'existing' are apps that were
- // mentioned in the saved state file, but appear to no longer be present
- // on the device. Write a deletion entity for them.
- for (String app : mExisting) {
- if (DEBUG) Slog.v(TAG, "- removing metadata for deleted pkg " + app);
- try {
- data.writeEntityHeader(app, -1);
- } catch (IOException e) {
- Slog.e(TAG, "Unable to write package deletions!");
- return;
- }
- }
- } catch (IOException e) {
- // Real error writing data
- Slog.e(TAG, "Unable to write package backup data file!");
- return;
- }
-
- // Finally, write the new state blob -- just the list of all apps we handled
- writeStateFile(mAllPackages, newState);
- }
-
- private static void writeEntity(BackupDataOutput data, String key, byte[] bytes)
- throws IOException {
- data.writeEntityHeader(key, bytes.length);
- data.writeEntityData(bytes, bytes.length);
- }
-
- // "Restore" here is a misnomer. What we're really doing is reading back the
- // set of app signatures associated with each backed-up app in this restore
- // image. We'll use those later to determine what we can legitimately restore.
- public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
- throws IOException {
- List<ApplicationInfo> restoredApps = new ArrayList<ApplicationInfo>();
- HashMap<String, Metadata> sigMap = new HashMap<String, Metadata>();
- if (DEBUG) Slog.v(TAG, "onRestore()");
- int storedSystemVersion = -1;
-
- while (data.readNextHeader()) {
- String key = data.getKey();
- int dataSize = data.getDataSize();
-
- if (DEBUG) Slog.v(TAG, " got key=" + key + " dataSize=" + dataSize);
-
- // generic setup to parse any entity data
- byte[] inputBytes = new byte[dataSize];
- data.readEntityData(inputBytes, 0, dataSize);
- ByteArrayInputStream inputBuffer = new ByteArrayInputStream(inputBytes);
- DataInputStream inputBufferStream = new DataInputStream(inputBuffer);
-
- if (key.equals(GLOBAL_METADATA_KEY)) {
- int storedSdkVersion = inputBufferStream.readInt();
- if (DEBUG) Slog.v(TAG, " storedSystemVersion = " + storedSystemVersion);
- if (storedSystemVersion > Build.VERSION.SDK_INT) {
- // returning before setting the sig map means we rejected the restore set
- Slog.w(TAG, "Restore set was from a later version of Android; not restoring");
- return;
- }
- mStoredSdkVersion = storedSdkVersion;
- mStoredIncrementalVersion = inputBufferStream.readUTF();
- mHasMetadata = true;
- if (DEBUG) {
- Slog.i(TAG, "Restore set version " + storedSystemVersion
- + " is compatible with OS version " + Build.VERSION.SDK_INT
- + " (" + mStoredIncrementalVersion + " vs "
- + Build.VERSION.INCREMENTAL + ")");
- }
- } else {
- // it's a file metadata record
- int versionCode = inputBufferStream.readInt();
- Signature[] sigs = readSignatureArray(inputBufferStream);
- if (DEBUG) {
- Slog.i(TAG, " read metadata for " + key
- + " dataSize=" + dataSize
- + " versionCode=" + versionCode + " sigs=" + sigs);
- }
-
- if (sigs == null || sigs.length == 0) {
- Slog.w(TAG, "Not restoring package " + key
- + " since it appears to have no signatures.");
- continue;
- }
-
- ApplicationInfo app = new ApplicationInfo();
- app.packageName = key;
- restoredApps.add(app);
- sigMap.put(key, new Metadata(versionCode, sigs));
- }
- }
-
- // On successful completion, cache the signature map for the Backup Manager to use
- mRestoredSignatures = sigMap;
- }
-
- private static void writeSignatureArray(DataOutputStream out, Signature[] sigs)
- throws IOException {
- // write the number of signatures in the array
- out.writeInt(sigs.length);
-
- // write the signatures themselves, length + flattened buffer
- for (Signature sig : sigs) {
- byte[] flat = sig.toByteArray();
- out.writeInt(flat.length);
- out.write(flat);
- }
- }
-
- private static Signature[] readSignatureArray(DataInputStream in) {
- try {
- int num;
- try {
- num = in.readInt();
- } catch (EOFException e) {
- // clean termination
- Slog.w(TAG, "Read empty signature block");
- return null;
- }
-
- if (DEBUG) Slog.v(TAG, " ... unflatten read " + num);
-
- // Sensical?
- if (num > 20) {
- Slog.e(TAG, "Suspiciously large sig count in restore data; aborting");
- throw new IllegalStateException("Bad restore state");
- }
-
- Signature[] sigs = new Signature[num];
- for (int i = 0; i < num; i++) {
- int len = in.readInt();
- byte[] flatSig = new byte[len];
- in.read(flatSig);
- sigs[i] = new Signature(flatSig);
- }
- return sigs;
- } catch (IOException e) {
- Slog.e(TAG, "Unable to read signatures");
- return null;
- }
- }
-
- // Util: parse out an existing state file into a usable structure
- private void parseStateFile(ParcelFileDescriptor stateFile) {
- mExisting.clear();
- mStateVersions.clear();
- mStoredSdkVersion = 0;
- mStoredIncrementalVersion = null;
-
- // The state file is just the list of app names we have stored signatures for
- // with the exception of the metadata block, to which is also appended the
- // version numbers corresponding with the last time we wrote this PM block.
- // If they mismatch the current system, we'll re-store the metadata key.
- FileInputStream instream = new FileInputStream(stateFile.getFileDescriptor());
- DataInputStream in = new DataInputStream(instream);
-
- int bufSize = 256;
- byte[] buf = new byte[bufSize];
- try {
- String pkg = in.readUTF();
- if (pkg.equals(GLOBAL_METADATA_KEY)) {
- mStoredSdkVersion = in.readInt();
- mStoredIncrementalVersion = in.readUTF();
- mExisting.add(GLOBAL_METADATA_KEY);
- } else {
- Slog.e(TAG, "No global metadata in state file!");
- return;
- }
-
- // The global metadata was first; now read all the apps
- while (true) {
- pkg = in.readUTF();
- int versionCode = in.readInt();
- mExisting.add(pkg);
- mStateVersions.put(pkg, new Metadata(versionCode, null));
- }
- } catch (EOFException eof) {
- // safe; we're done
- } catch (IOException e) {
- // whoops, bad state file. abort.
- Slog.e(TAG, "Unable to read Package Manager state file: " + e);
- }
- }
-
- // Util: write out our new backup state file
- private void writeStateFile(List<PackageInfo> pkgs, ParcelFileDescriptor stateFile) {
- FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
- DataOutputStream out = new DataOutputStream(outstream);
-
- try {
- // by the time we get here we know we've stored the global metadata record
- out.writeUTF(GLOBAL_METADATA_KEY);
- out.writeInt(Build.VERSION.SDK_INT);
- out.writeUTF(Build.VERSION.INCREMENTAL);
-
- // now write all the app names too
- for (PackageInfo pkg : pkgs) {
- out.writeUTF(pkg.packageName);
- out.writeInt(pkg.versionCode);
- }
- } catch (IOException e) {
- Slog.e(TAG, "Unable to write package manager state file!");
- return;
- }
- }
-}