FullBackup.java revision b0628bfd5aac480a0d412ac96b8af1d97ac01c30
1/*
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
19import android.os.ParcelFileDescriptor;
20import android.util.Log;
21
22import java.io.File;
23import java.io.FileInputStream;
24import java.io.FileOutputStream;
25import java.io.IOException;
26
27import libcore.io.ErrnoException;
28import libcore.io.Libcore;
29
30/**
31 * Global constant definitions et cetera related to the full-backup-to-fd
32 * binary format.
33 *
34 * @hide
35 */
36public class FullBackup {
37    static final String TAG = "FullBackup";
38
39    public static final String APK_TREE_TOKEN = "a";
40    public static final String OBB_TREE_TOKEN = "obb";
41    public static final String ROOT_TREE_TOKEN = "r";
42    public static final String DATA_TREE_TOKEN = "f";
43    public static final String DATABASE_TREE_TOKEN = "db";
44    public static final String SHAREDPREFS_TREE_TOKEN = "sp";
45    public static final String CACHE_TREE_TOKEN = "c";
46    public static final String SHARED_STORAGE_TOKEN = "shared";
47
48    public static final String APPS_PREFIX = "apps/";
49    public static final String SHARED_PREFIX = SHARED_STORAGE_TOKEN + "/";
50
51    public static final String FULL_BACKUP_INTENT_ACTION = "fullback";
52    public static final String FULL_RESTORE_INTENT_ACTION = "fullrest";
53    public static final String CONF_TOKEN_INTENT_EXTRA = "conftoken";
54
55    public static final int TYPE_EOF = 0;
56    public static final int TYPE_FILE = 1;
57    public static final int TYPE_DIRECTORY = 2;
58    public static final int TYPE_SYMLINK = 3;
59
60    static public native int backupToTar(String packageName, String domain,
61            String linkdomain, String rootpath, String path, BackupDataOutput output);
62
63    static public void restoreToFile(ParcelFileDescriptor data,
64            long size, int type, long mode, long mtime, File outFile,
65            boolean doChmod) throws IOException {
66        if (type == FullBackup.TYPE_DIRECTORY) {
67            // Canonically a directory has no associated content, so we don't need to read
68            // anything from the pipe in this case.  Just create the directory here and
69            // drop down to the final metadata adjustment.
70            if (outFile != null) outFile.mkdirs();
71        } else {
72            FileOutputStream out = null;
73
74            // Pull the data from the pipe, copying it to the output file, until we're done
75            try {
76                if (outFile != null) {
77                    File parent = outFile.getParentFile();
78                    if (!parent.exists()) {
79                        // in practice this will only be for the default semantic directories,
80                        // and using the default mode for those is appropriate.
81                        // TODO: support the edge case of apps that have adjusted the
82                        //       permissions on these core directories
83                        parent.mkdirs();
84                    }
85                    out = new FileOutputStream(outFile);
86                }
87            } catch (IOException e) {
88                Log.e(TAG, "Unable to create/open file " + outFile.getPath(), e);
89            }
90
91            byte[] buffer = new byte[32 * 1024];
92            final long origSize = size;
93            FileInputStream in = new FileInputStream(data.getFileDescriptor());
94            while (size > 0) {
95                int toRead = (size > buffer.length) ? buffer.length : (int)size;
96                int got = in.read(buffer, 0, toRead);
97                if (got <= 0) {
98                    Log.w(TAG, "Incomplete read: expected " + size + " but got "
99                            + (origSize - size));
100                    break;
101                }
102                if (out != null) {
103                    try {
104                        out.write(buffer, 0, got);
105                    } catch (IOException e) {
106                        // Problem writing to the file.  Quit copying data and delete
107                        // the file, but of course keep consuming the input stream.
108                        Log.e(TAG, "Unable to write to file " + outFile.getPath(), e);
109                        out.close();
110                        out = null;
111                        outFile.delete();
112                    }
113                }
114                size -= got;
115            }
116            if (out != null) out.close();
117        }
118
119        // Now twiddle the state to match the backup, assuming all went well
120        if (doChmod && outFile != null) {
121            try {
122                Libcore.os.chmod(outFile.getPath(), (int)mode);
123            } catch (ErrnoException e) {
124                e.rethrowAsIOException();
125            }
126            outFile.setLastModified(mtime);
127        }
128    }
129}
130