Android设备加密状态下SharedPreferences访问异常解决方案

1. 问题来了:为什么我的App一启动就黑屏闪退?

最近在搞一个TV项目,用的是Android 9.0的系统。项目上线前测试,发现一个挺诡异的问题:Launcher(也就是电视的主界面应用)刚启动的时候,偶尔会出现黑屏或者闪一下屏,然后应用就崩溃退出了。这可不是小问题,用户一开机就看到这个,体验直接降到冰点。

赶紧连上Logcat看日志,果然抓到了“罪魁祸首”。错误堆栈里明明白白地写着:

AndroidRuntime: java.lang.RuntimeException: Unable to create application com.example.myapp.MyApplication: java.lang.IllegalStateException: SharedPreferences in credential encrypted storage are not available until after user is unlocked

翻译一下就是:“无法创建应用,因为抛出了一个非法状态异常:在用户解锁设备之前,存储在凭据加密存储中的SharedPreferences是不可用的。”

看到这个错误,我当时第一反应是有点懵的。SharedPreferences不是用来存一些简单的配置信息,比如用户设置、开关状态什么的吗?它怎么会和“用户解锁”扯上关系?而且我们TV设备很多时候是常开待机的,或者开机就直接进主界面,没有像手机那样的锁屏密码界面,哪来的“解锁”?

后来我花了不少时间查资料、做实验,才把这里面的门道搞清楚。原来,从Android 7.0(Nougat)开始,谷歌引入了一个非常重要的安全特性,叫做“直接启动”(Direct Boot)。这个特性本意是好的,是为了在设备开机后、用户输入密码解锁前,也能让一些关键应用(比如闹钟、来电拦截)有限度地运行。但就是这个特性,给我们这些在“用户解锁”前就需要访问数据的普通应用,挖了一个大坑。

简单来说,Android把存储空间分成了两个区域:

  1. 设备加密存储(Device Encrypted Storage):设备一启动就能访问。这部分存储的密钥和设备硬件绑定,开机就能解密。
  2. 凭据加密存储(Credential Encrypted Storage):必须等用户解锁(输入密码、图案、指纹等)后才能访问。这部分存储的密钥和用户的解锁凭证绑定,安全性更高。

而我们平时默认使用的 Context.getSharedPreferences(),数据就是存在凭据加密存储里的!在用户解锁设备前,你去读它写它,系统就会毫不客气地抛出上面那个 IllegalStateException,导致你的应用崩溃。TV应用在开机启动时,系统可能还处在“直接启动”模式下,用户解锁状态未就绪,所以一碰SharedPreferences就“炸”了。

2. 刨根问底:理解“直接启动”与存储加密

要彻底解决这个问题,不能光知道个解决方案就完事,我们得稍微深入一点,理解Android是怎么管理启动和存储安全的。这样以后遇到类似问题,你才能举一反三。

2.1 什么是“直接启动”模式?

你可以把“直接启动”想象成手机的“安全安全模式”。当你按下手机电源键开机,到出现锁屏界面让你输入密码、指纹的这段时间,手机就运行在“直接启动”模式下。

在这个模式下,系统为了安全,做了严格的限制:

  • 核心系统服务在运行,保证手机能开机。
  • 被显式声明为 directBootAware 的应用可以有限运行。这类应用通常是闹钟、电话、短信这些基础功能应用。
  • 存储访问受限:只能访问“设备加密存储”区域。我们应用默认的数据目录(也就是凭据加密存储)是禁区。

对于TV或者一些物联网设备,它们可能没有设置锁屏密码,但系统启动流程依然会经历这个阶段。如果你的应用(比如Launcher)被设置为开机自启动,就非常有可能撞上这个阶段,从而触发存储访问异常。

2.2 存储加密的“双分区”

前面提到了,Android文件加密(FBE, File-Based Encryption)把数据分成了两个“保险箱”:

存储区域 可访问时机 密钥来源 默认存储位置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值