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"><application></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