Android 12(API31)下Package Installer失效问题排查咨询
Android 12联想M9(TB310XU)设备应用版本更新代码失效问题排查
问题背景
原代码可在Android 10及更早版本、联想M8 4代(TB300XU)设备上正常实现应用版本更新,但在Android 12(API 31)的联想M9(TB310XU)设备上失效,抛出空指针异常:
Failed query: java.lang.NullPointerException: Attempt to invoke interface method 'boolean android.database.Cursor.moveToFirst()' on a null object reference
完整堆栈关键调用链:
android.os.Parcel.createExceptionOrNull(Parcel.java:2425) android.os.Parcel.createException(Parcel.java:2409) android.os.Parcel.readException(Parcel.java:2392) android.os.Parcel.readException(Parcel.java:2334) android.content.pm.IPackageInstallerSession$Stub$Proxy.fsync(IPackageInstallerSession.java:730) android.content.pm.PackageInstaller$Session.fsync(PackageInstaller.java:967) // 最终指向代码中的session.fsync(outputStream)调用
原实现代码
val inputStream = context.applicationContext.contentResolver.openInputStream(Uri.fromFile(file)) val length = DocumentFile.fromSingleUri(context.applicationContext, Uri.fromFile(file))!! .length() val installer = context.applicationContext.packageManager.packageInstaller val params = SessionParams(SessionParams.MODE_FULL_INSTALL) val sessionId = installer.createSession(params) val session = installer.openSession(sessionId) val outputStream = session.openWrite(file.name, 0, length) val buf = ByteArray(1024) var len: Int while (inputStream!!.read(buf).also { len = it } > 0) { outputStream.write(buf, 0, len) } session.fsync(outputStream) outputStream.close() inputStream.close() val intent = Intent(context.applicationContext, DeviceReceivers::class.java) val pi = PendingIntent.getBroadcast( context.applicationContext, REQUEST_INSTALL_PACKAGE, intent, PendingIntent.FLAG_UPDATE_CURRENT // FLAG_IMMUTABLE for android 12 ) session.commit(pi.intentSender) session.close()
排查步骤
- 定位触发点:从堆栈看异常出现在
session.fsync(outputStream),系统底层查询Cursor返回null,优先怀疑文件URI权限或厂商定制实现差异。 - 替换文件URI生成方式:放弃
Uri.fromFile(file),改用FileProvider生成content://格式URI,确保系统安装服务能正常访问文件。需在AndroidManifest配置FileProvider,并通过getUriForFile生成URI。 - 修正PendingIntent Flag:Android 12强制要求PendingIntent指定
FLAG_IMMUTABLE或FLAG_MUTABLE,将代码中的Flag替换为PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE(若无需修改广播Intent则用IMMUTABLE)。 - 简化文件长度获取:
DocumentFile.fromSingleUri处理file://URI可能存在厂商bug,直接用file.length()获取文件大小,避免依赖系统DocumentFile实现。 - 验证文件状态:在打开输入流前添加
file.exists()和file.canRead()检查,确认安装包文件存在且当前应用有读取权限。 - 检查安装会话参数:给SessionParams补充配置,比如
params.setInstallLocation(SessionParams.INSTALL_LOCATION_AUTO),同时确认设备所有者应用已获取MANAGE_DEVICE_ADMINS及安装相关权限。 - 抓取系统日志:通过
adb logcat -s PackageInstaller过滤系统安装服务日志,查看是否有文件访问拒绝、会话创建失败等详细错误信息。
内容的提问来源于stack exchange,提问作者AllwiN
相关产品推荐
相关产品推荐

