你怎么测试了Android 6.0全备份行为? [英] How Do You Test the Android 6.0 Full-Backup Behavior?

查看:3543
本文介绍了你怎么测试了Android 6.0全备份行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

TL; DR:你是如何的 successfuly 的使用命令行工具(或任何其他)来测试了Android 6.0的备份和恢复的行为,因为我不能让他们恢复任何


自从我遇到了问题与早些时候从我的书,试图让这个工作一个示例应用程序,我从头开始为这一问题的目的。

我创建了一个全新的项目从Android 1.4.1工作室新项目向导,接受所有相关的默认设置,但我去的空活动模板,并添加了一个 2 应用程序ID和显示名称。我再补充一点code到活动给我的内部存储一些数据:

 包com.commonsware.myapplication2;

进口android.os.Bundle;
。进口的Andr​​oid preference preferenceManager。
进口android.support.v7.app.AppCompatActivity;

公共类MainActivity扩展AppCompatActivity {

  @覆盖
  保护无效的onCreate(包savedInstanceState){
    super.onCreate(savedInstanceState);
    的setContentView(R.layout.activity_main);

    preferenceManager
      .getDefaultShared preferences(本)
      。编辑()
      .putBoolean(富,真)
      。应用();
  }
}
 

我跑的应用程序,并确认后,使用 ADB shell中运行,作为com.commonsware.myapplication2 ... 共享preferences 文件存在。

我然后跑亚行外壳setprop log.tag.BackupXmlParserLogging VERBOSE ,每文档。没有明显的问题。

我然后跑亚行外壳BMGR运行,每文档,它产生了大量的日志消息,但没有任何有关我的应用程序,如预期(也没有暗示任何特别的问题与备份引擎)。

我然后跑亚行外壳BMGR fullbackup com.commonsware.myapplication2 ,每文档,其中产生的:

  11-16 15:09:15.246 10372-10372 /? D / AndroidRuntime:调用主入口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:启动全数据传输com.commonsware.myapplication2备份
