BackupAgent.java revision 4528186e0d65fc68ef0dd1941aa2ac8aefcd55a3
1/* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.app.backup; 18 19import android.app.IBackupAgent; 20import android.app.backup.IBackupManager; 21import android.content.Context; 22import android.content.ContextWrapper; 23import android.os.Binder; 24import android.os.IBinder; 25import android.os.ParcelFileDescriptor; 26import android.os.RemoteException; 27import android.util.Log; 28 29import java.io.IOException; 30 31/** 32 * This is the central interface between an application and Android's settings 33 * backup mechanism. Any implementation of a backup agent should perform backup 34 * and restore actions in 35 * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor)} 36 * and {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor)} 37 * respectively. 38 * <p> 39 * A backup agent based on convenient helper classes is available in 40 * {@link android.app.backup.BackupHelperAgent} for less complex implementation 41 * requirements. 42 * <p> 43 * STOPSHIP write more documentation about the backup process here. 44 */ 45public abstract class BackupAgent extends ContextWrapper { 46 private static final String TAG = "BackupAgent"; 47 private static final boolean DEBUG = false; 48 49 public BackupAgent() { 50 super(null); 51 } 52 53 public void onCreate() { 54 } 55 56 public void onDestroy() { 57 } 58 59 /** 60 * The application is being asked to write any data changed since the last 61 * time it performed a backup operation. The state data recorded during the 62 * last backup pass is provided in the <code>oldState</code> file 63 * descriptor. If <code>oldState</code> is <code>null</code>, no old state 64 * is available and the application should perform a full backup. In both 65 * cases, a representation of the final backup state after this pass should 66 * be written to the file pointed to by the file descriptor wrapped in 67 * <code>newState</code>. 68 * 69 * @param oldState An open, read-only ParcelFileDescriptor pointing to the 70 * last backup state provided by the application. May be 71 * <code>null</code>, in which case no prior state is being 72 * provided and the application should perform a full backup. 73 * @param data A structured wrapper around an open, read/write 74 * ParcelFileDescriptor pointing to the backup data destination. 75 * Typically the application will use backup helper classes to 76 * write to this file. 77 * @param newState An open, read/write ParcelFileDescriptor pointing to an 78 * empty file. The application should record the final backup 79 * state here after writing the requested data to dataFd. 80 */ 81 public abstract void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 82 ParcelFileDescriptor newState) throws IOException; 83 84 /** 85 * The application is being restored from backup and should replace any 86 * existing data with the contents of the backup. The backup data is 87 * provided in the file descriptor pointed to by the 88 * {@link android.app.backup.BackupDataInput} instance <code>data</code>. Once 89 * the restore is finished, the application should write a representation of 90 * the final state to the <code>newState</code> file descriptor. 91 * <p> 92 * The application is responsible for properly erasing its old data and 93 * replacing it with the data supplied to this method. No "clear user data" 94 * operation will be performed automatically by the operating system. The 95 * exception to this is in the case of a failed restore attempt: if 96 * onRestore() throws an exception, the OS will assume that the 97 * application's data may now be in an incoherent state, and will clear it 98 * before proceeding. 99 * 100 * @param data A structured wrapper around an open, read-only 101 * ParcelFileDescriptor pointing to a full snapshot of the 102 * application's data. Typically the application will use helper 103 * classes to read this data. 104 * @param appVersionCode The android:versionCode value of the application 105 * that backed up this particular data set. This makes it easier 106 * for an application's agent to distinguish among several 107 * possible older data versions when asked to perform the restore 108 * operation. 109 * @param newState An open, read/write ParcelFileDescriptor pointing to an 110 * empty file. The application should record the final backup 111 * state here after restoring its data from dataFd. 112 */ 113 public abstract void onRestore(BackupDataInput data, int appVersionCode, 114 ParcelFileDescriptor newState) 115 throws IOException; 116 117 118 // ----- Core implementation ----- 119 120 /** @hide */ 121 public final IBinder onBind() { 122 return mBinder; 123 } 124 125 private final IBinder mBinder = new BackupServiceBinder().asBinder(); 126 127 /** @hide */ 128 public void attach(Context context) { 129 attachBaseContext(context); 130 } 131 132 // ----- IBackupService binder interface ----- 133 private class BackupServiceBinder extends IBackupAgent.Stub { 134 private static final String TAG = "BackupServiceBinder"; 135 136 public void doBackup(ParcelFileDescriptor oldState, 137 ParcelFileDescriptor data, 138 ParcelFileDescriptor newState, 139 int token, IBackupManager callbackBinder) throws RemoteException { 140 // Ensure that we're running with the app's normal permission level 141 long ident = Binder.clearCallingIdentity(); 142 143 if (DEBUG) Log.v(TAG, "doBackup() invoked"); 144 BackupDataOutput output = new BackupDataOutput(data.getFileDescriptor()); 145 try { 146 BackupAgent.this.onBackup(oldState, output, newState); 147 } catch (IOException ex) { 148 Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex); 149 throw new RuntimeException(ex); 150 } catch (RuntimeException ex) { 151 Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex); 152 throw ex; 153 } finally { 154 Binder.restoreCallingIdentity(ident); 155 try { 156 callbackBinder.opComplete(token); 157 } catch (RemoteException e) { 158 // we'll time out anyway, so we're safe 159 } 160 } 161 } 162 163 public void doRestore(ParcelFileDescriptor data, int appVersionCode, 164 ParcelFileDescriptor newState, 165 int token, IBackupManager callbackBinder) throws RemoteException { 166 // Ensure that we're running with the app's normal permission level 167 long ident = Binder.clearCallingIdentity(); 168 169 if (DEBUG) Log.v(TAG, "doRestore() invoked"); 170 BackupDataInput input = new BackupDataInput(data.getFileDescriptor()); 171 try { 172 BackupAgent.this.onRestore(input, appVersionCode, newState); 173 } catch (IOException ex) { 174 Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex); 175 throw new RuntimeException(ex); 176 } catch (RuntimeException ex) { 177 Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex); 178 throw ex; 179 } finally { 180 Binder.restoreCallingIdentity(ident); 181 try { 182 callbackBinder.opComplete(token); 183 } catch (RemoteException e) { 184 // we'll time out anyway, so we're safe 185 } 186 } 187 } 188 } 189} 190