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