11-16 15:09:15.250 1406年至1418年/? I / GmsBackupTransport:尝试做com.commonsware.myapplication2完全备份
11-16 15:09:15.251 783-10419 /? I / AccountManagerService:getTypesVisibleToCaller:isPermitted?真正
11-16 15:09:15.257 1325年至1325年/? V / GLSActivity:AuthDelegateWrapperCreated与选定的意图:意图{CMP = com.google.android.gms / .auth.DefaultAuthDelegateService}
11-16 15:09:15.259 783-2127 /? I / AccountManagerService:getTypesVisibleToCaller:isPermitted?真正
11-16 15:09:15.262 1325年至1325年/? V / GLSActivity:AuthDelegateWrapperCreated与选定的意图:意图{CMP = com.google.android.gms / .auth.DefaultAuthDelegateService}
11-16 15:09:15.264 1325年至1325年/? V / GLSActivity:AuthDelegateWrapperCreated与选定的意图:意图{CMP = com.google.android.gms / .auth.DefaultAuthDelegateService}
11-16 15:09:15.284 1406年至1418年/? V / GmsBackupTransport:创建完整备份:com.commonsware.myapplication2
11-16 15:09:15.286 1406-10421 /? V / GmsBackupTransport:开始斯科蒂上传。
11-16 15:09:15.287 783-10422 /? D / BackupManagerService:绑定到完整备份代理:com.commonsware.myapplication2
11-16 15:09:15.291 783-10422 /? D / BackupManagerService:为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:拿到代理android.app.IBackupAgent$Stub$Proxy@f328610
11-16 15:09:15.299 783-1552 /? D / VoldConnector:SND  - > {8卷mkdirs /storage/emulated/0/Android/data/com.commonsware.myapplication2/files/}
11-16 15:09:15.302 783-878 /? D / VoldConnector:RCV<  -  {200 8命令成功}
11-16 15:09:15.302 7953-7965 / com.commonsware.myapplication2 V / BackupXmlParserLogging:机器人:fullBackupContent  - 真
11-16 15:09:15.309 783-10422 /? I / Backu prestoreController:获取部件状态用户:0
11-16 15:09:15.312 783-10425 /? I / file_backup_helper:名称:应用程序/ com.commonsware.myapplication2 / _manifest
11-16 15:09:15.313 783-10425 /? D / BackupManagerService:在com.commonsware.myapplication2调用doFullBackup()
11-16 15:09:15.320 7953-7967 / com.commonsware.myapplication2 I / file_backup_helper:名称:应用程序/ com.commonsware.myapplication2 / SP / com.commonsware.myapplication2_ preferences.xml
11-16 15:09:15.325 7953-7953 / com.commonsware.myapplication2 I /工艺:发送信号。 PID:7953 SIG:9
11-16 15:09:15.337 783-2131 /? D / GraphicsStats:缓冲区数:4
11-16 15:09:15.337 783-2131 /?我/的WindowState:WIN死亡:窗口{d0be7fd U0 com.commonsware.myapplication2 / com.commonsware.myapplication2.MainActivity}
11-16 15:09:15.357 783-2124 /? I / ActivityManager:过程com.commonsware.myapplication2(PID 7953)已死亡
11-16 15:09:15.357 783-2124 /? W / ActivityManager:强制删除ActivityRecord {d9c7ab7 U0 com.commonsware.myapplication2 / .MainActivity t1146}:应用程序死了,没有保存的状态
11-16 15:09:15.374 783-2124 /? I / ActivityManager:配置的变化= 480 {1.0 310mcc跨国公司EN_US ldltr sw360dp w360dp h568dp 480dpi NRML端口手指-keyb / V / H -nav / h的第9条修订?}
11-16 15:09:15.414 783-876 /? I / InputReader:重新配置的输入设备。变化= 0x00000004
11-16 15:09:15.414 783-876 /? I / InputReader:设备重新配置:n = 4,NAME ='touch_dev',尺寸1080x1920,方向0,模式1,显示ID 0
11-16 15:09:15.441 917-1161 /? E /表面:getSlotFromBufferLocked:未知缓冲区:0x9cfd78f0
11-16 15:09:15.446 783-1649 /? W / InputMethodManagerService:GOT的RemoteException发送SETACTIVE(假)通知,为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:最佳位置是空
11-16 15:09:15.551 3287-10448 /? I / MicroRecognitionRnrImpl:开始检测。
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 /窗口管理器:屏幕冻结+ 201ms由于窗口{48728f7 U0 com.android.systemui.ImageWallpaper}
11-16 15:09:15.566 199-10454 /? I / AudioFlinger:AudioFlinger的线程0xb2600000准备运行
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:无)in_snd_device(61:语音REC-MIC)
11-16 15:09:15.580 199-10454 /? D / msm8974_platform:platform_send_audio_calibration:发送音频校准snd_device(61)acdb_id(62)
11-16 15:09:15.580 199-10454 /? D /:无法抓取设备0000003E的查找信息
11-16 15:09:15.580 199-10454 /? E / ACDB装载机:错误:ACDB AudProc卷返回= -19
11-16 15:09:15.580 199-10454 /? D / audio_hw_primary:enable_snd_device:snd_device(61:语音REC-MIC)
11-16 15:09:15.583 199-10454 /? D / audio_hw_primary:enable_audio_route:应用和更新混频器路径:音频记录
11-16 15:09:15.641一四零六年至1593年/? D / GCoreFlp:FLP HAL存在,但批量大小为< = 0禁用FLP HAL。
11-16 15:09:15.649 783-2126 /? D / WifiService:acquireWifiLockLocked:WifiLock {NlpWifiLock型= 2 binder=android.os.BinderProxy@6b83dff}
11-16 15:09:15.651 783-897 /? D /无线:初始化公共字段10000,16,100,10
11-16 15:09:15.651 783-897 /? D /无线:桶[0] = 2:3:10000:2
11-16 15:09:15.670 3287-3287 /? W / MicroDetectionWorkerImp:标签[MicroDetectionWorkerImpl]太长;截断为[MicroDetectionWorkerImp]
11-16 15:09:15.670 3287-3287 /? I / MicroDetectionWorkerImp:onReady
11-16 15:09:15.971 3456-3476 /? W / OpenGLRenderer:错误地称为buildLayer上查看:ShortcutAndWidgetContainer,破坏层...
11-16 15:09:16.065 1406-10421 /? V / GmsBackupTransport:斯科蒂响应:RES = 200 =原料达2560 = 2560
11-16 15:09:16.069 783-10419 /? I / PFTBT:交通运输提出补偿= 0
11-16 15:09:16.083 783-10419 /? I / PFTBT:完全备份完成。
11-16 15:09:16.084 783-793 /? D / BackupManagerService:完成全运输备份。
 

一切似乎表明在备份错误或其它故障。

然后我删除了共享preferences 手动档,通过:

  ADB shell中运行,作为com.commonsware.myapplication2 RM /data/data/com.commonsware.myapplication2/shared_$p$pfs/com.commonsware.myapplication2_$p$pferences.xml
 

和确认共享preferences 文件不再存在。

我然后跑亚行外壳BMGR恢复com.commonsware.myapplication2 ,每文档。这产生的另一组日志信息,具有一些明显的错误:

  11-16 15:13:01.692 10593-10593 /? D / AndroidRuntime:调用主入口com.android.commands.bmgr.Bmgr
