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 android.system.ErrnoException; 21import dalvik.system.VMRuntime; 22import java.io.FileDescriptor; 23import java.io.IOException; 24import java.nio.channels.FileChannel.MapMode; 25import libcore.io.Libcore; 26import libcore.io.Memory; 27 28import static android.system.OsConstants.MAP_PRIVATE; 29import static android.system.OsConstants.MAP_SHARED; 30import static android.system.OsConstants.PROT_READ; 31import static android.system.OsConstants.PROT_WRITE; 32 33class MemoryBlock { 34 /** 35 * Handles calling munmap(2) on a memory-mapped region. 36 */ 37 private static class MemoryMappedBlock extends MemoryBlock { 38 private MemoryMappedBlock(long address, long byteCount) { 39 super(address, byteCount); 40 } 41 42 @Override public void free() { 43 if (address != 0) { 44 try { 45 Libcore.os.munmap(address, size); 46 } catch (ErrnoException errnoException) { 47 // The RI doesn't throw, presumably on the assumption that you can't get into 48 // a state where munmap(2) could return an error. 49 throw new AssertionError(errnoException); 50 } 51 } 52 super.free(); 53 } 54 55 @Override protected void finalize() throws Throwable { 56 free(); 57 } 58 } 59 60 /** 61 * Non-movable heap blocks are byte arrays on the Java heap that the GC 62 * guarantees not to move. Used to implement DirectByteBuffer. 63 * 64 * Losing the strong reference to the array is sufficient 65 * to allow the GC to reclaim the storage. No finalizer needed. 66 */ 67 private static class NonMovableHeapBlock extends MemoryBlock { 68 private byte[] array; 69 70 private NonMovableHeapBlock(byte[] array, long address, long byteCount) { 71 super(address, byteCount); 72 this.array = array; 73 } 74 75 @Override public byte[] array() { 76 return array; 77 } 78 79 @Override public void free() { 80 array = null; 81 super.free(); 82 } 83 } 84 85 /** 86 * Represents a block of memory we don't own. (We don't take ownership of memory corresponding 87 * to direct buffers created by the JNI NewDirectByteBuffer function.) 88 */ 89 private static class UnmanagedBlock extends MemoryBlock { 90 private UnmanagedBlock(long address, long byteCount) { 91 super(address, byteCount); 92 } 93 } 94 95 protected long address; 96 protected final long size; 97 private boolean accessible; 98 private boolean freed; 99 100 public static MemoryBlock mmap(FileDescriptor fd, long offset, long size, MapMode mapMode) throws IOException { 101 if (size == 0) { 102 // You can't mmap(2) a zero-length region, but Java allows it. 103 return new MemoryBlock(0, 0); 104 } 105 // Check just those errors mmap(2) won't detect. 106 if (offset < 0 || size < 0 || offset > Integer.MAX_VALUE || size > Integer.MAX_VALUE) { 107 throw new IllegalArgumentException("offset=" + offset + " size=" + size); 108 } 109 int prot; 110 int flags; 111 if (mapMode == MapMode.PRIVATE) { 112 prot = PROT_READ|PROT_WRITE; 113 flags = MAP_PRIVATE; 114 } else if (mapMode == MapMode.READ_ONLY) { 115 prot = PROT_READ; 116 flags = MAP_SHARED; 117 } else { // mapMode == MapMode.READ_WRITE 118 prot = PROT_READ|PROT_WRITE; 119 flags = MAP_SHARED; 120 } 121 try { 122 long address = Libcore.os.mmap(0L, size, prot, flags, fd, offset); 123 return new MemoryMappedBlock(address, size); 124 } catch (ErrnoException errnoException) { 125 throw errnoException.rethrowAsIOException(); 126 } 127 } 128 129 public static MemoryBlock allocate(int byteCount) { 130 VMRuntime runtime = VMRuntime.getRuntime(); 131 byte[] array = (byte[]) runtime.newNonMovableArray(byte.class, byteCount); 132 long address = runtime.addressOf(array); 133 return new NonMovableHeapBlock(array, address, byteCount); 134 } 135 136 public static MemoryBlock wrapFromJni(long address, long byteCount) { 137 return new UnmanagedBlock(address, byteCount); 138 } 139 140 private MemoryBlock(long address, long size) { 141 this.address = address; 142 this.size = size; 143 accessible = true; 144 freed = false; 145 } 146 147 // Used to support array/arrayOffset/hasArray for direct buffers. 148 public byte[] array() { 149 return null; 150 } 151 152 public void free() { 153 address = 0; 154 freed = true; 155 } 156 157 public boolean isFreed() { 158 return freed; 159 } 160 161 public boolean isAccessible() { 162 return !isFreed() && accessible; 163 } 164 165 public final void setAccessible(boolean accessible) { 166 this.accessible = accessible; 167 } 168 169 public final void pokeByte(int offset, byte value) { 170 Memory.pokeByte(address + offset, value); 171 } 172 173 public final void pokeByteArray(int offset, byte[] src, int srcOffset, int byteCount) { 174 Memory.pokeByteArray(address + offset, src, srcOffset, byteCount); 175 } 176 177 public final void pokeCharArray(int offset, char[] src, int srcOffset, int charCount, boolean swap) { 178 Memory.pokeCharArray(address + offset, src, srcOffset, charCount, swap); 179 } 180 181 public final void pokeDoubleArray(int offset, double[] src, int srcOffset, int doubleCount, boolean swap) { 182 Memory.pokeDoubleArray(address + offset, src, srcOffset, doubleCount, swap); 183 } 184 185 public final void pokeFloatArray(int offset, float[] src, int srcOffset, int floatCount, boolean swap) { 186 Memory.pokeFloatArray(address + offset, src, srcOffset, floatCount, swap); 187 } 188 189 public final void pokeIntArray(int offset, int[] src, int srcOffset, int intCount, boolean swap) { 190 Memory.pokeIntArray(address + offset, src, srcOffset, intCount, swap); 191 } 192 193 public final void pokeLongArray(int offset, long[] src, int srcOffset, int longCount, boolean swap) { 194 Memory.pokeLongArray(address + offset, src, srcOffset, longCount, swap); 195 } 196 197 public final void pokeShortArray(int offset, short[] src, int srcOffset, int shortCount, boolean swap) { 198 Memory.pokeShortArray(address + offset, src, srcOffset, shortCount, swap); 199 } 200 201 public final byte peekByte(int offset) { 202 return Memory.peekByte(address + offset); 203 } 204 205 public final void peekByteArray(int offset, byte[] dst, int dstOffset, int byteCount) { 206 Memory.peekByteArray(address + offset, dst, dstOffset, byteCount); 207 } 208 209 public final void peekCharArray(int offset, char[] dst, int dstOffset, int charCount, boolean swap) { 210 Memory.peekCharArray(address + offset, dst, dstOffset, charCount, swap); 211 } 212 213 public final void peekDoubleArray(int offset, double[] dst, int dstOffset, int doubleCount, boolean swap) { 214 Memory.peekDoubleArray(address + offset, dst, dstOffset, doubleCount, swap); 215 } 216 217 public final void peekFloatArray(int offset, float[] dst, int dstOffset, int floatCount, boolean swap) { 218 Memory.peekFloatArray(address + offset, dst, dstOffset, floatCount, swap); 219 } 220 221 public final void peekIntArray(int offset, int[] dst, int dstOffset, int intCount, boolean swap) { 222 Memory.peekIntArray(address + offset, dst, dstOffset, intCount, swap); 223 } 224 225 public final void peekLongArray(int offset, long[] dst, int dstOffset, int longCount, boolean swap) { 226 Memory.peekLongArray(address + offset, dst, dstOffset, longCount, swap); 227 } 228 229 public final void peekShortArray(int offset, short[] dst, int dstOffset, int shortCount, boolean swap) { 230 Memory.peekShortArray(address + offset, dst, dstOffset, shortCount, swap); 231 } 232 233 public final void pokeShort(int offset, short value, ByteOrder order) { 234 Memory.pokeShort(address + offset, value, order.needsSwap); 235 } 236 237 public final short peekShort(int offset, ByteOrder order) { 238 return Memory.peekShort(address + offset, order.needsSwap); 239 } 240 241 public final void pokeInt(int offset, int value, ByteOrder order) { 242 Memory.pokeInt(address + offset, value, order.needsSwap); 243 } 244 245 public final int peekInt(int offset, ByteOrder order) { 246 return Memory.peekInt(address + offset, order.needsSwap); 247 } 248 249 public final void pokeLong(int offset, long value, ByteOrder order) { 250 Memory.pokeLong(address + offset, value, order.needsSwap); 251 } 252 253 public final long peekLong(int offset, ByteOrder order) { 254 return Memory.peekLong(address + offset, order.needsSwap); 255 } 256 257 public final long toLong() { 258 return address; 259 } 260 261 public final String toString() { 262 return getClass().getName() + "[" + address + "]"; 263 } 264 265 public final long getSize() { 266 return size; 267 } 268} 269