open failed: EACCES (Permission denied)
Asked Answered
P

22

96

I am having a very weird problem with storage accessing on some devices. The app works on my testing devices (Nexus 4 & 7, Samsung GS5). All my devices running Android 4.4.2. But I received many emails from users saying that the app can not write to the storage (neither the internal storage nor the sd card). From the log file received from user feedback, I can see the problem is the following code:

try {
    if (fStream == null) {
    fStream = new FileOutputStream(filename, true);
}
    fStream.write(data, 0, bytes);
    return;
} catch (IOException ex) {
    ex.printStackTrace();
}

It throws exception at the line fStream = new FileOutputStream(filename, true); when creating FileOutputStream.

The stack log is:

W/System.err( 8147): Caused by: java.io.FileNotFoundException: /storage/emulated/0/my_folder/test_file_name.png: open failed: EACCES (Permission denied)
w/System.err( 8147):    at libcore.io.IoBridge.open(IoBridge.java:409)
W/System.err( 8147):    at java.io.FileOutputStream.<init>(FileOutputStream.java:88)
W/System.err( 8147):    at java.io.FileOutputStream.<init>(FileOutputStream.java:128)
W/System.err( 8147):    at myapp.save(SourceFile:515)
W/System.err( 8147):    ... 8 more
W/System.err( 8147): Caused by: libcore.io.ErrnoException: open failed: EACCES (Permission denied)
W/System.err( 8147):    at libcore.io.Posix.open(Native Method)
W/System.err( 8147):    at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
W/System.err( 8147):    at libcore.io.IoBridge.open(IoBridge.java:393)
W/System.err( 8147):    ... 11 more

In the AndroidManifest.xml I have the following permissions declared:

 <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="19"/>
    <uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> 

I've confirmed that the users are using the correct app's private on the SD card. And what's more weird is that it fails to write to internal storage as well. How can this happen if I have both read & write permissions? The users say they are not connecting their devices to the PC at that time.

Update

It turns out I am calling open and close FileOutputStream too frequently, which throws the FileNotFoundException at some point. Sounds more like a threading issue.

Philosophical answered 7/5, 2014 at 20:30 Comment(3)
It turns out I am calling open and close FileOutputStream too frequently, which throws the FileNotFoundException at some point. Sounds more like a threading issue.Philosophical
Check my answer here. hope it helps. https://mcmap.net/q/121718/-java-io-filenotfoundexception-open-failed-eacces-permission-deniedOsteotomy
getExternalStoragePublicDirectory(...) is depecratedString use this.getApplicationContext().getExternalFilesDir(null).toString(); insteadMasto
I
35

I ran into a similar issue a while back.

Your problem could be in two different areas. It's either how you're creating the file to write to, or your method of writing could be flawed in that it is phone dependent.

If you're writing the file to a specific location on the SD card, try using Environment variables. They should always point to a valid location. Here's an example to write to the downloads folder:

java.io.File xmlFile = new java.io.File(Environment
    .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
     + "/Filename.xml");

If you're writing the file to the application's internal storage. Try this example:

java.io.File xmlFile = new java.io.File((getActivity()
   .getApplicationContext().getFileStreamPath("FileName.xml")
   .getPath()));

Personally I rely on external libraries to handle the streaming to file. This one hasn't failed me yet.

org.apache.commons.io.FileUtils.copyInputStreamToFile(is, file);

I've lost data one too many times on a failed write command, so I rely on well-known and tested libraries for my IO heavy lifting.

If the files are large, you may also want to look into running the IO in the background, or use callbacks.

If you're already using environment variables, it could be a permissions issue. Check out Justin Fiedler's answer below.

Indecision answered 7/5, 2014 at 22:9 Comment(3)
I'll try with org.apache.commons.io.FileUtils and see if that helps. Will post update later. By the way, after more testing, it turns out that fStream = new FileOutputStream(filename, true); doesn't always fail to open the stream every time, looks like it works for the first time and fails next time.Philosophical
It turns out I am calling open and close FileOutputStream too frequently, which throws the FileNotFoundException at some point. Sounds more like a threading issue. I've marked your answer since accepted as you pointed out the possible error correctly.Philosophical
Thanks. Yeah, since we couldn't see your entire code, we just have to make some guesses on what could be causing your issue. Thanks for the accept!Indecision
T
179

