Merge change 5196 into donut
* changes: Modify the IBackupTransport API to support bulk restore operations. Change the BackupManagerService and LocalTransport to support the new API.
This commit is contained in:
@@ -43,14 +43,14 @@ public class RestoreSet implements Parcelable {
|
|||||||
* transport. This is guaranteed to be valid for the duration of a restore
|
* transport. This is guaranteed to be valid for the duration of a restore
|
||||||
* session, but is meaningless once the session has ended.
|
* session, but is meaningless once the session has ended.
|
||||||
*/
|
*/
|
||||||
public int token;
|
public long token;
|
||||||
|
|
||||||
|
|
||||||
public RestoreSet() {
|
public RestoreSet() {
|
||||||
// Leave everything zero / null
|
// Leave everything zero / null
|
||||||
}
|
}
|
||||||
|
|
||||||
public RestoreSet(String _name, String _dev, int _token) {
|
public RestoreSet(String _name, String _dev, long _token) {
|
||||||
name = _name;
|
name = _name;
|
||||||
device = _dev;
|
device = _dev;
|
||||||
token = _token;
|
token = _token;
|
||||||
@@ -65,7 +65,7 @@ public class RestoreSet implements Parcelable {
|
|||||||
public void writeToParcel(Parcel out, int flags) {
|
public void writeToParcel(Parcel out, int flags) {
|
||||||
out.writeString(name);
|
out.writeString(name);
|
||||||
out.writeString(device);
|
out.writeString(device);
|
||||||
out.writeInt(token);
|
out.writeLong(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Parcelable.Creator<RestoreSet> CREATOR
|
public static final Parcelable.Creator<RestoreSet> CREATOR
|
||||||
@@ -82,6 +82,6 @@ public class RestoreSet implements Parcelable {
|
|||||||
private RestoreSet(Parcel in) {
|
private RestoreSet(Parcel in) {
|
||||||
name = in.readString();
|
name = in.readString();
|
||||||
device = in.readString();
|
device = in.readString();
|
||||||
token = in.readInt();
|
token = in.readLong();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,63 +54,70 @@ interface IBackupTransport {
|
|||||||
long requestBackupTime();
|
long requestBackupTime();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establish a connection to the back-end data repository, if necessary. If the transport
|
* Send one application's data to the backup destination. The transport may send
|
||||||
* needs to initialize state that is not tied to individual applications' backup operations,
|
* the data immediately, or may buffer it. After this is called, {@link #finishBackup}
|
||||||
* this is where it should be done.
|
* must be called to ensure the data is sent and recorded successfully.
|
||||||
*
|
|
||||||
* @return Zero on success; a nonzero error code on failure.
|
|
||||||
*/
|
|
||||||
int startSession();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send one application's data to the backup destination.
|
|
||||||
*
|
*
|
||||||
* @param packageInfo The identity of the application whose data is being backed up.
|
* @param packageInfo The identity of the application whose data is being backed up.
|
||||||
* This specifically includes the signature list for the package.
|
* This specifically includes the signature list for the package.
|
||||||
* @param data The data stream that resulted from invoking the application's
|
* @param data The data stream that resulted from invoking the application's
|
||||||
* BackupService.doBackup() method. This may be a pipe rather than a file on
|
* BackupService.doBackup() method. This may be a pipe rather than a file on
|
||||||
* persistent media, so it may not be seekable.
|
* persistent media, so it may not be seekable.
|
||||||
* @return Zero on success; a nonzero error code on failure.
|
* @return false if errors occurred (the backup should be aborted and rescheduled),
|
||||||
|
* true if everything is OK so far (but {@link #finishBackup} must be called).
|
||||||
*/
|
*/
|
||||||
int performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor data);
|
boolean performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor inFd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finish sending application data to the backup destination. This must be
|
||||||
|
* called after {@link #performBackup} to ensure that all data is sent. Only
|
||||||
|
* when this method returns true can the backup be assumed to have succeeded.
|
||||||
|
*
|
||||||
|
* @return false if errors occurred (the backup should be aborted and rescheduled),
|
||||||
|
* true if everything is OK so far (but {@link #finishBackup} must be called).
|
||||||
|
*/
|
||||||
|
boolean finishBackup();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the set of backups currently available over this transport.
|
* Get the set of backups currently available over this transport.
|
||||||
*
|
*
|
||||||
* @return Descriptions of the set of restore images available for this device.
|
* @return Descriptions of the set of restore images available for this device,
|
||||||
|
* or null if an error occurred (the attempt should be rescheduled).
|
||||||
**/
|
**/
|
||||||
RestoreSet[] getAvailableRestoreSets();
|
RestoreSet[] getAvailableRestoreSets();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the set of applications from a given restore image.
|
* Start restoring application data from backup. After calling this function,
|
||||||
|
* alternate calls to {@link #nextRestorePackage} and {@link #nextRestoreData}
|
||||||
|
* to walk through the actual application data.
|
||||||
*
|
*
|
||||||
* @param token A backup token as returned by {@link #getAvailableRestoreSets}.
|
* @param token A backup token as returned by {@link #getAvailableRestoreSets}.
|
||||||
* @return An array of PackageInfo objects describing all of the applications
|
* @param packages List of applications to restore (if data is available).
|
||||||
* available for restore from this restore image. This should include the list
|
* Application data will be restored in the order given.
|
||||||
* of signatures for each package so that the Backup Manager can filter using that
|
* @return false if errors occurred (the restore should be aborted and rescheduled),
|
||||||
* information.
|
* true if everything is OK so far (go ahead and call {@link #nextRestorePackage}).
|
||||||
*/
|
*/
|
||||||
PackageInfo[] getAppSet(int token);
|
boolean startRestore(long token, in PackageInfo[] packages);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve one application's data from the backing store.
|
* Get the package name of the next application with data in the backup store.
|
||||||
*
|
* @return The name of one of the packages supplied to {@link #startRestore},
|
||||||
* @param token The backup record from which a restore is being requested.
|
* or "" (the empty string) if no more backup data is available,
|
||||||
* @param packageInfo The identity of the application whose data is being restored.
|
* or null if an error occurred (the restore should be aborted and rescheduled).
|
||||||
* This must include the signature list for the package; it is up to the transport
|
|
||||||
* to verify that the requested app's signatures match the saved backup record
|
|
||||||
* because the transport cannot necessarily trust the client device.
|
|
||||||
* @param data An open, writable file into which the backup image should be stored.
|
|
||||||
* @return Zero on success; a nonzero error code on failure.
|
|
||||||
*/
|
*/
|
||||||
int getRestoreData(int token, in PackageInfo packageInfo, in ParcelFileDescriptor data);
|
String nextRestorePackage();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminate the backup session, closing files, freeing memory, and cleaning up whatever
|
* Get the data for the application returned by {@link #nextRestorePackage}.
|
||||||
* other state the transport required.
|
* @param data An open, writable file into which the backup data should be stored.
|
||||||
*
|
* @return false if errors occurred (the restore should be aborted and rescheduled),
|
||||||
* @return Zero on success; a nonzero error code on failure. Even on failure, the session
|
* true if everything is OK so far (go ahead and call {@link #nextRestorePackage}).
|
||||||
* is torn down and must be restarted if another backup is attempted.
|
|
||||||
*/
|
*/
|
||||||
int endSession();
|
boolean getRestoreData(in ParcelFileDescriptor outFd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End a restore session (aborting any in-process data transfer as necessary),
|
||||||
|
* freeing any resources and connections used during the restore process.
|
||||||
|
*/
|
||||||
|
void finishRestore();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,11 +33,8 @@ public class LocalTransport extends IBackupTransport.Stub {
|
|||||||
private Context mContext;
|
private Context mContext;
|
||||||
private PackageManager mPackageManager;
|
private PackageManager mPackageManager;
|
||||||
private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup");
|
private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup");
|
||||||
private FileFilter mDirFileFilter = new FileFilter() {
|
private PackageInfo[] mRestorePackages = null;
|
||||||
public boolean accept(File f) {
|
private int mRestorePackage = -1; // Index into mRestorePackages
|
||||||
return f.isDirectory();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
public LocalTransport(Context context) {
|
public LocalTransport(Context context) {
|
||||||
@@ -51,21 +48,9 @@ public class LocalTransport extends IBackupTransport.Stub {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int startSession() throws RemoteException {
|
public boolean performBackup(PackageInfo packageInfo, ParcelFileDescriptor data)
|
||||||
if (DEBUG) Log.v(TAG, "session started");
|
|
||||||
mDataDir.mkdirs();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int endSession() throws RemoteException {
|
|
||||||
if (DEBUG) Log.v(TAG, "session ended");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data)
|
|
||||||
throws RemoteException {
|
throws RemoteException {
|
||||||
if (DEBUG) Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName);
|
if (DEBUG) Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName);
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
File packageDir = new File(mDataDir, packageInfo.packageName);
|
File packageDir = new File(mDataDir, packageInfo.packageName);
|
||||||
packageDir.mkdirs();
|
packageDir.mkdirs();
|
||||||
@@ -101,9 +86,8 @@ public class LocalTransport extends IBackupTransport.Stub {
|
|||||||
try {
|
try {
|
||||||
entity.write(buf, 0, dataSize);
|
entity.write(buf, 0, dataSize);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "Unable to update key file "
|
Log.e(TAG, "Unable to update key file " + entityFile.getAbsolutePath());
|
||||||
+ entityFile.getAbsolutePath());
|
return false;
|
||||||
err = -1;
|
|
||||||
} finally {
|
} finally {
|
||||||
entity.close();
|
entity.close();
|
||||||
}
|
}
|
||||||
@@ -111,14 +95,17 @@ public class LocalTransport extends IBackupTransport.Stub {
|
|||||||
entityFile.delete();
|
entityFile.delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// oops, something went wrong. abort the operation and return error.
|
// oops, something went wrong. abort the operation and return error.
|
||||||
Log.v(TAG, "Exception reading backup input:");
|
Log.v(TAG, "Exception reading backup input:", e);
|
||||||
e.printStackTrace();
|
return false;
|
||||||
err = -1;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
public boolean finishBackup() throws RemoteException {
|
||||||
|
if (DEBUG) Log.v(TAG, "finishBackup()");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore handling
|
// Restore handling
|
||||||
@@ -129,72 +116,66 @@ public class LocalTransport extends IBackupTransport.Stub {
|
|||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PackageInfo[] getAppSet(int token) throws android.os.RemoteException {
|
public boolean startRestore(long token, PackageInfo[] packages) {
|
||||||
if (DEBUG) Log.v(TAG, "getting app set " + token);
|
if (DEBUG) Log.v(TAG, "start restore " + token);
|
||||||
// the available packages are the extant subdirs of mDatadir
|
mRestorePackages = packages;
|
||||||
File[] packageDirs = mDataDir.listFiles(mDirFileFilter);
|
mRestorePackage = -1;
|
||||||
ArrayList<PackageInfo> packages = new ArrayList<PackageInfo>();
|
return true;
|
||||||
for (File dir : packageDirs) {
|
|
||||||
try {
|
|
||||||
PackageInfo pkg = mPackageManager.getPackageInfo(dir.getName(),
|
|
||||||
PackageManager.GET_SIGNATURES);
|
|
||||||
if (pkg != null) {
|
|
||||||
packages.add(pkg);
|
|
||||||
}
|
|
||||||
} catch (NameNotFoundException e) {
|
|
||||||
// restore set contains data for a package not installed on the
|
|
||||||
// phone -- just ignore it.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.v(TAG, "Built app set of " + packages.size() + " entries:");
|
|
||||||
for (PackageInfo p : packages) {
|
|
||||||
Log.v(TAG, " + " + p.packageName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PackageInfo[] result = new PackageInfo[packages.size()];
|
|
||||||
return packages.toArray(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRestoreData(int token, PackageInfo packageInfo, ParcelFileDescriptor outFd)
|
public String nextRestorePackage() {
|
||||||
throws android.os.RemoteException {
|
if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
|
||||||
if (DEBUG) Log.v(TAG, "getting restore data " + token + " : " + packageInfo.packageName);
|
while (++mRestorePackage < mRestorePackages.length) {
|
||||||
// we only support one hardcoded restore set
|
String name = mRestorePackages[mRestorePackage].packageName;
|
||||||
if (token != 0) return -1;
|
if (new File(mDataDir, name).isDirectory()) {
|
||||||
|
if (DEBUG) Log.v(TAG, " nextRestorePackage() = " + name);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// the data for a given package is at a known location
|
if (DEBUG) Log.v(TAG, " no more packages to restore");
|
||||||
File packageDir = new File(mDataDir, packageInfo.packageName);
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getRestoreData(ParcelFileDescriptor outFd) {
|
||||||
|
if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
|
||||||
|
if (mRestorePackage < 0) throw new IllegalStateException("nextRestorePackage not called");
|
||||||
|
File packageDir = new File(mDataDir, mRestorePackages[mRestorePackage].packageName);
|
||||||
|
|
||||||
// The restore set is the concatenation of the individual record blobs,
|
// The restore set is the concatenation of the individual record blobs,
|
||||||
// each of which is a file in the package's directory
|
// each of which is a file in the package's directory
|
||||||
File[] blobs = packageDir.listFiles();
|
File[] blobs = packageDir.listFiles();
|
||||||
if (DEBUG) Log.v(TAG, " found " + blobs.length + " key files");
|
if (blobs == null) {
|
||||||
int err = 0;
|
Log.e(TAG, "Error listing directory: " + packageDir);
|
||||||
if (blobs != null && blobs.length > 0) {
|
return false; // nextRestorePackage() ensures the dir exists, so this is an error
|
||||||
BackupDataOutput out = new BackupDataOutput(outFd.getFileDescriptor());
|
}
|
||||||
try {
|
|
||||||
for (File f : blobs) {
|
// We expect at least some data if the directory exists in the first place
|
||||||
copyToRestoreData(f, out);
|
if (DEBUG) Log.v(TAG, " getRestoreData() found " + blobs.length + " key files");
|
||||||
}
|
BackupDataOutput out = new BackupDataOutput(outFd.getFileDescriptor());
|
||||||
} catch (Exception e) {
|
try {
|
||||||
Log.e(TAG, "Unable to read backup records");
|
for (File f : blobs) {
|
||||||
err = -1;
|
FileInputStream in = new FileInputStream(f);
|
||||||
}
|
try {
|
||||||
|
int size = (int) f.length();
|
||||||
|
byte[] buf = new byte[size];
|
||||||
|
in.read(buf);
|
||||||
|
String key = new String(Base64.decode(f.getName()));
|
||||||
|
if (DEBUG) Log.v(TAG, " ... key=" + key + " size=" + size);
|
||||||
|
out.writeEntityHeader(key, size);
|
||||||
|
out.writeEntityData(buf, size);
|
||||||
|
} finally {
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "Unable to read backup records", e);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void copyToRestoreData(File f, BackupDataOutput out) throws IOException {
|
public void finishRestore() {
|
||||||
FileInputStream in = new FileInputStream(f);
|
if (DEBUG) Log.v(TAG, "finishRestore()");
|
||||||
int size = (int) f.length();
|
|
||||||
byte[] buf = new byte[size];
|
|
||||||
in.read(buf);
|
|
||||||
String key = new String(Base64.decode(f.getName()));
|
|
||||||
if (DEBUG) Log.v(TAG, " ... copy to stream: key=" + key
|
|
||||||
+ " size=" + size);
|
|
||||||
out.writeEntityHeader(key, size);
|
|
||||||
out.writeEntityData(buf, size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -351,28 +351,28 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
void addPackageParticipantsLocked(String packageName) {
|
void addPackageParticipantsLocked(String packageName) {
|
||||||
// Look for apps that define the android:backupAgent attribute
|
// Look for apps that define the android:backupAgent attribute
|
||||||
if (DEBUG) Log.v(TAG, "addPackageParticipantsLocked: " + packageName);
|
if (DEBUG) Log.v(TAG, "addPackageParticipantsLocked: " + packageName);
|
||||||
List<ApplicationInfo> targetApps = allAgentApps();
|
List<PackageInfo> targetApps = allAgentPackages();
|
||||||
addPackageParticipantsLockedInner(packageName, targetApps);
|
addPackageParticipantsLockedInner(packageName, targetApps);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPackageParticipantsLockedInner(String packageName,
|
private void addPackageParticipantsLockedInner(String packageName,
|
||||||
List<ApplicationInfo> targetApps) {
|
List<PackageInfo> targetPkgs) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.v(TAG, "Adding " + targetApps.size() + " backup participants:");
|
Log.v(TAG, "Adding " + targetPkgs.size() + " backup participants:");
|
||||||
for (ApplicationInfo a : targetApps) {
|
for (PackageInfo p : targetPkgs) {
|
||||||
Log.v(TAG, " " + a + " agent=" + a.backupAgentName);
|
Log.v(TAG, " " + p + " agent=" + p.applicationInfo.backupAgentName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ApplicationInfo app : targetApps) {
|
for (PackageInfo pkg : targetPkgs) {
|
||||||
if (packageName == null || app.packageName.equals(packageName)) {
|
if (packageName == null || pkg.packageName.equals(packageName)) {
|
||||||
int uid = app.uid;
|
int uid = pkg.applicationInfo.uid;
|
||||||
HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
|
HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
|
||||||
if (set == null) {
|
if (set == null) {
|
||||||
set = new HashSet<ApplicationInfo>();
|
set = new HashSet<ApplicationInfo>();
|
||||||
mBackupParticipants.put(uid, set);
|
mBackupParticipants.put(uid, set);
|
||||||
}
|
}
|
||||||
set.add(app);
|
set.add(pkg.applicationInfo);
|
||||||
backUpPackageManagerData();
|
backUpPackageManagerData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -382,67 +382,67 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
// 'packageName' is null, *all* participating apps will be removed.
|
// 'packageName' is null, *all* participating apps will be removed.
|
||||||
void removePackageParticipantsLocked(String packageName) {
|
void removePackageParticipantsLocked(String packageName) {
|
||||||
if (DEBUG) Log.v(TAG, "removePackageParticipantsLocked: " + packageName);
|
if (DEBUG) Log.v(TAG, "removePackageParticipantsLocked: " + packageName);
|
||||||
List<ApplicationInfo> allApps = null;
|
List<PackageInfo> allApps = null;
|
||||||
if (packageName != null) {
|
if (packageName != null) {
|
||||||
allApps = new ArrayList<ApplicationInfo>();
|
allApps = new ArrayList<PackageInfo>();
|
||||||
try {
|
try {
|
||||||
ApplicationInfo app = mPackageManager.getApplicationInfo(packageName, 0);
|
int flags = PackageManager.GET_SIGNATURES;
|
||||||
allApps.add(app);
|
allApps.add(mPackageManager.getPackageInfo(packageName, flags));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// just skip it
|
// just skip it (???)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// all apps with agents
|
// all apps with agents
|
||||||
allApps = allAgentApps();
|
allApps = allAgentPackages();
|
||||||
}
|
}
|
||||||
removePackageParticipantsLockedInner(packageName, allApps);
|
removePackageParticipantsLockedInner(packageName, allApps);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removePackageParticipantsLockedInner(String packageName,
|
private void removePackageParticipantsLockedInner(String packageName,
|
||||||
List<ApplicationInfo> agents) {
|
List<PackageInfo> agents) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.v(TAG, "removePackageParticipantsLockedInner (" + packageName
|
Log.v(TAG, "removePackageParticipantsLockedInner (" + packageName
|
||||||
+ ") removing " + agents.size() + " entries");
|
+ ") removing " + agents.size() + " entries");
|
||||||
for (ApplicationInfo a : agents) {
|
for (PackageInfo p : agents) {
|
||||||
Log.v(TAG, " - " + a);
|
Log.v(TAG, " - " + p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (ApplicationInfo app : agents) {
|
for (PackageInfo pkg : agents) {
|
||||||
if (packageName == null || app.packageName.equals(packageName)) {
|
if (packageName == null || pkg.packageName.equals(packageName)) {
|
||||||
int uid = app.uid;
|
int uid = pkg.applicationInfo.uid;
|
||||||
HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
|
HashSet<ApplicationInfo> set = mBackupParticipants.get(uid);
|
||||||
if (set != null) {
|
if (set != null) {
|
||||||
// Find the existing entry with the same package name, and remove it.
|
// Find the existing entry with the same package name, and remove it.
|
||||||
// We can't just remove(app) because the instances are different.
|
// We can't just remove(app) because the instances are different.
|
||||||
for (ApplicationInfo entry: set) {
|
for (ApplicationInfo entry: set) {
|
||||||
if (entry.packageName.equals(app.packageName)) {
|
if (entry.packageName.equals(pkg.packageName)) {
|
||||||
set.remove(entry);
|
set.remove(entry);
|
||||||
backUpPackageManagerData();
|
backUpPackageManagerData();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (set.size() == 0) {
|
if (set.size() == 0) {
|
||||||
mBackupParticipants.delete(uid); }
|
mBackupParticipants.delete(uid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the set of all applications that define an android:backupAgent attribute
|
// Returns the set of all applications that define an android:backupAgent attribute
|
||||||
private List<ApplicationInfo> allAgentApps() {
|
private List<PackageInfo> allAgentPackages() {
|
||||||
// !!! TODO: cache this and regenerate only when necessary
|
// !!! TODO: cache this and regenerate only when necessary
|
||||||
List<ApplicationInfo> allApps = mPackageManager.getInstalledApplications(0);
|
int flags = PackageManager.GET_SIGNATURES;
|
||||||
int N = allApps.size();
|
List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
|
||||||
if (N > 0) {
|
int N = packages.size();
|
||||||
for (int a = N-1; a >= 0; a--) {
|
for (int a = N-1; a >= 0; a--) {
|
||||||
ApplicationInfo app = allApps.get(a);
|
ApplicationInfo app = packages.get(a).applicationInfo;
|
||||||
if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
|
if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
|
||||||
|| app.backupAgentName == null) {
|
|| app.backupAgentName == null) {
|
||||||
allApps.remove(a);
|
packages.remove(a);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return allApps;
|
return packages;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the given package's known backup participants. Unlike add/remove, the update
|
// Reset the given package's known backup participants. Unlike add/remove, the update
|
||||||
@@ -455,7 +455,7 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
if (DEBUG) Log.v(TAG, "updatePackageParticipantsLocked: " + packageName);
|
if (DEBUG) Log.v(TAG, "updatePackageParticipantsLocked: " + packageName);
|
||||||
|
|
||||||
// brute force but small code size
|
// brute force but small code size
|
||||||
List<ApplicationInfo> allApps = allAgentApps();
|
List<PackageInfo> allApps = allAgentPackages();
|
||||||
removePackageParticipantsLockedInner(packageName, allApps);
|
removePackageParticipantsLockedInner(packageName, allApps);
|
||||||
addPackageParticipantsLockedInner(packageName, allApps);
|
addPackageParticipantsLockedInner(packageName, allApps);
|
||||||
}
|
}
|
||||||
@@ -578,17 +578,7 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
public void run() {
|
public void run() {
|
||||||
if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
|
if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
|
||||||
|
|
||||||
// start up the transport
|
// First, back up the package manager metadata if necessary
|
||||||
try {
|
|
||||||
mTransport.startSession();
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "Error session transport");
|
|
||||||
e.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The transport is up and running. First, back up the package manager
|
|
||||||
// metadata if necessary
|
|
||||||
boolean doPackageManager;
|
boolean doPackageManager;
|
||||||
synchronized (BackupManagerService.this) {
|
synchronized (BackupManagerService.this) {
|
||||||
doPackageManager = mDoPackageManager;
|
doPackageManager = mDoPackageManager;
|
||||||
@@ -601,7 +591,7 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
if (DEBUG) Log.i(TAG, "Running PM backup pass as well");
|
if (DEBUG) Log.i(TAG, "Running PM backup pass as well");
|
||||||
|
|
||||||
PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
|
PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
|
||||||
mPackageManager, allAgentApps());
|
mPackageManager, allAgentPackages());
|
||||||
BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
|
BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
|
||||||
pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
|
pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
|
||||||
processOneBackup(pmRequest,
|
processOneBackup(pmRequest,
|
||||||
@@ -614,10 +604,12 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
|
|
||||||
// Finally, tear down the transport
|
// Finally, tear down the transport
|
||||||
try {
|
try {
|
||||||
mTransport.endSession();
|
if (!mTransport.finishBackup()) {
|
||||||
} catch (Exception e) {
|
// STOPSHIP TODO: handle errors
|
||||||
Log.e(TAG, "Error ending transport");
|
Log.e(TAG, "Backup failure in finishBackup()");
|
||||||
e.printStackTrace();
|
}
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "Error in finishBackup()", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mJournal.delete()) {
|
if (!mJournal.delete()) {
|
||||||
@@ -712,24 +704,18 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
if (DEBUG) Log.v(TAG, "doBackup() success; calling transport");
|
if (DEBUG) Log.v(TAG, "doBackup() success; calling transport");
|
||||||
backupData =
|
backupData =
|
||||||
ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_ONLY);
|
ParcelFileDescriptor.open(backupDataName, ParcelFileDescriptor.MODE_READ_ONLY);
|
||||||
int error = transport.performBackup(packInfo, backupData);
|
if (!transport.performBackup(packInfo, backupData)) {
|
||||||
|
// STOPSHIP TODO: handle errors
|
||||||
|
Log.e(TAG, "Backup failure in performBackup()");
|
||||||
|
}
|
||||||
|
|
||||||
// !!! TODO: After successful transport, delete the now-stale data
|
// !!! TODO: After successful transport, delete the now-stale data
|
||||||
// and juggle the files so that next time the new state is passed
|
// and juggle the files so that next time the new state is passed
|
||||||
//backupDataName.delete();
|
//backupDataName.delete();
|
||||||
newStateName.renameTo(savedStateName);
|
newStateName.renameTo(savedStateName);
|
||||||
}
|
}
|
||||||
} catch (NameNotFoundException e) {
|
|
||||||
Log.e(TAG, "Package not found on backup: " + packageName);
|
|
||||||
} catch (FileNotFoundException fnf) {
|
|
||||||
Log.w(TAG, "File not found on backup: ");
|
|
||||||
fnf.printStackTrace();
|
|
||||||
} catch (RemoteException e) {
|
|
||||||
Log.d(TAG, "Remote target " + request.appInfo.packageName + " threw during backup:");
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.w(TAG, "Final exception guard in backup: ");
|
Log.e(TAG, "Error backing up " + packageName, e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -737,25 +723,6 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
|
|
||||||
// ----- Restore handling -----
|
// ----- Restore handling -----
|
||||||
|
|
||||||
// Is the given package restorable on this device? Returns the on-device app's
|
|
||||||
// ApplicationInfo struct if it is; null if not.
|
|
||||||
//
|
|
||||||
// !!! TODO: also consider signatures
|
|
||||||
PackageInfo isRestorable(PackageInfo packageInfo) {
|
|
||||||
if (packageInfo.packageName != null) {
|
|
||||||
try {
|
|
||||||
PackageInfo app = mPackageManager.getPackageInfo(packageInfo.packageName,
|
|
||||||
PackageManager.GET_SIGNATURES);
|
|
||||||
if ((app.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
|
|
||||||
return app;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
// doesn't exist on this device, or other error -- just ignore it.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean signaturesMatch(Signature[] storedSigs, Signature[] deviceSigs) {
|
private boolean signaturesMatch(Signature[] storedSigs, Signature[] deviceSigs) {
|
||||||
// Allow unsigned apps, but not signed on one device and unsigned on the other
|
// Allow unsigned apps, but not signed on one device and unsigned on the other
|
||||||
// !!! TODO: is this the right policy?
|
// !!! TODO: is this the right policy?
|
||||||
@@ -816,130 +783,141 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
/**
|
/**
|
||||||
* Restore sequence:
|
* Restore sequence:
|
||||||
*
|
*
|
||||||
* 1. start up the transport session
|
* 1. get the restore set description for our identity
|
||||||
* 2. get the restore set description for our identity
|
* 2. for each app in the restore set:
|
||||||
* 3. for each app in the restore set:
|
|
||||||
* 3.a. if it's restorable on this device, add it to the restore queue
|
* 3.a. if it's restorable on this device, add it to the restore queue
|
||||||
* 4. for each app in the restore queue:
|
* 3. for each app in the restore queue:
|
||||||
* 4.a. clear the app data
|
* 3.a. clear the app data
|
||||||
* 4.b. get the restore data for the app from the transport
|
* 3.b. get the restore data for the app from the transport
|
||||||
* 4.c. launch the backup agent for the app
|
* 3.c. launch the backup agent for the app
|
||||||
* 4.d. agent.doRestore() with the data from the server
|
* 3.d. agent.doRestore() with the data from the server
|
||||||
* 4.e. unbind the agent [and kill the app?]
|
* 3.e. unbind the agent [and kill the app?]
|
||||||
* 5. shut down the transport
|
* 4. shut down the transport
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int err = -1;
|
// build the set of apps to restore
|
||||||
try {
|
try {
|
||||||
err = mTransport.startSession();
|
RestoreSet[] images = mTransport.getAvailableRestoreSets();
|
||||||
} catch (Exception e) {
|
if (images == null) {
|
||||||
Log.e(TAG, "Error starting transport for restore");
|
// STOPSHIP TODO: Handle the failure somehow?
|
||||||
e.printStackTrace();
|
Log.e(TAG, "Error getting restore sets");
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (err == 0) {
|
if (images.length == 0) {
|
||||||
// build the set of apps to restore
|
Log.i(TAG, "No restore sets available");
|
||||||
try {
|
return;
|
||||||
RestoreSet[] images = mTransport.getAvailableRestoreSets();
|
}
|
||||||
if (images.length > 0) {
|
|
||||||
// !!! TODO: pick out the set for this token
|
|
||||||
mImage = images[0];
|
|
||||||
|
|
||||||
// Pull the Package Manager metadata from the restore set first
|
mImage = images[0];
|
||||||
PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
|
|
||||||
mPackageManager, allAgentApps());
|
|
||||||
PackageInfo pmApp = new PackageInfo();
|
|
||||||
pmApp.packageName = PACKAGE_MANAGER_SENTINEL;
|
|
||||||
// !!! TODO: version currently ignored when 'restoring' the PM metadata
|
|
||||||
processOneRestore(pmApp, 0,
|
|
||||||
IBackupAgent.Stub.asInterface(pmAgent.onBind()));
|
|
||||||
|
|
||||||
// build the set of apps we will attempt to restore
|
// Get the list of all packages which have backup enabled.
|
||||||
PackageInfo[] packages = mTransport.getAppSet(mImage.token);
|
// (Include the Package Manager metadata pseudo-package first.)
|
||||||
HashSet<RestoreRequest> appsToRestore = new HashSet<RestoreRequest>();
|
ArrayList<PackageInfo> restorePackages = new ArrayList<PackageInfo>();
|
||||||
for (PackageInfo pkg: packages) {
|
PackageInfo omPackage = new PackageInfo();
|
||||||
// get the real PackageManager idea of the package
|
omPackage.packageName = PACKAGE_MANAGER_SENTINEL;
|
||||||
PackageInfo app = isRestorable(pkg);
|
restorePackages.add(omPackage);
|
||||||
if (app != null) {
|
|
||||||
// Validate against the backed-up signature block, too
|
|
||||||
Metadata info = pmAgent.getRestoredMetadata(app.packageName);
|
|
||||||
if (info != null) {
|
|
||||||
if (app.versionCode >= info.versionCode) {
|
|
||||||
if (DEBUG) Log.v(TAG, "Restore version "
|
|
||||||
+ info.versionCode
|
|
||||||
+ " compatible with app version "
|
|
||||||
+ app.versionCode);
|
|
||||||
if (signaturesMatch(info.signatures, app.signatures)) {
|
|
||||||
appsToRestore.add(
|
|
||||||
new RestoreRequest(app, info.versionCode));
|
|
||||||
} else {
|
|
||||||
Log.w(TAG, "Sig mismatch restoring "
|
|
||||||
+ app.packageName);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.i(TAG, "Restore set for " + app.packageName
|
|
||||||
+ " is too new [" + info.versionCode
|
|
||||||
+ "] for installed app version "
|
|
||||||
+ app.versionCode);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Log.d(TAG, "Unable to get metadata for "
|
|
||||||
+ app.packageName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// now run the restore queue
|
List<PackageInfo> agentPackages = allAgentPackages();
|
||||||
doQueuedRestores(appsToRestore);
|
restorePackages.addAll(agentPackages);
|
||||||
|
|
||||||
|
// STOPSHIP TODO: pick out the set for this token (instead of images[0])
|
||||||
|
long token = images[0].token;
|
||||||
|
if (!mTransport.startRestore(token, restorePackages.toArray(new PackageInfo[0]))) {
|
||||||
|
// STOPSHIP TODO: Handle the failure somehow?
|
||||||
|
Log.e(TAG, "Error starting restore operation");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String packageName = mTransport.nextRestorePackage();
|
||||||
|
if (packageName == null) {
|
||||||
|
// STOPSHIP TODO: Handle the failure somehow?
|
||||||
|
Log.e(TAG, "Error getting first restore package");
|
||||||
|
return;
|
||||||
|
} else if (packageName.equals("")) {
|
||||||
|
Log.i(TAG, "No restore data available");
|
||||||
|
return;
|
||||||
|
} else if (!packageName.equals(PACKAGE_MANAGER_SENTINEL)) {
|
||||||
|
Log.e(TAG, "Expected restore data for \"" + PACKAGE_MANAGER_SENTINEL
|
||||||
|
+ "\", found only \"" + packageName + "\"");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull the Package Manager metadata from the restore set first
|
||||||
|
PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
|
||||||
|
mPackageManager, agentPackages);
|
||||||
|
processOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(pmAgent.onBind()));
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
packageName = mTransport.nextRestorePackage();
|
||||||
|
if (packageName == null) {
|
||||||
|
// STOPSHIP TODO: Handle the failure somehow?
|
||||||
|
Log.e(TAG, "Error getting next restore package");
|
||||||
|
return;
|
||||||
|
} else if (packageName.equals("")) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} catch (RemoteException e) {
|
|
||||||
// can't happen; transports run locally
|
|
||||||
}
|
|
||||||
|
|
||||||
// done; shut down the transport
|
Metadata metaInfo = pmAgent.getRestoredMetadata(packageName);
|
||||||
try {
|
if (metaInfo == null) {
|
||||||
mTransport.endSession();
|
Log.e(TAG, "Missing metadata for " + packageName);
|
||||||
} catch (Exception e) {
|
continue;
|
||||||
Log.e(TAG, "Error ending transport for restore");
|
}
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// even if the initial session startup failed, report that we're done here
|
int flags = PackageManager.GET_SIGNATURES;
|
||||||
}
|
PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
|
||||||
|
if (metaInfo.versionCode > packageInfo.versionCode) {
|
||||||
|
Log.w(TAG, "Package " + packageName
|
||||||
|
+ " restore version [" + metaInfo.versionCode
|
||||||
|
+ "] is too new for installed version ["
|
||||||
|
+ packageInfo.versionCode + "]");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// restore each app in the queue
|
if (!signaturesMatch(metaInfo.signatures, packageInfo.signatures)) {
|
||||||
void doQueuedRestores(HashSet<RestoreRequest> appsToRestore) {
|
Log.w(TAG, "Signature mismatch restoring " + packageName);
|
||||||
for (RestoreRequest req : appsToRestore) {
|
continue;
|
||||||
PackageInfo app = req.app;
|
}
|
||||||
Log.d(TAG, "starting agent for restore of " + app);
|
|
||||||
|
|
||||||
try {
|
if (DEBUG) Log.v(TAG, "Package " + packageName
|
||||||
// Remove the app's data first
|
+ " restore version [" + metaInfo.versionCode
|
||||||
clearApplicationDataSynchronous(app.packageName);
|
+ "] is compatible with installed version ["
|
||||||
|
+ packageInfo.versionCode + "]");
|
||||||
|
|
||||||
// Now perform the restore into the clean app
|
// Now perform the actual restore
|
||||||
IBackupAgent agent = bindToAgentSynchronous(app.applicationInfo,
|
clearApplicationDataSynchronous(packageName);
|
||||||
|
IBackupAgent agent = bindToAgentSynchronous(
|
||||||
|
packageInfo.applicationInfo,
|
||||||
IApplicationThread.BACKUP_MODE_RESTORE);
|
IApplicationThread.BACKUP_MODE_RESTORE);
|
||||||
if (agent != null) {
|
if (agent == null) {
|
||||||
processOneRestore(app, req.storedAppVersion, agent);
|
Log.w(TAG, "Can't find backup agent for " + packageName);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// unbind even on timeout, just in case
|
try {
|
||||||
mActivityManager.unbindBackupAgent(app.applicationInfo);
|
processOneRestore(packageInfo, metaInfo.versionCode, agent);
|
||||||
} catch (SecurityException ex) {
|
} finally {
|
||||||
// Try for the next one.
|
// unbind even on timeout or failure, just in case
|
||||||
Log.d(TAG, "error in bind", ex);
|
mActivityManager.unbindBackupAgent(packageInfo.applicationInfo);
|
||||||
} catch (RemoteException e) {
|
}
|
||||||
// can't happen
|
}
|
||||||
|
} catch (NameNotFoundException e) {
|
||||||
|
// STOPSHIP TODO: Handle the failure somehow?
|
||||||
|
Log.e(TAG, "Invalid paackage restoring data", e);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// STOPSHIP TODO: Handle the failure somehow?
|
||||||
|
Log.e(TAG, "Error restoring data", e);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
mTransport.finishRestore();
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
Log.e(TAG, "Error finishing restore", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do the guts of a restore of one application, derived from the 'mImage'
|
// Do the guts of a restore of one application, using mTransport.getRestoreData().
|
||||||
// restore set via the 'mTransport' transport.
|
void processOneRestore(PackageInfo app, int appVersionCode, IBackupAgent agent) {
|
||||||
void processOneRestore(PackageInfo app, int storedAppVersion, IBackupAgent agent) {
|
|
||||||
// !!! TODO: actually run the restore through mTransport
|
// !!! TODO: actually run the restore through mTransport
|
||||||
final String packageName = app.packageName;
|
final String packageName = app.packageName;
|
||||||
|
|
||||||
@@ -954,11 +932,12 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
|
|
||||||
// Run the transport's restore pass
|
// Run the transport's restore pass
|
||||||
// Run the target's backup pass
|
// Run the target's backup pass
|
||||||
int err = -1;
|
|
||||||
try {
|
try {
|
||||||
err = mTransport.getRestoreData(mImage.token, app, backupData);
|
if (!mTransport.getRestoreData(backupData)) {
|
||||||
} catch (RemoteException e) {
|
// STOPSHIP TODO: Handle this error somehow?
|
||||||
// can't happen
|
Log.e(TAG, "Error getting restore data for " + packageName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
backupData.close();
|
backupData.close();
|
||||||
}
|
}
|
||||||
@@ -973,30 +952,18 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
backupData = ParcelFileDescriptor.open(backupDataName,
|
backupData = ParcelFileDescriptor.open(backupDataName,
|
||||||
ParcelFileDescriptor.MODE_READ_ONLY);
|
ParcelFileDescriptor.MODE_READ_ONLY);
|
||||||
|
|
||||||
boolean success = false;
|
|
||||||
try {
|
try {
|
||||||
agent.doRestore(backupData, storedAppVersion, newState);
|
agent.doRestore(backupData, appVersionCode, newState);
|
||||||
success = true;
|
|
||||||
} catch (Exception e) {
|
|
||||||
Log.e(TAG, "Restore failed for " + packageName);
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
} finally {
|
||||||
newState.close();
|
newState.close();
|
||||||
backupData.close();
|
backupData.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// if everything went okay, remember the recorded state now
|
// if everything went okay, remember the recorded state now
|
||||||
if (success) {
|
File savedStateName = new File(mStateDir, packageName);
|
||||||
File savedStateName = new File(mStateDir, packageName);
|
newStateName.renameTo(savedStateName);
|
||||||
newStateName.renameTo(savedStateName);
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException fnfe) {
|
|
||||||
Log.v(TAG, "Couldn't open file for restore: " + fnfe);
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
Log.e(TAG, "Unable to process restore file: " + ioe);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.e(TAG, "Final exception guard in restore:");
|
Log.e(TAG, "Error restoring data for " + packageName, e);
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1206,7 +1173,7 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
mContext.enforceCallingPermission("android.permission.BACKUP",
|
mContext.enforceCallingPermission("android.permission.BACKUP",
|
||||||
"endRestoreSession");
|
"endRestoreSession");
|
||||||
|
|
||||||
mRestoreTransport.endSession();
|
mRestoreTransport.finishRestore();
|
||||||
mRestoreTransport = null;
|
mRestoreTransport = null;
|
||||||
synchronized(BackupManagerService.this) {
|
synchronized(BackupManagerService.this) {
|
||||||
if (BackupManagerService.this.mActiveRestoreSession == this) {
|
if (BackupManagerService.this.mActiveRestoreSession == this) {
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
|
|||||||
// is stored using the package name as a key)
|
// is stored using the package name as a key)
|
||||||
private static final String GLOBAL_METADATA_KEY = "@meta@";
|
private static final String GLOBAL_METADATA_KEY = "@meta@";
|
||||||
|
|
||||||
private List<ApplicationInfo> mAllApps;
|
private List<PackageInfo> mAllPackages;
|
||||||
private PackageManager mPackageManager;
|
private PackageManager mPackageManager;
|
||||||
private HashMap<String, Metadata> mRestoredSignatures;
|
private HashMap<String, Metadata> mRestoredSignatures;
|
||||||
|
|
||||||
@@ -73,9 +73,9 @@ public class PackageManagerBackupAgent extends BackupAgent {
|
|||||||
|
|
||||||
// We're constructed with the set of applications that are participating
|
// We're constructed with the set of applications that are participating
|
||||||
// in backup. This set changes as apps are installed & removed.
|
// in backup. This set changes as apps are installed & removed.
|
||||||
PackageManagerBackupAgent(PackageManager packageMgr, List<ApplicationInfo> apps) {
|
PackageManagerBackupAgent(PackageManager packageMgr, List<PackageInfo> packages) {
|
||||||
mPackageManager = packageMgr;
|
mPackageManager = packageMgr;
|
||||||
mAllApps = apps;
|
mAllPackages = packages;
|
||||||
mRestoredSignatures = null;
|
mRestoredSignatures = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,8 +118,8 @@ public class PackageManagerBackupAgent extends BackupAgent {
|
|||||||
|
|
||||||
// For each app we have on device, see if we've backed it up yet. If not,
|
// 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.
|
// write its signature block to the output, keyed on the package name.
|
||||||
for (ApplicationInfo app : mAllApps) {
|
for (PackageInfo pkg : mAllPackages) {
|
||||||
String packName = app.packageName;
|
String packName = pkg.packageName;
|
||||||
if (!existing.contains(packName)) {
|
if (!existing.contains(packName)) {
|
||||||
// We haven't stored this app's signatures yet, so we do that now
|
// We haven't stored this app's signatures yet, so we do that now
|
||||||
try {
|
try {
|
||||||
@@ -186,7 +186,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Finally, write the new state blob -- just the list of all apps we handled
|
// Finally, write the new state blob -- just the list of all apps we handled
|
||||||
writeStateFile(mAllApps, newState);
|
writeStateFile(mAllPackages, newState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// "Restore" here is a misnomer. What we're really doing is reading back the
|
// "Restore" here is a misnomer. What we're really doing is reading back the
|
||||||
@@ -327,7 +327,7 @@ public class PackageManagerBackupAgent extends BackupAgent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Util: write out our new backup state file
|
// Util: write out our new backup state file
|
||||||
private void writeStateFile(List<ApplicationInfo> apps, ParcelFileDescriptor stateFile) {
|
private void writeStateFile(List<PackageInfo> pkgs, ParcelFileDescriptor stateFile) {
|
||||||
FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
|
FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
|
||||||
DataOutputStream out = new DataOutputStream(outstream);
|
DataOutputStream out = new DataOutputStream(outstream);
|
||||||
|
|
||||||
@@ -338,8 +338,8 @@ public class PackageManagerBackupAgent extends BackupAgent {
|
|||||||
out.write(metaNameBuf);
|
out.write(metaNameBuf);
|
||||||
|
|
||||||
// now write all the app names too
|
// now write all the app names too
|
||||||
for (ApplicationInfo app : apps) {
|
for (PackageInfo pkg : pkgs) {
|
||||||
byte[] pkgNameBuf = app.packageName.getBytes();
|
byte[] pkgNameBuf = pkg.packageName.getBytes();
|
||||||
out.writeInt(pkgNameBuf.length);
|
out.writeInt(pkgNameBuf.length);
|
||||||
out.write(pkgNameBuf);
|
out.write(pkgNameBuf);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user