Как протестировать поведение полного резервного копирования Android 6.0?

TL: DR: Как вы успешно используете инструменты командной строки (или что-то еще) для проверки поведения резервного копирования и восстановления Android 6.0, поскольку я не могу заставить их что-либо восстановить?


Так как раньше у меня возникали проблемы с примером приложения из моей книги, пытаясь заставить это работать, я начал с нуля для целей этого вопроса.

Я создал совершенно новый проект от мастера создания нового проекта Android Studio 1.4.1, приняв все соответствующие значения по умолчанию, за исключением того, что я пошел с шаблоном «Empty Activity» и добавил 2 к идентификатору приложения и отображаемому имени. Затем я добавил немного кода к активности, чтобы дать мне некоторые данные о внутреннем хранилище:

 package com.commonsware.myapplication2; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v7.app.AppCompatActivity; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); PreferenceManager .getDefaultSharedPreferences(this) .edit() .putBoolean("foo", true) .apply(); } } 

Я запустил приложение и подтвердил, используя adb shell run-as com.commonsware.myapplication2 ... что файл SharedPreferences существует.

Затем я запустил adb shell setprop log.tag.BackupXmlParserLogging VERBOSE , за документы. Нет очевидных проблем.

Затем я запустил adb shell bmgr run , для документов, которые генерировали много сообщений о протоколировании, но ничего не относящихся к моему приложению, как и ожидалось (а также не предполагали каких-либо особых проблем с механизмом резервного копирования).

