backup.jd revision 371557fabde31fece172749783981c7835ba4053
1page.title=Data Backup
2@jd:body
3
4
5<div id="qv-wrapper">
6<div id="qv">
7
8  <h2>Quickview</h2>
9  <ul>
10    <li>Back up your data to the cloud in case the user looses it</li>
11    <li>Easily back up SharedPreferences and private files with BackupAgentHelper</li>
12    <li>Requires API Level 8</li>
13  </ul>
14
15  <h2>In this document</h2>
16  <ol>
17    <li><a href="#Basics">The Basics</a></li>
18    <li><a href="#BackupAgent">Extending BackupAgent</a>
19      <ol>
20        <li><a href="#RequiredMethods">Required Methods</a></li>
21        <li><a href="#PerformingBackup">Performing backup</a></li>
22        <li><a href="#PerformingRestore">Performing restore</a></li>
23      </ol>
24    </li>
25    <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
26      <ol>
27        <li><a href="#SharedPreferences">Backing up SharedPreferences</a></li>
28        <li><a href="#Files">Backing up Private Files</a></li>
29      </ol>
30    </li>
31    <li><a href="#RestoreVersion">Checking the Restore Data Version</a></li>
32    <li><a href="#RequestingBackup">Requesting Backup</a></li>
33    <li><a href="#RequestingRestore">Requesting Restore</a></li>
34    <li><a href="#DevelopingTestings">Developing and Testing Your Backup Agent</a></li>
35  </ol>
36
37  <h2>Key classes</h2>
38  <ol>
39    <li>{@link android.app.backup.BackupManager}</li>
40    <li>{@link android.app.backup.BackupAgent}</li>
41    <li>{@link android.app.backup.BackupAgentHelper}</li>
42  </ol>
43
44</div>
45</div>
46
47<p>Android's {@link android.app.backup backup} service allows you to copy your persistent
48application data to a remote "cloud" storage, in order to provide a restore point for the
49application data and settings. If a user performs a factory reset or converts to a new
50Android-powered device, the system automatically restores your backup data when the application
51is re-installed. This way, your users are not required to reproduce their previous data or
52application settings. This process is completely transparent to the user and does not affect the
53functionality or user experience in your application.</p>
54
55<p>Android-powered devices that support the backup service provide a cloud storage area that
56saves your backup data and a backup transport that delivers your data to
57the storage area and back to the device. During a backup
58operation, Android's Backup Manager requests backup data from your application, then delivers it to
59the cloud storage using the backup transport. During a restore operation, the Backup Manager
60retrieves the backup data from the backup transport and returns it to your application
61so it can restore the data to the device. The backup service is <em>not</em> designed for data
62synchronization (you do not have access the backup data, except during a restore operation on the
63device).</p>
64
65<p>The cloud storage used for backup won't necessarily be the same on all Android-powered devices.
66The cloud storage and backup transport may differ between devices and service providers.
67Where the backup data is stored is transparent to your application, but you are assured that your
68application data cannot be read by other applications.</p>
69
70<p class="caution"><strong>Caution:</strong> Because the cloud storage and transport service can
71differ from device to device, Android makes no guarantees about the security of your data while
72using backup. You should be cautious about using backup to store sensitive data, such as usernames
73and passwords.</p>
74
75
76<h2 id="Basics">The Basics</h2>
77
78<p>To backup your application data, you need to implement a backup agent. Your backup
79agent is called by the Backup Manager to provide the data you want to back up. It is also called
80to restore your backup data when the application is re-installed. The Backup Manager handles all
81your data transactions with the cloud storage and your backup agent handles all your data
82transactions on the device.</p>
83
84<p>To implement a backup agent, you must:</p>
85
86<ol>
87  <li>Declare your backup agent in your manifest file with the <a
88href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
89android:backupAgent}</a> attribute.</li>
90  <li>Define a backup agent by either:</p>
91    <ol type="a">
92      <li><a href="#backupAgent">Extending BackupAgent</a>
93        <p>The {@link android.app.backup.BackupAgent} class provides the central interface with
94which your application communicates with the Backup Manager. If you extend this class
95directly, you must override {@link
96android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
97onBackup()} and {@link
98android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
99onRestore()} to handle the backup and restore operations for your data.</p>
100        <p><em>Or</em></p>
101      <li><a href="#backupAgentHelper">Extending BackupAgentHelper</a>
102        <p>The {@link android.app.backup.BackupAgentHelper} class provides a convenient
103wrapper around the {@link android.app.backup.BackupAgent} class, which minimizes the amount of code
104you need to write. In your {@link android.app.backup.BackupAgentHelper}, you must use one or more
105"helper" objects, which automatically backup and restore certain types of data, so that you do not
106need to implement {@link
107android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
108onBackup()} and {@link
109android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
110onRestore()}.</p>
111        <p>Android currently provides backup helpers that will backup and restore complete files
112from {@link android.content.SharedPreferences} and <a
113href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</p>
114      </li>
115    </ol>
116  </li>
117</ol>
118
119
120
121
122<h2 id="BackupManifest">Declaring the Backup Agent in Your Manifest</h2>
123
124<p>This is the easiest step, so once you've decided on the class name for your backup agent, declare
125it in your manifest with the <a
126href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
127android:backupAgent}</a> attribute in the <a
128href="{@docRoot}guide/topics/manifest/application-element.html">{@code
129&lt;application&gt;}</a> tag.</p>
130
131<p>For example:</p>
132
133<pre>
134&lt;manifest ... &gt;
135    &lt;application android:label="MyApplication"
136                 <b>android:backupAgent="MyBackupAgent"</b>&gt;
137        &lt;activity ... &gt;
138            ...
139        &lt;/activity&gt;
140    &lt;/application&gt;
141&lt;/manifest&gt;
142</pre>
143
144<p>Another attribute you might want to use is <a
145href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
146android:restoreAnyVersion}</a>. This attribute takes a boolean value to indicate whether you
147want to restore the application data regardless of the current application version compared to the
148version that produced the backup data. (The default value is "{@code false}".) See <a
149href="#RestoreVersion">Checking the Restore Data Version</a> for more information.</p>
150
151<p class="note"><strong>Note:</strong> The backup service and the APIs you must use are
152available only on devices running API Level 8 (Android 2.2) or greater, so you should also
153set your <a
154href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
155attribute to "8". However, if you implement proper <a
156href="{@docRoot}resources/articles/backward-compatibility.html">backward compatibility</a> in
157your application, you can support this feature for devices running API Level 8 or greater, while
158remaining compatible with older devices.</p>
159
160
161
162
163
164<h2 id="BackupAgent">Extending BackupAgent</h2>
165
166<p>Most applications shouldn't need to extend the {@link android.app.backup.BackupAgent} class
167directly, but should instead <a href="BackupAgentHelper">extend BackupAgentHelper</a> to take
168advantage of the built-in helper classes that automatically backup and restore your files. However,
169you might want to extend {@link android.app.backup.BackupAgent} directly if you need to:</p>
170<ul>
171  <li>Version your data format. For instance, if you anticipate the need to revise the
172format in which you write your application data, you can build a backup agent to cross-check your
173application version during a restore operation and perform any necessary compatibility work if the
174version on the device is different than that of the backup data. For more information, see <a
175href="#RestoreVersion">Checking the Restore Data Version</a>.</li>
176  <li>Instead of backing up an entire file, you can specify the portions of data the should be
177backed up and how each portion is then restored to the device. (This can also help you manage
178different versions, because you read and write your data as unique entities, rather than
179complete files.)</li>
180  <li>Back up data in a database. If you have an SQLite database that you want to restore when
181the user re-installs your application, you need to build a custom {@link
182android.app.backup.BackupAgent} that reads the appropriate data during a backup operation, then
183create your table and insert the data during a restore operation.</li>
184</ul>
185
186<p>If you don't need to perform any of the tasks above and want to back up complete files from
187{@link android.content.SharedPreferences} or <a
188href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>, you
189should skip to <a href="BackupAgentHelper">Extending BackupAgentHelper</a>.</p>
190
191
192
193<h3 id="RequiredMethods">Required Methods</h3>
194
195<p>When you create a backup agent by extending {@link android.app.backup.BackupAgent}, you
196must implement the following callback methods:</p>
197
198<dl>
199  <dt>{@link
200android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
201onBackup()}</dt>
202    <dd>The Backup Manager calls this method after you <a href="#RequestBackup">request a
203backup</a>. In this method, you read your application data from the device and pass the data you
204want to back up to the Backup Manager, as described below in <a href="#PerformingBackup">Performing
205backup</a>.</dd>
206
207  <dt>{@link
208android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
209onRestore()}</dt>
210    <dd>The Backup Manager calls this method during a restore operation (you can <a
211href="#RequestRestore">request a restore</a>, but the system automatically performs restore when the
212user re-installs your application). When it calls this method, the Backup Manager delivers your
213backup data, which you then restore to the device, as described below in <a
214href="#PerformingRestore">Performing restore</a>.</dd>
215</dl>
216
217
218
219<h3 id="PerformingBackup">Performing backup</h3>
220
221
222<p>When it's time to back up your application data, the Backup Manager calls your {@link
223android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
224onBackup()} method. This is where you must provide your application data to the Backup Manager so
225it can be saved to cloud storage.</p>
226
227<p>Only the Backup Manager can call your backup agent's {@link
228android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
229onBackup()} method. Each time that your application data changes and you want to perform a backup,
230you must request a backup operation by calling {@link
231android.app.backup.BackupManager#dataChanged()} (see <a href="#RequestingBackup">Requesting
232Backup</a> for more information). A backup request does not result in an immediate call to your
233{@link
234android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
235onBackup()} method. Instead, the Backup Manager waits for an appropriate time, then performs
236backup for all applications that have requested a backup since the last backup was performed.</p>
237
238<p class="note"><strong>Tip:</strong> While developing your application, you can initiate an
239immediate backup operation from the Backup Manager with the <a
240href="{@docRoot}guide/developing/tools/bmgr.html">bmgr tool</a>.</p>
241
242<p>When the Backup Manager calls your {@link
243android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
244onBackup()} method, it passes three parameters:</p>
245
246<dl>
247  <dt>{@code oldState}</dt>
248    <dd>An open, read-only {@link android.os.ParcelFileDescriptor} pointing to the last backup
249state provided by your application. This is not the backup data from cloud storage, but a
250local representation of the data that was backed up the last time {@link
251android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
252onBackup()} was called (as defined by {@code newState}, below, or from {@link
253android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
254onRestore()}&mdash;more about this in the next section). Because {@link
255android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
256onBackup()} does not allow you to read existing backup data in
257the cloud storage, you can use this local representation to determine whether your data has changed
258since the last backup.</dd>
259  <dt>{@code data}</dt>
260    <dd>A {@link android.app.backup.BackupDataOutput} object, which you use to deliver your backup
261data to the Backup Manager.</dd>
262  <dt>{@code newState}</dt>
263    <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
264you must write a representation of the data that you delivered to {@code data} (a representation
265can be as simple as the last-modified timestamp for your file). This object is
266returned as {@code oldState} the next time the Backup Manager calls your {@link
267android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
268onBackup()} method. If you do not write your backup data to {@code newState}, then {@code oldState}
269will point to an empty file next time Backup Manager calls {@link
270android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
271onBackup()}.</dd>
272</dl>
273
274<p>Using these parameters, you should implement your {@link
275android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
276onBackup()} method to do the following:</p>
277
278<ol>
279  <li>Check whether your data has changed since the last backup by comparing {@code oldState} to
280your current data. How you read data in {@code oldState} depends on how you originally wrote it to
281{@code newState} (see step 3). The easiest way to record the state of a file is with its
282last-modified timestamp. For example, here's how you can read and compare a timestamp from {@code
283oldState}:
284    <pre>
285// Get the oldState input stream
286FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
287DataInputStream in = new DataInputStream(instream);
288
289try {
290    // Get the last modified timestamp from the state file and data file
291    long stateModified = in.readLong();
292    long fileModified = mDataFile.lastModified();
293
294    if (stateModified != fileModified) {
295        // The file has been modified, so do a backup
296        // Or the time on the device changed, so be safe and do a backup
297    } else {
298        // Don't back up because the file hasn't changed
299        return;
300    }
301} catch (IOException e) {
302    // Unable to read state file... be safe and do a backup
303}
304</pre>
305    <p>If nothing has changed and you don't need to back up, skip to step 3.</p>
306  </li>
307  <li>If your data has changed, compared to {@code oldState}, write the current data to
308{@code data} to back it up to the cloud storage.
309    <p>You must write each chunk of data as an "entity" in the {@link
310android.app.backup.BackupDataOutput}. An entity is a flattened binary data
311record that is identified by a unique key string. Thus, the data set that you back up is
312conceptually a set of key-value pairs.</p>
313    <p>To add an entity to your backup data set, you must:</p>
314    <ol>
315      <li>Call {@link android.app.backup.BackupDataOutput#writeEntityHeader(String,int)
316writeEntityheader()}, passing a unique string key for the data you're about to write and the data
317size.</li>
318      <li>Call {@link android.app.backup.BackupDataOutput#writeEntityData(byte[],int)
319writeEntityData()}, passing a byte buffer that contains your data and the number of bytes to write
320from the buffer (which should match the size passed to {@link
321android.app.backup.BackupDataOutput#writeEntityHeader(String,int) writeEntityHeader()}).</li>
322    </ol>
323    <p>For example, the following code flattens some data into a byte stream and writes it into a
324single entity:</p>
325    <pre>
326// Create buffer stream and data output stream for our data
327ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
328DataOutputStream outWriter = new DataOutputStream(bufStream);
329// Write structured data
330outWriter.writeString(playerName);
331outWriter.writeInt(playerScore);
332// Send the data to the Backup Manager via the BackupDataOutput
333byte[] buffer = bufStream.toByteArray();
334int len = buffer.length;
335data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);
336data.writeEntityData(buffer, len);
337</pre>
338    <p>Perform this for each piece of data that you want to back up. How you divide your data into
339entities is up to you (and you might use just one entity).</p>
340  </li>
341  <li>Whether or not you perform a backup (in step 2), write a representation of the current data to
342the {@code newState} {@link android.os.ParcelFileDescriptor}. The Backup Manager retains this object
343locally as a representation of the data that is currently backed up. It passes this back to you as
344{@code oldState} the next time it calls {@link
345android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
346onBackup()} so you can determine whether another backup is necessary (as handled in step 1). If you
347do not write the current data state to this file, then
348{@code oldState} will be empty during the next callback.
349    <p>Again, the following example saves a representation of the data using the file's
350last-modified timestamp:</p>
351    <pre>
352FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
353DataOutputStream out = new DataOutputStream(outstream);
354
355long modified = mDataFile.lastModified();
356out.writeLong(modified);
357</pre>
358  </li>
359</ol>
360
361<p class="caution"><strong>Caution:</strong> If your application data is saved to a file, make sure
362that you use synchronized statements while accessing the file so that your backup agent does not
363read the file while an Activity in your application is also writing the file.</p>
364
365
366
367
368<h3 id="PerformingRestore">Performing restore</h3>
369
370<p>When it's time to restore your application data, the Backup Manager calls your backup
371agent's {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
372onRestore()} method. When it calls this method, the Backup Manager delivers your backup data so
373you can restore it onto the device.</p>
374
375<p>Only the Backup Manager can call {@link
376android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
377onRestore()}, which happens automatically when the system installs your application and
378finds existing backup data. However, you can request a restore operation for
379your application by calling {@link
380android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} (see <a
381href="#RequestingRestore">Requesting restore</a> for more information).</p>
382
383<p class="note"><strong>Note:</strong> While developing your application, you can also request a
384restore operation with the <a href="{@docRoot}guide/developing/tools/bmgr.html">bmgr
385tool</a>.</p>
386
387<p>When the Backup Manager calls your {@link
388android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
389onRestore()} method, it passes three parameters:</p>
390
391<dl>
392  <dt>{@code data}</dt>
393    <dd>A {@link android.app.backup.BackupDataInput}, which allows you to read your backup
394data.</dd>
395  <dt>{@code appVersionCode}</dt>
396    <dd>An integer representing the value of your application's <a
397href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
398manifest attribute, as it was when this data was backed up. You can use this to cross-check the
399current application version and determine if the data format is compatible. For more
400information about using this to handle different versions of restore data, see the section
401below about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</dd>
402  <dt>{@code newState}</dt>
403    <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
404you must write the final backup state that was provided with {@code data}. This object is
405returned as {@code oldState} the next time {@link
406android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
407onBackup()} is called. Recall that you must also write the same {@code newState} object in the
408{@link
409android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
410onBackup()} callback&mdash;also doing it here ensures that the {@code oldState} object given to
411{@link
412android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
413onBackup()} is valid even the first time {@link
414android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
415onBackup()} is called after the device is restored.</dd>
416</dl>
417
418<p>In your implementation of {@link
419android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
420onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} to iterate
421through all entities in the data set. For each entity found, do the following:</p>
422
423<ol>
424  <li>Get the entity key with {@link android.app.backup.BackupDataInput#getKey()}.</li>
425  <li>Compare the entity key to a list of known key values that you should have declared as static
426final strings inside your {@link android.app.backup.BackupAgent} class. When the key matches one of
427your known key strings, enter into a statement to extract the entity data and save it to the device:
428    <ol>
429      <li>Get the entity data size with {@link
430android.app.backup.BackupDataInput#getDataSize()} and create a byte array of that size.</li>
431      <li>Call {@link android.app.backup.BackupDataInput#readEntityData(byte[],int,int)
432readEntityData()} and pass it the byte array, which is where the data will go, and specify the
433start offset and the size to read.</li>
434      <li>Your byte array is now full and you can read the data and write it to the device
435however you like.</li>
436    </ol>
437  </li>
438  <li>After you read and write your data back to the device, write the state of your data to the
439{@code newState} parameter the same as you do during {@link
440android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
441onBackup()}.
442</ol>
443
444<div class="special">
445<p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a
446href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code
447ExampleAgent}</a> class in the <a
448href="{@docRoot}}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
449application.</p>
450</div>
451
452
453
454
455
456
457<h2 id="BackupAgentHelper">Extending BackupAgentHelper</h2>
458
459<p>You should build your backup agent using {@link android.app.backup.BackupAgentHelper} if you want
460to back up complete files (from either {@link android.content.SharedPreferences} or <a
461href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>).
462Building your backup agent with {@link android.app.backup.BackupAgentHelper} requires far less
463code than extending {@link android.app.backup.BackupAgent}, because you don't have to implement
464{@link
465android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
466onBackup()} and {@link
467android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
468onRestore()}.</p>
469
470<p>Your implementation of {@link android.app.backup.BackupAgentHelper} must
471use one or more backup helpers. A backup helper is a specialized
472component that {@link android.app.backup.BackupAgentHelper} summons to perform backup and
473restore operations for a particular type of data. The Android framework currently provides two
474different helpers:</p>
475<ul>
476  <li>{@link android.app.backup.SharedPreferencesBackupHelper} to backup {@link
477android.content.SharedPreferences} files.</li>
478  <li>{@link android.app.backup.FileBackupHelper} to backup files from <a
479href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</li>
480</ul>
481
482<p>You can include multiple helpers in your {@link android.app.backup.BackupAgentHelper}, but only
483one helper is needed for each data type. That is, if you have multiple {@link
484android.content.SharedPreferences} files, then you need only one {@link
485android.app.backup.SharedPreferencesBackupHelper}.</p>
486
487<p>For each helper you want to add to your {@link android.app.backup.BackupAgentHelper}, you must do
488the following during your {@link android.app.backup.BackupAgent#onCreate()} method:</p>
489<ol>
490  <li>Instantiate in instance of the desired helper class. In the class constructor, you must
491specify the appropriate file(s) you want to backup.</li>
492  <li>Call {@link android.app.backup.BackupAgentHelper#addHelper(String,BackupHelper) addHelper()}
493to add the helper to your {@link android.app.backup.BackupAgentHelper}.</li>
494</ol>
495
496<p>The following sections describe how to create a backup agent using each of the available
497helpers.</p>
498
499
500
501<h3 id="SharedPreferences">Backing up SharedPreferences</h3>
502
503<p>When you instantiate a {@link android.app.backup.SharedPreferencesBackupHelper}, you must the
504name of one or more {@link android.content.SharedPreferences} files.</p>
505
506<p>For example, to back up a {@link android.content.SharedPreferences} file named
507"user_preferences", a complete backup agent using {@link android.app.backup.BackupAgentHelper} looks
508like this:</p>
509
510<pre>
511public class MyPrefsBackupAgent extends BackupAgentHelper {
512    // The name of the SharedPreferences file
513    static final String PREFS = "user_preferences";
514
515    // A key to uniquely identify the set of backup data
516    static final String PREFS_BACKUP_KEY = "prefs";
517
518    // Allocate a helper and add it to the backup agent
519    void onCreate() {
520        SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS);
521        addHelper(PREFS_BACKUP_KEY, helper);
522    }
523}
524</pre>
525
526<p>That's it! That's your entire backup agent. The {@link
527android.app.backup.SharedPreferencesBackupHelper} includes all the code
528needed to backup and restore a {@link android.content.SharedPreferences} file.</p>
529
530<p>When the Backup Manager calls {@link
531android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
532onBackup()} and {@link
533android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
534onRestore()}, {@link android.app.backup.BackupAgentHelper} calls your backup helpers to perform
535backup and restore for your specified files.</p>
536
537<p class="note"><strong>Note:</strong> {@link android.content.SharedPreferences} are threadsafe, so
538you can safely read and write the shared preferences file from your backup agent and
539other activities.</p>
540
541
542
543<h3 id="Files">Backing up other files</h3>
544
545<p>When you instantiate a {@link android.app.backup.FileBackupHelper}, you must include the name of
546one or more files that are saved to your application's <a
547href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>
548(as specified by {@link android.content.ContextWrapper#getFilesDir()}, which is the same
549location where {@link android.content.Context#openFileOutput(String,int) openFileOutput()} writes
550files).</p>
551
552<p>For example, to backup two files named "scores" and "stats," a backup agent using {@link
553android.app.backup.BackupAgentHelper} looks like this:</p>
554
555<pre>
556public class MyFileBackupAgent extends BackupAgentHelper {
557    // The name of the SharedPreferences file
558    static final String TOP_SCORES = "scores";
559    static final String PLAYER_STATS = "stats";
560
561    // A key to uniquely identify the set of backup data
562    static final String FILES_BACKUP_KEY = "myfiles";
563
564    // Allocate a helper and add it to the backup agent
565    void onCreate() {
566        FileBackupHelper helper = new FileBackupHelper(this, TOP_SCORES, PLAYER_STATS);
567        addHelper(FILES_BACKUP_KEY, helper);
568    }
569}
570</pre>
571
572<p>The {@link android.app.backup.FileBackupHelper} includes all the code necessary to backup and
573restore files that are saved to your application's <a
574href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>..</p>
575
576<p>However, reading and writing to files on internal storage is <strong>not threadsafe</strong>. To
577ensure that your backup agent does not read or write your files at the same time as your activities,
578you must use synchronized statements each time you perform a read or write. For example,
579in any Activity where you read and write the file, you need an object to use as the intrinsic
580lock for the synchronized statements:</p>
581
582<div class="sidebox-wrapper">
583<div class="sidebox">
584<p><strong>Interesting Fact:</strong></p>
585<p>A zero-length array is lighter-weight than a normal Object, so it's great for an
586intrinsic lock.</p>
587</div>
588</div>
589
590<pre>
591// Object for intrinsic lock
592static final Object[] sDataLock = new Object[0];
593</pre>
594
595<p>Then create a synchronized statement with this lock each time you read or write the files. For
596example, here's a synchronized statement for writing the latest score in a game to a file:</p>
597
598<pre>
599try {
600    synchronized (MyActivity.sDataLock) {
601        File dataFile = new File({@link android.content.Context#getFilesDir()}, TOP_SCORES);
602        RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
603        raFile.writeInt(score);
604    }
605} catch (IOException e) {
606    Log.e(TAG, "Unable to write to file");
607}
608</pre>
609
610<p>You should synchronize your read statements with the same lock.</p>
611
612<p>Then, in your {@link android.app.backup.BackupAgentHelper}, you must override {@link
613android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
614onBackup()} and {@link
615android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
616onRestore()} to synchronize the backup and restore operations with the same
617intrinsic lock. For example, the {@code MyFileBackupAgent} example from above needs the following
618methods:</p>
619
620<pre>
621&#64;Override
622public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
623          ParcelFileDescriptor newState) throws IOException {
624    // Hold the lock while the FileBackupHelper performs backup
625    synchronized (MyActivity.sDataLock) {
626        super.onBackup(oldState, data, newState);
627    }
628}
629
630&#64;Override
631public void onRestore(BackupDataInput data, int appVersionCode,
632        ParcelFileDescriptor newState) throws IOException {
633    // Hold the lock while the FileBackupHelper restores the file
634    synchronized (MyActivity.sDataLock) {
635        super.onRestore(data, appVersionCode, newState);
636    }
637}
638</pre>
639
640<p>That's it. All you need to do is add your {@link android.app.backup.FileBackupHelper} in the
641{@link android.app.backup.BackupAgent#onCreate()} method and override {@link
642android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
643onBackup()} and {@link
644android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
645onRestore()} to synchronize read and write operations.</p>
646
647<div class="special">
648<p>For an example implementation of {@link
649android.app.backup.BackupAgentHelper} with {@link android.app.backup.FileBackupHelper}, see the
650{@code FileHelperExampleAgent} class in the <a
651href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
652application.</p>
653</div>
654
655
656
657
658
659
660<h2 id="RestoreVersion">Checking the Restore Data Version</h2>
661
662<p>When the Backup Manager saves your data to cloud storage, it automatically includes the version
663of your application, as defined by your manifest file's <a
664href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
665attribute. Before the Backup Manager calls your backup agent to restore your data, it
666looks at the <a
667href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code
668android:versionCode}</a> of the installed application and compares it to the value
669recorded in the restore data set. If the version recorded in the restore data set is
670<em>newer</em> than the application version on the device, then the user has downgraded their
671application. In this case, the Backup Manager will abort the restore operation for your application
672and not call your {@link
673android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
674method, because the restore set is considered meaningless to an older version.</p>
675
676<p>You can override this behavior with the <a
677href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
678android:restoreAnyVersion}</a> attribute. This attribute is either "{@code true}" or "{@code
679false}" to indicate whether you want to restore the application regardless of the restore set
680version. The default value is "{@code false}". If you define this to be "{@code true}" then the
681Backup Manager will ignore the <a
682href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
683and call your {@link
684android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
685method in all cases. In doing so, you can manually check for the version difference in your {@link
686android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
687method and take any steps necessary to make the data compatible if the versions conflict.</p>
688
689<p>To help you handle different versions during a restore operation, the {@link
690android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
691method passes you the version code included with the restore data set as the {@code appVersionCode}
692parameter. You can then query the current application's version code with the {@link
693android.content.pm.PackageInfo#versionCode PackageInfo.versionCode} field. For example:</p>
694
695<pre>
696PackageInfo info;
697try {
698    String name = {@link android.content.ContextWrapper#getPackageName() getPackageName}();
699    info = {@link android.content.ContextWrapper#getPackageManager
700getPackageManager}().{@link android.content.pm.PackageManager#getPackageInfo(String,int)
701getPackageInfo}(name,0);
702} catch (NameNotFoundException nnfe) {
703    info = null;
704}
705
706int version;
707if (info != null) {
708    version = info.versionCode;
709}
710</pre>
711
712<p>Then simply compare the {@code version} acquired from {@link android.content.pm.PackageInfo}
713to the {@code appVersionCode} passed into {@link
714android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}.
715</p>
716
717<p class="caution"><strong>Caution:</strong> Be certain you understand the consequences of setting
718<a href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
719android:restoreAnyVersion}</a> to "{@code true}" for your application. If each version of your
720application that supports backup does not properly account for variations in your data format during
721{@link
722android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()},
723then the data on the device could be saved in a format incompatible with the version currently
724installed on the device.</p>
725
726
727
728<h2 id="RequestingBackup">Requesting Backup</h2>
729
730<p>You can request a backup operation at any time by calling {@link
731android.app.backup.BackupManager#dataChanged()}. This method notifies the Backup Manager that you'd
732like to backup your data using your backup agent. The Backup Manager then calls your backup
733agent's {@link
734android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
735onBackup()} method at an opportune time in the future. Typically, you should
736request a backup each time your data changes (such as when the user changes an application
737preference that you'd like to back up). If you call {@link
738android.app.backup.BackupManager#dataChanged()} several times consecutively, before the Backup
739Manager requests a backup from your agent, your agent still receives just one call to {@link
740android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
741onBackup()}.</p>
742
743<p class="note"><strong>Note:</strong> While developing your application, you can request a
744backup and initiate an immediate backup operation with the <a
745href="{@docRoot}guide/developing/tools/bmgr.html">bmgr
746tool</a>.</p>
747
748
749<h2 id="RequestingRestore">Requesting Restore</h2>
750
751<p>During the normal life of your application, you shouldn't need to request a restore operation.
752They system automatically checks for backup data and performs a restore when your application is
753installed. However, you can manually request a restore operation by calling {@link
754android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()}, if necessary. In
755which case, the Backup Manager calls your {@link
756android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
757implementation, passing the data from the current set of backup data.</p>
758
759<p class="note"><strong>Note:</strong> While developing your application, you can request a
760restore operation with the <a href="{@docRoot}guide/developing/tools/bmgr.html">bmgr
761tool</a>.</p>
762
763
764<h2 id="DevelopingTestings">Developing and Testing Your Backup Agent</h2>
765
766<p>To develop and test your backup agent:</p>
767<ul>
768  <li>Set your build target to a platform using API Level 8 or higher</li>
769  <li>Run your application on a suitable Android system image:
770    <ul>
771      <li>If using the emulator, create and use an AVD with the Google APIs add-on (API Level
7728) &mdash; the Google APIs add-on is available as an SDK component through the SDK and AVD
773Manager</li>
774      <li>If using a device, the device must be running Android 2.2 or greater and have Android
775Market built in</li>
776    </ul>
777  </li>
778  <li>Test your backup agent using the <a href="{@docRoot}guide/developing/tools/bmgr.html">{@code
779bmgr}</a> tool to initiate backup and restore operations</li>
780</ul>
781
782