/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dalvik.system; import java.io.File; import java.net.URL; import java.util.Enumeration; /** * Base class for common functionality between various dex-based * {@link ClassLoader} implementations. */ public class BaseDexClassLoader extends ClassLoader { /** originally specified path (just used for {@code toString()}) */ private final String originalPath; /** originally specified library path (just used for {@code toString()}) */ private final String originalLibraryPath; /** structured lists of path elements */ private final DexPathList pathList; /** * Constructs an instance. * * @param dexPath the list of jar/apk files containing classes and * resources, delimited by {@code File.pathSeparator}, which * defaults to {@code ":"} on Android * @param optimizedDirectory directory where optimized dex files * should be written; may be {@code null} * @param libraryPath the list of directories containing native * libraries, delimited by {@code File.pathSeparator}; may be * {@code null} * @param parent the parent class loader */ public BaseDexClassLoader(String dexPath, File optimizedDirectory, String libraryPath, ClassLoader parent) { super(parent); this.originalPath = dexPath; this.originalLibraryPath = libraryPath; this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory); } @Override protected Class findClass(String name) throws ClassNotFoundException { Class clazz = pathList.findClass(name); if (clazz == null) { throw new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + originalPath); } return clazz; } @Override protected URL findResource(String name) { return pathList.findResource(name); } @Override protected Enumeration findResources(String name) { return pathList.findResources(name); } @Override public String findLibrary(String name) { return pathList.findLibrary(name); } /** * Returns package information for the given package. * Unfortunately, instances of this class don't really have this * information, and as a non-secure {@code ClassLoader}, it isn't * even required to, according to the spec. Yet, we want to * provide it, in order to make all those hopeful callers of * {@code myClass.getPackage().getName()} happy. Thus we construct * a {@code Package} object the first time it is being requested * and fill most of the fields with dummy values. The {@code * Package} object is then put into the {@code ClassLoader}'s * package cache, so we see the same one next time. We don't * create {@code Package} objects for {@code null} arguments or * for the default package. * *

There is a limited chance that we end up with multiple * {@code Package} objects representing the same package: It can * happen when when a package is scattered across different JAR * files which were loaded by different {@code ClassLoader} * instances. This is rather unlikely, and given that this whole * thing is more or less a workaround, probably not worth the * effort to address. * * @param name the name of the class * @return the package information for the class, or {@code null} * if there is no package information available for it */ @Override protected synchronized Package getPackage(String name) { if (name != null && !name.isEmpty()) { Package pack = super.getPackage(name); if (pack == null) { pack = definePackage(name, "Unknown", "0.0", "Unknown", "Unknown", "0.0", "Unknown", null); } return pack; } return null; } @Override public String toString() { return getClass().getName() + "[dexPath=" + originalPath + ",libraryPath=" + originalLibraryPath + "]"; } }