1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage dalvik.system;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.File;
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.io.IOException;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.net.URL;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.zip.ZipFile;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.net.MalformedURLException;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport dalvik.system.DexFile;
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Provides a simple {@link ClassLoader} implementation that operates on a
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * list of jar/apk files with classes.dex entries.  The directory that
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * holds the optimized form of the files is specified explicitly.  This
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * can be used to execute code not installed as part of an application.
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * The best place to put the optimized DEX files is in app-specific
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * storage, so that removal of the app will automatically remove the
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * optimized DEX files.  If other storage is used (e.g. /sdcard), the
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * app may not have an opportunity to remove them.
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic class DexClassLoader extends ClassLoader {
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final boolean VERBOSE_DEBUG = false;
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* constructor args, held for init */
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final String mRawDexPath;
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final String mRawLibPath;
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final String mDexOutputPath;
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean mInitialized;
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Parallel arrays for jar/apk files.
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * (could stuff these into an object and have a single array;
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * improves clarity but adds overhead)
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private File[] mFiles;              // source file Files, for rsrc URLs
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private ZipFile[] mZips;            // source zip files, with resources
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private DexFile[] mDexs;            // opened, prepped DEX files
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Native library path.
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private String[] mLibPaths;
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Creates a {@code DexClassLoader} that finds interpreted and native
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * code.  Interpreted classes are found in a set of DEX files contained
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * in Jar or APK files.
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * The path lists are separated using the character specified by
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the "path.separator" system property, which defaults to ":".
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param dexPath
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *  the list of jar/apk files containing classes and resources
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param dexOutputDir
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *  directory where optimized DEX files should be written
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param libPath
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *  the list of directories containing native libraries; may be null
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param parent
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *  the parent class loader
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public DexClassLoader(String dexPath, String dexOutputDir, String libPath,
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ClassLoader parent) {
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        super(parent);
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dexPath == null || dexOutputDir == null)
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException();
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        mRawDexPath = dexPath;
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        mDexOutputPath = dexOutputDir;
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        mRawLibPath = libPath;
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Complete initialization on first use of the class loader.
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private synchronized void ensureInit() {
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (mInitialized) {
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String[] dexPathList;
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        mInitialized = true;
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dexPathList = mRawDexPath.split(":");
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int length = dexPathList.length;
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //System.out.println("DexClassLoader: " + dexPathList);
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        mFiles = new File[length];
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        mZips = new ZipFile[length];
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        mDexs = new DexFile[length];
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* open all Zip and DEX files up front */
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < length; i++) {
11744b801d9b1dbe13aa441f16443aff8f19ee56e1cElliott Hughes            //System.out.println("My path is: " + dexPathList[i]);
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            File pathFile = new File(dexPathList[i]);
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            mFiles[i] = pathFile;
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (pathFile.isFile()) {
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                try {
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    mZips[i] = new ZipFile(pathFile);
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } catch (IOException ioex) {
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    // expecting IOException and ZipException
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    System.out.println("Failed opening '" + pathFile
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        + "': " + ioex);
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    //ioex.printStackTrace();
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /* we need both DEX and Zip, because dex has no resources */
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                try {
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    String outputName =
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        generateOutputName(dexPathList[i], mDexOutputPath);
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    mDexs[i] = DexFile.loadDex(dexPathList[i], outputName, 0);
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } catch (IOException ioex) {
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    // might be a resource-only zip
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    System.out.println("Failed loadDex '" + pathFile
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        + "': " + ioex);
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (VERBOSE_DEBUG)
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    System.out.println("Not found: " + pathFile.getPath());
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Prep for native library loading.
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String pathList = System.getProperty("java.library.path", ".");
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String pathSep = System.getProperty("path.separator", ":");
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String fileSep = System.getProperty("file.separator", "/");
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (mRawLibPath != null) {
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (pathList.length() > 0) {
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                pathList += pathSep + mRawLibPath;
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            else {
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                pathList = mRawLibPath;
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        mLibPaths = pathList.split(pathSep);
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        length = mLibPaths.length;
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Add a '/' to the end so we don't have to do the property lookup
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // and concatenation later.
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < length; i++) {
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!mLibPaths[i].endsWith(fileSep))
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                mLibPaths[i] += fileSep;
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (VERBOSE_DEBUG)
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                System.out.println("Native lib path " +i+ ":  " + mLibPaths[i]);
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Convert a source path name and an output directory to an output
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * file name.
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static String generateOutputName(String sourcePathName,
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String outputDir) {
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        StringBuilder newStr = new StringBuilder(80);
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* start with the output directory */
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        newStr.append(outputDir);
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!outputDir.endsWith("/"))
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            newStr.append("/");
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* get the filename component of the path */
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String sourceFileName;
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int lastSlash = sourcePathName.lastIndexOf("/");
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (lastSlash < 0)
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sourceFileName = sourcePathName;
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sourceFileName = sourcePathName.substring(lastSlash+1);
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Replace ".jar", ".zip", whatever with ".dex".  We don't want to
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * use ".odex", because the build system uses that for files that
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * are paired with resource-only jar files.  If the VM can assume
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * that there's no classes.dex in the matching jar, it doesn't need
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * to open the jar to check for updated dependencies, providing a
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * slight performance boost at startup.  The use of ".dex" here
205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * matches the use on files in /data/dalvik-cache.
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int lastDot = sourceFileName.lastIndexOf(".");
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (lastDot < 0)
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            newStr.append(sourceFileName);
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        else
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            newStr.append(sourceFileName, 0, lastDot);
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        newStr.append(".dex");
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (VERBOSE_DEBUG)
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            System.out.println("Output file will be " + newStr.toString());
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return newStr.toString();
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Finds a class. This method is called by {@code loadClass()} after the
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * parent ClassLoader has failed to find a loaded class of the same name.
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param name
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            The name of the class to search for, in a human-readable form
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            like "java.lang.String" or "java.net.URLClassLoader$3$1".
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the {@link Class} object representing the class
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @throws ClassNotFoundException
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *             if the class cannot be found
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected Class<?> findClass(String name) throws ClassNotFoundException {
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ensureInit();
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (VERBOSE_DEBUG)
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            System.out.println("DexClassLoader " + this
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                + ": findClass '" + name + "'");
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        byte[] data = null;
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int length = mFiles.length;
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < length; i++) {
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (VERBOSE_DEBUG)
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                System.out.println("  Now searching: " + mFiles[i].getPath());
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (mDexs[i] != null) {
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                String slashName = name.replace('.', '/');
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Class clazz = mDexs[i].loadClass(slashName, this);
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (clazz != null) {
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (VERBOSE_DEBUG)
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        System.out.println("    found");
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    return clazz;
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        throw new ClassNotFoundException(name + " in loader " + this);
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Finds a resource. This method is called by {@code getResource()} after
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the parent ClassLoader has failed to find a loaded resource of the same
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * name.
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param name
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            The name of the resource to find
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the location of the resource as a URL, or {@code null} if the
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *         resource is not found.
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected URL findResource(String name) {
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ensureInit();
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int length = mFiles.length;
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < length; i++) {
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            File pathFile = mFiles[i];
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ZipFile zip = mZips[i];
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (zip.getEntry(name) != null) {
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (VERBOSE_DEBUG)
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    System.out.println("  found " + name + " in " + pathFile);
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                try {
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    // File.toURL() is compliant with RFC 1738 in always
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    // creating absolute path names. If we construct the
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    // URL by concatenating strings, we might end up with
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    // illegal URLs for relative names.
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    return new URL("jar:" + pathFile.toURL() + "!/" + name);
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } catch (MalformedURLException e) {
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new RuntimeException(e);
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (VERBOSE_DEBUG)
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            System.out.println("  resource " + name + " not found");
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return null;
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Finds a native library. This method is called after the parent
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * ClassLoader has failed to find a native library of the same name.
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param libname
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            The name of the library to find
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the complete path of the library, or {@code null} if the library
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *         is not found.
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected String findLibrary(String libname) {
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ensureInit();
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        String fileName = System.mapLibraryName(libname);
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < mLibPaths.length; i++) {
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            String pathName = mLibPaths[i] + fileName;
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            File test = new File(pathName);
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (test.exists()) {
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (VERBOSE_DEBUG)
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    System.out.println("  found " + libname);
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return pathName;
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (VERBOSE_DEBUG)
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            System.out.println("  library " + libname + " not found");
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return null;
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Returns package information for the given package. Unfortunately, the
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * DexClassLoader doesn't really have this information, and as a non-secure
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * ClassLoader, it isn't even required to, according to the spec. Yet, we
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * want to provide it, in order to make all those hopeful callers of
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <code>myClass.getPackage().getName()</code> happy. Thus we construct a
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Package object the first time it is being requested and fill most of the
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * fields with dummy values. The Package object is then put into the
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * ClassLoader's Package cache, so we see the same one next time. We don't
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * create Package objects for null arguments or for the default package.
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * <p>
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * There a limited chance that we end up with multiple Package objects
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * representing the same package: It can happen when when a package is
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * scattered across different JAR files being loaded by different
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * ClassLoaders. Rather unlikely, and given that this whole thing is more or
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * less a workaround, probably not worth the effort.
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param name
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *            the name of the class
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return the package information for the class, or {@code null} if there
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *         is not package information available for it
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected Package getPackage(String name) {
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (name != null && !"".equals(name)) {
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            synchronized(this) {
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Package pack = super.getPackage(name);
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (pack == null) {
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    pack = definePackage(name, "Unknown", "0.0", "Unknown",
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            "Unknown", "0.0", "Unknown", null);
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return pack;
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return null;
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
371