Затем я запустил adb shell bmgr fullbackup com.commonsware.myapplication2 , за документы, которые сгенерировали:

 11-16 15:09:15.246 10372-10372/? D/AndroidRuntime: Calling main entry com.android.commands.bmgr.Bmgr 11-16 15:09:15.248 783-793/? D/BackupManagerService: fullTransportBackup() 11-16 15:09:15.249 783-10419/? I/PFTBT: Initiating full-data transport backup of com.commonsware.myapplication2 11-16 15:09:15.250 1406-1418/? I/GmsBackupTransport: Attempt to do full backup on com.commonsware.myapplication2 11-16 15:09:15.251 783-10419/? I/AccountManagerService: getTypesVisibleToCaller: isPermitted? true 11-16 15:09:15.257 1325-1325/? V/GLSActivity: AuthDelegateWrapperCreated with selected intent: Intent { cmp=com.google.android.gms/.auth.DefaultAuthDelegateService } 11-16 15:09:15.259 783-2127/? I/AccountManagerService: getTypesVisibleToCaller: isPermitted? true 11-16 15:09:15.262 1325-1325/? V/GLSActivity: AuthDelegateWrapperCreated with selected intent: Intent { cmp=com.google.android.gms/.auth.DefaultAuthDelegateService } 11-16 15:09:15.264 1325-1325/? V/GLSActivity: AuthDelegateWrapperCreated with selected intent: Intent { cmp=com.google.android.gms/.auth.DefaultAuthDelegateService } 11-16 15:09:15.284 1406-1418/? V/GmsBackupTransport: create full backup for : com.commonsware.myapplication2 11-16 15:09:15.286 1406-10421/? V/GmsBackupTransport: Start scotty uploading. 11-16 15:09:15.287 783-10422/? D/BackupManagerService: Binding to full backup agent : com.commonsware.myapplication2 11-16 15:09:15.291 783-10422/? D/BackupManagerService: awaiting agent for ApplicationInfo{75f37e2 com.commonsware.myapplication2} 11-16 15:09:15.292 783-1544/? D/BackupManagerService: agentConnected pkg=com.commonsware.myapplication2 agent=android.os.BinderProxy@e073ad3 11-16 15:09:15.293 783-10422/? I/BackupManagerService: got agent android.app.IBackupAgent$Stub$Proxy@f328610 11-16 15:09:15.299 783-1552/? D/VoldConnector: SND -> {8 volume mkdirs /storage/emulated/0/Android/data/com.commonsware.myapplication2/files/} 11-16 15:09:15.302 783-878/? D/VoldConnector: RCV <- {200 8 Command succeeded} 11-16 15:09:15.302 7953-7965/com.commonsware.myapplication2 V/BackupXmlParserLogging: android:fullBackupContent - "true" 11-16 15:09:15.309 783-10422/? I/BackupRestoreController: Getting widget state for user: 0 11-16 15:09:15.312 783-10425/? I/file_backup_helper: Name: apps/com.commonsware.myapplication2/_manifest 11-16 15:09:15.313 783-10425/? D/BackupManagerService: Calling doFullBackup() on com.commonsware.myapplication2 11-16 15:09:15.320 7953-7967/com.commonsware.myapplication2 I/file_backup_helper: Name: apps/com.commonsware.myapplication2/sp/com.commonsware.myapplication2_preferences.xml 11-16 15:09:15.325 7953-7953/com.commonsware.myapplication2 I/Process: Sending signal. PID: 7953 SIG: 9 11-16 15:09:15.337 783-2131/? D/GraphicsStats: Buffer count: 4 11-16 15:09:15.337 783-2131/? I/WindowState: WIN DEATH: Window{d0be7fd u0 com.commonsware.myapplication2/com.commonsware.myapplication2.MainActivity} 11-16 15:09:15.357 783-2124/? I/ActivityManager: Process com.commonsware.myapplication2 (pid 7953) has died 11-16 15:09:15.357 783-2124/? W/ActivityManager: Force removing ActivityRecord{d9c7ab7 u0 com.commonsware.myapplication2/.MainActivity t1146}: app died, no saved state 11-16 15:09:15.374 783-2124/? I/ActivityManager: Config changes=480 {1.0 310mcc?mnc en_US ldltr sw360dp w360dp h568dp 480dpi nrml port finger -keyb/v/h -nav/h s.9} 11-16 15:09:15.414 783-876/? I/InputReader: Reconfiguring input devices. changes=0x00000004 11-16 15:09:15.414 783-876/? I/InputReader: Device reconfigured: id=4, name='touch_dev', size 1080x1920, orientation 0, mode 1, display id 0 11-16 15:09:15.441 917-1161/? E/Surface: getSlotFromBufferLocked: unknown buffer: 0x9cfd78f0 11-16 15:09:15.446 783-1649/? W/InputMethodManagerService: Got RemoteException sending setActive(false) notification to pid 7953 uid 10193 11-16 15:09:15.447 1477-1477/? I/Keyboard.Facilitator: onFinishInput() 11-16 15:09:15.513 3287-3287/? W/LocationOracle: Best location was null 11-16 15:09:15.551 3287-10448/? I/MicroRecognitionRnrImpl: Starting detection. 11-16 15:09:15.556 3287-10452/? I/MicrophoneInputStream: mic_starting com.google.android.apps.gsa.speech.audio.aa@5e3e5da 11-16 15:09:15.564 783-801/? I/WindowManager: Screen frozen for +201ms due to Window{48728f7 u0 com.android.systemui.ImageWallpaper} 11-16 15:09:15.566 199-10454/? I/AudioFlinger: AudioFlinger's thread 0xb2600000 ready to run 11-16 15:09:15.570 3287-10452/? I/MicrophoneInputStream: mic_started com.google.android.apps.gsa.speech.audio.aa@5e3e5da 11-16 15:09:15.579 199-10454/? D/audio_hw_primary: select_devices: out_snd_device(0: none) in_snd_device(61: voice-rec-mic) 11-16 15:09:15.580 199-10454/? D/msm8974_platform: platform_send_audio_calibration: sending audio calibration for snd_device(61) acdb_id(62) 11-16 15:09:15.580 199-10454/? D/: Failed to fetch the lookup information of the device 0000003E 11-16 15:09:15.580 199-10454/? E/ACDB-LOADER: Error: ACDB AudProc vol returned = -19 11-16 15:09:15.580 199-10454/? D/audio_hw_primary: enable_snd_device: snd_device(61: voice-rec-mic) 11-16 15:09:15.583 199-10454/? D/audio_hw_primary: enable_audio_route: apply and update mixer path: audio-record 11-16 15:09:15.641 1406-1593/? D/GCoreFlp: FLP HAL exists but batch size is <= 0. Disabling FLP HAL. 11-16 15:09:15.649 783-2126/? D/WifiService: acquireWifiLockLocked: WifiLock{NlpWifiLock type=2 binder=android.os.BinderProxy@6b83dff} 11-16 15:09:15.651 783-897/? D/wifi: Initialized common fields 10000, 16, 100, 10 11-16 15:09:15.651 783-897/? D/wifi: bucket[0] = 2:3:10000:2 11-16 15:09:15.670 3287-3287/? W/MicroDetectionWorkerImp: Tag [MicroDetectionWorkerImpl] is too long; truncated to [MicroDetectionWorkerImp] 11-16 15:09:15.670 3287-3287/? I/MicroDetectionWorkerImp: onReady 11-16 15:09:15.971 3456-3476/? W/OpenGLRenderer: Incorrectly called buildLayer on View: ShortcutAndWidgetContainer, destroying layer... 11-16 15:09:16.065 1406-10421/? V/GmsBackupTransport: Scotty response: res=200 raw=2560 up=2560 11-16 15:09:16.069 783-10419/? I/PFTBT: Transport suggested backoff=0 11-16 15:09:16.083 783-10419/? I/PFTBT: Full backup completed. 11-16 15:09:16.084 783-793/? D/BackupManagerService: Done with full transport backup. 

Ничто не кажется показателем ошибки или другого сбоя в резервном копировании.

Затем я удалил файл SharedPreferences вручную:

 adb shell run-as com.commonsware.myapplication2 rm /data/data/com.commonsware.myapplication2/shared_prefs/com.commonsware.myapplication2_preferences.xml 

И подтвердил, что файл SharedPreferences больше не существует.

