1 /*
2  * Copyright (C) 2010 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 
17 package libcore.io;
18 
19 import android.system.ErrnoException;
20 import java.io.FileDescriptor;
21 import java.io.IOException;
22 import java.io.RandomAccessFile;
23 import java.nio.ByteOrder;
24 import java.nio.channels.FileChannel;
25 import java.nio.NioUtils;
26 import libcore.io.Libcore;
27 import libcore.io.Memory;
28 import static android.system.OsConstants.*;
29 
30 /**
31  * A memory-mapped file. Use {@link #mmap} to map a file, {@link #close} to unmap a file,
32  * and either {@link #bigEndianIterator} or {@link #littleEndianIterator} to get a seekable
33  * {@link BufferIterator} over the mapped data.
34  */
35 public final class MemoryMappedFile implements AutoCloseable {
36     private long address;
37     private final long size;
38 
39     /**
40      * Use this if you've called {@code mmap} yourself.
41      */
MemoryMappedFile(long address, long size)42     public MemoryMappedFile(long address, long size) {
43         this.address = address;
44         this.size = size;
45     }
46 
47     /**
48      * Use this to mmap the whole file read-only.
49      */
mmapRO(String path)50     public static MemoryMappedFile mmapRO(String path) throws ErrnoException {
51         FileDescriptor fd = Libcore.os.open(path, O_RDONLY, 0);
52         long size = Libcore.os.fstat(fd).st_size;
53         long address = Libcore.os.mmap(0L, size, PROT_READ, MAP_SHARED, fd, 0);
54         Libcore.os.close(fd);
55         return new MemoryMappedFile(address, size);
56     }
57 
58     /**
59      * Unmaps this memory-mapped file using munmap(2). This is a no-op if close has already been
60      * called. Note that this class does <i>not</i> use finalization; you must call {@code close}
61      * yourself.
62      *
63      * Calling this method invalidates any iterators over this {@code MemoryMappedFile}. It is an
64      * error to use such an iterator after calling {@code close}.
65      */
close()66     public synchronized void close() throws ErrnoException {
67         if (address != 0) {
68             Libcore.os.munmap(address, size);
69             address = 0;
70         }
71     }
72 
73     /**
74      * Returns a new iterator that treats the mapped data as big-endian.
75      */
bigEndianIterator()76     public BufferIterator bigEndianIterator() {
77         return new NioBufferIterator(address, (int) size, ByteOrder.nativeOrder() != ByteOrder.BIG_ENDIAN);
78     }
79 
80     /**
81      * Returns a new iterator that treats the mapped data as little-endian.
82      */
littleEndianIterator()83     public BufferIterator littleEndianIterator() {
84         return new NioBufferIterator(address, (int) size, ByteOrder.nativeOrder() != ByteOrder.LITTLE_ENDIAN);
85     }
86 
87     /**
88      * Returns the size in bytes of the memory-mapped region.
89      */
size()90     public long size() {
91         return size;
92     }
93 }
94