| 1 12 package org.eclipse.core.runtime.adaptor; 13 14 import java.io.*; 15 import java.lang.reflect.Constructor ; 16 import java.lang.reflect.Method ; 17 import java.net.*; 18 import java.security.CodeSource ; 19 import java.security.ProtectionDomain ; 20 import java.util.*; 21 import org.eclipse.core.runtime.internal.adaptor.*; 22 import org.eclipse.osgi.framework.adaptor.FilePath; 23 import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; 24 import org.eclipse.osgi.framework.internal.core.*; 25 import org.eclipse.osgi.framework.internal.core.Constants; 26 import org.eclipse.osgi.framework.log.FrameworkLog; 27 import org.eclipse.osgi.framework.log.FrameworkLogEntry; 28 import org.eclipse.osgi.internal.profile.Profile; 29 import org.eclipse.osgi.service.datalocation.Location; 30 import org.eclipse.osgi.service.resolver.*; 31 import org.eclipse.osgi.service.runnable.ApplicationLauncher; 32 import org.eclipse.osgi.service.runnable.StartupMonitor; 33 import org.eclipse.osgi.util.ManifestElement; 34 import org.eclipse.osgi.util.NLS; 35 import org.osgi.framework.*; 36 import org.osgi.service.packageadmin.PackageAdmin; 37 import org.osgi.service.startlevel.StartLevel; 38 import org.osgi.util.tracker.ServiceTracker; 39 40 55 public class EclipseStarter { 56 private static FrameworkAdaptor adaptor; 57 private static BundleContext context; 58 private static boolean initialize = false; 59 public static boolean debug = false; 60 private static boolean running = false; 61 private static OSGi osgi = null; 62 private static ServiceRegistration defaultMonitorRegistration = null; 63 private static ServiceRegistration appLauncherRegistration = null; 64 private static ServiceRegistration splashStreamRegistration = null; 65 66 private static final String CLEAN = "-clean"; private static final String CONSOLE = "-console"; private static final String CONSOLE_LOG = "-consoleLog"; private static final String DEBUG = "-debug"; private static final String INITIALIZE = "-initialize"; private static final String DEV = "-dev"; private static final String WS = "-ws"; private static final String OS = "-os"; private static final String ARCH = "-arch"; private static final String NL = "-nl"; private static final String CONFIGURATION = "-configuration"; private static final String USER = "-user"; private static final String NOEXIT = "-noExit"; 81 private static final String DATA = "-data"; 85 public static final String PROP_BUNDLES = "osgi.bundles"; public static final String PROP_BUNDLES_STARTLEVEL = "osgi.bundles.defaultStartLevel"; public static final String PROP_EXTENSIONS = "osgi.framework.extensions"; public static final String PROP_INITIAL_STARTLEVEL = "osgi.startLevel"; public static final String PROP_DEBUG = "osgi.debug"; public static final String PROP_DEV = "osgi.dev"; public static final String PROP_CLEAN = "osgi.clean"; public static final String PROP_CONSOLE = "osgi.console"; public static final String PROP_CONSOLE_CLASS = "osgi.consoleClass"; public static final String PROP_CHECK_CONFIG = "osgi.checkConfiguration"; public static final String PROP_OS = "osgi.os"; public static final String PROP_WS = "osgi.ws"; public static final String PROP_NL = "osgi.nl"; public static final String PROP_ARCH = "osgi.arch"; public static final String PROP_ADAPTOR = "osgi.adaptor"; public static final String PROP_SYSPATH = "osgi.syspath"; public static final String PROP_LOGFILE = "osgi.logfile"; public static final String PROP_FRAMEWORK = "osgi.framework"; public static final String PROP_INSTALL_AREA = "osgi.install.area"; public static final String PROP_FRAMEWORK_SHAPE = "osgi.framework.shape"; public static final String PROP_NOSHUTDOWN = "osgi.noShutdown"; private static final String PROP_FORCED_RESTART = "osgi.forcedRestart"; 109 public static final String PROP_EXITCODE = "eclipse.exitcode"; public static final String PROP_EXITDATA = "eclipse.exitdata"; public static final String PROP_CONSOLE_LOG = "eclipse.consoleLog"; public static final String PROP_IGNOREAPP = "eclipse.ignoreApp"; public static final String PROP_REFRESH_BUNDLES = "eclipse.refreshBundles"; private static final String PROP_ALLOW_APPRELAUNCH = "eclipse.allowAppRelaunch"; private static final String PROP_APPLICATION_LAUNCHDEFAULT = "eclipse.application.launchDefault"; 117 private static final String FILE_SCHEME = "file:"; private static final String REFERENCE_SCHEME = "reference:"; private static final String REFERENCE_PROTOCOL = "reference"; private static final String INITIAL_LOCATION = "initial@"; 122 protected static final String DEFAULT_ADAPTOR_CLASS = "org.eclipse.osgi.baseadaptor.BaseAdaptor"; 124 private static final int DEFAULT_INITIAL_STARTLEVEL = 6; private static final String DEFAULT_BUNDLES_STARTLEVEL = "4"; protected static final String DEFAULT_CONSOLE_CLASS = "org.eclipse.osgi.framework.internal.core.FrameworkConsole"; private static final String CONSOLE_NAME = "OSGi Console"; 130 private static Runnable console; 131 private static FrameworkLog log; 132 private static HashMap searchCandidates = new HashMap(4); 134 private static EclipseAppLauncher appLauncher; 135 private static List shutdownHandlers; 136 137 141 public static void main(String [] args) throws Exception { 142 if (FrameworkProperties.getProperty("eclipse.startTime") == null) FrameworkProperties.setProperty("eclipse.startTime", Long.toString(System.currentTimeMillis())); if (FrameworkProperties.getProperty(PROP_NOSHUTDOWN) == null) 145 FrameworkProperties.setProperty(PROP_NOSHUTDOWN, "true"); if (FrameworkProperties.getProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION) == null) 148 FrameworkProperties.setProperty(Constants.OSGI_COMPATIBILITY_BOOTDELEGATION, "false"); run(args, null); 150 } 151 152 165 public static Object run(String [] args, Runnable endSplashHandler) throws Exception { 166 if (Profile.PROFILE && Profile.STARTUP) 167 Profile.logEnter("EclipseStarter.run()", null); if (running) 169 throw new IllegalStateException (EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING); 170 boolean startupFailed = true; 171 try { 172 startup(args, endSplashHandler); 173 startupFailed = false; 174 if (Boolean.valueOf(FrameworkProperties.getProperty(PROP_IGNOREAPP)).booleanValue() || isForcedRestart()) 175 return null; 176 return run(null); 177 } catch (Throwable e) { 178 if (endSplashHandler != null) 180 endSplashHandler.run(); 181 FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, startupFailed ? EclipseAdaptorMsg.ECLIPSE_STARTUP_STARTUP_ERROR : EclipseAdaptorMsg.ECLIPSE_STARTUP_APP_ERROR, 1, e, null); 183 if (log != null) { 184 log.log(logEntry); 185 if (context != null) logUnresolvedBundles(context.getBundles()); 187 } else 188 e.printStackTrace(); 190 } finally { 191 try { 192 if (isForcedRestart()) 195 FrameworkProperties.setProperty(PROP_EXITCODE, "23"); if (!Boolean.valueOf(FrameworkProperties.getProperty(PROP_NOSHUTDOWN)).booleanValue()) 197 shutdown(); 198 } catch (Throwable e) { 199 FrameworkLogEntry logEntry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_SHUTDOWN_ERROR, 1, e, null); 200 if (log != null) 201 log.log(logEntry); 202 else 203 e.printStackTrace(); 205 } 206 if (Profile.PROFILE && Profile.STARTUP) 207 Profile.logExit("EclipseStarter.run()"); if (Profile.PROFILE) { 209 String report = Profile.getProfileLog(); 210 if (report != null && report.length() > 0) 212 System.out.println(report); 213 } 214 } 215 FrameworkProperties.setProperty(PROP_EXITCODE, "13"); FrameworkProperties.setProperty(PROP_EXITDATA, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_CHECK_LOG, log == null ? null : log.getFile().getPath())); 218 return null; 219 } 220 221 225 public static boolean isRunning() { 226 return running; 227 } 228 229 protected static FrameworkLog createFrameworkLog() { 230 FrameworkLog frameworkLog; 231 String logFileProp = FrameworkProperties.getProperty(EclipseStarter.PROP_LOGFILE); 232 if (logFileProp != null) { 233 frameworkLog = new EclipseLog(new File(logFileProp)); 234 } else { 235 Location location = LocationManager.getConfigurationLocation(); 236 File configAreaDirectory = null; 237 if (location != null) 238 configAreaDirectory = new File(location.getURL().getFile()); 240 241 if (configAreaDirectory != null) { 242 String logFileName = Long.toString(System.currentTimeMillis()) + ".log"; File logFile = new File(configAreaDirectory, logFileName); 244 FrameworkProperties.setProperty(EclipseStarter.PROP_LOGFILE, logFile.getAbsolutePath()); 245 frameworkLog = new EclipseLog(logFile); 246 } else 247 frameworkLog = new EclipseLog(); 248 } 249 if ("true".equals(FrameworkProperties.getProperty(EclipseStarter.PROP_CONSOLE_LOG))) frameworkLog.setConsoleLog(true); 251 return frameworkLog; 252 } 253 254 265 public static BundleContext startup(String [] args, Runnable endSplashHandler) throws Exception { 266 if (Profile.PROFILE && Profile.STARTUP) 267 Profile.logEnter("EclipseStarter.startup()", null); if (running) 269 throw new IllegalStateException (EclipseAdaptorMsg.ECLIPSE_STARTUP_ALREADY_RUNNING); 270 initializeProperties(); 271 processCommandLine(args); 272 LocationManager.initializeLocations(); 273 loadConfigurationInfo(); 274 finalizeProperties(); 275 if (Profile.PROFILE) 276 Profile.initProps(); if (Profile.PROFILE && Profile.STARTUP) 278 Profile.logTime("EclipseStarter.startup()", "props inited"); adaptor = createAdaptor(); 280 log = adaptor.getFrameworkLog(); 281 if (Profile.PROFILE && Profile.STARTUP) 282 Profile.logTime("EclipseStarter.startup()", "adapter created"); osgi = new OSGi(adaptor); 284 if (Profile.PROFILE && Profile.STARTUP) 285 Profile.logTime("EclipseStarter.startup()", "OSGi created"); context = osgi.getBundleContext(); 287 registerFrameworkShutdownHandlers(); 288 publishSplashScreen(endSplashHandler); 289 osgi.launch(); 290 if (Profile.PROFILE && Profile.STARTUP) 291 Profile.logTime("EclipseStarter.startup()", "osgi launched"); String consolePort = FrameworkProperties.getProperty(PROP_CONSOLE); 293 if (consolePort != null) { 294 startConsole(osgi, new String [0], consolePort); 295 if (Profile.PROFILE && Profile.STARTUP) 296 Profile.logTime("EclipseStarter.startup()", "console started"); } 298 if ("true".equals(FrameworkProperties.getProperty(PROP_REFRESH_BUNDLES)) && refreshPackages(getCurrentBundles(false))) return context; if (Profile.PROFILE && Profile.STARTUP) 301 Profile.logTime("EclipseStarter.startup()", "loading basic bundles"); long stateStamp = adaptor.getState().getTimeStamp(); 303 Bundle[] startBundles = loadBasicBundles(); 304 if (startBundles == null) 305 return context; setStartLevel(getStartLevel()); 309 if (Profile.PROFILE && Profile.STARTUP) 310 Profile.logTime("EclipseStarter.startup()", "StartLevel set"); ensureBundlesActive(startBundles); 313 if (debug || FrameworkProperties.getProperty(PROP_DEV) != null) 314 if (stateStamp != adaptor.getState().getTimeStamp()) 316 logUnresolvedBundles(context.getBundles()); 317 running = true; 318 if (Profile.PROFILE && Profile.STARTUP) 319 Profile.logExit("EclipseStarter.startup()"); return context; 321 } 322 323 private static int getStartLevel() { 324 String level = FrameworkProperties.getProperty(PROP_INITIAL_STARTLEVEL); 325 if (level != null) 326 try { 327 return Integer.parseInt(level); 328 } catch (NumberFormatException e) { 329 if (debug) 330 System.out.println("Start level = " + level + " parsed. Using hardcoded default: 6"); } 332 return DEFAULT_INITIAL_STARTLEVEL; 333 } 334 335 347 public static Object run(Object argument) throws Exception { 348 if (Profile.PROFILE && Profile.STARTUP) 349 Profile.logEnter("EclipseStarter.run(Object)()", null); if (!running) 351 throw new IllegalStateException (EclipseAdaptorMsg.ECLIPSE_STARTUP_NOT_RUNNING); 352 if (initialize) 354 return new Integer (0); 355 if (appLauncher == null) { 356 boolean launchDefault = Boolean.valueOf(FrameworkProperties.getProperty(PROP_APPLICATION_LAUNCHDEFAULT, "true")).booleanValue(); appLauncher = new EclipseAppLauncher(context, Boolean.valueOf(FrameworkProperties.getProperty(PROP_ALLOW_APPRELAUNCH)).booleanValue(), launchDefault, log); 359 appLauncherRegistration = context.registerService(ApplicationLauncher.class.getName(), appLauncher, null); 360 return appLauncher.start(argument); 364 } 365 return appLauncher.reStart(argument); 366 } 367 368 385 public static void shutdown() throws Exception { 386 if (!running || osgi == null) 387 return; 388 if (appLauncherRegistration != null) 389 appLauncherRegistration.unregister(); 390 if (splashStreamRegistration != null) 391 splashStreamRegistration.unregister(); 392 if (defaultMonitorRegistration != null) 393 defaultMonitorRegistration.unregister(); 394 appLauncherRegistration = null; 395 appLauncher = null; 396 splashStreamRegistration = null; 397 defaultMonitorRegistration = null; 398 stopConsole(); 399 osgi.close(); 400 osgi = null; 401 context = null; 402 running = false; 403 } 404 405 private static void ensureBundlesActive(Bundle[] bundles) { 406 ServiceTracker tracker = null; 407 try { 408 for (int i = 0; i < bundles.length; i++) { 409 if (bundles[i].getState() != Bundle.ACTIVE) { 410 if (bundles[i].getState() == Bundle.INSTALLED) { 411 log.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_RESOLVED, bundles[i].getLocation()), 0, null, null)); 413 continue; 414 } 415 if (tracker == null) { 417 tracker = new ServiceTracker(context, StartLevel.class.getName(), null); 418 tracker.open(); 419 } 420 StartLevel sl = (StartLevel) tracker.getService(); 421 if (sl != null && (sl.getBundleStartLevel(bundles[i]) <= sl.getStartLevel())) { 422 log.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.ERROR, 0, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_ACTIVE, bundles[i]), 0, null, null)); 423 } 424 } 425 } 426 } finally { 427 if (tracker != null) 428 tracker.close(); 429 } 430 } 431 432 private static void logUnresolvedBundles(Bundle[] bundles) { 433 State state = adaptor.getState(); 434 FrameworkLog logService = adaptor.getFrameworkLog(); 435 StateHelper stateHelper = adaptor.getPlatformAdmin().getStateHelper(); 436 437 VersionConstraint[] leafConstraints = stateHelper.getUnsatisfiedLeaves(state.getBundles()); 439 Map missing = new HashMap(); 441 for (int i = 0; i < leafConstraints.length; i++) { 442 if (leafConstraints[i] instanceof BundleSpecification && ((BundleSpecification) leafConstraints[i]).isOptional()) 444 continue; 445 if (leafConstraints[i] instanceof ImportPackageSpecification) { 446 if (ImportPackageSpecification.RESOLUTION_OPTIONAL.equals(((ImportPackageSpecification) leafConstraints[i]).getDirective(Constants.RESOLUTION_DIRECTIVE))) 447 continue; 448 if (ImportPackageSpecification.RESOLUTION_DYNAMIC.equals(((ImportPackageSpecification) leafConstraints[i]).getDirective(Constants.RESOLUTION_DIRECTIVE))) 449 continue; 450 } 451 BundleDescription bundle = leafConstraints[i].getBundle(); 452 ArrayList constraints = (ArrayList) missing.get(bundle); 453 if (constraints == null) { 454 constraints = new ArrayList(); 455 missing.put(bundle, constraints); 456 } 457 constraints.add(leafConstraints[i]); 458 } 459 460 if (missing.size() > 0) { 462 FrameworkLogEntry[] rootChildren = new FrameworkLogEntry[missing.size()]; 463 int rootIndex = 0; 464 for (Iterator iter = missing.keySet().iterator(); iter.hasNext(); rootIndex++) { 465 BundleDescription description = (BundleDescription) iter.next(); 466 String symbolicName = description.getSymbolicName() == null ? FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME : description.getSymbolicName(); 467 String generalMessage = NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_RESOLVED, description.getLocation()); 468 ArrayList constraints = (ArrayList) missing.get(description); 469 FrameworkLogEntry[] logChildren = new FrameworkLogEntry[constraints.size()]; 470 for (int i = 0; i < logChildren.length; i++) 471 logChildren[i] = new FrameworkLogEntry(symbolicName, FrameworkLogEntry.WARNING, 0, MessageHelper.getResolutionFailureMessage((VersionConstraint) constraints.get(i)), 0, null, null); 472 rootChildren[rootIndex] = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, generalMessage, 0, null, logChildren); 473 } 474 logService.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_ROOTS_NOT_RESOLVED, 0, null, rootChildren)); 475 } 476 477 ArrayList allChildren = new ArrayList(); 480 for (int i = 0; i < bundles.length; i++) 481 if (bundles[i].getState() == Bundle.INSTALLED) { 482 String symbolicName = bundles[i].getSymbolicName() == null ? FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME : bundles[i].getSymbolicName(); 483 String generalMessage = NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_ERROR_BUNDLE_NOT_RESOLVED, bundles[i]); 484 BundleDescription description = state.getBundle(bundles[i].getBundleId()); 485 if (description == null) 487 continue; 488 FrameworkLogEntry[] logChildren = null; 489 VersionConstraint[] unsatisfied = stateHelper.getUnsatisfiedConstraints(description); 490 if (unsatisfied.length > 0) { 491 logChildren = new FrameworkLogEntry[unsatisfied.length]; 493 for (int j = 0; j < unsatisfied.length; j++) 494 logChildren[j] = new FrameworkLogEntry(symbolicName, FrameworkLogEntry.WARNING, 0, MessageHelper.getResolutionFailureMessage(unsatisfied[j]), 0, null, null); 495 } else { 496 ResolverError[] resolverErrors = state.getResolverErrors(description); 497 if (resolverErrors.length > 0) { 498 logChildren = new FrameworkLogEntry[resolverErrors.length]; 499 for (int j = 0; j < resolverErrors.length; j++) 500 logChildren[j] = new FrameworkLogEntry(symbolicName, FrameworkLogEntry.WARNING, 0, resolverErrors[j].toString(), 0, null, null); 501 } 502 } 503 504 allChildren.add(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, generalMessage, 0, null, logChildren)); 505 } 506 if (allChildren.size() > 0) 507 logService.log(new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, FrameworkLogEntry.WARNING, 0, EclipseAdaptorMsg.ECLIPSE_STARTUP_ALL_NOT_RESOLVED, 0, null, (FrameworkLogEntry[]) allChildren.toArray(new FrameworkLogEntry[allChildren.size()]))); 508 } 509 510 private static void publishSplashScreen(final Runnable endSplashHandler) { 511 if (endSplashHandler == null) 512 return; 513 try { 515 Method method = endSplashHandler.getClass().getMethod("getOutputStream", new Class [0]); Object outputStream = method.invoke(endSplashHandler, new Object [0]); 517 if (outputStream instanceof OutputStream) { 518 Dictionary osProperties = new Hashtable(); 519 osProperties.put("name", "splashstream"); splashStreamRegistration = context.registerService(OutputStream.class.getName(), outputStream, osProperties); 521 } 522 } catch (Exception ex) { 523 } 525 try { 527 Dictionary monitorProps = new Hashtable(); 528 monitorProps.put(Constants.SERVICE_RANKING, new Integer (Integer.MIN_VALUE)); 529 defaultMonitorRegistration = context.registerService(StartupMonitor.class.getName(), new DefaultStartupMonitor(endSplashHandler), monitorProps); 530 } catch (IllegalStateException e) { 531 } 533 } 534 535 private static URL searchForBundle(String name, String parent) throws MalformedURLException { 536 URL url = null; 537 File fileLocation = null; 538 boolean reference = false; 539 try { 540 new URL(name); url = new URL(new File(parent).toURL(), name); 542 } catch (MalformedURLException e) { 543 File child = new File(name); 548 fileLocation = child.isAbsolute() ? child : new File(parent, name); 549 url = new URL(REFERENCE_PROTOCOL, null, fileLocation.toURL().toExternalForm()); 550 reference = true; 551 } 552 if (!reference) { 554 URL baseURL = url; 555 if (url.getProtocol().equals(REFERENCE_PROTOCOL)) { 557 reference = true; 558 String baseSpec = url.getFile(); 559 if (baseSpec.startsWith(FILE_SCHEME)) { 560 File child = new File(baseSpec.substring(5)); 561 baseURL = child.isAbsolute() ? child.toURL() : new File(parent, child.getPath()).toURL(); 562 } else 563 baseURL = new URL(baseSpec); 564 } 565 566 fileLocation = new File(baseURL.getFile()); 567 if (!fileLocation.isAbsolute()) 569 fileLocation = new File(parent, fileLocation.toString()); 570 } 571 if (reference) { 574 String result = searchFor(fileLocation.getName(), new File(fileLocation.getParent()).getAbsolutePath()); 575 if (result != null) 576 url = new URL(REFERENCE_PROTOCOL, null, FILE_SCHEME + result); 577 else 578 return null; 579 } 580 581 try { 583 URLConnection result = url.openConnection(); 584 result.connect(); 585 return url; 586 } catch (IOException e) { 587 return null; 590 } 591 } 592 593 598 private static Bundle[] loadBasicBundles() throws IOException { 599 long startTime = System.currentTimeMillis(); 600 String osgiBundles = FrameworkProperties.getProperty(PROP_BUNDLES); 601 String osgiExtensions = FrameworkProperties.getProperty(PROP_EXTENSIONS); 602 if (osgiExtensions != null && osgiExtensions.length() > 0) { 603 osgiBundles = osgiExtensions + ',' + osgiBundles; 604 FrameworkProperties.setProperty(PROP_BUNDLES, osgiBundles); 605 } 606 String [] installEntries = getArrayFromList(osgiBundles, ","); InitialBundle[] initialBundles = getInitialBundles(installEntries); 609 Bundle[] curInitBundles = getCurrentBundles(true); 611 612 List toRefresh = new ArrayList(curInitBundles.length); 614 uninstallBundles(curInitBundles, initialBundles, toRefresh); 617 618 &nbs
|