使用 Android Q ffmpeg 拒绝权限”:错误=13,权限被拒绝

gow*_*ami 25 permissions android ffmpeg rtsp android-10.0

我想使用 ffmpeg 从 RTSP 视频中获取帧。但是对于上面的 android 10,我收到如下错误。

 E/FFmpeg: Exception while trying to run: [Ljava.lang.String;@55e447f
java.io.IOException: Cannot run program "/data/user/0/com.example.downloadimagefromurl/files/ffmpeg": error=13, Permission denied
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1050)
    at java.lang.Runtime.exec(Runtime.java:698)
    at java.lang.Runtime.exec(Runtime.java:563)
    at com.github.hiteshsondhi88.libffmpeg.ShellCommand.run(ShellCommand.java:10)
    at com.github.hiteshsondhi88.libffmpeg.FFmpegExecuteAsyncTask.doInBackground(FFmpegExecuteAsyncTask.java:38)
    at com.github.hiteshsondhi88.libffmpeg.FFmpegExecuteAsyncTask.doInBackground(FFmpegExecuteAsyncTask.java:10)
    at android.os.AsyncTask$3.call(AsyncTask.java:378)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
    at java.lang.Thread.run(Thread.java:919)
 Caused by: java.io.IOException: error=13, Permission denied
    at java.lang.UNIXProcess.forkAndExec(Native Method)
    at java.lang.UNIXProcess.<init>(UNIXProcess.java:133)
Run Code Online (Sandbox Code Playgroud)

正如@Saurabh Thorat 提供的答案一样,Google 不允许应用程序从 /data/user 目录运行二进制文件。

我知道的一个糟糕的解决方案是将 compileSdkVersion 和 targetSdkVersion 更改为 28 或更低,然后重新发布我不推荐的应用程序。

因此,我也在为未来的版本寻找更可行的解决方案。

任何提示、链接或建议将不胜感激。提前致谢。

Sau*_*rat 11

从 Android Q 开始,您无法在应用的私有数据目录中执行二进制文件。

来自问题跟踪器:https ://issuetracker.google.com/issues/128554619

在 targetAPI >= Q 的应用程序数据文件上阻止 exec() 的更改按预期工作。 有关此更改的背景信息,请参阅 https://android-review.googlesource.com/c/platform/system/sepolicy/+/804149。在可写的应用程序文件上调用 exec() 是 W^X ( https://en.wikipedia.org/wiki/W%5EX ) 违规,代表不安全的应用程序实践。可执行代码应始终从应用程序 APK 加载。

虽然 exec() 不再适用于应用程序主目录中的文件,但它继续支持只读 /data/app 目录中的文件。特别是,应该可以将二进制文件打包到应用程序的本机 libs 目录中并启用 android:extractNativeLibs=true,然后在 /data/app 工件上调用 exec()。使用 wrap.sh 功能完成了类似的方法,记录在 https://developer.android.com/ndk/guides/wrap-script#packaging_wrapsh 。

