How to deal with backup & restore on Android

9da5d5cc4b6a9f28058152e28364b02a?s=47 Marco Gomiero
December 17, 2016

How to deal with backup & restore on Android

One of the worst things is to lose all your data when you change a phone or when you reset it. With this talk we'll see how to deal with this problem and how to secure your application's data.

9da5d5cc4b6a9f28058152e28364b02a?s=128

Marco Gomiero

December 17, 2016
Tweet

Transcript

  1. How To Deal with Backup & Restore on Android

  2. Agenda 1. Backup Importance 2. Backup Options by Google 3.

    Custom Backup
  3. Marco Gomiero Computer Engineering Student @marcoGomier (Free Time) Android Developer

    github.com/prof18 marco.gomiero.93@gmail.com
  4. 1. Backup Importance

  5. Typical Scenario A fantastic brand new phone A fantastic ROM

    that I must try
  6. I’ve lost all my data!

  7. 2. Backup Options By Google

  8. Backup Options 1. Auto Backup 2. Key/Value Backup

  9. Auto Backup

  10. Overview ▣ Available from API 23 ▣ Upload data to

    Google Drive
  11. Google Drive App

  12. Google Drive App

  13. Overview ▣ Available from API 23 ▣ Upload data to

    Google Drive ▣ One backup for each device ▣ Max 25 MB per app
  14. What files are backed up? Auto Backup includes files in

    most of the directories that are assigned to the app by the system: ▣ Shared preferences files ▣ Files in the directory returned by: □ getFilesDir() □ getDatabasePath(String) □ getExternalFilesDir(String) ▣ Files in directories created with getDir(String, int). Every temporary cached file is excluded from the backup
  15. Restore Data is restored during ▣ App install from Play

    Store ▣ Device setup The restore is performed after installation, before the app is available to be launched by the user
  16. How to enable? Add the following attribute in the Manifest

    <application ... android:allowBackup="true"> </application> Very simple!
  17. How to enable? You can write custom rules on backup

    via xml.. <application … android:fullBackupContent="@xml/my_backup_rules"> </application> <full-backup-content> <include domain=["file" | "database" | "sharedpref" | "external" | "root"] path="string" /> <exclude domain=["file" | "database" | "sharedpref" | "external" | "root"] path="string" /> </full-backup-content>
  18. But.. ?

  19. Backup Conditions ▣ The user has enabled backup on device

    ▣ At least 24 hours have elapsed from previous backup ▣ The device is idle and charging ▣ The device is connected to a WiFi Network
  20. And if i wanna change my device right now?

  21. Conclusions Auto Backup is perfect for settings backup, not for

    complete data backup
  22. Key/Value Backup

  23. Overview ▣ Available from API 8 ▣ An alternative of

    Auto Backup for API lower than 23 ▣ Need more work :(
  24. How to deal with fragmentation? ▣ You can move to

    full-data backup by settings android:fullBackupOnly="true" in the Manifest ▣ On API 22 and lower, the app ignores this value and perform Key/Value Backup ▣ On API 23 and higher the app perform Auto Backup
  25. How to implement? Declare backup agent in the Manifest <application

    … android:backupAgent="MyBackupAgent"> </application>
  26. How to implement? Register the application with Android Backup Service

  27. How to implement?

  28. How to implement? Declare Backup Service KEY in the Manifest

    <application … <meta-data android:name="com.google.android.backup.api_key" android:value="AEdPqrEAAAAIDaYEVgU6DJnyJdBmU7KLH3kszDXLv _4DIsEIyQ" /> </application>
  29. How to implement? Define a Backup Agent by either: ▣

    Extending BackupAgent ▣ Extending BackupAgentHelper Spoiler: with the helper you’ll write far less code!
  30. BackupAgent Need to Override ▣ onBackup ▣ onRestore

  31. BackupAgentHelper Two different helper: ▣ SharedPreferencesBackupHelper ▣ FileBackupHelper

  32. SharedPreferencesBackupHelper 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 @Override public void onCreate() { SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS); addHelper(PREFS_BACKUP_KEY, helper); } }
  33. BackupAgentHelper Keep in mind that: SharedPreferenceBackupHelper is threadsafe, FileBackupHelper isn’t

  34. So, have i found what i need? ?

  35. No!

  36. Why? ▣ Only 5 MB per app Also Key Value

    Backup is perfect for settings backup
  37. 3. Custom Backup

  38. Custom Backup ▣ Database Dump ▣ Local Backup/Restore ▣ Online

    Backup/Restore with Google Drive API
  39. public void backup(String outFileName) { //database path final String inFileName

    = mContext.getDatabasePath(DATABASE_NAME).toString(); try { File dbFile = new File(inFileName); FileInputStream fis = new FileInputStream(dbFile); // Open the empty db as the output stream OutputStream output = new FileOutputStream(outFileName); // Transfer bytes from the input file to the output file byte[] buffer = new byte[1024]; int length; while ((length = fis.read(buffer)) > 0) { output.write(buffer, 0, length); } // Close the streams output.flush(); output.close(); fis.close(); Toast.makeText(mContext, "Backup Completed", Toast.LENGTH_SHORT).show(); } catch (Exception e) { Toast.makeText(mContext, "Unable to backup database. Retry", Toast.LENGTH_SHORT).show(); e.printStackTrace(); } }
  40. Where to save? Custom folder for the app: File folder

    = new File(Environment.getExternalStorageDirectory() + File.separator + getResources().getString(R.string.app_name)); boolean success = true; if (!folder.exists()) success = folder.mkdirs(); if (success) { //perform backup }
  41. public void importDB(String inFileName) { final String outFileName = mContext.getDatabasePath(DATABASE_NAME).toString();

    try { File dbFile = new File(inFileName); FileInputStream fis = new FileInputStream(dbFile); // Open the empty db as the output stream OutputStream output = new FileOutputStream(outFileName); // Transfer bytes from the input file to the output file byte[] buffer = new byte[1024]; int length; while ((length = fis.read(buffer)) > 0) { output.write(buffer, 0, length); } // Close the streams output.flush(); output.close(); fis.close(); Toast.makeText(mContext, "Import Completed", Toast.LENGTH_SHORT).show(); } catch (Exception e) { Toast.makeText(mContext, "Unable to import database. Retry", Toast.LENGTH_SHORT).show(); e.printStackTrace(); } }
  42. Save to Google Drive @Override public void onConnected(Bundle connectionHint) {

    Log.i(TAG, "API client connected."); //when the client is connected i have two possibility: backup (bckORrst -> true) or restore (bckORrst -> false) if (bckORrst) saveFileToDrive(); else { IntentSender intentSender = Drive.DriveApi .newOpenFileActivityBuilder() .setMimeType(new String[]{"application/db"}) .build(mGoogleApiClient); try { startIntentSenderForResult(intentSender, REQUEST_CODE_OPENER, null, 0, 0, 0); Log.i(TAG, "Open File Intent send"); } catch (IntentSender.SendIntentException e) { Log.w(TAG, "Unable to send Open File Intent", e); } } }
  43. private void saveFileToDrive() { Drive.DriveApi.newDriveContents(mGoogleApiClient).setResultCallback(new ResultCallback<DriveApi.DriveContentsResult>() { @Override public void

    onResult(@NonNull DriveApi.DriveContentsResult driveContentsResult) { if (!driveContentsResult.getStatus().isSuccess()) { //deal with failure } try { …. //same as before, except for: OutputStream outputStream = driveContentsResult.getDriveContents().getOutputStream(); …. } //drive file metadata MetadataChangeSet metadataChangeSet = new MetadataChangeSet.Builder() .setTitle("database_backup.db") .setMimeType("application/db") .build(); // Create an intent for the file chooser, and start it. IntentSender intentSender = Drive.DriveApi .newCreateFileActivityBuilder() .setInitialMetadata(metadataChangeSet) .setInitialDriveContents(driveContentsResult.getDriveContents()) .build(mGoogleApiClient); startIntentSenderForResult(intentSender, REQUEST_CODE_CREATOR, null, 0, 0, 0); } ….
  44. Import from Google Drive @Override public void onConnected(Bundle connectionHint) {

    Log.i(TAG, "API client connected."); //when the client is connected i have two possibility: backup (bckORrst -> true) or restore (bckORrst -> false) if (bckORrst) saveFileToDrive(); else { IntentSender intentSender = Drive.DriveApi .newOpenFileActivityBuilder() .setMimeType(new String[]{"application/db"}) .build(mGoogleApiClient); try { startIntentSenderForResult(intentSender, REQUEST_CODE_OPENER, null, 0, 0, 0); Log.i(TAG, "Open File Intent send"); } catch (IntentSender.SendIntentException e) { Log.w(TAG, "Unable to send Open File Intent", e); } } }
  45. Import from Google Drive @Override protected void onActivityResult(final int requestCode,

    final int resultCode, final Intent data) { switch (requestCode) { case REQUEST_CODE_CREATOR: // Called after a file is saved to Drive. if (resultCode == RESULT_OK) { Log.i(TAG, "Backup successfully saved."); Toast.makeText(this, "Backup successufly loaded!", Toast.LENGTH_SHORT).show(); } break; case REQUEST_CODE_OPENER: if (resultCode == RESULT_OK) { DriveId driveId = data.getParcelableExtra(OpenFileActivityBuilder.EXTRA_RESPONSE_DRIVE_ID); DriveFile file = driveId.asDriveFile(); importFromDrive(file); } } }
  46. private void importFromDrive(DriveFile dbFile) { dbFile.open(mGoogleApiClient, DriveFile.MODE_READ_ONLY, null).setResultCallback(new ResultCallback<DriveApi.DriveContentsResult>() {

    @Override public void onResult(@NonNull DriveApi.DriveContentsResult driveContentsResult) { if (!driveContentsResult.getStatus().isSuccess()) { //deal with failure } // DriveContents object contains pointers to the actual byte stream DriveContents contents = driveContentsResult.getDriveContents(); try { ParcelFileDescriptor parcelFileDescriptor = contents.getParcelFileDescriptor(); FileInputStream fileInputStream = new FileInputStream(parcelFileDescriptor.getFileDescriptor()); // Open the empty db as the output stream OutputStream output = new FileOutputStream(inFileName); …. }
  47. Check the source code on GitHub github.com/prof18/Database-Backup-Restore

  48. Reference: ▣ developer.android.com/guide/topics/data/aut obackup.html ▣ developer.android.com/guide/topics/data/ke yvaluebackup.html ▣ developers.google.com/drive/android/

  49. Thanks! Any questions? @marcoGomier github.com/prof18 marco.gomiero.93@gmail.com