DexClassLoder 해석

69141 단어 학습 펜
Android 클래스 로 더 DexClassLoader 의 간단 한 사용
DexClassLoader 는 외부 apk,jar 또는 dex 파일 을 불 러 올 수 있 습 니 다.
자바 에 서 는'클래스 로 더'(ClassLoader)라 는 개념 이 있 습 니 다.그 역할 은 동적 으로 Class 파일 을 불 러 오 는 것 입 니 다.
1.ClassLoader 의 기초 지식
ClassLoader 는 주로 클래스 의 요청 에 서 비 스 를 제공 합 니 다.JVM 이 클래스 가 필요 할 때 이름 에 따라 ClassLoader 에 이 클래스 를 요구 한 다음 ClassLoader 에서 이 클래스 의 class 대상 을 되 돌려 줍 니 다.
JVM 이 든 Dalvik 이 든 모두 ClassLoader 를 통 해 필요 한 종 류 를 불 러 옵 니 다.ClassLoader 를 불 러 오 는 방식 은 부모 의뢰 라 고 합 니 다.
JVM 및 Dalvik 의 클래스 에 대한 유일한 식별 은 ClassLoader id+PackageName+ClassName 입 니 다.
2.Android 플랫폼 의 ClassLoader
Android 에 서 는 BootClassLoader,URLClassLoader,PathClassLoader,DexClassLoader,BaseDexClassLoader 등 이 최종 적 으로 자바.lang.ClassLoader 에서 계승 되 었 습 니 다.
1.java.lang.ClassLoader 는 모든 ClassLoader 의 최종 부류 입 니 다.2.BootClassLoader 와 자바 가상 컴퓨터 에서 다른 것 은 BootClassLoader 는 ClassLoader 내부 클래스 로 c++가 아 닌 자바 코드 로 이 루어 집 니 다.Android 플랫폼 의 모든 ClassLoader 의 최종 parent 입 니 다.이 내부 클래스 는 가방 에서 볼 수 있 기 때문에 사용 할 수 없습니다.3.URLClassLoader 는 jar 파일 을 불 러 오 는 데 만 사용 할 수 있 지만,dalvik 는 jar 를 직접 식별 할 수 없 기 때문에 Android 에 서 는 이 로 더 를 사용 할 수 없습니다.4.BaseDexClassLoader PathClassLoader 와 DexClassLoader 는 모두 BaseDexClassLoader 에서 계승 되 었 으 며,그 중의 주요 논 리 는 모두 BaseDexClassLoader 에서 이 루어 졌 다.이 소스 코드 들 은 자바/dalvik/system 에 있 습 니 다.
BaseDexClassLoader 의 구조 함 수 는 다음 과 같은 네 가지 인 자 를 포함 합 니 다.dexPath 는 대상 클래스 가 있 는 APK 나 jar 파일 의 경 로 를 말 합 니 다.클래스 로 더 는 이 경로 에서 지정 한 대상 클래스 를 찾 습 니 다.이 클래스 는 APK 나 jar 의 전체 경로 여야 합 니 다.여러 경 로 를 포함 하려 면 경로 간 에 특정한 분할 자 를 사용 해 야 합 니 다.특정한 분할 부 호 는 System.getProperty("path.separtor")를 사용 하여 얻 을 수 있 습 니 다.위 에서'APK,DEX,JAR 불 러 오기 지원,SD 카드 에서 불 러 올 수도 있 습 니 다'는 이 경 로 를 말 합 니 다.마지막 으로 dexPath 경로 의 파일 ODEX 를 내부 위치 optimized Directory 로 최적화 한 다음 에 불 러 옵 니 다.
File optimized Directory 는 dex 파일 이 APK 나 Jar 파일 에 포함 되 어 있 기 때문에 대상 클래스 를 불 러 오기 전에 APK 나 Jar 파일 에서 dex 파일 의 압축 을 풀 어야 합 니 다.이 매개 변 수 는 압축 을 풀 어 주 는 dex 파일 저장 경 로 를 만 드 는 것 입 니 다.이것 도 apk 에서 dex 가 플랫폼 에 따라 ODEX 를 최적화 하 는 과정 이다.사실 APK 는 프로그램 압축 패키지 입 니 다.그 안에 dex 파일 이 포함 되 어 있 습 니 다.ODEX 최 적 화 는 가방 안의 실행 프로그램 을 추출 하면 ODEX 파일 이 됩 니 다.추출 했 기 때문에 시스템 이 처음 시작 할 때 압축 프로그램 압축 패 키 지 를 풀 지 않 아 도 됩 니 다.압축 을 푸 는 과정 이 하나 줄 어 들 었 습 니 다.이렇게 되면 시스템 시동 이 빨 라 집 니 다.왜 처음 이 라 고 하 죠?DEX 버 전도 실행 프로그램 이/data/dalvik-cache(PathClassLoader 대상)나 optimizedDirectory(DexClassLoader 대상)디 렉 터 리 로 압축 을 풀 수 있 는 것 은 처음 뿐 이 고,그 다음 에 디 렉 터 리 에 있 는 dex 파일 을 직접 읽 기 때문에 두 번 째 시작 과 정상 적 인 차이 가 많 지 않 습 니 다.물론 이것 은 단순 한 이해 일 뿐 실제 생 성 된 ODEX 는 어느 정도 최적화 작용 을 한다.ClassLoader 는 내부 저장 경로 의 dex 파일 만 불 러 올 수 있 기 때문에 이 경 로 는 내부 경로 여야 합 니 다.
libPath 는 대상 클래스 에서 사용 하 는 C/C+재고 저장 경 로 를 말 합 니 다.
classload 는 이 로 더 의 부모 로 더 를 말 합 니 다.일반적으로 현재 실행 중인 클래스 의 로 더 를 말 합 니 다.예 를 들 어 Android 에 서 는 context.getClassLoader()를 부모 로 더 합 니 다.
5.DexClassLoader
DexClassLoader 는 APK,DEX,JAR 를 불 러 올 수 있 고 SD 카드 에서 도 불 러 올 수 있 습 니 다.위 에서 dalvik 는 jar 를 직접 식별 할 수 없다 고 말 했 는데,DexClassLoader 는 jar 파일 을 불 러 올 수 있다 는 것 은 모순 되 지 않 습 니까?사실 BaseDexClassLoader 에 서 는".jar","zip","apk","dex"접미사 파일 이 마지막 에 해당 하 는 dex 파일 을 만 들 기 때문에 최종 적 으로 dex 파일 을 처 리 했 고 URLClassLoader 는 유사 한 처 리 를 하지 않 았 습 니 다.일반적으로 우 리 는 이 DexClassLoader 를 동적 으로 불 러 오 는 로 더 로 사용한다.
6.PathClassLoader
PathClassLoader 는 optimizedDirectory 를 Null 로 설정 하지 않 았 습 니 다.즉,최 적 화 된 저장 경 로 를 설정 하지 않 았 습 니 다.사실 optimizedDirectory 가 null 일 때의 기본 경 로 는/data/dalvik-cache 디 렉 터 리 입 니 다.PathClassLoader 는 Android 시스템 클래스 와 응용 프로그램 을 불 러 오 는 클래스 이 며 개발 자 에 게 사용 을 권장 하지 않 습 니 다.많은 블 로그 에서 PathClassLoader 는 설 치 된 apk 의 dex 만 불 러 올 수 있다 고 합 니 다.사실은 이것 은 dalvik 가상 머 신 에 있 을 것 입 니 다.art 가상 머 신 에 PathClassLoader 는 설치 되 지 않 은 apk 의 dex(art 플랫폼 에서 검 증 된 것)를 불 러 올 수 있 지만/data/dalvik-cache 에서 해당 하 는 dex 파일 을 찾 지 못 했 습 니 다.art 가상 머 신 이 apk 가 설치 되 지 않 았 다 고 판단 한 것 으로 의심 합 니 다.그래서 apk 최적화 후의 odex 를 메모리 에 넣 고 방출 하 는 것 입 니 다.이것 은 단지 추측 일 뿐 입 니 다.아 는 것 이 있 으 면 알려 주 기 를 바 랍 니 다.dalvik 에서 사용 할 수 없 기 때문에 우리 도 사용 할 수 없습니다.
ClassLoder 소스 코드:
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17/*
18 * Copyright (C) 2008 The Android Open Source Project
19 *
20 * Licensed under the Apache License, Version 2.0 (the "License");
21 * you may not use this file except in compliance with the License.
22 * You may obtain a copy of the License at
23 *
24 * http://www.apache.org/licenses/LICENSE-2.0
25 *
26 * Unless required by applicable law or agreed to in writing, software
27 * distributed under the License is distributed on an "AS IS" BASIS,
28 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29 * See the License for the specific language governing permissions and
30 * limitations under the License.
31 */
32
33package java.lang;
34
35import dalvik.system.PathClassLoader;
36import java.io.IOException;
37import java.io.InputStream;
38import java.net.URL;
39import java.nio.ByteBuffer;
40import java.security.ProtectionDomain;
41import java.util.Collection;
42import java.util.Collections;
43import java.util.Enumeration;
44import java.util.HashMap;
45import java.util.Map;
46import java.util.Set;
47
48/**
49 * Loads classes and resources from a repository. One or more class loaders are       
50 * installed at runtime. These are consulted whenever the runtime system needs a
51 * specific class that is not yet available in-memory. Typically, class loaders
52 * are grouped into a tree where child class loaders delegate all requests to
53 * parent class loaders. Only if the parent class loader cannot satisfy the
54 * request, the child class loader itself tries to handle it.
55 * 

56 * {@code ClassLoader} is an abstract class that implements the common 57 * infrastructure required by all class loaders. Android provides several 58 * concrete implementations of the class, with 59 * {@link dalvik.system.PathClassLoader} being the one typically used. Other 60 * applications may implement subclasses of {@code ClassLoader} to provide 61 * special ways for loading classes. 62 *

63 * @see Class 64 */
/* , , , , 65public abstract class ClassLoader { 66 67 /** 68 * The 'System' ClassLoader - the one that is responsible for loading 69 * classes from the classpath. It is not equal to the bootstrap class loader - 70 * that one handles the built-in classes. 71 * 72 * Because of a potential class initialization race between ClassLoader and 73 * java.lang.System, reproducible when using JDWP with "suspend=y", we defer 74 * creation of the system class loader until first use. We use a static 75 * inner class to get synchronization at init time without having to sync on 76 * every access. 77 * 78 * @see #getSystemClassLoader() 79 */ /* , , , 80 static private class SystemClassLoader { 81 public static ClassLoader loader = ClassLoader.createSystemClassLoader(); 82 } 83 84 /** 85 * The parent ClassLoader. 86 */ 87 private ClassLoader parent; 88 89 /** 90 * The packages known to the class loader. 91 */ 92 private Map packages = new HashMap(); 93 94 /** 95 * To avoid unloading individual classes, {@link java.lang.reflect.Proxy} 96 * only generates one class for each set of interfaces. This maps sets of 97 * interfaces to the proxy class that implements all of them. It is declared 98 * here so that these generated classes can be unloaded with their class 99 * loader. 100 * 101 * @hide 102 */ 103 public final Map>, Class>> proxyCache 104 = Collections.synchronizedMap(new HashMap>, Class>>()); 105 106 /** 107 * Create the system class loader. Note this is NOT the bootstrap class 108 * loader (which is managed by the VM). We use a null value for the parent 109 * to indicate that the bootstrap loader is our parent. 110 */ 111 private static ClassLoader createSystemClassLoader() { 112 String classPath = System.getProperty("java.class.path", "."); 113 114 // String[] paths = classPath.split(":"); 115 // URL[] urls = new URL[paths.length]; 116 // for (int i = 0; i < paths.length; i++) { 117 // try { 118 // urls[i] = new URL("file://" + paths[i]); 119 // } 120 // catch (Exception ex) { 121 // ex.printStackTrace(); 122 // } 123 // } 124 // 125 // return new java.net.URLClassLoader(urls, null); 126 127 // TODO Make this a java.net.URLClassLoader once we have those? 128 return new PathClassLoader(classPath, BootClassLoader.getInstance()); 129 } 130 131 /** 132 * Returns the system class loader. This is the parent for new 133 * {@code ClassLoader} instances and is typically the class loader used to 134 * start the application. 135 */ 136 public static ClassLoader getSystemClassLoader() { 137 return SystemClassLoader.loader; 138 } 139 140 /** 141 * Finds the URL of the resource with the specified name. The system class 142 * loader's resource lookup algorithm is used to find the resource. 143 * 144 * @return the {@code URL} object for the requested resource or {@code null} 145 * if the resource can not be found. 146 * @param resName 147 * the name of the resource to find. 148 * @see Class#getResource 149 */ 150 public static URL getSystemResource(String resName) { 151 return SystemClassLoader.loader.getResource(resName); 152 } 153 154 /** 155 * Returns an enumeration of URLs for the resource with the specified name. 156 * The system class loader's resource lookup algorithm is used to find the 157 * resource. 158 * 159 * @return an enumeration of {@code URL} objects containing the requested 160 * resources. 161 * @param resName 162 * the name of the resource to find. 163 * @throws IOException 164 * if an I/O error occurs. 165 */ 166 public static Enumeration getSystemResources(String resName) throws IOException { 167 return SystemClassLoader.loader.getResources(resName); 168 } 169 170 /** 171 * Returns a stream for the resource with the specified name. The system 172 * class loader's resource lookup algorithm is used to find the resource. 173 * Basically, the contents of the java.class.path are searched in order, 174 * looking for a path which matches the specified resource. 175 * 176 * @return a stream for the resource or {@code null}. 177 * @param resName 178 * the name of the resource to find. 179 * @see Class#getResourceAsStream 180 */ 181 public static InputStream getSystemResourceAsStream(String resName) { 182 return SystemClassLoader.loader.getResourceAsStream(resName); 183 } 184 185 /** 186 * Constructs a new instance of this class with the system class loader as 187 * its parent. 188 */ 189 protected ClassLoader() { 190 this(getSystemClassLoader(), false); 191 } 192 193 /** 194 * Constructs a new instance of this class with the specified class loader 195 * as its parent. 196 * 197 * @param parentLoader 198 * The {@code ClassLoader} to use as the new class loader's 199 * parent. 200 */ 201 protected ClassLoader(ClassLoader parentLoader) { 202 this(parentLoader, false); 203 } 204 205 /* 206 * constructor for the BootClassLoader which needs parent to be null. 207 */ 208 ClassLoader(ClassLoader parentLoader, boolean nullAllowed) { 209 if (parentLoader == null && !nullAllowed) { 210 throw new NullPointerException("parentLoader == null && !nullAllowed"); 211 } 212 parent = parentLoader; 213 } 214 215 /** 216 * Constructs a new class from an array of bytes containing a class 217 * definition in class file format. 218 * 219 * @param classRep 220 * the memory image of a class file. 221 * @param offset 222 * the offset into {@code classRep}. 223 * @param length 224 * the length of the class file. 225 * @return the {@code Class} object created from the specified subset of 226 * data in {@code classRep}. 227 * @throws ClassFormatError 228 * if {@code classRep} does not contain a valid class. 229 * @throws IndexOutOfBoundsException 230 * if {@code offset < 0}, {@code length < 0} or if 231 * {@code offset + length} is greater than the length of 232 * {@code classRep}. 233 * @deprecated Use {@link #defineClass(String, byte[], int, int)} 234 */ 235 @Deprecated 236 protected final Class> defineClass(byte[] classRep, int offset, int length) 237 throws ClassFormatError { 238 throw new UnsupportedOperationException("can't load this type of class file"); 239 } 240 241 /** 242 * Constructs a new class from an array of bytes containing a class bytes 243 * definition in class file format. 244 * 245 * @param className 246 * the expected name of the new class, may be {@code null} if not 247 * known. 248 * @param classRep 249 * the memory image of a class file. 250 * @param offset 251 * the offset into {@code classRep}. 252 * @param length 253 * the length of the class file. 254 * @return the {@code Class} object created from the specified subset of 255 * data in {@code classRep}. 256 * @throws ClassFormatError 257 * if {@code classRep} does not contain a valid class. 258 * @throws IndexOutOfBoundsException 259 * if {@code offset < 0}, {@code length < 0} or if 260 * {@code offset + length} is greater than the length of 261 * {@code classRep}. 262 */ 263 protected final Class> defineClass(String className, byte[] classRep, int offset, int length) 264 throws ClassFormatError { 265 throw new UnsupportedOperationException("can't load this type of class file"); 266 } 267 268 /** 269 * Constructs a new class from an array of bytes containing a class 270 * definition in class file format and assigns the specified protection 271 * domain to the new class. If the provided protection domain is 272 * {@code null} then a default protection domain is assigned to the class. 273 * 274 * @param className 275 * the expected name of the new class, may be {@code null} if not 276 * known. 277 * @param classRep 278 * the memory image of a class file. 279 * @param offset 280 * the offset into {@code classRep}. 281 * @param length 282 * the length of the class file. 283 * @param protectionDomain 284 * the protection domain to assign to the loaded class, may be 285 * {@code null}. 286 * @return the {@code Class} object created from the specified subset of 287 * data in {@code classRep}. 288 * @throws ClassFormatError 289 * if {@code classRep} does not contain a valid class. 290 * @throws IndexOutOfBoundsException 291 * if {@code offset < 0}, {@code length < 0} or if 292 * {@code offset + length} is greater than the length of 293 * {@code classRep}. 294 * @throws NoClassDefFoundError 295 * if {@code className} is not equal to the name of the class 296 * contained in {@code classRep}. 297 */ 298 protected final Class> defineClass(String className, byte[] classRep, int offset, int length, 299 ProtectionDomain protectionDomain) throws java.lang.ClassFormatError { 300 throw new UnsupportedOperationException("can't load this type of class file"); 301 } 302 303 /** 304 * Defines a new class with the specified name, byte code from the byte 305 * buffer and the optional protection domain. If the provided protection 306 * domain is {@code null} then a default protection domain is assigned to 307 * the class. 308 * 309 * @param name 310 * the expected name of the new class, may be {@code null} if not 311 * known. 312 * @param b 313 * the byte buffer containing the byte code of the new class. 314 * @param protectionDomain 315 * the protection domain to assign to the loaded class, may be 316 * {@code null}. 317 * @return the {@code Class} object created from the data in {@code b}. 318 * @throws ClassFormatError 319 * if {@code b} does not contain a valid class. 320 * @throws NoClassDefFoundError 321 * if {@code className} is not equal to the name of the class 322 * contained in {@code b}. 323 */ 324 protected final Class> defineClass(String name, ByteBuffer b, 325 ProtectionDomain protectionDomain) throws ClassFormatError { 326 327 byte[] temp = new byte[b.remaining()]; 328 b.get(temp); 329 return defineClass(name, temp, 0, temp.length, protectionDomain); 330 } 331 332 /** 333 * Overridden by subclasses, throws a {@code ClassNotFoundException} by , 334 * default. This method is called by {@code loadClass} after the parent 335 * {@code ClassLoader} has failed to find a loaded class of the same name. 336 * 337 * @param className 338 * the name of the class to look for. 339 * @return the {@code Class} object that is found. 340 * @throws ClassNotFoundException 341 * if the class cannot be found. 342 */ 343 protected Class> findClass(String className) throws ClassNotFoundException { 344 throw new ClassNotFoundException(className); 345 } 346 347 /** 348 * Returns the class with the specified name if it has already been loaded 349 * by the VM or {@code null} if it has not yet been loaded. 350 * 351 * @param className 352 * the name of the class to look for. 353 * @return the {@code Class} object or {@code null} if the requested class 354 * has not been loaded. 355 */ 356 protected final Class> findLoadedClass(String className) { 357 ClassLoader loader; 358 if (this == BootClassLoader.getInstance()) 359 loader = null; 360 else 361 loader = this; 362 return VMClassLoader.findLoadedClass(loader, className); 363 } 364 365 /** 366 * Finds the class with the specified name, loading it using the system 367 * class loader if necessary. 368 * 369 * @param className 370 * the name of the class to look for. 371 * @return the {@code Class} object with the requested {@code className}. 372 * @throws ClassNotFoundException 373 * if the class can not be found. 374 */ 375 protected final Class> findSystemClass(String className) throws ClassNotFoundException { 376 return Class.forName(className, false, getSystemClassLoader()); 377 } 378 379 /** 380 * Returns this class loader's parent. 381 * 382 * @return this class loader's parent or {@code null}. 383 */ 384 public final ClassLoader getParent() { 385 return parent; 386 } 387 388 /** 389 * Returns the URL of the resource with the specified name. This 390 * implementation first tries to use the parent class loader to find the 391 * resource; if this fails then {@link #findResource(String)} is called to 392 * find the requested resource. 393 * 394 * @param resName 395 * the name of the resource to find. 396 * @return the {@code URL} object for the requested resource or {@code null} 397 * if the resource can not be found 398 * @see Class#getResource 399 */ 400 public URL getResource(String resName) { 401 URL resource = parent.getResource(resName); 402 if (resource == null) { 403 resource = findResource(resName); 404 } 405 return resource; 406 } 407 408 /** 409 * Returns an enumeration of URLs for the resource with the specified name. 410 * This implementation first uses this class loader's parent to find the 411 * resource, then it calls {@link #findResources(String)} to get additional // , findResources(resName) resources 412 * URLs. The returned enumeration contains the {@code URL} objects of both 413 * find operations. 414 * 415 * @return an enumeration of {@code URL} objects for the requested resource. 416 * @param resName 417 * the name of the resource to find. 418 * @throws IOException 419 * if an I/O error occurs. 420 */ 421 @SuppressWarnings("unchecked") 422 public Enumeration getResources(String resName) throws IOException { 423 424 Enumeration first = parent.getResources(resName); 425 Enumeration second = findResources(resName); 426 427 return new TwoEnumerationsInOne(first, second); 428 } 429 430 /** 431 * Returns a stream for the resource with the specified name. See 432 * {@link #getResource(String)} for a description of the lookup algorithm 433 * used to find the resource. 434 * 435 * @return a stream for the resource or {@code null} if the resource can not be found 436 * @param resName 437 * the name of the resource to find. 438 * @see Class#getResourceAsStream 439 */ 440 public InputStream getResourceAsStream(String resName) { 441 try { 442 URL url = getResource(resName); 443 if (url != null) { 444 return url.openStream(); 445 } 446 } catch (IOException ex) { 447 // Don't want to see the exception. 448 } 449 450 return null; 451 } 452 453 /** 454 * Loads the class with the specified name. Invoking this method is 455 * equivalent to calling {@code loadClass(className, false)}. loadClass(className, false) 456 *

457 * Note: In the Android reference implementation, the 458 * second parameter of {@link #loadClass(String, boolean)} is ignored 459 * anyway. 460 *

461 * 462 * @return the {@code Class} object. 463 * @param className 464 * the name of the class to look for. 465 * @throws ClassNotFoundException 466 * if the class can not be found. 467 */
468 public Class> loadClass(String className) throws ClassNotFoundException { 469 return loadClass(className, false); 470 } 471 472 /** 473 * Loads the class with the specified name, optionally linking it after 474 * loading. The following steps are performed: 475 *
    476 *
  1. Call {@link #findLoadedClass(String)} to determine if the requested 477 * class has already been loaded.
  2. 478 *
  3. If the class has not yet been loaded: Invoke this method on the 479 * parent class loader.
  4. 480 *
  5. If the class has still not been loaded: Call 481 * {@link #findClass(String)} to find the class.
  6. 482 *
483 *

484 * Note: In the Android reference implementation, the 485 * {@code resolve} parameter is ignored; classes are never linked. 486 *

487 * 488 * @return the {@code Class} object. 489 * @param className 490 * the name of the class to look for. 491 * @param resolve 492 * Indicates if the class should be resolved after loading. This , 493 * parameter is ignored on the Android reference implementation; 494 * classes are not resolved. 495 * @throws ClassNotFoundException 496 * if the class can not be found. 497 */
498 protected Class> loadClass(String className, boolean resolve) throws ClassNotFoundException { 499 Class> clazz = findLoadedClass(className); 500 501 if (clazz == null) { 502 ClassNotFoundException suppressed = null; 503 try { 504 clazz = parent.loadClass(className, false); 505 } catch (ClassNotFoundException e) { 506 suppressed = e; 507 } 508 509 if (clazz == null) { 510 try { 511 clazz = findClass(className); 512 } catch (ClassNotFoundException e) { 513 e.addSuppressed(suppressed); 514 throw e; 515 } 516 } 517 } 518 519 return clazz; 520 } 521 522 /** 523 * Forces a class to be linked (initialized). If the class has already been 524 * linked this operation has no effect. 525 *

526 * Note: In the Android reference implementation, this 527 * method has no effect. 528 *

529 * 530 * @param clazz 531 * the class to link. 532 */
533 protected final void resolveClass(Class> clazz) { 534 // no-op, doesn't make sense on android. 535 } 536 537 /** 538 * Finds the URL of the resource with the specified name. This 539 * implementation just returns {@code null}; it should be overridden in 540 * subclasses. 541 * 542 * @param resName 543 * the name of the resource to find. 544 * @return the {@code URL} object for the requested resource. 545 */ 546 protected URL findResource(String resName) { 547 return null; 548 } 549 550 /** 551 * Finds an enumeration of URLs for the resource with the specified name. 552 * This implementation just returns an empty {@code Enumeration}; it should enumeration of URLs for the resource, 553 * be overridden in subclasses. 554 * 555 * @param resName 556 * the name of the resource to find. 557 * @return an enumeration of {@code URL} objects for the requested resource. 558 * @throws IOException 559 * if an I/O error occurs. 560 */ 561 @SuppressWarnings( { 562 "unchecked", "unused" 563 }) 564 protected Enumeration findResources(String resName) throws IOException { 565 return Collections.emptyEnumeration(); 566 } 567 568 /** 569 * Returns the absolute path of the native library with the specified name, , null, java.library.path 570 * or {@code null}. If this method returns {@code null} then the virtual 571 * machine searches the directories specified by the system property 572 * "java.library.path". 573 *

574 * This implementation always returns {@code null}. 575 *

576 * 577 * @param libName 578 * the name of the library to find. 579 * @return the absolute path of the library. 580 */
581 protected String findLibrary(String libName) { 582 return null; 583 } 584 585 /** 586 * Returns the package with the specified name. Package information is 587 * searched in this class loader. 588 * 589 * @param name 590 * the name of the package to find. 591 * @return the package with the requested name; {@code null} if the package 592 * can not be found. 593 */ 594 protected Package getPackage(String name) { 595 synchronized (packages) { 596 return packages.get(name); 597 } 598 } 599 600 /** 601 * Returns all the packages known to this class loader. 602 * 603 * @return an array with all packages known to this class loader. 604 */ 605 protected Package[] getPackages() { 606 synchronized (packages) { 607 Collection col = packages.values(); 608 Package[] result = new Package[col.size()]; 609 col.toArray(result); 610 return result; 611 } 612 } 613 614 /** 615 * Defines and returns a new {@code Package} using the specified package 616 * information. If {@code sealBase} is {@code null}, the package is left 617 * unsealed. Otherwise, the package is sealed using this URL. 618 * 619 * @param name 620 * the name of the package. 621 * @param specTitle 622 * the title of the specification. 623 * @param specVersion 624 * the version of the specification. 625 * @param specVendor 626 * the vendor of the specification. 627 * @param implTitle 628 * the implementation title. 629 * @param implVersion 630 * the implementation version. 631 * @param implVendor 632 * the specification vendor. 633 * @param sealBase 634 * the URL used to seal this package or {@code null} to leave the 635 * package unsealed. 636 * @return the {@code Package} object that has been created. 637 * @throws IllegalArgumentException 638 * if a package with the specified name already exists. 639 */ 640 protected Package definePackage(String name, String specTitle, String specVersion, 641 String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase) 642 throws IllegalArgumentException { 643 644 synchronized (packages) { 645 if (packages.containsKey(name)) { 646 throw new IllegalArgumentException("Package " + name + " already defined"); 647 } 648 649 Package newPackage = new Package(name, specTitle, specVersion, specVendor, implTitle, 650 implVersion, implVendor, sealBase); 651 652 packages.put(name, newPackage); 653 654 return newPackage; 655 } 656 } 657 658 /** 659 * Sets the signers of the specified class. This implementation does 660 * nothing. 661 * 662 * @param c 663 * the {@code Class} object for which to set the signers. 664 * @param signers 665 * the signers for {@code c}. 666 */ 667 protected final void setSigners(Class> c, Object[] signers) { 668 } 669 670 /** 671 * Sets the assertion status of the class with the specified name. 672 *

673 * Note: This method does nothing in the Android reference 674 * implementation. 675 *

676 * 677 * @param cname 678 * the name of the class for which to set the assertion status. 679 * @param enable 680 * the new assertion status. 681 */
682 public void setClassAssertionStatus(String cname, boolean enable) { 683 } 684 685 /** 686 * Sets the assertion status of the package with the specified name. 687 *

688 * Note: This method does nothing in the Android reference 689 * implementation. 690 *

691 * 692 * @param pname 693 * the name of the package for which to set the assertion status. 694 * @param enable 695 * the new assertion status. 696 */
697 public void setPackageAssertionStatus(String pname, boolean enable) { 698 } 699 700 /** 701 * Sets the default assertion status for this class loader. 702 *

703 * Note: This method does nothing in the Android reference 704 * implementation. 705 *

706 * 707 * @param enable 708 * the new assertion status. 709 */
710 public void setDefaultAssertionStatus(boolean enable) { 711 } 712 713 /** 714 * Sets the default assertion status for this class loader to {@code false} 715 * and removes any package default and class assertion status settings. 716 *

717 * Note: This method does nothing in the Android reference 718 * implementation. 719 *

720 */
721 public void clearAssertionStatus() { 722 } 723} 724 725/* 726 * Provides a helper class that combines two existing URL enumerations into one. 727 * It is required for the getResources() methods. Items are fetched from the 728 * first enumeration until it's empty, then from the second one. 729 */ 730class TwoEnumerationsInOne implements Enumeration { 731 732 private final Enumeration first; 733 734 private final Enumeration second; 735 736 public TwoEnumerationsInOne(Enumeration first, Enumeration second) { 737 this.first = first; 738 this.second = second; 739 } 740 741 @Override 742 public boolean hasMoreElements() { 743 return first.hasMoreElements() || second.hasMoreElements(); 744 } 745 746 @Override 747 public URL nextElement() { 748 if (first.hasMoreElements()) { 749 return first.nextElement(); 750 } else { 751 return second.nextElement(); 752 } 753 } 754 755} 756 757/** 758 * Provides an explicit representation of the boot class loader. It sits at the 759 * head of the class loader chain and delegates requests to the VM's internal 760 * class loading mechanism. 761 */ 762class BootClassLoader extends ClassLoader { 763 764 private static BootClassLoader instance; 765 766 @FindBugsSuppressWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED") 767 public static synchronized BootClassLoader getInstance() { 768 if (instance == null) { 769 instance = new BootClassLoader(); 770 } 771 772 return instance; 773 } 774 775 public BootClassLoader() { 776 super(null, true); 777 } 778 779 @Override 780 protected Class> findClass(String name) throws ClassNotFoundException { 781 return Class.classForName(name, false, null); 782 } 783 784 @Override 785 protected URL findResource(String name) { 786 return VMClassLoader.getResource(name); 787 } 788 789 @SuppressWarnings("unused") 790 @Override 791 protected Enumeration findResources(String resName) throws IOException { 792 return Collections.enumeration(VMClassLoader.getResources(resName)); 793 } 794 795 /** 796 * Returns package information for the given package. Unfortunately, the 797 * Android BootClassLoader doesn't really have this information, and as a 798 * non-secure ClassLoader, it isn't even required to, according to the spec. 799 * Yet, we want to provide it, in order to make all those hopeful callers of 800 * {@code myClass.getPackage().getName()} happy. Thus we construct a Package 801 * object the first time it is being requested and fill most of the fields 802 * with dummy values. The Package object is then put into the ClassLoader's 803 * Package cache, so we see the same one next time. We don't create Package 804 * objects for null arguments or for the default package. 805 *

806 * There a limited chance that we end up with multiple Package objects 807 * representing the same package: It can happen when when a package is 808 * scattered across different JAR files being loaded by different 809 * ClassLoaders. Rather unlikely, and given that this whole thing is more or 810 * less a workaround, probably not worth the effort. 811 */

812 @Override 813 protected Package getPackage(String name) { 814 if (name != null && !name.isEmpty()) { 815 synchronized (this) { 816 Package pack = super.getPackage(name); 817 818 if (pack == null) { 819 pack = definePackage(name, "Unknown", "0.0", "Unknown", "Unknown", "0.0", 820 "Unknown", null); 821 } 822 823 return pack; 824 } 825 } 826 827 return null; 828 } 829 830 @Override 831 public URL getResource(String resName) { 832 return findResource(resName); 833 } 834 835 @Override 836 protected Class> loadClass(String className, boolean resolve) 837 throws ClassNotFoundException { 838 Class> clazz = findLoadedClass(className); 839 840 if (clazz == null) { 841 clazz = findClass(className); 842 } 843 844 return clazz; 845 } 846 847 @Override 848 public Enumeration getResources(String resName) throws IOException { 849 return findResources(resName); 850 } 851} 852 853/** 854 * TODO Open issues - Missing / empty methods - Signer stuff - Protection 855 * domains - Assertions 856 */

이 부분의 논 리 를 중점적으로 보다.

    protected Class> loadClass(String className,     boolean resolve) throws ClassNotFoundException {
499        Class> clazz = findLoadedClass(className); //           
500
501        if (clazz == null) {
502            ClassNotFoundException suppressed = null;
503            try {
504                clazz = parent.loadClass(className, false);      //         
505            } catch (ClassNotFoundException e) {
506                suppressed = e;
507            }
508
509            if (clazz == null) {
510                try {
511                    clazz = findClass(className);  //          
512                } catch (ClassNotFoundException e) {
513                    e.addSuppressed(suppressed);
514                    throw e;
515                }
516            }
517        }
518
519        return clazz;
}
520
521

좋은 웹페이지 즐겨찾기