summaryrefslogtreecommitdiffstats
path: root/core/java/android/app/backup/FullBackup.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/app/backup/FullBackup.java')
-rw-r--r--core/java/android/app/backup/FullBackup.java110
1 files changed, 99 insertions, 11 deletions
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 9850566..dfb0dd7 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -16,6 +16,17 @@
package android.app.backup;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import libcore.io.ErrnoException;
+import libcore.io.Libcore;
+
/**
* Global constant definitions et cetera related to the full-backup-to-fd
* binary format.
@@ -23,18 +34,95 @@ package android.app.backup;
* @hide
*/
public class FullBackup {
- public static String APK_TREE_TOKEN = "a";
- public static String OBB_TREE_TOKEN = "obb";
- public static String ROOT_TREE_TOKEN = "r";
- public static String DATA_TREE_TOKEN = "f";
- public static String DATABASE_TREE_TOKEN = "db";
- public static String SHAREDPREFS_TREE_TOKEN = "sp";
- public static String CACHE_TREE_TOKEN = "c";
-
- public static String FULL_BACKUP_INTENT_ACTION = "fullback";
- public static String FULL_RESTORE_INTENT_ACTION = "fullrest";
- public static String CONF_TOKEN_INTENT_EXTRA = "conftoken";
+ static final String TAG = "FullBackup";
+
+ public static final String APK_TREE_TOKEN = "a";
+ public static final String OBB_TREE_TOKEN = "obb";
+ public static final String ROOT_TREE_TOKEN = "r";
+ public static final String DATA_TREE_TOKEN = "f";
+ public static final String DATABASE_TREE_TOKEN = "db";
+ public static final String SHAREDPREFS_TREE_TOKEN = "sp";
+ public static final String CACHE_TREE_TOKEN = "c";
+ public static final String SHARED_STORAGE_TOKEN = "shared";
+
+ public static final String APPS_PREFIX = "apps/";
+ public static final String SHARED_PREFIX = "shared/";
+
+ public static final String FULL_BACKUP_INTENT_ACTION = "fullback";
+ public static final String FULL_RESTORE_INTENT_ACTION = "fullrest";
+ public static final String CONF_TOKEN_INTENT_EXTRA = "conftoken";
+
+ public static final int TYPE_EOF = 0;
+ public static final int TYPE_FILE = 1;
+ public static final int TYPE_DIRECTORY = 2;
+ public static final int TYPE_SYMLINK = 3;
static public native int backupToTar(String packageName, String domain,
String linkdomain, String rootpath, String path, BackupDataOutput output);
+
+ static public void restoreToFile(ParcelFileDescriptor data,
+ long size, int type, long mode, long mtime, File outFile) throws IOException {
+ if (type == FullBackup.TYPE_DIRECTORY) {
+ // Canonically a directory has no associated content, so we don't need to read
+ // anything from the pipe in this case. Just create the directory here and
+ // drop down to the final metadata adjustment.
+ if (outFile != null) outFile.mkdirs();
+ } else {
+ FileOutputStream out = null;
+
+ // Pull the data from the pipe, copying it to the output file, until we're done
+ try {
+ if (outFile != null) {
+ File parent = outFile.getParentFile();
+ if (!parent.exists()) {
+ // in practice this will only be for the default semantic directories,
+ // and using the default mode for those is appropriate.
+ // TODO: support the edge case of apps that have adjusted the
+ // permissions on these core directories
+ parent.mkdirs();
+ }
+ out = new FileOutputStream(outFile);
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Unable to create/open file " + outFile.getPath(), e);
+ }
+
+ byte[] buffer = new byte[32 * 1024];
+ final long origSize = size;
+ FileInputStream in = new FileInputStream(data.getFileDescriptor());
+ while (size > 0) {
+ int toRead = (size > buffer.length) ? buffer.length : (int)size;
+ int got = in.read(buffer, 0, toRead);
+ if (got <= 0) {
+ Log.w(TAG, "Incomplete read: expected " + size + " but got "
+ + (origSize - size));
+ break;
+ }
+ if (out != null) {
+ try {
+ out.write(buffer, 0, got);
+ } catch (IOException e) {
+ // Problem writing to the file. Quit copying data and delete
+ // the file, but of course keep consuming the input stream.
+ Log.e(TAG, "Unable to write to file " + outFile.getPath(), e);
+ out.close();
+ out = null;
+ outFile.delete();
+ }
+ }
+ size -= got;
+ }
+ if (out != null) out.close();
+ }
+
+ // Now twiddle the state to match the backup, assuming all went well
+ if (outFile != null) {
+ try {
+ Libcore.os.chmod(outFile.getPath(), (int)mode);
+ } catch (ErrnoException e) {
+ e.rethrowAsIOException();
+ }
+ outFile.setLastModified(mtime);
+ }
+ }
}