Затем я запустил adb shell bmgr restore com.commonsware.myapplication2 , за документы. Это сгенерировало еще один набор сообщений регистрации с некоторыми очевидными ошибками:

 11-16 15:13:01.692 10593-10593/? D/AndroidRuntime: Calling main entry com.android.commands.bmgr.Bmgr 11-16 15:13:01.694 783-941/? V/BackupManagerService: beginRestoreSession: pkg=com.commonsware.myapplication2 transport=null 11-16 15:13:01.696 783-794/? V/RestoreSession: restorePackage pkg=com.commonsware.myapplication2 obs=android.app.backup.IRestoreObserver$Stub$Proxy@b011dce 11-16 15:13:01.696 783-794/? V/RestoreSession: restorePackage pkg=com.commonsware.myapplication2 token=3dd6ad03f250d4cb 11-16 15:13:01.696 783-900/? D/BackupManagerService: MSG_RUN_RESTORE observer=android.app.backup.IRestoreObserver$Stub$Proxy@b011dce 11-16 15:13:01.700 783-900/? I/AccountManagerService: getTypesVisibleToCaller: isPermitted? true 11-16 15:13:01.703 1325-1325/? V/GLSActivity: AuthDelegateWrapperCreated with selected intent: Intent { cmp=com.google.android.gms/.auth.DefaultAuthDelegateService } 11-16 15:13:01.705 783-1552/? I/AccountManagerService: getTypesVisibleToCaller: isPermitted? true 11-16 15:13:01.707 1325-1325/? V/GLSActivity: AuthDelegateWrapperCreated with selected intent: Intent { cmp=com.google.android.gms/.auth.DefaultAuthDelegateService } 11-16 15:13:01.708 1325-1325/? V/GLSActivity: AuthDelegateWrapperCreated with selected intent: Intent { cmp=com.google.android.gms/.auth.DefaultAuthDelegateService } 11-16 15:13:01.991 1406-1682/? I/GmsBackupTransport: Http Response Code : 200 11-16 15:13:01.995 1406-1887/? I/GmsBackupTransport: Current restore package : PackageInfo{f7f23bd @pm@} 11-16 15:13:01.996 783-900/? D/BackupManagerService: initiateOneRestore packageName=@pm@ 11-16 15:13:02.008 1406-1417/? I/GmsBackupTransport: Current restore package : PackageInfo{733fdb2 com.commonsware.myapplication2} 11-16 15:13:02.009 783-900/? I/BackupManagerService: Next restore package: RestoreDescription{com.commonsware.myapplication2 : STREAM} 11-16 15:13:02.023 783-10612/? I/AccountManagerService: getTypesVisibleToCaller: isPermitted? true 11-16 15:13:02.213 1406-1418/? I/GmsBackupTransport: Drive download http response status : 401 11-16 15:13:02.282 783-10612/? I/AccountManagerService: getTypesVisibleToCaller: isPermitted? true 11-16 15:13:02.311 783-10612/? I/AccountManagerService: getTypesVisibleToCaller: isPermitted? true 11-16 15:13:02.319 1325-1325/? V/GLSActivity: AuthDelegateWrapperCreated with selected intent: Intent { cmp=com.google.android.gms/.auth.DefaultAuthDelegateService } 11-16 15:13:02.321 783-1552/? I/AccountManagerService: getTypesVisibleToCaller: isPermitted? true 11-16 15:13:02.516 783-884/? D/WifiStateMachine: starting scan for "cw"WPA_PSK with 2427,5180 11-16 15:13:02.517 783-886/? D/ConnectivityService: updateNetworkScore for NetworkAgentInfo [WIFI () - 100] to 60 11-16 15:13:02.517 783-886/? D/ConnectivityService: rematching NetworkAgentInfo [WIFI () - 100] 11-16 15:13:02.695 1406-1418/? I/GmsBackupTransport: Reading next chunk on full restore - IOException 11-16 15:13:09.611 783-10612/? I/AccountManagerService: getTypesVisibleToCaller: isPermitted? true 11-16 15:13:09.808 1406-1418/? I/GmsBackupTransport: Drive download http response status : 401 11-16 15:13:09.834 783-10612/? I/AccountManagerService: getTypesVisibleToCaller: isPermitted? true 11-16 15:13:09.884 783-10612/? I/AccountManagerService: getTypesVisibleToCaller: isPermitted? true 11-16 15:13:09.892 1325-1325/? V/GLSActivity: AuthDelegateWrapperCreated with selected intent: Intent { cmp=com.google.android.gms/.auth.DefaultAuthDelegateService } 11-16 15:13:09.894 783-2126/? I/AccountManagerService: getTypesVisibleToCaller: isPermitted? true 11-16 15:13:09.897 1325-1325/? V/GLSActivity: AuthDelegateWrapperCreated with selected intent: Intent { cmp=com.google.android.gms/.auth.DefaultAuthDelegateService } 11-16 15:13:09.898 1325-1325/? V/GLSActivity: AuthDelegateWrapperCreated with selected intent: Intent { cmp=com.google.android.gms/.auth.DefaultAuthDelegateService } 11-16 15:13:10.110 1406-1418/? I/GmsBackupTransport: Reading next chunk on full restore - IOException 11-16 15:13:10.110 1406-1418/? E/GmsBackupTransport: HTTP reading error: java.io.IOException: Unauthorized full data restore request 11-16 15:13:10.110 1406-1418/? E/GmsBackupTransport: Fail to read full backup data chunk : java.io.IOException: Unauthorized full data restore request 11-16 15:13:10.112 783-10612/? E/StreamFeederThread: Error -1002 streaming restore for com.commonsware.myapplication2 11-16 15:13:10.119 783-10612/? I/ActivityManager: Force stopping com.commonsware.myapplication2 appid=10193 user=0: clear data 11-16 15:13:10.140 783-796/? I/ActivityManager: Start proc 10623:com.android.documentsui/u0a36 for broadcast com.android.documentsui/.PackageReceiver 11-16 15:13:10.174 10623-10623/? W/System: ClassLoader referenced unknown path: /system/app/DocumentsUI/lib/arm 11-16 15:13:10.198 1440-10637/? D/PackageBroadcastService: Received broadcast action=android.intent.action.PACKAGE_DATA_CLEARED and uri=com.commonsware.myapplication2 11-16 15:13:10.198 1440-10637/? D/AccountUtils: Clearing selected account for com.commonsware.myapplication2 11-16 15:13:10.203 1440-10637/? I/LocationSettingsChecker: Removing dialog suppression flag for package com.commonsware.myapplication2 11-16 15:13:10.208 1440-2449/? I/Icing: doRemovePackageData com.commonsware.myapplication2 11-16 15:13:10.232 783-900/? V/BackupManagerService: No more packages; finishing restore 11-16 15:13:10.234 783-900/? I/BackupRestoreController: restoreFinished for 0 11-16 15:13:10.234 783-900/? I/BackupManagerService: Restore complete. 11-16 15:13:10.234 783-793/? D/RestoreSession: endRestoreSession 11-16 15:13:10.234 10593-10593/? D/AndroidRuntime: Shutting down VM 11-16 15:13:10.235 783-900/? V/BackupManagerService: Clearing restore session and halting timeout 11-16 15:13:10.279 783-1544/? I/ActivityManager: Start proc 10661:com.android.externalstorage/u0a6 for content provider com.android.externalstorage/.ExternalStorageProvider 11-16 15:13:10.301 10661-10661/? W/System: ClassLoader referenced unknown path: /system/priv-app/ExternalStorageProvider/lib/arm 11-16 15:13:10.307 10661-10661/? D/ExternalStorage: After updating volumes, found 1 active roots 11-16 15:13:10.336 783-1544/? I/ActivityManager: Start proc 10675:com.android.shell/2000 for content provider com.android.shell/.BugreportStorageProvider 11-16 15:13:10.360 10675-10675/? W/System: ClassLoader referenced unknown path: /system/priv-app/Shell/lib/arm 11-16 15:13:10.371 10623-10636/? D/Documents: Update found 7 roots in 156ms 11-16 15:13:10.377 10623-10674/? D/Documents: Update found 7 roots in 65ms 11-16 15:13:14.635 783-886/? D/ConnectivityService: updateNetworkScore for NetworkAgentInfo [WIFI () - 100] to 56 11-16 15:13:14.635 783-886/? D/ConnectivityService: rematching NetworkAgentInfo [WIFI () - 100] 11-16 15:13:17.617 783-2632/? D/NetlinkSocketObserver: NeighborEvent{elapsedMs=2866928, 192.168.3.1, [000DB9340C50], RTM_NEWNEIGH, NUD_STALE} 11-16 15:13:22.520 783-884/? D/WifiStateMachine: starting scan for "cw"WPA_PSK with 2427,5180 11-16 15:13:23.729 783-886/? D/ConnectivityService: updateNetworkScore for NetworkAgentInfo [WIFI () - 100] to 60 11-16 15:13:23.731 783-886/? D/ConnectivityService: rematching NetworkAgentInfo [WIFI () - 100] 

