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