1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * Copyright (c) 2000, 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 sun.nio.ch; 28 29 import android.system.ErrnoException; 30 31 import java.io.FileDescriptor; 32 import java.io.IOException; 33 import java.nio.ByteBuffer; 34 import java.nio.DirectByteBuffer; 35 import java.nio.MappedByteBuffer; 36 import java.nio.channels.ClosedByInterruptException; 37 import java.nio.channels.ClosedChannelException; 38 import java.nio.channels.FileChannel; 39 import java.nio.channels.FileLock; 40 import java.nio.channels.FileLockInterruptionException; 41 import java.nio.channels.NonReadableChannelException; 42 import java.nio.channels.NonWritableChannelException; 43 import java.nio.channels.OverlappingFileLockException; 44 import java.nio.channels.ReadableByteChannel; 45 import java.nio.channels.SelectableChannel; 46 import java.nio.channels.WritableByteChannel; 47 import java.security.AccessController; 48 import java.util.ArrayList; 49 import java.util.List; 50 import libcore.io.Libcore; 51 52 import dalvik.annotation.optimization.ReachabilitySensitive; 53 import dalvik.system.BlockGuard; 54 import dalvik.system.CloseGuard; 55 56 import jdk.internal.access.JavaIOFileDescriptorAccess; 57 import jdk.internal.access.SharedSecrets; 58 import sun.misc.Cleaner; 59 import sun.security.action.GetPropertyAction; 60 61 public class FileChannelImpl 62 extends FileChannel 63 { 64 // Access to FileDescriptor internals 65 private static final JavaIOFileDescriptorAccess fdAccess = 66 SharedSecrets.getJavaIOFileDescriptorAccess(); 67 68 // Memory allocation size for mapping buffers 69 private static final long allocationGranularity; 70 71 // Used to make native read and write calls 72 private final FileDispatcher nd; 73 74 // File descriptor 75 // Android-added: @ReachabilitySensitive 76 // If this were reclaimed while we're in an operation on fd, the associated Stream 77 // could be finalized, closing the fd while still in use. This is not the case upstream, 78 // since there the Stream is accessible from the FileDescriptor. 79 // Android-changed: make public. Used by NioUtils.getFD(), and possibly others. 80 @ReachabilitySensitive 81 public final FileDescriptor fd; 82 83 // File access mode (immutable) 84 private final boolean writable; 85 private final boolean readable; 86 87 // Required to prevent finalization of creating stream (immutable) 88 private final Object parent; 89 90 // The path of the referenced file 91 // (null if the parent stream is created with a file descriptor) 92 private final String path; 93 94 // Thread-safe set of IDs of native threads, for signalling 95 private final NativeThreadSet threads = new NativeThreadSet(2); 96 97 // Lock for operations involving position and size 98 private final Object positionLock = new Object(); 99 100 // Android-added: CloseGuard support. 101 @ReachabilitySensitive 102 private final CloseGuard guard = CloseGuard.get(); 103 FileChannelImpl(FileDescriptor fd, String path, boolean readable, boolean writable, Object parent)104 private FileChannelImpl(FileDescriptor fd, String path, boolean readable, 105 boolean writable, Object parent) 106 { 107 this.fd = fd; 108 this.readable = readable; 109 this.writable = writable; 110 this.parent = parent; 111 this.path = path; 112 this.nd = new FileDispatcherImpl(); 113 // BEGIN Android-added: CloseGuard support. 114 if (fd != null && fd.valid()) { 115 guard.open("close"); 116 } 117 // END Android-added: CloseGuard support. 118 } 119 120 // Used by FileInputStream.getChannel() and RandomAccessFile.getChannel() open(FileDescriptor fd, String path, boolean readable, boolean writable, Object parent)121 public static FileChannel open(FileDescriptor fd, String path, 122 boolean readable, boolean writable, 123 Object parent) 124 { 125 return new FileChannelImpl(fd, path, readable, writable, parent); 126 } 127 ensureOpen()128 private void ensureOpen() throws IOException { 129 if (!isOpen()) 130 throw new ClosedChannelException(); 131 } 132 133 134 // -- Standard channel operations -- 135 implCloseChannel()136 protected void implCloseChannel() throws IOException { 137 // Android-added: CloseGuard support. 138 guard.close(); 139 // Release and invalidate any locks that we still hold 140 if (fileLockTable != null) { 141 for (FileLock fl: fileLockTable.removeAll()) { 142 synchronized (fl) { 143 if (fl.isValid()) { 144 nd.release(fd, fl.position(), fl.size()); 145 ((FileLockImpl)fl).invalidate(); 146 } 147 } 148 } 149 } 150 151 // signal any threads blocked on this channel 152 threads.signalAndWait(); 153 154 if (parent != null) { 155 156 // Close the fd via the parent stream's close method. The parent 157 // will reinvoke our close method, which is defined in the 158 // superclass AbstractInterruptibleChannel, but the isOpen logic in 159 // that method will prevent this method from being reinvoked. 160 // 161 ((java.io.Closeable)parent).close(); 162 } else { 163 nd.close(fd); 164 } 165 166 } 167 168 // BEGIN Android-added: CloseGuard support. finalize()169 protected void finalize() throws Throwable { 170 try { 171 if (guard != null) { 172 guard.warnIfOpen(); 173 } 174 close(); 175 } finally { 176 super.finalize(); 177 } 178 } 179 // END Android-added: CloseGuard support. 180 read(ByteBuffer dst)181 public int read(ByteBuffer dst) throws IOException { 182 ensureOpen(); 183 if (!readable) 184 throw new NonReadableChannelException(); 185 synchronized (positionLock) { 186 int n = 0; 187 int ti = -1; 188 try { 189 begin(); 190 ti = threads.add(); 191 if (!isOpen()) 192 return 0; 193 do { 194 n = IOUtil.read(fd, dst, -1, nd); 195 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 196 return IOStatus.normalize(n); 197 } finally { 198 threads.remove(ti); 199 end(n > 0); 200 assert IOStatus.check(n); 201 } 202 } 203 } 204 read(ByteBuffer[] dsts, int offset, int length)205 public long read(ByteBuffer[] dsts, int offset, int length) 206 throws IOException 207 { 208 if ((offset < 0) || (length < 0) || (offset > dsts.length - length)) 209 throw new IndexOutOfBoundsException(); 210 ensureOpen(); 211 if (!readable) 212 throw new NonReadableChannelException(); 213 synchronized (positionLock) { 214 long n = 0; 215 int ti = -1; 216 try { 217 begin(); 218 ti = threads.add(); 219 if (!isOpen()) 220 return 0; 221 do { 222 n = IOUtil.read(fd, dsts, offset, length, nd); 223 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 224 return IOStatus.normalize(n); 225 } finally { 226 threads.remove(ti); 227 end(n > 0); 228 assert IOStatus.check(n); 229 } 230 } 231 } 232 write(ByteBuffer src)233 public int write(ByteBuffer src) throws IOException { 234 ensureOpen(); 235 if (!writable) 236 throw new NonWritableChannelException(); 237 synchronized (positionLock) { 238 int n = 0; 239 int ti = -1; 240 try { 241 begin(); 242 ti = threads.add(); 243 if (!isOpen()) 244 return 0; 245 do { 246 n = IOUtil.write(fd, src, -1, nd); 247 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 248 return IOStatus.normalize(n); 249 } finally { 250 threads.remove(ti); 251 end(n > 0); 252 assert IOStatus.check(n); 253 } 254 } 255 } 256 write(ByteBuffer[] srcs, int offset, int length)257 public long write(ByteBuffer[] srcs, int offset, int length) 258 throws IOException 259 { 260 if ((offset < 0) || (length < 0) || (offset > srcs.length - length)) 261 throw new IndexOutOfBoundsException(); 262 ensureOpen(); 263 if (!writable) 264 throw new NonWritableChannelException(); 265 synchronized (positionLock) { 266 long n = 0; 267 int ti = -1; 268 try { 269 begin(); 270 ti = threads.add(); 271 if (!isOpen()) 272 return 0; 273 do { 274 n = IOUtil.write(fd, srcs, offset, length, nd); 275 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 276 return IOStatus.normalize(n); 277 } finally { 278 threads.remove(ti); 279 end(n > 0); 280 assert IOStatus.check(n); 281 } 282 } 283 } 284 285 // -- Other operations -- 286 position()287 public long position() throws IOException { 288 ensureOpen(); 289 synchronized (positionLock) { 290 long p = -1; 291 int ti = -1; 292 try { 293 begin(); 294 ti = threads.add(); 295 if (!isOpen()) 296 return 0; 297 boolean append = fdAccess.getAppend(fd); 298 // BEGIN Android-added: BlockGuard support. 299 // Note: position() itself doesn't seem to block, so this may be overzealous 300 // when position() is not followed by a read/write operation. http://b/77263638 301 if (append) { 302 BlockGuard.getThreadPolicy().onWriteToDisk(); 303 } 304 // END Android-added: BlockGuard support. 305 do { 306 // in append-mode then position is advanced to end before writing 307 p = (append) ? nd.size(fd) : position0(fd, -1); 308 } while ((p == IOStatus.INTERRUPTED) && isOpen()); 309 return IOStatus.normalize(p); 310 } finally { 311 threads.remove(ti); 312 end(p > -1); 313 assert IOStatus.check(p); 314 } 315 } 316 } 317 position(long newPosition)318 public FileChannel position(long newPosition) throws IOException { 319 ensureOpen(); 320 if (newPosition < 0) 321 throw new IllegalArgumentException(); 322 synchronized (positionLock) { 323 long p = -1; 324 int ti = -1; 325 try { 326 begin(); 327 ti = threads.add(); 328 if (!isOpen()) 329 return null; 330 // Android-added: BlockGuard support. 331 // Note: position() itself doesn't seem to block, so this may be overzealous 332 // when position() is not followed by a read/write operation. http://b/77263638 333 BlockGuard.getThreadPolicy().onReadFromDisk(); 334 do { 335 p = position0(fd, newPosition); 336 } while ((p == IOStatus.INTERRUPTED) && isOpen()); 337 return this; 338 } finally { 339 threads.remove(ti); 340 end(p > -1); 341 assert IOStatus.check(p); 342 } 343 } 344 } 345 size()346 public long size() throws IOException { 347 ensureOpen(); 348 synchronized (positionLock) { 349 long s = -1; 350 int ti = -1; 351 try { 352 begin(); 353 ti = threads.add(); 354 if (!isOpen()) 355 return -1; 356 do { 357 s = nd.size(fd); 358 } while ((s == IOStatus.INTERRUPTED) && isOpen()); 359 return IOStatus.normalize(s); 360 } finally { 361 threads.remove(ti); 362 end(s > -1); 363 assert IOStatus.check(s); 364 } 365 } 366 } 367 truncate(long newSize)368 public FileChannel truncate(long newSize) throws IOException { 369 ensureOpen(); 370 if (newSize < 0) 371 throw new IllegalArgumentException("Negative size"); 372 if (!writable) 373 throw new NonWritableChannelException(); 374 synchronized (positionLock) { 375 int rv = -1; 376 long p = -1; 377 int ti = -1; 378 long rp = -1; 379 try { 380 begin(); 381 ti = threads.add(); 382 if (!isOpen()) 383 return null; 384 385 // get current size 386 long size; 387 do { 388 size = nd.size(fd); 389 } while ((size == IOStatus.INTERRUPTED) && isOpen()); 390 if (!isOpen()) 391 return null; 392 393 // get current position 394 do { 395 p = position0(fd, -1); 396 } while ((p == IOStatus.INTERRUPTED) && isOpen()); 397 if (!isOpen()) 398 return null; 399 assert p >= 0; 400 401 // truncate file if given size is less than the current size 402 if (newSize < size) { 403 do { 404 rv = nd.truncate(fd, newSize); 405 } while ((rv == IOStatus.INTERRUPTED) && isOpen()); 406 if (!isOpen()) 407 return null; 408 } 409 410 // if position is beyond new size then adjust it 411 if (p > newSize) 412 p = newSize; 413 do { 414 rp = position0(fd, p); 415 } while ((rp == IOStatus.INTERRUPTED) && isOpen()); 416 return this; 417 } finally { 418 threads.remove(ti); 419 end(rv > -1); 420 assert IOStatus.check(rv); 421 } 422 } 423 } 424 force(boolean metaData)425 public void force(boolean metaData) throws IOException { 426 ensureOpen(); 427 int rv = -1; 428 int ti = -1; 429 try { 430 begin(); 431 ti = threads.add(); 432 if (!isOpen()) 433 return; 434 do { 435 rv = nd.force(fd, metaData); 436 } while ((rv == IOStatus.INTERRUPTED) && isOpen()); 437 } finally { 438 threads.remove(ti); 439 end(rv > -1); 440 assert IOStatus.check(rv); 441 } 442 } 443 444 // Assume at first that the underlying kernel supports sendfile(); 445 // set this to false if we find out later that it doesn't 446 // 447 private static volatile boolean transferSupported = true; 448 449 // Assume that the underlying kernel sendfile() will work if the target 450 // fd is a pipe; set this to false if we find out later that it doesn't 451 // 452 private static volatile boolean pipeSupported = true; 453 454 // Assume that the underlying kernel sendfile() will work if the target 455 // fd is a file; set this to false if we find out later that it doesn't 456 // 457 private static volatile boolean fileSupported = true; 458 transferToDirectlyInternal(long position, int icount, WritableByteChannel target, FileDescriptor targetFD)459 private long transferToDirectlyInternal(long position, int icount, 460 WritableByteChannel target, 461 FileDescriptor targetFD) 462 throws IOException 463 { 464 assert !nd.transferToDirectlyNeedsPositionLock() || 465 Thread.holdsLock(positionLock); 466 467 long n = -1; 468 int ti = -1; 469 try { 470 begin(); 471 ti = threads.add(); 472 if (!isOpen()) 473 return -1; 474 // Android-added: BlockGuard support. 475 BlockGuard.getThreadPolicy().onWriteToDisk(); 476 do { 477 n = transferTo0(fd, position, icount, targetFD); 478 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 479 if (n == IOStatus.UNSUPPORTED_CASE) { 480 if (target instanceof SinkChannelImpl) 481 pipeSupported = false; 482 if (target instanceof FileChannelImpl) 483 fileSupported = false; 484 return IOStatus.UNSUPPORTED_CASE; 485 } 486 if (n == IOStatus.UNSUPPORTED) { 487 // Don't bother trying again 488 transferSupported = false; 489 return IOStatus.UNSUPPORTED; 490 } 491 return IOStatus.normalize(n); 492 } finally { 493 threads.remove(ti); 494 end (n > -1); 495 } 496 } 497 transferToDirectly(long position, int icount, WritableByteChannel target)498 private long transferToDirectly(long position, int icount, 499 WritableByteChannel target) 500 throws IOException 501 { 502 if (!transferSupported) 503 return IOStatus.UNSUPPORTED; 504 505 FileDescriptor targetFD = null; 506 if (target instanceof FileChannelImpl) { 507 if (!fileSupported) 508 return IOStatus.UNSUPPORTED_CASE; 509 targetFD = ((FileChannelImpl)target).fd; 510 } else if (target instanceof SelChImpl) { 511 // Direct transfer to pipe causes EINVAL on some configurations 512 if ((target instanceof SinkChannelImpl) && !pipeSupported) 513 return IOStatus.UNSUPPORTED_CASE; 514 515 // Platform-specific restrictions. Now there is only one: 516 // Direct transfer to non-blocking channel could be forbidden 517 SelectableChannel sc = (SelectableChannel)target; 518 if (!nd.canTransferToDirectly(sc)) 519 return IOStatus.UNSUPPORTED_CASE; 520 521 targetFD = ((SelChImpl)target).getFD(); 522 } 523 524 if (targetFD == null) 525 return IOStatus.UNSUPPORTED; 526 int thisFDVal = IOUtil.fdVal(fd); 527 int targetFDVal = IOUtil.fdVal(targetFD); 528 if (thisFDVal == targetFDVal) // Not supported on some configurations 529 return IOStatus.UNSUPPORTED; 530 531 if (nd.transferToDirectlyNeedsPositionLock()) { 532 synchronized (positionLock) { 533 long pos = position(); 534 try { 535 return transferToDirectlyInternal(position, icount, 536 target, targetFD); 537 } finally { 538 position(pos); 539 } 540 } 541 } else { 542 return transferToDirectlyInternal(position, icount, target, targetFD); 543 } 544 } 545 546 // Maximum size to map when using a mapped buffer 547 private static final long MAPPED_TRANSFER_SIZE = 8L*1024L*1024L; 548 transferToTrustedChannel(long position, long count, WritableByteChannel target)549 private long transferToTrustedChannel(long position, long count, 550 WritableByteChannel target) 551 throws IOException 552 { 553 boolean isSelChImpl = (target instanceof SelChImpl); 554 if (!((target instanceof FileChannelImpl) || isSelChImpl)) 555 return IOStatus.UNSUPPORTED; 556 557 // Trusted target: Use a mapped buffer 558 long remaining = count; 559 while (remaining > 0L) { 560 long size = Math.min(remaining, MAPPED_TRANSFER_SIZE); 561 try { 562 MappedByteBuffer dbb = map(MapMode.READ_ONLY, position, size); 563 try { 564 // ## Bug: Closing this channel will not terminate the write 565 int n = target.write(dbb); 566 assert n >= 0; 567 remaining -= n; 568 if (isSelChImpl) { 569 // one attempt to write to selectable channel 570 break; 571 } 572 assert n > 0; 573 position += n; 574 } finally { 575 unmap(dbb); 576 } 577 } catch (ClosedByInterruptException e) { 578 // target closed by interrupt as ClosedByInterruptException needs 579 // to be thrown after closing this channel. 580 assert !target.isOpen(); 581 try { 582 close(); 583 } catch (Throwable suppressed) { 584 e.addSuppressed(suppressed); 585 } 586 throw e; 587 } catch (IOException ioe) { 588 // Only throw exception if no bytes have been written 589 if (remaining == count) 590 throw ioe; 591 break; 592 } 593 } 594 return count - remaining; 595 } 596 transferToArbitraryChannel(long position, int icount, WritableByteChannel target)597 private long transferToArbitraryChannel(long position, int icount, 598 WritableByteChannel target) 599 throws IOException 600 { 601 // Untrusted target: Use a newly-erased buffer 602 int c = Math.min(icount, TRANSFER_SIZE); 603 ByteBuffer bb = Util.getTemporaryDirectBuffer(c); 604 long tw = 0; // Total bytes written 605 long pos = position; 606 try { 607 Util.erase(bb); 608 while (tw < icount) { 609 bb.limit(Math.min((int)(icount - tw), TRANSFER_SIZE)); 610 int nr = read(bb, pos); 611 if (nr <= 0) 612 break; 613 bb.flip(); 614 // ## Bug: Will block writing target if this channel 615 // ## is asynchronously closed 616 int nw = target.write(bb); 617 tw += nw; 618 if (nw != nr) 619 break; 620 pos += nw; 621 bb.clear(); 622 } 623 return tw; 624 } catch (IOException x) { 625 if (tw > 0) 626 return tw; 627 throw x; 628 } finally { 629 Util.releaseTemporaryDirectBuffer(bb); 630 } 631 } 632 transferTo(long position, long count, WritableByteChannel target)633 public long transferTo(long position, long count, 634 WritableByteChannel target) 635 throws IOException 636 { 637 ensureOpen(); 638 if (!target.isOpen()) 639 throw new ClosedChannelException(); 640 if (!readable) 641 throw new NonReadableChannelException(); 642 if (target instanceof FileChannelImpl && 643 !((FileChannelImpl)target).writable) 644 throw new NonWritableChannelException(); 645 if ((position < 0) || (count < 0)) 646 throw new IllegalArgumentException(); 647 long sz = size(); 648 if (position > sz) 649 return 0; 650 int icount = (int)Math.min(count, Integer.MAX_VALUE); 651 if ((sz - position) < icount) 652 icount = (int)(sz - position); 653 654 long n; 655 656 // Attempt a direct transfer, if the kernel supports it 657 if ((n = transferToDirectly(position, icount, target)) >= 0) 658 return n; 659 660 // Attempt a mapped transfer, but only to trusted channel types 661 if ((n = transferToTrustedChannel(position, icount, target)) >= 0) 662 return n; 663 664 // Slow path for untrusted targets 665 return transferToArbitraryChannel(position, icount, target); 666 } 667 transferFromFileChannel(FileChannelImpl src, long position, long count)668 private long transferFromFileChannel(FileChannelImpl src, 669 long position, long count) 670 throws IOException 671 { 672 if (!src.readable) 673 throw new NonReadableChannelException(); 674 synchronized (src.positionLock) { 675 long pos = src.position(); 676 long max = Math.min(count, src.size() - pos); 677 678 long remaining = max; 679 long p = pos; 680 while (remaining > 0L) { 681 long size = Math.min(remaining, MAPPED_TRANSFER_SIZE); 682 // ## Bug: Closing this channel will not terminate the write 683 MappedByteBuffer bb = src.map(MapMode.READ_ONLY, p, size); 684 try { 685 long n = write(bb, position); 686 assert n > 0; 687 p += n; 688 position += n; 689 remaining -= n; 690 } catch (IOException ioe) { 691 // Only throw exception if no bytes have been written 692 if (remaining == max) 693 throw ioe; 694 break; 695 } finally { 696 unmap(bb); 697 } 698 } 699 long nwritten = max - remaining; 700 src.position(pos + nwritten); 701 return nwritten; 702 } 703 } 704 705 private static final int TRANSFER_SIZE = 8192; 706 transferFromArbitraryChannel(ReadableByteChannel src, long position, long count)707 private long transferFromArbitraryChannel(ReadableByteChannel src, 708 long position, long count) 709 throws IOException 710 { 711 // Untrusted target: Use a newly-erased buffer 712 int c = (int)Math.min(count, TRANSFER_SIZE); 713 ByteBuffer bb = Util.getTemporaryDirectBuffer(c); 714 long tw = 0; // Total bytes written 715 long pos = position; 716 try { 717 Util.erase(bb); 718 while (tw < count) { 719 bb.limit((int)Math.min((count - tw), (long)TRANSFER_SIZE)); 720 // ## Bug: Will block reading src if this channel 721 // ## is asynchronously closed 722 int nr = src.read(bb); 723 if (nr <= 0) 724 break; 725 bb.flip(); 726 int nw = write(bb, pos); 727 tw += nw; 728 if (nw != nr) 729 break; 730 pos += nw; 731 bb.clear(); 732 } 733 return tw; 734 } catch (IOException x) { 735 if (tw > 0) 736 return tw; 737 throw x; 738 } finally { 739 Util.releaseTemporaryDirectBuffer(bb); 740 } 741 } 742 transferFrom(ReadableByteChannel src, long position, long count)743 public long transferFrom(ReadableByteChannel src, 744 long position, long count) 745 throws IOException 746 { 747 ensureOpen(); 748 if (!src.isOpen()) 749 throw new ClosedChannelException(); 750 if (!writable) 751 throw new NonWritableChannelException(); 752 if ((position < 0) || (count < 0)) 753 throw new IllegalArgumentException(); 754 if (position > size()) 755 return 0; 756 if (src instanceof FileChannelImpl) 757 return transferFromFileChannel((FileChannelImpl)src, 758 position, count); 759 760 return transferFromArbitraryChannel(src, position, count); 761 } 762 read(ByteBuffer dst, long position)763 public int read(ByteBuffer dst, long position) throws IOException { 764 if (dst == null) 765 throw new NullPointerException(); 766 if (position < 0) 767 throw new IllegalArgumentException("Negative position"); 768 if (!readable) 769 throw new NonReadableChannelException(); 770 ensureOpen(); 771 if (nd.needsPositionLock()) { 772 synchronized (positionLock) { 773 return readInternal(dst, position); 774 } 775 } else { 776 return readInternal(dst, position); 777 } 778 } 779 readInternal(ByteBuffer dst, long position)780 private int readInternal(ByteBuffer dst, long position) throws IOException { 781 assert !nd.needsPositionLock() || Thread.holdsLock(positionLock); 782 int n = 0; 783 int ti = -1; 784 try { 785 begin(); 786 ti = threads.add(); 787 if (!isOpen()) 788 return -1; 789 do { 790 n = IOUtil.read(fd, dst, position, nd); 791 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 792 return IOStatus.normalize(n); 793 } finally { 794 threads.remove(ti); 795 end(n > 0); 796 assert IOStatus.check(n); 797 } 798 } 799 write(ByteBuffer src, long position)800 public int write(ByteBuffer src, long position) throws IOException { 801 if (src == null) 802 throw new NullPointerException(); 803 if (position < 0) 804 throw new IllegalArgumentException("Negative position"); 805 if (!writable) 806 throw new NonWritableChannelException(); 807 ensureOpen(); 808 if (nd.needsPositionLock()) { 809 synchronized (positionLock) { 810 return writeInternal(src, position); 811 } 812 } else { 813 return writeInternal(src, position); 814 } 815 } 816 writeInternal(ByteBuffer src, long position)817 private int writeInternal(ByteBuffer src, long position) throws IOException { 818 assert !nd.needsPositionLock() || Thread.holdsLock(positionLock); 819 int n = 0; 820 int ti = -1; 821 try { 822 begin(); 823 ti = threads.add(); 824 if (!isOpen()) 825 return -1; 826 do { 827 n = IOUtil.write(fd, src, position, nd); 828 } while ((n == IOStatus.INTERRUPTED) && isOpen()); 829 return IOStatus.normalize(n); 830 } finally { 831 threads.remove(ti); 832 end(n > 0); 833 assert IOStatus.check(n); 834 } 835 } 836 837 838 // -- Memory-mapped buffers -- 839 840 private static class Unmapper 841 implements Runnable 842 { 843 // may be required to close file 844 private static final NativeDispatcher nd = new FileDispatcherImpl(); 845 846 // keep track of mapped buffer usage 847 static volatile int count; 848 static volatile long totalSize; 849 static volatile long totalCapacity; 850 851 private volatile long address; 852 private final long size; 853 private final int cap; 854 private final FileDescriptor fd; 855 Unmapper(long address, long size, int cap, FileDescriptor fd)856 private Unmapper(long address, long size, int cap, 857 FileDescriptor fd) 858 { 859 assert (address != 0); 860 this.address = address; 861 this.size = size; 862 this.cap = cap; 863 this.fd = fd; 864 865 synchronized (Unmapper.class) { 866 count++; 867 totalSize += size; 868 totalCapacity += cap; 869 } 870 } 871 run()872 public void run() { 873 if (address == 0) 874 return; 875 unmap0(address, size); 876 address = 0; 877 878 // if this mapping has a valid file descriptor then we close it 879 if (fd.valid()) { 880 try { 881 nd.close(fd); 882 } catch (IOException ignore) { 883 // nothing we can do 884 } 885 } 886 887 synchronized (Unmapper.class) { 888 count--; 889 totalSize -= size; 890 totalCapacity -= cap; 891 } 892 } 893 } 894 unmap(MappedByteBuffer bb)895 private static void unmap(MappedByteBuffer bb) { 896 Cleaner cl = ((DirectBuffer)bb).cleaner(); 897 if (cl != null) 898 cl.clean(); 899 } 900 901 private static final int MAP_RO = 0; 902 private static final int MAP_RW = 1; 903 private static final int MAP_PV = 2; 904 map(MapMode mode, long position, long size)905 public MappedByteBuffer map(MapMode mode, long position, long size) 906 throws IOException 907 { 908 ensureOpen(); 909 if (mode == null) 910 throw new NullPointerException("Mode is null"); 911 if (position < 0L) 912 throw new IllegalArgumentException("Negative position"); 913 if (size < 0L) 914 throw new IllegalArgumentException("Negative size"); 915 if (position + size < 0) 916 throw new IllegalArgumentException("Position + size overflow"); 917 if (size > Integer.MAX_VALUE) 918 throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE"); 919 920 int imode = -1; 921 if (mode == MapMode.READ_ONLY) 922 imode = MAP_RO; 923 else if (mode == MapMode.READ_WRITE) 924 imode = MAP_RW; 925 else if (mode == MapMode.PRIVATE) 926 imode = MAP_PV; 927 assert (imode >= 0); 928 if ((mode != MapMode.READ_ONLY) && !writable) 929 throw new NonWritableChannelException(); 930 if (!readable) 931 throw new NonReadableChannelException(); 932 933 long addr = -1; 934 int ti = -1; 935 try { 936 begin(); 937 ti = threads.add(); 938 if (!isOpen()) 939 return null; 940 941 long filesize; 942 do { 943 filesize = nd.size(fd); 944 } while ((filesize == IOStatus.INTERRUPTED) && isOpen()); 945 if (!isOpen()) 946 return null; 947 948 if (filesize < position + size) { // Extend file size 949 if (!writable) { 950 throw new IOException("Channel not open for writing " + 951 "- cannot extend file to required size"); 952 } 953 int rv; 954 do { 955 rv = nd.truncate(fd, position + size); 956 } while ((rv == IOStatus.INTERRUPTED) && isOpen()); 957 if (!isOpen()) 958 return null; 959 } 960 if (size == 0) { 961 addr = 0; 962 // a valid file descriptor is not required 963 FileDescriptor dummy = new FileDescriptor(); 964 // Android-changed: Allocate a DirectByteBuffer directly. 965 /* 966 if ((!writable) || (imode == MAP_RO)) 967 return Util.newMappedByteBufferR(0, 0, dummy, null); 968 else 969 return Util.newMappedByteBuffer(0, 0, dummy, null); 970 */ 971 return new DirectByteBuffer(0, 0, dummy, null, 972 (!writable) || (imode == MAP_RO) /* readOnly */); 973 } 974 975 int pagePosition = (int)(position % allocationGranularity); 976 long mapPosition = position - pagePosition; 977 long mapSize = size + pagePosition; 978 try { 979 // Android-added: BlockGuard support. 980 BlockGuard.getThreadPolicy().onReadFromDisk(); 981 // If no exception was thrown from map0, the address is valid 982 addr = map0(imode, mapPosition, mapSize); 983 } catch (OutOfMemoryError x) { 984 // An OutOfMemoryError may indicate that we've exhausted memory 985 // so force gc and re-attempt map 986 System.gc(); 987 try { 988 Thread.sleep(100); 989 } catch (InterruptedException y) { 990 Thread.currentThread().interrupt(); 991 } 992 try { 993 addr = map0(imode, mapPosition, mapSize); 994 } catch (OutOfMemoryError y) { 995 // After a second OOME, fail 996 throw new IOException("Map failed", y); 997 } 998 } 999 1000 // On Windows, and potentially other platforms, we need an open 1001 // file descriptor for some mapping operations. 1002 FileDescriptor mfd; 1003 try { 1004 mfd = nd.duplicateForMapping(fd); 1005 } catch (IOException ioe) { 1006 unmap0(addr, mapSize); 1007 throw ioe; 1008 } 1009 1010 assert (IOStatus.checkAll(addr)); 1011 assert (addr % allocationGranularity == 0); 1012 int isize = (int)size; 1013 Unmapper um = new Unmapper(addr, mapSize, isize, mfd); 1014 // Android-changed: Allocate a DirectByteBuffer directly. 1015 /* 1016 if ((!writable) || (imode == MAP_RO)) { 1017 return Util.newMappedByteBufferR(isize, 1018 addr + pagePosition, 1019 mfd, 1020 um); 1021 } else { 1022 return Util.newMappedByteBuffer(isize, 1023 addr + pagePosition, 1024 mfd, 1025 um); 1026 } 1027 */ 1028 return new DirectByteBuffer(isize, addr + pagePosition, mfd, um, 1029 (!writable) || (imode == MAP_RO)); 1030 } finally { 1031 threads.remove(ti); 1032 end(IOStatus.checkAll(addr)); 1033 } 1034 } 1035 1036 // Android-removed: Unused method getMappedBufferPool(). 1037 /* 1038 /** 1039 * Invoked by sun.management.ManagementFactoryHelper to create the management 1040 * interface for mapped buffers. 1041 * 1042 public static sun.misc.JavaNioAccess.BufferPool getMappedBufferPool() { 1043 return new sun.misc.JavaNioAccess.BufferPool() { 1044 @Override 1045 public String getName() { 1046 return "mapped"; 1047 } 1048 @Override 1049 public long getCount() { 1050 return Unmapper.count; 1051 } 1052 @Override 1053 public long getTotalCapacity() { 1054 return Unmapper.totalCapacity; 1055 } 1056 @Override 1057 public long getMemoryUsed() { 1058 return Unmapper.totalSize; 1059 } 1060 }; 1061 } 1062 */ 1063 1064 // -- Locks -- 1065 1066 1067 1068 // keeps track of locks on this file 1069 private volatile FileLockTable fileLockTable; 1070 1071 // indicates if file locks are maintained system-wide (as per spec) 1072 private static boolean isSharedFileLockTable; 1073 1074 // indicates if the disableSystemWideOverlappingFileLockCheck property 1075 // has been checked 1076 private static volatile boolean propertyChecked; 1077 1078 // The lock list in J2SE 1.4/5.0 was local to each FileChannel instance so 1079 // the overlap check wasn't system wide when there were multiple channels to 1080 // the same file. This property is used to get 1.4/5.0 behavior if desired. isSharedFileLockTable()1081 private static boolean isSharedFileLockTable() { 1082 if (!propertyChecked) { 1083 synchronized (FileChannelImpl.class) { 1084 if (!propertyChecked) { 1085 String value = AccessController.doPrivileged( 1086 new GetPropertyAction( 1087 "sun.nio.ch.disableSystemWideOverlappingFileLockCheck")); 1088 isSharedFileLockTable = ((value == null) || value.equals("false")); 1089 propertyChecked = true; 1090 } 1091 } 1092 } 1093 return isSharedFileLockTable; 1094 } 1095 fileLockTable()1096 private FileLockTable fileLockTable() throws IOException { 1097 if (fileLockTable == null) { 1098 synchronized (this) { 1099 if (fileLockTable == null) { 1100 if (isSharedFileLockTable()) { 1101 int ti = threads.add(); 1102 try { 1103 ensureOpen(); 1104 fileLockTable = FileLockTable.newSharedFileLockTable(this, fd); 1105 } finally { 1106 threads.remove(ti); 1107 } 1108 } else { 1109 fileLockTable = new SimpleFileLockTable(); 1110 } 1111 } 1112 } 1113 } 1114 return fileLockTable; 1115 } 1116 lock(long position, long size, boolean shared)1117 public FileLock lock(long position, long size, boolean shared) 1118 throws IOException 1119 { 1120 ensureOpen(); 1121 if (shared && !readable) 1122 throw new NonReadableChannelException(); 1123 if (!shared && !writable) 1124 throw new NonWritableChannelException(); 1125 FileLockImpl fli = new FileLockImpl(this, position, size, shared); 1126 FileLockTable flt = fileLockTable(); 1127 flt.add(fli); 1128 boolean completed = false; 1129 int ti = -1; 1130 try { 1131 begin(); 1132 ti = threads.add(); 1133 if (!isOpen()) 1134 return null; 1135 int n; 1136 do { 1137 n = nd.lock(fd, true, position, size, shared); 1138 } while ((n == FileDispatcher.INTERRUPTED) && isOpen()); 1139 if (isOpen()) { 1140 if (n == FileDispatcher.RET_EX_LOCK) { 1141 assert shared; 1142 FileLockImpl fli2 = new FileLockImpl(this, position, size, 1143 false); 1144 flt.replace(fli, fli2); 1145 fli = fli2; 1146 } 1147 completed = true; 1148 } 1149 } finally { 1150 if (!completed) 1151 flt.remove(fli); 1152 threads.remove(ti); 1153 try { 1154 end(completed); 1155 } catch (ClosedByInterruptException e) { 1156 throw new FileLockInterruptionException(); 1157 } 1158 } 1159 return fli; 1160 } 1161 tryLock(long position, long size, boolean shared)1162 public FileLock tryLock(long position, long size, boolean shared) 1163 throws IOException 1164 { 1165 ensureOpen(); 1166 if (shared && !readable) 1167 throw new NonReadableChannelException(); 1168 if (!shared && !writable) 1169 throw new NonWritableChannelException(); 1170 FileLockImpl fli = new FileLockImpl(this, position, size, shared); 1171 FileLockTable flt = fileLockTable(); 1172 flt.add(fli); 1173 int result; 1174 1175 int ti = threads.add(); 1176 try { 1177 try { 1178 ensureOpen(); 1179 result = nd.lock(fd, false, position, size, shared); 1180 } catch (IOException e) { 1181 flt.remove(fli); 1182 throw e; 1183 } 1184 if (result == FileDispatcher.NO_LOCK) { 1185 flt.remove(fli); 1186 return null; 1187 } 1188 if (result == FileDispatcher.RET_EX_LOCK) { 1189 assert shared; 1190 FileLockImpl fli2 = new FileLockImpl(this, position, size, 1191 false); 1192 flt.replace(fli, fli2); 1193 return fli2; 1194 } 1195 return fli; 1196 } finally { 1197 threads.remove(ti); 1198 } 1199 } 1200 release(FileLockImpl fli)1201 void release(FileLockImpl fli) throws IOException { 1202 int ti = threads.add(); 1203 try { 1204 ensureOpen(); 1205 nd.release(fd, fli.position(), fli.size()); 1206 } finally { 1207 threads.remove(ti); 1208 } 1209 assert fileLockTable != null; 1210 fileLockTable.remove(fli); 1211 } 1212 1213 // -- File lock support -- 1214 1215 /** 1216 * A simple file lock table that maintains a list of FileLocks obtained by a 1217 * FileChannel. Use to get 1.4/5.0 behaviour. 1218 */ 1219 private static class SimpleFileLockTable extends FileLockTable { 1220 // synchronize on list for access 1221 private final List<FileLock> lockList = new ArrayList<FileLock>(2); 1222 SimpleFileLockTable()1223 public SimpleFileLockTable() { 1224 } 1225 checkList(long position, long size)1226 private void checkList(long position, long size) 1227 throws OverlappingFileLockException 1228 { 1229 assert Thread.holdsLock(lockList); 1230 for (FileLock fl: lockList) { 1231 if (fl.overlaps(position, size)) { 1232 throw new OverlappingFileLockException(); 1233 } 1234 } 1235 } 1236 add(FileLock fl)1237 public void add(FileLock fl) throws OverlappingFileLockException { 1238 synchronized (lockList) { 1239 checkList(fl.position(), fl.size()); 1240 lockList.add(fl); 1241 } 1242 } 1243 remove(FileLock fl)1244 public void remove(FileLock fl) { 1245 synchronized (lockList) { 1246 lockList.remove(fl); 1247 } 1248 } 1249 removeAll()1250 public List<FileLock> removeAll() { 1251 synchronized(lockList) { 1252 List<FileLock> result = new ArrayList<FileLock>(lockList); 1253 lockList.clear(); 1254 return result; 1255 } 1256 } 1257 replace(FileLock fl1, FileLock fl2)1258 public void replace(FileLock fl1, FileLock fl2) { 1259 synchronized (lockList) { 1260 lockList.remove(fl1); 1261 lockList.add(fl2); 1262 } 1263 } 1264 } 1265 1266 // -- Native methods -- 1267 1268 // Creates a new mapping map0(int prot, long position, long length)1269 private native long map0(int prot, long position, long length) 1270 throws IOException; 1271 1272 // Removes an existing mapping unmap0(long address, long length)1273 private static native int unmap0(long address, long length); 1274 1275 // Transfers from src to dst, or returns -2 if kernel can't do that transferTo0(FileDescriptor src, long position, long count, FileDescriptor dst)1276 private native long transferTo0(FileDescriptor src, long position, 1277 long count, FileDescriptor dst); 1278 1279 // Sets or reports this file's position 1280 // If offset is -1, the current position is returned 1281 // otherwise the position is set to offset position0(FileDescriptor fd, long offset)1282 private native long position0(FileDescriptor fd, long offset); 1283 1284 // Caches fieldIDs initIDs()1285 private static native long initIDs(); 1286 1287 static { 1288 // Android-removed: Move clinit code to JNI registration functions. 1289 // IOUtil.load(); 1290 allocationGranularity = initIDs(); 1291 } 1292 1293 } 1294