11月16日15:13:01.694 783-941 /? V / BackupManagerService:beginRestoreSession:PKG = com.commonsware.myapplication2运输= 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记号= 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?真正
11月16日15:13:01.703 1325年至1325年/? V / GLSActivity:AuthDelegateWrapperCreated与选定的意图:意图{CMP = com.google.android.gms / .auth.DefaultAuthDelegateService}
11月16日15:13:01.705 783-1552 /? I / AccountManagerService:getTypesVisibleToCaller:isPermitted?真正
11月16日15:13:01.707 1325年至1325年/? V / GLSActivity:AuthDelegateWrapperCreated与选定的意图:意图{CMP = com.google.android.gms / .auth.DefaultAuthDelegateService}
11月16日15:13:01.708 1325年至1325年/? V / GLSActivity:AuthDelegateWrapperCreated与选定的意图:意图{CMP = com.google.android.gms / .auth.DefaultAuthDelegateService}
11月16日15:13:01.991 1406年至1682年/? I / GmsBackupTransport:HTTP响应code:200
11月16日15:13:01.995 1406年至1887年/? I / GmsBackupTransport:当前还原包:PackageInfo {f7f23bd @下午@}
11月16日15:13:01.996 783-900 /? D / BackupManagerService:initiateOneRestore的packageName = @时@
11月16日15:13:02.008 1406年至1417年/? I / GmsBackupTransport:当前还原包:PackageInfo {733fdb2 com.commonsware.myapplication2}
11月16日15:13:02.009 783-900 /? I / BackupManagerService:下一步恢复包:RestoreDescription {com.commonsware.myapplication2:STREAM}
11月16日15:13:02.023 783-10612 /? I / AccountManagerService:getTypesVisibleToCaller:isPermitted?真正
11月16日15:13:02.213 1406年至1418年/? I / GmsBackupTransport:驱动下载HTTP响应状态:401
11月16日15:13:02.282 783-10612 /? I / AccountManagerService:getTypesVisibleToCaller:isPermitted?真正
11月16日15:13:02.311 783-10612 /? I / AccountManagerService:getTypesVisibleToCaller:isPermitted?真正
11月16日15:13:02.319 1325年至1325年/? V / GLSActivity:AuthDelegateWrapperCreated与选定的意图:意图{CMP = com.google.android.gms / .auth.DefaultAuthDelegateService}
11月16日15:13:02.321 783-1552 /? I / AccountManagerService:getTypesVisibleToCaller:isPermitted?真正
11月16日15:13:02.516 783-884 /? D / WifiStateMachine:为CWWPA_PSK与2427,5180开始扫描
11月16日15:13:02.517 783-886 /? D / ConnectivityService:updateNetworkScore为NetworkAgentInfo [WIFI() -  100] 60
11月16日15:13:02.517 783-886 /? D / ConnectivityService:重新匹配NetworkAgentInfo [WIFI() -  100]
11月16日15:13:02.695 1406年至1418年/? I / GmsBackupTransport:阅读下一大块的完整还原 -  IOException异常
11月16日15:13:09.611 783-10612 /? I / AccountManagerService:getTypesVisibleToCaller:isPermitted?真正
11月16日15:13:09.808 1406年至1418年/? I / GmsBackupTransport:驱动下载HTTP响应状态:401
11月16日15:13:09.834 783-10612 /? I / AccountManagerService:getTypesVisibleToCaller:isPermitted?真正
11月16日15:13:09.884 783-10612 /? I / AccountManagerService:getTypesVisibleToCaller:isPermitted?真正
11月16日15:13:09.892 1325年至1325年/? V / GLSActivity:AuthDelegateWrapperCreated与选定的意图:意图{CMP = com.google.android.gms / .auth.DefaultAuthDelegateService}
11月16日15:13:09.894 783-2126 /? I / AccountManagerService:getTypesVisibleToCaller:isPermitted?真正
11月16日15:13:09.897 1325年至1325年/? V / GLSActivity:AuthDelegateWrapperCreated与选定的意图:意图{CMP = com.google.android.gms / .auth.DefaultAuthDelegateService}
11月16日15:13:09.898 1325年至1325年/? V / GLSActivity:AuthDelegateWrapperCreated与选定的意图:意图{CMP = com.google.android.gms / .auth.DefaultAuthDelegateService}
11月16日15:13:10.110 1406年至1418年/? I / GmsBackupTransport:阅读下一大块的完整还原 -  IOException异常
11月16日15:13:10.110 1406年至1418年/? E / GmsBackupTransport:HTTP读取错误:java.io.IOException异常:未经授权的完整数据恢复请求
11月16日15:13:10.110 1406年至1418年/? E / GmsBackupTransport:无法读取完整的备份数据块:java.io.IOException异常:未经授权的完整数据恢复请求
11月16日15:13:10.112 783-10612 /? E / StreamFeederThread:错误的com.commonsware.myapplication2 -1002流恢复
11月16日15:13:10.119 783-10612 /? I / ActivityManager:强制停止com.commonsware.myapplication2的appid = 10193 USER = 0:清除数据
11月16日15:13:10.140 783-796 /? I / ActivityManager:启动PROC 10623:com.android.documentsui / u0a36广播com.android.documentsui / .PackageReceiver
11月16日15:13:10.174 10623-10623 /? W /系统:ClassLoader的引用了未知的路径:/系统/应用/ DocumentsUI / lib中/ ARM
11月16日15:13:10.198 1440-10637 /? D / PackageBroadcastService:接收到的广播动作= android.intent.action.PACKAGE_DATA_CLEARED和URI = com.commonsware.myapplication2
11月16日15:13:10.198 1440-10637 /? D / AccountUtils:清除选择账户com.commonsware.myapplication2
11月16日15:13:10.203 1440-10637 /? I / LocationSettingsChecker:删除对话框SUP pression标志包装com.commonsware.myapplication2
11月16日15:13:10.208 1440至2449年/? I /冰:doRemovePackageData com.commonsware.myapplication2
11月16日15:13:10.232 783-900 /? V / BackupManagerService:没有更多的包;整理恢复
11月16日15:13:10.234 783-900 /? I / Backu prestoreController:restoreFinished为0
11月16日15:13:10.234 783-900 /? I / BackupManagerService:恢复完成。
11月16日15:13:10.234 783-793 /? D / RestoreSession:endRestoreSession
11月16日15:13:10.234 10593-10593 /? D / AndroidRuntime:关闭虚拟机
11月16日15:13:10.235 783-900 /? V / BackupManagerService:清除恢复会话,并停止超时
11月16日15:13:10.279 783-1544 /? I / ActivityManager:启动PROC 10661:com.android.externalstorage / u0a6为内容提供商com.android.externalstorage / .ExternalStorageProvider
11月16日15:13:10.301 10661-10661 /? W /系统:ClassLoader的引用了未知的路径:/系统/私法-应用程序/ ExternalStorageProvider / lib中/ ARM
11月16日15:13:10.307 10661-10661 /? D / ExternalStorage:更新卷后,发现1活跃根
11月16日15:13:10.336 783-1544 /? I / ActivityManager:启动PROC 10675:com.android.shell / 2000为内容提供商com.android.shell / .BugreportStorageProvider
11月16日15:13:10.360 10675-10675 /? W /系统:ClassLoader的引用了未知的路径:/系统/私法-应用程序/壳牌/ lib中/ ARM
11月16日15:13:10.371 10623-10636 /? D /文件:更新发现7根在156ms
11月16日15:13:10.377 10623-10674 /? D /文件:更新发现7根在为65μs
11月16日15:13:14.635 783-886 /? D / ConnectivityService:updateNetworkScore为NetworkAgentInfo [WIFI() -  100] 56
11月16日15:13:14.635 783-886 /? D / ConnectivityService:重新匹配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:为CWWPA_PSK与2427,5180开始扫描
11月16日15:13:23.729 783-886 /? D / ConnectivityService:updateNetworkScore为NetworkAgentInfo [WIFI() -  100] 60
11月16日15:13:23.731 783-886 /? D / ConnectivityService:重新匹配NetworkAgentInfo [WIFI() -  100]
 

