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;
20f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tateimport android.app.QueuedWork;
21181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tateimport android.content.Context;
22181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tateimport android.content.ContextWrapper;
2379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport android.content.pm.ApplicationInfo;
241902492420825874b12962a10712e653901d120dChristopher Tateimport android.os.Binder;
25f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tateimport android.os.Handler;
26487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tateimport android.os.IBinder;
27f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tateimport android.os.Looper;
2822b8787ed4be8d4b7ed5d54802f9913fedb41425Christopher Tateimport android.os.ParcelFileDescriptor;
295cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tateimport android.os.Process;
30487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tateimport android.os.RemoteException;
3134385d352da19805ae948215e2edbeedd16b7941Elliott Hughesimport android.system.ErrnoException;
3234385d352da19805ae948215e2edbeedd16b7941Elliott Hughesimport android.system.Os;
3334385d352da19805ae948215e2edbeedd16b7941Elliott Hughesimport android.system.OsConstants;
3434385d352da19805ae948215e2edbeedd16b7941Elliott Hughesimport android.system.StructStat;
35303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williamsimport android.util.ArraySet;
36487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tateimport android.util.Log;
37487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
3891bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tateimport libcore.io.IoUtils;
3991bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate
408a372a0a280127743ce9a7ce4b6198c7a02d2a4fJeff Sharkeyimport org.xmlpull.v1.XmlPullParserException;
418a372a0a280127743ce9a7ce4b6198c7a02d2a4fJeff Sharkey
4279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport java.io.File;
437926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tateimport java.io.FileOutputStream;
4483248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onoratoimport java.io.IOException;
45303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williamsimport java.util.Collection;
4679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tateimport java.util.LinkedList;
47303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williamsimport java.util.Map;
48303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williamsimport java.util.Set;
49f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tateimport java.util.concurrent.CountDownLatch;
5079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
51487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate/**
52d17da43c82c4edb97514d6138bc208eeba321636Scott Main * Provides the central interface between an
534e14a829129feee14ebe453f61a124784c870610Christopher Tate * application and Android's data backup infrastructure.  An application that wishes
544e14a829129feee14ebe453f61a124784c870610Christopher Tate * to participate in the backup and restore mechanism will declare a subclass of
554e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link android.app.backup.BackupAgent}, implement the
56d17da43c82c4edb97514d6138bc208eeba321636Scott Main * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()}
57d17da43c82c4edb97514d6138bc208eeba321636Scott Main * and {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} methods,
58d17da43c82c4edb97514d6138bc208eeba321636Scott Main * and provide the name of its backup agent class in its {@code AndroidManifest.xml} file via
5961fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * the <code>
6061fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <a href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
61d17da43c82c4edb97514d6138bc208eeba321636Scott Main * tag's {@code android:backupAgent} attribute.
6261fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez *
6361fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <div class="special reference">
6461fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <h3>Developer Guides</h3>
6561fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <p>For more information about using BackupAgent, read the
6661fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez * <a href="{@docRoot}guide/topics/data/backup.html">Data Backup</a> developer guide.</p></div>
6761fd1e8d8c3ccf2d6b7d4af1c19e8f0988d5a1ecJoe Fernandez *
68d17da43c82c4edb97514d6138bc208eeba321636Scott Main * <h3>Basic Operation</h3>
695a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root * <p>
704e14a829129feee14ebe453f61a124784c870610Christopher Tate * When the application makes changes to data that it wishes to keep backed up,
714e14a829129feee14ebe453f61a124784c870610Christopher Tate * it should call the
724e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link android.app.backup.BackupManager#dataChanged() BackupManager.dataChanged()} method.
73d17da43c82c4edb97514d6138bc208eeba321636Scott Main * This notifies the Android Backup Manager that the application needs an opportunity
74d17da43c82c4edb97514d6138bc208eeba321636Scott Main * to update its backup image.  The Backup Manager, in turn, schedules a
754e14a829129feee14ebe453f61a124784c870610Christopher Tate * backup pass to be performed at an opportune time.
764e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p>
77d17da43c82c4edb97514d6138bc208eeba321636Scott Main * Restore operations are typically performed only when applications are first
784e14a829129feee14ebe453f61a124784c870610Christopher Tate * installed on a device.  At that time, the operating system checks to see whether
79d17da43c82c4edb97514d6138bc208eeba321636Scott Main * there is a previously-saved data set available for the application being installed, and if so,
80d17da43c82c4edb97514d6138bc208eeba321636Scott Main * begins an immediate restore pass to deliver the backup data as part of the installation
814e14a829129feee14ebe453f61a124784c870610Christopher Tate * process.
824e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p>
83d17da43c82c4edb97514d6138bc208eeba321636Scott Main * When a backup or restore pass is run, the application's process is launched
84d17da43c82c4edb97514d6138bc208eeba321636Scott Main * (if not already running), the manifest-declared backup agent class (in the {@code
85d17da43c82c4edb97514d6138bc208eeba321636Scott Main * android:backupAgent} attribute) is instantiated within
86d17da43c82c4edb97514d6138bc208eeba321636Scott Main * that process, and the agent's {@link #onCreate()} method is invoked.  This prepares the
874e14a829129feee14ebe453f61a124784c870610Christopher Tate * agent instance to run the actual backup or restore logic.  At this point the
884e14a829129feee14ebe453f61a124784c870610Christopher Tate * agent's
894e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()} or
904e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} method will be
914e14a829129feee14ebe453f61a124784c870610Christopher Tate * invoked as appropriate for the operation being performed.
924e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p>
93d17da43c82c4edb97514d6138bc208eeba321636Scott Main * A backup data set consists of one or more "entities," flattened binary data
94d17da43c82c4edb97514d6138bc208eeba321636Scott Main * records that are each identified with a key string unique within the data set.  Adding a
95d17da43c82c4edb97514d6138bc208eeba321636Scott Main * record to the active data set or updating an existing record is done by simply
964e14a829129feee14ebe453f61a124784c870610Christopher Tate * writing new entity data under the desired key.  Deleting an entity from the data set
974e14a829129feee14ebe453f61a124784c870610Christopher Tate * is done by writing an entity under that key with header specifying a negative data
984e14a829129feee14ebe453f61a124784c870610Christopher Tate * size, and no actual entity data.
994e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p>
1004e14a829129feee14ebe453f61a124784c870610Christopher Tate * <b>Helper Classes</b>
1014e14a829129feee14ebe453f61a124784c870610Christopher Tate * <p>
1024e14a829129feee14ebe453f61a124784c870610Christopher Tate * An extensible agent based on convenient helper classes is available in
1034e14a829129feee14ebe453f61a124784c870610Christopher Tate * {@link android.app.backup.BackupAgentHelper}.  That class is particularly
1044e14a829129feee14ebe453f61a124784c870610Christopher Tate * suited to handling of simple file or {@link android.content.SharedPreferences}
1054e14a829129feee14ebe453f61a124784c870610Christopher Tate * backup and restore.
1064e14a829129feee14ebe453f61a124784c870610Christopher Tate *
1074e14a829129feee14ebe453f61a124784c870610Christopher Tate * @see android.app.backup.BackupManager
1084e14a829129feee14ebe453f61a124784c870610Christopher Tate * @see android.app.backup.BackupAgentHelper
1094e14a829129feee14ebe453f61a124784c870610Christopher Tate * @see android.app.backup.BackupDataInput
1104e14a829129feee14ebe453f61a124784c870610Christopher Tate * @see android.app.backup.BackupDataOutput
111487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate */
112181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tatepublic abstract class BackupAgent extends ContextWrapper {
11383248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato    private static final String TAG = "BackupAgent";
114f0e32ee572746fcd6ba83ad5476045ccfef9f349Alan Jeon    private static final boolean DEBUG = false;
11583248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato
11679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /** @hide */
11779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    public static final int TYPE_EOF = 0;
11879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
11979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /**
12079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * During a full restore, indicates that the file system object being restored
12179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * is an ordinary file.
12279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     */
12379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    public static final int TYPE_FILE = 1;
12479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
12579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /**
12679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * During a full restore, indicates that the file system object being restored
12779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * is a directory.
12879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     */
12979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    public static final int TYPE_DIRECTORY = 2;
13079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
13179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /** @hide */
13279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    public static final int TYPE_SYMLINK = 3;
13379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
134f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate    Handler mHandler = null;
135f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate
136cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate    Handler getHandler() {
137cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate        if (mHandler == null) {
138cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate            mHandler = new Handler(Looper.getMainLooper());
139cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate        }
140cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate        return mHandler;
141cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate    }
142cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate
143f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate    class SharedPrefsSynchronizer implements Runnable {
144f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate        public final CountDownLatch mLatch = new CountDownLatch(1);
145f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate
146f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate        @Override
147f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate        public void run() {
148f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate            QueuedWork.waitToFinish();
149f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate            mLatch.countDown();
150f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate        }
151f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate    };
152f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate
153f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate    // Syncing shared preferences deferred writes needs to happen on the main looper thread
154f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate    private void waitForSharedPrefs() {
155cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate        Handler h = getHandler();
156f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate        final SharedPrefsSynchronizer s = new SharedPrefsSynchronizer();
157cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate        h.postAtFrontOfQueue(s);
158f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate        try {
159f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate            s.mLatch.await();
160f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate        } catch (InterruptedException e) { /* ignored */ }
161f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate    }
162f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate
163f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate
164181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    public BackupAgent() {
165181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate        super(null);
166181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    }
167487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
1684e14a829129feee14ebe453f61a124784c870610Christopher Tate    /**
1694e14a829129feee14ebe453f61a124784c870610Christopher Tate     * Provided as a convenience for agent implementations that need an opportunity
1704e14a829129feee14ebe453f61a124784c870610Christopher Tate     * to do one-time initialization before the actual backup or restore operation
1714e14a829129feee14ebe453f61a124784c870610Christopher Tate     * is begun.
1724e14a829129feee14ebe453f61a124784c870610Christopher Tate     * <p>
1734e14a829129feee14ebe453f61a124784c870610Christopher Tate     */
174181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    public void onCreate() {
175181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    }
176181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate
1774e14a829129feee14ebe453f61a124784c870610Christopher Tate    /**
1784e14a829129feee14ebe453f61a124784c870610Christopher Tate     * Provided as a convenience for agent implementations that need to do some
1794e14a829129feee14ebe453f61a124784c870610Christopher Tate     * sort of shutdown process after backup or restore is completed.
1804e14a829129feee14ebe453f61a124784c870610Christopher Tate     * <p>
1814e14a829129feee14ebe453f61a124784c870610Christopher Tate     * Agents do not need to override this method.
1824e14a829129feee14ebe453f61a124784c870610Christopher Tate     */
183181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    public void onDestroy() {
184181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    }
185487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
186487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate    /**
1875a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * The application is being asked to write any data changed since the last
1885a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * time it performed a backup operation. The state data recorded during the
1895a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * last backup pass is provided in the <code>oldState</code> file
1905a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * descriptor. If <code>oldState</code> is <code>null</code>, no old state
1915a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * is available and the application should perform a full backup. In both
1925a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * cases, a representation of the final backup state after this pass should
1935a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * be written to the file pointed to by the file descriptor wrapped in
1945a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * <code>newState</code>.
1954e14a829129feee14ebe453f61a124784c870610Christopher Tate     * <p>
1964e14a829129feee14ebe453f61a124784c870610Christopher Tate     * Each entity written to the {@link android.app.backup.BackupDataOutput}
1974e14a829129feee14ebe453f61a124784c870610Christopher Tate     * <code>data</code> stream will be transmitted
1984e14a829129feee14ebe453f61a124784c870610Christopher Tate     * over the current backup transport and stored in the remote data set under
1994e14a829129feee14ebe453f61a124784c870610Christopher Tate     * the key supplied as part of the entity.  Writing an entity with a negative
2004e14a829129feee14ebe453f61a124784c870610Christopher Tate     * data size instructs the transport to delete whatever entity currently exists
2014e14a829129feee14ebe453f61a124784c870610Christopher Tate     * under that key from the remote data set.
20234385d352da19805ae948215e2edbeedd16b7941Elliott Hughes     *
2035a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * @param oldState An open, read-only ParcelFileDescriptor pointing to the
2045a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            last backup state provided by the application. May be
2055a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            <code>null</code>, in which case no prior state is being
2065a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            provided and the application should perform a full backup.
2075a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * @param data A structured wrapper around an open, read/write
2084e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            file descriptor pointing to the backup data destination.
2095a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            Typically the application will use backup helper classes to
2105a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            write to this file.
2115a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * @param newState An open, read/write ParcelFileDescriptor pointing to an
2125a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            empty file. The application should record the final backup
2134e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            state here after writing the requested data to the <code>data</code>
2144e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            output stream.
215487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate     */
216290bb011c5c1a9ba1f2116810b06cf52a9c36b3eJoe Onorato    public abstract void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
2172e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate            ParcelFileDescriptor newState) throws IOException;
2185a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root
219487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate    /**
2205a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * The application is being restored from backup and should replace any
2215a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * existing data with the contents of the backup. The backup data is
2224e14a829129feee14ebe453f61a124784c870610Christopher Tate     * provided through the <code>data</code> parameter. Once
2235a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * the restore is finished, the application should write a representation of
2245a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * the final state to the <code>newState</code> file descriptor.
2255a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * <p>
2265a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * The application is responsible for properly erasing its old data and
2275a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * replacing it with the data supplied to this method. No "clear user data"
2285a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * operation will be performed automatically by the operating system. The
2295a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * exception to this is in the case of a failed restore attempt: if
2305a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * onRestore() throws an exception, the OS will assume that the
2315a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * application's data may now be in an incoherent state, and will clear it
2325a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * before proceeding.
23334385d352da19805ae948215e2edbeedd16b7941Elliott Hughes     *
2345a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * @param data A structured wrapper around an open, read-only
2354e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            file descriptor pointing to a full snapshot of the
2364e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            application's data.  The application should consume every
2374e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            entity represented in this data stream.
238b83a283ac178ab0a72f1d811189d79b26097835eScott Main     * @param appVersionCode The value of the <a
239b83a283ac178ab0a72f1d811189d79b26097835eScott Main     * href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code
240b83a283ac178ab0a72f1d811189d79b26097835eScott Main     *            android:versionCode}</a> manifest attribute,
241b83a283ac178ab0a72f1d811189d79b26097835eScott Main     *            from the application that backed up this particular data set. This
2424e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            makes it possible for an application's agent to distinguish among any
2435a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            possible older data versions when asked to perform the restore
2445a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            operation.
2455a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     * @param newState An open, read/write ParcelFileDescriptor pointing to an
2465a20ea16d7e5b70dc7bad8700f54170e4f220d12Kenny Root     *            empty file. The application should record the final backup
2474e14a829129feee14ebe453f61a124784c870610Christopher Tate     *            state here after restoring its data from the <code>data</code> stream.
2484a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate     *            When a full-backup dataset is being restored, this will be <code>null</code>.
249487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate     */
2505cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate    public abstract void onRestore(BackupDataInput data, int appVersionCode,
2512e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate            ParcelFileDescriptor newState) throws IOException;
252487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
2534a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate    /**
254a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * The application is having its entire file system contents backed up.  {@code data}
255a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * points to the backup destination, and the app has the opportunity to choose which
256a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * files are to be stored.  To commit a file as part of the backup, call the
257a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * {@link #fullBackupFile(File, FullBackupDataOutput)} helper method.  After all file
258a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * data is written to the output, the agent returns from this method and the backup
259a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * operation concludes.
260a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     *
261a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * <p>Certain parts of the app's data are never backed up even if the app explicitly
262a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * sends them to the output:
263a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     *
264a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * <ul>
265a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * <li>The contents of the {@link #getCacheDir()} directory</li>
266a8a739f34c4d9c56b113810582801f36381cbc77Christopher Tate     * <li>The contents of the {@link #getCodeCacheDir()} directory</li>
267a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * <li>The contents of the {@link #getNoBackupFilesDir()} directory</li>
268a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * <li>The contents of the app's shared library directory</li>
269a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * </ul>
270a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     *
271a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * <p>The default implementation of this method backs up the entirety of the
272a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * application's "owned" file system trees to the output other than the few exceptions
273a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * listed above.  Apps only need to override this method if they need to impose special
274a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * limitations on which files are being stored beyond the control that
275a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * {@link #getNoBackupFilesDir()} offers.
276303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams     * Alternatively they can provide an xml resource to specify what data to include or exclude.
277303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams     *
278a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     *
279a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * @param data A structured wrapper pointing to the backup destination.
280a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * @throws IOException
281a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     *
282a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * @see Context#getNoBackupFilesDir()
283303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams     * @see ApplicationInfo#fullBackupContent
284a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * @see #fullBackupFile(File, FullBackupDataOutput)
285a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     * @see #onRestoreFile(ParcelFileDescriptor, long, File, int, long, long)
28679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     */
28779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    public void onFullBackup(FullBackupDataOutput data) throws IOException {
288303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        FullBackup.BackupScheme backupScheme = FullBackup.getBackupScheme(this);
289303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        if (!backupScheme.isFullBackupContentEnabled()) {
290303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            return;
291303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        }
292303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams
293303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        Map<String, Set<String>> manifestIncludeMap;
294303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        ArraySet<String> manifestExcludeSet;
295303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        try {
296303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            manifestIncludeMap =
297303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    backupScheme.maybeParseAndGetCanonicalIncludePaths();
298303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            manifestExcludeSet = backupScheme.maybeParseAndGetCanonicalExcludePaths();
299303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        } catch (IOException | XmlPullParserException e) {
300303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
301303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                Log.v(FullBackup.TAG_XML_PARSER,
302303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                        "Exception trying to parse fullBackupContent xml file!"
303303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                                + " Aborting full backup.", e);
304303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            }
305303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            return;
306303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        }
307303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams
308303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        final String packageName = getPackageName();
309303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        final ApplicationInfo appInfo = getApplicationInfo();
31079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
3112c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        // System apps have control over where their default storage context
3122c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        // is pointed, so we're always explicit when building paths.
3138a372a0a280127743ce9a7ce4b6198c7a02d2a4fJeff Sharkey        final Context ceContext = createCredentialProtectedStorageContext();
3142c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String rootDir = ceContext.getDataDir().getCanonicalPath();
3152c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String filesDir = ceContext.getFilesDir().getCanonicalPath();
3162c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String noBackupDir = ceContext.getNoBackupFilesDir().getCanonicalPath();
3172c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String databaseDir = ceContext.getDatabasePath("foo").getParentFile()
3182c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                .getCanonicalPath();
3192c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String sharedPrefsDir = ceContext.getSharedPreferencesPath("foo").getParentFile()
3202c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                .getCanonicalPath();
3212c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String cacheDir = ceContext.getCacheDir().getCanonicalPath();
3222c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String codeCacheDir = ceContext.getCodeCacheDir().getCanonicalPath();
3232c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey
3248a372a0a280127743ce9a7ce4b6198c7a02d2a4fJeff Sharkey        final Context deContext = createDeviceProtectedStorageContext();
3252c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String deviceRootDir = deContext.getDataDir().getCanonicalPath();
3262c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String deviceFilesDir = deContext.getFilesDir().getCanonicalPath();
3272c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String deviceNoBackupDir = deContext.getNoBackupFilesDir().getCanonicalPath();
3282c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String deviceDatabaseDir = deContext.getDatabasePath("foo").getParentFile()
3292c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                .getCanonicalPath();
3302c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String deviceSharedPrefsDir = deContext.getSharedPreferencesPath("foo")
3312c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                .getParentFile().getCanonicalPath();
3322c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String deviceCacheDir = deContext.getCacheDir().getCanonicalPath();
3332c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String deviceCodeCacheDir = deContext.getCodeCacheDir().getCanonicalPath();
3342c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey
3352c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String libDir = (appInfo.nativeLibraryDir != null)
3362efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                ? new File(appInfo.nativeLibraryDir).getCanonicalPath()
33779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                : null;
33879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
339303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        // Maintain a set of excluded directories so that as we traverse the tree we know we're not
340303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        // going places we don't expect, and so the manifest includes can't take precedence over
341303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        // what the framework decides is not to be included.
342303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        final ArraySet<String> traversalExcludeSet = new ArraySet<String>();
34379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
344303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        // Add the directories we always exclude.
3452c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.add(filesDir);
3462c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.add(noBackupDir);
3472c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.add(databaseDir);
3482c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.add(sharedPrefsDir);
349303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        traversalExcludeSet.add(cacheDir);
350303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        traversalExcludeSet.add(codeCacheDir);
3512c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey
3522c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.add(deviceFilesDir);
3532c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.add(deviceNoBackupDir);
3542c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.add(deviceDatabaseDir);
3552c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.add(deviceSharedPrefsDir);
3562c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.add(deviceCacheDir);
3572c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.add(deviceCodeCacheDir);
3582c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey
35979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        if (libDir != null) {
360303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            traversalExcludeSet.add(libDir);
36179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        }
362303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams
363303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        // Root dir first.
364303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        applyXmlFiltersAndDoFullBackupForDomain(
365303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                packageName, FullBackup.ROOT_TREE_TOKEN, manifestIncludeMap,
366303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                manifestExcludeSet, traversalExcludeSet, data);
367303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        traversalExcludeSet.add(rootDir);
368303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams
3692c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        applyXmlFiltersAndDoFullBackupForDomain(
3702c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                packageName, FullBackup.DEVICE_ROOT_TREE_TOKEN, manifestIncludeMap,
3712c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                manifestExcludeSet, traversalExcludeSet, data);
3722c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.add(deviceRootDir);
3732c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey
374303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        // Data dir next.
375303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        traversalExcludeSet.remove(filesDir);
376303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        applyXmlFiltersAndDoFullBackupForDomain(
3772c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                packageName, FullBackup.FILES_TREE_TOKEN, manifestIncludeMap,
378303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                manifestExcludeSet, traversalExcludeSet, data);
379303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        traversalExcludeSet.add(filesDir);
380303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams
3812c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.remove(deviceFilesDir);
3822c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        applyXmlFiltersAndDoFullBackupForDomain(
3832c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                packageName, FullBackup.DEVICE_FILES_TREE_TOKEN, manifestIncludeMap,
3842c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                manifestExcludeSet, traversalExcludeSet, data);
3852c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.add(deviceFilesDir);
3862c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey
387303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        // Database directory.
388303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        traversalExcludeSet.remove(databaseDir);
389303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        applyXmlFiltersAndDoFullBackupForDomain(
390303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                packageName, FullBackup.DATABASE_TREE_TOKEN, manifestIncludeMap,
391303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                manifestExcludeSet, traversalExcludeSet, data);
392303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        traversalExcludeSet.add(databaseDir);
393303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams
3942c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.remove(deviceDatabaseDir);
3952c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        applyXmlFiltersAndDoFullBackupForDomain(
3962c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                packageName, FullBackup.DEVICE_DATABASE_TREE_TOKEN, manifestIncludeMap,
3972c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                manifestExcludeSet, traversalExcludeSet, data);
3982c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.add(deviceDatabaseDir);
3992c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey
400303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        // SharedPrefs.
401303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        traversalExcludeSet.remove(sharedPrefsDir);
402303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        applyXmlFiltersAndDoFullBackupForDomain(
403303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                packageName, FullBackup.SHAREDPREFS_TREE_TOKEN, manifestIncludeMap,
404303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                manifestExcludeSet, traversalExcludeSet, data);
405303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        traversalExcludeSet.add(sharedPrefsDir);
406416c39e8d48048fa4a997c09460c262cca871fc4Christopher Tate
4072c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.remove(deviceSharedPrefsDir);
4082c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        applyXmlFiltersAndDoFullBackupForDomain(
4092c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                packageName, FullBackup.DEVICE_SHAREDPREFS_TREE_TOKEN, manifestIncludeMap,
4102c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                manifestExcludeSet, traversalExcludeSet, data);
4112c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        traversalExcludeSet.add(deviceSharedPrefsDir);
4122c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey
413416c39e8d48048fa4a997c09460c262cca871fc4Christopher Tate        // getExternalFilesDir() location associated with this app.  Technically there should
414416c39e8d48048fa4a997c09460c262cca871fc4Christopher Tate        // not be any files here if the app does not properly have permission to access
415416c39e8d48048fa4a997c09460c262cca871fc4Christopher Tate        // external storage, but edge cases happen. fullBackupFileTree() catches
4165cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate        // IOExceptions and similar, and treats them as non-fatal, so we rely on that; and
4175cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate        // we know a priori that processes running as the system UID are not permitted to
4185cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate        // access external storage, so we check for that as well to avoid nastygrams in
4195cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate        // the log.
4205cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate        if (Process.myUid() != Process.SYSTEM_UID) {
4215cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate            File efLocation = getExternalFilesDir(null);
4225cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate            if (efLocation != null) {
423303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                applyXmlFiltersAndDoFullBackupForDomain(
424303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                        packageName, FullBackup.MANAGED_EXTERNAL_TREE_TOKEN, manifestIncludeMap,
425303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                        manifestExcludeSet, traversalExcludeSet, data);
426303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            }
427303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams
428303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        }
429303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams    }
430303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams
431303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams    /**
432d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * Notification that the application's current backup operation causes it to exceed
433d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * the maximum size permitted by the transport.  The ongoing backup operation is
434d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * halted and rolled back: any data that had been stored by a previous backup operation
435d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * is still intact.  Typically the quota-exceeded state will be detected before any data
436d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * is actually transmitted over the network.
437872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov     *
438d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * <p>The {@code quotaBytes} value is the total data size currently permitted for this
439d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * application.  If desired, the application can use this as a hint for determining
440d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * how much data to store.  For example, a messaging application might choose to
441d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * store only the newest messages, dropping enough older content to stay under
442d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * the quota.
443d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     *
444d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * <p class="note">Note that the maximum quota for the application can change over
445d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * time.  In particular, in the future the quota may grow.  Applications that adapt
446d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * to the quota when deciding what data to store should be aware of this and implement
447d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * their data storage mechanisms in a way that can take advantage of additional
448d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * quota.
449d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     *
450d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * @param backupDataBytes The amount of data measured while initializing the backup
451d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     *    operation, if the total exceeds the app's alloted quota.  If initial measurement
452d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     *    suggested that the data would fit but then too much data was actually submitted
453d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     *    as part of the operation, then this value is the amount of data that had been
454d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     *    streamed into the transport at the time the quota was reached.
455d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     * @param quotaBytes The maximum data size that the transport currently permits
456d43879c5e42b715576761f48503bae9313e47ffcChristopher Tate     *    this application to store as a backup.
457872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov     */
458872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov    public void onQuotaExceeded(long backupDataBytes, long quotaBytes) {
459872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov    }
460872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov
461872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov    /**
462303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams     * Check whether the xml yielded any <include/> tag for the provided <code>domainToken</code>.
463303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams     * If so, perform a {@link #fullBackupFileTree} which backs up the file or recurses if the path
464303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams     * is a directory.
465303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams     */
466303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams    private void applyXmlFiltersAndDoFullBackupForDomain(String packageName, String domainToken,
467303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                                                         Map<String, Set<String>> includeMap,
468303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                                                         ArraySet<String> filterSet,
469303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                                                         ArraySet<String> traversalExcludeSet,
470303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                                                         FullBackupDataOutput data)
471303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            throws IOException {
472303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        if (includeMap == null || includeMap.size() == 0) {
473303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            // Do entire sub-tree for the provided token.
474303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            fullBackupFileTree(packageName, domainToken,
475303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    FullBackup.getBackupScheme(this).tokenToDirectoryPath(domainToken),
476303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    filterSet, traversalExcludeSet, data);
477303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        } else if (includeMap.get(domainToken) != null) {
478303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            // This will be null if the xml parsing didn't yield any rules for
479303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            // this domain (there may still be rules for other domains).
480303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            for (String includeFile : includeMap.get(domainToken)) {
481303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                fullBackupFileTree(packageName, domainToken, includeFile, filterSet,
482303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                        traversalExcludeSet, data);
4835cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate            }
4845cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate        }
48579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    }
48679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
48779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /**
48879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * Write an entire file as part of a full-backup operation.  The file's contents
48979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * will be delivered to the backup destination along with the metadata necessary
49079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * to place it with the proper location and permissions on the device where the
49179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * data is restored.
49279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *
493c5be8f8a4b9946f26f43201a06e7ec3f9b34857eChristopher Tate     * <p class="note">Attempting to back up files in directories that are ignored by
494c5be8f8a4b9946f26f43201a06e7ec3f9b34857eChristopher Tate     * the backup system will have no effect.  For example, if the app calls this method
495c5be8f8a4b9946f26f43201a06e7ec3f9b34857eChristopher Tate     * with a file inside the {@link #getNoBackupFilesDir()} directory, it will be ignored.
49654de77470de4f605eef7f4b4e01718b301fe275eElliot Waite     * See {@link #onFullBackup(FullBackupDataOutput)} for details on what directories
497c5be8f8a4b9946f26f43201a06e7ec3f9b34857eChristopher Tate     * are excluded from backups.
498a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate     *
49979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param file The file to be backed up.  The file must exist and be readable by
50079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *     the caller.
50179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param output The destination to which the backed-up file data will be sent.
50279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     */
50379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    public final void fullBackupFile(File file, FullBackupDataOutput output) {
50479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        // Look up where all of our various well-defined dir trees live on this device
5052c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String rootDir;
5062c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String filesDir;
5072c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String nbFilesDir;
5082c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String dbDir;
5092c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String spDir;
5102c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String cacheDir;
5112c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String codeCacheDir;
5122c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String deviceRootDir;
5132c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String deviceFilesDir;
5142c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String deviceNbFilesDir;
5152c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String deviceDbDir;
5162c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String deviceSpDir;
5172c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String deviceCacheDir;
5182c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String deviceCodeCacheDir;
5192c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        final String libDir;
5202c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey
5215cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate        String efDir = null;
5222efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate        String filePath;
52379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
52479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        ApplicationInfo appInfo = getApplicationInfo();
52579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
5262efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate        try {
5272c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            // System apps have control over where their default storage context
5282c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            // is pointed, so we're always explicit when building paths.
5298a372a0a280127743ce9a7ce4b6198c7a02d2a4fJeff Sharkey            final Context ceContext = createCredentialProtectedStorageContext();
5302c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            rootDir = ceContext.getDataDir().getCanonicalPath();
5312c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            filesDir = ceContext.getFilesDir().getCanonicalPath();
5322c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            nbFilesDir = ceContext.getNoBackupFilesDir().getCanonicalPath();
5332c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            dbDir = ceContext.getDatabasePath("foo").getParentFile().getCanonicalPath();
5342c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            spDir = ceContext.getSharedPreferencesPath("foo").getParentFile().getCanonicalPath();
5352c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            cacheDir = ceContext.getCacheDir().getCanonicalPath();
5362c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            codeCacheDir = ceContext.getCodeCacheDir().getCanonicalPath();
5372c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey
5388a372a0a280127743ce9a7ce4b6198c7a02d2a4fJeff Sharkey            final Context deContext = createDeviceProtectedStorageContext();
5392c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            deviceRootDir = deContext.getDataDir().getCanonicalPath();
5402c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            deviceFilesDir = deContext.getFilesDir().getCanonicalPath();
5412c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            deviceNbFilesDir = deContext.getNoBackupFilesDir().getCanonicalPath();
5422c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            deviceDbDir = deContext.getDatabasePath("foo").getParentFile().getCanonicalPath();
5432c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            deviceSpDir = deContext.getSharedPreferencesPath("foo").getParentFile()
5442c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                    .getCanonicalPath();
5452c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            deviceCacheDir = deContext.getCacheDir().getCanonicalPath();
5462c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            deviceCodeCacheDir = deContext.getCodeCacheDir().getCanonicalPath();
5472c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey
5482efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            libDir = (appInfo.nativeLibraryDir == null)
5492efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    ? null
5502efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    : new File(appInfo.nativeLibraryDir).getCanonicalPath();
5515cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate
5525cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate            // may or may not have external files access to attempt backup/restore there
5535cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate            if (Process.myUid() != Process.SYSTEM_UID) {
5545cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate                File efLocation = getExternalFilesDir(null);
5555cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate                if (efLocation != null) {
5565cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate                    efDir = efLocation.getCanonicalPath();
5575cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate                }
5585cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate            }
5592efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate
5602efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            // Now figure out which well-defined tree the file is placed in, working from
561a8a739f34c4d9c56b113810582801f36381cbc77Christopher Tate            // most to least specific.  We also specifically exclude the lib, cache,
562a8a739f34c4d9c56b113810582801f36381cbc77Christopher Tate            // and code_cache dirs.
5632efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            filePath = file.getCanonicalPath();
5642efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate        } catch (IOException e) {
5652efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            Log.w(TAG, "Unable to obtain canonical paths");
5662efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate            return;
5672efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate        }
56879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
569a7835b6b6b00923b608a6bc3194e7840f67de7a8Christopher Tate        if (filePath.startsWith(cacheDir)
570a8a739f34c4d9c56b113810582801f36381cbc77Christopher Tate                || filePath.startsWith(codeCacheDir)
5712c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                || filePath.startsWith(nbFilesDir)
5722c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                || filePath.startsWith(deviceCacheDir)
5732c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                || filePath.startsWith(deviceCodeCacheDir)
5742c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                || filePath.startsWith(deviceNbFilesDir)
5752c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey                || filePath.startsWith(libDir)) {
576a8a739f34c4d9c56b113810582801f36381cbc77Christopher Tate            Log.w(TAG, "lib, cache, code_cache, and no_backup files are not backed up");
57779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            return;
57879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        }
57979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
58079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        final String domain;
58179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        String rootpath = null;
58279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        if (filePath.startsWith(dbDir)) {
58379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            domain = FullBackup.DATABASE_TREE_TOKEN;
58479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            rootpath = dbDir;
58579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        } else if (filePath.startsWith(spDir)) {
58679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            domain = FullBackup.SHAREDPREFS_TREE_TOKEN;
58779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            rootpath = spDir;
58879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        } else if (filePath.startsWith(filesDir)) {
5892c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            domain = FullBackup.FILES_TREE_TOKEN;
59079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            rootpath = filesDir;
5912c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        } else if (filePath.startsWith(rootDir)) {
59279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            domain = FullBackup.ROOT_TREE_TOKEN;
5932c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            rootpath = rootDir;
5942c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        } else if (filePath.startsWith(deviceDbDir)) {
5952c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            domain = FullBackup.DEVICE_DATABASE_TREE_TOKEN;
5962c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            rootpath = deviceDbDir;
5972c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        } else if (filePath.startsWith(deviceSpDir)) {
5982c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            domain = FullBackup.DEVICE_SHAREDPREFS_TREE_TOKEN;
5992c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            rootpath = deviceSpDir;
6002c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        } else if (filePath.startsWith(deviceFilesDir)) {
6012c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            domain = FullBackup.DEVICE_FILES_TREE_TOKEN;
6022c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            rootpath = deviceFilesDir;
6032c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey        } else if (filePath.startsWith(deviceRootDir)) {
6042c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            domain = FullBackup.DEVICE_ROOT_TREE_TOKEN;
6052c1ba9a961d4f96c26df260ee437655ad9e7c03eJeff Sharkey            rootpath = deviceRootDir;
6065cb5c337d5fe523723b8e5ceb4bdf38dff0cec70Christopher Tate        } else if ((efDir != null) && filePath.startsWith(efDir)) {
607416c39e8d48048fa4a997c09460c262cca871fc4Christopher Tate            domain = FullBackup.MANAGED_EXTERNAL_TREE_TOKEN;
608416c39e8d48048fa4a997c09460c262cca871fc4Christopher Tate            rootpath = efDir;
60979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        } else {
61079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            Log.w(TAG, "File " + filePath + " is in an unsupported location; skipping");
61179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            return;
61279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        }
61379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
61479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        // And now that we know where it lives, semantically, back it up appropriately
61511ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate        // In the measurement case, backupToTar() updates the size in output and returns
61611ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate        // without transmitting any file data.
61711ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate        if (DEBUG) Log.i(TAG, "backupFile() of " + filePath + " => domain=" + domain
61879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                + " rootpath=" + rootpath);
619303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams
62011ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate        FullBackup.backupToTar(getPackageName(), domain, null, rootpath, filePath, output);
62179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    }
62279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
62379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /**
62479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * Scan the dir tree (if it actually exists) and process each entry we find.  If the
625303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams     * 'excludes' parameters are non-null, they are consulted each time a new file system entity
62679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * is visited to see whether that entity (and its subtree, if appropriate) should be
62779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * omitted from the backup process.
62879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *
629303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams     * @param systemExcludes An optional list of excludes.
63079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @hide
63179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     */
632303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams    protected final void fullBackupFileTree(String packageName, String domain, String startingPath,
633303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                                            ArraySet<String> manifestExcludes,
634303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                                            ArraySet<String> systemExcludes,
635303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            FullBackupDataOutput output) {
636303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        // Pull out the domain and set it aside to use when making the tarball.
637303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        String domainPath = FullBackup.getBackupScheme(this).tokenToDirectoryPath(domain);
638303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        if (domainPath == null) {
639303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            // Should never happen.
640303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            return;
641303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        }
642303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams
643303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        File rootFile = new File(startingPath);
64479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        if (rootFile.exists()) {
64579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            LinkedList<File> scanQueue = new LinkedList<File>();
64679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            scanQueue.add(rootFile);
64779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
64879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            while (scanQueue.size() > 0) {
64979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                File file = scanQueue.remove(0);
6502efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                String filePath;
6512efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                try {
652da2018efeb4388d43deb378e9b56029606cdd3bcChristopher Tate                    // Ignore things that aren't "real" files or dirs
65385192a1b478b79905d16a285d559f8e3f05c6135Christopher Tate                    StructStat stat = Os.lstat(file.getPath());
654da2018efeb4388d43deb378e9b56029606cdd3bcChristopher Tate                    if (!OsConstants.S_ISREG(stat.st_mode)
655da2018efeb4388d43deb378e9b56029606cdd3bcChristopher Tate                            && !OsConstants.S_ISDIR(stat.st_mode)) {
656da2018efeb4388d43deb378e9b56029606cdd3bcChristopher Tate                        if (DEBUG) Log.i(TAG, "Not a file/dir (skipping)!: " + file);
65785192a1b478b79905d16a285d559f8e3f05c6135Christopher Tate                        continue;
65885192a1b478b79905d16a285d559f8e3f05c6135Christopher Tate                    }
65985192a1b478b79905d16a285d559f8e3f05c6135Christopher Tate
66085192a1b478b79905d16a285d559f8e3f05c6135Christopher Tate                    // For all other verification, look at the canonicalized path
6612efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    filePath = file.getCanonicalPath();
66279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
6632efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    // prune this subtree?
664303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    if (manifestExcludes != null && manifestExcludes.contains(filePath)) {
665303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                        continue;
666303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    }
667303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    if (systemExcludes != null && systemExcludes.contains(filePath)) {
6682efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                        continue;
6692efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    }
67079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
6712efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    // If it's a directory, enqueue its contents for scanning.
67285192a1b478b79905d16a285d559f8e3f05c6135Christopher Tate                    if (OsConstants.S_ISDIR(stat.st_mode)) {
67379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                        File[] contents = file.listFiles();
67479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                        if (contents != null) {
67579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                            for (File entry : contents) {
67679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                                scanQueue.add(0, entry);
67779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                            }
67879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                        }
67979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                    }
6802efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                } catch (IOException e) {
6812efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    if (DEBUG) Log.w(TAG, "Error canonicalizing path of " + file);
682303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
683303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                        Log.v(FullBackup.TAG_XML_PARSER, "Error canonicalizing path of " + file);
684303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    }
6852efd2dbbac9eac89620683696c6076463c3a1cd6Christopher Tate                    continue;
68679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                } catch (ErrnoException e) {
68779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                    if (DEBUG) Log.w(TAG, "Error scanning file " + file + " : " + e);
688303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
689303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                        Log.v(FullBackup.TAG_XML_PARSER, "Error scanning file " + file + " : " + e);
690303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    }
69179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                    continue;
69279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                }
69379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
69411ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                // Finally, back this file up (or measure it) before proceeding
695303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                FullBackup.backupToTar(packageName, domain, null, domainPath, filePath, output);
69679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            }
69779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        }
69879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    }
69979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
70079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    /**
70179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * Handle the data delivered via the given file descriptor during a full restore
70279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * operation.  The agent is given the path to the file's original location as well
70379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * as its size and metadata.
70479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * <p>
70579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * The file descriptor can only be read for {@code size} bytes; attempting to read
70679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * more data has undefined behavior.
70779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * <p>
70879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * The default implementation creates the destination file/directory and populates it
70979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * with the data from the file descriptor, then sets the file's access mode and
71079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * modification time to match the restore arguments.
71179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *
71279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param data A read-only file descriptor from which the agent can read {@code size}
71379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *     bytes of file data.
71479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param size The number of bytes of file content to be restored to the given
71579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *     destination.  If the file system object being restored is a directory, {@code size}
71679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *     will be zero.
71779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param destination The File on disk to be restored with the given data.
71879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param type The kind of file system object being restored.  This will be either
71979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *     {@link BackupAgent#TYPE_FILE} or {@link BackupAgent#TYPE_DIRECTORY}.
72079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param mode The access mode to be assigned to the destination after its data is
72179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *     written.  This is in the standard format used by {@code chmod()}.
72279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @param mtime The modification time of the file when it was backed up, suitable to
72379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     *     be assigned to the file after its data is written.
72479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @throws IOException
72575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate     */
72675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    public void onRestoreFile(ParcelFileDescriptor data, long size,
72779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            File destination, int type, long mode, long mtime)
72875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            throws IOException {
729b9ebed56e48e91876215a5c51f4562f1c7b0e49bMatthew Williams
730b9ebed56e48e91876215a5c51f4562f1c7b0e49bMatthew Williams        final boolean accept = isFileEligibleForRestore(destination);
731b9ebed56e48e91876215a5c51f4562f1c7b0e49bMatthew Williams        // If we don't accept the file, consume the bytes from the pipe anyway.
732b9ebed56e48e91876215a5c51f4562f1c7b0e49bMatthew Williams        FullBackup.restoreFile(data, size, type, mode, mtime, accept ? destination : null);
733b9ebed56e48e91876215a5c51f4562f1c7b0e49bMatthew Williams    }
734b9ebed56e48e91876215a5c51f4562f1c7b0e49bMatthew Williams
735b9ebed56e48e91876215a5c51f4562f1c7b0e49bMatthew Williams    private boolean isFileEligibleForRestore(File destination) throws IOException {
736303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        FullBackup.BackupScheme bs = FullBackup.getBackupScheme(this);
737303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        if (!bs.isFullBackupContentEnabled()) {
738303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
739303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                Log.v(FullBackup.TAG_XML_PARSER,
740303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                        "onRestoreFile \"" + destination.getCanonicalPath()
741303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                                + "\" : fullBackupContent not enabled for " + getPackageName());
742303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            }
743b9ebed56e48e91876215a5c51f4562f1c7b0e49bMatthew Williams            return false;
744303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        }
745b9ebed56e48e91876215a5c51f4562f1c7b0e49bMatthew Williams
746303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        Map<String, Set<String>> includes = null;
747303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        ArraySet<String> excludes = null;
748303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        final String destinationCanonicalPath = destination.getCanonicalPath();
749303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        try {
750303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            includes = bs.maybeParseAndGetCanonicalIncludePaths();
751303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            excludes = bs.maybeParseAndGetCanonicalExcludePaths();
752303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        } catch (XmlPullParserException e) {
753303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
754303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                Log.v(FullBackup.TAG_XML_PARSER,
755303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                        "onRestoreFile \"" + destinationCanonicalPath
756303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                                + "\" : Exception trying to parse fullBackupContent xml file!"
757303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                                + " Aborting onRestoreFile.", e);
758303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            }
759b9ebed56e48e91876215a5c51f4562f1c7b0e49bMatthew Williams            return false;
760303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        }
761303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams
762303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        if (excludes != null &&
763303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                isFileSpecifiedInPathList(destination, excludes)) {
764303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
765303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                Log.v(FullBackup.TAG_XML_PARSER,
766303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                        "onRestoreFile: \"" + destinationCanonicalPath + "\": listed in"
767303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                                + " excludes; skipping.");
768303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            }
769b9ebed56e48e91876215a5c51f4562f1c7b0e49bMatthew Williams            return false;
770303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        }
771303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams
772303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        if (includes != null && !includes.isEmpty()) {
773303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            // Rather than figure out the <include/> domain based on the path (a lot of code, and
774303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            // it's a small list), we'll go through and look for it.
775303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            boolean explicitlyIncluded = false;
776303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            for (Set<String> domainIncludes : includes.values()) {
777303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                explicitlyIncluded |= isFileSpecifiedInPathList(destination, domainIncludes);
778303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                if (explicitlyIncluded) {
779303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    break;
780303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                }
781303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            }
782303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            if (!explicitlyIncluded) {
783303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
784303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    Log.v(FullBackup.TAG_XML_PARSER,
785303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                            "onRestoreFile: Trying to restore \""
786303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                                    + destinationCanonicalPath + "\" but it isn't specified"
787303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                                    + " in the included files; skipping.");
788303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                }
789b9ebed56e48e91876215a5c51f4562f1c7b0e49bMatthew Williams                return false;
790303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            }
791303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        }
792b9ebed56e48e91876215a5c51f4562f1c7b0e49bMatthew Williams        return true;
79375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    }
79475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
79575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate    /**
796303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams     * @return True if the provided file is either directly in the provided list, or the provided
797303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams     * file is within a directory in the list.
798303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams     */
799303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams    private boolean isFileSpecifiedInPathList(File file, Collection<String> canonicalPathList)
800303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            throws IOException {
801303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        for (String canonicalPath : canonicalPathList) {
802303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            File fileFromList = new File(canonicalPath);
803303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            if (fileFromList.isDirectory()) {
804303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                if (file.isDirectory()) {
805303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    // If they are both directories check exact equals.
806303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    return file.equals(fileFromList);
807303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                } else {
808303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    // O/w we have to check if the file is within the directory from the list.
809303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    return file.getCanonicalPath().startsWith(canonicalPath);
810303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                }
811303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            } else {
812303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                if (file.equals(fileFromList)) {
813303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    // Need to check the explicit "equals" so we don't end up with substrings.
814303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                    return true;
815303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams                }
816303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            }
817303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        }
818303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        return false;
819303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams    }
820303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams
821303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams    /**
82279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * Only specialized platform agents should overload this entry point to support
82379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * restores to crazy non-app locations.
82479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate     * @hide
8254a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate     */
82679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate    protected void onRestoreFile(ParcelFileDescriptor data, long size,
82779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            int type, String domain, String path, long mode, long mtime)
82879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            throws IOException {
82979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        String basePath = null;
83079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
83179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        if (DEBUG) Log.d(TAG, "onRestoreFile() size=" + size + " type=" + type
83279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                + " domain=" + domain + " relpath=" + path + " mode=" + mode
83379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                + " mtime=" + mtime);
83479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
835303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        basePath = FullBackup.getBackupScheme(this).tokenToDirectoryPath(domain);
836303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams        if (domain.equals(FullBackup.MANAGED_EXTERNAL_TREE_TOKEN)) {
837303650c9cdb7cec88e7ec20747b161d9fff10719Matthew Williams            mode = -1;  // < 0 is a token to skip attempting a chmod()
83879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        }
83979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
84079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        // Now that we've figured out where the data goes, send it on its way
84179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        if (basePath != null) {
8427323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate            // Canonicalize the nominal path and verify that it lies within the stated domain
84379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            File outFile = new File(basePath, path);
8447323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate            String outPath = outFile.getCanonicalPath();
8457323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate            if (outPath.startsWith(basePath + File.separatorChar)) {
8467323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate                if (DEBUG) Log.i(TAG, "[" + domain + " : " + path + "] mapped to " + outPath);
8477323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate                onRestoreFile(data, size, outFile, type, mode, mtime);
8487323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate                return;
8497323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate            } else {
8507323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate                // Attempt to restore to a path outside the file's nominal domain.
8517323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate                if (DEBUG) {
8527323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate                    Log.e(TAG, "Cross-domain restore attempt: " + outPath);
8537323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate                }
8547323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate            }
85579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        }
8567323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate
8577323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate        // Not a supported output location, or bad path:  we need to consume the data
8587323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate        // anyway, so just use the default "copy the data out" implementation
8597323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate        // with a null destination.
8607323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate        if (DEBUG) Log.i(TAG, "[ skipping file " + path + "]");
8617323765bbf13d9638cf2cc1e06113bffcdac46c4Christopher Tate        FullBackup.restoreFile(data, size, type, mode, mtime, null);
8624a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate    }
863487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
8642e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate    /**
8652e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate     * The application's restore operation has completed.  This method is called after
8662e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate     * all available data has been delivered to the application for restore (via either
8672e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate     * the {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} or
8682e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate     * {@link #onRestoreFile(ParcelFileDescriptor, long, File, int, long, long) onRestoreFile()}
8692e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate     * callbacks).  This provides the app with a stable end-of-restore opportunity to
8702e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate     * perform any appropriate post-processing on the data that was just delivered.
8712e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate     *
8722e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate     * @see #onRestore(BackupDataInput, int, ParcelFileDescriptor)
8732e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate     * @see #onRestoreFile(ParcelFileDescriptor, long, File, int, long, long)
8742e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate     */
8752e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate    public void onRestoreFinished() {
8762e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate    }
8772e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate
878487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate    // ----- Core implementation -----
87944a2790374bf27116cbd91060d4f096ca5999709Christopher Tate
88044a2790374bf27116cbd91060d4f096ca5999709Christopher Tate    /** @hide */
88144a2790374bf27116cbd91060d4f096ca5999709Christopher Tate    public final IBinder onBind() {
882181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate        return mBinder;
883487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate    }
884487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
885487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate    private final IBinder mBinder = new BackupServiceBinder().asBinder();
886487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
887181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    /** @hide */
888181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    public void attach(Context context) {
889181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate        attachBaseContext(context);
890181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    }
891181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate
892487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate    // ----- IBackupService binder interface -----
893181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate    private class BackupServiceBinder extends IBackupAgent.Stub {
894181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate        private static final String TAG = "BackupServiceBinder";
895181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate
89675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        @Override
89722b8787ed4be8d4b7ed5d54802f9913fedb41425Christopher Tate        public void doBackup(ParcelFileDescriptor oldState,
89822b8787ed4be8d4b7ed5d54802f9913fedb41425Christopher Tate                ParcelFileDescriptor data,
89944a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                ParcelFileDescriptor newState,
900b6e73c96705c83db1f45686f2cd735d06ceb468eShreyas Basarge                long quotaBytes, int token, IBackupManager callbackBinder) throws RemoteException {
9011902492420825874b12962a10712e653901d120dChristopher Tate            // Ensure that we're running with the app's normal permission level
90244a2790374bf27116cbd91060d4f096ca5999709Christopher Tate            long ident = Binder.clearCallingIdentity();
9031902492420825874b12962a10712e653901d120dChristopher Tate
904436344ae12c819f58306ceb94241a266141e1218Christopher Tate            if (DEBUG) Log.v(TAG, "doBackup() invoked");
905ee87b96ee572e7245cf7b791e30c51505a8ba2a2Christopher Tate            BackupDataOutput output = new BackupDataOutput(data.getFileDescriptor(), quotaBytes);
9064a627c71ff53a4fca1f961f4b1dcc0461df18a06Christopher Tate
907290bb011c5c1a9ba1f2116810b06cf52a9c36b3eJoe Onorato            try {
908181fafaf48208978b8ba2022683ffa78aaeddde1Christopher Tate                BackupAgent.this.onBackup(oldState, output, newState);
9094ababd922eac5931e0222862ff082dc29e012816Joe Onorato            } catch (IOException ex) {
9104ababd922eac5931e0222862ff082dc29e012816Joe Onorato                Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
9114ababd922eac5931e0222862ff082dc29e012816Joe Onorato                throw new RuntimeException(ex);
912290bb011c5c1a9ba1f2116810b06cf52a9c36b3eJoe Onorato            } catch (RuntimeException ex) {
91383248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato                Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
914290bb011c5c1a9ba1f2116810b06cf52a9c36b3eJoe Onorato                throw ex;
9151902492420825874b12962a10712e653901d120dChristopher Tate            } finally {
916f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate                // Ensure that any SharedPreferences writes have landed after the backup,
917f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate                // in case the app code has side effects (since apps cannot provide this
918f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate                // guarantee themselves).
919f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate                waitForSharedPrefs();
920f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate
92144a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                Binder.restoreCallingIdentity(ident);
92244a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                try {
92311ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                    callbackBinder.opComplete(token, 0);
92444a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                } catch (RemoteException e) {
92544a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                    // we'll time out anyway, so we're safe
92644a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                }
92791bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate
92891bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                // Don't close the fd out from under the system service if this was local
92991bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                if (Binder.getCallingPid() != Process.myPid()) {
93091bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                    IoUtils.closeQuietly(oldState);
93191bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                    IoUtils.closeQuietly(data);
93291bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                    IoUtils.closeQuietly(newState);
93391bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                }
934290bb011c5c1a9ba1f2116810b06cf52a9c36b3eJoe Onorato            }
935487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate        }
936487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate
93775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        @Override
9385cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate        public void doRestore(ParcelFileDescriptor data, int appVersionCode,
93944a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                ParcelFileDescriptor newState,
94044a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                int token, IBackupManager callbackBinder) throws RemoteException {
9411902492420825874b12962a10712e653901d120dChristopher Tate            // Ensure that we're running with the app's normal permission level
94244a2790374bf27116cbd91060d4f096ca5999709Christopher Tate            long ident = Binder.clearCallingIdentity();
9431902492420825874b12962a10712e653901d120dChristopher Tate
944436344ae12c819f58306ceb94241a266141e1218Christopher Tate            if (DEBUG) Log.v(TAG, "doRestore() invoked");
94583248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato            BackupDataInput input = new BackupDataInput(data.getFileDescriptor());
94683248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato            try {
9475cbbf5652a78902ac3382dc4a3583bc5b0351027Christopher Tate                BackupAgent.this.onRestore(input, appVersionCode, newState);
94883248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato            } catch (IOException ex) {
94983248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato                Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex);
95083248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato                throw new RuntimeException(ex);
95183248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato            } catch (RuntimeException ex) {
95283248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato                Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex);
95383248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato                throw ex;
9541902492420825874b12962a10712e653901d120dChristopher Tate            } finally {
955f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate                // Ensure that any side-effect SharedPreferences writes have landed
956f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate                waitForSharedPrefs();
957f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate
95844a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                Binder.restoreCallingIdentity(ident);
95944a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                try {
96011ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                    callbackBinder.opComplete(token, 0);
96179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                } catch (RemoteException e) {
96279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                    // we'll time out anyway, so we're safe
96379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                }
96491bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate
96591bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                if (Binder.getCallingPid() != Process.myPid()) {
96691bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                    IoUtils.closeQuietly(data);
96791bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                    IoUtils.closeQuietly(newState);
96891bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                }
96979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            }
97079ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        }
97179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
97279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        @Override
97379ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate        public void doFullBackup(ParcelFileDescriptor data,
974b6e73c96705c83db1f45686f2cd735d06ceb468eShreyas Basarge                long quotaBytes, int token, IBackupManager callbackBinder) {
97579ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            // Ensure that we're running with the app's normal permission level
97679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            long ident = Binder.clearCallingIdentity();
97779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
97879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            if (DEBUG) Log.v(TAG, "doFullBackup() invoked");
97979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate
980f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate            // Ensure that any SharedPreferences writes have landed *before*
981f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate            // we potentially try to back up the underlying files directly.
982f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate            waitForSharedPrefs();
983f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate
98479ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            try {
985ee87b96ee572e7245cf7b791e30c51505a8ba2a2Christopher Tate                BackupAgent.this.onFullBackup(new FullBackupDataOutput(data, quotaBytes));
98679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            } catch (IOException ex) {
98711ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                Log.d(TAG, "onFullBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
98879ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                throw new RuntimeException(ex);
98979ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            } catch (RuntimeException ex) {
99011ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                Log.d(TAG, "onFullBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
99179ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                throw ex;
99279ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate            } finally {
993f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate                // ... and then again after, as in the doBackup() case
994f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate                waitForSharedPrefs();
995f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate
9967926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                // Send the EOD marker indicating that there is no more data
9977926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                // forthcoming from this agent.
9987926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                try {
9997926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                    FileOutputStream out = new FileOutputStream(data.getFileDescriptor());
10007926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                    byte[] buf = new byte[4];
10017926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                    out.write(buf);
10027926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                } catch (IOException e) {
10037926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                    Log.e(TAG, "Unable to finalize backup stream!");
10047926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate                }
10057926a693c4a4f4d2a2d352343bca23e189c7420dChristopher Tate
100679ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                Binder.restoreCallingIdentity(ident);
100779ec80db70d788f35aa13346e4684ecbd401bd84Christopher Tate                try {
100811ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                    callbackBinder.opComplete(token, 0);
100944a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                } catch (RemoteException e) {
101044a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                    // we'll time out anyway, so we're safe
101144a2790374bf27116cbd91060d4f096ca5999709Christopher Tate                }
101291bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate
101391bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                if (Binder.getCallingPid() != Process.myPid()) {
101491bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                    IoUtils.closeQuietly(data);
101591bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                }
101683248c432ffe2e2a17abbc8e4960c26574b46bcaJoe Onorato            }
1017487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate        }
101875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate
1019b6e73c96705c83db1f45686f2cd735d06ceb468eShreyas Basarge        public void doMeasureFullBackup(long quotaBytes, int token, IBackupManager callbackBinder) {
102011ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate            // Ensure that we're running with the app's normal permission level
102111ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate            final long ident = Binder.clearCallingIdentity();
1022ee87b96ee572e7245cf7b791e30c51505a8ba2a2Christopher Tate            FullBackupDataOutput measureOutput = new FullBackupDataOutput(quotaBytes);
1023b6e73c96705c83db1f45686f2cd735d06ceb468eShreyas Basarge
102411ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate            waitForSharedPrefs();
102511ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate            try {
102611ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                BackupAgent.this.onFullBackup(measureOutput);
102711ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate            } catch (IOException ex) {
102811ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                Log.d(TAG, "onFullBackup[M] (" + BackupAgent.this.getClass().getName() + ") threw", ex);
102911ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                throw new RuntimeException(ex);
103011ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate            } catch (RuntimeException ex) {
103111ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                Log.d(TAG, "onFullBackup[M] (" + BackupAgent.this.getClass().getName() + ") threw", ex);
103211ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                throw ex;
103311ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate            } finally {
103411ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                Binder.restoreCallingIdentity(ident);
103511ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                try {
103611ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                    callbackBinder.opComplete(token, measureOutput.getSize());
103711ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                } catch (RemoteException e) {
103811ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                    // timeout, so we're safe
103911ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                }
104011ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate            }
104111ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate        }
104211ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate
104375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        @Override
104475a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        public void doRestoreFile(ParcelFileDescriptor data, long size,
104575a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                int type, String domain, String path, long mode, long mtime,
104675a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                int token, IBackupManager callbackBinder) throws RemoteException {
104775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            long ident = Binder.clearCallingIdentity();
104875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            try {
104975a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                BackupAgent.this.onRestoreFile(data, size, type, domain, path, mode, mtime);
105075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            } catch (IOException e) {
105111ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                Log.d(TAG, "onRestoreFile (" + BackupAgent.this.getClass().getName() + ") threw", e);
105275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                throw new RuntimeException(e);
105375a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            } finally {
1054f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate                // Ensure that any side-effect SharedPreferences writes have landed
1055f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate                waitForSharedPrefs();
1056f85f5b2125461ea664cf67a16d4608a5a9bf2f98Christopher Tate
105775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                Binder.restoreCallingIdentity(ident);
105875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                try {
105911ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                    callbackBinder.opComplete(token, 0);
106075a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                } catch (RemoteException e) {
106175a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                    // we'll time out anyway, so we're safe
106275a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate                }
106391bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate
106491bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                if (Binder.getCallingPid() != Process.myPid()) {
106591bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                    IoUtils.closeQuietly(data);
106691bb0e5cca2612545b3b046f5bb1b3bc747be8afChristopher Tate                }
106775a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate            }
106875a99709accef8cf221fd436d646727e7c8dd1f1Christopher Tate        }
1069cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate
1070cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate        @Override
10712e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate        public void doRestoreFinished(int token, IBackupManager callbackBinder) {
10722e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate            long ident = Binder.clearCallingIdentity();
10732e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate            try {
10742e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate                BackupAgent.this.onRestoreFinished();
107511ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate            } catch (Exception e) {
107611ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                Log.d(TAG, "onRestoreFinished (" + BackupAgent.this.getClass().getName() + ") threw", e);
107711ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                throw e;
10782e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate            } finally {
10792e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate                // Ensure that any side-effect SharedPreferences writes have landed
10802e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate                waitForSharedPrefs();
10812e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate
10822e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate                Binder.restoreCallingIdentity(ident);
10832e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate                try {
108411ae768cf1b8348e761ad9c09e98788da1e591b1Christopher Tate                    callbackBinder.opComplete(token, 0);
10852e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate                } catch (RemoteException e) {
10862e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate                    // we'll time out anyway, so we're safe
10872e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate                }
10882e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate            }
10892e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate        }
10902e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate
10912e40d115ca4332d88424d1b591fdd8d5f78d1831Christopher Tate        @Override
1092cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate        public void fail(String message) {
1093cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate            getHandler().post(new FailRunnable(message));
1094cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate        }
1095872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov
1096872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov        @Override
1097872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov        public void doQuotaExceeded(long backupDataBytes, long quotaBytes) {
1098872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov            long ident = Binder.clearCallingIdentity();
1099872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov            try {
1100872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov                BackupAgent.this.onQuotaExceeded(backupDataBytes, quotaBytes);
1101872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov            } catch (Exception e) {
1102872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov                Log.d(TAG, "onQuotaExceeded(" + BackupAgent.this.getClass().getName() + ") threw",
1103872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov                        e);
1104872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov                throw e;
1105872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov            } finally {
1106872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov                waitForSharedPrefs();
1107872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov                Binder.restoreCallingIdentity(ident);
1108872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov            }
1109872d3b6e19933af6fa9ae65214b9f6df04fc3222Sergey Poromov        }
1110cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate    }
1111cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate
1112cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate    static class FailRunnable implements Runnable {
1113cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate        private String mMessage;
1114cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate
1115cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate        FailRunnable(String message) {
1116cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate            mMessage = message;
1117cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate        }
1118cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate
1119cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate        @Override
1120cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate        public void run() {
1121cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate            throw new IllegalStateException(mMessage);
1122cba5941c6085dab1566bc047c1ea31f58a2dd4cfChristopher Tate        }
1123487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate    }
1124487529a70cd1479ae8d6bbfb356be7e72542c185Christopher Tate}
1125