DexClassLoder解析

Android类装载器DexClassLoader的简单使用

DexClassLoader 可以加载外部的 apk、jar 或 dex文件,

在java中,有个概念叫做“类加载器”(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,等都最终继承自java.lang.ClassLoader。

1.java.lang.ClassLoader是所有ClassLoader的最终父类。
2.BootClassLoader
和java虚拟机中不同的是BootClassLoader是ClassLoader内部类,由java代码实现而不是c++实现,是Android平台上所有ClassLoader的最终parent,这个内部类是包内可见,所以我们没法使用。
3.URLClassLoader
只能用于加载jar文件,但是由于 dalvik 不能直接识别jar,所以在 Android 中无法使用这个加载器。
4.BaseDexClassLoader
PathClassLoader和DexClassLoader都继承自BaseDexClassLoader,其中的主要逻辑都是在BaseDexClassLoader完成的。这些源码在java/dalvik/system中。

BaseDexClassLoader的构造函数包含四个参数,分别为:
dexPath,指目标类所在的APK或jar文件的路径,类装载器将从该路径中寻找指定的目标类,该类必须是APK或jar的全路径.如果要包含多个路径,路径之间必须使用特定的分割符分隔,特定的分割符可以使用System.getProperty(“path.separtor”)获得。上面”支持加载APK、DEX和JAR,也可以从SD卡进行加载”指的就是这个路径,最终做的是将dexPath路径上的文件ODEX优化到内部位置optimizedDirectory,然后,再进行加载的。

File optimizedDirectory,由于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

你可能感兴趣的:(android学习笔)