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