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