3

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.

Vedant Agarwala
  • 18,146
  • 4
  • 66
  • 89
  • are you sure the memory card isnt write protected or locked?? take it out and have a look on the side of the card – Tasos Dec 30 '15 at 15:37
  • actually if its a microsd im not sure if they have a lock but if thats not the issue try replacing the card – Tasos Dec 30 '15 at 15:45
  • That isn't the issue. The aws farm sample app works on the same device. Plus its a nexus 5- external storage is irremovable. – Vedant Agarwala Dec 30 '15 at 16:09
  • it was just a thought. have a look here for any solution -- http://stackoverflow.com/questions/33030933/android-6-0-open-failed-eacces-permission-denied – Tasos Dec 30 '15 at 16:14

2 Answers2

2

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

Aitor Viana
  • 933
  • 6
  • 15
  • See my question: `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.` – Vedant Agarwala Dec 30 '15 at 20:26
  • But, are you requesting the permission programmatically? That I can't see from the code you posted. In M it's not enough with declaring the permission in the manifest. – Aitor Viana Dec 31 '15 at 20:12
  • Dude please read the question description. This is an automated test. Permissions are not supposed to be asked as app itself doesn't need it – Vedant Agarwala Jan 01 '16 at 09:07
  • 3
    Try to grant the permission using adb: `adb shell pm grant ` You can automate that inside a gradle task – Aitor Viana Jan 01 '16 at 11:10
  • On a further note, when you say `Besides, it works on the AWS device farm sample app.`. I checked the github link you posted and AWS target sdk 22, not 23. That's probably why it works for them without needing to do anything extra. – Aitor Viana Jan 01 '16 at 11:21
  • Oh yes that's true. And I will automate the command in the gradle task. – Vedant Agarwala Jan 01 '16 at 17:37
  • Hi @vedant I am also facing the same issue. Have you got the solution? If yes, please share it. – abhishek kumar gupta Mar 11 '21 at 19:03
  • @abhishekkumargupta I stopped working on this. Did you try aitor's solution? – Vedant Agarwala Mar 12 '21 at 10:33
  • @vedant I make it work by providing Storage Permission via. terminal like 'adb shell pm grant com.example.abhishek.test android.permission.WRITE_EXTERNAL_STORAGE' before running test case. – abhishek kumar gupta Mar 12 '21 at 17:16
  • @abhishekkumargupta you should add that as an answer here – Vedant Agarwala Mar 19 '21 at 09:49
0

I make it work by providing Storage Permission via. terminal(before running test case) like

adb shell pm grant com.example.abhishek.test android.permission.WRITE_EXTERNAL_STORAGE

abhishek kumar gupta
  • 2,189
  • 6
  • 35
  • 56