1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.  Oracle designates this
9 * particular file as subject to the "Classpath" exception as provided
10 * by Oracle in the LICENSE file that accompanied this code.
11 *
12 * This code is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 * version 2 for more details (a copy is included in the LICENSE file that
16 * accompanied this code).
17 *
18 * You should have received a copy of the GNU General Public License version
19 * 2 along with this work; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
23 * or visit www.oracle.com if you need additional information or have any
24 * questions.
25 */
26
27package java.io;
28
29import java.nio.channels.FileChannel;
30
31import dalvik.annotation.optimization.ReachabilitySensitive;
32import dalvik.system.BlockGuard;
33import dalvik.system.CloseGuard;
34import sun.nio.ch.FileChannelImpl;
35import libcore.io.IoBridge;
36import libcore.io.IoTracker;
37
38
39/**
40 * A <code>FileInputStream</code> obtains input bytes
41 * from a file in a file system. What files
42 * are  available depends on the host environment.
43 *
44 * <p><code>FileInputStream</code> is meant for reading streams of raw bytes
45 * such as image data. For reading streams of characters, consider using
46 * <code>FileReader</code>.
47 *
48 * @author  Arthur van Hoff
49 * @see     java.io.File
50 * @see     java.io.FileDescriptor
51 * @see     java.io.FileOutputStream
52 * @see     java.nio.file.Files#newInputStream
53 * @since   JDK1.0
54 */
55public
56class FileInputStream extends InputStream
57{
58    /* File Descriptor - handle to the open file */
59    // Android-added: @ReachabilitySensitive
60    @ReachabilitySensitive
61    private final FileDescriptor fd;
62
63    /**
64     * The path of the referenced file
65     * (null if the stream is created with a file descriptor)
66     */
67    private final String path;
68
69    private FileChannel channel = null;
70
71    private final Object closeLock = new Object();
72    private volatile boolean closed = false;
73
74    // Android-added: Field for tracking whether the stream owns the underlying FileDescriptor.
75    private final boolean isFdOwner;
76
77    // Android-added: CloseGuard support.
78    @ReachabilitySensitive
79    private final CloseGuard guard = CloseGuard.get();
80
81    // Android-added: Tracking of unbuffered I/O.
82    private final IoTracker tracker = new IoTracker();
83
84    /**
85     * Creates a <code>FileInputStream</code> by
86     * opening a connection to an actual file,
87     * the file named by the path name <code>name</code>
88     * in the file system.  A new <code>FileDescriptor</code>
89     * object is created to represent this file
90     * connection.
91     * <p>
92     * First, if there is a security
93     * manager, its <code>checkRead</code> method
94     * is called with the <code>name</code> argument
95     * as its argument.
96     * <p>
97     * If the named file does not exist, is a directory rather than a regular
98     * file, or for some other reason cannot be opened for reading then a
99     * <code>FileNotFoundException</code> is thrown.
100     *
101     * @param      name   the system-dependent file name.
102     * @exception  FileNotFoundException  if the file does not exist,
103     *                   is a directory rather than a regular file,
104     *                   or for some other reason cannot be opened for
105     *                   reading.
106     * @exception  SecurityException      if a security manager exists and its
107     *               <code>checkRead</code> method denies read access
108     *               to the file.
109     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
110     */
111    public FileInputStream(String name) throws FileNotFoundException {
112        this(name != null ? new File(name) : null);
113    }
114
115    /**
116     * Creates a <code>FileInputStream</code> by
117     * opening a connection to an actual file,
118     * the file named by the <code>File</code>
119     * object <code>file</code> in the file system.
120     * A new <code>FileDescriptor</code> object
121     * is created to represent this file connection.
122     * <p>
123     * First, if there is a security manager,
124     * its <code>checkRead</code> method  is called
125     * with the path represented by the <code>file</code>
126     * argument as its argument.
127     * <p>
128     * If the named file does not exist, is a directory rather than a regular
129     * file, or for some other reason cannot be opened for reading then a
130     * <code>FileNotFoundException</code> is thrown.
131     *
132     * @param      file   the file to be opened for reading.
133     * @exception  FileNotFoundException  if the file does not exist,
134     *                   is a directory rather than a regular file,
135     *                   or for some other reason cannot be opened for
136     *                   reading.
137     * @exception  SecurityException      if a security manager exists and its
138     *               <code>checkRead</code> method denies read access to the file.
139     * @see        java.io.File#getPath()
140     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
141     */
142    public FileInputStream(File file) throws FileNotFoundException {
143        String name = (file != null ? file.getPath() : null);
144        SecurityManager security = System.getSecurityManager();
145        if (security != null) {
146            security.checkRead(name);
147        }
148        if (name == null) {
149            throw new NullPointerException();
150        }
151        if (file.isInvalid()) {
152            throw new FileNotFoundException("Invalid file path");
153        }
154        fd = new FileDescriptor();
155
156        // Android-changed: Tracking mechanism for FileDescriptor sharing.
157        // fd.attach(this);
158        isFdOwner = true;
159
160        path = name;
161
162        // Android-added: BlockGuard support.
163        BlockGuard.getThreadPolicy().onReadFromDisk();
164
165        open(name);
166
167        // Android-added: CloseGuard support.
168        guard.open("close");
169    }
170
171    // Android-removed: Documentation around SecurityException. Not thrown on Android.
172    /**
173     * Creates a <code>FileInputStream</code> by using the file descriptor
174     * <code>fdObj</code>, which represents an existing connection to an
175     * actual file in the file system.
176     * <p>
177     * If there is a security manager, its <code>checkRead</code> method is
178     * called with the file descriptor <code>fdObj</code> as its argument to
179     * see if it's ok to read the file descriptor. If read access is denied
180     * to the file descriptor a <code>SecurityException</code> is thrown.
181     * <p>
182     * If <code>fdObj</code> is null then a <code>NullPointerException</code>
183     * is thrown.
184     * <p>
185     * This constructor does not throw an exception if <code>fdObj</code>
186     * is {@link java.io.FileDescriptor#valid() invalid}.
187     * However, if the methods are invoked on the resulting stream to attempt
188     * I/O on the stream, an <code>IOException</code> is thrown.
189     *
190     * @param      fdObj   the file descriptor to be opened for reading.
191     */
192    public FileInputStream(FileDescriptor fdObj) {
193        // Android-changed: Delegate to added hidden constructor.
194        this(fdObj, false /* isFdOwner */);
195    }
196
197    // Android-added: Internal/hidden constructor for specifying FileDescriptor ownership.
198    // Android-removed: SecurityManager calls.
199    /** @hide */
200    public FileInputStream(FileDescriptor fdObj, boolean isFdOwner) {
201        if (fdObj == null) {
202            // Android-changed: Improved NullPointerException message.
203            throw new NullPointerException("fdObj == null");
204        }
205        fd = fdObj;
206        path = null;
207
208        // Android-changed: FileDescriptor ownership tracking mechanism.
209        /*
210        /*
211         * FileDescriptor is being shared by streams.
212         * Register this stream with FileDescriptor tracker.
213         *
214        fd.attach(this);
215        */
216        this.isFdOwner = isFdOwner;
217    }
218
219    /**
220     * Opens the specified file for reading.
221     * @param name the name of the file
222     */
223    private native void open0(String name) throws FileNotFoundException;
224
225    // wrap native call to allow instrumentation
226    /**
227     * Opens the specified file for reading.
228     * @param name the name of the file
229     */
230    private void open(String name) throws FileNotFoundException {
231        open0(name);
232    }
233
234    /**
235     * Reads a byte of data from this input stream. This method blocks
236     * if no input is yet available.
237     *
238     * @return     the next byte of data, or <code>-1</code> if the end of the
239     *             file is reached.
240     * @exception  IOException  if an I/O error occurs.
241     */
242    public int read() throws IOException {
243        // Android-changed: Read methods delegate to read(byte[], int, int) to share Android logic.
244        byte[] b = new byte[1];
245        return (read(b, 0, 1) != -1) ? b[0] & 0xff : -1;
246    }
247
248    // Android-removed: Read methods delegate to read(byte[], int, int) to share Android logic.
249    // private native int read0() throws IOException;
250
251    // Android-removed: Read methods delegate to read(byte[], int, int) to share Android logic.
252    /*
253    /**
254     * Reads a subarray as a sequence of bytes.
255     * @param b the data to be written
256     * @param off the start offset in the data
257     * @param len the number of bytes that are written
258     * @exception IOException If an I/O error has occurred.
259     *
260    private native int readBytes(byte b[], int off, int len) throws IOException;
261    */
262
263    /**
264     * Reads up to <code>b.length</code> bytes of data from this input
265     * stream into an array of bytes. This method blocks until some input
266     * is available.
267     *
268     * @param      b   the buffer into which the data is read.
269     * @return     the total number of bytes read into the buffer, or
270     *             <code>-1</code> if there is no more data because the end of
271     *             the file has been reached.
272     * @exception  IOException  if an I/O error occurs.
273     */
274    public int read(byte b[]) throws IOException {
275        // Android-changed: Read methods delegate to read(byte[], int, int) to share Android logic.
276        return read(b, 0, b.length);
277    }
278
279    /**
280     * Reads up to <code>len</code> bytes of data from this input stream
281     * into an array of bytes. If <code>len</code> is not zero, the method
282     * blocks until some input is available; otherwise, no
283     * bytes are read and <code>0</code> is returned.
284     *
285     * @param      b     the buffer into which the data is read.
286     * @param      off   the start offset in the destination array <code>b</code>
287     * @param      len   the maximum number of bytes read.
288     * @return     the total number of bytes read into the buffer, or
289     *             <code>-1</code> if there is no more data because the end of
290     *             the file has been reached.
291     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
292     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
293     * <code>len</code> is negative, or <code>len</code> is greater than
294     * <code>b.length - off</code>
295     * @exception  IOException  if an I/O error occurs.
296     */
297    public int read(byte b[], int off, int len) throws IOException {
298        // Android-added: close() check before I/O.
299        if (closed && len > 0) {
300            throw new IOException("Stream Closed");
301        }
302
303        // Android-added: Tracking of unbuffered I/O.
304        tracker.trackIo(len);
305
306        // Android-changed: Use IoBridge instead of calling native method.
307        return IoBridge.read(fd, b, off, len);
308    }
309
310    /**
311     * Skips over and discards <code>n</code> bytes of data from the
312     * input stream.
313     *
314     * <p>The <code>skip</code> method may, for a variety of
315     * reasons, end up skipping over some smaller number of bytes,
316     * possibly <code>0</code>. If <code>n</code> is negative, the method
317     * will try to skip backwards. In case the backing file does not support
318     * backward skip at its current position, an <code>IOException</code> is
319     * thrown. The actual number of bytes skipped is returned. If it skips
320     * forwards, it returns a positive value. If it skips backwards, it
321     * returns a negative value.
322     *
323     * <p>This method may skip more bytes than what are remaining in the
324     * backing file. This produces no exception and the number of bytes skipped
325     * may include some number of bytes that were beyond the EOF of the
326     * backing file. Attempting to read from the stream after skipping past
327     * the end will result in -1 indicating the end of the file.
328     *
329     * @param      n   the number of bytes to be skipped.
330     * @return     the actual number of bytes skipped.
331     * @exception  IOException  if n is negative, if the stream does not
332     *             support seek, or if an I/O error occurs.
333     */
334    // BEGIN Android-changed: skip(long) implementation changed from bare native.
335    public long skip(long n) throws IOException {
336        // Android-added: close() check before I/O.
337        if (closed) {
338            throw new IOException("Stream Closed");
339        }
340
341        try {
342            // Android-added: BlockGuard support.
343            BlockGuard.getThreadPolicy().onReadFromDisk();
344            return skip0(n);
345        } catch(UseManualSkipException e) {
346            return super.skip(n);
347        }
348    }
349
350    private native long skip0(long n) throws IOException, UseManualSkipException;
351
352    /*
353     * Used to force manual skip when FileInputStream operates on pipe
354     */
355    private static class UseManualSkipException extends Exception {
356    }
357    // END Android-changed: skip(long) implementation changed from bare native.
358
359    /**
360     * Returns an estimate of the number of remaining bytes that can be read (or
361     * skipped over) from this input stream without blocking by the next
362     * invocation of a method for this input stream. Returns 0 when the file
363     * position is beyond EOF. The next invocation might be the same thread
364     * or another thread. A single read or skip of this many bytes will not
365     * block, but may read or skip fewer bytes.
366     *
367     * <p> In some cases, a non-blocking read (or skip) may appear to be
368     * blocked when it is merely slow, for example when reading large
369     * files over slow networks.
370     *
371     * @return     an estimate of the number of remaining bytes that can be read
372     *             (or skipped over) from this input stream without blocking.
373     * @exception  IOException  if this file input stream has been closed by calling
374     *             {@code close} or an I/O error occurs.
375     */
376    // BEGIN Android-changed: available() implementation changed from bare native.
377    public int available() throws IOException {
378        // Android-added: close() check before I/O.
379        if (closed) {
380            throw new IOException("Stream Closed");
381        }
382
383        return available0();
384    }
385
386    private native int available0() throws IOException;
387    // END Android-changed: available() implementation changed from bare native.
388
389    /**
390     * Closes this file input stream and releases any system resources
391     * associated with the stream.
392     *
393     * <p> If this stream has an associated channel then the channel is closed
394     * as well.
395     *
396     * @exception  IOException  if an I/O error occurs.
397     *
398     * @revised 1.4
399     * @spec JSR-51
400     */
401    public void close() throws IOException {
402        synchronized (closeLock) {
403            if (closed) {
404                return;
405            }
406            closed = true;
407        }
408
409        // Android-added: CloseGuard support.
410        guard.close();
411
412        if (channel != null) {
413           channel.close();
414        }
415
416        // BEGIN Android-changed: Close handling / notification of blocked threads.
417        if (isFdOwner) {
418            IoBridge.closeAndSignalBlockedThreads(fd);
419        }
420        // END Android-changed: Close handling / notification of blocked threads.
421    }
422
423    /**
424     * Returns the <code>FileDescriptor</code>
425     * object  that represents the connection to
426     * the actual file in the file system being
427     * used by this <code>FileInputStream</code>.
428     *
429     * @return     the file descriptor object associated with this stream.
430     * @exception  IOException  if an I/O error occurs.
431     * @see        java.io.FileDescriptor
432     */
433    public final FileDescriptor getFD() throws IOException {
434        if (fd != null) {
435            return fd;
436        }
437        throw new IOException();
438    }
439
440    /**
441     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
442     * object associated with this file input stream.
443     *
444     * <p> The initial {@link java.nio.channels.FileChannel#position()
445     * position} of the returned channel will be equal to the
446     * number of bytes read from the file so far.  Reading bytes from this
447     * stream will increment the channel's position.  Changing the channel's
448     * position, either explicitly or by reading, will change this stream's
449     * file position.
450     *
451     * @return  the file channel associated with this file input stream
452     *
453     * @since 1.4
454     * @spec JSR-51
455     */
456    public FileChannel getChannel() {
457        synchronized (this) {
458            if (channel == null) {
459                channel = FileChannelImpl.open(fd, path, true, false, this);
460            }
461            return channel;
462        }
463    }
464
465    // BEGIN Android-removed: Unused code.
466    /*
467    private static native void initIDs();
468
469    private native void close0() throws IOException;
470
471    static {
472        initIDs();
473    }
474    */
475    // END Android-changed: Unused code.
476
477    /**
478     * Ensures that the <code>close</code> method of this file input stream is
479     * called when there are no more references to it.
480     *
481     * @exception  IOException  if an I/O error occurs.
482     * @see        java.io.FileInputStream#close()
483     */
484    protected void finalize() throws IOException {
485        // Android-added: CloseGuard support.
486        if (guard != null) {
487            guard.warnIfOpen();
488        }
489
490        if ((fd != null) &&  (fd != FileDescriptor.in)) {
491            // Android-removed: Obsoleted comment about shared FileDescriptor handling.
492            close();
493        }
494    }
495}
496