Android应用自更新后崩溃:Failed to measure fs-verity, errno 1问题排查
APK更新后崩溃:fs-verity测量失败问题排查
我正在为Android应用添加外部APK链接自更新功能。从外部链接下载新版APK后,通过PackageInstaller完成更新,能看到新版本UI的新增文本(说明更新成功),但启动应用时崩溃,报错如下:
VerityUtils pid-594 E Failed to measure fs-verity, errno 1: /data/app/~~QTV2DULtWFYdJpO7yGn7sg==/com.test.app--JKzM4i9A3BAuvFAm9x9YQ==/base.apk
我怀疑APK文件损坏,但更新后能正常显示新UI的情况与此矛盾。另外,应用已拥有设备所有者权限,以下是实现代码:
class UpdateAppViewModel(application: Application): AndroidViewModel(application) { fun download() { viewModelScope.launch { withContext(Dispatchers.IO) { val fileUrl = "https://my-path-to-ne-apk-s3.net/test-app" val intent = Intent(Intent.ACTION_INSTALL_PACKAGE).apply { data = Uri.parse(fileUrl) flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK } Log.d("UPD", "START DOWNLOAD") val packageInstaller = getApplication<Application>().packageManager.packageInstaller val sessionParams = PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL) val sessionId = packageInstaller.createSession(sessionParams) val session = packageInstaller.openSession(sessionId) val inputStream = URL(fileUrl).openStream() val outputStream = session.openWrite("test-app.apk", 0, -1) inputStream.copyTo(outputStream) session.fsync(outputStream) inputStream.close() outputStream.close() Log.d("UPD", "FINISH DOWNLOAD") val pendingIntent = PendingIntent.getBroadcast(getApplication<Application>().applicationContext, 0, intent, 0) Log.d("UPD", "BEFORE COMMIT!") session.commit(pendingIntent.intentSender) Log.d("UPD", "AFTER COMMIT!") session.close() } } } }
请问该报错的原因是什么?
问题分析与原因
1. 报错本质
fs-verity是Android系统用于验证APK文件完整性的安全机制,会在应用启动时校验APK哈希值是否与安装时记录的一致。报错中的errno 1对应EPERM(权限不足),意味着系统读取APK进行完整性测量时权限不够,进而判定APK可能被篡改或损坏,最终触发崩溃。
2. 代码中的核心问题
- 错误的PendingIntent配置:你用
Intent.ACTION_INSTALL_PACKAGE创建的是触发系统安装器的动作intent,但PackageInstaller的commit方法需要的是接收安装结果的广播intent。错误的intent会破坏安装流程的权限上下文,导致后续fs-verity校验的权限环境异常。 - 缺失APK完整性校验:虽然更新后能显示新UI,但APK可能因网络波动出现部分字节丢失——APK结构未损坏(能解析资源和代码),但完整性哈希值不匹配,触发fs-verity校验失败。
- Session关闭时机错误:
session.close()在commit后立即执行,而commit是异步操作,此时Session可能还未完成APK的最终写入和权限配置,提前关闭会导致APK文件的权限或完整性出现异常。
3. 关键修复方向
- 替换为专用广播接收PendingIntent:创建自定义
BroadcastReceiver处理安装结果,用该广播的intent生成PendingIntent传入session.commit。 - 添加APK完整性校验:下载完成后计算APK的SHA-256哈希值,与服务器提供的校验值对比,确认文件完整后再执行安装。
- 调整Session关闭时机:在
BroadcastReceiver的回调(收到安装完成通知)中再调用session.close(),确保安装流程完全结束。
内容的提问来源于stack exchange,提问作者Rostislav Shtanko
相关产品推荐
相关产品推荐

