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