URLClassLoader.java revision b1396870f92135aa140bd2b86221768dea5bc11d
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/* 2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one or more 3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * contributor license agreements. See the NOTICE file distributed with 4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this work for additional information regarding copyright ownership. 5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0 6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (the "License"); you may not use this file except in compliance with 7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License. You may obtain a copy of the License at 8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and 15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License. 16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage java.net; 19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 20f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonimport java.io.BufferedReader; 21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.ByteArrayOutputStream; 22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.File; 23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FileInputStream; 24f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonimport java.io.FileNotFoundException; 25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FilePermission; 26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException; 27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream; 28f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilsonimport java.io.InputStreamReader; 29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.UnsupportedEncodingException; 30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.AccessControlContext; 31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.AccessController; 32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.CodeSource; 33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.PermissionCollection; 34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.PrivilegedAction; 35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.SecureClassLoader; 36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.security.cert.Certificate; 37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.ArrayList; 38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Collections; 39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Enumeration; 40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashMap; 41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.List; 42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Map; 43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.StringTokenizer; 44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.jar.Attributes; 45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.jar.JarEntry; 46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.jar.JarFile; 47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.jar.Manifest; 48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This class loader is responsible for loading classes and resources from a 51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * list of URLs which can refer to either directories or JAR files. Classes 52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * loaded by this {@code URLClassLoader} are granted permission to access the 53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * URLs contained in the URL search list. 54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic class URLClassLoader extends SecureClassLoader { 56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 57f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> originalUrls; 58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 59f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson List<URL> searchList; 60f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URLHandler> handlerList; 61f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Map<URL, URLHandler> handlerMap = new HashMap<URL, URLHandler>(); 62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private URLStreamHandlerFactory factory; 64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private AccessControlContext currentContext; 66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project static class SubURLClassLoader extends URLClassLoader { 68adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // The subclass that overwrites the loadClass() method 69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private boolean checkingPackageAccess = false; 70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project SubURLClassLoader(URL[] urls) { 72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project super(urls, ClassLoader.getSystemClassLoader()); 73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 74adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project SubURLClassLoader(URL[] urls, ClassLoader parent) { 76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project super(urls, parent); 77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Overrides the {@code loadClass()} of {@code ClassLoader}. It calls 81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the security manager's {@code checkPackageAccess()} before 82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * attempting to load the class. 83f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the Class object. 85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param className 86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * String the name of the class to search for. 87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param resolveClass 88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * boolean indicates if class should be resolved after 89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * loading. 90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws ClassNotFoundException 91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * If the class could not be found. 92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected synchronized Class<?> loadClass(String className, 95f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson boolean resolveClass) throws ClassNotFoundException { 96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project SecurityManager sm = System.getSecurityManager(); 97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (sm != null && !checkingPackageAccess) { 98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int index = className.lastIndexOf('.'); 99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (index > 0) { // skip if class is from a default package 100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project checkingPackageAccess = true; 102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project sm.checkPackageAccess(className.substring(0, index)); 103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } finally { 104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project checkingPackageAccess = false; 105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return super.loadClass(className, resolveClass); 109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 112f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson static class IndexFile { 113f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 114f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private HashMap<String, ArrayList<URL>> map; 115f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson //private URLClassLoader host; 116f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 117f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 118f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson static IndexFile readIndexFile(JarFile jf, JarEntry indexEntry, URL url) { 119f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson BufferedReader in = null; 120f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson InputStream is = null; 121f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 122f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // Add mappings from resource to jar file 123f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String parentURLString = getParentURL(url).toExternalForm(); 124f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes String prefix = "jar:" 125f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes + parentURLString + "/"; 126f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson is = jf.getInputStream(indexEntry); 127f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson in = new BufferedReader(new InputStreamReader(is, "UTF8")); 128f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson HashMap<String, ArrayList<URL>> pre_map = new HashMap<String, ArrayList<URL>>(); 129f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // Ignore the 2 first lines (index version) 130f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (in.readLine() == null) return null; 131f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (in.readLine() == null) return null; 132f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson TOP_CYCLE: 133f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson while (true) { 134f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String line = in.readLine(); 135f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (line == null) { 136f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson break; 137f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 138f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes URL jar = new URL(prefix + line + "!/"); 139f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson while (true) { 140f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson line = in.readLine(); 141f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (line == null) { 142f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson break TOP_CYCLE; 143f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 14480a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes if (line.isEmpty()) { 145f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson break; 146f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 147f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> list; 148f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (pre_map.containsKey(line)) { 149f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson list = pre_map.get(line); 150f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 151f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson list = new ArrayList<URL>(); 152f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson pre_map.put(line, list); 153f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 154f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson list.add(jar); 155f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 156f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 157f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (!pre_map.isEmpty()) { 158f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return new IndexFile(pre_map); 159f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 160f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (MalformedURLException e) { 161f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // Ignore this jar's index 162f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 163f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // Ignore this jar's index 164f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 165f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson finally { 166f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (in != null) { 167f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 168f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson in.close(); 169f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 170f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 171f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 172f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (is != null) { 173f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 174f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson is.close(); 175f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 176f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 177f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 178f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 179f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 180f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 181f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 182f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private static URL getParentURL(URL url) throws IOException { 183f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL fileURL = ((JarURLConnection) url.openConnection()).getJarFileURL(); 184f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String file = fileURL.getFile(); 185f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String parentFile = new File(file).getParent(); 186f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson parentFile = parentFile.replace(File.separatorChar, '/'); 187f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (parentFile.charAt(0) != '/') { 188f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes parentFile = "/" + parentFile; 189f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 190f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL parentURL = new URL(fileURL.getProtocol(), fileURL 191f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson .getHost(), fileURL.getPort(), parentFile); 192f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return parentURL; 193f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 194f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 195f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson public IndexFile(HashMap<String, ArrayList<URL>> map) { 196f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.map = map; 197f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 198f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 199f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> get(String name) { 200f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return map.get(name); 201f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 202f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 203f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 204f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson class URLHandler { 205f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL url; 206f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL codeSourceUrl; 207f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 208f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson public URLHandler(URL url) { 209f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.url = url; 210f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.codeSourceUrl = url; 211f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 212f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 213f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson void findResources(String name, ArrayList<URL> resources) { 214f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL res = findResource(name); 215f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (res != null && !resources.contains(res)) { 216f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson resources.add(res); 217f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 218f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 219f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 220f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Class<?> findClass(String packageName, String name, String origName) { 221f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL resURL = targetURL(url, name); 222f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (resURL != null) { 223f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 224f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson InputStream is = resURL.openStream(); 225f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return createClass(is, packageName, origName); 226f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 227f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 228f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 229f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 230f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 231f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 232f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 233f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Class<?> createClass(InputStream is, String packageName, String origName) { 234f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (is == null) { 235f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 236f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 237f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson byte[] clBuf = null; 238f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 239f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson clBuf = getBytes(is); 240f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 241f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 242f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } finally { 243f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 244f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson is.close(); 245f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 246f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 247f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 248f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (packageName != null) { 249f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String packageDotName = packageName.replace('/', '.'); 250f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Package packageObj = getPackage(packageDotName); 251f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (packageObj == null) { 252f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson definePackage(packageDotName, null, null, 253f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson null, null, null, null, null); 254f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 255f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (packageObj.isSealed()) { 256b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes throw new SecurityException("Package is sealed"); 257f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 258f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 259f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 260f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return defineClass(origName, clBuf, 0, clBuf.length, new CodeSource(codeSourceUrl, (Certificate[]) null)); 261f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 262f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 263f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL findResource(String name) { 264f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL resURL = targetURL(url, name); 265f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (resURL != null) { 266f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 267f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLConnection uc = resURL.openConnection(); 268f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson uc.getInputStream().close(); 269f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // HTTP can return a stream on a non-existent file 270f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // So check for the return code; 271f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (!resURL.getProtocol().equals("http")) { 272f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return resURL; 273f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 274f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson int code; 275f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if ((code = ((HttpURLConnection) uc).getResponseCode()) >= 200 276f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson && code < 300) { 277f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return resURL; 278f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 279f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (SecurityException e) { 280f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 281f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 282f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 283f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 284f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 285f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 286f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 287f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 288f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL targetURL(URL base, String name) { 289f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 290f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String file = base.getFile() + URIEncoderDecoder.quoteIllegal(name, 29138607710cdc82cb1a0e81c2fc5c78278b435e4fcJesse Wilson "/@" + URI.SOME_LEGAL); 292f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 293f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return new URL(base.getProtocol(), base.getHost(), base.getPort(), 294f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson file, null); 295f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (UnsupportedEncodingException e) { 296f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 297f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (MalformedURLException e) { 298f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 299f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 300f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 301f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 302f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 303f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 304f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson class URLJarHandler extends URLHandler { 305f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson final JarFile jf; 306f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson final String prefixName; 307f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson final IndexFile index; 308f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson final Map<URL, URLHandler> subHandlers = new HashMap<URL, URLHandler>(); 309f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 310f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson public URLJarHandler(URL url, URL jarURL, JarFile jf, String prefixName) { 311f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson super(url); 312f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.jf = jf; 313f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.prefixName = prefixName; 314f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.codeSourceUrl = jarURL; 315f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes final JarEntry je = jf.getJarEntry("META-INF/INDEX.LIST"); 316f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.index = (je == null ? null : IndexFile.readIndexFile(jf, je, url)); 317f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 318f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 319f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson public URLJarHandler(URL url, URL jarURL, JarFile jf, String prefixName, IndexFile index) { 320f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson super(url); 321f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.jf = jf; 322f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.prefixName = prefixName; 323f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.index = index; 324f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson this.codeSourceUrl = jarURL; 325f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 326f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 327f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson IndexFile getIndex() { 328f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return index; 329f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 330f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 331f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson @Override 332f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson void findResources(String name, ArrayList<URL> resources) { 333f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL res = findResourceInOwn(name); 334f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (res != null && !resources.contains(res)) { 335f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson resources.add(res); 336f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 337f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (index != null) { 338f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes int pos = name.lastIndexOf("/"); 339f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // only keep the directory part of the resource 340f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // as index.list only keeps track of directories and root files 341f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String indexedName = (pos > 0) ? name.substring(0, pos) : name; 342f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> urls = index.get(indexedName); 343f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (urls != null) { 344f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson urls.remove(url); 345f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson for (URL url : urls) { 346f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler h = getSubHandler(url); 347f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (h != null) { 348f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson h.findResources(name, resources); 349f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 350f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 351f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 352f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 353f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 354f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 355f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 356f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson @Override 357f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Class<?> findClass(String packageName, String name, String origName) { 358f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String entryName = prefixName + name; 359f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson JarEntry entry = jf.getJarEntry(entryName); 360f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (entry != null) { 361f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson /** 362f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * Avoid recursive load class, especially the class 363f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * is an implementation class of security provider 364f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * and the jar is signed. 365f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson */ 366f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 367f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Manifest manifest = jf.getManifest(); 368f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return createClass(entry, manifest, packageName, origName); 369f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 370f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 371f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 372f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (index != null) { 373f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> urls; 374f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (packageName == null) { 375f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson urls = index.get(name); 376f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 377f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson urls = index.get(packageName); 378f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 379f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (urls != null) { 380f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson urls.remove(url); 381f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson for (URL url : urls) { 382f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler h = getSubHandler(url); 383f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (h != null) { 384f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Class<?> res = h.findClass(packageName, name, origName); 385f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (res != null) { 386f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return res; 387f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 388f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 389f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 390f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 391f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 392f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 393f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 394f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 395f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private Class<?> createClass(JarEntry entry, Manifest manifest, String packageName, String origName) { 396f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson InputStream is = null; 397f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson byte[] clBuf = null; 398f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 399f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson is = jf.getInputStream(entry); 400f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson clBuf = getBytes(is); 401f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 402f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 403f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } finally { 404f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (is != null) { 405f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 406f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson is.close(); 407f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 408f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 409f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 410f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 411f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (packageName != null) { 412f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String packageDotName = packageName.replace('/', '.'); 413f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Package packageObj = getPackage(packageDotName); 414f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (packageObj == null) { 415f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (manifest != null) { 416f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson definePackage(packageDotName, manifest, 417f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson codeSourceUrl); 418f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 419f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson definePackage(packageDotName, null, null, 420f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson null, null, null, null, null); 421f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 422f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 423f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson boolean exception = packageObj.isSealed(); 424f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (manifest != null) { 425f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (isSealed(manifest, packageName + "/")) { 426f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson exception = !packageObj 427f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson .isSealed(codeSourceUrl); 428f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 429f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 430f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (exception) { 431b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes throw new SecurityException(String.format("Package %s is sealed", 432b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes packageName)); 433f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 434f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 435f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 436f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson CodeSource codeS = new CodeSource(codeSourceUrl, entry.getCertificates()); 437f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return defineClass(origName, clBuf, 0, clBuf.length, codeS); 438f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 439f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 440f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL findResourceInOwn(String name) { 441f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String entryName = prefixName + name; 442f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (jf.getEntry(entryName) != null) { 443f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return targetURL(url, name); 444f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 445f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 446f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 447f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 448f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson @Override 449f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL findResource(String name) { 450f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL res = findResourceInOwn(name); 451f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (res != null) { 452f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return res; 453f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 454f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (index != null) { 455f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes int pos = name.lastIndexOf("/"); 456f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // only keep the directory part of the resource 457f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // as index.list only keeps track of directories and root files 458f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String indexedName = (pos > 0) ? name.substring(0, pos) : name; 459f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> urls = index.get(indexedName); 460f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (urls != null) { 461f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson urls.remove(url); 462f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson for (URL url : urls) { 463f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler h = getSubHandler(url); 464f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (h != null) { 465f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson res = h.findResource(name); 466f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (res != null) { 467f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return res; 468f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 469f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 470f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 471f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 472f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 473f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 474f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 475f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 476f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private synchronized URLHandler getSubHandler(URL url) { 477f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler sub = subHandlers.get(url); 478f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (sub != null) { 479f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return sub; 480f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 481f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String protocol = url.getProtocol(); 482f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (protocol.equals("jar")) { 483f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson sub = createURLJarHandler(url); 484f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes } else if (protocol.equals("file")) { 485f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson sub = createURLSubJarHandler(url); 486f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 487f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson sub = createURLHandler(url); 488f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 489f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (sub != null) { 490f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson subHandlers.put(url, sub); 491f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 492f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return sub; 493f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 494f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 495f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private URLHandler createURLSubJarHandler(URL url) { 496f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String prefixName; 497f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String file = url.getFile(); 498f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (url.getFile().endsWith("!/")) { 499f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson prefixName = ""; 500f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 501f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes int sepIdx = file.lastIndexOf("!/"); 502f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (sepIdx == -1) { 503f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // Invalid URL, don't look here again 504f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 505f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 506f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson sepIdx += 2; 507f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson prefixName = file.substring(sepIdx); 508f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 509f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 510f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL jarURL = ((JarURLConnection) url 511f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson .openConnection()).getJarFileURL(); 512f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson JarURLConnection juc = (JarURLConnection) new URL( 513f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes "jar", "", 514f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes jarURL.toExternalForm() + "!/").openConnection(); 515f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson JarFile jf = juc.getJarFile(); 516f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLJarHandler jarH = new URLJarHandler(url, jarURL, jf, prefixName, null); 517f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // TODO : to think what we should do with indexes & manifest.class file here 518f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return jarH; 519f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 520f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 521f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 522f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 523f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 524f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 525f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 526f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson class URLFileHandler extends URLHandler { 527f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private String prefix; 528f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 529f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson public URLFileHandler(URL url) { 530f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson super(url); 531f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String baseFile = url.getFile(); 532f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String host = url.getHost(); 533f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson int hostLength = 0; 534f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (host != null) { 535f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson hostLength = host.length(); 536f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 537f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson StringBuilder buf = new StringBuilder(2 + hostLength 538f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson + baseFile.length()); 539f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (hostLength > 0) { 540f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes buf.append("//").append(host); 541f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 542f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // baseFile always ends with '/' 543f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson buf.append(baseFile); 544f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson prefix = buf.toString(); 545f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 546f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 547f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson @Override 548f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Class<?> findClass(String packageName, String name, String origName) { 549f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String filename = prefix + name; 550f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 551f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes filename = URLDecoder.decode(filename, "UTF-8"); 552f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IllegalArgumentException e) { 553f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 554f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (UnsupportedEncodingException e) { 555f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 556f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 557f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 558f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson File file = new File(filename); 559f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (file.exists()) { 560f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 561f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson InputStream is = new FileInputStream(file); 562f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return createClass(is, packageName, origName); 563f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (FileNotFoundException e) { 564f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 565f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 566f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 567f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 568f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 569f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson @Override 570f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL findResource(String name) { 571f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson int idx = 0; 572f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String filename; 573f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 574f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // Do not create a UNC path, i.e. \\host 575f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson while (idx < name.length() && 576f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ((name.charAt(idx) == '/') || (name.charAt(idx) == '\\'))) { 577f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson idx++; 578f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 579f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 580f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (idx > 0) { 581f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson name = name.substring(idx); 582f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 583f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 584f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 585f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes filename = URLDecoder.decode(prefix, "UTF-8") + name; 586f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 587f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (new File(filename).exists()) { 588f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return targetURL(url, name); 589f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 590f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 591f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IllegalArgumentException e) { 592f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 593f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (UnsupportedEncodingException e) { 594f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // must not happen 595f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson throw new AssertionError(e); 596f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 597f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 598f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 599f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 600f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 601f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 602adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 603adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Constructs a new {@code URLClassLoader} instance. The newly created 604adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * instance will have the system ClassLoader as its parent. URLs that end 605adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * with "/" are assumed to be directories, otherwise they are assumed to be 606adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * JAR files. 607f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 608adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param urls 609adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the list of URLs where a specific class or file could be 610adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * found. 611adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws SecurityException 612adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if a security manager exists and its {@code 613adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * checkCreateClassLoader()} method doesn't allow creation of 614adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * new ClassLoaders. 615adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 616adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public URLClassLoader(URL[] urls) { 617adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this(urls, ClassLoader.getSystemClassLoader(), null); 618adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 619adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 620adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 621adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Constructs a new URLClassLoader instance. The newly created instance will 622adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * have the system ClassLoader as its parent. URLs that end with "/" are 623adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * assumed to be directories, otherwise they are assumed to be JAR files. 624f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 625adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param urls 626adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the list of URLs where a specific class or file could be 627adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * found. 628adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param parent 629adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the class loader to assign as this loader's parent. 630adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws SecurityException 631adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if a security manager exists and its {@code 632adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * checkCreateClassLoader()} method doesn't allow creation of 633adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * new class loaders. 634adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 635adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public URLClassLoader(URL[] urls, ClassLoader parent) { 636adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this(urls, parent, null); 637adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 638adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 639adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 640adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Adds the specified URL to the search list. 641f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 642adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param url 643adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the URL which is to add. 644adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 645adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected void addURL(URL url) { 646adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 647f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson originalUrls.add(url); 648f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson searchList.add(createSearchURL(url)); 649adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (MalformedURLException e) { 650adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 651adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 652adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 653adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 654adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns all known URLs which point to the specified resource. 655f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 656adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param name 657adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the requested resource. 658adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the enumeration of URLs which point to the specified resource. 659adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException 660adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if an I/O error occurs while attempting to connect. 661adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 662adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 663adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Enumeration<URL> findResources(final String name) throws IOException { 664adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (name == null) { 665adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 666adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 667f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> result = AccessController.doPrivileged( 668f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson new PrivilegedAction<ArrayList<URL>>() { 669f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson public ArrayList<URL> run() { 670f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> results = new ArrayList<URL>(); 671f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson findResourcesImpl(name, results); 672f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return results; 673adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 674adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project }, currentContext); 675adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project SecurityManager sm; 676adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int length = result.size(); 677adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (length > 0 && (sm = System.getSecurityManager()) != null) { 678f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> reduced = new ArrayList<URL>(length); 679adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (int i = 0; i < length; i++) { 680f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL url = result.get(i); 681adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 682adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project sm.checkPermission(url.openConnection().getPermission()); 683f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson reduced.add(url); 684adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (IOException e) { 685adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (SecurityException e) { 686adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 687adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 688adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project result = reduced; 689adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 690f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return Collections.enumeration(result); 691adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 692adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 693f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson void findResourcesImpl(String name, ArrayList<URL> result) { 694f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson int n = 0; 695f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson while (true) { 696f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler handler = getHandler(n++); 697f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (handler == null) { 698f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson break; 699adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 700f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson handler.findResources(name, result); 701adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 702adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 703adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 704adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 705adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 706adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Converts an input stream into a byte array. 707f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 708adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param is 709adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the input stream 710f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * @return byte[] the byte array 711adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 712f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private static byte[] getBytes(InputStream is) 713adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project throws IOException { 714adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project byte[] buf = new byte[4096]; 715f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ByteArrayOutputStream bos = new ByteArrayOutputStream(4096); 716adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int count; 717adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project while ((count = is.read(buf)) > 0) { 718adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project bos.write(buf, 0, count); 719adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 720adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return bos.toByteArray(); 721adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 722adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 723adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 724adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Gets all permissions for the specified {@code codesource}. First, this 725adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * method retrieves the permissions from the system policy. If the protocol 726adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * is "file:/" then a new permission, {@code FilePermission}, granting the 727adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * read permission to the file is added to the permission collection. 728adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Otherwise, connecting to and accepting connections from the URL is 729adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * granted. 730f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 731adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param codesource 732adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the code source object whose permissions have to be known. 733adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the list of permissions according to the code source object. 734adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 735adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 736adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected PermissionCollection getPermissions(final CodeSource codesource) { 737adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project PermissionCollection pc = super.getPermissions(codesource); 738adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project URL u = codesource.getLocation(); 739f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (u.getProtocol().equals("jar")) { 740adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 741adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // Create a URL for the resource the jar refers to 742adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project u = ((JarURLConnection) u.openConnection()).getJarFileURL(); 743adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (IOException e) { 744adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // This should never occur. If it does continue using the jar 745adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // URL 746adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 747adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 748f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (u.getProtocol().equals("file")) { 749adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String path = u.getFile(); 750adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String host = u.getHost(); 751adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (host != null && host.length() > 0) { 752f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes path = "//" + host + path; 753adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 754adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 755adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (File.separatorChar != '/') { 756adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project path = path.replace('/', File.separatorChar); 757adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 758adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (isDirectory(u)) { 759f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes pc.add(new FilePermission(path + "-", "read")); 760adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 761f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes pc.add(new FilePermission(path, "read")); 762adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 763adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 764adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String host = u.getHost(); 765adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (host.length() == 0) { 766f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes host = "localhost"; 767adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 768f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes pc.add(new SocketPermission(host, "connect, accept")); 769adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 770adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return pc; 771adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 772adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 773adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 774adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns the search list of this {@code URLClassLoader}. 775f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 776adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the list of all known URLs of this instance. 777adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 778adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public URL[] getURLs() { 779f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return originalUrls.toArray(new URL[originalUrls.size()]); 780adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 781adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 782adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 783adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Determines if the URL is pointing to a directory. 784adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 785adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private static boolean isDirectory(URL url) { 786adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String file = url.getFile(); 787adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return (file.length() > 0 && file.charAt(file.length() - 1) == '/'); 788adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 789adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 790adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 791adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns a new {@code URLClassLoader} instance for the given URLs and the 792adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * system {@code ClassLoader} as its parent. The method {@code loadClass()} 793adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * of the new instance will call {@code 794adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * SecurityManager.checkPackageAccess()} before loading a class. 795f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 796adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param urls 797adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the list of URLs that is passed to the new {@code 798adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * URLClassloader}. 799adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the created {@code URLClassLoader} instance. 800adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 801adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public static URLClassLoader newInstance(final URL[] urls) { 802adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project URLClassLoader sub = AccessController 803adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .doPrivileged(new PrivilegedAction<URLClassLoader>() { 804adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public URLClassLoader run() { 805adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return new SubURLClassLoader(urls); 806adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 807adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project }); 808adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project sub.currentContext = AccessController.getContext(); 809adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return sub; 810adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 811adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 812adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 813adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns a new {@code URLClassLoader} instance for the given URLs and the 814adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * specified {@code ClassLoader} as its parent. The method {@code 815adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * loadClass()} of the new instance will call the SecurityManager's {@code 816adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * checkPackageAccess()} before loading a class. 817f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 818adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param urls 819adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the list of URLs that is passed to the new URLClassloader. 820adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param parentCl 821adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the parent class loader that is passed to the new 822adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * URLClassloader. 823adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the created {@code URLClassLoader} instance. 824adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 825adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public static URLClassLoader newInstance(final URL[] urls, 826f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson final ClassLoader parentCl) { 827adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project URLClassLoader sub = AccessController 828adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .doPrivileged(new PrivilegedAction<URLClassLoader>() { 829adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public URLClassLoader run() { 830adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return new SubURLClassLoader(urls, parentCl); 831adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 832adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project }); 833adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project sub.currentContext = AccessController.getContext(); 834adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return sub; 835adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 836adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 837adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 838adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Constructs a new {@code URLClassLoader} instance. The newly created 839adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * instance will have the specified {@code ClassLoader} as its parent and 840adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * use the specified factory to create stream handlers. URLs that end with 841adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * "/" are assumed to be directories, otherwise they are assumed to be JAR 842adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * files. 843f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 844adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param searchUrls 845adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the list of URLs where a specific class or file could be 846adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * found. 847adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param parent 848adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the {@code ClassLoader} to assign as this loader's parent. 849adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param factory 850adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the factory that will be used to create protocol-specific 851adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * stream handlers. 852adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws SecurityException 853adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if a security manager exists and its {@code 854adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * checkCreateClassLoader()} method doesn't allow creation of 855adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * new {@code ClassLoader}s. 856adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 857adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public URLClassLoader(URL[] searchUrls, ClassLoader parent, 858f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLStreamHandlerFactory factory) { 859adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project super(parent); 860adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // Required for pre-v1.2 security managers to work 861adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project SecurityManager security = System.getSecurityManager(); 862adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (security != null) { 863adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project security.checkCreateClassLoader(); 864adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 865adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this.factory = factory; 866adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // capture the context of the thread that creates this URLClassLoader 867adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project currentContext = AccessController.getContext(); 868adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int nbUrls = searchUrls.length; 869f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson originalUrls = new ArrayList<URL>(nbUrls); 870f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson handlerList = new ArrayList<URLHandler>(nbUrls); 871f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson searchList = Collections.synchronizedList(new ArrayList<URL>(nbUrls)); 872adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (int i = 0; i < nbUrls; i++) { 873f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson originalUrls.add(searchUrls[i]); 874adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 875f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson searchList.add(createSearchURL(searchUrls[i])); 876adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (MalformedURLException e) { 877adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 878adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 879adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 880adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 881adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 882adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Tries to locate and load the specified class using the known URLs. If the 883adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * class could be found, a class object representing the loaded class will 884adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * be returned. 885f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 886adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param clsName 887adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the class which has to be found. 888f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * @return the class that has been loaded. 889adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws ClassNotFoundException 890adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if the specified class cannot be loaded. 891adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 892adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 893adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected Class<?> findClass(final String clsName) 894adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project throws ClassNotFoundException { 895adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Class<?> cls = AccessController.doPrivileged( 896adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project new PrivilegedAction<Class<?>>() { 897adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public Class<?> run() { 898f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return findClassImpl(clsName); 899adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 900adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project }, currentContext); 901adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (cls != null) { 902adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return cls; 903adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 904adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project throw new ClassNotFoundException(clsName); 905adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 906adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 907adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 908adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns an URL that will be checked if it contains the class or resource. 909adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * If the file component of the URL is not a directory, a Jar URL will be 910adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * created. 911f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 912adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return java.net.URL a test URL 913adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 914adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private URL createSearchURL(URL url) throws MalformedURLException { 915adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (url == null) { 916adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return url; 917adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 918adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 919adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String protocol = url.getProtocol(); 920adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 921f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (isDirectory(url) || protocol.equals("jar")) { 922adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return url; 923adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 924adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (factory == null) { 925f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes return new URL("jar", "", 926f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes -1, url.toString() + "!/"); 927adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 928f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // use jar protocol as the stream handler protocol 929f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes return new URL("jar", "", 930f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes -1, url.toString() + "!/", 931fd6bb3510c2f94d636f3572dcf5f7f4dcd1a2726Elliott Hughes factory.createURLStreamHandler("jar")); 932adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 933adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 934adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 935adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns an URL referencing the specified resource or {@code null} if the 936adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * resource could not be found. 937f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 938adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param name 939adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the requested resource. 940adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the URL which points to the given resource. 941adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 942adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project @Override 943adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public URL findResource(final String name) { 944adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (name == null) { 945adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 946adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 947adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project URL result = AccessController.doPrivileged(new PrivilegedAction<URL>() { 948adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public URL run() { 949f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return findResourceImpl(name); 950adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 951adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project }, currentContext); 952adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project SecurityManager sm; 953adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (result != null && (sm = System.getSecurityManager()) != null) { 954adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 955adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project sm.checkPermission(result.openConnection().getPermission()); 956adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (IOException e) { 957adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 958adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (SecurityException e) { 959adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 960adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 961adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 962adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return result; 963adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 964adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 965adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 966adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Returns a URL among the given ones referencing the specified resource or 967adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * null if no resource could be found. 968f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 969f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * @param resName java.lang.String the name of the requested resource 970adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return URL URL for the resource. 971adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 972f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL findResourceImpl(String resName) { 973f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson int n = 0; 974f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 975f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson while (true) { 976f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler handler = getHandler(n++); 977f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (handler == null) { 978f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson break; 979f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 980f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL res = handler.findResource(resName); 981f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (res != null) { 982f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return res; 983f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 984f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 985f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 986f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 987f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 988f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler getHandler(int num) { 989f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (num < handlerList.size()) { 990f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return handlerList.get(num); 991f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 992f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson makeNewHandler(); 993f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (num < handlerList.size()) { 994f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return handlerList.get(num); 995f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 996f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 997f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 998f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 999f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private synchronized void makeNewHandler() { 1000f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson while (!searchList.isEmpty()) { 1001f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL nextCandidate = searchList.remove(0); 1002b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes if (nextCandidate == null) { 1003b1396870f92135aa140bd2b86221768dea5bc11dElliott Hughes throw new NullPointerException("A URL is null"); 1004f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 1005f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (!handlerMap.containsKey(nextCandidate)) { 1006f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler result; 1007f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String protocol = nextCandidate.getProtocol(); 1008f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (protocol.equals("jar")) { 1009f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson result = createURLJarHandler(nextCandidate); 1010f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes } else if (protocol.equals("file")) { 1011f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson result = createURLFileHandler(nextCandidate); 1012f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 1013f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson result = createURLHandler(nextCandidate); 1014f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 1015f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (result != null) { 1016f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson handlerMap.put(nextCandidate, result); 1017f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson handlerList.add(result); 1018f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return; 1019f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 1020f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 1021f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 1022f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 1023adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1024f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private URLHandler createURLHandler(URL url) { 1025f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return new URLHandler(url); 1026f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 1027f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 1028f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private URLHandler createURLFileHandler(URL url) { 1029f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return new URLFileHandler(url); 1030f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 1031f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 1032f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private URLHandler createURLJarHandler(URL url) { 1033f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String prefixName; 1034f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String file = url.getFile(); 1035f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes if (url.getFile().endsWith("!/")) { 1036f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson prefixName = ""; 1037f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } else { 1038f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes int sepIdx = file.lastIndexOf("!/"); 1039f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (sepIdx == -1) { 1040f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson // Invalid URL, don't look here again 1041f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 1042f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 1043f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson sepIdx += 2; 1044f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson prefixName = file.substring(sepIdx); 1045f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } 1046f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 1047f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL jarURL = ((JarURLConnection) url 1048f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson .openConnection()).getJarFileURL(); 1049f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson JarURLConnection juc = (JarURLConnection) new URL( 1050f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes "jar", "", 1051f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes jarURL.toExternalForm() + "!/").openConnection(); 1052f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson JarFile jf = juc.getJarFile(); 1053f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLJarHandler jarH = new URLJarHandler(url, jarURL, jf, prefixName); 1054f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 1055f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (jarH.getIndex() == null) { 1056f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson try { 1057f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Manifest manifest = jf.getManifest(); 1058f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (manifest != null) { 1059f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String classpath = manifest.getMainAttributes().getValue( 1060f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Attributes.Name.CLASS_PATH); 1061f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (classpath != null) { 1062f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson searchList.addAll(0, getInternalURLs(url, classpath)); 1063adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1064adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1065adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (IOException e) { 1066adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1067adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1068f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return jarH; 1069f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson } catch (IOException e) { 1070adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1071adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return null; 1072adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1073adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1074adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 1075adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Defines a new package using the information extracted from the specified 1076adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * manifest. 1077f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 1078adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param packageName 1079adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the name of the new package. 1080adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param manifest 1081adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the manifest containing additional information for the new 1082adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * package. 1083adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param url 1084adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the URL to the code source for the new package. 1085adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return the created package. 1086adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IllegalArgumentException 1087adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if a package with the given name already exists. 1088adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 1089adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected Package definePackage(String packageName, Manifest manifest, 1090f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URL url) throws IllegalArgumentException { 1091adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Attributes mainAttributes = manifest.getMainAttributes(); 1092f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes String dirName = packageName.replace('.', '/') + "/"; 1093adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Attributes packageAttributes = manifest.getAttributes(dirName); 1094adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project boolean noEntry = false; 1095adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (packageAttributes == null) { 1096adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project noEntry = true; 1097adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project packageAttributes = mainAttributes; 1098adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1099adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String specificationTitle = packageAttributes 1100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.SPECIFICATION_TITLE); 1101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (specificationTitle == null && !noEntry) { 1102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project specificationTitle = mainAttributes 1103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.SPECIFICATION_TITLE); 1104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String specificationVersion = packageAttributes 1106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.SPECIFICATION_VERSION); 1107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (specificationVersion == null && !noEntry) { 1108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project specificationVersion = mainAttributes 1109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.SPECIFICATION_VERSION); 1110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String specificationVendor = packageAttributes 1112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.SPECIFICATION_VENDOR); 1113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (specificationVendor == null && !noEntry) { 1114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project specificationVendor = mainAttributes 1115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.SPECIFICATION_VENDOR); 1116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String implementationTitle = packageAttributes 1118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.IMPLEMENTATION_TITLE); 1119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (implementationTitle == null && !noEntry) { 1120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project implementationTitle = mainAttributes 1121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.IMPLEMENTATION_TITLE); 1122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String implementationVersion = packageAttributes 1124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.IMPLEMENTATION_VERSION); 1125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (implementationVersion == null && !noEntry) { 1126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project implementationVersion = mainAttributes 1127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.IMPLEMENTATION_VERSION); 1128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String implementationVendor = packageAttributes 1130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.IMPLEMENTATION_VENDOR); 1131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (implementationVendor == null && !noEntry) { 1132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project implementationVendor = mainAttributes 1133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project .getValue(Attributes.Name.IMPLEMENTATION_VENDOR); 1134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return definePackage(packageName, specificationTitle, 1137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project specificationVersion, specificationVendor, implementationTitle, 1138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project implementationVersion, implementationVendor, isSealed(manifest, 1139f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson dirName) ? url : null); 1140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project private boolean isSealed(Manifest manifest, String dirName) { 1143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Attributes mainAttributes = manifest.getMainAttributes(); 1144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String value = mainAttributes.getValue(Attributes.Name.SEALED); 1145f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes boolean sealed = value != null && value.toLowerCase().equals("true"); 1146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project Attributes attributes = manifest.getAttributes(dirName); 1147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (attributes != null) { 1148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project value = attributes.getValue(Attributes.Name.SEALED); 1149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (value != null) { 1150f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes sealed = value.toLowerCase().equals("true"); 1151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return sealed; 1154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 1157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * returns URLs referenced in the string classpath. 1158f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson * 1159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param root 1160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the jar URL that classpath is related to 1161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param classpath 1162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the relative URLs separated by spaces 1163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return URL[] the URLs contained in the string classpath. 1164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 1165f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson private ArrayList<URL> getInternalURLs(URL root, String classpath) { 1166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // Class-path attribute is composed of space-separated values. 11675839b909d9528b7726e678a4b696ed37df15d897Jesse Wilson StringTokenizer tokenizer = new StringTokenizer(classpath); 1168f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson ArrayList<URL> addedURLs = new ArrayList<URL>(); 1169f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String file = root.getFile(); 1170f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes int jarIndex = file.lastIndexOf("!/") - 1; 1171f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes int index = file.lastIndexOf("/", jarIndex) + 1; 1172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (index == 0) { 1173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project index = file.lastIndexOf( 1174f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes System.getProperty("file.separator"), jarIndex) + 1; 1175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project file = file.substring(0, index); 1177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project while (tokenizer.hasMoreElements()) { 1178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project String element = tokenizer.nextToken(); 117980a7fbab52b96c9fd47c72f8987d1babe2cd001dElliott Hughes if (!element.isEmpty()) { 1180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project try { 1181a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson // Take absolute path case into consideration 1182a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson URL url = new URL(new URL(file), element); 1183a389b4a499f40379b0b204d7ba1c2057663d95c0Jesse Wilson addedURLs.add(createSearchURL(url)); 1184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } catch (MalformedURLException e) { 1185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // Nothing is added 1186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1189f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return addedURLs; 1190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1192f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Class<?> findClassImpl(String className) { 1193f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String partialName = className.replace('.', '/'); 1194f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes final String classFileName = new StringBuilder(partialName).append(".class").toString(); 1195f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson String packageName = null; 1196f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson int position = partialName.lastIndexOf('/'); 1197f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if ((position = partialName.lastIndexOf('/')) != -1) { 1198f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson packageName = partialName.substring(0, position); 1199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1200f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson int n = 0; 1201f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson while (true) { 1202f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson URLHandler handler = getHandler(n++); 1203f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (handler == null) { 1204f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson break; 1205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1206f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson Class<?> res = handler.findClass(packageName, classFileName, className); 1207f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson if (res != null) { 1208f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return res; 1209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1211f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson return null; 1212adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 1213adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 1214f5597e626ecf7949d249dea08c1a2964d890ec11Jesse Wilson 1215adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 1216