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 SecurityManager security = System.getSecurityManager(); 112 if (security != null) { 113 security.checkRead(path); 114 if ((mode&MODE_WRITE_ONLY) != 0) { 115 security.checkWrite(path); 116 } 117 } 118 119 if ((mode&MODE_READ_WRITE) == 0) { 120 throw new IllegalArgumentException( 121 "Must specify MODE_READ_ONLY, MODE_WRITE_ONLY, or MODE_READ_WRITE"); 122 } 123 124 FileDescriptor fd = Parcel.openFileDescriptor(path, mode); 125 return fd != null ? new ParcelFileDescriptor(fd) : null; 126 } 127 128 /** 129 * Create a new ParcelFileDescriptor that is a dup of an existing 130 * FileDescriptor. This obeys standard POSIX semantics, where the 131 * new file descriptor shared state such as file position with the 132 * original file descriptor. 133 */ 134 public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException { 135 FileDescriptor fd = Parcel.dupFileDescriptor(orig); 136 return fd != null ? new ParcelFileDescriptor(fd) : null; 137 } 138 139 /** 140 * Create a new ParcelFileDescriptor that is a dup of the existing 141 * FileDescriptor. This obeys standard POSIX semantics, where the 142 * new file descriptor shared state such as file position with the 143 * original file descriptor. 144 */ 145 public ParcelFileDescriptor dup() throws IOException { 146 return dup(getFileDescriptor()); 147 } 148 149 /** 150 * Create a new ParcelFileDescriptor from a raw native fd. The new 151 * ParcelFileDescriptor holds a dup of the original fd passed in here, 152 * so you must still close that fd as well as the new ParcelFileDescriptor. 153 * 154 * @param fd The native fd that the ParcelFileDescriptor should dup. 155 * 156 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor 157 * for a dup of the given fd. 158 */ 159 public static ParcelFileDescriptor fromFd(int fd) throws IOException { 160 FileDescriptor fdesc = getFileDescriptorFromFd(fd); 161 return new ParcelFileDescriptor(fdesc); 162 } 163 164 // Extracts the file descriptor from the specified socket and returns it untouched 165 private static native FileDescriptor getFileDescriptorFromFd(int fd) throws IOException; 166 167 /** 168 * Take ownership of a raw native fd in to a new ParcelFileDescriptor. 169 * The returned ParcelFileDescriptor now owns the given fd, and will be 170 * responsible for closing it. You must not close the fd yourself. 171 * 172 * @param fd The native fd that the ParcelFileDescriptor should adopt. 173 * 174 * @return Returns a new ParcelFileDescriptor holding a FileDescriptor 175 * for the given fd. 176 */ 177 public static ParcelFileDescriptor adoptFd(int fd) { 178 FileDescriptor fdesc = getFileDescriptorFromFdNoDup(fd); 179 return new ParcelFileDescriptor(fdesc); 180 } 181 182 // Extracts the file descriptor from the specified socket and returns it untouched 183 private static native FileDescriptor getFileDescriptorFromFdNoDup(int fd); 184 185 /** 186 * Create a new ParcelFileDescriptor from the specified Socket. The new 187 * ParcelFileDescriptor holds a dup of the original FileDescriptor in 188 * the Socket, so you must still close the Socket as well as the new 189 * ParcelFileDescriptor. 190 * 191 * @param socket The Socket whose FileDescriptor is used to create 192 * a new ParcelFileDescriptor. 193 * 194 * @return A new ParcelFileDescriptor with the FileDescriptor of the 195 * specified Socket. 196 */ 197 public static ParcelFileDescriptor fromSocket(Socket socket) { 198 FileDescriptor fd = socket.getFileDescriptor$(); 199 return fd != null ? new ParcelFileDescriptor(fd) : null; 200 } 201 202 /** 203 * Create a new ParcelFileDescriptor from the specified DatagramSocket. 204 * 205 * @param datagramSocket The DatagramSocket whose FileDescriptor is used 206 * to create a new ParcelFileDescriptor. 207 * 208 * @return A new ParcelFileDescriptor with the FileDescriptor of the 209 * specified DatagramSocket. 210 */ 211 public static ParcelFileDescriptor fromDatagramSocket(DatagramSocket datagramSocket) { 212 FileDescriptor fd = datagramSocket.getFileDescriptor$(); 213 return fd != null ? new ParcelFileDescriptor(fd) : null; 214 } 215 216 /** 217 * Create two ParcelFileDescriptors structured as a data pipe. The first 218 * ParcelFileDescriptor in the returned array is the read side; the second 219 * is the write side. 220 */ 221 public static ParcelFileDescriptor[] createPipe() throws IOException { 222 FileDescriptor[] fds = new FileDescriptor[2]; 223 createPipeNative(fds); 224 ParcelFileDescriptor[] pfds = new ParcelFileDescriptor[2]; 225 pfds[0] = new ParcelFileDescriptor(fds[0]); 226 pfds[1] = new ParcelFileDescriptor(fds[1]); 227 return pfds; 228 } 229 230 private static native void createPipeNative(FileDescriptor[] outFds) throws IOException; 231 232 /** 233 * @hide Please use createPipe() or ContentProvider.openPipeHelper(). 234 * Gets a file descriptor for a read-only copy of the given data. 235 * 236 * @param data Data to copy. 237 * @param name Name for the shared memory area that may back the file descriptor. 238 * This is purely informative and may be {@code null}. 239 * @return A ParcelFileDescriptor. 240 * @throws IOException if there is an error while creating the shared memory area. 241 */ 242 @Deprecated 243 public static ParcelFileDescriptor fromData(byte[] data, String name) throws IOException { 244 if (data == null) return null; 245 MemoryFile file = new MemoryFile(name, data.length); 246 if (data.length > 0) { 247 file.writeBytes(data, 0, 0, data.length); 248 } 249 file.deactivate(); 250 FileDescriptor fd = file.getFileDescriptor(); 251 return fd != null ? new ParcelFileDescriptor(fd) : null; 252 } 253 254 /** 255 * Retrieve the actual FileDescriptor associated with this object. 256 * 257 * @return Returns the FileDescriptor associated with this object. 258 */ 259 public FileDescriptor getFileDescriptor() { 260 return mFileDescriptor; 261 } 262 263 /** 264 * Return the total size of the file representing this fd, as determined 265 * by stat(). Returns -1 if the fd is not a file. 266 */ 267 public native long getStatSize(); 268 269 /** 270 * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream, 271 * and I really don't think we want it to be public. 272 * @hide 273 */ 274 public native long seekTo(long pos); 275 276 /** 277 * Return the native fd int for this ParcelFileDescriptor. The 278 * ParcelFileDescriptor still owns the fd, and it still must be closed 279 * through this API. 280 */ 281 public int getFd() { 282 if (mClosed) { 283 throw new IllegalStateException("Already closed"); 284 } 285 return getFdNative(); 286 } 287 288 private native int getFdNative(); 289 290 /** 291 * Return the native fd int for this ParcelFileDescriptor and detach it 292 * from the object here. You are now responsible for closing the fd in 293 * native code. 294 */ 295 public int detachFd() { 296 if (mClosed) { 297 throw new IllegalStateException("Already closed"); 298 } 299 if (mWrapped != null) { 300 int fd = mWrapped.detachFd(); 301 mClosed = true; 302 mGuard.close(); 303 return fd; 304 } 305 int fd = getFd(); 306 mClosed = true; 307 mGuard.close(); 308 Parcel.clearFileDescriptor(mFileDescriptor); 309 return fd; 310 } 311 312 /** 313 * Close the ParcelFileDescriptor. This implementation closes the underlying 314 * OS resources allocated to represent this stream. 315 * 316 * @throws IOException 317 * If an error occurs attempting to close this ParcelFileDescriptor. 318 */ 319 @Override 320 public void close() throws IOException { 321 if (mClosed) return; 322 mClosed = true; 323 mGuard.close(); 324 325 if (mWrapped != null) { 326 // If this is a proxy to another file descriptor, just call through to its 327 // close method. 328 mWrapped.close(); 329 } else { 330 Parcel.closeFileDescriptor(mFileDescriptor); 331 } 332 } 333 334 /** 335 * An InputStream you can create on a ParcelFileDescriptor, which will 336 * take care of calling {@link ParcelFileDescriptor#close 337 * ParcelFileDescriptor.close()} for you when the stream is closed. 338 */ 339 public static class AutoCloseInputStream extends FileInputStream { 340 private final ParcelFileDescriptor mFd; 341 342 public AutoCloseInputStream(ParcelFileDescriptor fd) { 343 super(fd.getFileDescriptor()); 344 mFd = fd; 345 } 346 347 @Override 348 public void close() throws IOException { 349 try { 350 mFd.close(); 351 } finally { 352 super.close(); 353 } 354 } 355 } 356 357 /** 358 * An OutputStream you can create on a ParcelFileDescriptor, which will 359 * take care of calling {@link ParcelFileDescriptor#close 360 * ParcelFileDescriptor.close()} for you when the stream is closed. 361 */ 362 public static class AutoCloseOutputStream extends FileOutputStream { 363 private final ParcelFileDescriptor mFd; 364 365 public AutoCloseOutputStream(ParcelFileDescriptor fd) { 366 super(fd.getFileDescriptor()); 367 mFd = fd; 368 } 369 370 @Override 371 public void close() throws IOException { 372 try { 373 mFd.close(); 374 } finally { 375 super.close(); 376 } 377 } 378 } 379 380 @Override 381 public String toString() { 382 return "{ParcelFileDescriptor: " + mFileDescriptor + "}"; 383 } 384 385 @Override 386 protected void finalize() throws Throwable { 387 if (mGuard != null) { 388 mGuard.warnIfOpen(); 389 } 390 try { 391 if (!mClosed) { 392 close(); 393 } 394 } finally { 395 super.finalize(); 396 } 397 } 398 399 public ParcelFileDescriptor(ParcelFileDescriptor descriptor) { 400 mWrapped = descriptor; 401 mFileDescriptor = mWrapped.mFileDescriptor; 402 mGuard.open("close"); 403 } 404 405 /** {@hide} */ 406 public ParcelFileDescriptor(FileDescriptor descriptor) { 407 if (descriptor == null) { 408 throw new NullPointerException("descriptor must not be null"); 409 } 410 mWrapped = null; 411 mFileDescriptor = descriptor; 412 mGuard.open("close"); 413 } 414 415 @Override 416 public int describeContents() { 417 return Parcelable.CONTENTS_FILE_DESCRIPTOR; 418 } 419 420 /** 421 * {@inheritDoc} 422 * If {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set in flags, 423 * the file descriptor will be closed after a copy is written to the Parcel. 424 */ 425 @Override 426 public void writeToParcel(Parcel out, int flags) { 427 out.writeFileDescriptor(mFileDescriptor); 428 if ((flags&PARCELABLE_WRITE_RETURN_VALUE) != 0 && !mClosed) { 429 try { 430 close(); 431 } catch (IOException e) { 432 // Empty 433 } 434 } 435 } 436 437 public static final Parcelable.Creator<ParcelFileDescriptor> CREATOR 438 = new Parcelable.Creator<ParcelFileDescriptor>() { 439 @Override 440 public ParcelFileDescriptor createFromParcel(Parcel in) { 441 return in.readFileDescriptor(); 442 } 443 444 @Override 445 public ParcelFileDescriptor[] newArray(int size) { 446 return new ParcelFileDescriptor[size]; 447 } 448 }; 449} 450