Тревожным подмножеством является следующее:

 11-16 15:13:10.110 1406-1418/? I/GmsBackupTransport: Reading next chunk on full restore - IOException 11-16 15:13:10.110 1406-1418/? E/GmsBackupTransport: HTTP reading error: java.io.IOException: Unauthorized full data restore request 11-16 15:13:10.110 1406-1418/? E/GmsBackupTransport: Fail to read full backup data chunk : java.io.IOException: Unauthorized full data restore request 11-16 15:13:10.112 783-10612/? E/StreamFeederThread: Error -1002 streaming restore for com.commonsware.myapplication2 

И, конечно же, файл не восстановлен. Я понятия не имею, что означает «Неавторизованный полный запрос восстановления данных».

Итак, я удалил приложение (через gradle uninstallDebug ) и установил его снова, не запуская его (через gradle installDebug ). Согласно документам: «Вы можете протестировать автоматическое восстановление для своего приложения, удалив и переустановив приложение. Данные приложения автоматически восстанавливаются из облака после завершения установки приложения». Однако через несколько минут после его SharedPreferences файл SharedPreferences все еще не существует.

Затем я снова запустил adb shell bmgr restore com.commonsware.myapplication2 и получил аналогичный набор операторов ведения журнала с тем же сообщением «Неавторизованный полный запрос восстановления данных».

Есть ли шаги к этому процессу, которые я пропускаю или в противном случае недокументированы?

EDIT : Я тестировал фактическое оборудование (Nexus 6). По словам MH, я протестировал эту процедуру на эмуляторе Android 6.0 (sans Play Services), и он работает. Это говорит о том, что документация не совсем ошибочна, хотя она по-прежнему задает вопрос о том, почему она не работает с оборудованием.

Solutions Collecting From Web of "Как протестировать поведение полного резервного копирования Android 6.0?"

После обсуждения и тестирования различных сценариев (см. Комментарии ниже вопроса), я решил объединить и записать эти результаты в ответ. На самом деле это фактически не решает проблему, но ответ будет отвечать на вопрос «Как успешно использовать инструменты командной строки (или что-то еще) для проверки поведения резервного копирования и восстановления Android 6.0?» Он будет делать это в виде пошагового руководства, излагающего, что сработало для меня, и как я преодолел различные коряги, которые я обнаружил на этом пути.

Вот оно. Если вы еще не прошли обучение в разделе « Настройка автоматического резервного копирования для приложений », я бы предложил вам сделать это в первую очередь. Он документирует функцию автоматического резервного копирования и уже делает очень приличную работу по документированию различных этапов.

Начнем с начала: нам нужно приложение для тестирования! Как и CommonsWare, я просто использовал Android Studio для создания нового проекта с пустым действием. Убедитесь, что вы установили API 23 в качестве целевого SDK. Откройте автогенерированную MainActivity и добавьте некоторый код в onCreate() чтобы сохранить значение в общих настройках (или просто скопировать фрагмент кода из вопроса):

 PreferenceManager .getDefaultSharedPreferences(this) .edit() .putBoolean("foo", true) .apply(); 