Apps targeting Android Q - API 29 by default are given a filtered view into external storage. A quick fix for that is to add this code in the AndroidManifest.xml:

<manifest ... >
    <!-- This attribute is "false" by default on apps targeting Android Q. -->
    <application android:requestLegacyExternalStorage="true" ... >
     ...
    </application>
</manifest>

Read more about it here: https://developer.android.com/training/data-storage/compatibility

Tamarah answered 26/8, 2019 at 7:52 Comment(4)
Because this solution is temporary, here is the whole implementation of how to query the media files: developer.android.com/training/data-storage/shared/media . If it's an image, after you get the uri, you need to call ContentResolver.loadThumbnail(uri, size, cancelSignal) to receive the bitmap containing that image.Ransack
google play console will ask you later to gives an explanation why you are using this attribute otherwise they will block your app.Synchroflash
You're dumb!!!!Foolhardy
@Foolhardy why?Tamarah
U
134

For API 23+ you need to request the read/write permissions even if they are already in your manifest.

// Storage Permissions
private static final int REQUEST_EXTERNAL_STORAGE = 1;
private static String[] PERMISSIONS_STORAGE = {
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
};

/**
 * Checks if the app has permission to write to device storage
 *
 * If the app does not has permission then the user will be prompted to grant permissions
 *
 * @param activity
 */
public static void verifyStoragePermissions(Activity activity) {
    // Check if we have write permission
    int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE);

    if (permission != PackageManager.PERMISSION_GRANTED) {
        // We don't have permission so prompt the user
        ActivityCompat.requestPermissions(
                activity,
                PERMISSIONS_STORAGE,
                REQUEST_EXTERNAL_STORAGE
        );
    }
}

AndroidManifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Underfur answered 22/10, 2015 at 19:20 Comment(11)
That's true, solved my problem. More info: developer.android.com/training/permissions/requesting.htmlAbb
Exact, my problem, was similar. If I tested the app in Android versions lower than v6. the app worked like a charm, but, for >=6, something was, wrong. As @easyspeak said, just add permission request.Ketone
how to do it on instrumented test?Cl
i gave permission but not able to make .zip file in sdcardItalianate
Google is ruthless with this stuff.Steels
This is the correct answer, not the one that is currently marked.Okinawa
The READ permission is unnecessary (If your app uses the WRITE_EXTERNAL_STORAGE permission, then it implicitly has permission to read the external storage as well.)Andress
@Andress where to add those lines of code project except AndroidManifest.xml codeRespond
I have been hustling for 3 days now. This solved my problem. Thanks.Kaluga
Should we call this method somewhere? Or just paste in the mainActivity code?Wrens
@TinaJ you can call this anywhere you want before needing the permissions. In my case I called it immediately before saving an image. You can call it in your main Activity but it might be off-putting to some users to ask for permissions before you need them.Underfur
I
35

I ran into a similar issue a while back.

Your problem could be in two different areas. It's either how you're creating the file to write to, or your method of writing could be flawed in that it is phone dependent.

If you're writing the file to a specific location on the SD card, try using Environment variables. They should always point to a valid location. Here's an example to write to the downloads folder:

java.io.File xmlFile = new java.io.File(Environment
    .getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
     + "/Filename.xml");

If you're writing the file to the application's internal storage. Try this example:

java.io.File xmlFile = new java.io.File((getActivity()
   .getApplicationContext().getFileStreamPath("FileName.xml")
   .getPath()));

Personally I rely on external libraries to handle the streaming to file. This one hasn't failed me yet.

org.apache.commons.io.FileUtils.copyInputStreamToFile(is, file);

I've lost data one too many times on a failed write command, so I rely on well-known and tested libraries for my IO heavy lifting.

If the files are large, you may also want to look into running the IO in the background, or use callbacks.

If you're already using environment variables, it could be a permissions issue. Check out Justin Fiedler's answer below.

