001/* 002 * @(#)Launcher.java 1.42 05/11/17 003 * 004 * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. 005 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 006 */ 007 008package sun.misc; 009 010import java.io.File; 011import java.io.IOException; 012import java.io.FilePermission; 013import java.net.URL; 014import java.net.URLClassLoader; 015import java.net.MalformedURLException; 016import java.net.URLStreamHandler; 017import java.net.URLStreamHandlerFactory; 018import java.util.HashSet; 019import java.util.StringTokenizer; 020import java.util.Set; 021import java.util.Vector; 022import java.security.AccessController; 023import java.security.AllPermission; 024import java.security.PrivilegedAction; 025import java.security.PrivilegedExceptionAction; 026import java.security.AccessControlContext; 027import java.security.PermissionCollection; 028import java.security.Permissions; 029import java.security.Permission; 030import java.security.ProtectionDomain; 031import java.security.CodeSource; 032import sun.security.action.GetPropertyAction; 033import sun.security.util.SecurityConstants; 034import sun.net.www.ParseUtil; 035import sun.jkernel.Bundle; 036import sun.jkernel.DownloadManager; 037 038/** 039 * This class is used by the system to launch the main application. 040Launcher */ 041public class Launcher { 042 private static URLStreamHandlerFactory factory = new Factory(); 043 private static Launcher launcher = new Launcher(); 044 045 public static Launcher getLauncher() { 046 return launcher; 047 } 048 049 private ClassLoader loader; 050 051 public Launcher() { 052 // Create the extension class loader 053 ClassLoader extcl; 054 try { 055 extcl = ExtClassLoader.getExtClassLoader(); 056 } catch (IOException e) { 057 throw new InternalError( 058 "Could not create extension class loader"); 059 } 060 061 // Now create the class loader to use to launch the application 062 try { 063 loader = AppClassLoader.getAppClassLoader(extcl); 064 } catch (IOException e) { 065 throw new InternalError( 066 "Could not create application class loader"); 067 } 068 069 // Also set the context class loader for the primordial thread. 070 Thread.currentThread().setContextClassLoader(loader); 071 072 // Finally, install a security manager if requested 073 String s = System.getProperty("java.security.manager"); 074 if (s != null) { 075 SecurityManager sm = null; 076 if ("".equals(s) || "default".equals(s)) { 077 sm = new java.lang.SecurityManager(); 078 } else { 079 try { 080 sm = (SecurityManager)loader.loadClass(s).newInstance(); 081 } catch (IllegalAccessException e) { 082 } catch (InstantiationException e) { 083 } catch (ClassNotFoundException e) { 084 } catch (ClassCastException e) { 085 } 086 } 087 if (sm != null) { 088 System.setSecurityManager(sm); 089 } else { 090 throw new InternalError( 091 "Could not create SecurityManager: " + s); 092 } 093 } 094 } 095 096 /* 097 * Returns the class loader used to launch the main application. 098 */ 099 public ClassLoader getClassLoader() { 100 return loader; 101 } 102 103 public static void addURLToAppClassLoader(URL u) { 104 AccessController.checkPermission(new AllPermission()); 105 ClassLoader loader = Launcher.getLauncher().getClassLoader(); 106 ((Launcher.AppClassLoader) loader).addAppURL(u); 107 } 108 109 110 public static void addURLToExtClassLoader(URL u) { 111 AccessController.checkPermission(new AllPermission()); 112 ClassLoader loader = Launcher.getLauncher().getClassLoader(); 113 ((Launcher.ExtClassLoader) loader.getParent()).addExtURL(u); 114 } 115 116 /* 117 * The class loader used for loading installed extensions. 118 */ 119 static class ExtClassLoader extends URLClassLoader { 120 private File[] dirs; 121 122 /** 123 * create an ExtClassLoader. The ExtClassLoader is created 124 * within a context that limits which files it can read 125 */ 126 public static ExtClassLoader getExtClassLoader() throws IOException 127 { 128 final File[] dirs = getExtDirs(); 129 130 try { 131 // Prior implementations of this doPrivileged() block supplied 132 // aa synthesized ACC via a call to the private method 133 // ExtClassLoader.getContext(). 134 135 return (ExtClassLoader) AccessController.doPrivileged( 136 new PrivilegedExceptionAction() { 137 public Object run() throws IOException { 138 int len = dirs.length; 139 for (int i = 0; i < len; i++) { 140 MetaIndex.registerDirectory(dirs[i]); 141 } 142 return new ExtClassLoader(dirs); 143 } 144 }); 145 } catch (java.security.PrivilegedActionException e) { 146 throw (IOException) e.getException(); 147 } 148 } 149 150 void addExtURL(URL url) { 151 super.addURL(url); 152 } 153 154 /* 155 * Creates a new ExtClassLoader for the specified directories. 156 */ 157 public ExtClassLoader(File[] dirs) throws IOException { 158 super(getExtURLs(dirs), null, factory); 159 this.dirs = dirs; 160 } 161 162 private static File[] getExtDirs() { 163 String s = System.getProperty("java.ext.dirs"); 164 File[] dirs; 165 if (s != null) { 166 StringTokenizer st = 167 new StringTokenizer(s, File.pathSeparator); 168 int count = st.countTokens(); 169 dirs = new File[count]; 170 for (int i = 0; i < count; i++) { 171 dirs[i] = new File(st.nextToken()); 172 } 173 } else { 174 dirs = new File[0]; 175 } 176 return dirs; 177 } 178 179 private static URL[] getExtURLs(File[] dirs) throws IOException { 180 Vector urls = new Vector(); 181 for (int i = 0; i < dirs.length; i++) { 182 String[] files = dirs[i].list(); 183 if (files != null) { 184 for (int j = 0; j < files.length; j++) { 185 if (!files[j].equals("meta-index")) { 186 File f = new File(dirs[i], files[j]); 187 urls.add(getFileURL(f)); 188 } 189 } 190 } 191 } 192 URL[] ua = new URL[urls.size()]; 193 urls.copyInto(ua); 194 return ua; 195 } 196 197 /* 198 * Searches the installed extension directories for the specified 199 * library name. For each extension directory, we first look for 200 * the native library in the subdirectory whose name is the value 201 * of the system property <code>os.arch</code>. Failing that, we 202 * look in the extension directory itself. 203 */ 204 public String findLibrary(String name) { 205 name = System.mapLibraryName(name); 206 for (int i = 0; i < dirs.length; i++) { 207 // Look in architecture-specific subdirectory first 208 String arch = System.getProperty("os.arch"); 209 if (arch != null) { 210 File file = new File(new File(dirs[i], arch), name); 211 if (file.exists()) { 212 return file.getAbsolutePath(); 213 } 214 } 215 // Then check the extension directory 216 File file = new File(dirs[i], name); 217 if (file.exists()) { 218 return file.getAbsolutePath(); 219 } 220 } 221 return null; 222 } 223 224 protected Class findClass(String name) throws ClassNotFoundException { 225 // Check for download before we look for it. If DownloadManager ends up 226 // downloading it, it will add it to our search path before we proceed 227 // to the findClass(). 228 DownloadManager.getBootClassPathEntryForClass(name); 229 return super.findClass(name); 230 } 231 232 private static AccessControlContext getContext(File[] dirs) 233 throws IOException 234 { 235 PathPermissions perms = 236 new PathPermissions(dirs); 237 238 ProtectionDomain domain = new ProtectionDomain( 239 new CodeSource(perms.getCodeBase(), 240 (java.security.cert.Certificate[]) null), 241 perms); 242 243 AccessControlContext acc = 244 new AccessControlContext(new ProtectionDomain[] { domain }); 245 246 return acc; 247 } 248 } 249 250 /** 251 * The class loader used for loading from java.class.path. 252 * runs in a restricted security context. 253 */ 254 static class AppClassLoader extends URLClassLoader { 255 256 public static ClassLoader getAppClassLoader(final ClassLoader extcl) 257 throws IOException 258 { 259 final String s = System.getProperty("java.class.path"); 260 final File[] path = (s == null) ? new File[0] : getClassPath(s); 261 262 // Note: on bugid 4256530 263 // Prior implementations of this doPrivileged() block supplied 264 // a rather restrictive ACC via a call to the private method 265 // AppClassLoader.getContext(). This proved overly restrictive 266 // when loading classes. Specifically it prevent 267 // accessClassInPackage.sun.* grants from being honored. 268 // 269 return (AppClassLoader) 270 AccessController.doPrivileged(new PrivilegedAction() { 271 public Object run() { 272 URL[] urls = 273 (s == null) ? new URL[0] : pathToURLs(path); 274 return new AppClassLoader(urls, extcl); 275 } 276 }); 277 } 278 279 /* 280 * Creates a new AppClassLoader 281 */ 282 AppClassLoader(URL[] urls, ClassLoader parent) { 283 super(urls, parent, factory); 284 } 285 286 287 /** 288 * Override loadClass so we can checkPackageAccess. 289 */ 290 public synchronized Class loadClass(String name, boolean resolve) 291 throws ClassNotFoundException 292 { 293 DownloadManager.getBootClassPathEntryForClass(name); 294 int i = name.lastIndexOf('.'); 295 if (i != -1) { 296 SecurityManager sm = System.getSecurityManager(); 297 if (sm != null) { 298 sm.checkPackageAccess(name.substring(0, i)); 299 } 300 } 301 return (super.loadClass(name, resolve)); 302 } 303 304 /** 305 * allow any classes loaded from classpath to exit the VM. 306 */ 307 protected PermissionCollection getPermissions(CodeSource codesource) 308 { 309 PermissionCollection perms = super.getPermissions(codesource); 310 perms.add(new RuntimePermission("exitVM")); 311 return perms; 312 } 313 314 /** 315 * This class loader supports dynamic additions to the class path 316 * at runtime. 317 * 318 * @see java.lang.instrument.Instrumentation#appendToSystemClassPathSearch 319 */ 320 private void appendToClassPathForInstrumentation(String path) { 321 assert(Thread.holdsLock(this)); 322 323 // addURL is a no-op if path already contains the URL 324 super.addURL( getFileURL(new File(path)) ); 325 } 326 327 /** 328 * create a context that can read any directories (recursively) 329 * mentioned in the class path. In the case of a jar, it has to 330 * be the directory containing the jar, not just the jar, as jar 331 * files might refer to other jar files. 332 */ 333 334 private static AccessControlContext getContext(File[] cp) 335 throws java.net.MalformedURLException 336 { 337 PathPermissions perms = 338 new PathPermissions(cp); 339 340 ProtectionDomain domain = 341 new ProtectionDomain(new CodeSource(perms.getCodeBase(), 342 (java.security.cert.Certificate[]) null), 343 perms); 344 345 AccessControlContext acc = 346 new AccessControlContext(new ProtectionDomain[] { domain }); 347 348 return acc; 349 } 350 351 352 void addAppURL(URL url) { 353 super.addURL(url); 354 } 355 356 } 357 358 private static URLClassPath bootstrapClassPath; 359 360 public static synchronized URLClassPath getBootstrapClassPath() { 361 if (bootstrapClassPath == null) { 362 String prop = (String)AccessController.doPrivileged(new GetPropertyAction("sun.boot.class.path")); 363 URL[] urls; 364 if (prop != null) { 365 final String path = prop; 366 urls = (URL[])AccessController.doPrivileged( 367 new PrivilegedAction() { 368 public Object run() { 369 File[] classPath = getClassPath(path); 370 int len = classPath.length; 371 Set seenDirs = new HashSet(); 372 for (int i = 0; i < len; i++) { 373 File curEntry = classPath[i]; 374 // Negative test used to properly handle 375 // nonexistent jars on boot class path 376 if (!curEntry.isDirectory()) { 377 curEntry = curEntry.getParentFile(); 378 } 379 if (curEntry != null && seenDirs.add(curEntry)) { 380 MetaIndex.registerDirectory(curEntry); 381 } 382 } 383 return pathToURLs(classPath); 384 } 385 } 386 ); 387 } else { 388 urls = new URL[0]; 389 } 390 391 bootstrapClassPath = new URLClassPath(urls, factory); 392 final File[] additionalBootStrapPaths = 393 DownloadManager.getAdditionalBootStrapPaths(); 394 AccessController.doPrivileged( 395 new PrivilegedAction() { 396 public Object run() { 397 for (int i = 0; i < additionalBootStrapPaths.length; i++) 398 bootstrapClassPath.addURL(getFileURL(additionalBootStrapPaths[i])); 399 return null; 400 } 401 }); 402 } 403 return bootstrapClassPath; 404 } 405 406 407 public static synchronized void flushBootstrapClassPath() { 408 bootstrapClassPath = null; 409 } 410 411 412 private static URL[] pathToURLs(File[] path) { 413 URL[] urls = new URL[path.length]; 414 for (int i = 0; i < path.length; i++) { 415 urls[i] = getFileURL(path[i]); 416 } 417 // DEBUG 418 //for (int i = 0; i < urls.length; i++) { 419 // System.out.println("urls[" + i + "] = " + '"' + urls[i] + '"'); 420 //} 421 return urls; 422 } 423 424 private static File[] getClassPath(String cp) { 425 File[] path; 426 if (cp != null) { 427 int count = 0, maxCount = 1; 428 int pos = 0, lastPos = 0; 429 // Count the number of separators first 430 while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) { 431 maxCount++; 432 lastPos = pos + 1; 433 } 434 path = new File[maxCount]; 435 lastPos = pos = 0; 436 // Now scan for each path component 437 while ((pos = cp.indexOf(File.pathSeparator, lastPos)) != -1) { 438 if (pos - lastPos > 0) { 439 path[count++] = new File(cp.substring(lastPos, pos)); 440 } else { 441 // empty path component translates to "." 442 path[count++] = new File("."); 443 } 444 lastPos = pos + 1; 445 } 446 // Make sure we include the last path component 447 if (lastPos < cp.length()) { 448 path[count++] = new File(cp.substring(lastPos)); 449 } else { 450 path[count++] = new File("."); 451 } 452 // Trim array to correct size 453 if (count != maxCount) { 454 File[] tmp = new File[count]; 455 System.arraycopy(path, 0, tmp, 0, count); 456 path = tmp; 457 } 458 } else { 459 path = new File[0]; 460 } 461 // DEBUG 462 //for (int i = 0; i < path.length; i++) { 463 // System.out.println("path[" + i + "] = " + '"' + path[i] + '"'); 464 //} 465 return path; 466 } 467 468 private static URLStreamHandler fileHandler; 469 470 static URL getFileURL(File file) { 471 try { 472 file = file.getCanonicalFile(); 473 } catch (IOException e) {} 474 475 try { 476 return ParseUtil.fileToEncodedURL(file); 477 } catch (MalformedURLException e) { 478 // Should never happen since we specify the protocol... 479 throw new InternalError(); 480 } 481 } 482 483 /* 484 * The stream handler factory for loading system protocol handlers. 485 */ 486 private static class Factory implements URLStreamHandlerFactory { 487 private static String PREFIX = "sun.net.www.protocol"; 488 489 public URLStreamHandler createURLStreamHandler(String protocol) { 490 String name = PREFIX + "." + protocol + ".Handler"; 491 try { 492 Class c = Class.forName(name); 493 return (URLStreamHandler)c.newInstance(); 494 } catch (ClassNotFoundException e) { 495 e.printStackTrace(); 496 } catch (InstantiationException e) { 497 e.printStackTrace(); 498 } catch (IllegalAccessException e) { 499 e.printStackTrace(); 500 } 501 throw new InternalError("could not load " + protocol + 502 "system protocol handler"); 503 } 504 } 505} 506 507class PathPermissions extends PermissionCollection { 508 // use serialVersionUID from JDK 1.2.2 for interoperability 509 private static final long serialVersionUID = 8133287259134945693L; 510 511 private File path[]; 512 private Permissions perms; 513 514 URL codeBase; 515 516 PathPermissions(File path[]) 517 { 518 this.path = path; 519 this.perms = null; 520 this.codeBase = null; 521 } 522 523 URL getCodeBase() 524 { 525 return codeBase; 526 } 527 528 public void add(java.security.Permission permission) { 529 throw new SecurityException("attempt to add a permission"); 530 } 531 532 private synchronized void init() 533 { 534 if (perms != null) 535 return; 536 537 perms = new Permissions(); 538 539 // this is needed to be able to create the classloader itself! 540 perms.add(SecurityConstants.CREATE_CLASSLOADER_PERMISSION); 541 542 // add permission to read any "java.*" property 543 perms.add(new java.util.PropertyPermission("java.*", 544 SecurityConstants.PROPERTY_READ_ACTION)); 545 546 AccessController.doPrivileged(new PrivilegedAction() { 547 public Object run() { 548 for (int i=0; i < path.length; i++) { 549 File f = path[i]; 550 String path; 551 try { 552 path = f.getCanonicalPath(); 553 } catch (IOException ioe) { 554 path = f.getAbsolutePath(); 555 } 556 if (i == 0) { 557 codeBase = Launcher.getFileURL(new File(path)); 558 } 559 if (f.isDirectory()) { 560 if (path.endsWith(File.separator)) { 561 perms.add(new FilePermission(path+"-", 562 SecurityConstants.FILE_READ_ACTION)); 563 } else { 564 perms.add(new FilePermission( 565 path + File.separator+"-", 566 SecurityConstants.FILE_READ_ACTION)); 567 } 568 } else { 569 int endIndex = path.lastIndexOf(File.separatorChar); 570 if (endIndex != -1) { 571 path = path.substring(0, endIndex+1) + "-"; 572 perms.add(new FilePermission(path, 573 SecurityConstants.FILE_READ_ACTION)); 574 } else { 575 // XXX? 576 } 577 } 578 } 579 return null; 580 } 581 }); 582 } 583 584 public boolean implies(java.security.Permission permission) { 585 if (perms == null) 586 init(); 587 return perms.implies(permission); 588 } 589 590 public java.util.Enumeration elements() { 591 if (perms == null) 592 init(); 593 synchronized (perms) { 594 return perms.elements(); 595 } 596 } 597 598 public String toString() { 599 if (perms == null) 600 init(); 601 return perms.toString(); 602 } 603}