中的令人担忧的子集:

  11-16 15:13:10.110 1406年至1418年/? I / GmsBackupTransport:阅读下一大块的完整还原 -  IOException异常
11月16日15:13:10.110 1406年至1418年/? E / GmsBackupTransport:HTTP读取错误:java.io.IOException异常:未经授权的完整数据恢复请求
11月16日15:13:10.110 1406年至1418年/? E / GmsBackupTransport:无法读取完整的备份数据块:java.io.IOException异常:未经授权的完整数据恢复请求
11月16日15:13:10.112 783-10612 /? E / StreamFeederThread:错误的com.commonsware.myapplication2 -1002流恢复
 

和,果不其然,该文件是不可恢复的。我不知道什么是未经授权的完整的数据恢复请求的意思。

所以,我卸载应用程序(通过摇篮uninstallDebug ),并且不需要通过摇篮installDebug )。根据文档,你可以测试通过卸载并重新安装您的应用程序为您的应用程序的自动恢复。该应用程序数据从云中自动恢复,一旦应用程序安装完成。然而,在重新安装了几分钟之后,共享preferences 文件仍然不存在。

我然后跑亚行外壳BMGR再次还原com.commonsware.myapplication2 ,并得到了一组类似的日志记录语句,具有相同的未经授权的完整的数据恢复请求消息

是否有步骤这个过程中,我很想念或者其他没有证件?

修改:我一直在测试在实际硬件(一台Nexus 6)。每MH的评论,我测试的是Android 6.0模拟器(没有播放服务)此过程中,和它的作品。这表明,该文件是不是的完全的错误,虽然它仍然回避,为什么它不工作的硬件问题。

在讨论和测试各种情景(请参阅下面的问题,评论)
解决方案

之后,我决定结合起来,并写了这些结果变成一个答案。在现实中,这实际上并没有解决问题presented,但它会回答的你怎么successfuly使用命令行工具(或任何其他)来测试了Android 6.0的备份问题和恢复行为吗?的它会做这样的一步一步的指导,概述为我工作的形式和我如何克服各种碰壁我encounted前进的道路上。

下面去。如果你还没有通过培训转眼就配置自动备份的应用程序 然而,我建议你这样做第一。它记录了自动备份功能,并已经这样做了记录的各个步骤的一个非常体面的工作。

