DexPathList.java revision 19c3551836aedca51e7e016007efca18d030763b
12cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom/* 22cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Copyright (C) 2011 The Android Open Source Project 32cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * 42cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License"); 52cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * you may not use this file except in compliance with the License. 62cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * You may obtain a copy of the License at 72cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * 82cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * http://www.apache.org/licenses/LICENSE-2.0 92cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * 102cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Unless required by applicable law or agreed to in writing, software 112cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS, 122cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * See the License for the specific language governing permissions and 142cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * limitations under the License. 152cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 162cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 172cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrompackage dalvik.system; 182cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 195d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.system.ErrnoException; 205d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.system.StructStat; 212cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstromimport java.io.File; 222cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstromimport java.io.IOException; 232cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstromimport java.net.MalformedURLException; 242cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstromimport java.net.URL; 252cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstromimport java.util.ArrayList; 262cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstromimport java.util.Arrays; 272cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstromimport java.util.Collections; 282cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstromimport java.util.Enumeration; 292cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstromimport java.util.List; 30384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanovimport java.util.zip.ZipEntry; 312cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstromimport libcore.io.IoUtils; 322cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstromimport libcore.io.Libcore; 332ce899fcb81707dd5447a15c29c2c137697f2f5eNeil Fullerimport libcore.io.ClassPathURLStreamHandler; 342ce899fcb81707dd5447a15c29c2c137697f2f5eNeil Fuller 352ce899fcb81707dd5447a15c29c2c137697f2f5eNeil Fullerimport static android.system.OsConstants.S_ISDIR; 362cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 372cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom/** 382cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * A pair of lists of entries, associated with a {@code ClassLoader}. 392cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * One of the lists is a dex/resource path — typically referred 402cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * to as a "class path" — list, and the other names directories 412cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * containing native code libraries. Class path entries may be any of: 422cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * a {@code .jar} or {@code .zip} file containing an optional 432cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * top-level {@code classes.dex} file as well as arbitrary resources, 442cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * or a plain {@code .dex} file (with no possibility of associated 452cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * resources). 462cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * 472cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * <p>This class also contains methods to use these lists to look up 482cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * classes and resources.</p> 492cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 502cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom/*package*/ final class DexPathList { 512cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom private static final String DEX_SUFFIX = ".dex"; 52384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov private static final String zipSeparator = "!/"; 532cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 542cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** class definition context */ 552cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom private final ClassLoader definingContext; 562cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 572cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 582cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * List of dex/resource (class path) elements. 592cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Should be called pathElements, but the Facebook app uses reflection 602cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * to modify 'dexElements' (http://b/7726934). 612cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 62104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy private Element[] dexElements; 632cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 64384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov /** List of native library path elements. */ 65384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov private final Element[] nativeLibraryPathElements; 66384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 67384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov /** List of application native library directories. */ 687694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov private final List<File> nativeLibraryDirectories; 692cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 70384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov /** List of system native library directories. */ 71384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov private final List<File> systemNativeLibraryDirectories; 72384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 732cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 741e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers * Exceptions thrown during creation of the dexElements list. 751e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers */ 76104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy private IOException[] dexElementsSuppressedExceptions; 771e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers 781e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers /** 792cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Constructs an instance. 802cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * 812cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @param definingContext the context in which any as-yet unresolved 822cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * classes should be defined 832cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @param dexPath list of dex/resource path elements, separated by 842cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * {@code File.pathSeparator} 85a2656629522f9d79e2dca7418ab5963f50d0fda8Dimitry Ivanov * @param librarySearchPath list of native library directory path elements, 862cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * separated by {@code File.pathSeparator} 87a2656629522f9d79e2dca7418ab5963f50d0fda8Dimitry Ivanov * @param libraryPermittedPath is path containing permitted directories for 88a2656629522f9d79e2dca7418ab5963f50d0fda8Dimitry Ivanov * linker isolated namespaces (in addition to librarySearchPath which is allowed 89a2656629522f9d79e2dca7418ab5963f50d0fda8Dimitry Ivanov * implicitly). Note that this path does not affect the search order for the library 90a2656629522f9d79e2dca7418ab5963f50d0fda8Dimitry Ivanov * and intended for white-listing additional paths when loading native libraries 91a2656629522f9d79e2dca7418ab5963f50d0fda8Dimitry Ivanov * by absolute path. 922cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @param optimizedDirectory directory where optimized {@code .dex} files 932cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * should be found and written to, or {@code null} to use the default 942cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * system directory for same 952cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 962cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom public DexPathList(ClassLoader definingContext, String dexPath, 9719c3551836aedca51e7e016007efca18d030763bDimitry Ivanov String librarySearchPath, File optimizedDirectory) { 98384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 992cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (definingContext == null) { 1002cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom throw new NullPointerException("definingContext == null"); 1012cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 1022cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 1032cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (dexPath == null) { 1042cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom throw new NullPointerException("dexPath == null"); 1052cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 1062cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 1072cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (optimizedDirectory != null) { 1082cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (!optimizedDirectory.exists()) { 1092cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom throw new IllegalArgumentException( 1102cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom "optimizedDirectory doesn't exist: " 1112cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom + optimizedDirectory); 1122cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 1132cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 1142cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (!(optimizedDirectory.canRead() 1152cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom && optimizedDirectory.canWrite())) { 1162cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom throw new IllegalArgumentException( 1172cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom "optimizedDirectory not readable/writable: " 1182cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom + optimizedDirectory); 1192cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 1202cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 1212cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 1222cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom this.definingContext = definingContext; 123384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 1241e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>(); 1257694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov // save dexPath for BaseDexClassLoader 126384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, 12770fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier suppressedExceptions, definingContext); 128384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 129384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // Native libraries may exist in both the system and 130384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // application library paths, and we use this search order: 131384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // 132a2656629522f9d79e2dca7418ab5963f50d0fda8Dimitry Ivanov // 1. This class loader's library path for application libraries (librarySearchPath): 133384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // 1.1. Native library directories 134384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // 1.2. Path to libraries in apk-files 135384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // 2. The VM's library path from the system property for system libraries 136384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // also known as java.library.path 137384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // 138384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // This order was reversed prior to Gingerbread; see http://b/2933456. 139a2656629522f9d79e2dca7418ab5963f50d0fda8Dimitry Ivanov this.nativeLibraryDirectories = splitPaths(librarySearchPath, false); 140384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov this.systemNativeLibraryDirectories = 141384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov splitPaths(System.getProperty("java.library.path"), true); 142384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov List<File> allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories); 143384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories); 144384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 145384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories, 14670fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier suppressedExceptions, 14770fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier definingContext); 148384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 1491e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers if (suppressedExceptions.size() > 0) { 1501e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers this.dexElementsSuppressedExceptions = 1511e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers suppressedExceptions.toArray(new IOException[suppressedExceptions.size()]); 1521e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers } else { 1531e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers dexElementsSuppressedExceptions = null; 1541e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers } 1552cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 1562cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 1572cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom @Override public String toString() { 158384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov List<File> allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories); 159384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories); 160384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 1617694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov File[] nativeLibraryDirectoriesArray = 162384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov allNativeLibraryDirectories.toArray( 163384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov new File[allNativeLibraryDirectories.size()]); 1647694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov 1652cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return "DexPathList[" + Arrays.toString(dexElements) + 1667694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov ",nativeLibraryDirectories=" + Arrays.toString(nativeLibraryDirectoriesArray) + "]"; 1672cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 1682cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 1692cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 1702cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * For BaseDexClassLoader.getLdLibraryPath. 1712cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 1727694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov public List<File> getNativeLibraryDirectories() { 1732cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return nativeLibraryDirectories; 1742cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 1752cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 1762cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 177104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy * Adds a new path to this instance 178104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy * @param dexPath list of dex/resource path element, separated by 179104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy * {@code File.pathSeparator} 180104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy * @param optimizedDirectory directory where optimized {@code .dex} files 181104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy * should be found and written to, or {@code null} to use the default 182104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy * system directory for same 183104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy */ 184104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy public void addDexPath(String dexPath, File optimizedDirectory) { 185104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy final List<IOException> suppressedExceptionList = new ArrayList<IOException>(); 186104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy final Element[] newElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, 187104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy suppressedExceptionList, definingContext); 188104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy 189104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy if (newElements != null && newElements.length > 0) { 190104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy final Element[] oldElements = dexElements; 191104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy dexElements = new Element[oldElements.length + newElements.length]; 192104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy System.arraycopy( 193104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy oldElements, 0, dexElements, 0, oldElements.length); 194104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy System.arraycopy( 195104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy newElements, 0, dexElements, oldElements.length, newElements.length); 196104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy } 197104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy 198104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy if (suppressedExceptionList.size() > 0) { 199104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy final IOException[] newSuppressedExceptions = suppressedExceptionList.toArray( 200104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy new IOException[suppressedExceptionList.size()]); 201104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy if (dexElementsSuppressedExceptions != null) { 202104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy final IOException[] oldSuppressedExceptions = dexElementsSuppressedExceptions; 203104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy final int suppressedExceptionsLength = oldSuppressedExceptions.length + 204104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy newSuppressedExceptions.length; 205104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy dexElementsSuppressedExceptions = new IOException[suppressedExceptionsLength]; 206104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy System.arraycopy(oldSuppressedExceptions, 0, dexElementsSuppressedExceptions, 207104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy 0, oldSuppressedExceptions.length); 208104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy System.arraycopy(newSuppressedExceptions, 0, dexElementsSuppressedExceptions, 209104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy oldSuppressedExceptions.length, newSuppressedExceptions.length); 210104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy } else { 211104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy dexElementsSuppressedExceptions = newSuppressedExceptions; 212104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy } 213104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy } 214104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy } 215104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy 216104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy /** 2172cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Splits the given dex path string into elements using the path 2182cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * separator, pruning out any elements that do not refer to existing 219384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov * and readable files. 2202cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 2217694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov private static List<File> splitDexPath(String path) { 222384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov return splitPaths(path, false); 2232cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 2242cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 2252cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 2262cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Splits the given path strings into file elements using the path 2272cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * separator, combining the results and filtering out elements 2282cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * that don't exist, aren't readable, or aren't either a regular 2292cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * file or a directory (as specified). Either string may be empty 2302cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * or {@code null}, in which case it is ignored. If both strings 2312cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * are empty or {@code null}, or all elements get pruned out, then 2322cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * this returns a zero-element list. 2332cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 234384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov private static List<File> splitPaths(String searchPath, boolean directoriesOnly) { 235384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov List<File> result = new ArrayList<>(); 2362cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 237384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov if (searchPath != null) { 238384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov for (String path : searchPath.split(File.pathSeparator)) { 239384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov if (directoriesOnly) { 240384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov try { 241384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov StructStat sb = Libcore.os.stat(path); 242384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov if (!S_ISDIR(sb.st_mode)) { 243384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov continue; 244384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } 245384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } catch (ErrnoException ignored) { 246384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov continue; 247384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } 2482cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 249384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov result.add(new File(path)); 2502cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 2512cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 252384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 253384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov return result; 2542cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 2552cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 2562cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 2572cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Makes an array of dex/resource path elements, one per element of 2582cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * the given array. 2592cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 2607694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov private static Element[] makeDexElements(List<File> files, File optimizedDirectory, 26170fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier List<IOException> suppressedExceptions, 26270fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier ClassLoader loader) { 26370fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier return makeElements(files, optimizedDirectory, suppressedExceptions, false, loader); 264384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } 265384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 266384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov /** 267384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov * Makes an array of directory/zip path elements, one per element of the given array. 268384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov */ 269384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov private static Element[] makePathElements(List<File> files, 27070fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier List<IOException> suppressedExceptions, 27170fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier ClassLoader loader) { 27270fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier return makeElements(files, null, suppressedExceptions, true, loader); 273384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } 274384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 275ac4309ac7ba48b85b6d301e95ae767a3bcb8f83eDmitriy Ivanov /* 276941742a1bf0e1fcde72525371a12828267c2d6bdDimitry Ivanov * TODO (dimitry): Revert after apps stops relying on the existence of this 277941742a1bf0e1fcde72525371a12828267c2d6bdDimitry Ivanov * method (see http://b/21957414 and http://b/26317852 for details) 278ac4309ac7ba48b85b6d301e95ae767a3bcb8f83eDmitriy Ivanov */ 279ac4309ac7ba48b85b6d301e95ae767a3bcb8f83eDmitriy Ivanov private static Element[] makePathElements(List<File> files, File optimizedDirectory, 280ac4309ac7ba48b85b6d301e95ae767a3bcb8f83eDmitriy Ivanov List<IOException> suppressedExceptions) { 281941742a1bf0e1fcde72525371a12828267c2d6bdDimitry Ivanov return makeElements(files, optimizedDirectory, suppressedExceptions, false, null); 282ac4309ac7ba48b85b6d301e95ae767a3bcb8f83eDmitriy Ivanov } 283ac4309ac7ba48b85b6d301e95ae767a3bcb8f83eDmitriy Ivanov 284384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov private static Element[] makeElements(List<File> files, File optimizedDirectory, 285384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov List<IOException> suppressedExceptions, 28670fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier boolean ignoreDexFiles, 28770fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier ClassLoader loader) { 288da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier Element[] elements = new Element[files.size()]; 289da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier int elementsPos = 0; 2902cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /* 2912cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Open all files and load the (direct or contained) dex files 2922cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * up front. 2932cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 2942cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom for (File file : files) { 2952cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom File zip = null; 296384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov File dir = new File(""); 2972cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom DexFile dex = null; 298384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov String path = file.getPath(); 2992cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom String name = file.getName(); 3002cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 301384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov if (path.contains(zipSeparator)) { 302384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov String split[] = path.split(zipSeparator, 2); 303384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov zip = new File(split[0]); 304384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov dir = new File(split[1]); 305384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } else if (file.isDirectory()) { 306384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // We support directories for looking up resources and native libraries. 307384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // Looking up resources in directories is useful for running libcore tests. 308da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier elements[elementsPos++] = new Element(file, true, null, null); 309384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } else if (file.isFile()) { 310384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov if (!ignoreDexFiles && name.endsWith(DEX_SUFFIX)) { 311bf5ea97806d25d7232a626c7603b88162a8a8c7aHui Lu // Raw dex file (not inside a zip/jar). 312bf5ea97806d25d7232a626c7603b88162a8a8c7aHui Lu try { 313da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier dex = loadDexFile(file, optimizedDirectory, loader, elements); 314bf5ea97806d25d7232a626c7603b88162a8a8c7aHui Lu } catch (IOException ex) { 315bf5ea97806d25d7232a626c7603b88162a8a8c7aHui Lu System.logE("Unable to load dex file: " + file, ex); 316bf5ea97806d25d7232a626c7603b88162a8a8c7aHui Lu } 317bf5ea97806d25d7232a626c7603b88162a8a8c7aHui Lu } else { 318bf5ea97806d25d7232a626c7603b88162a8a8c7aHui Lu zip = file; 319bf5ea97806d25d7232a626c7603b88162a8a8c7aHui Lu 320384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov if (!ignoreDexFiles) { 321384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov try { 322da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier dex = loadDexFile(file, optimizedDirectory, loader, elements); 323384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } catch (IOException suppressed) { 324384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov /* 325384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov * IOException might get thrown "legitimately" by the DexFile constructor if 326384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov * the zip file turns out to be resource-only (that is, no classes.dex file 327384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov * in it). 328384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov * Let dex == null and hang on to the exception to add to the tea-leaves for 329384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov * when findClass returns null. 330384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov */ 331384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov suppressedExceptions.add(suppressed); 332384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } 333bf5ea97806d25d7232a626c7603b88162a8a8c7aHui Lu } 334bf5ea97806d25d7232a626c7603b88162a8a8c7aHui Lu } 3352cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } else { 336bf5ea97806d25d7232a626c7603b88162a8a8c7aHui Lu System.logW("ClassLoader referenced unknown path: " + file); 3372cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 3382cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 3392cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if ((zip != null) || (dex != null)) { 340da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier elements[elementsPos++] = new Element(dir, false, zip, dex); 3412cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 3422cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 343da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier if (elementsPos != elements.length) { 344da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier elements = Arrays.copyOf(elements, elementsPos); 345da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier } 346da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier return elements; 3472cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 3482cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 3492cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 35070fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier * Constructs a {@code DexFile} instance, as appropriate depending on whether 35170fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier * {@code optimizedDirectory} is {@code null}. An application image file may be associated with 35270fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier * the {@code loader} if it is not null. 3532cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 354da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier private static DexFile loadDexFile(File file, File optimizedDirectory, ClassLoader loader, 355da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier Element[] elements) 3562cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom throws IOException { 3572cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (optimizedDirectory == null) { 358da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier return new DexFile(file, loader, elements); 3592cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } else { 3602cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom String optimizedPath = optimizedPathFor(file, optimizedDirectory); 361da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier return DexFile.loadDex(file.getPath(), optimizedPath, 0, loader, elements); 3622cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 3632cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 3642cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 3652cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 3662cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Converts a dex/jar file path and an output directory to an 367ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * output file path for an associated optimized dex file. 3682cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 3692cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom private static String optimizedPathFor(File path, 3702cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom File optimizedDirectory) { 371ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom /* 372ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * Get the filename component of the path, and replace the 373ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * suffix with ".dex" if that's not already the suffix. 374ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * 375ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * We don't want to use ".odex", because the build system uses 376ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * that for files that are paired with resource-only jar 377ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * files. If the VM can assume that there's no classes.dex in 378ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * the matching jar, it doesn't need to open the jar to check 379ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * for updated dependencies, providing a slight performance 380ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * boost at startup. The use of ".dex" here matches the use on 381ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * files in /data/dalvik-cache. 382ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom */ 383ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom String fileName = path.getName(); 384ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom if (!fileName.endsWith(DEX_SUFFIX)) { 385ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom int lastDot = fileName.lastIndexOf("."); 386ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom if (lastDot < 0) { 387ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom fileName += DEX_SUFFIX; 388ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom } else { 389ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom StringBuilder sb = new StringBuilder(lastDot + 4); 390ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom sb.append(fileName, 0, lastDot); 391ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom sb.append(DEX_SUFFIX); 392ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom fileName = sb.toString(); 393ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom } 394ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom } 395ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom 3962cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom File result = new File(optimizedDirectory, fileName); 3972cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return result.getPath(); 3982cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 3992cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4002cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 4012cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Finds the named class in one of the dex files pointed at by 4022cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * this instance. This will find the one in the earliest listed 4032cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * path element. If the class is found but has not yet been 4042cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * defined, then this method will define it in the defining 4052cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * context that this instance was constructed with. 4062cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * 4072cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @param name of class to find 4082cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @param suppressed exceptions encountered whilst finding the class 4092cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @return the named class or {@code null} if the class is not 4102cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * found in any of the dex files 4112cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 4122cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom public Class findClass(String name, List<Throwable> suppressed) { 4132cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom for (Element element : dexElements) { 4142cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom DexFile dex = element.dexFile; 4152cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4162cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (dex != null) { 4172cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed); 4182cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (clazz != null) { 4192cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return clazz; 4202cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4212cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4222cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4231e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers if (dexElementsSuppressedExceptions != null) { 4241e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions)); 4251e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers } 4262cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return null; 4272cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4282cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4292cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 4302cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Finds the named resource in one of the zip/jar files pointed at 4312cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * by this instance. This will find the one in the earliest listed 4322cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * path element. 4332cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * 4342cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @return a URL to the named resource or {@code null} if the 4352cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * resource is not found in any of the zip/jar files 4362cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 4372cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom public URL findResource(String name) { 4382cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom for (Element element : dexElements) { 4392cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom URL url = element.findResource(name); 4402cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (url != null) { 4412cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return url; 4422cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4432cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4442cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4452cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return null; 4462cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4472cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4482cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 4492cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Finds all the resources with the given name, returning an 4502cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * enumeration of them. If there are no resources with the given 4512cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * name, then this method returns an empty enumeration. 4522cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 4532cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom public Enumeration<URL> findResources(String name) { 4542cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom ArrayList<URL> result = new ArrayList<URL>(); 4552cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4562cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom for (Element element : dexElements) { 4572cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom URL url = element.findResource(name); 4582cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (url != null) { 4592cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom result.add(url); 4602cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4612cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4622cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4632cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return Collections.enumeration(result); 4642cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4652cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4662cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 4672cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Finds the named native code library on any of the library 4682cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * directories pointed at by this instance. This will find the 4692cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * one in the earliest listed directory, ignoring any that are not 4702cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * readable regular files. 4712cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * 4722cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @return the complete path to the library or {@code null} if no 4732cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * library was found 4742cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 4752cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom public String findLibrary(String libraryName) { 4762cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom String fileName = System.mapLibraryName(libraryName); 477384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 478384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov for (Element element : nativeLibraryPathElements) { 479384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov String path = element.findNativeLibrary(fileName); 480384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 481384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov if (path != null) { 4822cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return path; 4832cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4842cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 485384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 4862cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return null; 4872cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4882cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4892cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 490384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov * Element of the dex/resource/native library path 4912cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 4922cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /*package*/ static class Element { 493384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov private final File dir; 4942cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom private final boolean isDirectory; 4952cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom private final File zip; 4962cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom private final DexFile dexFile; 4972cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4982ce899fcb81707dd5447a15c29c2c137697f2f5eNeil Fuller private ClassPathURLStreamHandler urlHandler; 4992cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom private boolean initialized; 5002cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 501384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov public Element(File dir, boolean isDirectory, File zip, DexFile dexFile) { 502384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov this.dir = dir; 5032cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom this.isDirectory = isDirectory; 5042cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom this.zip = zip; 5052cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom this.dexFile = dexFile; 5062cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5072cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 5082cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom @Override public String toString() { 5092cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (isDirectory) { 510384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov return "directory \"" + dir + "\""; 5112cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } else if (zip != null) { 512384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov return "zip file \"" + zip + "\"" + 513384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov (dir != null && !dir.getPath().isEmpty() ? ", dir \"" + dir + "\"" : ""); 5142cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } else { 5152cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return "dex file \"" + dexFile + "\""; 5162cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5172cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5182cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 5192cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom public synchronized void maybeInit() { 5202cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (initialized) { 5212cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return; 5222cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5232cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 5242cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom initialized = true; 5252cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 5262cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (isDirectory || zip == null) { 5272cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return; 5282cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5292cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 5302cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom try { 5312ce899fcb81707dd5447a15c29c2c137697f2f5eNeil Fuller urlHandler = new ClassPathURLStreamHandler(zip.getPath()); 5322cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } catch (IOException ioe) { 5332cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /* 5342cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Note: ZipException (a subclass of IOException) 5352cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * might get thrown by the ZipFile constructor 5362cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * (e.g. if the file isn't actually a zip/jar 5372cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * file). 5382cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 539384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov System.logE("Unable to open zip file: " + zip, ioe); 540384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov urlHandler = null; 541384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } 542384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } 543384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 544384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov public String findNativeLibrary(String name) { 545384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov maybeInit(); 546384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 547384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov if (isDirectory) { 548384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov String path = new File(dir, name).getPath(); 549384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov if (IoUtils.canOpenReadOnly(path)) { 550384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov return path; 551384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } 552384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } else if (urlHandler != null) { 553384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // Having a urlHandler means the element has a zip file. 554384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // In this case Android supports loading the library iff 555384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // it is stored in the zip uncompressed. 556384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 557384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov String entryName = new File(dir, name).getPath(); 558384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov if (urlHandler.isEntryStored(entryName)) { 559384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov return zip.getPath() + zipSeparator + entryName; 560384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } 5612cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 562384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 563384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov return null; 5642cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5652cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 5662cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom public URL findResource(String name) { 5672cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom maybeInit(); 5682cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 5692cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom // We support directories so we can run tests and/or legacy code 5702cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom // that uses Class.getResource. 5712cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (isDirectory) { 572384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov File resourceFile = new File(dir, name); 5732cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (resourceFile.exists()) { 5742cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom try { 5752cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return resourceFile.toURI().toURL(); 5762cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } catch (MalformedURLException ex) { 5772cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom throw new RuntimeException(ex); 5782cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5792cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5802cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5812cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 5822ce899fcb81707dd5447a15c29c2c137697f2f5eNeil Fuller if (urlHandler == null) { 5832ce899fcb81707dd5447a15c29c2c137697f2f5eNeil Fuller /* This element has no zip/jar file. 5842cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 5852cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return null; 5862cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5872ce899fcb81707dd5447a15c29c2c137697f2f5eNeil Fuller return urlHandler.getEntryUrlOrNull(name); 5881a796cbc5dfb263511f2f4e5213adbc1d396a813Neil Fuller } 5892cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5902cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom} 591