DexPathList.java revision f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05
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; 302cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstromimport libcore.io.IoUtils; 312cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstromimport libcore.io.Libcore; 322ce899fcb81707dd5447a15c29c2c137697f2f5eNeil Fullerimport libcore.io.ClassPathURLStreamHandler; 332ce899fcb81707dd5447a15c29c2c137697f2f5eNeil Fuller 342ce899fcb81707dd5447a15c29c2c137697f2f5eNeil Fullerimport static android.system.OsConstants.S_ISDIR; 352cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 362cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom/** 372cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * A pair of lists of entries, associated with a {@code ClassLoader}. 382cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * One of the lists is a dex/resource path — typically referred 392cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * to as a "class path" — list, and the other names directories 402cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * containing native code libraries. Class path entries may be any of: 412cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * a {@code .jar} or {@code .zip} file containing an optional 422cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * top-level {@code classes.dex} file as well as arbitrary resources, 432cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * or a plain {@code .dex} file (with no possibility of associated 442cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * resources). 452cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * 462cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * <p>This class also contains methods to use these lists to look up 472cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * classes and resources.</p> 482cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 492cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom/*package*/ final class DexPathList { 502cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom private static final String DEX_SUFFIX = ".dex"; 51384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov private static final String zipSeparator = "!/"; 522cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 532cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** class definition context */ 542cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom private final ClassLoader definingContext; 552cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 562cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 572cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * List of dex/resource (class path) elements. 582cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Should be called pathElements, but the Facebook app uses reflection 592cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * to modify 'dexElements' (http://b/7726934). 602cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 61104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy private Element[] dexElements; 622cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 63384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov /** List of native library path elements. */ 64f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe private final NativeLibraryElement[] nativeLibraryPathElements; 65384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 66384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov /** List of application native library directories. */ 677694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov private final List<File> nativeLibraryDirectories; 682cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 69384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov /** List of system native library directories. */ 70384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov private final List<File> systemNativeLibraryDirectories; 71384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 722cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 731e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers * Exceptions thrown during creation of the dexElements list. 741e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers */ 75104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy private IOException[] dexElementsSuppressedExceptions; 761e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers 771e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers /** 782cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Constructs an instance. 792cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * 802cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @param definingContext the context in which any as-yet unresolved 812cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * classes should be defined 822cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @param dexPath list of dex/resource path elements, separated by 832cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * {@code File.pathSeparator} 84a2656629522f9d79e2dca7418ab5963f50d0fda8Dimitry Ivanov * @param librarySearchPath list of native library directory path elements, 852cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * separated by {@code File.pathSeparator} 862cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @param optimizedDirectory directory where optimized {@code .dex} files 872cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * should be found and written to, or {@code null} to use the default 882cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * system directory for same 892cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 902cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom public DexPathList(ClassLoader definingContext, String dexPath, 9119c3551836aedca51e7e016007efca18d030763bDimitry Ivanov String librarySearchPath, File optimizedDirectory) { 92384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 932cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (definingContext == null) { 942cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom throw new NullPointerException("definingContext == null"); 952cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 962cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 972cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (dexPath == null) { 982cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom throw new NullPointerException("dexPath == null"); 992cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 1002cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 1012cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (optimizedDirectory != null) { 1022cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (!optimizedDirectory.exists()) { 1032cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom throw new IllegalArgumentException( 1042cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom "optimizedDirectory doesn't exist: " 1052cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom + optimizedDirectory); 1062cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 1072cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 1082cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (!(optimizedDirectory.canRead() 1092cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom && optimizedDirectory.canWrite())) { 1102cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom throw new IllegalArgumentException( 1112cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom "optimizedDirectory not readable/writable: " 1122cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom + optimizedDirectory); 1132cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 1142cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 1152cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 1162cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom this.definingContext = definingContext; 117384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 1181e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>(); 1197694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov // save dexPath for BaseDexClassLoader 120384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, 12170fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier suppressedExceptions, definingContext); 122384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 123384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // Native libraries may exist in both the system and 124384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // application library paths, and we use this search order: 125384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // 126a2656629522f9d79e2dca7418ab5963f50d0fda8Dimitry Ivanov // 1. This class loader's library path for application libraries (librarySearchPath): 127384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // 1.1. Native library directories 128384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // 1.2. Path to libraries in apk-files 129384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // 2. The VM's library path from the system property for system libraries 130384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // also known as java.library.path 131384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // 132384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov // This order was reversed prior to Gingerbread; see http://b/2933456. 133a2656629522f9d79e2dca7418ab5963f50d0fda8Dimitry Ivanov this.nativeLibraryDirectories = splitPaths(librarySearchPath, false); 134384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov this.systemNativeLibraryDirectories = 135384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov splitPaths(System.getProperty("java.library.path"), true); 136384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov List<File> allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories); 137384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories); 138384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 139f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe this.nativeLibraryPathElements = makePathElements(allNativeLibraryDirectories); 140384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 1411e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers if (suppressedExceptions.size() > 0) { 1421e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers this.dexElementsSuppressedExceptions = 1431e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers suppressedExceptions.toArray(new IOException[suppressedExceptions.size()]); 1441e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers } else { 1451e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers dexElementsSuppressedExceptions = null; 1461e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers } 1472cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 1482cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 1492cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom @Override public String toString() { 150384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov List<File> allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories); 151384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories); 152384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 1537694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov File[] nativeLibraryDirectoriesArray = 154384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov allNativeLibraryDirectories.toArray( 155384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov new File[allNativeLibraryDirectories.size()]); 1567694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov 1572cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return "DexPathList[" + Arrays.toString(dexElements) + 1587694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov ",nativeLibraryDirectories=" + Arrays.toString(nativeLibraryDirectoriesArray) + "]"; 1592cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 1602cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 1612cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 1622cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * For BaseDexClassLoader.getLdLibraryPath. 1632cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 1647694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov public List<File> getNativeLibraryDirectories() { 1652cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return nativeLibraryDirectories; 1662cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 1672cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 1682cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 169104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy * Adds a new path to this instance 170104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy * @param dexPath list of dex/resource path element, separated by 171104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy * {@code File.pathSeparator} 172104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy * @param optimizedDirectory directory where optimized {@code .dex} files 173104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy * should be found and written to, or {@code null} to use the default 174104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy * system directory for same 175104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy */ 176104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy public void addDexPath(String dexPath, File optimizedDirectory) { 177104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy final List<IOException> suppressedExceptionList = new ArrayList<IOException>(); 178104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy final Element[] newElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, 179104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy suppressedExceptionList, definingContext); 180104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy 181104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy if (newElements != null && newElements.length > 0) { 182104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy final Element[] oldElements = dexElements; 183104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy dexElements = new Element[oldElements.length + newElements.length]; 184104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy System.arraycopy( 185104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy oldElements, 0, dexElements, 0, oldElements.length); 186104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy System.arraycopy( 187104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy newElements, 0, dexElements, oldElements.length, newElements.length); 188104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy } 189104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy 190104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy if (suppressedExceptionList.size() > 0) { 191104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy final IOException[] newSuppressedExceptions = suppressedExceptionList.toArray( 192104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy new IOException[suppressedExceptionList.size()]); 193104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy if (dexElementsSuppressedExceptions != null) { 194104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy final IOException[] oldSuppressedExceptions = dexElementsSuppressedExceptions; 195104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy final int suppressedExceptionsLength = oldSuppressedExceptions.length + 196104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy newSuppressedExceptions.length; 197104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy dexElementsSuppressedExceptions = new IOException[suppressedExceptionsLength]; 198104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy System.arraycopy(oldSuppressedExceptions, 0, dexElementsSuppressedExceptions, 199104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy 0, oldSuppressedExceptions.length); 200104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy System.arraycopy(newSuppressedExceptions, 0, dexElementsSuppressedExceptions, 201104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy oldSuppressedExceptions.length, newSuppressedExceptions.length); 202104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy } else { 203104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy dexElementsSuppressedExceptions = newSuppressedExceptions; 204104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy } 205104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy } 206104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy } 207104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy 208104fb10863f65fe04af2b40526d0d0abe3ba3e92Todd Kennedy /** 2092cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Splits the given dex path string into elements using the path 2102cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * separator, pruning out any elements that do not refer to existing 211384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov * and readable files. 2122cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 2137694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov private static List<File> splitDexPath(String path) { 214384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov return splitPaths(path, false); 2152cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 2162cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 2172cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 2182cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Splits the given path strings into file elements using the path 2192cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * separator, combining the results and filtering out elements 2202cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * that don't exist, aren't readable, or aren't either a regular 2212cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * file or a directory (as specified). Either string may be empty 2222cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * or {@code null}, in which case it is ignored. If both strings 2232cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * are empty or {@code null}, or all elements get pruned out, then 2242cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * this returns a zero-element list. 2252cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 226384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov private static List<File> splitPaths(String searchPath, boolean directoriesOnly) { 227384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov List<File> result = new ArrayList<>(); 2282cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 229384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov if (searchPath != null) { 230384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov for (String path : searchPath.split(File.pathSeparator)) { 231384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov if (directoriesOnly) { 232384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov try { 233384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov StructStat sb = Libcore.os.stat(path); 234384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov if (!S_ISDIR(sb.st_mode)) { 235384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov continue; 236384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } 237384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } catch (ErrnoException ignored) { 238384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov continue; 239384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } 2402cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 241384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov result.add(new File(path)); 2422cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 2432cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 244384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 245384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov return result; 2462cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 2472cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 2482cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 2492cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Makes an array of dex/resource path elements, one per element of 2502cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * the given array. 2512cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 2527694b783f48e2cc57928b61c84fd90311cb0c35aDmitriy Ivanov private static Element[] makeDexElements(List<File> files, File optimizedDirectory, 253f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe List<IOException> suppressedExceptions, ClassLoader loader) { 254f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe Element[] elements = new Element[files.size()]; 255f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe int elementsPos = 0; 256f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe /* 257f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * Open all files and load the (direct or contained) dex files up front. 258f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe */ 259f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe for (File file : files) { 260f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (file.isDirectory()) { 261f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe // We support directories for looking up resources. Looking up resources in 262f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe // directories is useful for running libcore tests. 263f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe elements[elementsPos++] = new Element(file); 264f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } else if (file.isFile()) { 265f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe String name = file.getName(); 266f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 267f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (name.endsWith(DEX_SUFFIX)) { 268f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe // Raw dex file (not inside a zip/jar). 269f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe try { 270f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe DexFile dex = loadDexFile(file, optimizedDirectory, loader, elements); 271f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (dex != null) { 272f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe elements[elementsPos++] = new Element(dex, null); 273f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 274f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } catch (IOException suppressed) { 275f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe System.logE("Unable to load dex file: " + file, suppressed); 276f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe suppressedExceptions.add(suppressed); 277f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 278f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } else { 279f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe DexFile dex = null; 280f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe try { 281f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe dex = loadDexFile(file, optimizedDirectory, loader, elements); 282f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } catch (IOException suppressed) { 283f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe /* 284f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * IOException might get thrown "legitimately" by the DexFile constructor if 285f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * the zip file turns out to be resource-only (that is, no classes.dex file 286f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * in it). 287f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * Let dex == null and hang on to the exception to add to the tea-leaves for 288f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * when findClass returns null. 289f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe */ 290f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe suppressedExceptions.add(suppressed); 291f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 292f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 293f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (dex == null) { 294f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe elements[elementsPos++] = new Element(file); 295f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } else { 296f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe elements[elementsPos++] = new Element(dex, file); 297f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 298f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 299f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } else { 300f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe System.logW("ClassLoader referenced unknown path: " + file); 301f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 302f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 303f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (elementsPos != elements.length) { 304f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe elements = Arrays.copyOf(elements, elementsPos); 305f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 306f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return elements; 3072cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 3082cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 3092cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 31070fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier * Constructs a {@code DexFile} instance, as appropriate depending on whether 31170fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier * {@code optimizedDirectory} is {@code null}. An application image file may be associated with 31270fcc38e7a03f04864499a7356ae1f1e692b7463Mathieu Chartier * the {@code loader} if it is not null. 3132cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 314da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier private static DexFile loadDexFile(File file, File optimizedDirectory, ClassLoader loader, 315da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier Element[] elements) 3162cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom throws IOException { 3172cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (optimizedDirectory == null) { 318da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier return new DexFile(file, loader, elements); 3192cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } else { 3202cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom String optimizedPath = optimizedPathFor(file, optimizedDirectory); 321da3729f76948e5c7ce5eadbdfc03a0f9fe7d4d83Mathieu Chartier return DexFile.loadDex(file.getPath(), optimizedPath, 0, loader, elements); 3222cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 3232cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 3242cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 3252cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 3262cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Converts a dex/jar file path and an output directory to an 327ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * output file path for an associated optimized dex file. 3282cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 3292cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom private static String optimizedPathFor(File path, 3302cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom File optimizedDirectory) { 331ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom /* 332ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * Get the filename component of the path, and replace the 333ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * suffix with ".dex" if that's not already the suffix. 334ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * 335ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * We don't want to use ".odex", because the build system uses 336ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * that for files that are paired with resource-only jar 337ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * files. If the VM can assume that there's no classes.dex in 338ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * the matching jar, it doesn't need to open the jar to check 339ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * for updated dependencies, providing a slight performance 340ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * boost at startup. The use of ".dex" here matches the use on 341ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom * files in /data/dalvik-cache. 342ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom */ 343ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom String fileName = path.getName(); 344ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom if (!fileName.endsWith(DEX_SUFFIX)) { 345ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom int lastDot = fileName.lastIndexOf("."); 346ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom if (lastDot < 0) { 347ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom fileName += DEX_SUFFIX; 348ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom } else { 349ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom StringBuilder sb = new StringBuilder(lastDot + 4); 350ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom sb.append(fileName, 0, lastDot); 351ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom sb.append(DEX_SUFFIX); 352ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom fileName = sb.toString(); 353ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom } 354ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom } 355ca2c58ceaf2d35d30fe06b1676cc1436a24c4d30Brian Carlstrom 3562cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom File result = new File(optimizedDirectory, fileName); 3572cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return result.getPath(); 3582cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 3592cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 360f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe /* 361f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * TODO (dimitry): Revert after apps stops relying on the existence of this 362f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * method (see http://b/21957414 and http://b/26317852 for details) 363f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe */ 364f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe @SuppressWarnings("unused") 365f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe private static Element[] makePathElements(List<File> files, File optimizedDirectory, 366f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe List<IOException> suppressedExceptions) { 367f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return makeDexElements(files, optimizedDirectory, suppressedExceptions, null); 368f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 369f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 370f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe /** 371f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * Makes an array of directory/zip path elements for the native library search path, one per 372f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * element of the given array. 373f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe */ 374f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe private static NativeLibraryElement[] makePathElements(List<File> files) { 375f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe NativeLibraryElement[] elements = new NativeLibraryElement[files.size()]; 376f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe int elementsPos = 0; 377f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe for (File file : files) { 378f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe String path = file.getPath(); 379f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 380f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (path.contains(zipSeparator)) { 381f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe String split[] = path.split(zipSeparator, 2); 382f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe File zip = new File(split[0]); 383f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe String dir = split[1]; 384f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe elements[elementsPos++] = new NativeLibraryElement(zip, dir); 385f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } else if (file.isDirectory()) { 386f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe // We support directories for looking up native libraries. 387f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe elements[elementsPos++] = new NativeLibraryElement(file); 388f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } else { 389f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe System.logW("ClassLoader referenced unknown path: " + file); 390f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 391f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 392f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (elementsPos != elements.length) { 393f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe elements = Arrays.copyOf(elements, elementsPos); 394f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 395f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return elements; 396f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 397f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 3982cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 3992cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Finds the named class in one of the dex files pointed at by 4002cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * this instance. This will find the one in the earliest listed 4012cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * path element. If the class is found but has not yet been 4022cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * defined, then this method will define it in the defining 4032cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * context that this instance was constructed with. 4042cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * 4052cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @param name of class to find 4062cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @param suppressed exceptions encountered whilst finding the class 4072cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @return the named class or {@code null} if the class is not 4082cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * found in any of the dex files 4092cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 410f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe public Class<?> findClass(String name, List<Throwable> suppressed) { 4112cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom for (Element element : dexElements) { 412f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe Class<?> clazz = element.findClass(name, definingContext, suppressed); 413f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (clazz != null) { 414f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return clazz; 4152cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4162cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 417f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 4181e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers if (dexElementsSuppressedExceptions != null) { 4191e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions)); 4201e93f6737ef1a3540c8ce19c4fe3fa2efcdc1c78Ian Rogers } 4212cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return null; 4222cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4232cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4242cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 4252cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Finds the named resource in one of the zip/jar files pointed at 4262cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * by this instance. This will find the one in the earliest listed 4272cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * path element. 4282cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * 4292cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @return a URL to the named resource or {@code null} if the 4302cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * resource is not found in any of the zip/jar files 4312cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 4322cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom public URL findResource(String name) { 4332cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom for (Element element : dexElements) { 4342cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom URL url = element.findResource(name); 4352cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (url != null) { 4362cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return url; 4372cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4382cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4392cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4402cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return null; 4412cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4422cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4432cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 4442cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Finds all the resources with the given name, returning an 4452cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * enumeration of them. If there are no resources with the given 4462cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * name, then this method returns an empty enumeration. 4472cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 4482cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom public Enumeration<URL> findResources(String name) { 4492cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom ArrayList<URL> result = new ArrayList<URL>(); 4502cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4512cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom for (Element element : dexElements) { 4522cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom URL url = element.findResource(name); 4532cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (url != null) { 4542cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom result.add(url); 4552cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4562cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4572cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4582cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return Collections.enumeration(result); 4592cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4602cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4612cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 4622cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Finds the named native code library on any of the library 4632cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * directories pointed at by this instance. This will find the 4642cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * one in the earliest listed directory, ignoring any that are not 4652cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * readable regular files. 4662cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * 4672cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * @return the complete path to the library or {@code null} if no 4682cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * library was found 4692cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 4702cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom public String findLibrary(String libraryName) { 4712cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom String fileName = System.mapLibraryName(libraryName); 472384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 473f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe for (NativeLibraryElement element : nativeLibraryPathElements) { 474384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov String path = element.findNativeLibrary(fileName); 475384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 476384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov if (path != null) { 4772cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return path; 4782cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4792cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 480384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 4812cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return null; 4822cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 4832cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4842cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /** 485f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * Element of the dex/resource path. Note: should be called DexElement, but apps reflect on 486f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * this. 4872cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 4882cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /*package*/ static class Element { 489f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe /** 490f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * A file denoting a zip file (in case of a resource jar or a dex jar), or a directory 491f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * (only when dexFile is null). 492f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe */ 493f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe private final File path; 494f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 4952cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom private final DexFile dexFile; 4962cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 4972ce899fcb81707dd5447a15c29c2c137697f2f5eNeil Fuller private ClassPathURLStreamHandler urlHandler; 4982cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom private boolean initialized; 4992cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 500f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe /** 501f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * Element encapsulates a dex file. This may be a plain dex file (in which case dexZipPath 502f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * should be null), or a jar (in which case dexZipPath should denote the zup file). 503f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe */ 504f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe public Element(DexFile dexFile, File dexZipPath) { 5052cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom this.dexFile = dexFile; 506f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe this.path = dexZipPath; 507f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 508f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 509f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe public Element(File path) { 510f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe this.path = path; 511f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe this.dexFile = null; 5122cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5132cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 514f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe @Override 515f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe public String toString() { 516f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (dexFile == null) { 517f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return (path.isDirectory() ? "directory \"" : "zip file \"") + path + "\""; 5182cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } else { 519f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (path == null) { 5202cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return "dex file \"" + dexFile + "\""; 521f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } else { 522f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return "zip file \"" + path + "\""; 523f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 5242cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5252cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5262cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 5272cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom public synchronized void maybeInit() { 5282cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (initialized) { 5292cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return; 5302cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5312cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom initialized = true; 5322cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 533f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (path == null || path.isDirectory()) { 5342cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return; 5352cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5362cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 5372cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom try { 538f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe urlHandler = new ClassPathURLStreamHandler(path.getPath()); 5392cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } catch (IOException ioe) { 5402cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom /* 5412cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * Note: ZipException (a subclass of IOException) 5422cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * might get thrown by the ZipFile constructor 5432cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * (e.g. if the file isn't actually a zip/jar 5442cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom * file). 5452cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 546f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe System.logE("Unable to open zip file: " + path, ioe); 547384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov urlHandler = null; 548384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } 549384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov } 550384730cb57f41235f09829355d7ce67132625f7fDmitriy Ivanov 551f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe public Class<?> findClass(String name, ClassLoader definingContext, 552f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe List<Throwable> suppressed) { 553f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return dexFile != null ? dexFile.loadClassBinaryName(name, definingContext, suppressed) 554f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe : null; 5552cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5562cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 5572cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom public URL findResource(String name) { 5582cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom maybeInit(); 5592cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 560f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (urlHandler != null) { 561f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return urlHandler.getEntryUrlOrNull(name); 562f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 563f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 5642cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom // We support directories so we can run tests and/or legacy code 5652cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom // that uses Class.getResource. 566f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (path != null && path.isDirectory()) { 567f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe File resourceFile = new File(path, name); 5682cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom if (resourceFile.exists()) { 5692cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom try { 5702cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom return resourceFile.toURI().toURL(); 5712cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } catch (MalformedURLException ex) { 5722cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom throw new RuntimeException(ex); 5732cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5742cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5752cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 5762cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom 577f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return null; 578f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 579f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 580f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 581f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe /** 582f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * Element of the native library path 583f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe */ 584f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe /*package*/ static class NativeLibraryElement { 585f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe /** 586f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * A file denoting a directory or zip file. 587f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe */ 588f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe private final File path; 589f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 590f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe /** 591f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * If path denotes a zip file, this denotes a base path inside the zip. 592f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe */ 593f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe private final String zipDir; 594f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 595f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe private ClassPathURLStreamHandler urlHandler; 596f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe private boolean initialized; 597f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 598f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe public NativeLibraryElement(File dir) { 599f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe this.path = dir; 600f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe this.zipDir = null; 601f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 602f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe // We should check whether path is a directory, but that is non-eliminatable overhead. 603f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 604f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 605f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe public NativeLibraryElement(File zip, String zipDir) { 606f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe this.path = zip; 607f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe this.zipDir = zipDir; 608f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 609f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe // Simple check that should be able to be eliminated by inlining. We should also 610f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe // check whether path is a file, but that is non-eliminatable overhead. 611f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (zipDir == null) { 612f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe throw new IllegalArgumentException(); 613f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 614f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 615f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 616f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe @Override 617f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe public String toString() { 618f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (zipDir == null) { 619f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return "directory \"" + path + "\""; 620f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } else { 621f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return "zip file \"" + path + "\"" + 622f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe (!zipDir.isEmpty() ? ", dir \"" + zipDir + "\"" : ""); 623f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 624f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 625f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 626f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe public synchronized void maybeInit() { 627f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (initialized) { 628f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return; 629f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 630f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe initialized = true; 631f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 632f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (zipDir == null) { 633f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return; 634f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 635f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 636f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe try { 637f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe urlHandler = new ClassPathURLStreamHandler(path.getPath()); 638f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } catch (IOException ioe) { 639f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe /* 640f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * Note: ZipException (a subclass of IOException) 641f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * might get thrown by the ZipFile constructor 642f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * (e.g. if the file isn't actually a zip/jar 643f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe * file). 6442cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom */ 645f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe System.logE("Unable to open zip file: " + path, ioe); 646f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe urlHandler = null; 647f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 648f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 649f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 650f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe public String findNativeLibrary(String name) { 651f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe maybeInit(); 652f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 653f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (zipDir == null) { 654f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe String entryPath = new File(path, name).getPath(); 655f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (IoUtils.canOpenReadOnly(entryPath)) { 656f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return entryPath; 657f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 658f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } else if (urlHandler != null) { 659f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe // Having a urlHandler means the element has a zip file. 660f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe // In this case Android supports loading the library iff 661f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe // it is stored in the zip uncompressed. 662f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe String entryName = zipDir + '/' + name; 663f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe if (urlHandler.isEntryStored(entryName)) { 664f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return path.getPath() + zipSeparator + entryName; 665f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe } 6662cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 667f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe 668f2e5d9ce27779b4c047f1c1ba8af32fd26d2ae05Andreas Gampe return null; 6691a796cbc5dfb263511f2f4e5213adbc1d396a813Neil Fuller } 6702cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom } 6712cf03dc15c40b92634ff606694af5a6e9aa4db09Brian Carlstrom} 672