全面复盘Android开发者容易忽视的Backup功能(1)

本文涉及的产品
阿里云百炼推荐规格 ADB PostgreSQL,4核16GB 100GB 1个月
日志服务 SLS,月写入数据量 50GB 1个月
简介: 全面复盘Android开发者容易忽视的Backup功能(1)

allowBackup属性大家都不陌生,为了安全起见最好将它关闭。对它的认识好像也仅限于此了,事实上Google在Backup功能上花了很多心思,提供了多个模式的选择和充分的定制接口。本文将带大家全面复盘Backup功能的由来、原理和定制方法,以备不时之需。篇幅较长,配合收藏更佳。

为节省部分读者的时间,贴出重点章节供快速空降。

  • 关心Backup功能原理的,直接空降2.8章节
  • 关心Backup功能测试的,直接空降3.2章节
  • 关心Backup文件破解的,直接空降3.3章节
  • 关心Backup实战的,直接空降4.0章节
  • 关心Android 12影响的,直接空降5.0章节

1. 前言

两年前我就遇到过一个Backup功能相关的CTS问题,说的是整机恢复到AccessibilitySerivce的时候发生错误。整机备份和恢复非常耗时,我不可能真的跑一遍去定位问题,我得找个高效的办法。


通过查阅Backup的原理我知道了可以单独Backup和Restore某个app,甚至可以解密备份文件查看数据内容。有了这些方法的协助,我很快就找到了原因。


虽然很快地解决了那个问题,但我的心里留下了一个想法。Backup功能好像比我想象的复杂有趣,一定要找个时间好好了解一下。恰逢近期在做Backup功能的定制,对这块有了充分的认识,便整理出来分享给大家。

2. 完整认识Backup

2.1 功能由来

手机等智能设备是现代生活中的重要角色,我们会在这些智能设备上做登录账户,设置偏好,拍摄照片,保存联系人等日常操作。


这些数据耗费了我们很多时间和精力,对我们而言极为重要。如果我们的设备换代了或者重新安装了某个应用,之前使用的数据如果能自动保留,那将是非常出色的用户体验。而保留数据的第一步则在于Backup环节。

2.2 数据来源

用户的数据可以笼统地划分为三块:登录账号相关的身份数据、系统设置相关的偏好以及各App的数据。这三块数据的类型不同、位置不同,进而导致Backup的实现也不同。

1832b220aa754cd18c504acc7686a560.png

App数据:应用内部的图片,视频等数据。这是我们尤为关心的数据,如何安全完整地转移这些数据是Backup功能的目标所在,也是本文需要讲解的核心内容

身份数据:用户登录的身份数据。可以通过Smart Lock或Account Transfer API在设备间立即恢复登录状态

设置偏好:系统设置App和SettingProvider将记录用户的偏好数据,甚至包括用户授予App的权限记录。系统将针对这些设置数据备份和恢复

2.3 备份对象

我们知道可以将数据存放在App目录,也可以存放于公共目录。但随着Android系统针对公共目录的限制愈加严格,将数据存放到App自己的目录显得更加合理。

App自身目录的这块数据顺理成章地成为Backup功能的主要对象,按照文件的类型可以细分如下。

1672147209077.png

注意:


放置在外部存储空间中的文件也是支持的,这里不再赘述

cache、nobackup等目录下的文件不在Backup对象内

Backup操作从最外层的data目录开始,按照文件单位逐个读取逐个备份。目录内的文件一般按照文件名的顺序进行备份,但这个顺序无法保证,取决于File#list() API的结果。

1672147248093.png

2.4 如何开启

在Manifest文件里使用allowBackup属性可以控制Backup功能的开关。这个属性早在Android 1.6(API 4)的时候便引入了,起初默认是关闭的。


allowBackup

Added in API level 4

Whether to allow the application to participate in the backup and restore infrastructure. If this attribute is set to false, no >backup or restore of the application will ever be performed, even by a full-system backup that would otherwise cause all >application data to be saved via adb. The default value of this attribute is true.


可能是Android设备火了,备份恢复的需求越来越大,自Android 6.0之后默认值变成了true,即默认将支持Backup功能。

2.5 开启的隐患

allowBackup属性开启的话,开发者使用几个简单的adb命令就可以将应用的数据备份和恢复。意味着自己的数据被转移到别人的设备上是非常简单的,这无疑造成了具大的安全隐患。


后面的实战将会揭晓控制备份和恢复的诸多可能,比如在恢复的逻辑里加入了限制使得恶意的恢复失败。但即便在恢复阶段拦截了,备份的ab文件仍掌握在别人手里,仍不稳妥。因为通过破解备份文件也可以阅读到部分甚至全部内容。


