Cannot restore an adb backup due to a tarball with a broken header I have two devices that have Android 5.0.2 and 6.0.1 respectively. I would like to migrate some non-cloud apps from the device with the older Android version to the new one using adb. The backing up command is simple:

adb backup -apk -f foo.bar.baz.ab foo.bar.baz


Now, after connecting the device with the newer Android version, the following command is expected to work:

adb restore foo.bar.baz.ab


Unfortunately it isn't. As usual, the restoring process fails silently just reporting that the restoring process is ended. Actually nothing really happens. Here are the logs:

adb logcat -s BackupManagerService



  08-27 01:02:44.100  1300  2300 I BackupManagerService: Beginning full restore...
  08-27 01:02:44.100  1300  2300 D BackupManagerService: Starting restore confirmation UI, token=1956031088
  08-27 01:02:44.120  1300  2300 D BackupManagerService: Waiting for full restore completion...
  08-27 01:02:45.650  1300  2450 D BackupManagerService: acknowledgeFullBackupOrRestore : token=1956031088 allow=true
  08-27 01:02:45.660  1300 18181 I BackupManagerService: --- Performing full-dataset restore ---
  08-27 01:02:45.680  1300 18181 I BackupManagerService: Package foo.bar.baz not installed; requiring apk in dataset
  08-27 01:02:45.680  1300 18181 D BackupManagerService: APK file; installing
  08-27 01:02:45.680  1300 18181 D BackupManagerService: Installing from backup: foo.bar.baz
  08-27 01:02:45.690  1300 18181 E BackupManagerService: Unable to transcribe restored apk for install
  08-27 01:02:45.690  1300 18181 E BackupManagerService: Parse error in header: Invalid number in header: 'я╛В' for radix 8
  08-27 01:02:45.710  1300 18181 W BackupManagerService: io exception on restore socket read
  08-27 01:02:45.710  1300 18181 W BackupManagerService: java.io.IOException: Invalid number in header: 'я╛В' for radix 8
  08-27 01:02:45.710  1300 18181 W BackupManagerService:  at com.android.server.backup.BackupManagerService$PerformAdbRestoreTask.extractRadix(BackupManagerService.java:7380)
  08-27 01:02:45.710  1300 18181 W BackupManagerService:  at com.android.server.backup.BackupManagerService$PerformAdbRestoreTask.readTarHeaders(BackupManagerService.java:7179)
  08-27 01:02:45.710  1300 18181 W BackupManagerService:  at com.android.server.backup.BackupManagerService$PerformAdbRestoreTask.restoreOneFile(BackupManagerService.java:6396)
  08-27 01:02:45.710  1300 18181 W BackupManagerService:  at com.android.server.backup.BackupManagerService$PerformAdbRestoreTask.run(BackupManagerService.java:6254)
  08-27 01:02:45.710  1300 18181 W BackupManagerService:  at java.lang.Thread.run(Thread.java:818)
  08-27 01:02:45.710  1300  2300 I BackupManagerService: Full restore processing complete.
  08-27 01:02:45.720  1300 18181 D BackupManagerService: Full restore pass complete.  


It looks somewhat strange that the same backup format cannot be restored on a newer device. I've also tried to repack the underlying tarball using nelenkov/android-backup-extractor preserving the same file order (tar cvf ... -T files.lst) hoping that the broken header gets repaired. No luck.

What does cause such a backup/restore behavior and how do I resolve the issue to migrate the application from the older device to the newer one? Any help is highly appreciated and thanks in advance.


Android Debug Bridge version 1.0.31
LG Optimus E975, Android 5.0.2, CyanogenMod 12-2015...
Samsung Galaxy S5, Android 6.0.2, flashed to a newer Sprint stock firmware (initially Android 5.0.x earlier)
After a whole day of various experiments with another tools like TitaniumBackup (neither worked nice, TB was only able to restore APKs, not data) I've figured out that specifying the -apk key was the problem. Simply omitting the flag during a backup operation makes it fully restorable.

So my new backup/restore plan became as follows:


device 1: backup data only
device 2: backup APK+data retaining the APK only later (requires nelenkov/android-backup-exractor by Nikolay Elenkov; can be easily built using JDK 1.8.x and Gradle 2.7 (couldn't build it using Gradle 2.7+ and Gradle 3.0+) with simple gradle command)
device 2: restore the APK using adb install
device 2: restore the data using adb restore


Here are the scripts:

backup.sh



#!/bin/bash

set -e

PACKAGE=$1

if [ -z "$PACKAGE" ]; then
    echo no package specified
    exit
fi

echo "&gt;&gt;&gt; Backing up $PACKAGE data..."
adb backup -f "$PACKAGE".DATA.ab $PACKAGE

echo "&gt;&gt;&gt; Backing up $PACKAGE APK..."
adb backup -apk -f "$PACKAGE".APK.ab $PACKAGE

echo "&gt;&gt;&gt; Extracting APK..."
java -jar abe-all.jar unpack "$PACKAGE".APK.ab "$PACKAGE".APK.ab.tar
rm "$PACKAGE".APK.ab
APK_FILENAME=$(basename $(tar tf "$PACKAGE".APK.ab.tar | grep '^apps/'"$PACKAGE"'/a/'))
tar xvf "$PACKAGE".APK.ab.tar -C ./ "apps/$PACKAGE/a/$APK_FILENAME" --strip-components=3
mv "$APK_FILENAME" "$PACKAGE".apk
rm "$PACKAGE".APK.ab.tar

echo
echo "*************"
echo "*** Done ***"
echo "*************"


This script requires a package name as the input parameter and stores an APK and its data as foo.bar.apk and foo.bar.DATA.ab respectively. I also implemented it as a twice-backup script (a device asks for making a backup two times) because I didn't want to re-pack underlying tarballs preserving the original file order just making sure that the DATA.ab file is in its original state.

restore.sh



#!/bin/bash

set -e

PACKAGE=$1

if [ -z "$PACKAGE" ]; then
    echo no package specified
    exit
fi

echo "&gt;&gt;&gt; Installing $PACKAGE APK..."
adb install -r $PACKAGE.apk

echo "&gt;&gt;&gt; Restoring $PACKAGE data..."
adb restore $PACKAGE.DATA.ab

echo
echo "*************"
echo "*** Done ***"
echo "*************"


This script simply installs an APK on a target device and restores its data. The only input parameter is the application package name.

So the overall backup/restore process is:


Connect device #1
Execute backup.sh passing an application package name
Click "Backup..." on the device #1 (one will be asked two times for the data and APK+data backups respectively)
Repeat the previous two steps for other packages if necessary
Disconnect the device #1 and connect the  device #2
Execute restore.sh passing an application package name
Click "Restore..." on the device #2 once asked
Repeat the previous two steps for other packages if necessary