Indecision answered 7/5, 2014 at 22:9 Comment(3)
I'll try with org.apache.commons.io.FileUtils and see if that helps. Will post update later. By the way, after more testing, it turns out that fStream = new FileOutputStream(filename, true); doesn't always fail to open the stream every time, looks like it works for the first time and fails next time.Philosophical
It turns out I am calling open and close FileOutputStream too frequently, which throws the FileNotFoundException at some point. Sounds more like a threading issue. I've marked your answer since accepted as you pointed out the possible error correctly.Philosophical
Thanks. Yeah, since we couldn't see your entire code, we just have to make some guesses on what could be causing your issue. Thanks for the accept!Indecision
E
9

Add these both permission of read and write, to solve this issue

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Add this below line in Application tag

android:requestLegacyExternalStorage="true"
Eleazar answered 29/9, 2020 at 12:31 Comment(2)
android:requestLegacyExternalStorage="true" .. using this worksCm
Although, the suggested solution will work, it's just a temporary fix. Check Android documentation.Westbound
T
6

In my case I had the wrong case in

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

android.permission must be lowercase, and somehow the entire string was uppercase in our source.

Tabloid answered 25/9, 2015 at 18:23 Comment(0)
D
5

I also faced the same issue. After lot of hard work, I found what was wrong in my case. My device was connected to computer via USB cable. There are types for USB connections like Mass Storage, Media Device(MTP), Camera(PTP) etc. My connection type was - 'Mass Storage', and this was causing the problems. When I changed the connection type, the issue was solved.

Always remember while accessing filesystem on android device :-

DON'T CONNECT AS MASS STORAGE to the computer/pc.

Dreadnought answered 22/10, 2014 at 10:17 Comment(2)
Changed to what? I have PTP and MTP as my only options, neither work. Even loading the app on my device and starting it from the device without it being connected to my computer doesn't fix it.Idaliaidalina
Or debug it with Wifi.Nostrum
A
3

In my case it was permissions issue. The catch is that on device with Android 4.0.4 I got access to file without any error or exception. And on device with Android 5.1 it failed with ACCESS exception (open failed: EACCES (Permission denied)). Handled it with adding follow permission to manifest file:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

So I guess that it's the difference between permissions management in OS versions that causes to failures.

Accelerando answered 8/1, 2017 at 14:29 Comment(0)
L
2

First give or check permissions like

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

If these two permissions are OK, then check your output streams are in correct format.

Example:

FileOutputStream fos=new FileOutputStream(Environment.getExternalStorageDirectory()+"/rahul1.jpg");
Lowestoft answered 21/2, 2017 at 10:14 Comment(0)
F
2

I ran into the same problem and found that I have to request the permissions at run time, even if I have declared it in the manifest. Just as stated as Justin Fiedler's answer.

The official documentation about this are here: https://developer.android.com/training/permissions/requesting.html

My implementation is slightly different from Justin Fiedler's answer that it also implement v4 fragment's onRequestPermissionsResult method to handle the permissions request response.

public static final int REQUEST_EXTERNAL_PERMISSION_CODE = 666;

@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
public static final String[] PERMISSIONS_EXTERNAL_STORAGE = {
        READ_EXTERNAL_STORAGE,
        WRITE_EXTERNAL_STORAGE
};

public boolean checkExternalStoragePermission(Activity activity) {
    if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN) {
        return true;
    }

    int readStoragePermissionState = ContextCompat.checkSelfPermission(activity, READ_EXTERNAL_STORAGE);
    int writeStoragePermissionState = ContextCompat.checkSelfPermission(activity, WRITE_EXTERNAL_STORAGE);
    boolean externalStoragePermissionGranted = readStoragePermissionState == PackageManager.PERMISSION_GRANTED &&
            writeStoragePermissionState == PackageManager.PERMISSION_GRANTED;
    if (!externalStoragePermissionGranted) {
        requestPermissions(PERMISSIONS_EXTERNAL_STORAGE, REQUEST_EXTERNAL_PERMISSION_CODE);
    }

    return externalStoragePermissionGranted;
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        if (requestCode == REQUEST_EXTERNAL_PERMISSION_CODE) {
            if (checkExternalStoragePermission(getActivity())) {
                // Continue with your action after permission request succeed
            }
        }
    }
}
Fuqua answered 2/4, 2017 at 1:4 Comment(1)
Great illustration. Saved my day. :-)Yulan
C
1