此外,请注意通过 exec() 执行的可执行文件不是根据 Android 进程生命周期管理的,一般来说,Android 应用程序不鼓励 exec()。虽然不是 Android 文档, 但在NDK 中使用“exec()”对此进行了一些详细说明。依赖 exec() 在未来的 Android 版本中可能会出现问题。

  • 我的 bravobit ffmpeg 总是发生同样的事情……每当 Google 发布新的 Android 版本时,你都必须祈祷,这样你的应用程序才不会以任何方式停止工作:(( (4认同)
  • 在[与 Google 工程师的讨论](https://issuetracker.google.com/issues/152645643) 中,他们不断保证在未来版本中仍将支持 `exec()`,但像 `ffmpeg ⇒ 这样的黑客重命名lib..ffmpeg..so` 是必需的,尤其是发布时。 (2认同)

Ash*_*iya 8

仅将 Build.gradle 文件 targetSdkVersion 29更改为 28 并在您的设备上重新安装您的应用程序 - 由于 targetSdkVersion 29 是在 Play 商店发布构建所需的平台,因此暂时解决了您的权限问题,因此我建议您使用它库,支持目标Sdk 30

https://github.com/SimformSolutionsPvtLtd/SSffmpegVideoOperation

  • 但仍然将 Targetsdk 更改为 28 是临时解决方法。无法在生产应用程序中使用它。有没有任何图书馆可以实现同样的目标? (6认同)
  • 谢谢。这实际上是一个很好的解决方法。不知道为什么你被否决了。 (3认同)
  • 始终以最新版本为目标并更改代码以满足要求。永远不要听人们告诉你降级你的“targetSdkVersion”。“从 2020 年 11 月 2 日起,应用更新必须针对 Android 10(API 级别 29)或更高版本。” - https://developer.android.com/distribute/best-practices/develop/target-sdk (2认同)

1ni*_*las 7

根据@Saurabh Thorat 的回答,我提出了一个解决问题的拉取请求。你可以在这里找到它。

快速总结:

将 ffmpeg 二进制文件移至 libs 文件夹并添加android:extractNativeLibs = "true"到清单中,以便它可以将自身复制到其中/data/app/{package_name}/lib/{arch}/,然后从那里执行(Android 10 支持)。

编辑(一般用途):为了将可执行文件复制到/data/app/{package_name}/lib/{arch}/,文件名必须是lib(something).so. 如果名称不以 开头lib和结尾.so,则不会复制它们。

  • 谢谢,我想我尝试过,但会再试一次,如果在调试模式下不是 lib*so,请注意它的复制内容 (2认同)

dr_*_*r_g 6

在早期的答案正确地解释你打的问题。这也是去年 9 月提出的一个悬而未决的问题,在您使用的库的论坛上进行了讨论(从我在堆栈跟踪中看到的内容)。

为 SDK 29 编译的解决方案是停止将二进制文件放在 /data/ 目录中,并确保它们位于本机 libs 目录中。在非 root 设备上安装和解压 APK 后无法实现,因此在准备 Android 项目时应正确完成(例如通过 gradle 设置),并确保在安装时正确解压内容:android:extractNativeLibs=true.

在您的情况下,此代码将打包为“资产”的二进制文件移动到用户数据目录中:

https://github.com/WritingMinds/ffmpeg-android-java/blob/master/FFmpegAndroid/src/main/java/com/github/hiteshsondhi88/libffmpeg/FileUtils.java

这是在可读/可写位置运行任何可执行文件的安全问题。我上面链接的源代码需要删除,而是打包在 /libs 中的本机二进制文件。由于应用程序安装目录中的 /libs 位置是可执行的但不可写,因此更改更加安全。

总之,第 3 方库需要解决它,或者您可以这样做并贡献一个拉取请求。或者 fork 自己的并为自己重新编译。

如果您的应用程序在安装后实际下载内容,并希望执行任何下载,那么仍然存在问题。据我所知,现在在 Android 10 中这是不可能的。

面向未来的解决方案是停止使用外部二进制文件,并将依赖项编译为 NDK 项目。他们将需要围绕本机代码的 jni 包装器(一些工作)。还有一个相关的项目,我知道的,你可以看看。

  • 它确实涉及一些工作,我仍在与你提到的图书馆斗争。 (3认同)

Gáb*_*áth 6

我在使用FFmpeg-Android-Java时遇到了同样的情况。似乎不再支持这个库......所以我只是转移到MobileFFmpeg并且工作起来很有魅力!

如果您使用 gradle 插件 4.0.0(及更高版本),您唯一需要注意的是在模块级 build.gradle 中添加以下内容:

android {
    packagingOptions {
        pickFirst 'lib/x86/libc++_shared.so'
        pickFirst 'lib/x86_64/libc++_shared.so'
        pickFirst 'lib/armeabi-v7a/libc++_shared.so'
        pickFirst 'lib/arm64-v8a/libc++_shared.so'
    }
}
Run Code Online (Sandbox Code Playgroud)