您如何测试 Android 6.0 的完整备份行为?

How Do You Test the Android 6.0 Full-Backup Behavior?

TL;DR:您如何成功使用命令行工具(或其他工具)来测试Android 6.0 备份和恢复行为,正如我无法让他们恢复任何东西?


因为我之前 运行 遇到了我书中的一个示例应用程序的问题,试图让它正常工作,所以为了这个问题,我从头开始。

我从 Android Studio 1.4.1 新项目向导创建了一个 b运行d-new 项目,接受所有相关默认值,除了我使用 "Empty Activity" 模板和在应用程序 ID 和显示名称中添加了 2。然后我在 activity 中添加了一些代码来给我一些关于内部存储的数据:

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

果然,文件没有恢复。我不知道 "Unauthorized full data restore request" 是什么意思。

所以,我卸载了该应用程序(通过 gradle uninstallDebug)并在没有 运行 的情况下再次安装它(通过 gradle installDebug)。根据文档,"You can test automatic restore for your app by uninstalling and reinstalling your app. The app data is automatically restored from the cloud once the app installation is complete." 然而,在重新安装几分钟后,SharedPreferences 文件仍然不存在。

然后我再次 运行 adb shell bmgr restore com.commonsware.myapplication2,得到了一组类似的日志语句,具有相同的 "Unauthorized full data restore request" 消息。

此过程中是否有我遗漏或未记录的步骤?

编辑:我一直在实际硬件(Nexus 6)上进行测试。根据 MH 的评论,我在 Android 6.0 模拟器(没有 Play 服务)上测试了这个程序,它有效。这表明文档并非 完全 错误,尽管它仍然回避了为什么它不能与硬件一起工作的问题。

在讨论和测试了各种场景(参考问题下方的评论)之后,我决定将这些结果结合起来写成一个答案。实际上,这并没有真正解决所提出的问题,但它会回答 "How do you successfuly use the command-line tools (or anything else) to test the Android 6.0 backup and restore behavior?" 的问题,它将以分步指南的形式进行概述对我有用的方法以及我如何克服一路上遇到的各种障碍。

开始了。如果您还没有完成关于“Configuring Auto Backup for Apps”的培训,我建议您先完成。它记录了自动备份功能,并且已经很好地记录了各个步骤。

让我们从头开始:我们需要一个应用程序来测试!就像 CommonsWare 一样,我只是使用 Android Studio 创建了一个带有 Empty activity 的新项目。确保将 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

之后,打开备份 t运行sport 和备份 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 帐户,重新启动,重新添加并再次选择加入。其他人 reported 认为恢复出厂设置也有效,但对我来说这似乎有点过分了。 :)

如果你已经走到这一步,那么是时候确保我们的测试应用程序得到备份了!要强制备份,运行:

adb shell bmgr fullbackup com.example.mh.backuptest

如果您的应用仍处于 运行ning 状态,这将终止您的应用 - 别担心,这很正常。您应该从备份 t运行sport:

中看到相当多的输出
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

同样,备份 t运行sport 将生成相当多的输出:

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

输出应该是您第一次 运行 命令时看到的(在这个相当长的故事的早期阶段)。如果是这样,是时候恭喜了!您已使用 Google 的应用程序自动备份成功备份和恢复您的应用程序!

开心吗?那我们再做一个测试吧!卸载应用程序:

adb uninstall com.example.mh.backuptest

即使我们看到 'Success',确认它已经消失了:

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.

看起来很有希望!重装应用程序时真的恢复了我们备份的首选项文件吗?

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

如果您现在看到的输出应该很熟悉,那么答案是肯定的!


最后说明:我已经在各种设备上成功测试了上述步骤:

  • 默认 Android 6.0 模拟器 (emulator64-x86) w/o Google 播放服务
  • Genymotion Google Nexus 5X - API 23 - 带有 Google Play 服务的预览
  • 带有 Google Play 服务的 Nexus 5X(物理设备)。

如果我没记错的话,如果设备上没有安装 Google Play 服务,备份管理器实际上不会转到 Google 驱动器(这不足为奇),但感觉请随时纠正我。


来源:

我在 Android 6.0 中遇到了一个错误,它有时甚至会杀死 sticky foreground 服务 运行 doFullBackup(),并且几个小时不重新启动它。如果您的应用程序需要在 phone 充电时不间断地 运行 ,这是有问题的(Chroma Doze 是一种白噪声发生器,因此它经常在用户睡着时 运行s):

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

这只会影响带有 targetSdkVersion 23 的应用,但是一旦您发布了此类应用,就不可能恢复到 22:尝试安装下一版本的用户请参阅 (Error -504)在 Play 商店中。

我知道有两种解决方案:

  • 在清单中设置 android:allowBackup="false" 以禁用所有备份。
  • 实施 android:backupAgent,它(最终)禁用完整备份并使用旧备份 API。

但是,如果您安装的 targetSdkVersion 23 应用程序没有 backupAgent,添加 backupAgent 实际上不会立即禁用完整备份;您需要重新启动设备才能将其从队列中移除。

要查看哪些应用将收到完整备份,您可以运行以下操作:

$ adb shell dumpsys backup

然后查找 Full backup queue: 部分。