1 /* 2 * Copyright (C) 2014 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 com.android.layoutlib.bridge.impl.DelegateManager; 20 import com.android.layoutlib.bridge.libcore.io.BridgeBufferIterator; 21 import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 22 23 import android.system.ErrnoException; 24 25 import java.io.File; 26 import java.io.IOException; 27 import java.io.RandomAccessFile; 28 import java.nio.ByteOrder; 29 import java.nio.MappedByteBuffer; 30 import java.nio.channels.FileChannel.MapMode; 31 import java.util.HashMap; 32 import java.util.Map; 33 34 /** 35 * Delegate used to provide alternate implementation of select methods of {@link MemoryMappedFile}. 36 */ 37 public class MemoryMappedFile_Delegate { 38 39 private static final DelegateManager<MemoryMappedFile_Delegate> sManager = new 40 DelegateManager<MemoryMappedFile_Delegate>(MemoryMappedFile_Delegate.class); 41 42 private static final Map<MemoryMappedFile, Long> sMemoryMappedFileMap = 43 new HashMap<MemoryMappedFile, Long>(); 44 45 private final MappedByteBuffer mMappedByteBuffer; 46 private final long mSize; 47 48 /** Path on the target device where the data file is available. */ 49 private static final String TARGET_PATH = System.getenv("ANDROID_ROOT") + "/usr/share/zoneinfo"; 50 /** Path on the host (inside the SDK) where the data files are available. */ 51 private static File sRootPath; 52 53 @LayoutlibDelegate mmapRO(String path)54 static MemoryMappedFile mmapRO(String path) throws ErrnoException { 55 if (!path.startsWith(TARGET_PATH)) { 56 throw new ErrnoException("Custom timezone data files are not supported.", 1); 57 } 58 if (sRootPath == null) { 59 throw new ErrnoException("Bridge has not been initialized properly.", 1); 60 } 61 path = path.substring(TARGET_PATH.length()); 62 try { 63 File f = new File(sRootPath, path); 64 if (!f.exists()) { 65 throw new ErrnoException("File not found: " + f.getPath(), 1); 66 } 67 RandomAccessFile file = new RandomAccessFile(f, "r"); 68 try { 69 long size = file.length(); 70 MemoryMappedFile_Delegate newDelegate = new MemoryMappedFile_Delegate(file); 71 long filePointer = file.getFilePointer(); 72 MemoryMappedFile mmFile = new MemoryMappedFile(filePointer, size); 73 long delegateIndex = sManager.addNewDelegate(newDelegate); 74 sMemoryMappedFileMap.put(mmFile, delegateIndex); 75 return mmFile; 76 } finally { 77 file.close(); 78 } 79 } catch (IOException e) { 80 throw new ErrnoException("mmapRO", 1, e); 81 } 82 } 83 84 @LayoutlibDelegate close(MemoryMappedFile thisFile)85 static void close(MemoryMappedFile thisFile) throws ErrnoException { 86 Long index = sMemoryMappedFileMap.get(thisFile); 87 if (index != null) { 88 sMemoryMappedFileMap.remove(thisFile); 89 sManager.removeJavaReferenceFor(index); 90 } 91 } 92 93 @LayoutlibDelegate bigEndianIterator(MemoryMappedFile file)94 static BufferIterator bigEndianIterator(MemoryMappedFile file) { 95 MemoryMappedFile_Delegate delegate = getDelegate(file); 96 return new BridgeBufferIterator(delegate.mSize, delegate.mMappedByteBuffer.duplicate()); 97 } 98 99 // TODO: implement littleEndianIterator() 100 MemoryMappedFile_Delegate(RandomAccessFile file)101 public MemoryMappedFile_Delegate(RandomAccessFile file) throws IOException { 102 mSize = file.length(); 103 // It's weird that map() takes size as long, but returns MappedByteBuffer which uses an int 104 // to store the marker to the position. 105 mMappedByteBuffer = file.getChannel().map(MapMode.READ_ONLY, 0, mSize); 106 assert mMappedByteBuffer.order() == ByteOrder.BIG_ENDIAN; 107 } 108 setDataDir(File path)109 public static void setDataDir(File path) { 110 sRootPath = path; 111 } 112 getDelegate(MemoryMappedFile file)113 private static MemoryMappedFile_Delegate getDelegate(MemoryMappedFile file) { 114 Long index = sMemoryMappedFileMap.get(file); 115 return index == null ? null : sManager.getDelegate(index); 116 } 117 118 } 119