Home » Android » java – StrictMode complains about InputStream not being closed

java – StrictMode complains about InputStream not being closed

Posted by: admin June 15, 2020 Leave a comment

Questions:

I’m getting the following violation reported by StrictMode in Android.

02-05 04:07:41.190: ERROR/StrictMode(15093): A resource was acquired
at attached stack trace but never released. See java.io.Closeable for
information on avoiding resource leaks. 02-05 04:07:41.190:
ERROR/StrictMode(15093): java.lang.Throwable: Explicit termination
method ‘close’ not called

It is cribbing about not closing streams properly. However, shouldn’t closing in close the underlying streams? What could be the reason for the flagged error?

    private ArrayList<Uri> loadPath() {
        ArrayList<Uri> uris = new ArrayList<Uri>();
        if (mFile.exists()) {
            ObjectInputStream in = null;
            try {
                in = new ObjectInputStream(new BufferedInputStream(
                         new FileInputStream(mFile), STREAM_BUFFER_SIZE));
                ArrayList<String> strings = new ArrayList<String>();
                strings.addAll((ArrayList<String>) in.readObject());
                for (String string : strings) {
                    uris.add(Uri.parse(string));
                }
            } catch (Exception e) {
                mFile.delete();
            } finally {
                IOUtils.closeQuietly(in);
            }
        }
        return uris;
     }

    public static void closeQuietly(InputStream input) {
        try {
            if (input != null) {
                input.close();
            }
        } catch (IOException ioe) {
            // ignore
        }
    }
How to&Answers:

Looking at the source code, the constructors for both ObjectInputStream and BufferedInputStream can throw exceptions which would cause a FileInputStream object to be allocated on the following line, but the in variable will still be null:

            in = new ObjectInputStream(
                    new BufferedInputStream(
                            new FileInputStream(mFile), 
                    STREAM_BUFFER_SIZE)
            );

Since in is null when we get to the finally block, that open FileInputStream object will not be closed by your closeQuietly() method, causing StrictMode to complain eventually 🙂

The simplest fix I would suggest is to split that allocation into 3 variables and call closeQuietly() on each, maybe something like this:

private ArrayList<Uri> loadPath() {
    final ArrayList<Uri> uris = new ArrayList<Uri>();
    if (mFile.exists()) {
        ObjectInputStream ois = null;
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        try {
            fis = new FileInputStream(mFile);
            bis = new BufferedInputStream(fis, STREAM_BUFFER_SIZE);
            ois = new ObjectInputStream(bis);
            final ArrayList<String> strings = new ArrayList<String>();
            strings.addAll((ArrayList<String>) ois.readObject());
            for (final String string : strings) {
                uris.add(Uri.parse(string));
            }
        } catch (final Exception e) {
            mFile.delete();
        } finally {
            closeQuietly(fis);
            closeQuietly(bis);
            closeQuietly(ois);
        }
    }
    return uris;
}

Answer:

If you take a look at ObjectOutpuStream source, you will see that its close method closes underlying stream. Android’s strict mode like many other code analysis tools have false positives which you can either ignore or rewrite your code so that it won’t complain (inline closeQuietly method).

Answer:

The code should work, unless you’re using ProGuard which could mess up a little with bytecode.

FileInputStream has hooks to CloseGuard which is checked in finalize() if the instance was closed. That is why I think it should work. The question is weather close() was invoked or not?

I think that FileInputStream was created (because StrictMode thrown exception) but then a exception was thrown in finally and ignored somewhere.

    try {
        if (input != null) {
            input.close();
        }
    } catch (Exception ioe) {
        // check exception here
    }

Answer:

in = new ObjectInputStream(new BufferedInputStream(
                         new FileInputStream(mFile), STREAM_BUFFER_SIZE));

In this code sample you only close the ObjectInputStream but not the BufferedInputStream
or the FileInputStream, you need to close them all.