• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.os;
18 import java.io.File;
19 import java.io.FileDescriptor;
20 import java.io.FileInputStream;
21 import java.io.FileNotFoundException;
22 import java.io.FileOutputStream;
23 import java.io.IOException;
24 import java.net.DatagramSocket;
25 import java.net.Socket;
26 
27 /**
28  * The FileDescriptor returned by {@link Parcel#readFileDescriptor}, allowing
29  * you to close it when done with it.
30  */
31 public class ParcelFileDescriptor implements Parcelable {
32     private final FileDescriptor mFileDescriptor;
33     private boolean mClosed;
34     //this field is to create wrapper for ParcelFileDescriptor using another
35     //PartialFileDescriptor but avoid invoking close twice
36     //consider ParcelFileDescriptor A(fileDescriptor fd),  ParcelFileDescriptor B(A)
37     //in this particular case fd.close might be invoked twice.
38     private final ParcelFileDescriptor mParcelDescriptor;
39 
40     /**
41      * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied
42      * and this file doesn't already exist, then create the file with
43      * permissions such that any application can read it.
44      */
45     public static final int MODE_WORLD_READABLE = 0x00000001;
46 
47     /**
48      * For use with {@link #open}: if {@link #MODE_CREATE} has been supplied
49      * and this file doesn't already exist, then create the file with
50      * permissions such that any application can write it.
51      */
52     public static final int MODE_WORLD_WRITEABLE = 0x00000002;
53 
54     /**
55      * For use with {@link #open}: open the file with read-only access.
56      */
57     public static final int MODE_READ_ONLY = 0x10000000;
58 
59     /**
60      * For use with {@link #open}: open the file with write-only access.
61      */
62     public static final int MODE_WRITE_ONLY = 0x20000000;
63 
64     /**
65      * For use with {@link #open}: open the file with read and write access.
66      */
67     public static final int MODE_READ_WRITE = 0x30000000;
68 
69     /**
70      * For use with {@link #open}: create the file if it doesn't already exist.
71      */
72     public static final int MODE_CREATE = 0x08000000;
73 
74     /**
75      * For use with {@link #open}: erase contents of file when opening.
76      */
77     public static final int MODE_TRUNCATE = 0x04000000;
78 
79     /**
80      * For use with {@link #open}: append to end of file while writing.
81      */
82     public static final int MODE_APPEND = 0x02000000;
83 
84     /**
85      * Create a new ParcelFileDescriptor accessing a given file.
86      *
87      * @param file The file to be opened.
88      * @param mode The desired access mode, must be one of
89      * {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
90      * {@link #MODE_READ_WRITE}; may also be any combination of
91      * {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
92      * {@link #MODE_WORLD_READABLE}, and {@link #MODE_WORLD_WRITEABLE}.
93      *
94      * @return Returns a new ParcelFileDescriptor pointing to the given
95      * file.
96      *
97      * @throws FileNotFoundException Throws FileNotFoundException if the given
98      * file does not exist or can not be opened with the requested mode.
99      */
open(File file, int mode)100     public static ParcelFileDescriptor open(File file, int mode)
101             throws FileNotFoundException {
102         String path = file.getPath();
103         SecurityManager security = System.getSecurityManager();
104         if (security != null) {
105             security.checkRead(path);
106             if ((mode&MODE_WRITE_ONLY) != 0) {
107                 security.checkWrite(path);
108             }
109         }
110 
111         if ((mode&MODE_READ_WRITE) == 0) {
112             throw new IllegalArgumentException(
113                     "Must specify MODE_READ_ONLY, MODE_WRITE_ONLY, or MODE_READ_WRITE");
114         }
115 
116         FileDescriptor fd = Parcel.openFileDescriptor(path, mode);
117         return fd != null ? new ParcelFileDescriptor(fd) : null;
118     }
119 
120     /**
121      * Create a new ParcelFileDescriptor that is a dup of an existing
122      * FileDescriptor.  This obeys standard POSIX semantics, where the
123      * new file descriptor shared state such as file position with the
124      * original file descriptor.
125      */
dup(FileDescriptor orig)126     public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
127         FileDescriptor fd = Parcel.dupFileDescriptor(orig);
128         return fd != null ? new ParcelFileDescriptor(fd) : null;
129     }
130 
131     /**
132      * Create a new ParcelFileDescriptor that is a dup of the existing
133      * FileDescriptor.  This obeys standard POSIX semantics, where the
134      * new file descriptor shared state such as file position with the
135      * original file descriptor.
136      */
dup()137     public ParcelFileDescriptor dup() throws IOException {
138         return dup(getFileDescriptor());
139     }
140 
141     /**
142      * Create a new ParcelFileDescriptor from a raw native fd.  The new
143      * ParcelFileDescriptor holds a dup of the original fd passed in here,
144      * so you must still close that fd as well as the new ParcelFileDescriptor.
145      *
146      * @param fd The native fd that the ParcelFileDescriptor should dup.
147      *
148      * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
149      * for a dup of the given fd.
150      */
fromFd(int fd)151     public static ParcelFileDescriptor fromFd(int fd) throws IOException {
152         FileDescriptor fdesc = getFileDescriptorFromFd(fd);
153         return new ParcelFileDescriptor(fdesc);
154     }
155 
156     // Extracts the file descriptor from the specified socket and returns it untouched
getFileDescriptorFromFd(int fd)157     private static native FileDescriptor getFileDescriptorFromFd(int fd) throws IOException;
158 
159     /**
160      * Take ownership of a raw native fd in to a new ParcelFileDescriptor.
161      * The returned ParcelFileDescriptor now owns the given fd, and will be
162      * responsible for closing it.  You must not close the fd yourself.
163      *
164      * @param fd The native fd that the ParcelFileDescriptor should adopt.
165      *
166      * @return Returns a new ParcelFileDescriptor holding a FileDescriptor
167      * for the given fd.
168      */
adoptFd(int fd)169     public static ParcelFileDescriptor adoptFd(int fd) {
170         FileDescriptor fdesc = getFileDescriptorFromFdNoDup(fd);
171         return new ParcelFileDescriptor(fdesc);
172     }
173 
174     // Extracts the file descriptor from the specified socket and returns it untouched
getFileDescriptorFromFdNoDup(int fd)175     private static native FileDescriptor getFileDescriptorFromFdNoDup(int fd);
176 
177     /**
178      * Create a new ParcelFileDescriptor from the specified Socket.  The new
179      * ParcelFileDescriptor holds a dup of the original FileDescriptor in
180      * the Socket, so you must still close the Socket as well as the new
181      * ParcelFileDescriptor.
182      *
183      * @param socket The Socket whose FileDescriptor is used to create
184      *               a new ParcelFileDescriptor.
185      *
186      * @return A new ParcelFileDescriptor with the FileDescriptor of the
187      *         specified Socket.
188      */
fromSocket(Socket socket)189     public static ParcelFileDescriptor fromSocket(Socket socket) {
190         FileDescriptor fd = socket.getFileDescriptor$();
191         return fd != null ? new ParcelFileDescriptor(fd) : null;
192     }
193 
194     /**
195      * Create a new ParcelFileDescriptor from the specified DatagramSocket.
196      *
197      * @param datagramSocket The DatagramSocket whose FileDescriptor is used
198      *               to create a new ParcelFileDescriptor.
199      *
200      * @return A new ParcelFileDescriptor with the FileDescriptor of the
201      *         specified DatagramSocket.
202      */
fromDatagramSocket(DatagramSocket datagramSocket)203     public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) {
204         FileDescriptor fd = datagramSocket.getFileDescriptor$();
205         return fd != null ? new ParcelFileDescriptor(fd) : null;
206     }
207 
208     /**
209      * Create two ParcelFileDescriptors structured as a data pipe.  The first
210      * ParcelFileDescriptor in the returned array is the read side; the second
211      * is the write side.
212      */
createPipe()213     public static ParcelFileDescriptor[] createPipe() throws IOException {
214         FileDescriptor[] fds = new FileDescriptor[2];
215         createPipeNative(fds);
216         ParcelFileDescriptor[] pfds = new ParcelFileDescriptor[2];
217         pfds[0] = new ParcelFileDescriptor(fds[0]);
218         pfds[1] = new ParcelFileDescriptor(fds[1]);
219         return pfds;
220     }
221 
createPipeNative(FileDescriptor[] outFds)222     private static native void createPipeNative(FileDescriptor[] outFds) throws IOException;
223 
224     /**
225      * @hide Please use createPipe() or ContentProvider.openPipeHelper().
226      * Gets a file descriptor for a read-only copy of the given data.
227      *
228      * @param data Data to copy.
229      * @param name Name for the shared memory area that may back the file descriptor.
230      *        This is purely informative and may be {@code null}.
231      * @return A ParcelFileDescriptor.
232      * @throws IOException if there is an error while creating the shared memory area.
233      */
234     @Deprecated
fromData(byte[] data, String name)235     public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException {
236         if (data == null) return null;
237         MemoryFile file = new MemoryFile(name, data.length);
238         if (data.length > 0) {
239             file.writeBytes(data, 0, 0, data.length);
240         }
241         file.deactivate();
242         FileDescriptor fd = file.getFileDescriptor();
243         return fd != null ? new ParcelFileDescriptor(fd) : null;
244     }
245 
246     /**
247      * Retrieve the actual FileDescriptor associated with this object.
248      *
249      * @return Returns the FileDescriptor associated with this object.
250      */
getFileDescriptor()251     public FileDescriptor getFileDescriptor() {
252         return mFileDescriptor;
253     }
254 
255     /**
256      * Return the total size of the file representing this fd, as determined
257      * by stat().  Returns -1 if the fd is not a file.
258      */
getStatSize()259     public native long getStatSize();
260 
261     /**
262      * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
263      * and I really don't think we want it to be public.
264      * @hide
265      */
seekTo(long pos)266     public native long seekTo(long pos);
267 
268     /**
269      * Return the native fd int for this ParcelFileDescriptor.  The
270      * ParcelFileDescriptor still owns the fd, and it still must be closed
271      * through this API.
272      */
getFd()273     public int getFd() {
274         if (mClosed) {
275             throw new IllegalStateException("Already closed");
276         }
277         return getFdNative();
278     }
279 
getFdNative()280     private native int getFdNative();
281 
282     /**
283      * Return the native fd int for this ParcelFileDescriptor and detach it
284      * from the object here.  You are now responsible for closing the fd in
285      * native code.
286      */
detachFd()287     public int detachFd() {
288         if (mClosed) {
289             throw new IllegalStateException("Already closed");
290         }
291         if (mParcelDescriptor != null) {
292             int fd = mParcelDescriptor.detachFd();
293             mClosed = true;
294             return fd;
295         }
296         int fd = getFd();
297         mClosed = true;
298         Parcel.clearFileDescriptor(mFileDescriptor);
299         return fd;
300     }
301 
302     /**
303      * Close the ParcelFileDescriptor. This implementation closes the underlying
304      * OS resources allocated to represent this stream.
305      *
306      * @throws IOException
307      *             If an error occurs attempting to close this ParcelFileDescriptor.
308      */
close()309     public void close() throws IOException {
310         synchronized (this) {
311             if (mClosed) return;
312             mClosed = true;
313         }
314         if (mParcelDescriptor != null) {
315             // If this is a proxy to another file descriptor, just call through to its
316             // close method.
317             mParcelDescriptor.close();
318         } else {
319             Parcel.closeFileDescriptor(mFileDescriptor);
320         }
321     }
322 
323     /**
324      * An InputStream you can create on a ParcelFileDescriptor, which will
325      * take care of calling {@link ParcelFileDescriptor#close
326      * ParcelFileDescriptor.close()} for you when the stream is closed.
327      */
328     public static class AutoCloseInputStream extends FileInputStream {
329         private final ParcelFileDescriptor mFd;
330 
AutoCloseInputStream(ParcelFileDescriptor fd)331         public AutoCloseInputStream(ParcelFileDescriptor fd) {
332             super(fd.getFileDescriptor());
333             mFd = fd;
334         }
335 
336         @Override
close()337         public void close() throws IOException {
338             try {
339                 mFd.close();
340             } finally {
341                 super.close();
342             }
343         }
344     }
345 
346     /**
347      * An OutputStream you can create on a ParcelFileDescriptor, which will
348      * take care of calling {@link ParcelFileDescriptor#close
349      * ParcelFileDescriptor.close()} for you when the stream is closed.
350      */
351     public static class AutoCloseOutputStream extends FileOutputStream {
352         private final ParcelFileDescriptor mFd;
353 
AutoCloseOutputStream(ParcelFileDescriptor fd)354         public AutoCloseOutputStream(ParcelFileDescriptor fd) {
355             super(fd.getFileDescriptor());
356             mFd = fd;
357         }
358 
359         @Override
close()360         public void close() throws IOException {
361             try {
362                 mFd.close();
363             } finally {
364                 super.close();
365             }
366         }
367     }
368 
369     @Override
toString()370     public String toString() {
371         return "{ParcelFileDescriptor: " + mFileDescriptor + "}";
372     }
373 
374     @Override
finalize()375     protected void finalize() throws Throwable {
376         try {
377             if (!mClosed) {
378                 close();
379             }
380         } finally {
381             super.finalize();
382         }
383     }
384 
ParcelFileDescriptor(ParcelFileDescriptor descriptor)385     public ParcelFileDescriptor(ParcelFileDescriptor descriptor) {
386         super();
387         mParcelDescriptor = descriptor;
388         mFileDescriptor = mParcelDescriptor.mFileDescriptor;
389     }
390 
ParcelFileDescriptor(FileDescriptor descriptor)391     /*package */ParcelFileDescriptor(FileDescriptor descriptor) {
392         super();
393         if (descriptor == null) {
394             throw new NullPointerException("descriptor must not be null");
395         }
396         mFileDescriptor = descriptor;
397         mParcelDescriptor = null;
398     }
399 
400     /* Parcelable interface */
describeContents()401     public int describeContents() {
402         return Parcelable.CONTENTS_FILE_DESCRIPTOR;
403     }
404 
405     /**
406      * {@inheritDoc}
407      * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags,
408      * the file descriptor will be closed after a copy is written to the Parcel.
409      */
writeToParcel(Parcel out, int flags)410     public void writeToParcel(Parcel out, int flags) {
411         out.writeFileDescriptor(mFileDescriptor);
412         if ((flags&PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) {
413             try {
414                 close();
415             } catch (IOException e) {
416                 // Empty
417             }
418         }
419     }
420 
421     public static final Parcelable.Creator<ParcelFileDescriptor> CREATOR
422             = new Parcelable.Creator<ParcelFileDescriptor>() {
423         public ParcelFileDescriptor createFromParcel(Parcel in) {
424             return in.readFileDescriptor();
425         }
426         public ParcelFileDescriptor[] newArray(int size) {
427             return new ParcelFileDescriptor[size];
428         }
429     };
430 
431 }
432