所以涉及到私密数据的App最好将该属性关闭,自行考虑数据的同步方式,比如通过账号系统恢复。


这个属性曾经引发安全隐患,详情可参考:https://blog.csdn.net/zihao2012/article/details/44220389

2.6 备份模式

Android 6.0之前Backup功能只有键值对备份(Key-value Backup)这一种模式,而且默认是关闭的。


想要打开键值对备份功能得将allowBackup属性设置为true,并指定BackupAgent实现,即明确地告知诉Backup功能每个文件按照什么key备份到Android Backup Service。简单来讲,必须给Backup功能提供一个备份文件的映射关系,好让它知道备份的源头和恢复的目标。


6.0之后allowBackup属性默认为true,但打开的不是键值对备份,而是新引入的自动备份(Auto Backup)。自动备份模式执行傻瓜式的全体备份和恢复,可供备份文件存放的空间更大,便捷够用更推荐。。


两个模式在备份的频次、文件的存放位置、恢复的执行时机等细节都很不一样。

1672147302106.png

2.7 备份的托管位置

使用键值对模式备份的文件托管在Google服务器(Android Backup Service),Google承诺将会加密传输这些数据,并尊重隐私条款。同时在App关闭Backup功能的时候删除这些备份,可以放心使用。


如果采用了默认的自动备份模式,那数据存放在Google Drive云盘。云盘拥有自己的账号系统,使用的是账号级别的加密保护,更为安全。

2.8 实现原理

那Android系统是如何实现Backup和Restore功能的呢?


在解答这个问题之前,我们先思考下如果你是Google开发者,你会怎么实现?


这里有个ContentProvider方案。简言之,使用一个统一调度的App通过ContentProvider组件向各个实现了特定Uri或Permission的ContentProvider App发出读写数据的请求。


各App通过ContentProvider将需要备份的Data、File、DB以及SP文件传输出去,调度App收集到包名为单位的备份文件集合,加密后上传到服务器或内存卡

恢复则是调度App将文件解密之后通过ContentProvider再回传给各App,各App自行执行恢复的逻辑

但这个方案有点缺憾。对于大部分App来说文件全部备份和恢复就行了,不需要搞特别的定制。但实际情况是需要支持备份恢复的话,就得各自实现一套ContentProvider去做文件的收集和覆盖。


而Google采取的方案是这样的。默认认为每个App都支持Backup功能,然后给App提供同样的BackupAgent去执行自动备份和恢复的处理。当App存在特别定制的需求的时候可以指定扩展的BackupAgent逻辑,更加灵活高效。


内部的实现原理简述如下。


系统服务BMS(BackupManagerService)收到BackupManager API发起的备份/恢复请求后,该服务将通过IBackupTransport和Cloud端建立连接

BMS通过持有的BackupHandler依据操作参数启动相应的Backup或Restore线程

任务线程通过AppBackupUtils检查该App是否支持Backup/Restore

之后依据备份模式创建对应的Engine并通过通过IBackupAgent向App发起实际的操作请求

BackupAgent将按照对应模式去读取或写入文件

1832b220aa754cd18c504acc7686a560.png

3. 发起、调试和解密Backup

3.1 Backup/Restore的发起

3.1.1 代码方式

选取了键值对备份模式的话,需要在数据发生变动的时候手动发起备份。SDK提供了API:BackupManager的dataChanged()。调用之后BackupManager将调度备份请求在适当的时机发起备份处理。


事实上BackupManager还提供了requestRestore()供我们手动发起恢复,API的返回值将告诉我们是否将要执行恢复操作。这个API发起的恢复结束之后不会KILL进程,存在造成数据错乱的隐患,最好依赖于系统自行的恢复操作。

※自Android 9.0开始这个API废弃了,调用了也没有反应。

3.1.2 命令方式

ⅰ. adb命令

adb的backup和restore命令可以帮助我们手动发起较为简单的请求,但只支持自动备份模式。

  • Backup
// 比如备份某个App的数据并以指定的名称保存备份文件
adb backup -f <fileName>.ab -apk <packageName>

接下来系统会提示我们输入备份密码。

1832b220aa754cd18c504acc7686a560.png

输完密码之后点击开始备份,系统将弹出备份开始或结束的Toast。当然不输入密码直接备份也是可以的,但备份的数据容易被破解。

  • Restore
// 发起恢复请求的命令很简单
adb restore <fileName>.ab

接下来输入密码开始恢复,同样的会有Toast提示恢复的进度。