让我们从头开始:我们需要一个应用程序来测试!就像CommonsWare,我只是用Android的Studio来创建一个空缺的活动一个新的项目。请确保您设置的API 23的目标SDK。打开自动生成的 MainActivity ,并添加一些code到的onCreate()坚持一个值,该共享preferences(或只是复制从问题的code段):

  preferenceManager
  .getDefaultShared preferences(本)
  。编辑()
  .putBoolean(富,真)
  。应用();
 

构建,部署和运行应用程序。这应该引起被持久化,并会导致磁盘上所创建的XML文件。与确认:

  ADB shell中运行,为<程序包> LS -al shared_ preFS
 

我的测试应用程序的装箱率是 com.example.mh.backuptest (这是我在这个例子中使用从这里开始的命令),所以我的命令是:

  ADB shell中运行,作为com.example.mh.backuptest -al ls的shared_ preFS
 

您应该看到输出列表中的 shared_ preFS 文件夹,所有文件的单一线,应该只有一个:

  com.example.mh.backuptest_ preferences.xml
 

这意味着已成功创建了preference文件和被写入其中。如果你喜欢,你可以检查该文件的内容证实了这一点。

现在,回到检测自动备份。首先,确保你在自动应用程序备份选择。在你的Andr​​oid 6.0设备,请访问:

 设置>备份和放大器;复位>备份我的数据>上
 

在此之后,打开详细日志记录备份传输和备份XML解析器,这样我们就可以看到发生了什么:

 亚行外壳setprop log.tag.GmsBackupTransport VERBOSE
亚行外壳setprop log.tag.BackupXmlParserLogging VERBOSE
 

然后,初始化备份管理器:

 亚行外壳BMGR运行
 

这应该产生在logcat中相当多的输出。您应该看到至少有一些与此类似:

  D / AndroidRuntime:调用主入口com.android.commands.bmgr.Bmgr
V / BackupManagerService:安排立即备份通
V / BackupManagerService:运行备份通
V / BackupManagerService:清理未决备份
V / PerformBackupTask:开始的1目标备份
D / PerformBackupTask:invokeAgentForBackup上@下午@
I / Backu prestoreController:获取部件状态用户:0
D / PerformBackupTask:中Backu prequest {PKG = com.google.android.googlequicksearchbox}开始键/值备份
D / BackupManagerService:等待代理ApplicationInfo {9f9289c com.google.android.googlequicksearchbox}
D / BackupManagerService:agentConnected PKG = com.google.android.googlequicksearchbox agent=android.os.BinderProxy@dcdbafd
I / BackupManagerService:拿到代理android.app.IBackupAgent$Stub$Proxy@c3fe3f2
D / PerformBackupTask:invokeAgentForBackup上com.google.android.googlequicksearchbox
D / BackupHelperDispatcher:处理现有的帮手'L'com.android.launcher3.LauncherBackupHelper@7e2dcc3
V / LauncherBackupHelper:lastBackupTime = 1448612678367
W / LauncherBackupHelper:应用最喜欢的空意图:223
I / Backu prestoreController:获取部件状态用户:0
V / GmsBackupTransport:启动新的备份会话
V / GmsBackupTransport:开始performBackup为com.google.android.googlequicksearchbox
V / GmsBackupTransport:performBackup做了com.google.android.googlequicksearchbox
V / GmsBackupTransport:发送请求:101667字节
I / GmsBackupTransport:HTTP响应code:200
V / GmsBackupTransport:备份完成的com.google.android.googlequicksearchbox
I / BackupManagerService:备份传球完成。
 

如果您输出包含更多的不要担心。我故意去掉不相关的备份线路。我只仅粘贴在一个单一的应用程序是越来越备份的输出;你可能会看到更多的项目在第一次运行这个命令。

如果不是你看到的线沿线的东西:

  GmsBackupTransport:斯科蒂传输异常。空值
PFTBT:错误-1002备份com.example.mh.backuptest
 

或者

  GmsBackupTransport:拒绝完整的数据备份。用户还没有看到保持最新的法律文本
 

请确保您已选择在自动备份的应用程序(见上文)。如果你有,你看到的仍然是这些消息 - 这事对我来说太 - 试试切换设置了几次,重新启动设备。仍然没有运气?我一直在那里......从设备,重启删除谷歌帐户,重新添加它并再次选择研究。别人有href="http://stackoverflow.com/a/33478196/1029225">报道一个工厂重置工程太

如果你走得很远了这一点,那么它的时间,以确保我们的测试应用程序获取备份!要强制备份,运行:

 亚行外壳BMGR fullbackup com.example.mh.backuptest
 

这会杀了你的应用程序,如果它仍在运行 - 不要担心,这是正常的。你应该看到相当长的一段输出从备份传输:

  D / AndroidRuntime:调用主入口com.android.commands.bmgr.Bmgr