Создавайте, развертывайте и запускайте приложение. Это должно привести к тому, что foo будет сохранен и приведет к созданию xml-файла на диске. Подтвердите это с помощью:

 adb shell run-as <package_name> ls -al shared_prefs 

Пакет моего тестового приложения – com.example.mh.backuptest (это то, что я буду использовать в примерах команд здесь), поэтому моя команда:

 adb shell run-as com.example.mh.backuptest ls -al shared_prefs 

Вы должны увидеть одну строку вывода, в которой перечислены все файлы в папке shared_prefs , которая должна быть только одной:

 com.example.mh.backuptest_preferences.xml 

Это означает, что файл предпочтений был успешно создан, и foo был записан на него. Если хотите, вы можете проверить содержимое файла, чтобы подтвердить это.

Теперь вернемся к тестированию автоматического резервного копирования. Во-первых, убедитесь, что вы выбрали автоматическое резервное копирование приложений. На устройстве Android 6.0 перейдите по ссылке:

 Settings > Backup & reset > Back up my data > On 

После этого включите подробное ведение журнала резервного копирования и резервного копирования XML-анализатора, чтобы мы могли видеть, что происходит:

 adb shell setprop log.tag.GmsBackupTransport VERBOSE adb shell setprop log.tag.BackupXmlParserLogging VERBOSE 

Затем инициализируйте диспетчер резервного копирования:

 adb shell bmgr run 

Это должно генерировать довольно много вывода в logcat. Вы должны увидеть хотя бы что-то похожее на это:

 D/AndroidRuntime: Calling main entry com.android.commands.bmgr.Bmgr V/BackupManagerService: Scheduling immediate backup pass V/BackupManagerService: Running a backup pass V/BackupManagerService: clearing pending backups V/PerformBackupTask: Beginning backup of 1 targets D/PerformBackupTask: invokeAgentForBackup on @pm@ I/BackupRestoreController: Getting widget state for user: 0 D/PerformBackupTask: starting key/value backup of BackupRequest{pkg=com.google.android.googlequicksearchbox} D/BackupManagerService: awaiting agent for ApplicationInfo{9f9289c com.google.android.googlequicksearchbox} D/BackupManagerService: agentConnected pkg=com.google.android.googlequicksearchbox agent=android.os.BinderProxy@dcdbafd I/BackupManagerService: got agent android.app.IBackupAgent$Stub$Proxy@c3fe3f2 D/PerformBackupTask: invokeAgentForBackup on com.google.android.googlequicksearchbox D/BackupHelperDispatcher: handling existing helper 'L' com.android.launcher3.LauncherBackupHelper@7e2dcc3 V/LauncherBackupHelper: lastBackupTime = 1448612678367 W/LauncherBackupHelper: empty intent on application favorite: 223 I/BackupRestoreController: Getting widget state for user: 0 V/GmsBackupTransport: starting new backup session V/GmsBackupTransport: starting performBackup for com.google.android.googlequicksearchbox V/GmsBackupTransport: performBackup done for com.google.android.googlequicksearchbox V/GmsBackupTransport: sending request: 101667 bytes I/GmsBackupTransport: Http Response Code : 200 V/GmsBackupTransport: backup finished for com.google.android.googlequicksearchbox I/BackupManagerService: Backup pass finished. 

Не беспокойтесь, если ваш вывод содержит намного больше. Я намеренно удалил строки, не имеющие отношения к резервному копированию. Я только только вставил в вывод, когда одно приложение получает резервное копирование; Вы, вероятно, увидите намного больше записей при первом запуске этой команды.

Если вместо этого вы видите что-то вроде:

 GmsBackupTransport: Scotty transfer exception. null PFTBT : Error -1002 backing up com.example.mh.backuptest 

Или:

 GmsBackupTransport: Rejecting full data backup. user has not seen up to date legal text 

Убедитесь, что вы выбрали автоматическое резервное копирование приложений (см. Выше). Если у вас есть, и вы все еще видите эти сообщения – что тоже случилось со мной, попробуйте несколько раз переключить настройку и перезагрузите устройство. Еще не повезло? Я был там … Удалите учетную запись Google с устройства, перезагрузите, повторно добавьте его и снова выберите. Другие сообщили, что заводская перезагрузка работает тоже, но для меня это кажется немного за бортом. 🙂

Если вы зашли так далеко, то пришло время обеспечить, чтобы наше тестовое приложение получило резервную копию! Чтобы принудительно выполнить резервное копирование, выполните:

 adb shell bmgr fullbackup com.example.mh.backuptest 

