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