使用 Android Q ffmpeg 拒绝权限": error=13, Permission denied
Posted
技术标签:
【中文标题】使用 Android Q ffmpeg 拒绝权限": error=13, Permission denied【英文标题】:permission is denied using Android Q ffmpeg": error=13, Permission denied 【发布时间】:2020-06-07 18:12:50 【问题描述】:我想使用 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)
正如@Saurabh Thorat 提供的答案,Google 不允许应用从 /data/user 目录运行二进制文件。
我知道的一个糟糕的解决方案是将 compileSdkVersion 和 targetSdkVersion 更改为 28 或更低,然后重新发布我不推荐的应用程序。
因此,我也在为未来的版本寻找更可行的解决方案。
任何提示、链接或建议将不胜感激。提前致谢。
【问题讨论】:
可能与这个***.com/questions/8854359/…有关 没有@Priyankagb 我已经为我的应用授予了外部存储权限 对于您的示例,我也收到相同的错误 2020-02-24 12:38:16.934 2817-3054/com.techdorid.ffmpegandroid.demo W/System.err: java.io.IOException:无法运行程序“/data/user/0/com.techdorid.ffmpegandroid.demo/files/ffmpeg”:错误=13,权限被拒绝 在这一行我收到错误(FFmpegExecuteAsyncTask.java:44) 这是否仅在使用 ffmpeg 或使用其他与存储相关的东西时发生? 【参考方案1】:我知道这已经很晚了,但您甚至可以使用 gradle 任务将所有内容从特定目录复制到 apk 中特定于架构的 lib 文件夹中
使用 android 安装程序在安装时可以将所有库提取到 /data/app 文件夹的 hacky 技巧,这个地方是可执行的(即使在 Android Q 之后)!
然后你就可以在 /data/app 目录下执行你的文件了!欲了解更多信息,请点击文章链接 - https://withme.skullzbones.com/blog/programming/execute-native-binaries-android-q-no-root/
【讨论】:
【参考方案2】:仅更改Build.gradle 文件 targetSdkVersion 29 到 28 和 在您的设备上重新安装您的应用程序 - 由于 targetSdkVersion 29 是 Play 商店发布构建所需的平台,因此暂时解决了您的权限问题,因此我建议您使用此库,它支持 target Sdk 30
https://github.com/SimformSolutionsPvtLtd/SSffmpegVideoOperation
【讨论】:
谢谢。这实际上是一个很好的解决方法。不知道你为什么被否决。 但仍将 targetsdk 更改为 28 是临时解决方法。不能在生产应用程序中使用它。是否有任何图书馆可以实现相同的目标? 不,亲爱的,没有任何图书馆,如果有的话,我一定会通知你的。 始终以最新版本为目标并更改您的代码以满足要求。永远不要听别人告诉你降级你的targetSdkVersion
。 “从 2020 年 11 月 2 日起,应用更新必须针对 Android 10(API 级别 29)或更高版本。” - developer.android.com/distribute/best-practices/develop/…
此库需要 minSdk=24,因此请确保您只针对具有 sdk>=24 的设备【参考方案3】:
你可以使用 // 实现 'com.arthenica:mobile-ffmpeg-full:4.4' 实现 'com.arthenica:mobile-ffmpeg-full:4.2.LTS'
【讨论】:
【参考方案4】:根据@Saurabh Thorat 的回答,我提出了一个解决问题的拉取请求。 你可以找到它here。
快速总结:
将 ffmpeg 二进制文件移动到 libs 文件夹并将
android:extractNativeLibs = "true"
添加到清单中,以便它可以将自身复制到/data/app/package_name/lib/arch/
中,然后从那里执行它(Android 10 支持)。
编辑(一般用途):为了将可执行文件复制到/data/app/package_name/lib/arch/
,文件名必须是lib(something).so
。如果名称不以lib
开头并以.so
结尾,则不会被复制。
【讨论】:
谢谢,这适用于我的调试版本,但在发布版本中,/data/app/package_name/lib/arch/
中的库似乎没有被复制,有什么想法吗?
谢谢我这样做了,但没有效果,我怀疑它可能与本机反应有关
@1nikoas 谢谢,但我没有使用我自己的库,我只是遇到了同样的错误/问题
谢谢,我以为我试过了,但会再试一次,如果在调试模式下不是 lib*so,请注意它的复制
见issuetracker.google.com/issues/152645643【参考方案5】:
我在使用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'
【讨论】:
这在 targetSdkVersion 30 中不起作用【参考方案6】:earlier answer 正确解释了您遇到的问题。这也是去年 9 月提出的 open issue,在您正在使用的库的论坛上进行了讨论(从堆栈跟踪中可以看到)。
为 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 包装器(一些工作)。有a related project我知道你可以看看。
【讨论】:
它确实涉及一些工作,我还在为你提到的图书馆而苦苦挣扎。 我也在苦苦挣扎。有人得到答案吗?【参考方案7】:从 Android Q 开始,您无法在应用的私有数据目录中执行二进制文件。
来自问题跟踪器:https://issuetracker.google.com/issues/128554619
对 targetAPI 的应用程序数据文件阻止 exec() 的更改 >= Q 按预期工作。请参见 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进程生命周期管理,一般 说, exec() 不鼓励 Android 应用程序。虽然不是 安卓文档, Using "exec()" with NDK 详细介绍了这一点。依赖 exec() 可能会出现问题 未来的 Android 版本。
【讨论】:
你能告诉我我要补充什么吗?要使用此代码 id android 10 @Chitrang 不,我没有得到任何答案。如果你有什么。请与我分享 这就是我开始这个赏金的原因,让我们希望最好。 bravobit ffmpeg 在我身上总是发生同样的事情......每当谷歌发布一个新的 Android 版本时,你必须交叉手指,这样你的应用程序就不会以任何方式停止工作:( ( 在discussion with Google engineers 中,他们一直保证exec()
在未来的版本中仍将受到支持,但需要像ffmpeg ⇒ lib..ffmpeg..so
这样的黑客重命名,尤其是在发布时。以上是关于使用 Android Q ffmpeg 拒绝权限": error=13, Permission denied的主要内容,如果未能解决你的问题,请参考以下文章
尝试使用 ffmpeg 时 AWS Lambda 权限被拒绝
FFMPEG命令在设置项目的目标SDK版本29(Android Q问题)时不起作用
java.lang.SecurityException:权限被拒绝:打开提供程序 com.quickblox.q_municate_core.db.DatabaseProvider