FullBackup.java revision 75a99709accef8cf221fd436d646727e7c8dd1f1
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/";
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) throws IOException {
65        if (type == FullBackup.TYPE_DIRECTORY) {
66            // Canonically a directory has no associated content, so we don't need to read
67            // anything from the pipe in this case.  Just create the directory here and
68            // drop down to the final metadata adjustment.
69            if (outFile != null) outFile.mkdirs();
70        } else {
71            FileOutputStream out = null;
72
73            // Pull the data from the pipe, copying it to the output file, until we're done
74            try {
75                if (outFile != null) {
76                    File parent = outFile.getParentFile();
77                    if (!parent.exists()) {
78                        // in practice this will only be for the default semantic directories,
79                        // and using the default mode for those is appropriate.
80                        // TODO: support the edge case of apps that have adjusted the
81                        //       permissions on these core directories
82                        parent.mkdirs();
83                    }
84                    out = new FileOutputStream(outFile);
85                }
86            } catch (IOException e) {
87                Log.e(TAG, "Unable to create/open file " + outFile.getPath(), e);
88            }
89
90            byte[] buffer = new byte[32 * 1024];
91            final long origSize = size;
92            FileInputStream in = new FileInputStream(data.getFileDescriptor());
93            while (size > 0) {
94                int toRead = (size > buffer.length) ? buffer.length : (int)size;
95                int got = in.read(buffer, 0, toRead);
96                if (got <= 0) {
97                    Log.w(TAG, "Incomplete read: expected " + size + " but got "
98                            + (origSize - size));
99                    break;
100                }
101                if (out != null) {
102                    try {
103                        out.write(buffer, 0, got);
104                    } catch (IOException e) {
105                        // Problem writing to the file.  Quit copying data and delete
106                        // the file, but of course keep consuming the input stream.
107                        Log.e(TAG, "Unable to write to file " + outFile.getPath(), e);
108                        out.close();
109                        out = null;
110                        outFile.delete();
111                    }
112                }
113                size -= got;
114            }
115            if (out != null) out.close();
116        }
117
118        // Now twiddle the state to match the backup, assuming all went well
119        if (outFile != null) {
120            try {
121                Libcore.os.chmod(outFile.getPath(), (int)mode);
122            } catch (ErrnoException e) {
123                e.rethrowAsIOException();
124            }
125            outFile.setLastModified(mtime);
126        }
127    }
128}
129