1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.nio; 19 20import dalvik.system.VMRuntime; 21import java.io.FileDescriptor; 22import java.io.IOException; 23import java.nio.channels.FileChannel.MapMode; 24import libcore.io.ErrnoException; 25import libcore.io.Libcore; 26import libcore.io.Memory; 27import static libcore.io.OsConstants.*; 28 29class MemoryBlock { 30 /** 31 * Handles calling munmap(2) on a memory-mapped region. 32 */ 33 private static class MemoryMappedBlock extends MemoryBlock { 34 private MemoryMappedBlock(long address, long byteCount) { 35 super(address, byteCount); 36 } 37 38 @Override public void free() { 39 if (address != 0) { 40 try { 41 Libcore.os.munmap(address, size); 42 } catch (ErrnoException errnoException) { 43 // The RI doesn't throw, presumably on the assumption that you can't get into 44 // a state where munmap(2) could return an error. 45 throw new AssertionError(errnoException); 46 } 47 address = 0; 48 } 49 } 50 51 @Override protected void finalize() throws Throwable { 52 free(); 53 } 54 } 55 56 /** 57 * Non-movable heap blocks are byte arrays on the Java heap that the GC 58 * guarantees not to move. Used to implement DirectByteBuffer. 59 * 60 * Losing the strong reference to the array is sufficient 61 * to allow the GC to reclaim the storage. No finalizer needed. 62 */ 63 private static class NonMovableHeapBlock extends MemoryBlock { 64 private byte[] array; 65 66 private NonMovableHeapBlock(byte[] array, long address, long byteCount) { 67 super(address, byteCount); 68 this.array = array; 69 } 70 71 @Override public byte[] array() { 72 return array; 73 } 74 75 @Override public void free() { 76 array = null; 77 address = 0; 78 } 79 } 80 81 /** 82 * Represents a block of memory we don't own. (We don't take ownership of memory corresponding 83 * to direct buffers created by the JNI NewDirectByteBuffer function.) 84 */ 85 private static class UnmanagedBlock extends MemoryBlock { 86 private UnmanagedBlock(long address, long byteCount) { 87 super(address, byteCount); 88 } 89 } 90 91 protected long address; 92 protected final long size; 93 94 public static MemoryBlock mmap(FileDescriptor fd, long offset, long size, MapMode mapMode) throws IOException { 95 if (size == 0) { 96 // You can't mmap(2) a zero-length region, but Java allows it. 97 return new MemoryBlock(0, 0); 98 } 99 // Check just those errors mmap(2) won't detect. 100 if (offset < 0 || size < 0 || offset > Integer.MAX_VALUE || size > Integer.MAX_VALUE) { 101 throw new IllegalArgumentException("offset=" + offset + " size=" + size); 102 } 103 int prot; 104 int flags; 105 if (mapMode == MapMode.PRIVATE) { 106 prot = PROT_READ|PROT_WRITE; 107 flags = MAP_PRIVATE; 108 } else if (mapMode == MapMode.READ_ONLY) { 109 prot = PROT_READ; 110 flags = MAP_SHARED; 111 } else { // mapMode == MapMode.READ_WRITE 112 prot = PROT_READ|PROT_WRITE; 113 flags = MAP_SHARED; 114 } 115 try { 116 long address = Libcore.os.mmap(0L, size, prot, flags, fd, offset); 117 return new MemoryMappedBlock(address, size); 118 } catch (ErrnoException errnoException) { 119 throw errnoException.rethrowAsIOException(); 120 } 121 } 122 123 public static MemoryBlock allocate(int byteCount) { 124 VMRuntime runtime = VMRuntime.getRuntime(); 125 byte[] array = (byte[]) runtime.newNonMovableArray(byte.class, byteCount); 126 long address = runtime.addressOf(array); 127 return new NonMovableHeapBlock(array, address, byteCount); 128 } 129 130 public static MemoryBlock wrapFromJni(long address, long byteCount) { 131 return new UnmanagedBlock(address, byteCount); 132 } 133 134 private MemoryBlock(long address, long size) { 135 this.address = address; 136 this.size = size; 137 } 138 139 // Used to support array/arrayOffset/hasArray for direct buffers. 140 public byte[] array() { 141 return null; 142 } 143 144 public void free() { 145 } 146 147 public final void pokeByte(int offset, byte value) { 148 Memory.pokeByte(address + offset, value); 149 } 150 151 public final void pokeByteArray(int offset, byte[] src, int srcOffset, int byteCount) { 152 Memory.pokeByteArray(address + offset, src, srcOffset, byteCount); 153 } 154 155 public final void pokeCharArray(int offset, char[] src, int srcOffset, int charCount, boolean swap) { 156 Memory.pokeCharArray(address + offset, src, srcOffset, charCount, swap); 157 } 158 159 public final void pokeDoubleArray(int offset, double[] src, int srcOffset, int doubleCount, boolean swap) { 160 Memory.pokeDoubleArray(address + offset, src, srcOffset, doubleCount, swap); 161 } 162 163 public final void pokeFloatArray(int offset, float[] src, int srcOffset, int floatCount, boolean swap) { 164 Memory.pokeFloatArray(address + offset, src, srcOffset, floatCount, swap); 165 } 166 167 public final void pokeIntArray(int offset, int[] src, int srcOffset, int intCount, boolean swap) { 168 Memory.pokeIntArray(address + offset, src, srcOffset, intCount, swap); 169 } 170 171 public final void pokeLongArray(int offset, long[] src, int srcOffset, int longCount, boolean swap) { 172 Memory.pokeLongArray(address + offset, src, srcOffset, longCount, swap); 173 } 174 175 public final void pokeShortArray(int offset, short[] src, int srcOffset, int shortCount, boolean swap) { 176 Memory.pokeShortArray(address + offset, src, srcOffset, shortCount, swap); 177 } 178 179 public final byte peekByte(int offset) { 180 return Memory.peekByte(address + offset); 181 } 182 183 public final void peekByteArray(int offset, byte[] dst, int dstOffset, int byteCount) { 184 Memory.peekByteArray(address + offset, dst, dstOffset, byteCount); 185 } 186 187 public final void peekCharArray(int offset, char[] dst, int dstOffset, int charCount, boolean swap) { 188 Memory.peekCharArray(address + offset, dst, dstOffset, charCount, swap); 189 } 190 191 public final void peekDoubleArray(int offset, double[] dst, int dstOffset, int doubleCount, boolean swap) { 192 Memory.peekDoubleArray(address + offset, dst, dstOffset, doubleCount, swap); 193 } 194 195 public final void peekFloatArray(int offset, float[] dst, int dstOffset, int floatCount, boolean swap) { 196 Memory.peekFloatArray(address + offset, dst, dstOffset, floatCount, swap); 197 } 198 199 public final void peekIntArray(int offset, int[] dst, int dstOffset, int intCount, boolean swap) { 200 Memory.peekIntArray(address + offset, dst, dstOffset, intCount, swap); 201 } 202 203 public final void peekLongArray(int offset, long[] dst, int dstOffset, int longCount, boolean swap) { 204 Memory.peekLongArray(address + offset, dst, dstOffset, longCount, swap); 205 } 206 207 public final void peekShortArray(int offset, short[] dst, int dstOffset, int shortCount, boolean swap) { 208 Memory.peekShortArray(address + offset, dst, dstOffset, shortCount, swap); 209 } 210 211 public final void pokeShort(int offset, short value, ByteOrder order) { 212 Memory.pokeShort(address + offset, value, order.needsSwap); 213 } 214 215 public final short peekShort(int offset, ByteOrder order) { 216 return Memory.peekShort(address + offset, order.needsSwap); 217 } 218 219 public final void pokeInt(int offset, int value, ByteOrder order) { 220 Memory.pokeInt(address + offset, value, order.needsSwap); 221 } 222 223 public final int peekInt(int offset, ByteOrder order) { 224 return Memory.peekInt(address + offset, order.needsSwap); 225 } 226 227 public final void pokeLong(int offset, long value, ByteOrder order) { 228 Memory.pokeLong(address + offset, value, order.needsSwap); 229 } 230 231 public final long peekLong(int offset, ByteOrder order) { 232 return Memory.peekLong(address + offset, order.needsSwap); 233 } 234 235 public final long toLong() { 236 return address; 237 } 238 239 public final String toString() { 240 return getClass().getName() + "[" + address + "]"; 241 } 242 243 public final long getSize() { 244 return size; 245 } 246} 247