D / BackupManagerService:fullTransportBackup()
I / PFTBT:启动全数据传输com.example.mh.backuptest备份
V / GmsBackupTransport:创建完整备份:com.example.mh.backuptest
V / GmsBackupTransport:开始斯科蒂上传。
D / BackupManagerService:绑定到完整备份代理:com.example.mh.backuptest
I / ActivityManager:启动PROC 22032:com.example.mh.backuptest / u0a491用于备份的android / FullBackupAgent
D / BackupManagerService:等待代理ApplicationInfo {dd359cd com.example.mh.backuptest}
V / GmsBackupTransport:[读]
V / GmsBackupTransport:[阅读]等待avaible数据。
BackupManagerService:agentConnected PKG = com.example.mh.backuptest agent=android.os.BinderProxy@9e7e282
I / BackupManagerService:拿到代理android.app.IBackupAgent$Stub$Proxy@14b3d93
V / BackupXmlParserLogging:机器人:fullBackupContent  - 真
I / Backu prestoreController:获取部件状态用户:0
I / file_backup_helper:名称:应用程序/ com.example.mh.backuptest / _manifest
V / GmsBackupTransport:[PUSH]推512字节到管道。
V / GmsBackupTransport:可用[PUSH]信号数据。
V / GmsBackupTransport:[PUSH]等待数据被处理。
V / GmsBackupTransport:[阅读]读取256个字节的数据。
V / GmsBackupTransport:[读]
V / GmsBackupTransport:[阅读]读取256个字节的数据。
V / GmsBackupTransport:[读]信号数据进行处理。
V / GmsBackupTransport:[读]
V / GmsBackupTransport:[阅读]等待avaible数据。
V / GmsBackupTransport:[PUSH]按2048字节到管道。
V / GmsBackupTransport:可用[PUSH]信号数据。
V / GmsBackupTransport:[PUSH]等待数据被处理。
V / GmsBackupTransport:[阅读]读取256个字节的数据。
V / GmsBackupTransport:[读]
V / GmsBackupTransport:[阅读]读取256个字节的数据。
V / GmsBackupTransport:[读]
V / GmsBackupTransport:[阅读]读取256个字节的数据。
V / GmsBackupTransport:[读]
V / GmsBackupTransport:[阅读]读取256个字节的数据。
V / GmsBackupTransport:[读]
V / GmsBackupTransport:[阅读]读取256个字节的数据。
V / GmsBackupTransport:[读]
V / GmsBackupTransport:[阅读]读取256个字节的数据。
V / GmsBackupTransport:[读]
V / GmsBackupTransport:[阅读]读取256个字节的数据。
V / GmsBackupTransport:[读]
V / GmsBackupTransport:[阅读]读取256个字节的数据。
V / GmsBackupTransport:[读]信号数据进行处理。
V / GmsBackupTransport:[读]
V / GmsBackupTransport:[阅读]等待avaible数据。
D / BackupManagerService:在com.example.mh.backuptest调用doFullBackup()
I / file_backup_helper:名称:应用程序/ com.example.mh.backuptest / SP / com.example.mh.backuptest_ preferences.xml
V / GmsBackupTransport:[PUSH]推512字节到管道。
V / GmsBackupTransport:可用[PUSH]信号数据。
V / GmsBackupTransport:[PUSH]等待数据被处理。
V / GmsBackupTransport:[阅读]读取256个字节的数据。
V / GmsBackupTransport:[读]
V / GmsBackupTransport:[阅读]读取256个字节的数据。
V / GmsBackupTransport:[读]信号数据进行处理。
V / GmsBackupTransport:[读]
V / GmsBackupTransport:[阅读]等待avaible数据。
V / GmsBackupTransport:[PUSH]推512字节到管道。
V / GmsBackupTransport:可用[PUSH]信号数据。
V / GmsBackupTransport:[PUSH]等待数据被处理。
V / GmsBackupTransport:[阅读]读取256个字节的数据。
V / GmsBackupTransport:[读]
V / GmsBackupTransport:[阅读]读取256个字节的数据。
V / GmsBackupTransport:[读]信号数据进行处理。
V / GmsBackupTransport:[读]
V / GmsBackupTransport:[阅读]等待avaible数据。
V / GmsBackupTransport:[完成]信号没有更多的数据。
I /工艺:发送信号。 PID:22032 SIG:9
I / ActivityManager:过程com.example.mh.backuptest(PID 22032)已死亡
V / GmsBackupTransport:斯科蒂响应:RES = 200 =原料达3584 = 1047
I / PFTBT:交通运输提出补偿= 0
I / PFTBT:完全备份完成。
D / BackupManagerService:完成全运输备份。
 

通过我们的测试应用程序备份,让我们来看看它实际上是恢复数据了。首先,让我们删除,我们的测试应用程序创建的preference文件,这是默认的自动备份的一部分:

  ADB shell中运行,作为com.example.mh.backuptest RM shared_ preFS / com.example.mh.backuptest_ preferences.xml
 

确认文件已经不存在:

  ADB shell中运行,作为com.example.mh.backuptest -al ls的shared_ preFS
 

如果该命令没有任何输出执行,这意味着有在 shared_ preFS 文件夹中没有文件,您已成功删除了preFS。

现在,触发恢复我们的测试程序:

 亚行外壳BMGR恢复com.example.mh.backuptest
 

再次备份传输会产生相当长的输出:

  V / BackupManagerService:beginRestoreSession:PKG = com.example.mh.backuptest运输= 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记号= 31eda3bdfd5fddb7
