FullBackup.java revision b0628bfd5aac480a0d412ac96b8af1d97ac01c30
14a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate/*
24a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * Copyright (C) 2011 The Android Open Source Project
34a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate *
44a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * Licensed under the Apache License, Version 2.0 (the "License");
54a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * you may not use this file except in compliance with the License.
64a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * You may obtain a copy of the License at
74a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate *
84a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate *      http://www.apache.org/licenses/LICENSE-2.0
94a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate *
104a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * Unless required by applicable law or agreed to in writing, software
114a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * distributed under the License is distributed on an "AS IS" BASIS,
124a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * See the License for the specific language governing permissions and
144a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * limitations under the License.
154a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate */
164a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate
174a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tatepackage android.app.backup;
184a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate
1975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport android.os.ParcelFileDescriptor;
2075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport android.util.Log;
2175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
2275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.File;
2375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.FileInputStream;
2475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.FileOutputStream;
2575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.IOException;
2675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
2775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport libcore.io.ErrnoException;
2875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport libcore.io.Libcore;
2975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
304a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate/**
314a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * Global constant definitions et cetera related to the full-backup-to-fd
324a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * binary format.
334a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate *
344a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * @hide
354a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate */
364a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tatepublic class FullBackup {
3775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    static final String TAG = "FullBackup";
3875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
3975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String APK_TREE_TOKEN = "a";
4075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String OBB_TREE_TOKEN = "obb";
4175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String ROOT_TREE_TOKEN = "r";
4275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String DATA_TREE_TOKEN = "f";
4375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String DATABASE_TREE_TOKEN = "db";
4475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String SHAREDPREFS_TREE_TOKEN = "sp";
4575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String CACHE_TREE_TOKEN = "c";
4675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String SHARED_STORAGE_TOKEN = "shared";
4775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
4875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String APPS_PREFIX = "apps/";
49b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate    public static final String SHARED_PREFIX = SHARED_STORAGE_TOKEN + "/";
5075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
5175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String FULL_BACKUP_INTENT_ACTION = "fullback";
5275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String FULL_RESTORE_INTENT_ACTION = "fullrest";
5375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String CONF_TOKEN_INTENT_EXTRA = "conftoken";
5475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
5575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final int TYPE_EOF = 0;
5675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final int TYPE_FILE = 1;
5775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final int TYPE_DIRECTORY = 2;
5875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final int TYPE_SYMLINK = 3;
594a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate
604a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate    static public native int backupToTar(String packageName, String domain,
614a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate            String linkdomain, String rootpath, String path, BackupDataOutput output);
6275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
6375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    static public void restoreToFile(ParcelFileDescriptor data,
64b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate            long size, int type, long mode, long mtime, File outFile,
65b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate            boolean doChmod) throws IOException {
6675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        if (type == FullBackup.TYPE_DIRECTORY) {
6775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            // Canonically a directory has no associated content, so we don't need to read
6875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            // anything from the pipe in this case.  Just create the directory here and
6975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            // drop down to the final metadata adjustment.
7075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            if (outFile != null) outFile.mkdirs();
7175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        } else {
7275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            FileOutputStream out = null;
7375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
7475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            // Pull the data from the pipe, copying it to the output file, until we're done
7575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            try {
7675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                if (outFile != null) {
7775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    File parent = outFile.getParentFile();
7875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    if (!parent.exists()) {
7975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        // in practice this will only be for the default semantic directories,
8075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        // and using the default mode for those is appropriate.
8175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        // TODO: support the edge case of apps that have adjusted the
8275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        //       permissions on these core directories
8375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        parent.mkdirs();
8475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    }
8575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    out = new FileOutputStream(outFile);
8675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                }
8775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            } catch (IOException e) {
8875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                Log.e(TAG, "Unable to create/open file " + outFile.getPath(), e);
8975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            }
9075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
9175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            byte[] buffer = new byte[32 * 1024];
9275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            final long origSize = size;
9375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            FileInputStream in = new FileInputStream(data.getFileDescriptor());
9475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            while (size > 0) {
9575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                int toRead = (size > buffer.length) ? buffer.length : (int)size;
9675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                int got = in.read(buffer, 0, toRead);
9775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                if (got <= 0) {
9875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    Log.w(TAG, "Incomplete read: expected " + size + " but got "
9975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                            + (origSize - size));
10075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    break;
10175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                }
10275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                if (out != null) {
10375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    try {
10475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        out.write(buffer, 0, got);
10575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    } catch (IOException e) {
10675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        // Problem writing to the file.  Quit copying data and delete
10775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        // the file, but of course keep consuming the input stream.
10875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        Log.e(TAG, "Unable to write to file " + outFile.getPath(), e);
10975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        out.close();
11075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        out = null;
11175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        outFile.delete();
11275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    }
11375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                }
11475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                size -= got;
11575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            }
11675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            if (out != null) out.close();
11775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        }
11875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
11975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        // Now twiddle the state to match the backup, assuming all went well
120b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate        if (doChmod && outFile != null) {
12175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            try {
12275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                Libcore.os.chmod(outFile.getPath(), (int)mode);
12375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            } catch (ErrnoException e) {
12475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                e.rethrowAsIOException();
12575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            }
12675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            outFile.setLastModified(mtime);
12775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        }
12875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    }
1294a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate}
130