1487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate/*
2487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate * Copyright (C) 2009 The Android Open Source Project
3487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate *
4487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate * Licensed under the Apache License, Version 2.0 (the "License");
5487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate * you may not use this file except in compliance with the License.
6487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate * You may obtain a copy of the License at
7487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate *
8487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate *      http://www.apache.org/licenses/LICENSE-2.0
9487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate *
10487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate * Unless required by applicable law or agreed to in writing, software
11487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate * distributed under the License is distributed on an "AS IS" BASIS,
12487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate * See the License for the specific language governing permissions and
14487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate * limitations under the License.
15487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate */
16487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
174528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tatepackage android.app.backup;
18487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
19181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tateimport android.app.IBackupAgent;
204528186e0d65fc68ef0dd1941aa2ac8aefcd55a3Christopher Tateimport android.app.backup.IBackupManager;
21181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tateimport android.content.Context;
22181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tateimport android.content.ContextWrapper;
2379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport android.content.pm.ApplicationInfo;
241902492420825874b12962a10712e653901d120dChristopher Tateimport android.os.Binder;
25487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tateimport android.os.IBinder;
2622b8787ed4be8d4b7ed5d54802f9913fedb41425Christopher Tateimport android.os.ParcelFileDescriptor;
27487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tateimport android.os.RemoteException;
28487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tateimport android.util.Log;
29487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
3079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport java.io.File;
317926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tateimport java.io.FileOutputStream;
3283248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onoratoimport java.io.IOException;
3379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport java.util.HashSet;
3479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport java.util.LinkedList;
3579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
3679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport libcore.io.ErrnoException;
3779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport libcore.io.Libcore;
3879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport libcore.io.OsConstants;
3979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport libcore.io.StructStat;
4083248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato
41487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate/**
42d17da43c82c4edb97514d6138bc208eeba321636Scott Main * Provides the central interface between an
434e14a829129feee14ebe453f61a124784c870610Christopher Tate * application and Android's data backup infrastructure.  An application that wishes
444e14a829129feee14ebe453f61a124784c870610Christopher Tate * to participate in the backup and restore mechanism will declare a subclass of
454e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link android.app.backup.BackupAgent}, implement the
46d17da43c82c4edb97514d6138bc208eeba321636Scott Main * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()}
47d17da43c82c4edb97514d6138bc208eeba321636Scott Main * and {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} methods,
48d17da43c82c4edb97514d6138bc208eeba321636Scott Main * and provide the name of its backup agent class in its {@code AndroidManifest.xml} file via
4961fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * the <code>
5061fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
51d17da43c82c4edb97514d6138bc208eeba321636Scott Main * tag's {@code android:backupAgent} attribute.
5261fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez *
5361fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <div class="special reference">
5461fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <h3>Developer Guides</h3>
5561fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <p>For more information about using BackupAgent, read the
5661fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p></div>
5761fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez *
58d17da43c82c4edb97514d6138bc208eeba321636Scott Main * <h3>Basic Operation</h3>
595a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root * <p>
604e14a829129feee14ebe453f61a124784c870610Christopher Tate * When the application makes changes to data that it wishes to keep backed up,
614e14a829129feee14ebe453f61a124784c870610Christopher Tate * it should call the
624e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link android.app.backup.BackupManager#dataChanged() BackupManager.dataChanged()} method.
63d17da43c82c4edb97514d6138bc208eeba321636Scott Main * This notifies the Android Backup Manager that the application needs an opportunity
64d17da43c82c4edb97514d6138bc208eeba321636Scott Main * to update its backup image.  The Backup Manager, in turn, schedules a
654e14a829129feee14ebe453f61a124784c870610Christopher Tate * backup pass to be performed at an opportune time.
664e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p>
67d17da43c82c4edb97514d6138bc208eeba321636Scott Main * Restore operations are typically performed only when applications are first
684e14a829129feee14ebe453f61a124784c870610Christopher Tate * installed on a device.  At that time, the operating system checks to see whether
69d17da43c82c4edb97514d6138bc208eeba321636Scott Main * there is a previously-saved data set available for the application being installed, and if so,
70d17da43c82c4edb97514d6138bc208eeba321636Scott Main * begins an immediate restore pass to deliver the backup data as part of the installation
714e14a829129feee14ebe453f61a124784c870610Christopher Tate * process.
724e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p>
73d17da43c82c4edb97514d6138bc208eeba321636Scott Main * When a backup or restore pass is run, the application's process is launched
74d17da43c82c4edb97514d6138bc208eeba321636Scott Main * (if not already running), the manifest-declared backup agent class (in the {@code
75d17da43c82c4edb97514d6138bc208eeba321636Scott Main * android:backupAgent} attribute) is instantiated within
76d17da43c82c4edb97514d6138bc208eeba321636Scott Main * that process, and the agent's {@link #onCreate()} method is invoked.  This prepares the
774e14a829129feee14ebe453f61a124784c870610Christopher Tate * agent instance to run the actual backup or restore logic.  At this point the
784e14a829129feee14ebe453f61a124784c870610Christopher Tate * agent's
794e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()} or
804e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} method will be
814e14a829129feee14ebe453f61a124784c870610Christopher Tate * invoked as appropriate for the operation being performed.
824e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p>
83d17da43c82c4edb97514d6138bc208eeba321636Scott Main * A backup data set consists of one or more "entities," flattened binary data
84d17da43c82c4edb97514d6138bc208eeba321636Scott Main * records that are each identified with a key string unique within the data set.  Adding a
85d17da43c82c4edb97514d6138bc208eeba321636Scott Main * record to the active data set or updating an existing record is done by simply
864e14a829129feee14ebe453f61a124784c870610Christopher Tate * writing new entity data under the desired key.  Deleting an entity from the data set
874e14a829129feee14ebe453f61a124784c870610Christopher Tate * is done by writing an entity under that key with header specifying a negative data
884e14a829129feee14ebe453f61a124784c870610Christopher Tate * size, and no actual entity data.
894e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p>
904e14a829129feee14ebe453f61a124784c870610Christopher Tate * <b>Helper Classes</b>
914e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p>
924e14a829129feee14ebe453f61a124784c870610Christopher Tate * An extensible agent based on convenient helper classes is available in
934e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link android.app.backup.BackupAgentHelper}.  That class is particularly
944e14a829129feee14ebe453f61a124784c870610Christopher Tate * suited to handling of simple file or {@link android.content.SharedPreferences}
954e14a829129feee14ebe453f61a124784c870610Christopher Tate * backup and restore.
964e14a829129feee14ebe453f61a124784c870610Christopher Tate *
974e14a829129feee14ebe453f61a124784c870610Christopher Tate * @see android.app.backup.BackupManager
984e14a829129feee14ebe453f61a124784c870610Christopher Tate * @see android.app.backup.BackupAgentHelper
994e14a829129feee14ebe453f61a124784c870610Christopher Tate * @see android.app.backup.BackupDataInput
1004e14a829129feee14ebe453f61a124784c870610Christopher Tate * @see android.app.backup.BackupDataOutput
101487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate */
102181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tatepublic abstract class BackupAgent extends ContextWrapper {
10383248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato    private static final String TAG = "BackupAgent";
1044a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate    private static final boolean DEBUG = true;
10583248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato
10679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /** @hide */
10779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    public static final int TYPE_EOF = 0;
10879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
10979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /**
11079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * During a full restore, indicates that the file system object being restored
11179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * is an ordinary file.
11279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     */
11379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    public static final int TYPE_FILE = 1;
11479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
11579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /**
11679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * During a full restore, indicates that the file system object being restored
11779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * is a directory.
11879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     */
11979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    public static final int TYPE_DIRECTORY = 2;
12079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
12179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /** @hide */
12279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    public static final int TYPE_SYMLINK = 3;
12379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
124181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    public BackupAgent() {
125181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate        super(null);
126181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    }
127487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
1284e14a829129feee14ebe453f61a124784c870610Christopher Tate    /**
1294e14a829129feee14ebe453f61a124784c870610Christopher Tate     * Provided as a convenience for agent implementations that need an opportunity
1304e14a829129feee14ebe453f61a124784c870610Christopher Tate     * to do one-time initialization before the actual backup or restore operation
1314e14a829129feee14ebe453f61a124784c870610Christopher Tate     * is begun.
1324e14a829129feee14ebe453f61a124784c870610Christopher Tate     * <p>
1334e14a829129feee14ebe453f61a124784c870610Christopher Tate     * Agents do not need to override this method.
1344e14a829129feee14ebe453f61a124784c870610Christopher Tate     */
135181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    public void onCreate() {
136181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    }
137181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate
1384e14a829129feee14ebe453f61a124784c870610Christopher Tate    /**
1394e14a829129feee14ebe453f61a124784c870610Christopher Tate     * Provided as a convenience for agent implementations that need to do some
1404e14a829129feee14ebe453f61a124784c870610Christopher Tate     * sort of shutdown process after backup or restore is completed.
1414e14a829129feee14ebe453f61a124784c870610Christopher Tate     * <p>
1424e14a829129feee14ebe453f61a124784c870610Christopher Tate     * Agents do not need to override this method.
1434e14a829129feee14ebe453f61a124784c870610Christopher Tate     */
144181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    public void onDestroy() {
145181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    }
146487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
147487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate    /**
1485a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * The application is being asked to write any data changed since the last
1495a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * time it performed a backup operation. The state data recorded during the
1505a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * last backup pass is provided in the <code>oldState</code> file
1515a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * descriptor. If <code>oldState</code> is <code>null</code>, no old state
1525a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * is available and the application should perform a full backup. In both
1535a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * cases, a representation of the final backup state after this pass should
1545a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * be written to the file pointed to by the file descriptor wrapped in
1555a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * <code>newState</code>.
1564e14a829129feee14ebe453f61a124784c870610Christopher Tate     * <p>
1574e14a829129feee14ebe453f61a124784c870610Christopher Tate     * Each entity written to the {@link android.app.backup.BackupDataOutput}
1584e14a829129feee14ebe453f61a124784c870610Christopher Tate     * <code>data</code> stream will be transmitted
1594e14a829129feee14ebe453f61a124784c870610Christopher Tate     * over the current backup transport and stored in the remote data set under
1604e14a829129feee14ebe453f61a124784c870610Christopher Tate     * the key supplied as part of the entity.  Writing an entity with a negative
1614e14a829129feee14ebe453f61a124784c870610Christopher Tate     * data size instructs the transport to delete whatever entity currently exists
1624e14a829129feee14ebe453f61a124784c870610Christopher Tate     * under that key from the remote data set.
1635a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *
1645a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * @param oldState An open, read-only ParcelFileDescriptor pointing to the
1655a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            last backup state provided by the application. May be
1665a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            <code>null</code>, in which case no prior state is being
1675a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            provided and the application should perform a full backup.
1685a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * @param data A structured wrapper around an open, read/write
1694e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            file descriptor pointing to the backup data destination.
1705a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            Typically the application will use backup helper classes to
1715a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            write to this file.
1725a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * @param newState An open, read/write ParcelFileDescriptor pointing to an
1735a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            empty file. The application should record the final backup
1744e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            state here after writing the requested data to the <code>data</code>
1754e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            output stream.
176487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate     */
177290bb011c5c1a9ba1f2116810b06cf52a9c36b3eJoe Onorato    public abstract void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
1784ababd922eac5931e0222862ff082dc29e012816Joe Onorato             ParcelFileDescriptor newState) throws IOException;
1795a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root
180487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate    /**
1815a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * The application is being restored from backup and should replace any
1825a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * existing data with the contents of the backup. The backup data is
1834e14a829129feee14ebe453f61a124784c870610Christopher Tate     * provided through the <code>data</code> parameter. Once
1845a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * the restore is finished, the application should write a representation of
1855a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * the final state to the <code>newState</code> file descriptor.
1865a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * <p>
1875a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * The application is responsible for properly erasing its old data and
1885a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * replacing it with the data supplied to this method. No "clear user data"
1895a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * operation will be performed automatically by the operating system. The
1905a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * exception to this is in the case of a failed restore attempt: if
1915a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * onRestore() throws an exception, the OS will assume that the
1925a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * application's data may now be in an incoherent state, and will clear it
1935a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * before proceeding.
1945a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *
1955a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * @param data A structured wrapper around an open, read-only
1964e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            file descriptor pointing to a full snapshot of the
1974e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            application's data.  The application should consume every
1984e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            entity represented in this data stream.
199b83a283ac178ab0a72f1d811189d79b26097835eScott Main     * @param appVersionCode The value of the <a
200b83a283ac178ab0a72f1d811189d79b26097835eScott Main     * href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code
201b83a283ac178ab0a72f1d811189d79b26097835eScott Main     *            android:versionCode}</a> manifest attribute,
202b83a283ac178ab0a72f1d811189d79b26097835eScott Main     *            from the application that backed up this particular data set. This
2034e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            makes it possible for an application's agent to distinguish among any
2045a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            possible older data versions when asked to perform the restore
2055a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            operation.
2065a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * @param newState An open, read/write ParcelFileDescriptor pointing to an
2075a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            empty file. The application should record the final backup
2084e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            state here after restoring its data from the <code>data</code> stream.
2094a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate     *            When a full-backup dataset is being restored, this will be <code>null</code>.
210487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate     */
2115cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate    public abstract void onRestore(BackupDataInput data, int appVersionCode,
2125cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate            ParcelFileDescriptor newState)
21383248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato            throws IOException;
214487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
2154a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate    /**
21679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * The default implementation backs up the entirety of the application's "owned"
21779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * file system trees to the output.
21879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     */
21979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    public void onFullBackup(FullBackupDataOutput data) throws IOException {
22079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        ApplicationInfo appInfo = getApplicationInfo();
22179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
2222efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate        String rootDir = new File(appInfo.dataDir).getCanonicalPath();
2232efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate        String filesDir = getFilesDir().getCanonicalPath();
2242efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate        String databaseDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
2252efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate        String sharedPrefsDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
2262efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate        String cacheDir = getCacheDir().getCanonicalPath();
22779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        String libDir = (appInfo.nativeLibraryDir != null)
2282efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                ? new File(appInfo.nativeLibraryDir).getCanonicalPath()
22979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                : null;
23079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
23179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        // Filters, the scan queue, and the set of resulting entities
23279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        HashSet<String> filterSet = new HashSet<String>();
23379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        String packageName = getPackageName();
23479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
23579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        // Okay, start with the app's root tree, but exclude all of the canonical subdirs
23679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        if (libDir != null) {
23779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            filterSet.add(libDir);
23879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        }
23979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        filterSet.add(cacheDir);
24079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        filterSet.add(databaseDir);
24179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        filterSet.add(sharedPrefsDir);
24279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        filterSet.add(filesDir);
24379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        fullBackupFileTree(packageName, FullBackup.ROOT_TREE_TOKEN, rootDir, filterSet, data);
24479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
24579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        // Now do the same for the files dir, db dir, and shared prefs dir
24679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        filterSet.add(rootDir);
24779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        filterSet.remove(filesDir);
24879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        fullBackupFileTree(packageName, FullBackup.DATA_TREE_TOKEN, filesDir, filterSet, data);
24979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
25079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        filterSet.add(filesDir);
25179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        filterSet.remove(databaseDir);
25279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        fullBackupFileTree(packageName, FullBackup.DATABASE_TREE_TOKEN, databaseDir, filterSet, data);
25379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
25479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        filterSet.add(databaseDir);
25579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        filterSet.remove(sharedPrefsDir);
25679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        fullBackupFileTree(packageName, FullBackup.SHAREDPREFS_TREE_TOKEN, sharedPrefsDir, filterSet, data);
25779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    }
25879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
25979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /**
26079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * Write an entire file as part of a full-backup operation.  The file's contents
26179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * will be delivered to the backup destination along with the metadata necessary
26279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * to place it with the proper location and permissions on the device where the
26379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * data is restored.
26479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *
26579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param file The file to be backed up.  The file must exist and be readable by
26679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *     the caller.
26779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param output The destination to which the backed-up file data will be sent.
26879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     */
26979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    public final void fullBackupFile(File file, FullBackupDataOutput output) {
27079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        // Look up where all of our various well-defined dir trees live on this device
27179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        String mainDir;
27279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        String filesDir;
27379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        String dbDir;
27479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        String spDir;
27579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        String cacheDir;
27679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        String libDir;
2772efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate        String filePath;
27879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
27979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        ApplicationInfo appInfo = getApplicationInfo();
28079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
2812efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate        try {
2822efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            mainDir = new File(appInfo.dataDir).getCanonicalPath();
2832efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            filesDir = getFilesDir().getCanonicalPath();
2842efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            dbDir = getDatabasePath("foo").getParentFile().getCanonicalPath();
2852efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            spDir = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
2862efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            cacheDir = getCacheDir().getCanonicalPath();
2872efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            libDir = (appInfo.nativeLibraryDir == null)
2882efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    ? null
2892efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    : new File(appInfo.nativeLibraryDir).getCanonicalPath();
2902efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate
2912efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            // Now figure out which well-defined tree the file is placed in, working from
2922efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            // most to least specific.  We also specifically exclude the lib and cache dirs.
2932efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            filePath = file.getCanonicalPath();
2942efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate        } catch (IOException e) {
2952efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            Log.w(TAG, "Unable to obtain canonical paths");
2962efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            return;
2972efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate        }
29879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
29979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        if (filePath.startsWith(cacheDir) || filePath.startsWith(libDir)) {
30079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            Log.w(TAG, "lib and cache files are not backed up");
30179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            return;
30279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        }
30379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
30479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        final String domain;
30579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        String rootpath = null;
30679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        if (filePath.startsWith(dbDir)) {
30779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            domain = FullBackup.DATABASE_TREE_TOKEN;
30879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            rootpath = dbDir;
30979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        } else if (filePath.startsWith(spDir)) {
31079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            domain = FullBackup.SHAREDPREFS_TREE_TOKEN;
31179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            rootpath = spDir;
31279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        } else if (filePath.startsWith(filesDir)) {
31379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            domain = FullBackup.DATA_TREE_TOKEN;
31479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            rootpath = filesDir;
31579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        } else if (filePath.startsWith(mainDir)) {
31679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            domain = FullBackup.ROOT_TREE_TOKEN;
31779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            rootpath = mainDir;
31879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        } else {
31979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            Log.w(TAG, "File " + filePath + " is in an unsupported location; skipping");
32079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            return;
32179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        }
32279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
32379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        // And now that we know where it lives, semantically, back it up appropriately
32479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        Log.i(TAG, "backupFile() of " + filePath + " => domain=" + domain
32579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                + " rootpath=" + rootpath);
32679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        FullBackup.backupToTar(getPackageName(), domain, null, rootpath, filePath,
32779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                output.getData());
32879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    }
32979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
33079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /**
33179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * Scan the dir tree (if it actually exists) and process each entry we find.  If the
33279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * 'excludes' parameter is non-null, it is consulted each time a new file system entity
33379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * is visited to see whether that entity (and its subtree, if appropriate) should be
33479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * omitted from the backup process.
33579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *
33679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @hide
33779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     */
33879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    protected final void fullBackupFileTree(String packageName, String domain, String rootPath,
33979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            HashSet<String> excludes, FullBackupDataOutput output) {
34079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        File rootFile = new File(rootPath);
34179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        if (rootFile.exists()) {
34279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            LinkedList<File> scanQueue = new LinkedList<File>();
34379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            scanQueue.add(rootFile);
34479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
34579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            while (scanQueue.size() > 0) {
34679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                File file = scanQueue.remove(0);
3472efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                String filePath;
3482efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                try {
3492efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    filePath = file.getCanonicalPath();
35079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
3512efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    // prune this subtree?
3522efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    if (excludes != null && excludes.contains(filePath)) {
3532efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                        continue;
3542efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    }
35579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
3562efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    // If it's a directory, enqueue its contents for scanning.
35779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                    StructStat stat = Libcore.os.lstat(filePath);
35879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                    if (OsConstants.S_ISLNK(stat.st_mode)) {
35979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                        if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file);
36079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                        continue;
36179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                    } else if (OsConstants.S_ISDIR(stat.st_mode)) {
36279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                        File[] contents = file.listFiles();
36379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                        if (contents != null) {
36479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                            for (File entry : contents) {
36579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                                scanQueue.add(0, entry);
36679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                            }
36779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                        }
36879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                    }
3692efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                } catch (IOException e) {
3702efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    if (DEBUG) Log.w(TAG, "Error canonicalizing path of " + file);
3712efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    continue;
37279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                } catch (ErrnoException e) {
37379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                    if (DEBUG) Log.w(TAG, "Error scanning file " + file + " : " + e);
37479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                    continue;
37579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                }
37679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
37779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                // Finally, back this file up before proceeding
37879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                FullBackup.backupToTar(packageName, domain, null, rootPath, filePath,
37979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                        output.getData());
38079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            }
38179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        }
38279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    }
38379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
38479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /**
38579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * Handle the data delivered via the given file descriptor during a full restore
38679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * operation.  The agent is given the path to the file's original location as well
38779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * as its size and metadata.
38879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * <p>
38979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * The file descriptor can only be read for {@code size} bytes; attempting to read
39079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * more data has undefined behavior.
39179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * <p>
39279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * The default implementation creates the destination file/directory and populates it
39379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * with the data from the file descriptor, then sets the file's access mode and
39479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * modification time to match the restore arguments.
39579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *
39679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param data A read-only file descriptor from which the agent can read {@code size}
39779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *     bytes of file data.
39879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param size The number of bytes of file content to be restored to the given
39979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *     destination.  If the file system object being restored is a directory, {@code size}
40079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *     will be zero.
40179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param destination The File on disk to be restored with the given data.
40279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param type The kind of file system object being restored.  This will be either
40379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *     {@link BackupAgent#TYPE_FILE} or {@link BackupAgent#TYPE_DIRECTORY}.
40479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param mode The access mode to be assigned to the destination after its data is
40579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *     written.  This is in the standard format used by {@code chmod()}.
40679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param mtime The modification time of the file when it was backed up, suitable to
40779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *     be assigned to the file after its data is written.
40879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @throws IOException
40975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate     */
41075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public void onRestoreFile(ParcelFileDescriptor data, long size,
41179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            File destination, int type, long mode, long mtime)
41275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            throws IOException {
41379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        FullBackup.restoreFile(data, size, type, mode, mtime, destination);
41475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    }
41575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
41675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    /**
41779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * Only specialized platform agents should overload this entry point to support
41879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * restores to crazy non-app locations.
41979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @hide
4204a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate     */
42179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    protected void onRestoreFile(ParcelFileDescriptor data, long size,
42279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            int type, String domain, String path, long mode, long mtime)
42379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            throws IOException {
42479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        String basePath = null;
42579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
42679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        if (DEBUG) Log.d(TAG, "onRestoreFile() size=" + size + " type=" + type
42779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                + " domain=" + domain + " relpath=" + path + " mode=" + mode
42879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                + " mtime=" + mtime);
42979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
43079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        // Parse out the semantic domains into the correct physical location
43179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        if (domain.equals(FullBackup.DATA_TREE_TOKEN)) {
4322efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            basePath = getFilesDir().getCanonicalPath();
43379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        } else if (domain.equals(FullBackup.DATABASE_TREE_TOKEN)) {
4342efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            basePath = getDatabasePath("foo").getParentFile().getCanonicalPath();
43579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        } else if (domain.equals(FullBackup.ROOT_TREE_TOKEN)) {
4362efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            basePath = new File(getApplicationInfo().dataDir).getCanonicalPath();
43779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        } else if (domain.equals(FullBackup.SHAREDPREFS_TREE_TOKEN)) {
4382efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            basePath = getSharedPrefsFile("foo").getParentFile().getCanonicalPath();
43979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        } else if (domain.equals(FullBackup.CACHE_TREE_TOKEN)) {
4402efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            basePath = getCacheDir().getCanonicalPath();
44179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        } else {
44279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            // Not a supported location
44379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            Log.i(TAG, "Data restored from non-app domain " + domain + ", ignoring");
44479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        }
44579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
44679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        // Now that we've figured out where the data goes, send it on its way
44779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        if (basePath != null) {
44879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            File outFile = new File(basePath, path);
44979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            if (DEBUG) Log.i(TAG, "[" + domain + " : " + path + "] mapped to " + outFile.getPath());
45079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            onRestoreFile(data, size, outFile, type, mode, mtime);
45179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        } else {
45279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            // Not a supported output location?  We need to consume the data
45379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            // anyway, so just use the default "copy the data out" implementation
45479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            // with a null destination.
45579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            if (DEBUG) Log.i(TAG, "[ skipping data from unsupported domain " + domain + "]");
45679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            FullBackup.restoreFile(data, size, type, mode, mtime, null);
45779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        }
4584a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate    }
459487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
460487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate    // ----- Core implementation -----
46144a2790374bf27116cbd91060d4f096ca5999709Christopher Tate
46244a2790374bf27116cbd91060d4f096ca5999709Christopher Tate    /** @hide */
46344a2790374bf27116cbd91060d4f096ca5999709Christopher Tate    public final IBinder onBind() {
464181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate        return mBinder;
465487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate    }
466487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
467487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate    private final IBinder mBinder = new BackupServiceBinder().asBinder();
468487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
469181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    /** @hide */
470181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    public void attach(Context context) {
471181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate        attachBaseContext(context);
472181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    }
473181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate
474487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate    // ----- IBackupService binder interface -----
475181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    private class BackupServiceBinder extends IBackupAgent.Stub {
476181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate        private static final String TAG = "BackupServiceBinder";
477181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate
47875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        @Override
47922b8787ed4be8d4b7ed5d54802f9913fedb41425Christopher Tate        public void doBackup(ParcelFileDescriptor oldState,
48022b8787ed4be8d4b7ed5d54802f9913fedb41425Christopher Tate                ParcelFileDescriptor data,
48144a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                ParcelFileDescriptor newState,
48244a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                int token, IBackupManager callbackBinder) throws RemoteException {
4831902492420825874b12962a10712e653901d120dChristopher Tate            // Ensure that we're running with the app's normal permission level
48444a2790374bf27116cbd91060d4f096ca5999709Christopher Tate            long ident = Binder.clearCallingIdentity();
4851902492420825874b12962a10712e653901d120dChristopher Tate
486436344ae12c819f58306ceb94241a266141e1218Christopher Tate            if (DEBUG) Log.v(TAG, "doBackup() invoked");
48783248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato            BackupDataOutput output = new BackupDataOutput(data.getFileDescriptor());
4884a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate
489290bb011c5c1a9ba1f2116810b06cf52a9c36b3eJoe Onorato            try {
490181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate                BackupAgent.this.onBackup(oldState, output, newState);
4914ababd922eac5931e0222862ff082dc29e012816Joe Onorato            } catch (IOException ex) {
4924ababd922eac5931e0222862ff082dc29e012816Joe Onorato                Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
4934ababd922eac5931e0222862ff082dc29e012816Joe Onorato                throw new RuntimeException(ex);
494290bb011c5c1a9ba1f2116810b06cf52a9c36b3eJoe Onorato            } catch (RuntimeException ex) {
49583248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato                Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
496290bb011c5c1a9ba1f2116810b06cf52a9c36b3eJoe Onorato                throw ex;
4971902492420825874b12962a10712e653901d120dChristopher Tate            } finally {
49844a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                Binder.restoreCallingIdentity(ident);
49944a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                try {
50044a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                    callbackBinder.opComplete(token);
50144a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                } catch (RemoteException e) {
50244a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                    // we'll time out anyway, so we're safe
50344a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                }
504290bb011c5c1a9ba1f2116810b06cf52a9c36b3eJoe Onorato            }
505487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate        }
506487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
50775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        @Override
5085cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate        public void doRestore(ParcelFileDescriptor data, int appVersionCode,
50944a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                ParcelFileDescriptor newState,
51044a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                int token, IBackupManager callbackBinder) throws RemoteException {
5111902492420825874b12962a10712e653901d120dChristopher Tate            // Ensure that we're running with the app's normal permission level
51244a2790374bf27116cbd91060d4f096ca5999709Christopher Tate            long ident = Binder.clearCallingIdentity();
5131902492420825874b12962a10712e653901d120dChristopher Tate
514436344ae12c819f58306ceb94241a266141e1218Christopher Tate            if (DEBUG) Log.v(TAG, "doRestore() invoked");
51583248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato            BackupDataInput input = new BackupDataInput(data.getFileDescriptor());
51683248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato            try {
5175cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate                BackupAgent.this.onRestore(input, appVersionCode, newState);
51883248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato            } catch (IOException ex) {
51983248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato                Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex);
52083248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato                throw new RuntimeException(ex);
52183248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato            } catch (RuntimeException ex) {
52283248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato                Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex);
52383248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato                throw ex;
5241902492420825874b12962a10712e653901d120dChristopher Tate            } finally {
52544a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                Binder.restoreCallingIdentity(ident);
52644a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                try {
52779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                    callbackBinder.opComplete(token);
52879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                } catch (RemoteException e) {
52979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                    // we'll time out anyway, so we're safe
53079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                }
53179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            }
53279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        }
53379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
53479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        @Override
53579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        public void doFullBackup(ParcelFileDescriptor data,
53679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                int token, IBackupManager callbackBinder) {
53779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            // Ensure that we're running with the app's normal permission level
53879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            long ident = Binder.clearCallingIdentity();
53979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
54079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            if (DEBUG) Log.v(TAG, "doFullBackup() invoked");
54179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
54279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            try {
54379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                BackupAgent.this.onFullBackup(new FullBackupDataOutput(data));
54479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            } catch (IOException ex) {
54579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
54679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                throw new RuntimeException(ex);
54779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            } catch (RuntimeException ex) {
54879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
54979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                throw ex;
55079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            } finally {
5517926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                // Send the EOD marker indicating that there is no more data
5527926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                // forthcoming from this agent.
5537926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                try {
5547926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                    FileOutputStream out = new FileOutputStream(data.getFileDescriptor());
5557926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                    byte[] buf = new byte[4];
5567926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                    out.write(buf);
5577926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                } catch (IOException e) {
5587926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                    Log.e(TAG, "Unable to finalize backup stream!");
5597926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                }
5607926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate
56179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                Binder.restoreCallingIdentity(ident);
56279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                try {
56344a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                    callbackBinder.opComplete(token);
56444a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                } catch (RemoteException e) {
56544a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                    // we'll time out anyway, so we're safe
56644a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                }
56783248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato            }
568487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate        }
56975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
57075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        @Override
57175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        public void doRestoreFile(ParcelFileDescriptor data, long size,
57275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                int type, String domain, String path, long mode, long mtime,
57375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                int token, IBackupManager callbackBinder) throws RemoteException {
57475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            long ident = Binder.clearCallingIdentity();
57575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            try {
57675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                BackupAgent.this.onRestoreFile(data, size, type, domain, path, mode, mtime);
57775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            } catch (IOException e) {
57875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                throw new RuntimeException(e);
57975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            } finally {
58075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                Binder.restoreCallingIdentity(ident);
58175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                try {
58275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    callbackBinder.opComplete(token);
58375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                } catch (RemoteException e) {
58475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    // we'll time out anyway, so we're safe
58575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                }
58675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            }
58775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        }
588487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate    }
589487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate}
590