D / BackupManagerService:MSG_RUN_RESTORE observer=android.app.backup.IRestoreObserver$Stub$Proxy@23829fa
V / GmsBackupTransport:新的恢复会话,2的应用程序
V / GmsBackupTransport:发送请求:471字节
I / GmsBackupTransport:HTTP响应code:200
V / GmsBackupTransport:// @下午:109项
I / GmsBackupTransport:当前还原包:PackageInfo {195d280 @下午@}
V / GmsBackupTransport:一个键/值对恢复
D / BackupManagerService:initiateOneRestore的packageName = @时@
I / GmsBackupTransport:当前还原包:PackageInfo {1edd0b9 com.example.mh.backuptest}
V / GmsBackupTransport:完全还原: https://www.googleapis.com/drive/v2/files/XXXXXXXXXXXXXXXXXXXXXXXXXXXX?alt=media&sources=ANDROID_BACKUP
I / BackupManagerService:下一步恢复包:RestoreDescription {com.example.mh.backuptest:STREAM}
V / GmsBackupTransport:读第一块为com.example.mh.backuptest
V / GmsBackupTransport:创建com.example.mh.backuptest http连接
I / GmsBackupTransport:驱动下载HTTP响应状态:200
V / GmsBackupTransport:CONTENTLENGTH是3584
V / GmsBackupTransport:下载:三千五百八十四分之八百零八字节
V / GmsBackupTransport:阅读808字节
V / GmsBackupTransport:读下一大块的com.example.mh.backuptest
V / GmsBackupTransport:下载:三千五百八十四分之二千一百九十七字节
V / GmsBackupTransport:读1389字节
I / RestoreEngine:SIG +版本匹配;获取数据
V / GmsBackupTransport:读下一大块的com.example.mh.backuptest
V / GmsBackupTransport:下载:三千五百八十四分之三千五百八十四字节
V / GmsBackupTransport:读1387字节
V / GmsBackupTransport:读下一大块的com.example.mh.backuptest
V / GmsBackupTransport:读-1字节
D / RestoreEngine:需要启动代理com.example.mh.backuptest
D / RestoreEngine:清除应用程序数据preparatory充分恢复
I / ActivityManager:强制停止com.example.mh.backuptest的appid = 10491 USER = 0:清除数据
V / GmsBackupTransport:达到HTTP内容结束 - 没有更多的数据
D / PackageBroadcastService:接收到的广播动作= android.intent.action.PACKAGE_DATA_CLEARED和URI = com.example.mh.backuptest
D / AccountUtils:清除选择账户com.example.mh.backuptest
I / LocationSettingsChecker:删除对话框SUP pression标志包装com.example.mh.backuptest
I /冰:doRemovePackageData com.example.mh.backuptest
I / ActivityManager:启动PROC 22708:com.example.mh.backuptest / u0a491用于备份的android / FullBackupAgent
D / BackupManagerService:等待代理ApplicationInfo {dd359cd com.example.mh.backuptest}
D / BackupManagerService:agentConnected PKG = com.example.mh.backuptest agent=android.os.BinderProxy@7875d75
I / BackupManagerService:拿到代理android.app.IBackupAgent$Stub$Proxy@9aa10a
D / VoldConnector:SND  - > {14卷mkdirs /storage/emulated/0/Android/data/com.example.mh.backuptest/files/}
D / VoldConnector:RCV<  -  {200 14命令成功}
V / BackupXmlParserLogging:机器人:fullBackupContent  - 真
V / BackupManagerService:没有更多的包;整理恢复
V / GmsBackupTransport:恢复完成
D / RestoreSession:endRestoreSession
I / Backu prestoreController:restoreFinished为0
I / BackupManagerService:恢复完成。
 

如果一切看起来就像上面,让我们检查,如果我们的preference文件是回到了它应该是:

  ADB shell中运行,作为com.example.mh.backuptest -al ls的shared_ preFS
 

输出应该是你所看到的第一次运行命令(在这个相当长的故事的早期阶段)。如果是这样,它的时间为祝贺!你已经设法成功地备份和恢复您的应用程序使用谷歌的自动备份的应用程序!

快乐?然后,让我们做一个更多的考验!卸载应用程序:

 亚行卸载com.example.mh.backuptest
 

尽管我们看到了成功,确认它的消失:

  ADB shell中运行,作为com.example.mh.backuptest
 

期望的输出:

I /工艺:发送信号。



TL;DR: How do you successfuly use the command-line tools (or anything else) to test the Android 6.0 backup and restore behavior, as I cannot get them to restore anything?


Since I was running into problems earlier with a sample app from my book trying to get this working, I started from scratch for the purposes of this question.

I created a brand-new project from the Android Studio 1.4.1 new-project wizard, accepting all relevant defaults, except I went with the "Empty Activity" template and added a 2 to the application ID and display name. I then added a bit of code to the activity to give me some data on internal storage:

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();
  }
}