Это убьет ваше приложение, если оно все еще работает – не беспокойтесь, это нормально. Вы должны увидеть довольно много информации о резервном транспорте:

 D/AndroidRuntime: Calling main entry com.android.commands.bmgr.Bmgr D/BackupManagerService: fullTransportBackup() I/PFTBT: Initiating full-data transport backup of com.example.mh.backuptest V/GmsBackupTransport: create full backup for : com.example.mh.backuptest V/GmsBackupTransport: Start scotty uploading. D/BackupManagerService: Binding to full backup agent : com.example.mh.backuptest I/ActivityManager: Start proc 22032:com.example.mh.backuptest/u0a491 for backup android/FullBackupAgent D/BackupManagerService: awaiting agent for ApplicationInfo{dd359cd com.example.mh.backuptest} V/GmsBackupTransport: [READ] V/GmsBackupTransport: [READ] wait for avaible data. BackupManagerService: agentConnected pkg=com.example.mh.backuptest agent=android.os.BinderProxy@9e7e282 I/BackupManagerService: got agent android.app.IBackupAgent$Stub$Proxy@14b3d93 V/BackupXmlParserLogging: android:fullBackupContent - "true" I/BackupRestoreController: Getting widget state for user: 0 I/file_backup_helper: Name: apps/com.example.mh.backuptest/_manifest V/GmsBackupTransport: [PUSH] Push 512 bytes into pipe. V/GmsBackupTransport: [PUSH] signal data available. V/GmsBackupTransport: [PUSH] Wait for data been processed. V/GmsBackupTransport: [READ] Read 256 bytes data. V/GmsBackupTransport: [READ] V/GmsBackupTransport: [READ] Read 256 bytes data. V/GmsBackupTransport: [READ] signal data processed. V/GmsBackupTransport: [READ] V/GmsBackupTransport: [READ] wait for avaible data. V/GmsBackupTransport: [PUSH] Push 2048 bytes into pipe. V/GmsBackupTransport: [PUSH] signal data available. V/GmsBackupTransport: [PUSH] Wait for data been processed. V/GmsBackupTransport: [READ] Read 256 bytes data. V/GmsBackupTransport: [READ] V/GmsBackupTransport: [READ] Read 256 bytes data. V/GmsBackupTransport: [READ] V/GmsBackupTransport: [READ] Read 256 bytes data. V/GmsBackupTransport: [READ] V/GmsBackupTransport: [READ] Read 256 bytes data. V/GmsBackupTransport: [READ] V/GmsBackupTransport: [READ] Read 256 bytes data. V/GmsBackupTransport: [READ] V/GmsBackupTransport: [READ] Read 256 bytes data. V/GmsBackupTransport: [READ] V/GmsBackupTransport: [READ] Read 256 bytes data. V/GmsBackupTransport: [READ] V/GmsBackupTransport: [READ] Read 256 bytes data. V/GmsBackupTransport: [READ] signal data processed. V/GmsBackupTransport: [READ] V/GmsBackupTransport: [READ] wait for avaible data. D/BackupManagerService: Calling doFullBackup() on com.example.mh.backuptest I/file_backup_helper: Name: apps/com.example.mh.backuptest/sp/com.example.mh.backuptest_preferences.xml V/GmsBackupTransport: [PUSH] Push 512 bytes into pipe. V/GmsBackupTransport: [PUSH] signal data available. V/GmsBackupTransport: [PUSH] Wait for data been processed. V/GmsBackupTransport: [READ] Read 256 bytes data. V/GmsBackupTransport: [READ] V/GmsBackupTransport: [READ] Read 256 bytes data. V/GmsBackupTransport: [READ] signal data processed. V/GmsBackupTransport: [READ] V/GmsBackupTransport: [READ] wait for avaible data. V/GmsBackupTransport: [PUSH] Push 512 bytes into pipe. V/GmsBackupTransport: [PUSH] signal data available. V/GmsBackupTransport: [PUSH] Wait for data been processed. V/GmsBackupTransport: [READ] Read 256 bytes data. V/GmsBackupTransport: [READ] V/GmsBackupTransport: [READ] Read 256 bytes data. V/GmsBackupTransport: [READ] signal data processed. V/GmsBackupTransport: [READ] V/GmsBackupTransport: [READ] wait for avaible data. V/GmsBackupTransport: [FINISH] signal no more data. I/Process: Sending signal. PID: 22032 SIG: 9 I/ActivityManager: Process com.example.mh.backuptest (pid 22032) has died V/GmsBackupTransport: Scotty response: res=200 raw=3584 up=1047 I/PFTBT: Transport suggested backoff=0 I/PFTBT: Full backup completed. D/BackupManagerService: Done with full transport backup. 

С помощью нашего тестового приложения, давайте посмотрим, действительно ли он восстанавливает данные. Во-первых, давайте удалим файл предпочтений, созданный нашим тестовым приложением, и который является частью автозагрузки по умолчанию:

 adb shell run-as com.example.mh.backuptest rm shared_prefs/com.example.mh.backuptest_preferences.xml 

Убедитесь, что файла больше нет:

 adb shell run-as com.example.mh.backuptest ls -al shared_prefs 

Если команда выполняется без какого-либо вывода, это означает, что в папке shared_prefs не было файлов и что вы успешно удалили префы.

Теперь запустите восстановление для нашего тестового приложения:

 adb shell bmgr restore com.example.mh.backuptest 

