8

I am trying to get Internal Storage details(Storage which is used as Internal Memory) using below code.

public void getinternalstorage() {
        StatFs stat = new StatFs(Environment.getExternalStorageDirectory().getPath());
        double bytesavalible = (double) stat.getBlockSizeLong() * (double) stat.getAvailableBlocksLong();
        final double gb = bytesavalible / (1024 * 1024 * 1024);
        double total = (double) stat.getBlockSizeLong() * stat.getBlockCountLong();
        final double totalgb = total / (1024 * 1024 * 1024);
        final double per = (100 - (gb / totalgb) * 100);
        update_inte((int) (per * 1), round(totalgb, 2), round((gb), 2));
        TextView text2written = (TextView) findViewById(R.id.inter);
        text2written.setText(String.valueOf(round((totalgb - gb), 2)) + " GB " + "/ " + String.valueOf(round(totalgb, 2)) + " GB");
    }

I have also taken the required permissions.

For Android 5.0 and below-

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

For android 6.0 and above I am requesting runtime permissions.

But I have received android.system.ErrnoException error from around 10 users. Full Stack Trace

Fatal Exception: java.lang.RuntimeException: Unable to resume activity {com.package.app.Main_Screen}: java.lang.IllegalArgumentException: Invalid path: /sdcard
       at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3121)
       at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3152)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1398)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:148)
       at android.app.ActivityThread.main(ActivityThread.java:5443)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
Caused by java.lang.IllegalArgumentException: Invalid path: /sdcard
       at android.os.StatFs.doStat(StatFs.java:46)
       at android.os.StatFs.(StatFs.java)
       at com.package.app.Main_Screen.getinternalstorage(Main_Screen.java:565)
       at com.package.app.Main_Screen.on_resume(Main_Screen.java:785)
       at com.package.app.Main_Screen.checkPermission(Main_Screen.java:1070)
       at com.package.app.Main_Screen.onResume(Main_Screen.java:779)
       at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1281)
       at android.app.Activity.performResume(Activity.java:6320)
       at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3110)
       at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3152)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1398)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:148)
       at android.app.ActivityThread.main(ActivityThread.java:5443)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
Caused by android.system.ErrnoException: statvfs failed: ENOENT (No such file or directory)
       at libcore.io.Posix.statvfs(Posix.java)
       at libcore.io.BlockGuardOs.statvfs(BlockGuardOs.java:298)
       at android.system.Os.statvfs(Os.java:500)
       at android.os.StatFs.doStat(StatFs.java:44)
       at android.os.StatFs.(StatFs.java)
       at com.package.app.Main_Screen.getinternalstorage(Main_Screen.java:565)
       at com.package.app.Main_Screen.on_resume(Main_Screen.java:785)
       at com.package.app.Main_Screen.checkPermission(Main_Screen.java:1070)
       at com.package.app.Main_Screen.onResume(Main_Screen.java:779)
       at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1281)
       at android.app.Activity.performResume(Activity.java:6320)
       at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3110)
       at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3152)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1398)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:148)
       at android.app.ActivityThread.main(ActivityThread.java:5443)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)

