blob: cb4e0e7840031a2ee591a91c2b4cb3ec5bb4a185 [file] [log] [blame]
Christopher Tate487529a2009-04-29 14:03:25 -07001/*
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
Christopher Tate45281862010-03-05 15:46:30 -080017package android.app.backup;
Christopher Tate487529a2009-04-29 14:03:25 -070018
Christopher Tate181fafa2009-05-14 11:12:14 -070019import android.app.IBackupAgent;
Christopher Tate45281862010-03-05 15:46:30 -080020import android.app.backup.IBackupManager;
Christopher Tate181fafa2009-05-14 11:12:14 -070021import android.content.Context;
22import android.content.ContextWrapper;
Christopher Tate19024922010-01-22 16:39:53 -080023import android.os.Binder;
Christopher Tate487529a2009-04-29 14:03:25 -070024import android.os.IBinder;
Christopher Tate22b87872009-05-04 16:41:53 -070025import android.os.ParcelFileDescriptor;
Christopher Tate487529a2009-04-29 14:03:25 -070026import android.os.RemoteException;
27import android.util.Log;
28
Joe Onorato83248c42009-06-17 17:55:20 -070029import java.io.IOException;
30
Christopher Tate487529a2009-04-29 14:03:25 -070031/**
Scott Maind17da432010-04-29 21:42:58 -070032 * Provides the central interface between an
Christopher Tate4e14a822010-04-08 12:54:23 -070033 * application and Android's data backup infrastructure. An application that wishes
34 * to participate in the backup and restore mechanism will declare a subclass of
35 * {@link android.app.backup.BackupAgent}, implement the
Scott Maind17da432010-04-29 21:42:58 -070036 * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()}
37 * and {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} methods,
38 * and provide the name of its backup agent class in its {@code AndroidManifest.xml} file via
39 * the <code><a
40 * href="{@docRoot}guide/topics/manifest/application-element.html">&lt;application&gt;</a></code>
41 * tag's {@code android:backupAgent} attribute.
42 * <h3>Basic Operation</h3>
Kenny Root5a20ea12010-02-23 18:49:11 -080043 * <p>
Christopher Tate4e14a822010-04-08 12:54:23 -070044 * When the application makes changes to data that it wishes to keep backed up,
45 * it should call the
46 * {@link android.app.backup.BackupManager#dataChanged() BackupManager.dataChanged()} method.
Scott Maind17da432010-04-29 21:42:58 -070047 * This notifies the Android Backup Manager that the application needs an opportunity
48 * to update its backup image. The Backup Manager, in turn, schedules a
Christopher Tate4e14a822010-04-08 12:54:23 -070049 * backup pass to be performed at an opportune time.
50 * <p>
Scott Maind17da432010-04-29 21:42:58 -070051 * Restore operations are typically performed only when applications are first
Christopher Tate4e14a822010-04-08 12:54:23 -070052 * installed on a device. At that time, the operating system checks to see whether
Scott Maind17da432010-04-29 21:42:58 -070053 * there is a previously-saved data set available for the application being installed, and if so,
54 * begins an immediate restore pass to deliver the backup data as part of the installation
Christopher Tate4e14a822010-04-08 12:54:23 -070055 * process.
56 * <p>
Scott Maind17da432010-04-29 21:42:58 -070057 * When a backup or restore pass is run, the application's process is launched
58 * (if not already running), the manifest-declared backup agent class (in the {@code
59 * android:backupAgent} attribute) is instantiated within
60 * that process, and the agent's {@link #onCreate()} method is invoked. This prepares the
Christopher Tate4e14a822010-04-08 12:54:23 -070061 * agent instance to run the actual backup or restore logic. At this point the
62 * agent's
63 * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()} or
64 * {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()} method will be
65 * invoked as appropriate for the operation being performed.
66 * <p>
Scott Maind17da432010-04-29 21:42:58 -070067 * A backup data set consists of one or more "entities," flattened binary data
68 * records that are each identified with a key string unique within the data set. Adding a
69 * record to the active data set or updating an existing record is done by simply
Christopher Tate4e14a822010-04-08 12:54:23 -070070 * writing new entity data under the desired key. Deleting an entity from the data set
71 * is done by writing an entity under that key with header specifying a negative data
72 * size, and no actual entity data.
73 * <p>
74 * <b>Helper Classes</b>
75 * <p>
76 * An extensible agent based on convenient helper classes is available in
77 * {@link android.app.backup.BackupAgentHelper}. That class is particularly
78 * suited to handling of simple file or {@link android.content.SharedPreferences}
79 * backup and restore.
80 *
81 * @see android.app.backup.BackupManager
82 * @see android.app.backup.BackupAgentHelper
83 * @see android.app.backup.BackupDataInput
84 * @see android.app.backup.BackupDataOutput
Christopher Tate487529a2009-04-29 14:03:25 -070085 */
Christopher Tate181fafa2009-05-14 11:12:14 -070086public abstract class BackupAgent extends ContextWrapper {
Joe Onorato83248c42009-06-17 17:55:20 -070087 private static final String TAG = "BackupAgent";
Christopher Tate436344a2009-09-30 16:17:37 -070088 private static final boolean DEBUG = false;
Joe Onorato83248c42009-06-17 17:55:20 -070089
Christopher Tate181fafa2009-05-14 11:12:14 -070090 public BackupAgent() {
91 super(null);
92 }
Christopher Tate487529a2009-04-29 14:03:25 -070093
Christopher Tate4e14a822010-04-08 12:54:23 -070094 /**
95 * Provided as a convenience for agent implementations that need an opportunity
96 * to do one-time initialization before the actual backup or restore operation
97 * is begun.
98 * <p>
99 * Agents do not need to override this method.
100 */
Christopher Tate181fafa2009-05-14 11:12:14 -0700101 public void onCreate() {
102 }
103
Christopher Tate4e14a822010-04-08 12:54:23 -0700104 /**
105 * Provided as a convenience for agent implementations that need to do some
106 * sort of shutdown process after backup or restore is completed.
107 * <p>
108 * Agents do not need to override this method.
109 */
Christopher Tate181fafa2009-05-14 11:12:14 -0700110 public void onDestroy() {
111 }
Christopher Tate487529a2009-04-29 14:03:25 -0700112
113 /**
Kenny Root5a20ea12010-02-23 18:49:11 -0800114 * The application is being asked to write any data changed since the last
115 * time it performed a backup operation. The state data recorded during the
116 * last backup pass is provided in the <code>oldState</code> file
117 * descriptor. If <code>oldState</code> is <code>null</code>, no old state
118 * is available and the application should perform a full backup. In both
119 * cases, a representation of the final backup state after this pass should
120 * be written to the file pointed to by the file descriptor wrapped in
121 * <code>newState</code>.
Christopher Tate4e14a822010-04-08 12:54:23 -0700122 * <p>
123 * Each entity written to the {@link android.app.backup.BackupDataOutput}
124 * <code>data</code> stream will be transmitted
125 * over the current backup transport and stored in the remote data set under
126 * the key supplied as part of the entity. Writing an entity with a negative
127 * data size instructs the transport to delete whatever entity currently exists
128 * under that key from the remote data set.
Kenny Root5a20ea12010-02-23 18:49:11 -0800129 *
130 * @param oldState An open, read-only ParcelFileDescriptor pointing to the
131 * last backup state provided by the application. May be
132 * <code>null</code>, in which case no prior state is being
133 * provided and the application should perform a full backup.
134 * @param data A structured wrapper around an open, read/write
Christopher Tate4e14a822010-04-08 12:54:23 -0700135 * file descriptor pointing to the backup data destination.
Kenny Root5a20ea12010-02-23 18:49:11 -0800136 * Typically the application will use backup helper classes to
137 * write to this file.
138 * @param newState An open, read/write ParcelFileDescriptor pointing to an
139 * empty file. The application should record the final backup
Christopher Tate4e14a822010-04-08 12:54:23 -0700140 * state here after writing the requested data to the <code>data</code>
141 * output stream.
Christopher Tate487529a2009-04-29 14:03:25 -0700142 */
Joe Onorato290bb012009-05-13 18:57:29 -0400143 public abstract void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
Joe Onorato4ababd92009-06-25 18:29:18 -0400144 ParcelFileDescriptor newState) throws IOException;
Kenny Root5a20ea12010-02-23 18:49:11 -0800145
Christopher Tate487529a2009-04-29 14:03:25 -0700146 /**
Kenny Root5a20ea12010-02-23 18:49:11 -0800147 * The application is being restored from backup and should replace any
148 * existing data with the contents of the backup. The backup data is
Christopher Tate4e14a822010-04-08 12:54:23 -0700149 * provided through the <code>data</code> parameter. Once
Kenny Root5a20ea12010-02-23 18:49:11 -0800150 * the restore is finished, the application should write a representation of
151 * the final state to the <code>newState</code> file descriptor.
152 * <p>
153 * The application is responsible for properly erasing its old data and
154 * replacing it with the data supplied to this method. No "clear user data"
155 * operation will be performed automatically by the operating system. The
156 * exception to this is in the case of a failed restore attempt: if
157 * onRestore() throws an exception, the OS will assume that the
158 * application's data may now be in an incoherent state, and will clear it
159 * before proceeding.
160 *
161 * @param data A structured wrapper around an open, read-only
Christopher Tate4e14a822010-04-08 12:54:23 -0700162 * file descriptor pointing to a full snapshot of the
163 * application's data. The application should consume every
164 * entity represented in this data stream.
Scott Mainb83a2832010-04-29 13:26:53 -0700165 * @param appVersionCode The value of the <a
166 * href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code
167 * android:versionCode}</a> manifest attribute,
168 * from the application that backed up this particular data set. This
Christopher Tate4e14a822010-04-08 12:54:23 -0700169 * makes it possible for an application's agent to distinguish among any
Kenny Root5a20ea12010-02-23 18:49:11 -0800170 * possible older data versions when asked to perform the restore
171 * operation.
172 * @param newState An open, read/write ParcelFileDescriptor pointing to an
173 * empty file. The application should record the final backup
Christopher Tate4e14a822010-04-08 12:54:23 -0700174 * state here after restoring its data from the <code>data</code> stream.
Christopher Tate487529a2009-04-29 14:03:25 -0700175 */
Christopher Tate5cbbf562009-06-22 16:44:51 -0700176 public abstract void onRestore(BackupDataInput data, int appVersionCode,
177 ParcelFileDescriptor newState)
Joe Onorato83248c42009-06-17 17:55:20 -0700178 throws IOException;
Christopher Tate487529a2009-04-29 14:03:25 -0700179
180
181 // ----- Core implementation -----
Christopher Tate44a27902010-01-27 17:15:49 -0800182
183 /** @hide */
184 public final IBinder onBind() {
Christopher Tate181fafa2009-05-14 11:12:14 -0700185 return mBinder;
Christopher Tate487529a2009-04-29 14:03:25 -0700186 }
187
188 private final IBinder mBinder = new BackupServiceBinder().asBinder();
189
Christopher Tate181fafa2009-05-14 11:12:14 -0700190 /** @hide */
191 public void attach(Context context) {
192 attachBaseContext(context);
193 }
194
Christopher Tate487529a2009-04-29 14:03:25 -0700195 // ----- IBackupService binder interface -----
Christopher Tate181fafa2009-05-14 11:12:14 -0700196 private class BackupServiceBinder extends IBackupAgent.Stub {
197 private static final String TAG = "BackupServiceBinder";
198
Christopher Tate22b87872009-05-04 16:41:53 -0700199 public void doBackup(ParcelFileDescriptor oldState,
200 ParcelFileDescriptor data,
Christopher Tate44a27902010-01-27 17:15:49 -0800201 ParcelFileDescriptor newState,
202 int token, IBackupManager callbackBinder) throws RemoteException {
Christopher Tate19024922010-01-22 16:39:53 -0800203 // Ensure that we're running with the app's normal permission level
Christopher Tate44a27902010-01-27 17:15:49 -0800204 long ident = Binder.clearCallingIdentity();
Christopher Tate19024922010-01-22 16:39:53 -0800205
Christopher Tate436344a2009-09-30 16:17:37 -0700206 if (DEBUG) Log.v(TAG, "doBackup() invoked");
Joe Onorato83248c42009-06-17 17:55:20 -0700207 BackupDataOutput output = new BackupDataOutput(data.getFileDescriptor());
Joe Onorato290bb012009-05-13 18:57:29 -0400208 try {
Christopher Tate181fafa2009-05-14 11:12:14 -0700209 BackupAgent.this.onBackup(oldState, output, newState);
Joe Onorato4ababd92009-06-25 18:29:18 -0400210 } catch (IOException ex) {
211 Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
212 throw new RuntimeException(ex);
Joe Onorato290bb012009-05-13 18:57:29 -0400213 } catch (RuntimeException ex) {
Joe Onorato83248c42009-06-17 17:55:20 -0700214 Log.d(TAG, "onBackup (" + BackupAgent.this.getClass().getName() + ") threw", ex);
Joe Onorato290bb012009-05-13 18:57:29 -0400215 throw ex;
Christopher Tate19024922010-01-22 16:39:53 -0800216 } finally {
Christopher Tate44a27902010-01-27 17:15:49 -0800217 Binder.restoreCallingIdentity(ident);
218 try {
219 callbackBinder.opComplete(token);
220 } catch (RemoteException e) {
221 // we'll time out anyway, so we're safe
222 }
Joe Onorato290bb012009-05-13 18:57:29 -0400223 }
Christopher Tate487529a2009-04-29 14:03:25 -0700224 }
225
Christopher Tate5cbbf562009-06-22 16:44:51 -0700226 public void doRestore(ParcelFileDescriptor data, int appVersionCode,
Christopher Tate44a27902010-01-27 17:15:49 -0800227 ParcelFileDescriptor newState,
228 int token, IBackupManager callbackBinder) throws RemoteException {
Christopher Tate19024922010-01-22 16:39:53 -0800229 // Ensure that we're running with the app's normal permission level
Christopher Tate44a27902010-01-27 17:15:49 -0800230 long ident = Binder.clearCallingIdentity();
Christopher Tate19024922010-01-22 16:39:53 -0800231
Christopher Tate436344a2009-09-30 16:17:37 -0700232 if (DEBUG) Log.v(TAG, "doRestore() invoked");
Joe Onorato83248c42009-06-17 17:55:20 -0700233 BackupDataInput input = new BackupDataInput(data.getFileDescriptor());
234 try {
Christopher Tate5cbbf562009-06-22 16:44:51 -0700235 BackupAgent.this.onRestore(input, appVersionCode, newState);
Joe Onorato83248c42009-06-17 17:55:20 -0700236 } catch (IOException ex) {
237 Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex);
238 throw new RuntimeException(ex);
239 } catch (RuntimeException ex) {
240 Log.d(TAG, "onRestore (" + BackupAgent.this.getClass().getName() + ") threw", ex);
241 throw ex;
Christopher Tate19024922010-01-22 16:39:53 -0800242 } finally {
Christopher Tate44a27902010-01-27 17:15:49 -0800243 Binder.restoreCallingIdentity(ident);
244 try {
245 callbackBinder.opComplete(token);
246 } catch (RemoteException e) {
247 // we'll time out anyway, so we're safe
248 }
Joe Onorato83248c42009-06-17 17:55:20 -0700249 }
Christopher Tate487529a2009-04-29 14:03:25 -0700250 }
251 }
252}