summaryrefslogtreecommitdiffstats
path: root/docs/html/guide/topics
diff options
context:
space:
mode:
authorScott Main <smain@google.com>2010-04-29 13:26:53 -0700
committerScott Main <smain@google.com>2010-05-14 11:47:42 -0700
commitb83a283ac178ab0a72f1d811189d79b26097835e (patch)
tree2be72c9a1ca56ea65b6f35608c867bf8c21a79af /docs/html/guide/topics
parentfb473bb6118f6b82fdeda443b4fdc4ce31d3ed60 (diff)
downloadframeworks_base-b83a283ac178ab0a72f1d811189d79b26097835e.zip
frameworks_base-b83a283ac178ab0a72f1d811189d79b26097835e.tar.gz
frameworks_base-b83a283ac178ab0a72f1d811189d79b26097835e.tar.bz2
docs: add dev guide for backup
Change-Id: I168f6b15d3441c9cbea2cd9699612476c7244530
Diffstat (limited to 'docs/html/guide/topics')
-rw-r--r--docs/html/guide/topics/data/backup.jd761
1 files changed, 761 insertions, 0 deletions
diff --git a/docs/html/guide/topics/data/backup.jd b/docs/html/guide/topics/data/backup.jd
new file mode 100644
index 0000000..98f7a4f
--- /dev/null
+++ b/docs/html/guide/topics/data/backup.jd
@@ -0,0 +1,761 @@
+page.title=Data Backup
+@jd:body
+
+
+<div id="qv-wrapper">
+<div id="qv">
+
+ <h2>Quickview</h2>
+ <ul>
+ <li>Back up your data to the cloud in case the user looses it</li>
+ <li>Easily back up SharedPreferences and private files with BackupAgentHelper</li>
+ <li>Requires API Level 8</li>
+ </ul>
+
+ <h2>In this document</h2>
+ <ol>
+ <li><a href="#Basics">The Basics</a></li>
+ <li><a href="#BackupAgent">Extending BackupAgent</a>
+ <ol>
+ <li><a href="#RequiredMethods">Required Methods</a></li>
+ <li><a href="#PerformingBackup">Performing backup</a></li>
+ <li><a href="#PerformingRestore">Performing restore</a></li>
+ </ol>
+ </li>
+ <li><a href="#BackupAgentHelper">Extending BackupAgentHelper</a>
+ <ol>
+ <li><a href="#SharedPreferences">Backing up SharedPreferences</a></li>
+ <li><a href="#Files">Backing up Private Files</a></li>
+ </ol>
+ </li>
+ <li><a href="#RestoreVersion">Checking the Restore Data Version</a></li>
+ <li><a href="#RequestingBackup">Requesting Backup</a></li>
+ <li><a href="#RequestingRestore">Requesting Restore</a></li>
+ </ol>
+
+ <h2>Key classes</h2>
+ <ol>
+ <li>{@link android.app.backup.BackupManager}</li>
+ <li>{@link android.app.backup.BackupAgent}</li>
+ <li>{@link android.app.backup.BackupAgentHelper}</li>
+ </ol>
+
+</div>
+</div>
+
+<p>Android's {@link android.app.backup backup} service allows you to copy your persistent
+application data to a remote "cloud" storage, in order to provide a restore point for the
+application data and settings. If a user performs a factory reset or converts to a new
+Android-powered device, the system automatically restores your backup data when the application
+is re-installed. This way, your users are not required to reproduce their previous data or
+application settings. This process is completely transparent to the user and does not affect the
+functionality or user experience in your application.</p>
+
+<p>Android-powered devices that support the backup service provide a cloud storage area that
+saves your backup data and a backup transport that delivers your data to
+the storage area and back to the device. During a backup
+operation, Android's Backup Manager requests backup data from your application, then delivers it to
+the cloud storage using the backup transport. During a restore operation, the Backup Manager
+retrieves the backup data from the backup transport and returns it to your application
+so it can restore the data to the device. The backup service is <em>not</em> designed for data
+synchronization (you do not have access the backup data, except during a restore operation on the
+device).</p>
+
+<p>The cloud storage used for backup won't necessarily be the same on all Android-powered devices.
+The cloud storage and backup transport may differ between devices and service providers.
+Where the backup data is stored is transparent to your application, but you are assured that your
+application data cannot be read by other applications.</p>
+
+<p class="caution"><strong>Caution:</strong> Because the cloud storage and transport service can
+differ from device to device, Android makes no guarantees about the security of your data while
+using backup. You should be cautious about using backup to store sensitive data, such as usernames
+and passwords.</p>
+
+
+<h2 id="Basics">The Basics</h2>
+
+<p>To backup your application data, you need to implement a backup agent. Your backup
+agent is called by the Backup Manager to provide the data you want to back up. It is also called
+to restore your backup data when the application is re-installed. The Backup Manager handles all
+your data transactions with the cloud storage and your backup agent handles all your data
+transactions on the device.</p>
+
+<p>To implement a backup agent, you must:</p>
+
+<ol>
+ <li>Declare your backup agent in your manifest file with the <a
+href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
+android:backupAgent}</a> attribute.</li>
+ <li>Define a backup agent by either:</p>
+ <ol type="a">
+ <li><a href="#backupAgent">Extending BackupAgent</a>
+ <p>The {@link android.app.backup.BackupAgent} class provides the central interface with
+which your application communicates with the Backup Manager. If you extend this class
+directly, you must override {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()} to handle the backup and restore operations for your data.</p>
+ <p><em>Or</em></p>
+ <li><a href="#backupAgentHelper">Extending BackupAgentHelper</a>
+ <p>The {@link android.app.backup.BackupAgentHelper} class provides a convenient
+wrapper around the {@link android.app.backup.BackupAgent} class, which minimizes the amount of code
+you need to write. In your {@link android.app.backup.BackupAgentHelper}, you must use one or more
+"helper" objects, which automatically backup and restore certain types of data, so that you do not
+need to implement {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}.</p>
+ <p>Android currently provides backup helpers that will backup and restore complete files
+from {@link android.content.SharedPreferences} and <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</p>
+ </li>
+ </ol>
+ </li>
+</ol>
+
+
+
+
+<h2 id="BackupManifest">Declaring the Backup Agent in Your Manifest</h2>
+
+<p>This is the easiest step, so once you've decided on the class name for your backup agent, declare
+it in your manifest with the <a
+href="{@docRoot}guide/topics/manifest/application-element.html#agent">{@code
+android:backupAgent}</a> attribute in the <a
+href="{@docRoot}guide/topics/manifest/application-element.html">{@code
+&lt;application&gt;}</a> tag.</p>
+
+<p>For example:</p>
+
+<pre>
+&lt;manifest ... &gt;
+ &lt;application android:label="MyApplication"
+ <b>android:backupAgent="MyBackupAgent"</b>&gt;
+ &lt;activity ... &gt;
+ ...
+ &lt;/activity&gt;
+ &lt;/application&gt;
+&lt;/manifest&gt;
+</pre>
+
+<p>Another attribute you might want to use is <a
+href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
+android:restoreAnyVersion}</a>. This attribute takes a boolean value to indicate whether you
+want to restore the application data regardless of the current application version compared to the
+version that produced the backup data. (The default value is "{@code false}".) See <a
+href="#RestoreVersion">Checking the Restore Data Version</a> for more information.</p>
+
+<p class="note"><strong>Note:</strong> The backup service and the APIs you must use are
+available only on devices running API Level 8 (Android 2.2) or greater, so you should also
+set your <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code android:minSdkVersion}</a>
+attribute to "8". However, if you implement proper <a
+href="{@docRoot}resources/articles/backward-compatibility.html">backward compatibility</a> in
+your application, you can support this feature for devices running API Level 8 or greater, while
+remaining compatible with older devices.</p>
+
+
+
+
+
+<h2 id="BackupAgent">Extending BackupAgent</h2>
+
+<p>Most applications shouldn't need to extend the {@link android.app.backup.BackupAgent} class
+directly, but should instead <a href="BackupAgentHelper">extend BackupAgentHelper</a> to take
+advantage of the built-in helper classes that automatically backup and restore your files. However,
+you might want to extend {@link android.app.backup.BackupAgent} directly if you need to:</p>
+<ul>
+ <li>Version your data format. For instance, if you anticipate the need to revise the
+format in which you write your application data, you can build a backup agent to cross-check your
+application version during a restore operation and perform any necessary compatibility work if the
+version on the device is different than that of the backup data. For more information, see <a
+href="#RestoreVersion">Checking the Restore Data Version</a>.</li>
+ <li>Instead of backing up an entire file, you can specify the portions of data the should be
+backed up and how each portion is then restored to the device. (This can also help you manage
+different versions, because you read and write your data as unique entities, rather than
+complete files.)</li>
+ <li>Back up data in a database. If you have an SQLite database that you want to restore when
+the user re-installs your application, you need to build a custom {@link
+android.app.backup.BackupAgent} that reads the appropriate data during a backup operation, then
+create your table and insert the data during a restore operation.</li>
+</ul>
+
+<p>If you don't need to perform any of the tasks above and want to back up complete files from
+{@link android.content.SharedPreferences} or <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>, you
+should skip to <a href="BackupAgentHelper">Extending BackupAgentHelper</a>.</p>
+
+
+
+<h3 id="RequiredMethods">Required Methods</h3>
+
+<p>When you create a backup agent by extending {@link android.app.backup.BackupAgent}, you
+must implement the following callback methods:</p>
+
+<dl>
+ <dt>{@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()}</dt>
+ <dd>The Backup Manager calls this method after you <a href="#RequestBackup">request a
+backup</a>. In this method, you read your application data from the device and pass the data you
+want to back up to the Backup Manager, as described below in <a href="#PerformingBackup">Performing
+backup</a>.</dd>
+
+ <dt>{@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}</dt>
+ <dd>The Backup Manager calls this method during a restore operation (you can <a
+href="#RequestRestore">request a restore</a>, but the system automatically performs restore when the
+user re-installs your application). When it calls this method, the Backup Manager delivers your
+backup data, which you then restore to the device, as described below in <a
+href="#PerformingRestore">Performing restore</a>.</dd>
+</dl>
+
+
+
+<h3 id="PerformingBackup">Performing backup</h3>
+
+
+<p>When it's time to back up your application data, the Backup Manager calls your {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method. This is where you must provide your application data to the Backup Manager so
+it can be saved to cloud storage.</p>
+
+<p>Only the Backup Manager can call your backup agent's {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method. Each time that your application data changes and you want to perform a backup,
+you must request a backup operation by calling {@link
+android.app.backup.BackupManager#dataChanged()} (see <a href="#RequestingBackup">Requesting
+Backup</a> for more information). A backup request does not result in an immediate call to your
+{@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method. Instead, the Backup Manager waits for an appropriate time, then performs
+backup for all applications that have requested a backup since the last backup was performed.</p>
+
+<p class="note"><strong>Tip:</strong> While developing your application, you can initiate an
+immediate backup operation from the Backup Manager with the <a
+href="{@docRoot}guide/developing/tools/bmgr.html">bmgr tool</a>.</p>
+
+<p>When the Backup Manager calls your {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method, it passes three parameters:</p>
+
+<dl>
+ <dt>{@code oldState}</dt>
+ <dd>An open, read-only {@link android.os.ParcelFileDescriptor} pointing to the last backup
+state provided by your application. This is not the backup data from cloud storage, but a
+local representation of the data that was backed up the last time {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} was called (as defined by {@code newState}, below, or from {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}&mdash;more about this in the next section). Because {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} does not allow you to read existing backup data in
+the cloud storage, you can use this local representation to determine whether your data has changed
+since the last backup.</dd>
+ <dt>{@code data}</dt>
+ <dd>A {@link android.app.backup.BackupDataOutput} object, which you use to deliver your backup
+data to the Backup Manager.</dd>
+ <dt>{@code newState}</dt>
+ <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
+you must write a representation of the data that you delivered to {@code data} (a representation
+can be as simple as the last-modified timestamp for your file). This object is
+returned as {@code oldState} the next time the Backup Manager calls your {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method. If you do not write your backup data to {@code newState}, then {@code oldState}
+will point to an empty file next time Backup Manager calls {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()}.</dd>
+</dl>
+
+<p>Using these parameters, you should implement your {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method to do the following:</p>
+
+<ol>
+ <li>Check whether your data has changed since the last backup by comparing {@code oldState} to
+your current data. How you read data in {@code oldState} depends on how you originally wrote it to
+{@code newState} (see step 3). The easiest way to record the state of a file is with its
+last-modified timestamp. For example, here's how you can read and compare a timestamp from {@code
+oldState}:
+ <pre>
+// Get the oldState input stream
+FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
+DataInputStream in = new DataInputStream(instream);
+
+try {
+ // Get the last modified timestamp from the state file and data file
+ long stateModified = in.readLong();
+ long fileModified = mDataFile.lastModified();
+
+ if (stateModified != fileModified) {
+ // The file has been modified, so do a backup
+ // Or the time on the device changed, so be safe and do a backup
+ } else {
+ // Don't back up because the file hasn't changed
+ return;
+ }
+} catch (IOException e) {
+ // Unable to read state file... be safe and do a backup
+}
+</pre>
+ <p>If nothing has changed and you don't need to back up, skip to step 3.</p>
+ </li>
+ <li>If your data has changed, compared to {@code oldState}, write the current data to
+{@code data} to back it up to the cloud storage.
+ <p>You must write each chunk of data as an "entity" in the {@link
+android.app.backup.BackupDataOutput}. An entity is a flattened binary data
+record that is identified by a unique key string. Thus, the data set that you back up is
+conceptually a set of key-value pairs.</p>
+ <p>To add an entity to your backup data set, you must:</p>
+ <ol>
+ <li>Call {@link android.app.backup.BackupDataOutput#writeEntityHeader(String,int)
+writeEntityheader()}, passing a unique string key for the data you're about to write and the data
+size.</li>
+ <li>Call {@link android.app.backup.BackupDataOutput#writeEntityData(byte[],int)
+writeEntityData()}, passing a byte buffer that contains your data and the number of bytes to write
+from the buffer (which should match the size passed to {@link
+android.app.backup.BackupDataOutput#writeEntityHeader(String,int) writeEntityHeader()}).</li>
+ </ol>
+ <p>For example, the following code flattens some data into a byte stream and writes it into a
+single entity:</p>
+ <pre>
+// Create buffer stream and data output stream for our data
+ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
+DataOutputStream outWriter = new DataOutputStream(bufStream);
+// Write structured data
+outWriter.writeString(playerName);
+outWriter.writeInt(playerScore);
+// Send the data to the Backup Manager via the BackupDataOutput
+byte[] buffer = bufStream.toByteArray();
+int len = buffer.length;
+data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);
+data.writeEntityData(buffer, len);
+</pre>
+ <p>Perform this for each piece of data that you want to back up. How you divide your data into
+entities is up to you (and you might use just one entity).</p>
+ </li>
+ <li>Whether or not you perform a backup (in step 2), write a representation of the current data to
+the {@code newState} {@link android.os.ParcelFileDescriptor}. The Backup Manager retains this object
+locally as a representation of the data that is currently backed up. It passes this back to you as
+{@code oldState} the next time it calls {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} so you can determine whether another backup is necessary (as handled in step 1). If you
+do not write the current data state to this file, then
+{@code oldState} will be empty during the next callback.
+ <p>Again, the following example saves a representation of the data using the file's
+last-modified timestamp:</p>
+ <pre>
+FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
+DataOutputStream out = new DataOutputStream(outstream);
+
+long modified = mDataFile.lastModified();
+out.writeLong(modified);
+</pre>
+ </li>
+</ol>
+
+<p class="caution"><strong>Caution:</strong> If your application data is saved to a file, make sure
+that you use synchronized statements while accessing the file so that your backup agent does not
+read the file while an Activity in your application is also writing the file.</p>
+
+
+
+
+<h3 id="PerformingRestore">Performing restore</h3>
+
+<p>When it's time to restore your application data, the Backup Manager calls your backup
+agent's {@link android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()} method. When it calls this method, the Backup Manager delivers your backup data so
+you can restore it onto the device.</p>
+
+<p>Only the Backup Manager can call {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}, which happens automatically when the system installs your application and
+finds existing backup data. However, you can request a restore operation for
+your application by calling {@link
+android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()} (see <a
+href="#RequestingRestore">Requesting restore</a> for more information).</p>
+
+<p class="note"><strong>Note:</strong> While developing your application, you can also request a
+restore operation with the <a href="{@docRoot}guide/developing/tools/bmgr.html">bmgr
+tool</a>.</p>
+
+<p>When the Backup Manager calls your {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()} method, it passes three parameters:</p>
+
+<dl>
+ <dt>{@code data}</dt>
+ <dd>A {@link android.app.backup.BackupDataInput}, which allows you to read your backup
+data.</dd>
+ <dt>{@code appVersionCode}</dt>
+ <dd>An integer representing the value of your application's <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
+manifest attribute, as it was when this data was backed up. You can use this to cross-check the
+current application version and determine if the data format is compatible. For more
+information about using this to handle different versions of restore data, see the section
+below about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</dd>
+ <dt>{@code newState}</dt>
+ <dd>An open, read/write {@link android.os.ParcelFileDescriptor} pointing to a file in which
+you must write the final backup state that was provided with {@code data}. This object is
+returned as {@code oldState} the next time {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} is called. Recall that you must also write the same {@code newState} object in the
+{@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} callback&mdash;also doing it here ensures that the {@code oldState} object given to
+{@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} is valid even the first time {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} is called after the device is restored.</dd>
+</dl>
+
+<p>In your implementation of {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} to iterate
+through all entities in the data set. For each entity found, do the following:</p>
+
+<ol>
+ <li>Get the entity key with {@link android.app.backup.BackupDataInput#getKey()}.</li>
+ <li>Compare the entity key to a list of known key values that you should have declared as static
+final strings inside your {@link android.app.backup.BackupAgent} class. When the key matches one of
+your known key strings, enter into a statement to extract the entity data and save it to the device:
+ <ol>
+ <li>Get the entity data size with {@link
+android.app.backup.BackupDataInput#getDataSize()} and create a byte array of that size.</li>
+ <li>Call {@link android.app.backup.BackupDataInput#readEntityData(byte[],int,int)
+readEntityData()} and pass it the byte array, which is where the data will go, and specify the
+start offset and the size to read.</li>
+ <li>Your byte array is now full and you can read the data and write it to the device
+however you like.</li>
+ </ol>
+ </li>
+ <li>After you read and write your data back to the device, write the state of your data to the
+{@code newState} parameter the same as you do during {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()}.
+</ol>
+
+<div class="special">
+<p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a
+href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code
+ExampleAgent}</a> class in the <a
+href="{@docRoot}}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
+application.</p>
+</div>
+
+
+
+
+
+
+<h2 id="BackupAgentHelper">Extending BackupAgentHelper</h2>
+
+<p>You should build your backup agent using {@link android.app.backup.BackupAgentHelper} if you want
+to back up complete files (from either {@link android.content.SharedPreferences} or <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>).
+Building your backup agent with {@link android.app.backup.BackupAgentHelper} requires far less
+code than extending {@link android.app.backup.BackupAgent}, because you don't have to implement
+{@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}.</p>
+
+<p>Your implementation of {@link android.app.backup.BackupAgentHelper} must
+use one or more backup helpers. A backup helper is a specialized
+component that {@link android.app.backup.BackupAgentHelper} summons to perform backup and
+restore operations for a particular type of data. The Android framework currently provides two
+different helpers:</p>
+<ul>
+ <li>{@link android.app.backup.SharedPreferencesBackupHelper} to backup {@link
+android.content.SharedPreferences} files.</li>
+ <li>{@link android.app.backup.FileBackupHelper} to backup files from <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>.</li>
+</ul>
+
+<p>You can include multiple helpers in your {@link android.app.backup.BackupAgentHelper}, but only
+one helper is needed for each data type. That is, if you have multiple {@link
+android.content.SharedPreferences} files, then you need only one {@link
+android.app.backup.SharedPreferencesBackupHelper}.</p>
+
+<p>For each helper you want to add to your {@link android.app.backup.BackupAgentHelper}, you must do
+the following during your {@link android.app.backup.BackupAgent#onCreate()} method:</p>
+<ol>
+ <li>Instantiate in instance of the desired helper class. In the class constructor, you must
+specify the appropriate file(s) you want to backup.</li>
+ <li>Call {@link android.app.backup.BackupAgentHelper#addHelper(String,BackupHelper) addHelper()}
+to add the helper to your {@link android.app.backup.BackupAgentHelper}.</li>
+</ol>
+
+<p>The following sections describe how to create a backup agent using each of the available
+helpers.</p>
+
+
+
+<h3 id="SharedPreferences">Backing up SharedPreferences</h3>
+
+<p>When you instantiate a {@link android.app.backup.SharedPreferencesBackupHelper}, you must the
+name of one or more {@link android.content.SharedPreferences} files.</p>
+
+<p>For example, to back up a {@link android.content.SharedPreferences} file named
+"user_preferences", a complete backup agent using {@link android.app.backup.BackupAgentHelper} looks
+like this:</p>
+
+<pre>
+public class MyPrefsBackupAgent extends BackupAgentHelper {
+ // The name of the SharedPreferences file
+ static final String PREFS = "user_preferences";
+
+ // A key to uniquely identify the set of backup data
+ static final String PREFS_BACKUP_KEY = "prefs";
+
+ // Allocate a helper and add it to the backup agent
+ void onCreate() {
+ SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS);
+ addHelper(PREFS_BACKUP_KEY, helper);
+ }
+}
+</pre>
+
+<p>That's it! That's your entire backup agent. The {@link
+android.app.backup.SharedPreferencesBackupHelper} includes all the code
+needed to backup and restore a {@link android.content.SharedPreferences} file.</p>
+
+<p>When the Backup Manager calls {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()}, {@link android.app.backup.BackupAgentHelper} calls your backup helpers to perform
+backup and restore for your specified files.</p>
+
+<p class="note"><strong>Note:</strong> {@link android.content.SharedPreferences} are threadsafe, so
+you can safely read and write the shared preferences file from your backup agent and
+other activities.</p>
+
+
+
+<h3 id="Files">Backing up other files</h3>
+
+<p>When you instantiate a {@link android.app.backup.FileBackupHelper}, you must include the name of
+one or more files that are saved to your application's <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>
+(as specified by {@link android.content.ContextWrapper#getFilesDir()}, which is the same
+location where {@link android.content.Context#openFileOutput(String,int) openFileOutput()} writes
+files).</p>
+
+<p>For example, to backup two files named "scores" and "stats," a backup agent using {@link
+android.app.backup.BackupAgentHelper} looks like this:</p>
+
+<pre>
+public class MyFileBackupAgent extends BackupAgentHelper {
+ // The name of the SharedPreferences file
+ static final String TOP_SCORES = "scores";
+ static final String PLAYER_STATS = "stats";
+
+ // A key to uniquely identify the set of backup data
+ static final String FILES_BACKUP_KEY = "myfiles";
+
+ // Allocate a helper and add it to the backup agent
+ void onCreate() {
+ FileBackupHelper helper = new FileBackupHelper(this, TOP_SCORES, PLAYER_STATS);
+ addHelper(FILES_BACKUP_KEY, helper);
+ }
+}
+</pre>
+
+<p>The {@link android.app.backup.FileBackupHelper} includes all the code necessary to backup and
+restore files that are saved to your application's <a
+href="{@docRoot}guide/topics/data/data-storage.html#filesInternal">internal storage</a>..</p>
+
+<p>However, reading and writing to files on internal storage is <strong>not threadsafe</strong>. To
+ensure that your backup agent does not read or write your files at the same time as your activities,
+you must use synchronized statements each time you perform a read or write. For example,
+in any Activity where you read and write the file, you need an object to use as the intrinsic
+lock for the synchronized statements:</p>
+
+<div class="sidebox-wrapper">
+<div class="sidebox">
+<p><strong>Interesting Fact:</strong></p>
+<p>A zero-length array is lighter-weight than a normal Object, so it's great for an
+intrinsic lock.</p>
+</div>
+</div>
+
+<pre>
+// Object for intrinsic lock
+static final Object[] sDataLock = new Object[0];
+</pre>
+
+<p>Then create a synchronized statement with this lock each time you read or write the files. For
+example, here's a synchronized statement for writing the latest score in a game to a file:</p>
+
+<pre>
+try {
+ synchronized (MyActivity.sDataLock) {
+ File dataFile = new File({@link android.content.Context#getFilesDir()}, TOP_SCORES);
+ RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
+ raFile.writeInt(score);
+ }
+} catch (IOException e) {
+ Log.e(TAG, "Unable to write to file");
+}
+</pre>
+
+<p>You should synchronize your read statements with the same lock.</p>
+
+<p>Then, in your {@link android.app.backup.BackupAgentHelper}, you must override {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()} to synchronize the backup and restore operations with the same
+intrinsic lock. For example, the {@code MyFileBackupAgent} example from above needs the following
+methods:</p>
+
+<pre>
+&#64;Override
+public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+ ParcelFileDescriptor newState) throws IOException {
+ // Hold the lock while the FileBackupHelper performs backup
+ synchronized (MyActivity.sDataLock) {
+ super.onBackup(oldState, data, newState);
+ }
+}
+
+&#64;Override
+public void onRestore(BackupDataInput data, int appVersionCode,
+ ParcelFileDescriptor newState) throws IOException {
+ // Hold the lock while the FileBackupHelper restores the file
+ synchronized (MyActivity.sDataLock) {
+ super.onRestore(data, appVersionCode, newState);
+ }
+}
+</pre>
+
+<p>That's it. All you need to do is add your {@link android.app.backup.FileBackupHelper} in the
+{@link android.app.backup.BackupAgent#onCreate()} method and override {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} and {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
+onRestore()} to synchronize read and write operations.</p>
+
+<div class="special">
+<p>For an example implementation of {@link
+android.app.backup.BackupAgentHelper} with {@link android.app.backup.FileBackupHelper}, see the
+{@code FileHelperExampleAgent} class in the <a
+href="{@docRoot}resources/samples/BackupRestore/index.html">Backup and Restore</a> sample
+application.</p>
+</div>
+
+
+
+
+
+
+<h2 id="RestoreVersion">Checking the Restore Data Version</h2>
+
+<p>When the Backup Manager saves your data to cloud storage, it automatically includes the version
+of your application, as defined by your manifest file's <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
+attribute. Before the Backup Manager calls your backup agent to restore your data, it
+looks at the <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code
+android:versionCode}</a> of the installed application and compares it to the value
+recorded in the restore data set. If the version recorded in the restore data set is
+<em>newer</em> than the application version on the device, then the user has downgraded their
+application. In this case, the Backup Manager will abort the restore operation for your application
+and not call your {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
+method, because the restore set is considered meaningless to an older version.</p>
+
+<p>You can override this behavior with the <a
+href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
+android:restoreAnyVersion}</a> attribute. This attribute is either "{@code true}" or "{@code
+false}" to indicate whether you want to restore the application regardless of the restore set
+version. The default value is "{@code false}". If you define this to be "{@code true}" then the
+Backup Manager will ignore the <a
+href="{@docRoot}guide/topics/manifest/manifest-element.html#vcode">{@code android:versionCode}</a>
+and call your {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
+method in all cases. In doing so, you can manually check for the version difference in your {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
+method and take any steps necessary to make the data compatible if the versions conflict.</p>
+
+<p>To help you handle different versions during a restore operation, the {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
+method passes you the version code included with the restore data set as the {@code appVersionCode}
+parameter. You can then query the current application's version code with the {@link
+android.content.pm.PackageInfo#versionCode PackageInfo.versionCode} field. For example:</p>
+
+<pre>
+PackageInfo info;
+try {
+ String name = {@link android.content.ContextWrapper#getPackageName() getPackageName}();
+ info = {@link android.content.ContextWrapper#getPackageManager
+getPackageManager}().{@link android.content.pm.PackageManager#getPackageInfo(String,int)
+getPackageInfo}(name,0);
+} catch (NameNotFoundException nnfe) {
+ info = null;
+}
+
+int version;
+if (info != null) {
+ version = info.versionCode;
+}
+</pre>
+
+<p>Then simply compare the {@code version} acquired from {@link android.content.pm.PackageInfo}
+to the {@code appVersionCode} passed into {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}.
+</p>
+
+<p class="caution"><strong>Caution:</strong> Be certain you understand the consequences of setting
+<a href="{@docRoot}guide/topics/manifest/application-element.html#restoreany">{@code
+android:restoreAnyVersion}</a> to "{@code true}" for your application. If each version of your
+application that supports backup does not properly account for variations in your data format during
+{@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()},
+then the data on the device could be saved in a format incompatible with the version currently
+installed on the device.</p>
+
+
+
+<h2 id="RequestingBackup">Requesting Backup</h2>
+
+<p>You can request a backup operation at any time by calling {@link
+android.app.backup.BackupManager#dataChanged()}. This method notifies the Backup Manager that you'd
+like to backup your data using your backup agent. The Backup Manager then calls your backup
+agent's {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()} method at an opportune time in the future. Typically, you should
+request a backup each time your data changes (such as when the user changes an application
+preference that you'd like to back up). If you call {@link
+android.app.backup.BackupManager#dataChanged()} several times consecutively, before the Backup
+Manager requests a backup from your agent, your agent still receives just one call to {@link
+android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,ParcelFileDescriptor)
+onBackup()}.</p>
+
+<p class="note"><strong>Note:</strong> While developing your application, you can request a
+backup and initiate an immediate backup operation with the <a
+href="{@docRoot}guide/developing/tools/bmgr.html">bmgr
+tool</a>.</p>
+
+
+<h2 id="RequestingRestore">Requesting Restore</h2>
+
+<p>During the normal life of your application, you shouldn't need to request a restore operation.
+They system automatically checks for backup data and performs a restore when your application is
+installed. However, you can manually request a restore operation by calling {@link
+android.app.backup.BackupManager#requestRestore(RestoreObserver) requestRestore()}, if necessary. In
+which case, the Backup Manager calls your {@link
+android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor) onRestore()}
+implementation, passing the data from the current set of backup data.</p>
+
+<p class="note"><strong>Note:</strong> While developing your application, you can request a
+restore operation with the <a href="{@docRoot}guide/developing/tools/bmgr.html">bmgr
+tool</a>.</p>
+