I ran the app and confirmed, using adb shell run-as com.commonsware.myapplication2 ... that the SharedPreferences file existed.

I then ran adb shell setprop log.tag.BackupXmlParserLogging VERBOSE, per the docs. No obvious problems.

I then ran adb shell bmgr run, per the docs, which generated a lot of logging messages but nothing pertaining to my app, as expected (and also not suggesting any particular problems with the backup engine).

I then ran adb shell bmgr fullbackup com.commonsware.myapplication2, per the docs, which generated:

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.

Nothing seems indicative of an error or other failure in the backup.

I then deleted the SharedPreferences file manually, via:

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

and confirmed that the SharedPreferences file no longer exists.

I then ran adb shell bmgr restore com.commonsware.myapplication2, per the docs. This generated another set of logging messages, with some apparent errors:

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]

The worrisome subset of that is:

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

And, sure enough, the file is not restored. I have no idea what an "Unauthorized full data restore request" means.

So, I uninstalled the app (via gradle uninstallDebug) and installed it again without running it (via gradle installDebug). According to the docs, "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." However, a few minutes after reinstalling it, the SharedPreferences file still does not exist.

I then ran adb shell bmgr restore com.commonsware.myapplication2 again, and got a similar set of logging statements, with the same "Unauthorized full data restore request" message.

Are there steps to this process that I am missing or are otherwise undocumented?

EDIT: I had been testing on actual hardware (a Nexus 6). Per MH's comment, I tested this procedure on an Android 6.0 emulator (sans Play Services), and it works. That suggests that the documentation isn't completely wrong, though it still begs the question of why it's not working with hardware.

解决方案

After having discussed and tested various scenarios (refer to comments below the question), I've decided to combine and write up those results into an answer. In reality, this doesn't actually solve the problem presented, but it will answer the question of "How do you successfuly use the command-line tools (or anything else) to test the Android 6.0 backup and restore behavior?" It will do so in the form of a step-by-step guide outlining what worked for me and how I overcame the various snags I encounted along the way.

Here goes. If you haven't gone through the training on "Configuring Auto Backup for Apps" yet, I'd suggest you do that first. It documents the auto-backup feature and already does a very decent job of documenting the various steps.

Let's start at the beginning: we need an app to test with! Just like CommonsWare, I simply used Android Studio to create a new project with an Empty activity. Make sure you set API 23 as target SDK. Open up the auto-generated MainActivity and add some code into onCreate() to persist a value into the shared preferences (or just copy the code snippet from the question):

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

Build, deploy and run the app. This should trigger foo to be persisted, and will result in an xml file being created on disk. Confirm this with:

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

My test app's packge is com.example.mh.backuptest (which is what I'll use in the example commands from here on), so my command is:

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

You should see a single line of output listing all files in the shared_prefs folder, which should be only one:

com.example.mh.backuptest_preferences.xml

This means the preference file was successfully created and foo was written to it. If you like, you can inspect the file's contents to confirm this.

Now, back to testing auto-backup. First, make sure you're opted in to automatic app backups. On your Android 6.0 device, go to:

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

After that, turn on verbose logging for the backup transport and backup xml parser so that we can see what's happening:

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

Then, initialise the backup manager:

adb shell bmgr run

This should generate quite a bit of output in logcat. You should see at least something similar to this:

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.

Don't worry if your output contains a lot more. I intentionally removed lines not relevant to backing up. I've only only pasted in the output for when a single app is getting backed up; you will probably see a lot more entries the first time you run this command.

If instead you see something along the lines of:

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

Or:

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

Make sure you have opted in to automatic app backups (see above). If you have and you're still seeing these messages - which happened for me too - try toggling the setting a few times and rebooting the device. Still no luck? I've been there... Remove the Google account from the device, reboot, re-add it and opt in again. Others have reported that a factory reset works too, but that seems a little overboard to me. :)

If you got this far, then it's time to ensure our test app gets backed up! To force a backup, run:

adb shell bmgr fullbackup com.example.mh.backuptest

This will kill your app if it's still running - don't worry, that's normal. You should see quite some output from the backup transport:

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.

With our test app backed up, let's see if it in fact restores data too. First, let's remove the preference file that our test app created and that is part of the default auto backup:

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

Confirm that the file is no longer there:

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

If the command executes without any output, it means there were no files in the shared_prefs folder and that you successfully deleted the prefs.

Now, trigger a restore for our test app:

adb shell bmgr restore com.example.mh.backuptest

Again, backup transport will generate quite some output:

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.

If everything looks like above, let's check if our preference file is back where it should be:

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

The output should be what you saw the very first time you ran the command (in the early stages of this rather long story). If so, it's time for congratulations! You've managed to successfully backup and restore your app using Google's Auto Backup for Apps!

Happy? Then let's do one more test! Uninstall the app:

adb uninstall com.example.mh.backuptest

Even though we see 'Success', confirm that it's gone:

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

Expected output:

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

Now, install the app again (but don't start it):

adb install backuptest.apk 

Have a look at 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.


Sources:

这篇关于你怎么测试了Android 6.0全备份行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