Опять же, резервный транспорт будет генерировать довольно некоторый результат:

 V/BackupManagerService: beginRestoreSession: pkg=com.example.mh.backuptest transport=null V/RestoreSession: restorePackage pkg=com.example.mh.backuptest obs=android.app.backup.IRestoreObserver$Stub$Proxy@23829fa V/RestoreSession: restorePackage pkg=com.example.mh.backuptest token=31eda3bdfd5fddb7 D/BackupManagerService: MSG_RUN_RESTORE observer=android.app.backup.IRestoreObserver$Stub$Proxy@23829fa V/GmsBackupTransport: New restore session, 2 apps V/GmsBackupTransport: sending request: 471 bytes I/GmsBackupTransport: Http Response Code : 200 V/GmsBackupTransport: @pm@: 109 keys I/GmsBackupTransport: Current restore package : PackageInfo{195d280 @pm@} V/GmsBackupTransport: A key/value pairs restore D/BackupManagerService: initiateOneRestore packageName=@pm@ I/GmsBackupTransport: Current restore package : PackageInfo{1edd0b9 com.example.mh.backuptest} V/GmsBackupTransport: A full restore : https://www.googleapis.com/drive/v2/files/XXXXXXXXXXXXXXXXXXXXXXXXXXXX?alt=media&sources=ANDROID_BACKUP I/BackupManagerService: Next restore package: RestoreDescription{com.example.mh.backuptest : STREAM} V/GmsBackupTransport: Read first chunk for com.example.mh.backuptest V/GmsBackupTransport: Create http connection for com.example.mh.backuptest I/GmsBackupTransport: Drive download http response status : 200 V/GmsBackupTransport: ContentLength is 3584 V/GmsBackupTransport: Downloaded: 808 / 3584 bytes V/GmsBackupTransport: Read 808 Bytes V/GmsBackupTransport: Read next chunk for com.example.mh.backuptest V/GmsBackupTransport: Downloaded: 2197 / 3584 bytes V/GmsBackupTransport: Read 1389 Bytes I/RestoreEngine: Sig + version match; taking data V/GmsBackupTransport: Read next chunk for com.example.mh.backuptest V/GmsBackupTransport: Downloaded: 3584 / 3584 bytes V/GmsBackupTransport: Read 1387 Bytes V/GmsBackupTransport: Read next chunk for com.example.mh.backuptest V/GmsBackupTransport: Read -1 Bytes D/RestoreEngine: Need to launch agent for com.example.mh.backuptest D/RestoreEngine: Clearing app data preparatory to full restore I/ActivityManager: Force stopping com.example.mh.backuptest appid=10491 user=0: clear data V/GmsBackupTransport: Reach end of http content -- NO MORE DATA D/PackageBroadcastService: Received broadcast action=android.intent.action.PACKAGE_DATA_CLEARED and uri=com.example.mh.backuptest D/AccountUtils: Clearing selected account for com.example.mh.backuptest I/LocationSettingsChecker: Removing dialog suppression flag for package com.example.mh.backuptest I/Icing: doRemovePackageData com.example.mh.backuptest I/ActivityManager: Start proc 22708:com.example.mh.backuptest/u0a491 for backup android/FullBackupAgent D/BackupManagerService: awaiting agent for ApplicationInfo{dd359cd com.example.mh.backuptest} D/BackupManagerService: agentConnected pkg=com.example.mh.backuptest agent=android.os.BinderProxy@7875d75 I/BackupManagerService: got agent android.app.IBackupAgent$Stub$Proxy@9aa10a D/VoldConnector: SND -> {14 volume mkdirs /storage/emulated/0/Android/data/com.example.mh.backuptest/files/} D/VoldConnector: RCV <- {200 14 Command succeeded} V/BackupXmlParserLogging: android:fullBackupContent - "true" V/BackupManagerService: No more packages; finishing restore V/GmsBackupTransport: restore finished D/RestoreSession: endRestoreSession I/BackupRestoreController: restoreFinished for 0 I/BackupManagerService: Restore complete. 

Если все выглядит выше, давайте проверим, вернулся ли наш файл предпочтений туда, где он должен быть:

 adb shell run-as com.example.mh.backuptest ls -al shared_prefs 

Результат должен быть тем, что вы видели в первый раз, когда вы запустили команду (на ранних этапах этой довольно длинной истории). Если да, пришло время для поздравлений! Вы успешно выполнили резервное копирование и восстановление своего приложения с помощью Auto Backup для приложений Google!

Счастливый? Тогда давайте сделаем еще один тест! Удалите приложение:

 adb uninstall com.example.mh.backuptest 

Несмотря на то, что мы видим «Успех», подтвердите, что он ушел:

 adb shell run-as com.example.mh.backuptest 

Ожидаемый результат:

 run-as: Package 'com.example.mh.backuptest' is unknown 

Теперь установите приложение еще раз (но не начинайте его):

 adb install backuptest.apk 

