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
1979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport android.content.Context;
2079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport android.content.pm.ApplicationInfo;
2179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport android.content.pm.PackageManager;
2275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport android.os.ParcelFileDescriptor;
2375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport android.util.Log;
2475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
2575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.File;
2675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.FileInputStream;
2775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.FileOutputStream;
2875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport java.io.IOException;
2975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
3075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport libcore.io.ErrnoException;
3175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tateimport libcore.io.Libcore;
3275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
334a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate/**
344a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * Global constant definitions et cetera related to the full-backup-to-fd
3579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * binary format.  Nothing in this namespace is part of any API; it's all
3679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate * hidden details of the current implementation gathered into one location.
374a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate *
384a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate * @hide
394a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate */
404a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tatepublic class FullBackup {
4175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    static final String TAG = "FullBackup";
4275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
4375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String APK_TREE_TOKEN = "a";
4475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String OBB_TREE_TOKEN = "obb";
4575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String ROOT_TREE_TOKEN = "r";
4675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String DATA_TREE_TOKEN = "f";
4775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String DATABASE_TREE_TOKEN = "db";
4875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String SHAREDPREFS_TREE_TOKEN = "sp";
49416c39e8d48048fa4a997c09460c262cca871fc4Christopher Tate    public static final String MANAGED_EXTERNAL_TREE_TOKEN = "ef";
5075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String CACHE_TREE_TOKEN = "c";
5175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String SHARED_STORAGE_TOKEN = "shared";
5275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
5375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String APPS_PREFIX = "apps/";
54b0628bfd5aac480a0d412ac96b8af1d97ac01c30Christopher Tate    public static final String SHARED_PREFIX = SHARED_STORAGE_TOKEN + "/";
5575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
5675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String FULL_BACKUP_INTENT_ACTION = "fullback";
5775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String FULL_RESTORE_INTENT_ACTION = "fullrest";
5875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public static final String CONF_TOKEN_INTENT_EXTRA = "conftoken";
5975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
6079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /**
6179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @hide
6279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     */
634a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate    static public native int backupToTar(String packageName, String domain,
644a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate            String linkdomain, String rootpath, String path, BackupDataOutput output);
6575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
6679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /**
6779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * Copy data from a socket to the given File location on permanent storage.  The
68f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate     * modification time and access mode of the resulting file will be set if desired,
69f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate     * although group/all rwx modes will be stripped: the restored file will not be
70f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate     * accessible from outside the target application even if the original file was.
7179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * If the {@code type} parameter indicates that the result should be a directory,
7279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * the socket parameter may be {@code null}; even if it is valid, no data will be
7379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * read from it in this case.
7479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * <p>
7579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * If the {@code mode} argument is negative, then the resulting output file will not
7679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * have its access mode or last modification time reset as part of this operation.
7779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *
7879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param data Socket supplying the data to be copied to the output file.  If the
7979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *    output is a directory, this may be {@code null}.
8079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param size Number of bytes of data to copy from the socket to the file.  At least
8179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *    this much data must be available through the {@code data} parameter.
8279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param type Must be either {@link BackupAgent#TYPE_FILE} for ordinary file data
8379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *    or {@link BackupAgent#TYPE_DIRECTORY} for a directory.
8479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param mode Unix-style file mode (as used by the chmod(2) syscall) to be set on
85f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate     *    the output file or directory.  group/all rwx modes are stripped even if set
86f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate     *    in this parameter.  If this parameter is negative then neither
87f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate     *    the mode nor the mtime values will be applied to the restored file.
8879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param mtime A timestamp in the standard Unix epoch that will be imposed as the
8979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *    last modification time of the output file.  if the {@code mode} parameter is
9079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *    negative then this parameter will be ignored.
9179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param outFile Location within the filesystem to place the data.  This must point
92294b512ecaa98a6a8ef12285ad14e7a4091b5d57Christopher Tate     *    to a location that is writeable by the caller, preferably using an absolute path.
9379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @throws IOException
9479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     */
9579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    static public void restoreFile(ParcelFileDescriptor data,
9679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            long size, int type, long mode, long mtime, File outFile) throws IOException {
9779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        if (type == BackupAgent.TYPE_DIRECTORY) {
9875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            // Canonically a directory has no associated content, so we don't need to read
9975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            // anything from the pipe in this case.  Just create the directory here and
10075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            // drop down to the final metadata adjustment.
10175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            if (outFile != null) outFile.mkdirs();
10275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        } else {
10375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            FileOutputStream out = null;
10475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
10575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            // Pull the data from the pipe, copying it to the output file, until we're done
10675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            try {
10775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                if (outFile != null) {
10875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    File parent = outFile.getParentFile();
10975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    if (!parent.exists()) {
11075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        // in practice this will only be for the default semantic directories,
11175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        // and using the default mode for those is appropriate.
11275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        parent.mkdirs();
11375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    }
11475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    out = new FileOutputStream(outFile);
11575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                }
11675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            } catch (IOException e) {
11775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                Log.e(TAG, "Unable to create/open file " + outFile.getPath(), e);
11875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            }
11975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
12075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            byte[] buffer = new byte[32 * 1024];
12175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            final long origSize = size;
12275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            FileInputStream in = new FileInputStream(data.getFileDescriptor());
12375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            while (size > 0) {
12475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                int toRead = (size > buffer.length) ? buffer.length : (int)size;
12575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                int got = in.read(buffer, 0, toRead);
12675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                if (got <= 0) {
12775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    Log.w(TAG, "Incomplete read: expected " + size + " but got "
12875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                            + (origSize - size));
12975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    break;
13075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                }
13175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                if (out != null) {
13275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    try {
13375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        out.write(buffer, 0, got);
13475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    } catch (IOException e) {
13575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        // Problem writing to the file.  Quit copying data and delete
13675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        // the file, but of course keep consuming the input stream.
13775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        Log.e(TAG, "Unable to write to file " + outFile.getPath(), e);
13875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        out.close();
13975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        out = null;
14075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                        outFile.delete();
14175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    }
14275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                }
14375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                size -= got;
14475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            }
14575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            if (out != null) out.close();
14675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        }
14775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
14875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        // Now twiddle the state to match the backup, assuming all went well
14979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        if (mode >= 0 && outFile != null) {
15075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            try {
151f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate                // explicitly prevent emplacement of files accessible by outside apps
152f6d6fa8cbc0251da1900e858bb0379cda5014b6fChristopher Tate                mode &= 0700;
15375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                Libcore.os.chmod(outFile.getPath(), (int)mode);
15475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            } catch (ErrnoException e) {
15575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                e.rethrowAsIOException();
15675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            }
15775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            outFile.setLastModified(mtime);
15875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        }
15975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    }
1604a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate}
161