I am receiving this error from 5.0 to 7.0 Android Version

  • Hi John, what do you get with: Environment.getExternalStorageDirectory().getPath() . Are you using the emulator? – Jorgesys Dec 11 '17 at 16:21
  • Your mixing up internal storage and external sotrage in your question, very confusing, please edit. "People will think that they can work with removable storage much like they can with a desktop or notebook. Unfortunately, your users are largely mistaken, and are even more mistaken with Android 4.4+. That’s because Google’s approach towards removable storage is… unconventional." See [Commonsware blog he's a user on SO](https://commonsware.com/blog/2017/11/15/storage-situation-removable-storage.html) – Jon Goodwin Dec 11 '17 at 16:22
  • @Jorgesys No, I am not using an emulator but these errors are occurring from real devices. Also I am not able to reproduce this error in my test device. In my test device it is returning the Internal storage path. –  Dec 11 '17 at 16:27
  • @JonGoodwin Recently most of the mobile phones return Internal Storage path when `Environment.getExternalStorageDirectory().getPath()` is called. Also I have error from Motorola device Moto E 2nd gen. I have users using Moto E 2nd gen and the app is working fine for them. –  Dec 11 '17 at 16:31
  • My reading of the blog is "you will NEVER get it to work on EVERY phone". – Jon Goodwin Dec 11 '17 at 16:33
  • @JonGoodwin Yes you are right. But how is it possible that two users using the same exact model but one having issue and the other not having? –  Dec 11 '17 at 16:40
  • The reason this is so complex is it involves every aspect of the device, the hardware, the removable media, the ROM, the Android version on the phone and the application (yours). Android have never liked the lack of security inherent in external storage. The phone manufacturers have kernel access so can do anything they like with storage, we mortal programmers cannot. – Jon Goodwin Dec 11 '17 at 17:13
  • I think `Environment.getExternalStorageDirectory().getPath()` is not reliable enough to get the external storage. This [link](https://gist.github.com/PauloLuan/4bcecc086095bce28e22) could give you references how to prevent missing sd card path. – aLIEz Dec 11 '17 at 17:19
  • @JonGoodwin So basically there is nothing which can be done to avoid this error? –  Dec 11 '17 at 17:20
  • @user3042930 I am not finding the External Storage, but I am trying to find the Internal Storage. –  Dec 11 '17 at 17:21
  • Maybe you could use `getFilesDir()` to get Internal Storage path. – aLIEz Dec 11 '17 at 17:32
  • @aLIEz Thanks. Will try and get back soon with the updated results. –  Dec 11 '17 at 17:47
  • There are always things you can do. There is no reason at all that your app should fall over in a heap, a simple try{}catch{} around the offending code should mitigate it crashing. – Jon Goodwin Dec 11 '17 at 18:42
  • @JonGoodwin Nice Idea about the `try{}ctach{}`. Will try that and on the catch event will try @aLIEz way of getting the path and see whether that solves the issue. –  Dec 11 '17 at 19:00
  • Hmm, my first comment I think you have not read/understood properly. If you use Internal storage you don't have any problems. External storage/removable storage you have BIG problems. On a phone (let's not talk about Tablets, but it's almost the same) External storage/removable can and almost always IS INSIDE the phone. You question is in one part specific and in another part TOTALLY confused. Please edit you question to make it clear. getinternalstorage() method using inside getExternalStorageDirectory() is a VERY silly thing ;O) It's ALL about semantics. – Jon Goodwin Dec 11 '17 at 20:08

2 Answers2

5

I) Getting the path from the External Storage Directory with

Environment.getExternalStorageDirectory().getPath()

you will get something like:

 /storage/emulated/0
 /mnt/sdcard 
 /mnt/sdcard-ext 

but the error points out that you are only gettin /sdcard:

Caused by java.lang.IllegalArgumentException: Invalid path: /sdcard at android.os.StatFs.doStat(StatFs.java:46) at android.os.StatFs.(StatFs.java)

If we check the SDK method that raise this error:

private static StructStatVfs doStat(String path) {
    try {
        return Os.statvfs(path);
    } catch (ErrnoException e) {
        throw new IllegalArgumentException("Invalid path: " + path, e);
    }
}

The function statvfs() returns information about a mounted filesystem. path is the pathname of any file within the mounted filesystem.

So, to avoid this problem you must be sure that the SD Card is mounted! In this case is difficult assure this in all your production users, the option would be a validation.

btw, i recommend the use of getAbsolutePath()

Environment.getExternalStorageDirectory().getAbsolutePath();

instead of

Environment.getExternalStorageDirectory().getPath();

To get the absolute path, the path after resolving it against the current directory if it's relative, resulting in a "fully qualified path".


II) The other error message displayed is:

Caused by android.system.ErrnoException: statvfs failed: ENOENT (No such file or directory) at libcore.io.Posix.statvfs(Posix.java)

Remember, your application can´t read the internal Storage, remember, you must require WRITE_EXTERNAL_STORAGE (inherent READ_EXTERNAL_STORAGE) permission manually in devices 6.0+

This would be the cause of:

ENOENT (No such file or directory)

because the user must accept the permission.

Cullub
  • 2,901
  • 3
  • 30
  • 47
Jorgesys
  • 124,308
  • 23
  • 334
  • 268
0

Hi Please check below step by step process.

1) Please check runtime permission first into your code for latest devices see below link for it.

https://developer.android.com/training/permissions/requesting.html

2) You need to use the environment variable. Environment.getExternalStorageDirectory(); . There are many methods in Environment.java . It depends on what information you need . For example to get external storage name you use Environment.getExternalStorageDirectory().getName(); there are other methos you can make use of them. For Internal storage the api's may not be available publicly .

StatFs stat = new StatFs(type.getPath());
long bytesAvailable = (long)stat.getBlockSize()*(long)stat.getAvailableBlocks();  
long megAvailable = bytesAvailable / (1024 * 1024);  
Log.i("TAG","Available size in MB : "+megAvailable); 

Please check below 2 link those also helps you.

Android get free size of internal/external memory

How to Check available space on android device ? on SD card?

Hope this helps.

Jyubin Patel
  • 1,373
  • 7
  • 17