1832b220aa754cd18c504acc7686a560.png

ⅱ.bmgr工具

adb backup命令提供的功能不够强大,官方推荐bmgr工具。它将备份和恢复的步骤分得更细,便于我们理清各个环节,更好的协助我们测试备份和恢复的逻辑。


bmgr工具没有UI,完全通过命令在后台默默运行。


首先需要启用它。

注意:要确保设置里的Backup功能没有被关闭,Settings > Backup & Restore。

>adb shell bmgr enabled
Backup Manager currently enabled

接着,查看ROM里支持的文件传输服务,*号表示当前选择的服务。

>adb shell bmgr list transports 
    com.android.localtransport/.LocalTransport
    com.google.android.gms/.backup.migrate.service.D2dTransport
  * com.google.android.gms/.backup.BackupTransportService

GMS的传输服务要求设备联网和科学上网,为方面测试我们切换服务为本地传输

>adb shell bmgr transport com.android.localtransport/.LocalTransport
Selected transport com.android.localtransport/.LocalTransport (formerly com.google.android.gms/.backup.BackupTransportService)

查看传输服务的更改是否生效。

>adb shell bmgr list transports
  * com.android.localtransport/.LocalTransport
    com.google.android.gms/.backup.migrate.service.D2dTransport
    com.google.android.gms/.backup.BackupTransportService

针对某个App发起备份。

>adb shell bmgr backupnow <package>

在另一个终端捕捉备份的执行日志,有可能会提示没有设置锁屏密码

Backup  : [CryptoEnableCheck] Should not encrypt backups: device has no lock screen.

设置密码后再次发起备份,可以看到成功备份了。

>adb shell bmgr backupnow <package>
Package xxx with result: Success
Backup finished with result: Success

日志终端也显示回调了App指定的BackupAgent

AndroidRuntime: Calling main entry com.android.commands.bmgr.Bmgr
PFTBT   : backupmanager pftbt token=4081832e
BackupManagerService: awaiting agent for ApplicationInfo{30f779b xxx}
BackupRestoreAgent: MyBackupAgent()
BackupRestoreAgent: onCreate()
BackupManagerService: agentConnected pkg=xxx agent=android.os.BinderProxy@5f88b66
BackupManagerService: got agent android.app.IBackupAgent$Stub$Proxy@c309ea7
BackupRestoreAgent: onBackup()
BackupRestoreAgent: onDestroy()

bmgr工具在手动恢复的时候需要Token信息,通过dumpsys backup获取对应的Token。Token来自于AncestralCurrent两个标签的组合,比如本次的Token为01。

>adb shell dumpsys backup
Backup Manager is enabled / setup complete / not pending init
Auto-restore is enabled
No backups running
Last backup pass started: 1619317275335 (now = 1619319671619)
  next scheduled: 1619332172012
...
Ancestral: 0 ★
Current:   1 ★
...

清空App数据。

>adb shell pm clear <package>

手动恢复数据,从命令和日志两个终端都能看到数据被正确恢复了。

>adb shell bmgr restore 01 <package>
Scheduling restore: Local disk image
restoreStarting: 1 packages
onUpdate: 0 = com.example.alldemo
restoreFinished: 0
done
BackupRestoreAgent: MyBackupAgent()
BackupRestoreAgent: onCreate()
BackupManagerService: agentConnected pkg=com.example.alldemo agent=android.os.BinderProxy@a480a0c
BackupManagerService: got agent android.app.IBackupAgent$Stub$Proxy@5041f55
BackupManagerService: initiateOneRestore packageName=xxx
BackupRestoreAgent: onRestore()
BackupManagerService: restoreFinished packageName=xxx
BackupRestoreAgent: onRestoreFinished()
BackupManagerService: Restore complete, killing host process of xxx ★
BackupRestoreAgent: onDestroy()
BackupManagerService: No more packages; finishing restore
BackupManagerService: Restore complete.

当然将App卸载后通过市场或手动安装可以自动地恢复数据,这个动作由系统在Apk安装的时候自动完成。


Transport服务的选择要小心。如果选了GMS Transport的话,要注意GMS场景的网络问题,不然备份会失败。

更加详细的bmgr使用方法可参考如下文档。

https://developer.android.google.cn/studio/command-line/bmgr?hl=zh-cn

3.1.3 Google发起

Google将会按照每日一次的频次对支持自动备份模式的App发起备份操作。


恢复的话则是在设备第一次开机登录Google账号后。Google会将数据从服务器下载通过BackupManager向各个备份过的App发起恢复操作。尚未安装的App则在后期Apk安装完成之后由Google自行发起恢复。

