diff options
| author | Android (Google) Code Review <android-gerrit@google.com> | 2009-06-24 16:52:16 -0700 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2009-06-24 16:52:16 -0700 |
| commit | 67669c9c1753b062fe2a71f89b589d01b32ba0f7 (patch) | |
| tree | 729bb3c925638802fdb42e67c508f08f85a3ff55 /core/java | |
| parent | 5158cc55088fec902320cafc02c746e3bf087a10 (diff) | |
| parent | efe52647f6b41993be43a5f47d1178bb0468cec8 (diff) | |
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.
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/backup/RestoreSet.java | 10 | ||||
| -rw-r--r-- | core/java/com/android/internal/backup/IBackupTransport.aidl | 77 | ||||
| -rw-r--r-- | core/java/com/android/internal/backup/LocalTransport.java | 135 |
3 files changed, 105 insertions, 117 deletions
diff --git a/core/java/android/backup/RestoreSet.java b/core/java/android/backup/RestoreSet.java index 96a99aea0deb..eeca148667f3 100644 --- a/core/java/android/backup/RestoreSet.java +++ b/core/java/android/backup/RestoreSet.java @@ -43,14 +43,14 @@ public class RestoreSet implements Parcelable { * transport. This is guaranteed to be valid for the duration of a restore * session, but is meaningless once the session has ended. */ - public int token; + public long token; public RestoreSet() { // Leave everything zero / null } - public RestoreSet(String _name, String _dev, int _token) { + public RestoreSet(String _name, String _dev, long _token) { name = _name; device = _dev; token = _token; @@ -65,7 +65,7 @@ public class RestoreSet implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeString(name); out.writeString(device); - out.writeInt(token); + out.writeLong(token); } public static final Parcelable.Creator<RestoreSet> CREATOR @@ -82,6 +82,6 @@ public class RestoreSet implements Parcelable { private RestoreSet(Parcel in) { name = in.readString(); device = in.readString(); - token = in.readInt(); + token = in.readLong(); } -}
\ No newline at end of file +} diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl index 84ed729cb7ae..ec6352818ad9 100644 --- a/core/java/com/android/internal/backup/IBackupTransport.aidl +++ b/core/java/com/android/internal/backup/IBackupTransport.aidl @@ -54,63 +54,70 @@ interface IBackupTransport { long requestBackupTime(); /** - * Establish a connection to the back-end data repository, if necessary. If the transport - * needs to initialize state that is not tied to individual applications' backup operations, - * this is where it should be done. - * - * @return Zero on success; a nonzero error code on failure. - */ - int startSession(); - - /** - * Send one application's data to the backup destination. + * Send one application's data to the backup destination. The transport may send + * the data immediately, or may buffer it. After this is called, {@link #finishBackup} + * must be called to ensure the data is sent and recorded successfully. * * @param packageInfo The identity of the application whose data is being backed up. * This specifically includes the signature list for the package. * @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 * 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. * - * @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(); /** - * 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}. - * @return An array of PackageInfo objects describing all of the applications - * available for restore from this restore image. This should include the list - * of signatures for each package so that the Backup Manager can filter using that - * information. + * @param packages List of applications to restore (if data is available). + * Application data will be restored in the order given. + * @return false if errors occurred (the restore should be aborted and rescheduled), + * 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. - * - * @param token The backup record from which a restore is being requested. - * @param packageInfo The identity of the application whose data is being restored. - * 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. + * 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}, + * or "" (the empty string) if no more backup data is available, + * or null if an error occurred (the restore should be aborted and rescheduled). */ - int getRestoreData(int token, in PackageInfo packageInfo, in ParcelFileDescriptor data); + String nextRestorePackage(); /** - * Terminate the backup session, closing files, freeing memory, and cleaning up whatever - * other state the transport required. - * - * @return Zero on success; a nonzero error code on failure. Even on failure, the session - * is torn down and must be restarted if another backup is attempted. + * Get the data for the application returned by {@link #nextRestorePackage}. + * @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), + * true if everything is OK so far (go ahead and call {@link #nextRestorePackage}). + */ + 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. */ - int endSession(); + void finishRestore(); } diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java index 3dd71f315425..0fbbb3fb06d0 100644 --- a/core/java/com/android/internal/backup/LocalTransport.java +++ b/core/java/com/android/internal/backup/LocalTransport.java @@ -33,11 +33,8 @@ public class LocalTransport extends IBackupTransport.Stub { private Context mContext; private PackageManager mPackageManager; private File mDataDir = new File(Environment.getDownloadCacheDirectory(), "backup"); - private FileFilter mDirFileFilter = new FileFilter() { - public boolean accept(File f) { - return f.isDirectory(); - } - }; + private PackageInfo[] mRestorePackages = null; + private int mRestorePackage = -1; // Index into mRestorePackages public LocalTransport(Context context) { @@ -51,21 +48,9 @@ public class LocalTransport extends IBackupTransport.Stub { return 0; } - public int startSession() throws RemoteException { - 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) + public boolean performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) throws RemoteException { if (DEBUG) Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName); - int err = 0; File packageDir = new File(mDataDir, packageInfo.packageName); packageDir.mkdirs(); @@ -101,9 +86,8 @@ public class LocalTransport extends IBackupTransport.Stub { try { entity.write(buf, 0, dataSize); } catch (IOException e) { - Log.e(TAG, "Unable to update key file " - + entityFile.getAbsolutePath()); - err = -1; + Log.e(TAG, "Unable to update key file " + entityFile.getAbsolutePath()); + return false; } finally { entity.close(); } @@ -111,14 +95,17 @@ public class LocalTransport extends IBackupTransport.Stub { entityFile.delete(); } } + return true; } catch (IOException e) { // oops, something went wrong. abort the operation and return error. - Log.v(TAG, "Exception reading backup input:"); - e.printStackTrace(); - err = -1; + Log.v(TAG, "Exception reading backup input:", e); + return false; } + } - return err; + public boolean finishBackup() throws RemoteException { + if (DEBUG) Log.v(TAG, "finishBackup()"); + return true; } // Restore handling @@ -129,72 +116,66 @@ public class LocalTransport extends IBackupTransport.Stub { return array; } - public PackageInfo[] getAppSet(int token) throws android.os.RemoteException { - if (DEBUG) Log.v(TAG, "getting app set " + token); - // the available packages are the extant subdirs of mDatadir - File[] packageDirs = mDataDir.listFiles(mDirFileFilter); - ArrayList<PackageInfo> packages = new ArrayList<PackageInfo>(); - 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. - } - } + public boolean startRestore(long token, PackageInfo[] packages) { + if (DEBUG) Log.v(TAG, "start restore " + token); + mRestorePackages = packages; + mRestorePackage = -1; + return true; + } - if (DEBUG) { - Log.v(TAG, "Built app set of " + packages.size() + " entries:"); - for (PackageInfo p : packages) { - Log.v(TAG, " + " + p.packageName); + public String nextRestorePackage() { + if (mRestorePackages == null) throw new IllegalStateException("startRestore not called"); + while (++mRestorePackage < mRestorePackages.length) { + String name = mRestorePackages[mRestorePackage].packageName; + if (new File(mDataDir, name).isDirectory()) { + if (DEBUG) Log.v(TAG, " nextRestorePackage() = " + name); + return name; } } - PackageInfo[] result = new PackageInfo[packages.size()]; - return packages.toArray(result); + if (DEBUG) Log.v(TAG, " no more packages to restore"); + return ""; } - public int getRestoreData(int token, PackageInfo packageInfo, ParcelFileDescriptor outFd) - throws android.os.RemoteException { - if (DEBUG) Log.v(TAG, "getting restore data " + token + " : " + packageInfo.packageName); - // we only support one hardcoded restore set - if (token != 0) return -1; - - // the data for a given package is at a known location - File packageDir = new File(mDataDir, packageInfo.packageName); + 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, // each of which is a file in the package's directory File[] blobs = packageDir.listFiles(); - if (DEBUG) Log.v(TAG, " found " + blobs.length + " key files"); - int err = 0; - if (blobs != null && blobs.length > 0) { - BackupDataOutput out = new BackupDataOutput(outFd.getFileDescriptor()); - try { - for (File f : blobs) { - copyToRestoreData(f, out); + if (blobs == null) { + Log.e(TAG, "Error listing directory: " + packageDir); + return false; // nextRestorePackage() ensures the dir exists, so this is an error + } + + // We expect at least some data if the directory exists in the first place + if (DEBUG) Log.v(TAG, " getRestoreData() found " + blobs.length + " key files"); + BackupDataOutput out = new BackupDataOutput(outFd.getFileDescriptor()); + try { + for (File f : blobs) { + 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(); } - } catch (Exception e) { - Log.e(TAG, "Unable to read backup records"); - err = -1; } + 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 { - FileInputStream in = new FileInputStream(f); - 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); + public void finishRestore() { + if (DEBUG) Log.v(TAG, "finishRestore()"); } } |
