Testing Android Device-to-Device Transfer

Android has supported autoBackup for apps by default since Android 6, enabling users to backup app data automatically to Google Drive. Configuration for this backup could be added with backup rules, or it could be turned off entirely with autoBackup=false. This also allowed apps to configure device-to-device transfer (D2D transfer), which provided users a way to easily transfer their data between their old and new phones. Since these processes were governed by the same rules, it was easy to control both, but apps couldn’t take advantage of device-to-device transfer’s differences to transfer more data than would be allowed by the 25MB cloud storage limit. Once an app starts targeting Android 12 or above, however, Android introduces the ability to configure device-to-device transfer separately from Google Drive backup and removes the ability to turn off device-to-device transfer using autoBackup=false. With these changes, it’s important to test both types of backup separately since their behavior no longer matches. 

Testing the different kinds of backup

Testing cloud backup is fairly simple. The Android developer’s website has clear documentation that makes it easy to backup and restore your app using adb. However, it’s less clear how device-to-device transfer can be tested. Fortunately, the command mentioned in Android’s documentation for making sure the device has the transport for cloud backup enabled provides a hint.
When I run adb shell bmgr list transports on my phone it returns this:

  android/com.android.internal.backup.LocalTransport
  com.google.android.gms/.backup.migrate.service.D2dTransport
* com.google.android.gms/.backup.BackupTransportService

By changing the transport, testing device-to-device transport is possible. Unfortunately, it’s not as smooth as testing cloud backup because you can’t directly restore. Logcat displays the warning W/Backup: [D2dTransport] Can't restore from D2d Transport. Still, this approach allows you to at least see which files are being backed up without actually using device-to-device transfer to transfer all your data to a new device.

Commands for testing device-to-device transfer

  1. List transports to make sure you have device-to-device transfer available
    adb shell bmgr list transports
  2. Switch to the D2D transport listed
    adb shell bmgr transport com.google.android.gms/.backup.migrate.service.D2dTransport
  3. The output of adb shell bmgr list transports should change to:
        android/com.android.internal.backup.LocalTransport
      * com.google.android.gms/.backup.migrate.service.D2dTransport
        com.google.android.gms/.backup.BackupTransportService
  4. Make sure backup is enabled on the device as mentioned in Android’s testing backup documentation
    1. If you switch transports before you enable backup, you can avoid setting up a Google account to back up to on an emulator. However, if you want to test backup, you’ll still need to do that.
  5. Run the same backup commands you would for testing cloud backup while watching Logcat
    adb shell bmgr backupnow <your-package-name>
  6. Assuming you have something to back up, you should see progress towards backing up just like you would for cloud backup which should complete with
    Package <your-package-name> with result: Success
    Backup finished with result: Success
  7. Search for backup in Logcat
  8. Make sure that the correct information was backed up and that the backup was successful. For instance, if you only wanted to transfer shared preferences, you might see something like the below output:
    D/KeyValueBackupTask: Starting full backups for: [<your-package-name>]
    D/Backup: [D2dTransport] Moved from state 0 to 1
    I/Backup: [D2dTransport] performFullBackup : PackageInfo{<your-package-info>}
    I/FullBackup_native: measured [/data/data/<your-package-name>/shared_prefs] at 0
    I/FullBackup_native: measured [/data/data/<your-package-name>/shared_prefs/test_preferences.xml] at 1024
    I/file_backup_helper:    Name: apps/<your-package-name>/_manifest
    I/FullBackup_native: measured [/data/cache/backup_stage/_manifest] at 1536
    D/BackupManagerService: Calling doFullBackup() on <your-package-name>
    I/FullBackup_native: measured [/data/data/<your-package-name>/shared_prefs] at 0
    I/file_backup_helper:    Name: apps/<your-package-name>/sp/test_preferences.xml
    I/FullBackup_native: measured [/data/data/<your-package-name>/shared_prefs/test_preferences.xml] at 1024
    D/Backup: [D2dTransport] backup finished
    D/Backup: [D2dTransport] finishBackup from: 1, package: <your-package-name>
    D/Backup: [D2dTransport] Moved from state 1 to 0
    I/PFTBT: Full backup completed with status: 0
    I/PFTBT: Full data backup pass finished.
  9. Switch back to the cloud transport
    adb shell bmgr transport com.google.android.gms/.backup.BackupTransportService

Bonus: Disabling device-to-device transfer

While it’s certainly more difficult, it’s still possible for an application to disable device-to-device transfer. Since Android 12 allows you to configure device-to-device transfer, you can simply disable all the types of data that are backed up. For example:

<data-extraction-rules>
    <cloud-backup disableIfNoEncryptionCapabilities="true">
        <exclude domain="file" path="."/>
        <exclude domain="database" path="."/>
        <exclude domain="sharedpref" path="."/>
        <exclude domain="external" path="."/>
        <exclude domain="root" path="."/>
    </cloud-backup>
    <device-transfer>
        <exclude domain="file" path="."/>
        <exclude domain="database" path="."/>
        <exclude domain="sharedpref" path="."/>
        <exclude domain="external" path="."/>
        <exclude domain="root" path="."/>
    </device-transfer>
</data-extraction-rules>

You can test that device-to-device transfer is fully disabled by following the generic directions above. However, the results will be quite different.

Instead of seeing backup progress, you may receive this error message:
Package <your-package-name> with result: Transport rejected package because it wasn't able to process it at the time. When you search for backup in Logcat, you should look for something similar to the following output:

D/KeyValueBackupTask: Starting full backups for: [<your-package-name>]
D/Backup: [D2dTransport] Moved from state 0 to 1
I/Backup: [D2dTransport] performFullBackup : PackageInfo{<your-package-info>}
I/FullBackup_native: measured [/data/user_de/0/<your-package-name>] at 0
I/FullBackup_native: measured [/data/user_de/0/<your-package-name>/files] at 0
I/FullBackup_native: measured [/data/user_de/0/<your-package-name>/databases] at 0
I/FullBackup_native: measured [/data/user_de/0/<your-package-name>/shared_prefs] at 0
D/Backup: [D2dTransport] Declining backup of size 0
I/Backup: [D2dTransport] Canceling full backup of <your-package-name>
D/Backup: [D2dTransport] finishBackup from: 1, package: <your-package-name>
I/Backup: [D2dTransport] Deleting partial backup data file: <your-package-name> due to error: 5
D/Backup: [D2dTransport] Moved from state 1 to 0
I/PFTBT: Transport rejected backup of <your-package-name>, skipping
W/ActivityManager: Unbinding backup agent with no active backup
I/PFTBT: Full backup completed with status: 0
I/PFTBT: Full data backup pass finished.

Since there’s no data to be backed up, the device-to-device transport skips the app.

Hopefully, you’ll be able to use this guide to easily test device-to-device transfer, allowing you to make sure that your config is set up correctly for both types of backup.

No Comments, Be The First!

Your email address will not be published.