Home | History | Annotate | Download | only in system
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package dalvik.system;
     18 
     19 import java.io.File;
     20 import java.net.URL;
     21 import java.util.ArrayList;
     22 import java.util.Enumeration;
     23 import java.util.List;
     24 
     25 /**
     26  * Base class for common functionality between various dex-based
     27  * {@link ClassLoader} implementations.
     28  */
     29 public class BaseDexClassLoader extends ClassLoader {
     30     private final DexPathList pathList;
     31 
     32     /**
     33      * Constructs an instance.
     34      *
     35      * @param dexPath the list of jar/apk files containing classes and
     36      * resources, delimited by {@code File.pathSeparator}, which
     37      * defaults to {@code ":"} on Android
     38      * @param optimizedDirectory directory where optimized dex files
     39      * should be written; may be {@code null}
     40      * @param libraryPath the list of directories containing native
     41      * libraries, delimited by {@code File.pathSeparator}; may be
     42      * {@code null}
     43      * @param parent the parent class loader
     44      */
     45     public BaseDexClassLoader(String dexPath, File optimizedDirectory,
     46             String libraryPath, ClassLoader parent) {
     47         super(parent);
     48         this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
     49     }
     50 
     51     @Override
     52     protected Class<?> findClass(String name) throws ClassNotFoundException {
     53         List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
     54         Class c = pathList.findClass(name, suppressedExceptions);
     55         if (c == null) {
     56             ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);
     57             for (Throwable t : suppressedExceptions) {
     58                 cnfe.addSuppressed(t);
     59             }
     60             throw cnfe;
     61         }
     62         return c;
     63     }
     64 
     65     @Override
     66     protected URL findResource(String name) {
     67         return pathList.findResource(name);
     68     }
     69 
     70     @Override
     71     protected Enumeration<URL> findResources(String name) {
     72         return pathList.findResources(name);
     73     }
     74 
     75     @Override
     76     public String findLibrary(String name) {
     77         return pathList.findLibrary(name);
     78     }
     79 
     80     /**
     81      * Returns package information for the given package.
     82      * Unfortunately, instances of this class don't really have this
     83      * information, and as a non-secure {@code ClassLoader}, it isn't
     84      * even required to, according to the spec. Yet, we want to
     85      * provide it, in order to make all those hopeful callers of
     86      * {@code myClass.getPackage().getName()} happy. Thus we construct
     87      * a {@code Package} object the first time it is being requested
     88      * and fill most of the fields with dummy values. The {@code
     89      * Package} object is then put into the {@code ClassLoader}'s
     90      * package cache, so we see the same one next time. We don't
     91      * create {@code Package} objects for {@code null} arguments or
     92      * for the default package.
     93      *
     94      * <p>There is a limited chance that we end up with multiple
     95      * {@code Package} objects representing the same package: It can
     96      * happen when when a package is scattered across different JAR
     97      * files which were loaded by different {@code ClassLoader}
     98      * instances. This is rather unlikely, and given that this whole
     99      * thing is more or less a workaround, probably not worth the
    100      * effort to address.
    101      *
    102      * @param name the name of the class
    103      * @return the package information for the class, or {@code null}
    104      * if there is no package information available for it
    105      */
    106     @Override
    107     protected synchronized Package getPackage(String name) {
    108         if (name != null && !name.isEmpty()) {
    109             Package pack = super.getPackage(name);
    110 
    111             if (pack == null) {
    112                 pack = definePackage(name, "Unknown", "0.0", "Unknown",
    113                         "Unknown", "0.0", "Unknown", null);
    114             }
    115 
    116             return pack;
    117         }
    118 
    119         return null;
    120     }
    121 
    122     /**
    123      * @hide
    124      */
    125     public String getLdLibraryPath() {
    126         StringBuilder result = new StringBuilder();
    127         for (File directory : pathList.getNativeLibraryDirectories()) {
    128             if (result.length() > 0) {
    129                 result.append(':');
    130             }
    131             result.append(directory);
    132         }
    133         return result.toString();
    134     }
    135 
    136     @Override public String toString() {
    137         return getClass().getName() + "[" + pathList + "]";
    138     }
    139 }
    140