In my case I used the option android:isolatedProcess="true" for a service in the AndroidManifest.xml.

As soon as I removed it, the error disappeared...

Christian answered 5/3, 2015 at 19:40 Comment(0)
W
1

Also I found solving for my way.

Before launch app i granted root to file-explorer and did not disable permission on write/read when exit from app.

My app can not use external memory while i did restrat device for resetting all permissions.

Womanizer answered 22/5, 2015 at 7:26 Comment(0)
M
1

I got the same issue but Sometimes, the most dificult issue get simple answer.

I recheck the manifest permisions and there WAS_NOT write permision shame of me!!!

Mercurial answered 19/6, 2017 at 16:43 Comment(1)
jesus christ, this just happened to me, thanks heapsOverweening
O
1

@Uriel Frankel is correct that the Android 10 storage access has changed. But the right way is not to use legacy storage flag but to request the storage of your app like so:

val screenShotDirPath = getApplication<Application>().getExternalFilesDir(Environment.DIRECTORY_PICTURES)?.path

getExternalFilesDir is what you need.

Otti answered 1/10, 2019 at 15:2 Comment(0)
K
1

I had the same problem. My app worked on Android 11, but the error showed up in Android 10. Upgrading to Android 11 solved the problem.

Kristianson answered 15/6, 2021 at 22:5 Comment(1)
I am currently having this issue, but since we support Android 10 I have to find a fix. It's only on 10 though. Android 9, 11, and 12 all work fine.Altostratus
G
0

If the clients are using Android 6.0, Android added new permission model for (Marshmallow).

Trick: If you are targeting version 22 or below, your application will request all permissions at install time just as it would on any device running an OS below Marshmallow

Gaucherie answered 6/4, 2016 at 22:51 Comment(0)
C
0

In my case the issue was the WIFI Configuration that was static had a conflict with another device using the same IP Address.

Crenulation answered 27/2, 2017 at 7:34 Comment(0)
P
0

This error was thrown by another app that I'm sharing my app's file to (using Intent.FLAG_GRANT_READ_URI_PERMISSION)

Turns out, the File Uri has to be provided via FileProvider class as shown here.

Peculate answered 24/12, 2020 at 4:54 Comment(0)
M
0

I was able to solve this problem by removing

  tools:ignore="ScopedStorage" />

this line from

uses-permission 
   android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    android:maxSdkVersion="28" tools:ignore="ScopedStorage" 

   

and also you don't need read permission anymore

Marguerita answered 4/6, 2021 at 8:58 Comment(0)
S
0

Using Android 12 (API 31), I read in OS docs that we must use Manifest main property :

example:

 uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"

The issue has been solved.

Scag answered 9/9, 2022 at 7:59 Comment(0)
J
-1

For those of you who tried all the above solutions and still doesn't solve your error on API 30. Change targetSdkVersion 30 to 29 in defaultConfig in your build.gradle(app)

Code will look like:-

defaultConfig {
    applicationId "com.example.company"
    minSdkVersion 16
    targetSdkVersion 29
   .
   .
   .
}
Junia answered 1/5, 2021 at 5:15 Comment(1)
worked for me. I guess target version 30 + handles permissions differently. I will post the full solution for target version 30 if i find itCircinate
D
-2

I solved this by using another path:

data/data/[packagename]/cache/...
Delagarza answered 2/4, 2021 at 8:40 Comment(1)
Hi @Delagarza - Welcome to Stack Overflow ... Does your answer solve premission denied or the Original Problem (OP) ? If you think you have some added inisight of the existing historical answers, please edit the most relevant answer to include your new insights.Curkell
C
-3

in my case i forgot to add / in front of file name after i added i got rid of from it

bitmap.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(Environment.getExternalStorageDirectory()+"/arjunreddy.png"));
Capitulate answered 27/8, 2017 at 7:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.