117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta/*
217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta * Copyright (C) 2014 The Android Open Source Project
317a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta *
417a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta * Licensed under the Apache License, Version 2.0 (the "License");
517a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta * you may not use this file except in compliance with the License.
617a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta * You may obtain a copy of the License at
717a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta *
817a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta *      http://www.apache.org/licenses/LICENSE-2.0
917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta *
1017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta * Unless required by applicable law or agreed to in writing, software
1117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta * distributed under the License is distributed on an "AS IS" BASIS,
1217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1317a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta * See the License for the specific language governing permissions and
1417a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta * limitations under the License.
1517a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta */
1617a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
1717a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Guptapackage libcore.io;
1817a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
1917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Guptaimport com.android.layoutlib.bridge.impl.DelegateManager;
2017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Guptaimport com.android.layoutlib.bridge.libcore.io.BridgeBufferIterator;
2117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Guptaimport com.android.tools.layoutlib.annotations.LayoutlibDelegate;
2217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
2317a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Guptaimport android.system.ErrnoException;
2417a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
2517a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Guptaimport java.io.File;
2617a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Guptaimport java.io.IOException;
2717a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Guptaimport java.io.RandomAccessFile;
285ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Guptaimport java.nio.ByteOrder;
2917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Guptaimport java.nio.MappedByteBuffer;
3017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Guptaimport java.nio.channels.FileChannel.MapMode;
3117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Guptaimport java.util.HashMap;
3217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Guptaimport java.util.Map;
3317a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
3417a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta/**
3517a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta * Delegate used to provide alternate implementation of select methods of {@link MemoryMappedFile}.
3617a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta */
3717a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Guptapublic class MemoryMappedFile_Delegate {
3817a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
3917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    private static final DelegateManager<MemoryMappedFile_Delegate> sManager = new
4017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta            DelegateManager<MemoryMappedFile_Delegate>(MemoryMappedFile_Delegate.class);
4117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
4217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    private static final Map<MemoryMappedFile, Long> sMemoryMappedFileMap =
4317a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta            new HashMap<MemoryMappedFile, Long>();
4417a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
4517a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    private final MappedByteBuffer mMappedByteBuffer;
4617a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    private final long mSize;
4717a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
4817a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    /** Path on the target device where the data file is available. */
4917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    private static final String TARGET_PATH = System.getenv("ANDROID_ROOT") + "/usr/share/zoneinfo";
5017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    /** Path on the host (inside the SDK) where the data files are available. */
5117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    private static File sRootPath;
5217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
5317a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    @LayoutlibDelegate
5417a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    static MemoryMappedFile mmapRO(String path) throws ErrnoException {
5517a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        if (!path.startsWith(TARGET_PATH)) {
5617a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta            throw new ErrnoException("Custom timezone data files are not supported.", 1);
5717a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        }
5817a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        if (sRootPath == null) {
5917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta            throw new ErrnoException("Bridge has not been initialized properly.", 1);
6017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        }
6117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        path = path.substring(TARGET_PATH.length());
6217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        try {
635ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta            File f = new File(sRootPath, path);
645ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta            if (!f.exists()) {
655ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta                throw new ErrnoException("File not found: " + f.getPath(), 1);
665ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta            }
675ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta            RandomAccessFile file = new RandomAccessFile(f, "r");
685ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta            try {
695ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta                long size = file.length();
705ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta                MemoryMappedFile_Delegate newDelegate = new MemoryMappedFile_Delegate(file);
715ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta                long filePointer = file.getFilePointer();
725ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta                MemoryMappedFile mmFile = new MemoryMappedFile(filePointer, size);
735ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta                long delegateIndex = sManager.addNewDelegate(newDelegate);
745ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta                sMemoryMappedFileMap.put(mmFile, delegateIndex);
755ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta                return mmFile;
765ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta            } finally {
775ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta                file.close();
785ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta            }
7917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        } catch (IOException e) {
8017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta            throw new ErrnoException("mmapRO", 1, e);
8117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        }
8217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    }
8317a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
8417a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    @LayoutlibDelegate
8517a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    static void close(MemoryMappedFile thisFile) throws ErrnoException {
8617a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        Long index = sMemoryMappedFileMap.get(thisFile);
8717a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        if (index != null) {
8817a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta            sMemoryMappedFileMap.remove(thisFile);
8917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta            sManager.removeJavaReferenceFor(index);
9017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        }
9117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    }
9217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
9317a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    @LayoutlibDelegate
9417a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    static BufferIterator bigEndianIterator(MemoryMappedFile file) {
9517a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        MemoryMappedFile_Delegate delegate = getDelegate(file);
965ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta        return new BridgeBufferIterator(delegate.mSize, delegate.mMappedByteBuffer.duplicate());
9717a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    }
9817a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
9917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    // TODO: implement littleEndianIterator()
10017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
10117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    public MemoryMappedFile_Delegate(RandomAccessFile file) throws IOException {
10217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        mSize = file.length();
10317a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        // It's weird that map() takes size as long, but returns MappedByteBuffer which uses an int
10417a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        // to store the marker to the position.
10517a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        mMappedByteBuffer = file.getChannel().map(MapMode.READ_ONLY, 0, mSize);
1065ceb7f6431f447aa9d4e949578ce5d4b90b8297cDeepanshu Gupta        assert mMappedByteBuffer.order() == ByteOrder.BIG_ENDIAN;
10717a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    }
10817a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
10917a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    public static void setDataDir(File path) {
11017a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        sRootPath = path;
11117a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    }
11217a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
11317a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    private static MemoryMappedFile_Delegate getDelegate(MemoryMappedFile file) {
11417a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        Long index = sMemoryMappedFileMap.get(file);
11517a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta        return index == null ? null : sManager.getDelegate(index);
11617a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta    }
11717a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta
11817a6170c62e6f74f2881623a9c16f0b6fea54721Deepanshu Gupta}
119