blob: d7f1c9f0fab411c14f9face9fa3532e19ebb1b5c [file] [log] [blame]
Christopher Tate4a627c72011-04-01 14:43:32 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.app.backup;
18
Christopher Tate79ec80d2011-06-24 14:58:49 -070019import android.content.Context;
20import android.content.pm.ApplicationInfo;
21import android.content.pm.PackageManager;
Christopher Tate75a99702011-05-18 16:28:19 -070022import android.os.ParcelFileDescriptor;
23import android.util.Log;
24
25import java.io.File;
26import java.io.FileInputStream;
27import java.io.FileOutputStream;
28import java.io.IOException;
29
30import libcore.io.ErrnoException;
31import libcore.io.Libcore;
32
Christopher Tate4a627c72011-04-01 14:43:32 -070033/**
34 * Global constant definitions et cetera related to the full-backup-to-fd
Christopher Tate79ec80d2011-06-24 14:58:49 -070035 * binary format. Nothing in this namespace is part of any API; it's all
36 * hidden details of the current implementation gathered into one location.
Christopher Tate4a627c72011-04-01 14:43:32 -070037 *
38 * @hide
39 */
40public class FullBackup {
Christopher Tate75a99702011-05-18 16:28:19 -070041 static final String TAG = "FullBackup";
Christopher Tate4a627c72011-04-01 14:43:32 -070042
Christopher Tate75a99702011-05-18 16:28:19 -070043 public static final String APK_TREE_TOKEN = "a";
44 public static final String OBB_TREE_TOKEN = "obb";
45 public static final String ROOT_TREE_TOKEN = "r";
46 public static final String DATA_TREE_TOKEN = "f";
47 public static final String DATABASE_TREE_TOKEN = "db";
48 public static final String SHAREDPREFS_TREE_TOKEN = "sp";
49 public static final String CACHE_TREE_TOKEN = "c";
50 public static final String SHARED_STORAGE_TOKEN = "shared";
51
52 public static final String APPS_PREFIX = "apps/";
Christopher Tateb0628bf2011-06-02 15:08:13 -070053 public static final String SHARED_PREFIX = SHARED_STORAGE_TOKEN + "/";
Christopher Tate75a99702011-05-18 16:28:19 -070054
55 public static final String FULL_BACKUP_INTENT_ACTION = "fullback";
56 public static final String FULL_RESTORE_INTENT_ACTION = "fullrest";
57 public static final String CONF_TOKEN_INTENT_EXTRA = "conftoken";
58
Christopher Tate79ec80d2011-06-24 14:58:49 -070059 /**
60 * @hide
61 */
Christopher Tate4a627c72011-04-01 14:43:32 -070062 static public native int backupToTar(String packageName, String domain,
63 String linkdomain, String rootpath, String path, BackupDataOutput output);
Christopher Tate75a99702011-05-18 16:28:19 -070064
Christopher Tate79ec80d2011-06-24 14:58:49 -070065 /**
66 * Copy data from a socket to the given File location on permanent storage. The
67 * modification time and access mode of the resulting file will be set if desired.
68 * If the {@code type} parameter indicates that the result should be a directory,
69 * the socket parameter may be {@code null}; even if it is valid, no data will be
70 * read from it in this case.
71 * <p>
72 * If the {@code mode} argument is negative, then the resulting output file will not
73 * have its access mode or last modification time reset as part of this operation.
74 *
75 * @param data Socket supplying the data to be copied to the output file. If the
76 * output is a directory, this may be {@code null}.
77 * @param size Number of bytes of data to copy from the socket to the file. At least
78 * this much data must be available through the {@code data} parameter.
79 * @param type Must be either {@link BackupAgent#TYPE_FILE} for ordinary file data
80 * or {@link BackupAgent#TYPE_DIRECTORY} for a directory.
81 * @param mode Unix-style file mode (as used by the chmod(2) syscall) to be set on
82 * the output file or directory. If this parameter is negative then neither
83 * the mode nor the mtime parameters will be used.
84 * @param mtime A timestamp in the standard Unix epoch that will be imposed as the
85 * last modification time of the output file. if the {@code mode} parameter is
86 * negative then this parameter will be ignored.
87 * @param outFile Location within the filesystem to place the data. This must point
88 * to a location that is writeable by the caller, prefereably using an absolute path.
89 * @throws IOException
90 */
91 static public void restoreFile(ParcelFileDescriptor data,
92 long size, int type, long mode, long mtime, File outFile) throws IOException {
93 if (type == BackupAgent.TYPE_DIRECTORY) {
Christopher Tate75a99702011-05-18 16:28:19 -070094 // Canonically a directory has no associated content, so we don't need to read
95 // anything from the pipe in this case. Just create the directory here and
96 // drop down to the final metadata adjustment.
97 if (outFile != null) outFile.mkdirs();
98 } else {
99 FileOutputStream out = null;
100
101 // Pull the data from the pipe, copying it to the output file, until we're done
102 try {
103 if (outFile != null) {
104 File parent = outFile.getParentFile();
105 if (!parent.exists()) {
106 // in practice this will only be for the default semantic directories,
107 // and using the default mode for those is appropriate.
108 // TODO: support the edge case of apps that have adjusted the
109 // permissions on these core directories
110 parent.mkdirs();
111 }
112 out = new FileOutputStream(outFile);
113 }
114 } catch (IOException e) {
115 Log.e(TAG, "Unable to create/open file " + outFile.getPath(), e);
116 }
117
118 byte[] buffer = new byte[32 * 1024];
119 final long origSize = size;
120 FileInputStream in = new FileInputStream(data.getFileDescriptor());
121 while (size > 0) {
122 int toRead = (size > buffer.length) ? buffer.length : (int)size;
123 int got = in.read(buffer, 0, toRead);
124 if (got <= 0) {
125 Log.w(TAG, "Incomplete read: expected " + size + " but got "
126 + (origSize - size));
127 break;
128 }
129 if (out != null) {
130 try {
131 out.write(buffer, 0, got);
132 } catch (IOException e) {
133 // Problem writing to the file. Quit copying data and delete
134 // the file, but of course keep consuming the input stream.
135 Log.e(TAG, "Unable to write to file " + outFile.getPath(), e);
136 out.close();
137 out = null;
138 outFile.delete();
139 }
140 }
141 size -= got;
142 }
143 if (out != null) out.close();
144 }
145
146 // Now twiddle the state to match the backup, assuming all went well
Christopher Tate79ec80d2011-06-24 14:58:49 -0700147 if (mode >= 0 && outFile != null) {
Christopher Tate75a99702011-05-18 16:28:19 -0700148 try {
149 Libcore.os.chmod(outFile.getPath(), (int)mode);
150 } catch (ErrnoException e) {
151 e.rethrowAsIOException();
152 }
153 outFile.setLastModified(mtime);
154 }
155 }
Christopher Tate4a627c72011-04-01 14:43:32 -0700156}