29

I want to get the frames from the RTSP video using ffmpeg. But for android 10 above I am getting error as below.

 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)

As the answer provided by @Saurabh Thorat, Google doesn't allow apps to run binary files from /data/user directory.

One bad solution that I know is to change compileSdkVersion and targetSdkVersion to 28 or below and re-release my application which is not recommended.

Hence, I am looking for more viable solutions for future releases as well.

Any hint, links or suggestion would be highly appreciated. Thanks in advance.

Chitrang
  • 5,097
  • 1
  • 35
  • 58
v teja
  • 613
  • 2
  • 7
  • 17
  • maybe related to this https://stackoverflow.com/questions/8854359/exception-open-failed-eacces-permission-denied-on-android – Priyanka Feb 24 '20 at 06:27
  • No @Priyankagb i already gave external storage permissions to my app – v teja Feb 24 '20 at 06:43
  • 1
    for your sample also i am getting same error 2020-02-24 12:38:16.934 2817-3054/com.techdorid.ffmpegandroid.demo W/System.err: java.io.IOException: Cannot run program "/data/user/0/com.techdorid.ffmpegandroid.demo/files/ffmpeg": error=13, Permission denied – v teja Feb 24 '20 at 07:09
  • in this line i am getting error (FFmpegExecuteAsyncTask.java:44) – v teja Feb 24 '20 at 07:10
  • Is this occurs only while using **ffmpeg** or using other storage-related-stuff also? – Rumit Patel Mar 12 '20 at 07:36
  • @pratikvekariya no change i found in your library. Same problem occurs. If you have any solution plz give. – Vikash Sharma May 03 '20 at 15:41
  • Hi @gowthami, I was wondering if you found a solution? – Russell C. Jun 14 '20 at 22:59
  • dont use this solution. time waster github.com/PratikVekariya4445/FFmpegAndroid. it cause error (https://android.googlesource.com/platform/bionic/+/master/android-changes-for-ndk-developers.md#Text-Relocations-Enforced-for-API-level-23) – Daxesh V Jul 17 '20 at 09:05
  • This post may help fix issue on `Android 11+' a https://stackoverflow.com/a/72917882 – Hex24 Jul 09 '22 at 00:12

8 Answers8

12

From Android Q onwards, you cannot execute binaries in your app's private data directory.

From the issuetracker: https://issuetracker.google.com/issues/128554619

The change to block exec() on application data files for targetAPI >= Q is working-as-intended. Please see https://android-review.googlesource.com/c/platform/system/sepolicy/+/804149 for background on this change. Calling exec() on writable application files is a W^X (https://en.wikipedia.org/wiki/W%5EX) violation and represents an unsafe application practice. Executable code should always be loaded from the application APK.

While exec() no longer works on files within the application home directory, it continues to be supported for files within the read-only /data/app directory. In particular, it should be possible to package the binaries into your application's native libs directory and enable android:extractNativeLibs=true, and then call exec() on the /data/app artifacts. A similar approach is done with the wrap.sh functionality, documented at https://developer.android.com/ndk/guides/wrap-script#packaging_wrapsh .

Additionally, please be aware that executables executed via exec() are not managed according to the Android process lifecycle, and generally speaking, exec() is discouraged from Android applications. While not Android documentation, Using "exec()" with NDK covers this in some detail. Relying on exec() may be problematic in future Android versions.

Saurabh Thorat
  • 18,131
  • 5
  • 53
  • 70
  • 1
    can you please tell me what i have to add. To work this code id android 10 – v teja Feb 24 '20 at 06:46
  • 1
    @Chitrang no i didn't get any answer. If you have anything . Please share with me – v teja Mar 11 '20 at 12:50
  • That's why I started this bounty, let's hope for the best. – Chitrang Mar 11 '20 at 15:58
  • 7
    Always the same and exactly the same is happening to me with bravobit ffmpeg... Whenever Google releases a new Android version you have to cross fingers so your app won't stop working in any way :(( – Diego Perez Mar 31 '20 at 15:27
  • 2
    In a [discussion with Google engineers](https://issuetracker.google.com/issues/152645643), they keep assuring that `exec()` will still be supported in the future versions, but the hacky rename like `ffmpeg ⇒ lib..ffmpeg..so` is required, especially for release. – Alex Cohn Sep 05 '20 at 10:19
10

Change only on Build.gradle file targetSdkVersion 29 to 28 and Re-Install your app on your device - It is resolved your permission issue for temporary because of the targetSdkVersion 29 is required platform for released build on play store so I suggest to you use this library, It is support the target Sdk 30

https://github.com/SimformSolutionsPvtLtd/SSffmpegVideoOperation

  • 3
    Thank you. this actually was a great workaround. not sure why you were downvoted. – painor Apr 06 '20 at 23:38
  • 6
    But still changing targetsdk to 28 is temporary workaround. Cant use it in production app. Is there any library that would achieve same ? – Sanket Patel May 22 '20 at 07:50
  • No dear , Not any library for this, If it available then sure I will inform you. – Ashwin Vavaliya Jul 27 '20 at 04:27
  • 3
    ALWAYS target the latest version and make changes to your code to meet the requirements. Never listen to people telling you to downgrade your `targetSdkVersion`. "From 2 November 2020, app updates must target Android 10 (API level 29) or higher." - https://developer.android.com/distribute/best-practices/develop/target-sdk – HB. Sep 04 '20 at 09:41
  • This library requires minSdk=24, so make sure you are only targeting devices with sdk>=24 – Bhavik Mehta Sep 18 '20 at 07:04
  • Here I shared with you one PR : please if required https://github.com/alexcohn/FFmpeg-Android/tree/pull_request_Q https://github.com/tanersener/mobile-ffmpeg/pulls – Ashwin Vavaliya Sep 20 '20 at 03:18
  • This won't work now as targetSdk 29 is now mandatory. – Dhruv Kaushal Nov 17 '20 at 06:19
  • I changed targetSdkVersion from 29 to 28 and it worked. Thank you – VIVEK CHOUDHARY Nov 18 '20 at 14:47
  • I updated the link which I shared link to https://github.com/SimformSolutionsPvtLtd/SSffmpegVideoOperation It is my won created library and you can easily use with upto targetSdk 30 – Ashwin Vavaliya Apr 19 '21 at 03:44
8

The earlier answer correctly explains the problem you are hitting. This is also an open issue raised last September, discussed on the forum of the library you are using (from what I can see in the stack trace).

The solution to compile for SDK 29 would be to stop putting binaries in the /data/ directory, and ensure they are in the native libs directory. That can't be achieved after the APK is installed and unpacked on non-rooted devices, and so should be done correctly when preparing the Android project (e.g. through gradle settings), and to make sure that upon installation the contents get properly unpacked: android:extractNativeLibs=true.

In your case, this code moves binaries that are packaged as 'assets' into the users data directory:

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

That's a security concern running any executables in a location that is read/writeable. That source code I linked to above would need to be removed, instead, the native binaries packaged in /libs. The change is more secure as the /libs location inside your apps install directory is executable but not writable.

In summary, the 3rd party lib needs to address it, or you could do it and contribute a pull request. Or fork your own and recompile it for yourself.

There's still a problem, if your app actually downloads content after it is installed, and expects to execute any downloads. That's now impossible as far as I can tell in Android 10.

The future-proof solution is to stop using external binaries, and to compile the dependencies as NDK projects. They will need jni wrappers around native code (a bit of work). There is a related project I know of you could look into.

dr_g
  • 1,179
  • 7
  • 10
7

Based on the answer by @Saurabh Thorat, I made a pull request which fixes the problem. You can find it here.

Quick summary:

Moved ffmpeg binary to the libs folder and added android:extractNativeLibs = "true" to the manifest so it can copy itself into /data/app/{package_name}/lib/{arch}/ and then execute it from there (which is supported on Android 10).

EDIT (for general use): In order for the executable files to be copied into /data/app/{package_name}/lib/{arch}/, the file names have to be lib(something).so. If the names don't start with lib and end with .so, they won't be copied.

1nikolas
  • 93
  • 1
  • 8
  • 1
    Thanks, this works on debug builds for me but in a release build the lib placed in ```/data/app/{package_name}/lib/{arch}/``` doesnt seem to be copied, any ideas? – MandelDuck Aug 18 '20 at 21:05
  • @MandelDuck you have to add abiFilters on the release too. Have a look at here https://github.com/WritingMinds/ffmpeg-android-java/pull/361#issuecomment-656107645 – 1nikolas Aug 19 '20 at 23:15
  • 1
    thanks I did that but no effect, I suspect it may be react native releated – MandelDuck Aug 20 '20 at 23:33
  • @MandelDuck this library is super old, its not worth trying to fix it. Just use mobile-ffmpeg – 1nikolas Aug 22 '20 at 10:03
  • 1
    @1nikoas thanks but im not using thie library its my own library, I just had the same error/issue – MandelDuck Aug 23 '20 at 20:02
  • @MandelDuck ohh I know whats your problem then. I had the same issue when making the pr. In order for the lib files to be copied, you have to name the file lib(something).so. If it doesn't start with "lib" and end with ".so" it won't be copied. – 1nikolas Aug 24 '20 at 21:40
  • 2
    thanks, I thought I tried that but will try again, note its copied if its not lib*so in debug mode – MandelDuck Aug 25 '20 at 22:27
  • @MandelDuck yeah I noticed that too, on debug mode it copies everything but on release it has to be lib*.so – 1nikolas Aug 26 '20 at 01:08
  • 1
    see https://issuetracker.google.com/issues/152645643 – Alex Cohn Sep 05 '20 at 10:06
6

I experienced the same when I used FFmpeg-Android-Java. It seems that this library is no more supported... So I just shifted to MobileFFmpeg and works like a charm!

The only thing that you have to take care of is adding the followings in your module-level build.gradle if you use gradle plugin 4.0.0 (and above):

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'
    }
}
gabhor
  • 669
  • 9
  • 23
1

You can use // implementation 'com.arthenica:mobile-ffmpeg-full:4.4' implementation 'com.arthenica:mobile-ffmpeg-full:4.2.LTS'

1

I know this is late but you can even use gradle tasks to copy everything from a specific directory to your architecture specific lib folder in apk

Using the hacky trick that the android installer while installing can extract all the libraries to the /data/app folder and this place is executable (even after Android Q)!

Then you can execute your files in /data/app directories! for more information here's the article link - https://withme.skullzbones.com/blog/programming/execute-native-binaries-android-q-no-root/

Agent_Orange
  • 351
  • 1
  • 13
0

Per the ffmpeg-android-java pull request, there is a workaround to support Android 10, but the APK with that workaround may get rejected by Play Store (see pull request for details).

An alternative is to switch to a newer Android ffmpeg library. As of July 2022 ffmpeg-kit is an actively contributed library and it worked great with my project as a drop-in replacement to ffmpeg-android-java.

Batta
  • 455
  • 5
  • 13