Я начал работать над этим. Пока я публикую свои результаты в качестве ответа "сообщества вики" по двум причинам: во-первых, если кто-то хочет присоединиться, есть место для разговора; во-вторых, если я отойду от этого проекта, у кого-то еще будут советы начать работать.
Логика резервного копирования на хосте полностью содержится в https://github.com/android/platform_system_core/blob/master/adb/commandline.cpp в названной функции backup
. Функция очень проста: она проверяет параметры командной строки, отправляет команду, в основном, как есть, демону adb на телефоне и записывает вывод телефона в файл. Нет даже проверки ошибок: если, например, вы отказываетесь от резервного копирования на телефоне, adb
просто записывает пустой файл.
На телефоне логика резервного копирования начинается service_to_fd()
с https://github.com/android/platform_system_core/blob/master/adb/services.cpp . Функция определяет, что команда от хоста есть "backup"
, и передает команду unparsed /system/bin/bu
, которая является тривиальным сценарием оболочки, который запускается com.android.commands.bu.Backup
как основной класс нового процесса приложения Android. Это вызывает, ServiceManager.getService("backup")
чтобы получить службу резервного копирования как IBackupManager
, и вызывает IBackupManager.fullBackup()
, передавая ему все еще неиспользованный файловый дескриптор (очень косвенно), связанный с backup.ab
файлом на хосте.
Управление передается fullBackup()
в com.android.server.backup.BackupManagerService , который выскакивает в GUI, запрашивая у пользователя подтверждение / отклонение резервной копии. Когда пользователь делает это, acknowledgeFullBackupOrRestore()
(тот же файл) вызывается. Если пользователь одобрил запрос, acknowledgeFullBackupOrRestore()
выясняет, зашифрована ли резервная копия, и передает сообщение BackupHandler
(тот же файл), BackupHandler
затем создает экземпляр и запускает PerformAdbBackupTask
( тот же файл, строка 4004 на момент написания)
Наконец, мы начинаем генерировать вывод тамPerformAdbBackupTask.run()
, между строки 4151 и 4330 .
Сначала run()
записывается заголовок, который состоит из 4 или 9 строк ASCII:
"ANDROID BACKUP"
- версия формата резервной копии: в настоящее время
"4"
- либо
"0"
если архив не распакован, либо "1"
если
- метод шифрования: в настоящее время либо
"none"
или"AES-256"
- (если зашифровано), "соль пароля пользователя", закодированная в шестнадцатеричном виде, все заглавные буквы
- (если зашифровано), "соль контрольной суммы главного ключа", закодированная в шестнадцатеричном виде, все заглавные буквы
- (если зашифровано), «количество использованных раундов PBKDF2» как десятичное число: в настоящее время
"10000"
- (если зашифровано), «IV пользовательского ключа» закодировано в шестнадцатеричном виде, все заглавные буквы
- (если зашифровано), «главный IV + блоб ключа, зашифрованный ключом пользователя», закодированный в шестнадцатеричном виде, все заглавные буквы
Фактические данные резервного копирования следующим образом , либо в виде ( в зависимости от сжатия и шифрования) tar
, deflate(tar)
, encrypt(tar)
, или encrypt(deflate(tar))
.
TODO : запишите путь к коду, который генерирует вывод tar - вы можете просто использовать tar, если записи находятся в правильном порядке (см. Ниже).
Формат архива тар
Данные приложения хранятся в каталоге app /, начиная с файла _manifest, APK (если требуется) в /, файлы приложения в f /, базы данных в db / и общие настройки в sp /. Если вы запросили резервное копирование внешнего хранилища (используя опцию -shared), в архиве также будет каталог shared /, содержащий файлы внешнего хранилища.
$ tar tvf mybackup.tar
-rw------- 1000/1000 1019 2012-06-04 16:44 apps/org.myapp/_manifest
-rw-r--r-- 1000/1000 1412208 2012-06-02 23:53 apps/org.myapp/a/org.myapp-1.apk
-rw-rw---- 10091/10091 231 2012-06-02 23:41 apps/org.myapp/f/share_history.xml
-rw-rw---- 10091/10091 0 2012-06-02 23:41 apps/org.myapp/db/myapp.db-journal
-rw-rw---- 10091/10091 5120 2012-06-02 23:41 apps/org.myapp/db/myapp.db
-rw-rw---- 10091/10091 1110 2012-06-03 01:29 apps/org.myapp/sp/org.myapp_preferences.xml
Детали шифрования
- Ключ AES 256 получен из резервного пароля шифрования с использованием 10000 раундов PBKDF2 со случайно сгенерированной 512-битной солью.
- Главный ключ AES 256 генерируется случайным образом
- Главный ключ 'контрольная сумма' генерируется путем запуска главного ключа через 10000 раундов PBKDF2 с новой случайно сгенерированной 512-битной солью.
- Случайное резервное копирование шифрования IV генерируется.
- IV, главный ключ и контрольная сумма объединяются и шифруются ключом, полученным в 1. Полученный большой двоичный объект сохраняется в заголовке в виде шестнадцатеричной строки.
- Фактические данные резервной копии шифруются с помощью мастер-ключа и добавляются в конец файла.
Пример реализации кода пакета / распаковки (производит / использует) архивы tar: https://github.com/nelenkov/android-backup-extractor
Некоторые подробности здесь: http://nelenkov.blogspot.com/2012/06/unpacking-android-backups.html
Скрипты Perl для упаковки / распаковки и исправления испорченных архивов:
http://forum.xda-developers.com/showthread.php?p=27840175#post27840175