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