DexClassLoder 해석
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 * - Call {@link #findLoadedClass(String)} to determine if the requested
477 * class has already been loaded.
478 * - If the class has not yet been loaded: Invoke this method on the
479 * parent class loader.
480 * - If the class has still not been loaded: Call
481 * {@link #findClass(String)} to find the class.
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