3.2 Backup/Restore的调试

logcat指定BackupManagerService的Tag,可以监听到Backup和Restore的日志,辅助我们把握操作的进度和报错的原因。

>adb logcat -s BackupManagerService

比如针对Google Photos App进行adb备份和恢复操作的时候,将会输出如下日志。

  • Backup
>adb logcat -s BackupManagerService
BackupManagerService: Requesting backup: apks=true obb=false shared=false all=false system=true includekeyvalue=false pkgs=[Ljava.lang.String;@190020e
BackupManagerService: Beginning adb backup...
BackupManagerService: Starting backup confirmation UI, token=1441721864
BackupManagerService: Waiting for backup completion...
BackupManagerService: acknowledgeAdbBackupOrRestore : token=1441721864 allow=true
BackupManagerService: --- Performing adb backup ---
BackupManagerService: Package com.google.android.apps.photos is key-value.
BackupManagerService: Adb backup processing complete.
BackupManagerService: Full backup pass complete.
  • Restore
>adb logcat -s BackupManagerService
BackupManagerService: Beginning restore...
BackupManagerService: Starting restore confirmation UI, token=1694423050
BackupManagerService: Waiting for restore completion...
BackupManagerService: acknowledgeAdbBackupOrRestore : token=1694423050 allow=true
BackupManagerService: --- Performing full-dataset restore ---
BackupManagerService: adb restore processing complete.
BackupManagerService: Full restore pass complete.

一般来说BackupManagerService提供的日志情报足够了,但在调试Transport,使用bmgr工具等场景的时候,还可以使用这些Tag获得更详细的日志:Backup,BackupManager,PFTBT,GmsBackupTransport,PerformBackupTask和RestoreSession等。

>adb logcat -s AndroidRuntime -s Backup -s BackupManager -s BackupManagerService -s PFTBT -s GmsBackupTransport -s -s PerformBackupTask -s RestoreSession

3.3 Backup文件的解密

Backup文件的后缀名为.ab,估计是android backup的缩写。我们用Text打开上面备份的Google Photos文件,可以看到如下信息。

ANDROID BACKUP
5
1
AES-256
C356E772D89C31C0FCAE6BF16BEC2FF90F0503BCD12111B380FF6054B823D80963EEDC661D92DB908788B48499A80B62731C1A9822C8BF5CD8D67AE85FF45CD9
...

整个文件内容包含头和内容,其中头的信息非常重要,关乎到备份的策略和解密的方式。


Backup功能的版本号,比如上面的5,定义在源码的UserBackupManagerService文件中

Backup备份文件是否压缩,比如上面的1意味着经过了压缩

Backup加密方式,比如上面采用了AES-256加密算法,如果未输入密码备份的话,此处会显示none

未输入密码的ab文件。

ANDROID BACKUP
5
1
none
xレb
...

我们可以使用abe.jar来解密备份的文件,如果使用了加密算法的话,还需要Java Cryptography Extension jar包的帮助。

这里简单演示下没有加密的备份文件的破解过程。

// 输入如下命令
java -jar abe.jar unpack backupFileName-nopwd.ab backupFileName-nopwd.tar

未输出任何Exception则表示解密成功,并会生成指定的tar包。解压出来之后是包括DB、SP在内的原始数据。

1832b220aa754cd18c504acc7686a560.png

abe.jar全名为android-backup-extractor,是采用Java语言编写的转为解密Android备份文件的工具,非常好用。

abe.jar下载地址


除了这个工具,貌似DD命令也可以破解,笔者没有试过,感兴趣的可以参考如下文章进行更深入的尝试。

浅谈安卓系统备份文件ab格式解析


相关实践学习
阿里云百炼xAnalyticDB PostgreSQL构建AIGC应用
通过该实验体验在阿里云百炼中构建企业专属知识库构建及应用全流程。同时体验使用ADB-PG向量检索引擎提供专属安全存储,保障企业数据隐私安全。
AnalyticDB PostgreSQL 企业智能数据中台:一站式管理数据服务资产
企业在数据仓库之上可构建丰富的数据服务用以支持数据应用及业务场景;ADB PG推出全新企业智能数据平台,用以帮助用户一站式的管理企业数据服务资产,包括创建, 管理,探索, 监控等; 助力企业在现有平台之上快速构建起数据服务资产体系
相关文章
|
2月前
|
IDE Android开发 iOS开发
Android VS iOS:哪个操作系统更适合开发者?**
**在移动应用开发领域,Android和iOS是两大主流操作系统,它们各自拥有独特的特点和优势。本文探讨了Android和iOS操作系统在开发者视角下的差异与优劣,分析了它们在开发环境、用户群体、市场前景等方面的比较,帮助开发者选择最适合他们需求的平台。
43 2
|
23小时前
|
JSON Java Android开发
Android 开发者必备秘籍:轻松攻克 JSON 格式数据解析难题,让你的应用更出色!
【8月更文挑战第18天】在Android开发中,解析JSON数据至关重要。JSON以其简洁和易读成为首选的数据交换格式。开发者可通过多种途径解析JSON,如使用内置的`JSONObject`和`JSONArray`类直接操作数据,或借助Google提供的Gson库将JSON自动映射为Java对象。无论哪种方法,正确解析JSON都是实现高效应用的关键,能帮助开发者处理网络请求返回的数据,并将其展示给用户,从而提升应用的功能性和用户体验。
|
6天前
|
图形学 Android开发
小功能⭐️Unity调用Android常用事件
小功能⭐️Unity调用Android常用事件
|
9天前
|
API 开发工具 Android开发
探索Android与iOS开发环境的差异及对开发者的影响
【8月更文挑战第10天】在移动应用开发的广阔天地中,Android和iOS作为两大主要平台,各自拥有独特的开发环境和生态系统。本文将深入探讨这两个平台的开发环境差异,以及这些差异如何影响开发者的工作效率、应用性能和最终用户体验。通过比较两者的开发工具、编程语言和API等方面,我们将揭示平台选择对项目成功的重要性,并为开发者提供在选择平台时的参考依据。
|
18天前
|
开发框架 Java Android开发
安卓与iOS开发环境的差异及其对开发者的影响
在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。它们不仅在用户界面、操作系统架构上有所区别,更在开发环境和工具上展现出独特的差异。本文将从开发语言、工具和库、以及跨平台开发框架三个方面深入探讨这些差异如何塑造开发者的技术选择和职业路径,进而影响移动应用的生态发展。
11 2
|
21天前
|
Java API Android开发
安卓与iOS开发环境的差异及其对开发者的影响
在移动应用开发的广阔天地中,安卓和iOS这两大操作系统平台各自拥有独特的开发环境。本文旨在深入探讨这两个平台在开发语言、工具、API等方面的主要差异,并分析这些差异如何影响开发者的决策过程及最终产品的用户体验。通过比较分析,我们将揭示不同环境下的开发策略,以及它们对市场趋势的潜在影响。
9 0
|
22天前
|
前端开发 安全 数据库
💡Android开发者必看!掌握这5大框架,轻松打造爆款应用不是梦!🏆
【7月更文挑战第28天】在Android开发领域,五大框架如星辰般指引方向,加速进程,提升应用品质。1. **Retrofit**:Square公司的类型安全HTTP客户端,使网络请求变得优雅简洁。2. **Room**:Google推荐的ORM库,简化SQLite数据库访问。3. **MVVM**:一种架构模式,提高代码可维护性和扩展性。4. **Dagger 2**:依赖注入框架,减少样板代码,以声明方式管理依赖。5. **Jetpack Compose**:全新的UI工具包,采用声明式UI编程,让UI开发更直观高效。掌握这些框架,能有效应对Android开发挑战,助力打造爆款应用。
101 0
|
1月前
|
IDE 开发工具 Android开发
安卓与iOS开发环境的差异及其对开发者的影响
【7月更文挑战第2天】在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据了半壁江山。它们的开发环境不仅在技术层面有着根本的不同,而且在设计理念、用户群体以及市场策略上也大相径庭。本文将深入探讨这些差异如何塑造开发者的工作方式,影响他们的决策过程,并最终决定移动应用的质量和成功。
|
1月前
|
开发工具 Android开发 iOS开发
安卓与iOS开发环境的差异及对开发者的意义
本文深入探讨了安卓和iOS两大移动操作系统的开发环境,对比分析了两者在编程语言、开发工具、用户界面设计以及应用商店政策等方面的核心差异。通过统计数据支持,本文揭示了这些差异如何影响开发者的决策过程和最终产品的市场表现。文章旨在为移动应用开发者提供全面的视角,帮助他们根据目标受众和技术偏好做出明智的平台选择。
17 0
|
2月前
|
数据库 Android开发 数据安全/隐私保护
在 Android Studio 中结合使用 SQLite 数据库实现简单的注册和登录功能
在 Android Studio 中结合使用 SQLite 数据库实现简单的注册和登录功能
116 2

相关实验场景

更多