1ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein/* 2ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Copyright (C) 2011 The Android Open Source Project 3ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * 4ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Licensed under the Apache License, Version 2.0 (the "License"); 5ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * you may not use this file except in compliance with the License. 6ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * You may obtain a copy of the License at 7ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * 8ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * http://www.apache.org/licenses/LICENSE-2.0 9ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * 10ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Unless required by applicable law or agreed to in writing, software 11ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * distributed under the License is distributed on an "AS IS" BASIS, 12ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * See the License for the specific language governing permissions and 14ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * limitations under the License. 15ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 16ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 17ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornsteinpackage dalvik.system; 18ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 19ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornsteinimport java.io.File; 20ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornsteinimport java.io.IOException; 21ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornsteinimport java.net.MalformedURLException; 22ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornsteinimport java.net.URL; 23ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornsteinimport java.util.ArrayList; 24ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornsteinimport java.util.Collections; 25ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornsteinimport java.util.Enumeration; 26ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornsteinimport java.util.regex.Pattern; 27ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornsteinimport java.util.zip.ZipFile; 28ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 29ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein/** 30ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * A pair of lists of entries, associated with a {@code ClassLoader}. 31ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * One of the lists is a dex/resource path — typically referred 32ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * to as a "class path" — list, and the other names directories 33ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * containing native code libraries. Class path entries may be any of: 34ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * a {@code .jar} or {@code .zip} file containing an optional 35ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * top-level {@code classes.dex} file as well as arbitrary resources, 36ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * or a plain {@code .dex} file (with no possibility of associated 37ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * resources). 38ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * 39ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * <p>This class also contains methods to use these lists to look up 40ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * classes and resources.</p> 41ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 42ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein/*package*/ final class DexPathList { 43ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein private static final String DEX_SUFFIX = ".dex"; 44ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein private static final String JAR_SUFFIX = ".jar"; 45ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein private static final String ZIP_SUFFIX = ".zip"; 46ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein private static final String APK_SUFFIX = ".apk"; 47ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 48ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** class definition context */ 49ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein private final ClassLoader definingContext; 50ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 51ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** list of dex/resource (class path) elements */ 52ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein private final Element[] dexElements; 53ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 54ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** list of native library directory elements */ 55ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein private final File[] nativeLibraryDirectories; 56ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 57ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** 58ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Constructs an instance. 59ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * 60ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * @param definingContext the context in which any as-yet unresolved 61ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * classes should be defined 62ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * @param dexPath list of dex/resource path elements, separated by 63ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * {@code File.pathSeparator} 64ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * @param libraryPath list of native library directory path elements, 65ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * separated by {@code File.pathSeparator} 66ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * @param optimizedDirectory directory where optimized {@code .dex} files 67ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * should be found and written to, or {@code null} to use the default 68ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * system directory for same 69ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 70ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein public DexPathList(ClassLoader definingContext, String dexPath, 71ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein String libraryPath, File optimizedDirectory) { 72ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (definingContext == null) { 73ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein throw new NullPointerException("definingContext == null"); 74ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 75ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 76ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (dexPath == null) { 77ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein throw new NullPointerException("dexPath == null"); 78ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 79ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 80ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (optimizedDirectory != null) { 81ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (!optimizedDirectory.exists()) { 82ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein throw new IllegalArgumentException( 83ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein "optimizedDirectory doesn't exist: " 84ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein + optimizedDirectory); 85ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 86ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 87ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (!(optimizedDirectory.canRead() 88ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein && optimizedDirectory.canWrite())) { 89ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein throw new IllegalArgumentException( 90ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein "optimizedDirectory not readable/writable: " 91ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein + optimizedDirectory); 92ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 93ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 94ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 95ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein this.definingContext = definingContext; 96ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein this.dexElements = 97ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein makeDexElements(splitDexPath(dexPath), optimizedDirectory); 98ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein this.nativeLibraryDirectories = splitLibraryPath(libraryPath); 99ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 100ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 101ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** 102ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Splits the given dex path string into elements using the path 103ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * separator, pruning out any elements that do not refer to existing 104ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * and readable files. (That is, directories are not included in the 105ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * result.) 106ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 107ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein private static ArrayList<File> splitDexPath(String path) { 108ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return splitPaths(path, null, false); 109ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 110ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 111ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** 112ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Splits the given library directory path string into elements 113ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * using the path separator ({@code File.pathSeparator}, which 114ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * defaults to {@code ":"} on Android, appending on the elements 115ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * from the system library path, and pruning out any elements that 116ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * do not refer to existing and readable directories. 117ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 118ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein private static File[] splitLibraryPath(String path) { 119ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /* 120ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Native libraries may exist in both the system and 121ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * application library paths, and we use this search order: 122ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * 123ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * 1. this class loader's library path for application 124ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * libraries 125ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * 2. the VM's library path from the system 126ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * property for system libraries 127ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * 128ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * This order was reversed prior to Gingerbread; see http://b/2933456. 129ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 130ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein ArrayList<File> result = splitPaths( 131ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein path, System.getProperty("java.library.path", "."), true); 132ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return result.toArray(new File[result.size()]); 133ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 134ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 135ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** 136ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Splits the given path strings into file elements using the path 137ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * separator, combining the results and filtering out elements 138ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * that don't exist, aren't readable, or aren't either a regular 139ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * file or a directory (as specified). Either string may be empty 140ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * or {@code null}, in which case it is ignored. If both strings 141ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * are empty or {@code null}, or all elements get pruned out, then 142ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * this returns a zero-element list. 143ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 144ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein private static ArrayList<File> splitPaths(String path1, String path2, 145ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein boolean wantDirectories) { 146ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein ArrayList<File> result = new ArrayList<File>(); 147ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 148ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein splitAndAdd(path1, wantDirectories, result); 149ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein splitAndAdd(path2, wantDirectories, result); 150ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return result; 151ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 152ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 153ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** 154ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Helper for {@link #splitPaths}, which does the actual splitting 155ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * and filtering and adding to a result. 156ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 157ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein private static void splitAndAdd(String path, boolean wantDirectories, 158ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein ArrayList<File> resultList) { 159ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (path == null) { 160ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return; 161ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 162ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 163ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein String[] strings = path.split(Pattern.quote(File.pathSeparator)); 164ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 165ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein for (String s : strings) { 166ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein File file = new File(s); 167ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 168ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (! (file.exists() && file.canRead())) { 169ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein continue; 170ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 171ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 172ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /* 173ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Note: There are other entities in filesystems than 174ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * regular files and directories. 175ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 176ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (wantDirectories) { 177ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (!file.isDirectory()) { 178ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein continue; 179ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 180ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } else { 181ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (!file.isFile()) { 182ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein continue; 183ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 184ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 185ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 186ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein resultList.add(file); 187ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 188ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 189ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 190ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** 191ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Makes an array of dex/resource path elements, one per element of 192ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * the given array. 193ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 194ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein private static Element[] makeDexElements(ArrayList<File> files, 195ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein File optimizedDirectory) { 196ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein ArrayList<Element> elements = new ArrayList<Element>(); 197ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 198ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /* 199ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Open all files and load the (direct or contained) dex files 200ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * up front. 201ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 202ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein for (File file : files) { 2038dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath File zip = null; 204ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein DexFile dex = null; 205ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein String name = file.getName(); 206ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 207ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (name.endsWith(DEX_SUFFIX)) { 208ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein // Raw dex file (not inside a zip/jar). 209ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein try { 210ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein dex = loadDexFile(file, optimizedDirectory); 211ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } catch (IOException ex) { 212a7ef55258ac71153487357b861c7639d627df82fElliott Hughes System.logE("Unable to load dex file: " + file, ex); 213ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 214ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } else if (name.endsWith(APK_SUFFIX) || name.endsWith(JAR_SUFFIX) 215ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein || name.endsWith(ZIP_SUFFIX)) { 2168dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath zip = file; 217ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 218ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein try { 219ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein dex = loadDexFile(file, optimizedDirectory); 220ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } catch (IOException ignored) { 221ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /* 222ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * IOException might get thrown "legitimately" by 223ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * the DexFile constructor if the zip file turns 224ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * out to be resource-only (that is, no 225ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * classes.dex file in it). Safe to just ignore 226ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * the exception here, and let dex == null. 227ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 228ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 229ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } else { 230a7ef55258ac71153487357b861c7639d627df82fElliott Hughes System.logW("Unknown file type for: " + file); 231ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 232ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 233ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if ((zip != null) || (dex != null)) { 234ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein elements.add(new Element(file, zip, dex)); 235ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 236ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 237ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 238ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return elements.toArray(new Element[elements.size()]); 239ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 240ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 241ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** 242ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Constructs a {@code DexFile} instance, as appropriate depending 243ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * on whether {@code optimizedDirectory} is {@code null}. 244ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 245ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein private static DexFile loadDexFile(File file, File optimizedDirectory) 246ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein throws IOException { 247ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (optimizedDirectory == null) { 248ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return new DexFile(file); 249ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } else { 250ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein String optimizedPath = optimizedPathFor(file, optimizedDirectory); 251ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return DexFile.loadDex(file.getPath(), optimizedPath, 0); 252ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 253ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 254ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 255ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** 256ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Converts a dex/jar file path and an output directory to an 257ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * output file path for an associated optimized dex file. 258ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 259ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein private static String optimizedPathFor(File path, 260ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein File optimizedDirectory) { 261ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /* 262ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Get the filename component of the path, and replace the 263ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * suffix with ".dex" if that's not already the suffix. 264ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * 265ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * We don't want to use ".odex", because the build system uses 266ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * that for files that are paired with resource-only jar 267ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * files. If the VM can assume that there's no classes.dex in 268ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * the matching jar, it doesn't need to open the jar to check 269ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * for updated dependencies, providing a slight performance 270ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * boost at startup. The use of ".dex" here matches the use on 271ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * files in /data/dalvik-cache. 272ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 273ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein String fileName = path.getName(); 274ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (!fileName.endsWith(DEX_SUFFIX)) { 275ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein int lastDot = fileName.lastIndexOf("."); 276ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (lastDot < 0) { 277ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein fileName += DEX_SUFFIX; 278ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } else { 279ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein StringBuilder sb = new StringBuilder(lastDot + 4); 280ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein sb.append(fileName, 0, lastDot); 281ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein sb.append(DEX_SUFFIX); 282ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein fileName = sb.toString(); 283ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 284ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 285ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 286ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein File result = new File(optimizedDirectory, fileName); 287ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return result.getPath(); 288ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 289ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 290ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** 291ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Finds the named class in one of the dex files pointed at by 292ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * this instance. This will find the one in the earliest listed 293ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * path element. If the class is found but has not yet been 294ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * defined, then this method will define it in the defining 295ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * context that this instance was constructed with. 296ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * 297ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * @return the named class or {@code null} if the class is not 298ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * found in any of the dex files 299ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 300ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein public Class findClass(String name) { 301ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein for (Element element : dexElements) { 302ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein DexFile dex = element.dexFile; 303ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 304ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (dex != null) { 305ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein Class clazz = dex.loadClassBinaryName(name, definingContext); 306ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (clazz != null) { 307ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return clazz; 308ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 309ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 310ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 311ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 312ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return null; 313ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 314ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 315ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** 316ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Finds the named resource in one of the zip/jar files pointed at 317ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * by this instance. This will find the one in the earliest listed 318ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * path element. 319ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * 320ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * @return a URL to the named resource or {@code null} if the 321ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * resource is not found in any of the zip/jar files 322ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 323ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein public URL findResource(String name) { 324ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein for (Element element : dexElements) { 325ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein URL url = element.findResource(name); 326ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (url != null) { 327ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return url; 328ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 329ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 330ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 331ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return null; 332ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 333ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 334ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** 335ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Finds all the resources with the given name, returning an 336ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * enumeration of them. If there are no resources with the given 337ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * name, then this method returns an empty enumeration. 338ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 339ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein public Enumeration<URL> findResources(String name) { 340ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein ArrayList<URL> result = new ArrayList<URL>(); 341ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 342ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein for (Element element : dexElements) { 343ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein URL url = element.findResource(name); 344ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (url != null) { 345ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein result.add(url); 346ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 347ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 348ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 349ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return Collections.enumeration(result); 350ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 351ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 352ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** 353ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Finds the named native code library on any of the library 354ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * directories pointed at by this instance. This will find the 355ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * one in the earliest listed directory, ignoring any that are not 356ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * readable regular files. 357ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * 358ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * @return the complete path to the library or {@code null} if no 359ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * library was found 360ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 361ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein public String findLibrary(String libraryName) { 362ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein String fileName = System.mapLibraryName(libraryName); 363ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 364ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein for (File directory : nativeLibraryDirectories) { 365ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein File file = new File(directory, fileName); 366ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein if (file.exists() && file.isFile() && file.canRead()) { 367ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return file.getPath(); 368ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 369ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 370ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 371ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return null; 372ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 373ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 374ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /** 375ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Element of the dex/resource file path 376ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 377ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /*package*/ static class Element { 3788dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath private final File file; 3798dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath private final File zip; 3808dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath private final DexFile dexFile; 381ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 3828dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath private ZipFile zipFile; 3838dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath private boolean init; 3848dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath 3858dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath public Element(File file, File zip, DexFile dexFile) { 386ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein this.file = file; 3878dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath this.zip = zip; 388ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein this.dexFile = dexFile; 389ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 390ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 3918dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath public synchronized void maybeInit() { 3928dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath if (init) { 3938dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath return; 3948dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath } 3958dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath 3968dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath init = true; 3978dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath 3988dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath if (zip == null) { 399ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /* 400ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * Either this element has no zip/jar file (first 401ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * clause), or the zip/jar file doesn't have an entry 402ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * for the given name (second clause). 403ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 4048dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath return; 4058dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath } 4068dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath 4078dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath try { 4088dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath zipFile = new ZipFile(zip); 4098dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath } catch (IOException ioe) { 4108dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath /* 4118dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath * Note: ZipException (a subclass of IOException) 4128dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath * might get thrown by the ZipFile constructor 4138dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath * (e.g. if the file isn't actually a zip/jar 4148dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath * file). 4158dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath */ 4168dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath System.logE("Unable to open zip file: " + file, ioe); 4178dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath zipFile = null; 4188dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath } 4198dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath } 4208dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath 4218dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath public URL findResource(String name) { 4228dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath maybeInit(); 4238dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath 4248dd90ae77922eb05d46c797937620a4c69f758f7Narayan Kamath if (zipFile == null || zipFile.getEntry(name) == null) { 425ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return null; 426ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 427ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein 428ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein try { 429ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein /* 430ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * File.toURL() is compliant with RFC 1738 in 431ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * always creating absolute path names. If we 432ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * construct the URL by concatenating strings, we 433ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * might end up with illegal URLs for relative 434ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein * names. 435ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein */ 436ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein return new URL("jar:" + file.toURL() + "!/" + name); 437ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } catch (MalformedURLException ex) { 438ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein throw new RuntimeException(ex); 439ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 440ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 441ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein } 442ea52753a0f80fcd70acfe9150ecb854511ff38dbDan Bornstein} 443