Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write external storage "permission denied" in instumentation testing on API 23 or higher

I cannot write to external storage even in the test case method (inside a subclass of ActivityInstrumentationTestCase2):

public void testWriteToStorage() throws Throwable {
    File file = new File(Environment.getExternalStorageDirectory(), "test");
    new FileOutputStream(file); // error thrown here
}

Error:

java.io.FileNotFoundException: /storage/emulated/0/test: open failed: EACCES (Permission denied)
        at libcore.io.IoBridge.open(IoBridge.java:452)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:87)
        at java.io.FileOutputStream.<init>(FileOutputStream.java:72)
        at com.unacademy.activity.GalleryTestCase.testWriteToStorage(GalleryTestCase.java:49)
        at java.lang.reflect.Method.invoke(Native Method)
        at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:214)
        at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:199)
        at android.test.ActivityInstrumentationTestCase2.runTest(ActivityInstrumentationTestCase2.java:192)
        at junit.framework.TestCase.runBare(TestCase.java:134)
        at junit.framework.TestResult$1.protect(TestResult.java:115)
        at android.support.test.internal.runner.junit3.AndroidTestResult.runProtected(AndroidTestResult.java:77)
        at junit.framework.TestResult.run(TestResult.java:118)
        at android.support.test.internal.runner.junit3.AndroidTestResult.run(AndroidTestResult.java:55)
        at junit.framework.TestCase.run(TestCase.java:124)
        at android.support.test.internal.runner.junit3.NonLeakyTestSuite$NonLeakyTest.run(NonLeakyTestSuite.java:63)
        at junit.framework.TestSuite.runTest(TestSuite.java:243)
        at junit.framework.TestSuite.run(TestSuite.java:238)
        at android.support.test.internal.runner.junit3.DelegatingTestSuite.run(DelegatingTestSuite.java:103)
        at android.support.test.internal.runner.junit3.AndroidTestSuite.run(AndroidTestSuite.java:69)
        at android.support.test.internal.runner.junit3.JUnit38ClassRunner.run(JUnit38ClassRunner.java:90)
        at org.junit.runners.Suite.runChild(Suite.java:128)
        at org.junit.runners.Suite.runChild(Suite.java:27)
        at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
        at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
        at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
        at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
        at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
        at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
        at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
        at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:54)
        at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:240)
        at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1879)
        Caused by: android.system.ErrnoException: open failed: EACCES (Permission denied)
        at libcore.io.Posix.open(Native Method)
        at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)
        at libcore.io.IoBridge.open(IoBridge.java:438)
        ... 32 more

I have the WRITE_EXTERNAL_STORAGE permission in the manifest and I know that after API 23 dangerous permissions require a consent from user at runtime.

But this is not in the Application context; it's in the instrumentation context. Besides, it works on the AWS device farm sample app. To the best of my ability I copied the exact same code from there but it still fails here.

NOTE: I'm just trying to take a screenshot and store in external storage for AWS Device Farm to pick it up. If anyone managed to do it in some other way please tell me; that'll be really helpful as well.

like image 427
Vedant Agarwala Avatar asked Jan 28 '26 03:01

Vedant Agarwala


1 Answers

One thing that comes to my mind is that you're targeting M and maybe not handling the permission request at the runtime.

As you say, in M WRITE_EXTERNAL_STORAGE is considered a dangerous permission but, the permission handling also changed. Before M, permissions were declared in the manifest and accepted by the user when installing the app. In M, you also have to request the permissions at runtime.

Please check this library that will help you handling the permissions in M.

https://github.com/aitorvs/allowme

I also suggest that you try to avoid external storage whenever possible or even better, storage permissions altogether. Check this fantastic talk from Ian Lake.

https://www.youtube.com/watch?v=C28pvd2plBA

like image 146
Aitor Viana Avatar answered Jan 30 '26 03:01

Aitor Viana