4. 日志采集与初步过滤:adb logcat 抓取 ExoPlayer 相关日志、过滤 SecurityException/Denied 关键字、定位关键时间戳

4.1 现象识别

当 ExoPlayer 因权限不足无法播放时,典型现象包括:

  • 播放器回调 onPlayerError,错误类型为 PlaybackException.ERROR_CODE_IO_UNSPECIFIED
  • 播放界面显示“无法播放此视频”或空白黑屏
  • 日志中频繁出现 SecurityException 或 Access Denied 关键字

这些现象提示我们需要立即启动日志采集,定位具体哪个资源(文件、URI、证书)被拒绝访问。

4.2 数据采集:使用 adb logcat 抓取 ExoPlayer 日志

打开终端,执行以下命令将日志持续写入文件,以便事后分析:

adb logcat -v time -f /sdcard/exo_log.txt *:V

关键参数说明:

参数作用
-v time为每条日志附加时间戳(精确到毫秒)
-f /sdcard/exo_log.txt将输出重定向到设备文件,避免终端缓冲丢失
*:V显示所有级别的日志(Verbose 及以上),不漏掉任何线索
贴士: 如设备无 root 权限,可将日志输出到应用私有目录 /data/data/<package>/files/ 或使用 adb logcat -d > local.log 截取当前缓冲区内容。

同时,建议在 ExoPlayer 初始化前后增加自定义日志标记,方便过滤:

adb logcat -v time -s ExoPlayerImpl:V MediaSource:V *:E

此命令只保留 ExoPlayerImpl 和 MediaSource 的详细信息,同时显示所有错误日志。

4.3 初步过滤:使用 grep 提取 SecurityException / Denied 关键字

将抓取到的日志文件 pull 到本地,然后用 grep 快速定位可疑行:

adb pull /sdcard/exo_log.txt ./
grep -in "SecurityException\|Denied\|Permission" exo_log.txt > filtered_log.txt
more filtered_log.txt

常见匹配模式示例:

模式典型日志片段含义
SecurityException java.lang.SecurityException: Neither user 10123 nor current process has android.permission.INTERNET 缺少网络权限
Denied open failed: EACCES (Permission denied) for /storage/emulated/0/video.mp4 文件系统访问被拒绝
Permission No permission to access URI: content://media/external/video/media/123 Content URI 权限缺失
注意: 不要只过滤异常堆栈第一行,还要向后看 Caused by 链,底层 `PermissionDenied` 可能被包装在多级异常中。

4.4 定位关键时间戳

在过滤后的日志中,找到第一次出现 SecurityException/Denied 的时间点,并以此为中心前后各扩展 2 秒,观察关联事件:

  • 时间戳格式(如 01-23 14:30:15.123)对应文件中的第一列。
  • 记录该时间戳,用于与播放器初始化、资源加载、DRM 请求等操作对齐。
  • 检查该时间戳附近是否有 ExoPlayer 的 onLoadError、onPlayerError 回调日志。

以下命令可输出时间戳前后的上下文:

# 假设时间戳为 "01-23 14:30:15.123"
grep -n "01-23 14:30:1[3-7]" exo_log.txt | head -50

4.5 修复动作:根据日志确认权限缺口

对照过滤结果,按优先级执行修复:

  1. 网络权限:在 AndroidManifest.xml 中追加 <uses-permission android:name="android.permission.INTERNET" />。
  2. 文件/存储权限:Android 11+ 需使用 MediaStore 或 SAF;传统文件路径需动态请求 READ_EXTERNAL_STORAGE。
  3. Content URI 权限:为 Intent 添加 FLAG_GRANT_READ_URI_PERMISSION,或在 ContentResolver 中 takePersistableUriPermission。
  4. DRM 证书权限:确认设备是否支持 Widevine,以及证书路径是否可读。

4.6 复测:重新采集并验证修复

修改代码后,重新安装应用,再次执行相同的 adb logcat 命令,并过滤相同关键字:

adb logcat -v time -f /sdcard/exo_verify.txt *:V
# 在设备上复现播放操作
adb pull /sdcard/exo_verify.txt ./
grep -c "SecurityException\|Denied" exo_verify.txt

若返回 0,则权限问题已解决;否则返回 1+,需返回步骤 4.2 检查遗漏的日志行。

4.7 预防:日志采集最佳实践

  • 在 ExoPlayer 初始化时,主动输出当前应用的权限列表:context.checkSelfPermission() 结果打印到 Logcat。
  • 使用 exoplayer2:exoplayer-core-2.19.1 及以上版本,其内部日志更详细地输出权限失败原因。
  • 建立自动化测试脚本,在每一次 CI 构建后自动抓取 Logcat 并扫描 SecurityException 关键字。
  • 在安卓 13+ 上注意通知权限(POST_NOTIFICATIONS)也可能导致播放中断,需一并检查。
日志采集与初步过滤流程 日志采集与初步过滤故障排查流程 播放失败 / 错误回调 adb logcat -v time 抓取日志 adb pull → 本地日志文件 grep 过滤 SecurityException / Denied 定位关键时间戳 & 上下文 确认权限缺口 → 修复 💡 关键:时间戳对齐 + 多级异常链检查;若过滤后无匹配,请扩大时间窗口或检查日志级别(*:E 可能错过 WARN)。