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