Посмотрите на logcat:

 V/BackupManagerService: restoreAtInstall pkg=com.example.mh.backuptest token=3 restoreSet=31eda3bdfd5fddb7 D/BackupManagerService: MSG_RUN_RESTORE observer=null V/GmsBackupTransport: New restore session, 2 apps V/GmsBackupTransport: sending request: 471 bytes I/GmsBackupTransport: Http Response Code : 200 V/GmsBackupTransport: @pm@: 109 keys I/GmsBackupTransport: Current restore package : PackageInfo{2981234 @pm@} V/GmsBackupTransport: A key/value pairs restore D/BackupManagerService: initiateOneRestore packageName=@pm@ I/GmsBackupTransport: Current restore package : PackageInfo{883c85d com.example.mh.backuptest} V/GmsBackupTransport: A full restore : https://www.googleapis.com/drive/v2/files/XXXXXXXXXXXXXXXXXXXXXXXXXXXX?alt=media&sources=ANDROID_BACKUP I/BackupManagerService: Next restore package: RestoreDescription{com.example.mh.backuptest : STREAM} V/GmsBackupTransport: Read first chunk for com.example.mh.backuptest V/GmsBackupTransport: Create http connection for com.example.mh.backuptest I/GmsBackupTransport: Drive download http response status : 200 V/GmsBackupTransport: ContentLength is 3584 V/GmsBackupTransport: Downloaded: 808 / 3584 bytes V/GmsBackupTransport: Read 808 Bytes V/GmsBackupTransport: Read next chunk for com.example.mh.backuptest V/GmsBackupTransport: Downloaded: 2197 / 3584 bytes V/GmsBackupTransport: Read 1389 Bytes I/RestoreEngine: Sig + version match; taking data V/GmsBackupTransport: Read next chunk for com.example.mh.backuptest V/GmsBackupTransport: Downloaded: 3584 / 3584 bytes V/GmsBackupTransport: Read 1387 Bytes V/GmsBackupTransport: Read next chunk for com.example.mh.backuptest V/GmsBackupTransport: Read -1 Bytes D/RestoreEngine: Need to launch agent for com.example.mh.backuptest D/RestoreEngine: Clearing app data preparatory to full restore I/ActivityManager: Force stopping com.example.mh.backuptest appid=10493 user=0: clear data V/GmsBackupTransport: Reach end of http content -- NO MORE DATA D/PackageBroadcastService: Received broadcast action=android.intent.action.PACKAGE_DATA_CLEARED and uri=com.example.mh.backuptest D/AccountUtils: Clearing selected account for com.example.mh.backuptest I/LocationSettingsChecker: Removing dialog suppression flag for package com.example.mh.backuptest I/Icing: doRemovePackageData com.example.mh.backuptest I/ActivityManager: Start proc 31545:com.example.mh.backuptest/u0a493 for backup android/FullBackupAgent D/BackupManagerService: awaiting agent for ApplicationInfo{a84d42d com.example.mh.backuptest} D/BackupManagerService: agentConnected pkg=com.example.mh.backuptest agent=android.os.BinderProxy@b023d62 I/BackupManagerService: got agent android.app.IBackupAgent$Stub$Proxy@a742ef3 D/VoldConnector: SND -> {17 volume mkdirs /storage/emulated/0/Android/data/com.example.mh.backuptest/files/} D/VoldConnector: RCV <- {200 17 Command succeeded} V/BackupXmlParserLogging: android:fullBackupContent - "true" D/BackupManagerService: Restore complete, killing host process of com.example.mh.backuptest V/BackupManagerService: No more packages; finishing restore I/Process: Sending signal. PID: 31545 SIG: 9 V/GmsBackupTransport: restore finished I/BackupRestoreController: restoreFinished for 0 I/BackupManagerService: Restore complete. 

That looks promising! Did it really restore our backed up preference file when reinstalling the app?

 adb shell run-as com.example.mh.backuptest ls -al shared_prefs 

If you see the output that should be familiar by now, then the answer is yes!


Final notes: I've successfully tested above steps on various devices:

  • Default Android 6.0 Emulator (emulator64-x86) w/o Google Play Services
  • Genymotion Google Nexus 5X – API 23 – PREVIEW w/ Google Play Services
  • Nexus 5X (physical device) w/ Google Play Services.

If I recall correctly, without Google Play Services installed on the device, the backup manager doesn't actually go off to Google Drive (which wouldn't be surprising), but feel free to correct me on that.


Источники:

  • CommonWare's great question at the very top of this page.
  • Google's training on Configuring Auto Backup for Apps .
  • Various issues on Google's bug tracker, including this one and this one .

I encountered a bug in Android 6.0, where it will sometimes kill even a sticky foreground service to run doFullBackup() , and not restart it for hours. This is problematic if your app needs to run without interruption while the phone is charging (Chroma Doze is a white noise generator, so it often runs while the user is asleep):

 01-22 03:01:00.303 879 25791 I PFTBT : Initiating full-data transport backup of net.pmarks.chromadoze 01-22 03:01:00.470 879 25793 D BackupManagerService: Binding to full backup agent : net.pmarks.chromadoze 01-22 03:01:00.470 879 25793 D BackupManagerService: awaiting agent for ApplicationInfo{8ab9ee7 net.pmarks.chromadoze} 01-22 03:01:00.482 879 8822 D BackupManagerService: agentConnected pkg=net.pmarks.chromadoze agent=android.os.BinderProxy@3428a8a 01-22 03:01:00.482 879 25793 I BackupManagerService: got agent android.app.IBackupAgent$Stub$Proxy@a4738fb 01-22 03:01:00.525 879 25793 I BackupRestoreController: Getting widget state for user: 0 01-22 03:01:00.527 879 25796 D BackupManagerService: Calling doFullBackup() on net.pmarks.chromadoze 01-22 03:01:00.554 879 8821 I WindowState: WIN DEATH: Window{7b1ddb4 u0 net.pmarks.chromadoze/net.pmarks.chromadoze.ChromaDoze} 01-22 03:01:00.570 879 3721 I ActivityManager: Process net.pmarks.chromadoze (pid 18451) has died 01-22 03:01:00.570 879 3721 W ActivityManager: Scheduling restart of crashed service net.pmarks.chromadoze/.NoiseService in 13305612ms 

This only affects apps with targetSdkVersion 23 , but once you've published such an app, reverting to 22 is impossible: users who attempt to install the next version see (Error -504) in the Play store.

There are two solutions that I'm aware of:

  • Set android:allowBackup="false" in your manifest to disable all backups.
  • Implement an android:backupAgent , which (eventually) disables full backups and uses the old backup API instead.

However, if you have a targetSdkVersion 23 app installed without a backupAgent , adding the backupAgent doesn't actually disable full backups right away; you need to reboot the device to remove it from the queue.

To see which apps will receive a full backup, you can run the following:

 $ adb shell dumpsys backup 

And then look for the Full backup queue: section.