Merge branch osgiR8 into master
diff --git a/bundles/org.eclipse.equinox.launcher.cocoa.macosx.x86_64/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.launcher.cocoa.macosx.x86_64/META-INF/MANIFEST.MF
index 132012b..b908331 100644
--- a/bundles/org.eclipse.equinox.launcher.cocoa.macosx.x86_64/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.launcher.cocoa.macosx.x86_64/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %pluginName
 Bundle-Vendor: %providerName
 Bundle-SymbolicName: org.eclipse.equinox.launcher.cocoa.macosx.x86_64;singleton:=true
-Bundle-Version: 1.1.1200.qualifier
+Bundle-Version: 1.1.1300.qualifier
 Fragment-Host: org.eclipse.equinox.launcher;bundle-version="[1.0.0,1.6.0)"
 Eclipse-PlatformFilter: (& (osgi.ws=cocoa) (osgi.os=macosx) (osgi.arch=x86_64) )
 Bundle-Localization: launcher.cocoa.macosx.x86_64
diff --git a/bundles/org.eclipse.equinox.launcher.cocoa.macosx.x86_64/build.properties b/bundles/org.eclipse.equinox.launcher.cocoa.macosx.x86_64/build.properties
index ee7308c..3c97f0c 100644
--- a/bundles/org.eclipse.equinox.launcher.cocoa.macosx.x86_64/build.properties
+++ b/bundles/org.eclipse.equinox.launcher.cocoa.macosx.x86_64/build.properties
@@ -17,4 +17,4 @@
                
 customBuildCallbacks=customBuildCallbacks.xml
 generateSourceBundle=false
-binaryTag=v20200508-0906
+binaryTag=v20200608-1138
diff --git a/bundles/org.eclipse.equinox.launcher.cocoa.macosx.x86_64/pom.xml b/bundles/org.eclipse.equinox.launcher.cocoa.macosx.x86_64/pom.xml
index 80b43e8..1d12bef 100644
--- a/bundles/org.eclipse.equinox.launcher.cocoa.macosx.x86_64/pom.xml
+++ b/bundles/org.eclipse.equinox.launcher.cocoa.macosx.x86_64/pom.xml
@@ -14,12 +14,12 @@
   <parent>
     <artifactId>launcher-binary-parent</artifactId>
     <groupId>org.eclipse.equinox.framework</groupId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
     <relativePath>../../launcher-binary-parent</relativePath>
   </parent>
   <groupId>org.eclipse.equinox</groupId>
   <artifactId>org.eclipse.equinox.launcher.cocoa.macosx.x86_64</artifactId>
-  <version>1.1.1200-SNAPSHOT</version>
+  <version>1.1.1300-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 
   <properties>
diff --git a/bundles/org.eclipse.equinox.launcher.gtk.linux.aarch64/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.launcher.gtk.linux.aarch64/META-INF/MANIFEST.MF
index 3c37485e..880be03 100644
--- a/bundles/org.eclipse.equinox.launcher.gtk.linux.aarch64/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.launcher.gtk.linux.aarch64/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %pluginName
 Bundle-Vendor: %providerName
 Bundle-SymbolicName: org.eclipse.equinox.launcher.gtk.linux.aarch64;singleton:=true
-Bundle-Version: 1.1.1200.qualifier
+Bundle-Version: 1.1.1300.qualifier
 Fragment-Host: org.eclipse.equinox.launcher;bundle-version="[1.0.0,1.6.0)"
 Eclipse-PlatformFilter: (& (osgi.ws=gtk) (osgi.os=linux) (osgi.arch=aarch64))
 Bundle-Localization: launcher.gtk.linux.aarch64
diff --git a/bundles/org.eclipse.equinox.launcher.gtk.linux.aarch64/build.properties b/bundles/org.eclipse.equinox.launcher.gtk.linux.aarch64/build.properties
index 0c52f82..3facbe2 100644
--- a/bundles/org.eclipse.equinox.launcher.gtk.linux.aarch64/build.properties
+++ b/bundles/org.eclipse.equinox.launcher.gtk.linux.aarch64/build.properties
@@ -16,4 +16,4 @@
                about.html
                
 generateSourceBundle=false
-binaryTag=v20200508-0906
+binaryTag=v20200608-1138
diff --git a/bundles/org.eclipse.equinox.launcher.gtk.linux.aarch64/pom.xml b/bundles/org.eclipse.equinox.launcher.gtk.linux.aarch64/pom.xml
index 8cdab6d..8294abe 100644
--- a/bundles/org.eclipse.equinox.launcher.gtk.linux.aarch64/pom.xml
+++ b/bundles/org.eclipse.equinox.launcher.gtk.linux.aarch64/pom.xml
@@ -14,12 +14,12 @@
   <parent>
     <artifactId>launcher-binary-parent</artifactId>
     <groupId>org.eclipse.equinox.framework</groupId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
     <relativePath>../../launcher-binary-parent</relativePath>
   </parent>
   <groupId>org.eclipse.equinox</groupId>
   <artifactId>org.eclipse.equinox.launcher.gtk.linux.aarch64</artifactId>
-  <version>1.1.1200-SNAPSHOT</version>
+  <version>1.1.1300-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 
   <properties>
diff --git a/bundles/org.eclipse.equinox.launcher.gtk.linux.ppc64le/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.launcher.gtk.linux.ppc64le/META-INF/MANIFEST.MF
index 2f61158..760406c 100644
--- a/bundles/org.eclipse.equinox.launcher.gtk.linux.ppc64le/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.launcher.gtk.linux.ppc64le/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %pluginName
 Bundle-Vendor: %providerName
 Bundle-SymbolicName: org.eclipse.equinox.launcher.gtk.linux.ppc64le;singleton:=true
-Bundle-Version: 1.1.1200.qualifier
+Bundle-Version: 1.1.1300.qualifier
 Fragment-Host: org.eclipse.equinox.launcher;bundle-version="[1.0.0,1.6.0)"
 Eclipse-PlatformFilter: (& (osgi.ws=gtk) (osgi.os=linux) (osgi.arch=ppc64le))
 Bundle-Localization: launcher.gtk.linux.ppc64le
diff --git a/bundles/org.eclipse.equinox.launcher.gtk.linux.ppc64le/build.properties b/bundles/org.eclipse.equinox.launcher.gtk.linux.ppc64le/build.properties
index 1284517..795a120 100644
--- a/bundles/org.eclipse.equinox.launcher.gtk.linux.ppc64le/build.properties
+++ b/bundles/org.eclipse.equinox.launcher.gtk.linux.ppc64le/build.properties
@@ -16,4 +16,4 @@
                about.html
                
 generateSourceBundle=false
-binaryTag=v20200508-0906
+binaryTag=v20200608-1138
diff --git a/bundles/org.eclipse.equinox.launcher.gtk.linux.ppc64le/pom.xml b/bundles/org.eclipse.equinox.launcher.gtk.linux.ppc64le/pom.xml
index ac0f89a..3798512 100644
--- a/bundles/org.eclipse.equinox.launcher.gtk.linux.ppc64le/pom.xml
+++ b/bundles/org.eclipse.equinox.launcher.gtk.linux.ppc64le/pom.xml
@@ -14,12 +14,12 @@
   <parent>
     <artifactId>launcher-binary-parent</artifactId>
     <groupId>org.eclipse.equinox.framework</groupId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
     <relativePath>../../launcher-binary-parent</relativePath>
   </parent>
   <groupId>org.eclipse.equinox</groupId>
   <artifactId>org.eclipse.equinox.launcher.gtk.linux.ppc64le</artifactId>
-  <version>1.1.1200-SNAPSHOT</version>
+  <version>1.1.1300-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 
   <properties>
diff --git a/bundles/org.eclipse.equinox.launcher.gtk.linux.s390x/build.properties b/bundles/org.eclipse.equinox.launcher.gtk.linux.s390x/build.properties
index 9fe9ce9..9fb27d2 100644
--- a/bundles/org.eclipse.equinox.launcher.gtk.linux.s390x/build.properties
+++ b/bundles/org.eclipse.equinox.launcher.gtk.linux.s390x/build.properties
@@ -17,4 +17,4 @@
                
 customBuildCallbacks=customBuildCallbacks.xml
 generateSourceBundle=false
-binaryTag=v20200508-0906
+binaryTag=v20200608-1138
diff --git a/bundles/org.eclipse.equinox.launcher.gtk.linux.s390x/pom.xml b/bundles/org.eclipse.equinox.launcher.gtk.linux.s390x/pom.xml
index f1ad5e6..8ba1af7 100644
--- a/bundles/org.eclipse.equinox.launcher.gtk.linux.s390x/pom.xml
+++ b/bundles/org.eclipse.equinox.launcher.gtk.linux.s390x/pom.xml
@@ -14,7 +14,7 @@
   <parent>
     <artifactId>launcher-binary-parent</artifactId>
     <groupId>org.eclipse.equinox.framework</groupId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
     <relativePath>../../launcher-binary-parent</relativePath>
   </parent>
   <groupId>org.eclipse.equinox</groupId>
diff --git a/bundles/org.eclipse.equinox.launcher.gtk.linux.x86_64/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.launcher.gtk.linux.x86_64/META-INF/MANIFEST.MF
index 484f5a7..0430139 100644
--- a/bundles/org.eclipse.equinox.launcher.gtk.linux.x86_64/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.launcher.gtk.linux.x86_64/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %pluginName
 Bundle-Vendor: %providerName
 Bundle-SymbolicName: org.eclipse.equinox.launcher.gtk.linux.x86_64;singleton:=true
-Bundle-Version: 1.1.1200.qualifier
+Bundle-Version: 1.1.1300.qualifier
 Fragment-Host: org.eclipse.equinox.launcher;bundle-version="[1.0.0,1.6.0)"
 Eclipse-PlatformFilter: (& (osgi.ws=gtk) (osgi.os=linux) (osgi.arch=x86_64))
 Bundle-Localization: launcher.gtk.linux.x86_64
diff --git a/bundles/org.eclipse.equinox.launcher.gtk.linux.x86_64/build.properties b/bundles/org.eclipse.equinox.launcher.gtk.linux.x86_64/build.properties
index d7e9bd0..6a6ffd7 100644
--- a/bundles/org.eclipse.equinox.launcher.gtk.linux.x86_64/build.properties
+++ b/bundles/org.eclipse.equinox.launcher.gtk.linux.x86_64/build.properties
@@ -17,4 +17,4 @@
                
 customBuildCallbacks=customBuildCallbacks.xml
 generateSourceBundle=false
-binaryTag=v20200508-0906
+binaryTag=v20200608-1138
diff --git a/bundles/org.eclipse.equinox.launcher.gtk.linux.x86_64/pom.xml b/bundles/org.eclipse.equinox.launcher.gtk.linux.x86_64/pom.xml
index c833eb8..8029ce3 100644
--- a/bundles/org.eclipse.equinox.launcher.gtk.linux.x86_64/pom.xml
+++ b/bundles/org.eclipse.equinox.launcher.gtk.linux.x86_64/pom.xml
@@ -14,12 +14,12 @@
   <parent>
     <artifactId>launcher-binary-parent</artifactId>
     <groupId>org.eclipse.equinox.framework</groupId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
     <relativePath>../../launcher-binary-parent</relativePath>
   </parent>
   <groupId>org.eclipse.equinox</groupId>
   <artifactId>org.eclipse.equinox.launcher.gtk.linux.x86_64</artifactId>
-  <version>1.1.1200-SNAPSHOT</version>
+  <version>1.1.1300-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 
   <properties>
diff --git a/bundles/org.eclipse.equinox.launcher.win32.win32.x86_64/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.launcher.win32.win32.x86_64/META-INF/MANIFEST.MF
index de8f0e5..57efed9 100644
--- a/bundles/org.eclipse.equinox.launcher.win32.win32.x86_64/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.launcher.win32.win32.x86_64/META-INF/MANIFEST.MF
@@ -3,7 +3,7 @@
 Bundle-Name: %pluginName
 Bundle-Vendor: %providerName
 Bundle-SymbolicName: org.eclipse.equinox.launcher.win32.win32.x86_64;singleton:=true
-Bundle-Version: 1.1.1200.qualifier
+Bundle-Version: 1.1.1300.qualifier
 Fragment-Host: org.eclipse.equinox.launcher;bundle-version="[1.0.0,1.6.0)"
 Eclipse-PlatformFilter: (& (osgi.ws=win32) (osgi.os=win32) (osgi.arch=x86_64))
 Bundle-Localization: launcher.win32.win32.x86_64
diff --git a/bundles/org.eclipse.equinox.launcher.win32.win32.x86_64/build.properties b/bundles/org.eclipse.equinox.launcher.win32.win32.x86_64/build.properties
index 6aa8690..7e711dd 100644
--- a/bundles/org.eclipse.equinox.launcher.win32.win32.x86_64/build.properties
+++ b/bundles/org.eclipse.equinox.launcher.win32.win32.x86_64/build.properties
@@ -16,4 +16,4 @@
                about.html
 generateSourceBundle=false
 customBuildCallbacks=customBuildCallbacks.xml
-binaryTag=v20200508-0906
+binaryTag=v20200608-1138
diff --git a/bundles/org.eclipse.equinox.launcher.win32.win32.x86_64/pom.xml b/bundles/org.eclipse.equinox.launcher.win32.win32.x86_64/pom.xml
index 2833e37..45cb8e6 100644
--- a/bundles/org.eclipse.equinox.launcher.win32.win32.x86_64/pom.xml
+++ b/bundles/org.eclipse.equinox.launcher.win32.win32.x86_64/pom.xml
@@ -14,12 +14,12 @@
   <parent>
     <artifactId>launcher-binary-parent</artifactId>
     <groupId>org.eclipse.equinox.framework</groupId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
     <relativePath>../../launcher-binary-parent</relativePath>
   </parent>
   <groupId>org.eclipse.equinox</groupId>
   <artifactId>org.eclipse.equinox.launcher.win32.win32.x86_64</artifactId>
-  <version>1.1.1200-SNAPSHOT</version>
+  <version>1.1.1300-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 
   <properties>
diff --git a/bundles/org.eclipse.equinox.launcher/pom.xml b/bundles/org.eclipse.equinox.launcher/pom.xml
index 84535ec..2ec9103 100644
--- a/bundles/org.eclipse.equinox.launcher/pom.xml
+++ b/bundles/org.eclipse.equinox.launcher/pom.xml
@@ -14,7 +14,7 @@
   <parent>
     <artifactId>rt.equinox.framework</artifactId>
     <groupId>org.eclipse.equinox.framework</groupId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
   <groupId>org.eclipse.equinox</groupId>
diff --git a/bundles/org.eclipse.osgi.compatibility.state/pom.xml b/bundles/org.eclipse.osgi.compatibility.state/pom.xml
index 6ea46d1..cb3b877 100644
--- a/bundles/org.eclipse.osgi.compatibility.state/pom.xml
+++ b/bundles/org.eclipse.osgi.compatibility.state/pom.xml
@@ -14,7 +14,7 @@
   <parent>
     <artifactId>rt.equinox.framework</artifactId>
     <groupId>org.eclipse.equinox.framework</groupId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
   <groupId>org.eclipse.osgi</groupId>
diff --git a/bundles/org.eclipse.osgi.services/pom.xml b/bundles/org.eclipse.osgi.services/pom.xml
index 0d1c51c..c757ef1 100644
--- a/bundles/org.eclipse.osgi.services/pom.xml
+++ b/bundles/org.eclipse.osgi.services/pom.xml
@@ -14,7 +14,7 @@
   <parent>
     <artifactId>rt.equinox.framework</artifactId>
     <groupId>org.eclipse.equinox.framework</groupId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
   <groupId>org.eclipse.osgi</groupId>
diff --git a/bundles/org.eclipse.osgi.tests/pom.xml b/bundles/org.eclipse.osgi.tests/pom.xml
index fcc58f3..09698e8 100644
--- a/bundles/org.eclipse.osgi.tests/pom.xml
+++ b/bundles/org.eclipse.osgi.tests/pom.xml
@@ -14,7 +14,7 @@
   <parent>
     <artifactId>rt.equinox.framework</artifactId>
     <groupId>org.eclipse.equinox.framework</groupId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
   <groupId>org.eclipse.osgi</groupId>
@@ -73,6 +73,11 @@
                 <type>p2-installable-unit</type>
                 <versionRange>0.0.0</versionRange>
               </requirement>
+              <requirement>
+                <id>org.junit.jupiter.api</id>
+                <type>p2-installable-unit</type>
+                <versionRange>0.0.0</versionRange>
+              </requirement>
             </extraRequirements>
           </dependency-resolution>
         </configuration>
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/AbstractBundleTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/AbstractBundleTests.java
index ee2f835..10a06ad 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/AbstractBundleTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/AbstractBundleTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2006, 20010 IBM Corporation and others.
+ * Copyright (c) 2006, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -24,13 +24,16 @@
 import java.util.jar.JarOutputStream;
 import java.util.jar.Manifest;
 import org.eclipse.core.tests.harness.CoreTest;
+import org.eclipse.osgi.framework.util.ThreadInfoReport;
 import org.eclipse.osgi.launch.Equinox;
 import org.eclipse.osgi.tests.OSGiTestsActivator;
+import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.BundleEvent;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
 import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.launch.Framework;
 
 public class AbstractBundleTests extends CoreTest {
 	public static int BUNDLE_LISTENER = 0x01;
@@ -267,15 +270,94 @@
 		equinox.start();
 	}
 
-	protected void stopQuietly(Equinox equinox) {
+	static public void stop(Framework equinox, int expected) {
+		FrameworkEvent actual = stop(equinox);
+		if (expected > 0) {
+			assertNotNull("No FrameworkEvent returned.", actual);
+			assertEquals("Wrong FrameworkEvent.", getFrameworkEventType(expected),
+					getFrameworkEventType(actual.getType()));
+		}
+	}
+
+	static private String getFrameworkEventType(int type) {
+		switch (type) {
+		case FrameworkEvent.ERROR:
+			return "ERROR";
+		case FrameworkEvent.INFO:
+			return "INFO";
+		case FrameworkEvent.STARTED:
+			return "STARTED";
+		case FrameworkEvent.STOPPED:
+			return "STOPPED";
+		case FrameworkEvent.STOPPED_BOOTCLASSPATH_MODIFIED:
+			return "STOPPED_BOOTCLASSPATH_MODIFIED";
+		case FrameworkEvent.STOPPED_SYSTEM_REFRESHED:
+			return "STOPPED_SYSTEM_REFRESHED";
+		case FrameworkEvent.STOPPED_UPDATE:
+			return "STOPPED_UPDATE";
+		default:
+			return "UNKNOWN:" + type;
+		}
+	}
+
+	static public FrameworkEvent stop(Framework equinox) {
+		return stop(equinox, false, 10000);
+	}
+
+	static public FrameworkEvent stopQuietly(Framework equinox) {
+		return stop(equinox, true, 10000);
+	}
+
+	static public FrameworkEvent update(final Framework equinox) {
+		final Exception[] failureException = new BundleException[1];
+		final FrameworkEvent[] success = new FrameworkEvent[] { null };
+		final String uuid = getUUID(equinox);
+		Thread waitForUpdate = new Thread(new Runnable() {
+			@Override
+			public void run() {
+				success[0] = waitForStop(equinox, uuid, false, 10000);
+			}
+		}, "test waitForStop thread"); //$NON-NLS-1$
+		waitForUpdate.start();
+
+		try {
+			// delay hack to allow waitForUpdate thread to block on waitForStop before we
+			// update.
+			Thread.sleep(200);
+		} catch (InterruptedException e) {
+			Thread.currentThread().interrupt();
+			fail("unexpected interuption", e);
+		}
+
+		try {
+			equinox.update();
+		} catch (BundleException e) {
+			fail("Failed to update the framework", e); //$NON-NLS-1$
+		}
+		try {
+			waitForUpdate.join();
+		} catch (InterruptedException e) {
+			Thread.currentThread().interrupt();
+			fail("unexpected interuption", e); //$NON-NLS-1$
+		}
+		if (failureException[0] != null) {
+			fail("Error occurred while waiting", failureException[0]); //$NON-NLS-1$
+		}
+		return success[0];
+	}
+
+	static public FrameworkEvent stop(Framework equinox, boolean quietly, long timeout) {
 		if (equinox == null)
-			return;
+			return null;
+		final String uuid = getUUID(equinox);
 		try {
 			equinox.stop();
-			equinox.waitForStop(5000);
-		} catch (Exception e) {
-			// Ignore
+		} catch (BundleException e) {
+			if (!quietly) {
+				fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
+			}
 		}
+		return waitForStop(equinox, uuid, quietly, timeout);
 	}
 
 	protected static boolean delete(File file) {
@@ -295,4 +377,51 @@
 		return (true);
 	}
 
-}
\ No newline at end of file
+	static public FrameworkEvent waitForStop(Framework equinox, String uuid, boolean quietly, long timeout) {
+		try {
+			FrameworkEvent stopEvent = equinox.waitForStop(timeout);
+			if (stopEvent.getType() == FrameworkEvent.WAIT_TIMEDOUT) {
+				StringBuilder sb = new StringBuilder("Framework state is: ");
+				sb.append(getState(equinox)).append(" - ").append(uuid).append('\n');
+				sb.append(ThreadInfoReport.getThreadDump(null)).append('\n');
+				if (!quietly) {
+					fail(sb.toString());
+				} else {
+					System.out.println(sb.toString());
+				}
+			}
+			return stopEvent;
+		} catch (InterruptedException e) {
+			Thread.currentThread().interrupt();
+			if (!quietly) {
+				fail("Unexpected interrupted exception", e); //$NON-NLS-1$
+			}
+		}
+		return null;
+	}
+
+	public static String getUUID(Framework equinox) {
+		BundleContext bc = equinox.getBundleContext();
+		return bc == null ? null : bc.getProperty(Constants.FRAMEWORK_UUID);
+	}
+
+	static private String getState(Framework framework) {
+		int state = framework.getState();
+		switch (state) {
+		case Bundle.UNINSTALLED:
+			return "UNINSTALLED";
+		case Bundle.INSTALLED:
+			return "INSTALLED";
+		case Bundle.RESOLVED:
+			return "RESOLVED";
+		case Bundle.STARTING:
+			return "STARTING";
+		case Bundle.ACTIVE:
+			return "ACTIVE";
+		case Bundle.STOPPING:
+			return "STOPPING";
+		default:
+			return "UNKNOWN:" + state;
+		}
+	}
+}
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/CascadeConfigTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/CascadeConfigTests.java
index dc0e78a..dc7d060 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/CascadeConfigTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/CascadeConfigTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2016 IBM Corporation and others.
+ * Copyright (c) 2008, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -15,12 +15,17 @@
 
 import java.io.File;
 import java.io.FileOutputStream;
-import java.util.*;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
 import junit.framework.Test;
 import junit.framework.TestSuite;
 import org.eclipse.osgi.launch.Equinox;
 import org.eclipse.osgi.tests.OSGiTestsActivator;
-import org.osgi.framework.*;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
 import org.osgi.framework.launch.Framework;
 import org.osgi.framework.wiring.FrameworkWiring;
 
@@ -40,8 +45,7 @@
 		BundleContext systemContext = equinox.getBundleContext();
 		systemContext.installBundle(installer.getBundleLocation("test"));
 
-		equinox.stop();
-		equinox.waitForStop(10000);
+		stopQuietly(equinox);
 
 		// Now create a child framework and make sure test1 bundle is there
 		File configChild = OSGiTestsActivator.getContext().getDataFile(getName() + "_child");
@@ -58,8 +62,7 @@
 
 		systemContext.installBundle(installer.getBundleLocation("test2"));
 
-		equinox.stop();
-		equinox.waitForStop(10000);
+		stop(equinox);
 
 		// reuse the same configuration and make sure both bundles are there
 		equinox = new Equinox(childMap);
@@ -71,8 +74,7 @@
 		Bundle test2 = systemContext.getBundle(installer.getBundleLocation("test2"));
 		assertNotNull("Missing bundle.", test2);
 
-		equinox.stop();
-		equinox.waitForStop(10000);
+		stop(equinox);
 
 		// restart using the parent and make sure only the test1 bundle is there
 		equinox = new Equinox(parentMap);
@@ -84,8 +86,7 @@
 		test2 = systemContext.getBundle(installer.getBundleLocation("test2"));
 		assertNull("Unexpected bundle.", test2);
 
-		equinox.stop();
-		equinox.waitForStop(10000);
+		stop(equinox);
 	}
 
 	public void testCascadeConfigDataArea() throws Exception {
@@ -100,8 +101,7 @@
 		Bundle b = systemContext.installBundle(installer.getBundleLocation("substitutes.a"));
 		equinox.adapt(FrameworkWiring.class).resolveBundles(Collections.singletonList(b));
 
-		equinox.stop();
-		equinox.waitForStop(10000);
+		stop(equinox);
 
 		// Now create a child framework and make sure bundle is there
 		File configChild = OSGiTestsActivator.getContext().getDataFile(getName() + "_child");
@@ -123,8 +123,7 @@
 		File dataFile = test1Context.getDataFile("test1");
 		assertTrue(dataFile.getAbsolutePath().startsWith(configChild.getAbsolutePath()));
 
-		equinox.stop();
-		equinox.waitForStop(10000);
+		stop(equinox);
 
 		// get parent again
 		equinox = new Equinox(parentMap);
@@ -143,8 +142,7 @@
 		dataFile = test1Context.getDataFile("test1");
 		assertTrue(dataFile.getAbsolutePath().startsWith(configParent.getAbsolutePath()));
 
-		equinox.stop();
-		equinox.waitForStop(10000);
+		stop(equinox);
 	}
 
 	public void testCascadeConfigIni() throws Exception {
@@ -181,7 +179,6 @@
 		assertEquals("Wrong value for parent.child.key", "child", systemContext.getProperty("parent.child.key"));
 		assertEquals("Wrong value for child.key", "child", systemContext.getProperty("child.key"));
 
-		equinox.stop();
-		equinox.waitForStop(10000);
+		stop(equinox);
 	}
 }
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/DiscardBundleTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/DiscardBundleTests.java
index 6bc0d22..f431426 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/DiscardBundleTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/DiscardBundleTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013 IBM Corporation and others.
+ * Copyright (c) 2013, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -26,7 +26,6 @@
 import org.eclipse.osgi.tests.OSGiTestsActivator;
 import org.osgi.framework.BundleException;
 import org.osgi.framework.Constants;
-import org.osgi.framework.FrameworkEvent;
 
 /*
  * The framework must discard a persisted bundle when the
@@ -204,19 +203,13 @@
 		return new File(root, BUNDLE_JAR);
 	}
 
-	private Equinox restart(Equinox equinox, Map<String, ?> configuration) throws BundleException, InterruptedException {
+	private Equinox restart(Equinox equinox, Map<String, ?> configuration) throws BundleException {
 		stop(equinox);
 		equinox = new Equinox(configuration);
 		initAndStart(equinox);
 		return equinox;
 	}
 
-	private void stop(Equinox equinox) throws BundleException, InterruptedException {
-		equinox.stop();
-		FrameworkEvent event = equinox.waitForStop(5000);
-		assertEquals("The framework was not stopped", FrameworkEvent.STOPPED, event.getType());
-	}
-
 	private void touchFile(File file) {
 		if (file.isDirectory())
 			file = new File(file, BUNDLE_MANIFEST);
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ImportJavaSEPackagesTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ImportJavaSEPackagesTests.java
index 6bf21e4..da55e92 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ImportJavaSEPackagesTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ImportJavaSEPackagesTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2018 IBM Corporation and others.
+ * Copyright (c) 2018, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -76,13 +76,7 @@
 			assertEquals("It should throw a bundle exception of type manifest error", BundleException.MANIFEST_ERROR, e.getType());
 			assertTrue("It should throw a Bundle Exception stating Invalid manifest header Export-Package", e.getMessage().contains("Cannot specify java.* packages in Export headers"));
 		} finally {
-
-			try {
-				equinox.stop();
-				equinox.waitForStop(10000);
-			} catch (Exception e) {
-				//do nothing
-			}
+			stopQuietly(equinox);
 		}
 
 	}
@@ -109,13 +103,7 @@
 		} catch (BundleException e) {
 			fail("Failed to test Import-Package header");
 		} finally {
-
-			try {
-				equinox.stop();
-				equinox.waitForStop(10000);
-			} catch (Exception e) {
-				//do nothing
-			}
+			stopQuietly(equinox);
 		}
 	}
 
@@ -216,13 +204,7 @@
 		} catch (BundleException e) {
 			fail("Failed to test System packages");
 		} finally {
-
-			try {
-				equinox.stop();
-				equinox.waitForStop(10000);
-			} catch (Exception e) {
-				//do nothing
-			}
+			stopQuietly(equinox);
 		}
 	}
 
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/MultiReleaseJarTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/MultiReleaseJarTests.java
index 81700d0..39712ff 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/MultiReleaseJarTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/MultiReleaseJarTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2017 IBM Corporation and others.
+ * Copyright (c) 2017, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -397,12 +397,7 @@
 			assertEquals("Wrong class.", (rv >= 11) ? "BASE11" : "BASEXX", loadClass("multi.release.test.sub2.TestClass11", mrBundle, false));
 			assertEquals("Wrong class.", (rv >= 11) ? "ADD11" : CNFE, loadClass("multi.release.test.sub2.TestClassAdd11", mrBundle, true));
 		} finally {
-			try {
-				equinox.stop();
-				equinox.waitForStop(10000);
-			} catch (Exception e) {
-				// ignore;
-			}
+			stopQuietly(equinox);
 		}
 	}
 
@@ -480,12 +475,7 @@
 			assertEquals("Wrong resource.", (rv >= 11) ? "ADD 11" : RNF, readResource("multi/release/test/sub2/testResourceAdd11.txt", mrBundle));
 
 		} finally {
-			try {
-				equinox.stop();
-				equinox.waitForStop(10000);
-			} catch (Exception e) {
-				// ignore;
-			}
+			stopQuietly(equinox);
 		}
 	}
 
@@ -591,12 +581,7 @@
 			assertEquals("Wrong resource.", (rv >= 11) ? "ADD 11" : RNF, readResources("multi/release/test/sub2/testResourceAdd11.txt", mrBundle));
 
 		} finally {
-			try {
-				equinox.stop();
-				equinox.waitForStop(10000);
-			} catch (Exception e) {
-				// ignore;
-			}
+			stopQuietly(equinox);
 		}
 	}
 
@@ -689,12 +674,7 @@
 			listResources("multi/release/test", expected, mrBundle, 0);
 			listResources("multi/release/test", expectedRecurse, mrBundle, BundleWiring.LISTRESOURCES_RECURSE);
 		} finally {
-			try {
-				equinox.stop();
-				equinox.waitForStop(10000);
-			} catch (Exception e) {
-				// ignore;
-			}
+			stopQuietly(equinox);
 		}
 	}
 
@@ -755,12 +735,7 @@
 			assertTrue("Wrong package filter: " + filter, filter.contains(expectedPkg));
 
 		} finally {
-			try {
-				equinox.stop();
-				equinox.waitForStop(10000);
-			} catch (Exception e) {
-				// ignore;
-			}
+			stopQuietly(equinox);
 		}
 	}
 
@@ -776,8 +751,7 @@
 			location = mrBundle.getLocation();
 			mrBundle.start();
 		} finally {
-			equinox.stop();
-			equinox.waitForStop(10000);
+			stop(equinox);
 		}
 		System.out.println("Equinox state: " + equinox.getState());
 		for (int rv = 8; rv <= 11; rv++) {
@@ -793,8 +767,7 @@
 			location = mrBundle.getLocation();
 			mrBundle.start();
 		} finally {
-			equinox.stop();
-			equinox.waitForStop(10000);
+			stop(equinox);
 		}
 
 		for (int rv = 8; rv <= 11; rv++) {
@@ -838,12 +811,7 @@
 			assertTrue("Wrong package filter: " + rv + " " + filter, filter.contains(expectedPkg));
 
 		} finally {
-			try {
-				equinox.stop();
-				equinox.waitForStop(10000);
-			} catch (Exception e) {
-				// ignore;
-			}
+			stopQuietly(equinox);
 		}
 	}
 
@@ -863,8 +831,7 @@
 			Bundle mrBundle = systemContext.installBundle("reference:" + copyMrJarBundle.toURI().toString());
 			mrBundle.start();
 		} finally {
-			equinox.stop();
-			equinox.waitForStop(1000);
+			stop(equinox);
 		}
 
 		copyMrJarBundle.delete();
@@ -875,8 +842,7 @@
 		try {
 			equinox.start();
 		} finally {
-			equinox.stop();
-			equinox.waitForStop(1000);
+			stop(equinox);
 		}
 	}
 
@@ -898,8 +864,7 @@
 			Object testService = loader.iterator().next();
 			assertEquals("Wrong service found.", "SERVICE_BASE", testService.toString());
 		} finally {
-			equinox.stop();
-			equinox.waitForStop(1000);
+			stop(equinox);
 		}
 	}
 
@@ -927,8 +892,7 @@
 			}
 
 		} finally {
-			equinox.stop();
-			equinox.waitForStop(1000);
+			stop(equinox);
 		}
 	}
 
@@ -948,8 +912,7 @@
 			Collection<String> list = mrBundle.adapt(BundleWiring.class).listResources("/META-INF/", "*.txt", 0);
 			assertTrue("Found versioned META-INF resources: " + list, list.isEmpty());
 		} finally {
-			equinox.stop();
-			equinox.waitForStop(1000);
+			stop(equinox);
 		}
 	}
 }
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java
index 93ed0bc..2c3c875 100755
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/SystemBundleTests.java
@@ -163,16 +163,7 @@
 		URL configURL = configLocation.getURL();
 		assertTrue("incorrect configuration location", configURL.toExternalForm().endsWith("testSystemBundle01/")); //$NON-NLS-1$ //$NON-NLS-2$
 
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -190,16 +181,7 @@
 			fail("Failed to start the framework", e); //$NON-NLS-1$
 		}
 		assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 
 		try {
@@ -208,16 +190,7 @@
 			fail("Failed to start the framework", e); //$NON-NLS-1$
 		}
 		assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -240,16 +213,7 @@
 		assertNotNull("config property is null", configArea); //$NON-NLS-1$
 		assertTrue("Wrong configuration area", configArea.endsWith("testSystemBundle03/")); //$NON-NLS-1$ //$NON-NLS-2$
 		// don't do anything; just put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected error stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -289,16 +253,7 @@
 		assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$
 		assertEquals("Wrong state for installed bundle", Bundle.ACTIVE, substitutesA.getState()); //$NON-NLS-1$
 		// put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -339,16 +294,7 @@
 		}
 		assertEquals("Wrong state for active bundle", Bundle.ACTIVE, substitutesA.getState()); //$NON-NLS-1$
 		// put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -389,16 +335,7 @@
 		}
 		assertEquals("Wrong state for active bundle", Bundle.ACTIVE, substitutesA.getState()); //$NON-NLS-1$
 		// put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 
 		try {
@@ -418,16 +355,7 @@
 		// no need to start the bundle again it should have been persistently started
 		assertEquals("Wrong state for active bundle", Bundle.ACTIVE, substitutesA2.getState()); //$NON-NLS-1$
 		// put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 
 	}
@@ -481,29 +409,11 @@
 		assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox2.getState()); //$NON-NLS-1$
 
 		// put the framework 1 back to the RESOLVED state
-		try {
-			equinox1.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox1.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox1);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox1.getState()); //$NON-NLS-1$
 
 		// put the framework 2 back to the RESOLVED state
-		try {
-			equinox2.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox2.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox2);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox2.getState()); //$NON-NLS-1$
 	}
 
@@ -551,16 +461,7 @@
 		URL configURL = configLocation.getURL();
 		assertTrue("incorrect configuration location", configURL.toExternalForm().endsWith("testSystemBundle07_01/")); //$NON-NLS-1$ //$NON-NLS-2$
 
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -577,16 +478,7 @@
 			fail("Failed to start the framework", e); //$NON-NLS-1$
 		}
 		assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 
 		config = OSGiTestsActivator.getContext().getDataFile("testSystemBundle08_2"); //$NON-NLS-1$
@@ -613,16 +505,7 @@
 		URL configURL = configLocation.getURL();
 		assertTrue("incorrect configuration location", configURL.toExternalForm().endsWith("testSystemBundle08_2/")); //$NON-NLS-1$ //$NON-NLS-2$
 
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -650,16 +533,7 @@
 		} catch (BundleException e) {
 			fail("Unexpected exception starting test bundle", e); //$NON-NLS-1$
 		}
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -675,39 +549,9 @@
 			fail("Failed to start the framework", e); //$NON-NLS-1$
 		}
 		assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$
-		final Exception[] failureException = new BundleException[1];
-		final FrameworkEvent[] success = new FrameworkEvent[] {null};
-		Thread t = new Thread(new Runnable() {
-			@Override
-			public void run() {
-				try {
-					success[0] = equinox.waitForStop(10000);
-				} catch (InterruptedException e) {
-					failureException[0] = e;
-				}
-			}
-		}, "test waitForStop thread"); //$NON-NLS-1$
-		t.start();
-		try {
-			// delay hack to allow t thread to block on waitForStop before we update.
-			Thread.sleep(500);
-		} catch (InterruptedException e) {
-			fail("unexpected interuption", e);
-		}
-		try {
-			equinox.update();
-		} catch (BundleException e) {
-			fail("Failed to update the framework", e); //$NON-NLS-1$
-		}
-		try {
-			t.join();
-		} catch (InterruptedException e) {
-			fail("unexpected interuption", e); //$NON-NLS-1$
-		}
-		if (failureException[0] != null)
-			fail("Error occurred while waiting", failureException[0]); //$NON-NLS-1$
-		assertNotNull("Wait for stop event is null", success[0]); //$NON-NLS-1$
-		assertEquals("Wait for stop event type is wrong", FrameworkEvent.STOPPED_UPDATE, success[0].getType()); //$NON-NLS-1$
+
+		FrameworkEvent success = update(equinox);
+		assertEquals("Wait for stop event type is wrong", FrameworkEvent.STOPPED_UPDATE, success.getType()); //$NON-NLS-1$
 		// TODO delay hack to allow the framework to get started again
 		for (int i = 0; i < 5 && Bundle.ACTIVE != equinox.getState(); i++)
 			try {
@@ -716,16 +560,7 @@
 				// nothing
 			}
 		assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -756,16 +591,7 @@
 		assertEquals("Wrong number of exports", 1, pkg2.length); //$NON-NLS-1$
 		assertEquals("Wrong package name", "test.pkg2", pkg2[0].getName()); //$NON-NLS-1$ //$NON-NLS-2$
 
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -793,16 +619,7 @@
 		assertEquals("Wrong stopEvent", FrameworkEvent.WAIT_TIMEDOUT, stopEvent.getType()); //$NON-NLS-1$
 
 		assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			stopEvent = equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stopEvent = stop(equinox);
 		assertNotNull("Stop event is null", stopEvent); //$NON-NLS-1$
 		assertEquals("Wrong stopEvent", FrameworkEvent.STOPPED, stopEvent.getType()); //$NON-NLS-1$
 	}
@@ -844,16 +661,7 @@
 		}
 		assertEquals("Wrong state for active bundle", Bundle.ACTIVE, substitutesA.getState()); //$NON-NLS-1$
 		// put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 
 		// initialize the framework again to the same configuration
@@ -870,16 +678,7 @@
 		// make sure the bundle is there
 		assertNotNull("missing installed bundle", substitutesA); //$NON-NLS-1$
 		assertEquals("Unexpected symbolic name", "substitutes.a", substitutesA.getSymbolicName()); //$NON-NLS-1$ //$NON-NLS-2$
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 
 		// initialize the framework again to the same configuration but use clean option
@@ -896,16 +695,7 @@
 
 		// make sure the bundle is there
 		assertNull("Unexpected bundle is installed", substitutesA); //$NON-NLS-1$
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -928,18 +718,7 @@
 		assertNotNull("StartLevel service is null", st); //$NON-NLS-1$
 		assertEquals("Unexpected start level", 10, st.getStartLevel()); //$NON-NLS-1$
 		assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-
-		FrameworkEvent stopEvent = null;
-		try {
-			stopEvent = equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		FrameworkEvent stopEvent = stop(equinox);
 		assertNotNull("Stop event is null", stopEvent); //$NON-NLS-1$
 		assertEquals("Wrong stopEvent", FrameworkEvent.STOPPED, stopEvent.getType()); //$NON-NLS-1$
 	}
@@ -1010,20 +789,7 @@
 		} catch (ClassNotFoundException e) {
 			fail("failed to load class", e); //$NON-NLS-1$
 		}
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-
-		FrameworkEvent stopEvent = null;
-		try {
-			stopEvent = equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
-		assertNotNull("Stop event is null", stopEvent); //$NON-NLS-1$
-		assertEquals("Wrong stopEvent", FrameworkEvent.STOPPED, stopEvent.getType()); //$NON-NLS-1$
+		stop(equinox, FrameworkEvent.STOPPED);
 	}
 
 	public void testChangeEE() throws IOException, BundleException {
@@ -1054,12 +820,7 @@
 		Assert.assertTrue("Could not resolve bundle.", equinox.adapt(FrameworkWiring.class).resolveBundles(Collections.singleton(b)));
 
 		// put the framework back to the RESOLVED state
-		equinox.stop();
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 
 		// configure equinox for java 8
 		configuration.put("osgi.java.profile", javaSE8Profile.toExternalForm());
@@ -1074,12 +835,7 @@
 		Assert.assertFalse("Could resolve bundle.", equinox.adapt(FrameworkWiring.class).resolveBundles(Collections.singleton(b)));
 
 		// put the framework back to the RESOLVED state
-		equinox.stop();
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 
 		// move back to java 9
 		configuration.put("osgi.java.profile", javaSE9Profile.toExternalForm());
@@ -1094,12 +850,7 @@
 		Assert.assertTrue("Could not resolve bundle.", equinox.adapt(FrameworkWiring.class).resolveBundles(Collections.singleton(b)));
 
 		// put the framework back to the RESOLVED state
-		equinox.stop();
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 	}
 
 	public void testMRUBundleFileList() {
@@ -1148,16 +899,7 @@
 			}
 		}
 		// put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 
 		try {
 			equinox.start();
@@ -1167,37 +909,7 @@
 
 		openAllBundleFiles(equinox.getBundleContext());
 
-		final Exception[] failureException = new BundleException[1];
-		final FrameworkEvent[] success = new FrameworkEvent[] {null};
-		Thread waitForUpdate = new Thread(new Runnable() {
-			@Override
-			public void run() {
-				try {
-					success[0] = equinox.waitForStop(10000);
-				} catch (InterruptedException e) {
-					failureException[0] = e;
-				}
-			}
-		}, "test waitForStop thread"); //$NON-NLS-1$
-		waitForUpdate.start();
-		try {
-			// delay hack to allow waitForUpdate thread to block on waitForStop before we update.
-			Thread.sleep(100);
-		} catch (InterruptedException e) {
-			fail("unexpected interuption", e);
-		}
-		try {
-			equinox.update();
-		} catch (BundleException e) {
-			fail("Failed to update the framework", e); //$NON-NLS-1$
-		}
-		try {
-			waitForUpdate.join();
-		} catch (InterruptedException e) {
-			fail("unexpected interuption", e); //$NON-NLS-1$
-		}
-		if (failureException[0] != null)
-			fail("Error occurred while waiting", failureException[0]); //$NON-NLS-1$
+		update(equinox);
 
 		// we can either have a hack here that waits until the system bundle is active
 		// or we can just try to start it and race with the update() call above
@@ -1209,16 +921,7 @@
 
 		openAllBundleFiles(equinox.getBundleContext());
 
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -1303,29 +1006,11 @@
 		assertFalse("URL is equal: " + entry1.toExternalForm(), entry1.equals(entry2)); //$NON-NLS-1$
 
 		// put the framework 1 back to the RESOLVED state
-		try {
-			equinox1.stop();
-		} catch (BundleException e) {
-			fail("Unexpected error stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox1.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox1);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox1.getState()); //$NON-NLS-1$
 
 		// put the framework 2 back to the RESOLVED state
-		try {
-			equinox2.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox2.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox2);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox2.getState()); //$NON-NLS-1$
 	}
 
@@ -1397,29 +1082,11 @@
 		}
 
 		// put the framework 1 back to the RESOLVED state
-		try {
-			equinox1.stop();
-		} catch (BundleException e) {
-			fail("Unexpected error stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox1.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox1);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox1.getState()); //$NON-NLS-1$
 
 		// put the framework 2 back to the RESOLVED state
-		try {
-			equinox2.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox2.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox2);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox2.getState()); //$NON-NLS-1$
 		handlerReg.unregister();
 		System.getProperties().remove("test.url");
@@ -1452,17 +1119,14 @@
 
 		assertFalse("UUIDs are the same: " + uuid1_1, uuid1_1.equals(uuid2_1));
 
+		stop(equinox1);
+		stop(equinox2);
+
 		try {
-			equinox1.stop();
-			equinox2.stop();
-			equinox1.waitForStop(1000);
-			equinox2.waitForStop(1000);
 			equinox1.init();
 			equinox2.init();
 		} catch (BundleException e) {
 			fail("Failed to re-init frameworks.", e);
-		} catch (InterruptedException e) {
-			fail("Failed to stop frameworks.", e);
 		}
 
 		String uuid1_2 = equinox1.getBundleContext().getProperty(Constants.FRAMEWORK_UUID);
@@ -1473,16 +1137,8 @@
 		assertFalse("UUIDs are the same: " + uuid1_2, uuid1_2.equals(uuid2_2));
 		assertFalse("UUIDs are the same: " + uuid2_1, uuid2_1.equals(uuid2_2));
 
-		try {
-			equinox1.stop();
-			equinox2.stop();
-			equinox1.waitForStop(1000);
-			equinox2.waitForStop(1000);
-		} catch (BundleException e) {
-			fail("Failed to re-init frameworks.", e);
-		} catch (InterruptedException e) {
-			fail("Failed to stop frameworks.", e);
-		}
+		stop(equinox1);
+		stop(equinox2);
 	}
 
 	private void verifyUUID(String uuid) {
@@ -1572,16 +1228,7 @@
 		}
 
 		// put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 
 		try {
 			equinox.start();
@@ -1603,16 +1250,7 @@
 			fail("Failed to get bundle entries", t);
 		}
 
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -1643,16 +1281,7 @@
 			URL resource = tb1.getResource("tb1/resource.txt");
 			assertNotNull("Resource is null", resource);
 
-			try {
-				equinox.stop();
-			} catch (BundleException e) {
-				fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-			}
-			try {
-				equinox.waitForStop(10000);
-			} catch (InterruptedException e) {
-				fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-			}
+			stop(equinox);
 			assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 		} finally {
 			testBundleInstaller.shutdown();
@@ -1672,16 +1301,7 @@
 		} catch (BundleException e) {
 			fail("Failed to start the framework", e); //$NON-NLS-1$
 		}
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -1742,16 +1362,7 @@
 			reg.unregister();
 		}
 		// put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected error stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 
 		try {
 			equinox.start();
@@ -1792,16 +1403,7 @@
 		}
 
 		// put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected error stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 
 		try {
 			equinox.start();
@@ -1829,16 +1431,7 @@
 		assertEquals("Wrong number of wires for wiring1", 1, packages1.size());
 		assertEquals("Wrong number of wires for wiring2", 1, packages2.size());
 
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected error stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 	}
 
 	private void doTestBug351519Refresh(Boolean refreshDuplicates) {
@@ -1913,16 +1506,7 @@
 			assertEquals("Refreshed bundles does not include v1", refreshed[0], tb1v1);
 		}
 
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -1950,16 +1534,7 @@
 			fail("failed to install and start test bundle", e1); //$NON-NLS-1$
 		}
 
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -1988,13 +1563,10 @@
 		equinox.start();
 		assertEquals("Unexpected state", Bundle.ACTIVE, testTCCL.getState()); //$NON-NLS-1$
 
-		// test that the correct tccl is used for framework update
-		try {
-			equinox.update();
-			checkActive(testTCCL);
-		} catch (Exception e) {
-			fail("Unexpected exception", e); //$NON-NLS-1$
-		}
+		update(equinox);
+
+		checkActive(testTCCL);
+
 		systemContext = equinox.getBundleContext();
 		assertEquals("Unexpected state", Bundle.ACTIVE, testTCCL.getState()); //$NON-NLS-1$
 
@@ -2020,16 +1592,7 @@
 		} finally {
 			Thread.currentThread().setContextClassLoader(current);
 		}
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected error stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 	}
 
 	private void checkActive(Bundle b) {
@@ -2116,16 +1679,7 @@
 			resolverHookReg.unregister();
 		}
 		// put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected error stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 
 		if (!errors.isEmpty()) {
 			fail("Failed to resolve dynamic", errors.iterator().next());
@@ -2180,13 +1734,7 @@
 				}
 			}
 		});
-		equinox.stop();
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			Thread.currentThread().interrupt();
-			fail("Unexpected interruption.", e);
-		}
+		stop(equinox);
 
 		List<Bundle> expectedOrder = Arrays.asList(systemBundle, chainTest, chainTestA, chainTestB, chainTestC, chainTestD);
 		assertEquals("Wrong stopping order", expectedOrder.toArray(), stoppingOrder.toArray());
@@ -2206,13 +1754,7 @@
 		equinox.start();
 
 		long startTime = System.currentTimeMillis();
-		equinox.stop();
-		try {
-			equinox.waitForStop(500);
-		} catch (InterruptedException e) {
-			Thread.currentThread().interrupt();
-			fail("Unexpected interruption.", e);
-		}
+		stop(equinox, true, 500);
 		long stopTime = System.currentTimeMillis() - startTime;
 		if (stopTime > 2000) {
 			fail("waitForStop time took too long: " + stopTime);
@@ -2240,14 +1782,7 @@
 		assertEquals("Wrong value for test.substitute1", "Some.PASSED.test", systemContext.getProperty("test.substitute1"));
 		// check that non-substitution keeps $ delimiters.
 		assertEquals("Wrong value for test.substitute2", "Some.$test.prop2$.test", systemContext.getProperty("test.substitute2"));
-		equinox.stop();
-		try {
-			equinox.waitForStop(5000);
-		} catch (InterruptedException e) {
-			Thread.currentThread().interrupt();
-			fail("Unexpected interruption.", e);
-		}
-
+		stop(equinox);
 	}
 
 	public void testDynamicSecurityManager() throws BundleException {
@@ -2284,14 +1819,7 @@
 					// do nothing
 				}
 			});
-			equinox.stop();
-			try {
-				FrameworkEvent event = equinox.waitForStop(10000);
-				assertEquals("Wrong event.", FrameworkEvent.STOPPED, event.getType());
-			} catch (InterruptedException e) {
-				Thread.currentThread().interrupt();
-				fail("Unexpected interruption.", e);
-			}
+			stop(equinox);
 			assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 		} finally {
 			System.setSecurityManager(null);
@@ -2616,8 +2144,7 @@
 			fail("Expected to be able to load the class from boot.", e);
 		}
 		long bId = b.getBundleId();
-		equinox.stop();
-		equinox.waitForStop(5000);
+		stop(equinox);
 
 		// remove the setting to ensure false is used for the embedded case
 		configIni.remove(compatBootDelegate);
@@ -2667,8 +2194,7 @@
 		};
 		systemContext.addBundleListener(systemBundleListener);
 
-		equinox.stop();
-		equinox.waitForStop(5000);
+		stop(equinox);
 		assertEquals("Wrong number of STOPPING events", 1, stoppingEvent.get());
 		assertEquals("Wrong number of STOPPED events", 1, stoppedEvent.get());
 	}
@@ -2711,9 +2237,7 @@
 		assertTrue("Unexpected Export-Package header: " + exportPackage, exportPackage.contains("something.system"));
 		assertTrue("Unexpected Provide-Capability header: " + provideCapability, provideCapability.contains("something.extra"));
 		assertTrue("Unexpected Export-Package header: " + exportPackage, exportPackage.contains("something.extra"));
-		equinox.stop();
-
-		equinox.waitForStop(5000);
+		stop(equinox);
 
 		configuration.put(EquinoxConfiguration.PROP_SYSTEM_PROVIDE_HEADER, EquinoxConfiguration.SYSTEM_PROVIDE_HEADER_ORIGINAL);
 		equinox = new Equinox(configuration);
@@ -2725,9 +2249,7 @@
 		assertFalse("Unexpected Export-Package header: " + exportPackage, exportPackage.contains("something.system"));
 		assertFalse("Unexpected Provide-Capability header: " + provideCapability, provideCapability.contains("something.extra"));
 		assertFalse("Unexpected Export-Package header: " + exportPackage, exportPackage.contains("something.extra"));
-		equinox.stop();
-
-		equinox.waitForStop(5000);
+		stop(equinox);
 
 		configuration.put(EquinoxConfiguration.PROP_SYSTEM_PROVIDE_HEADER, EquinoxConfiguration.SYSTEM_PROVIDE_HEADER_SYSTEM);
 		equinox = new Equinox(configuration);
@@ -2739,9 +2261,7 @@
 		assertTrue("Unexpected Export-Package header: " + exportPackage, exportPackage.contains("something.system"));
 		assertFalse("Unexpected Provide-Capability header: " + provideCapability, provideCapability.contains("something.extra"));
 		assertFalse("Unexpected Export-Package header: " + exportPackage, exportPackage.contains("something.extra"));
-		equinox.stop();
-
-		equinox.waitForStop(5000);
+		stop(equinox);
 
 		configuration.put(EquinoxConfiguration.PROP_SYSTEM_PROVIDE_HEADER, EquinoxConfiguration.SYSTEM_PROVIDE_HEADER_SYSTEM_EXTRA);
 		equinox = new Equinox(configuration);
@@ -2753,9 +2273,7 @@
 		assertTrue("Unexpected Export-Package header: " + exportPackage, exportPackage.contains("something.system"));
 		assertTrue("Unexpected Provide-Capability header: " + provideCapability, provideCapability.contains("something.extra"));
 		assertTrue("Unexpected Export-Package header: " + exportPackage, exportPackage.contains("something.extra"));
-		equinox.stop();
-
-		equinox.waitForStop(5000);
+		stop(equinox);
 	}
 
 	public void testSystemBundleLoader() {
@@ -2840,16 +2358,7 @@
 		@SuppressWarnings("deprecation")
 		String osgiEE = equinox.getBundleContext().getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT);
 		// don't do anything; just put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected error stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 
 		assertTrue("Wrong osgi EE: expected: " + expectedEEName + " but was: " + osgiEE, osgiEE.endsWith(expectedEEName));
@@ -2986,8 +2495,7 @@
 				assertEquals("Requirement directives differ: " + outerReq.getNamespace(), outerReq.getDirectives(), innerReq.getDirectives());
 			}
 		} finally {
-			equinox.stop();
-			equinox.waitForStop(5000);
+			stop(equinox);
 		}
 	}
 
@@ -3037,16 +2545,7 @@
 			fail("Unexpected update error", e); //$NON-NLS-1$
 		}
 
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -3062,8 +2561,7 @@
 		Equinox equinox = new Equinox(configuration);
 		equinox.start();
 		checkActiveThreadType(equinox, true);
-		equinox.stop();
-		equinox.waitForStop(10000);
+		stop(equinox);
 
 		// test setting to 'normal'
 		// should result in a non-daemon thread
@@ -3071,8 +2569,7 @@
 		equinox = new Equinox(configuration);
 		equinox.start();
 		checkActiveThreadType(equinox, false);
-		equinox.stop();
-		equinox.waitForStop(10000);
+		stop(equinox);
 
 		// test setting to null (default)
 		// should result in a non-daemon thread
@@ -3109,8 +2606,7 @@
 		// should be active now
 		assertEquals("Wrong state of bundle.", Bundle.ACTIVE, b.getState());
 		// put the framework back to the RESOLVED state
-		equinox.stop();
-		equinox.waitForStop(10000);
+		stop(equinox);
 
 		// revert back to default behavior
 		configuration.remove(EquinoxConfiguration.PROP_COMPATIBILITY_START_LAZY_ON_FAIL_CLASSLOAD);
@@ -3161,14 +2657,7 @@
 		// check for substitution
 		assertEquals("Wrong value for test.config", getName(), systemContext.getProperty("test.config"));
 
-		equinox.stop();
-		try {
-			equinox.waitForStop(5000);
-		} catch (InterruptedException e) {
-			Thread.currentThread().interrupt();
-			fail("Unexpected interruption.", e);
-		}
-
+		stop(equinox);
 	}
 
 	void checkActiveThreadType(Equinox equinox, boolean expectIsDeamon) {
@@ -3208,16 +2697,7 @@
 			fail("Failed init", e);
 		} finally {
 			System.setProperty("os.name", origOS);
-			try {
-				if (equinox != null) {
-					equinox.stop();
-					equinox.waitForStop(1000);
-				}
-			} catch (BundleException e) {
-				fail("Failed to stop framework.", e);
-			} catch (InterruptedException e) {
-				fail("Failed to stop framework.", e);
-			}
+			stop(equinox);
 		}
 	}
 
@@ -3241,16 +2721,7 @@
 		} catch (BundleException e) {
 			fail("Failed init", e);
 		} finally {
-			try {
-				if (equinox != null) {
-					equinox.stop();
-					equinox.waitForStop(1000);
-				}
-			} catch (BundleException e) {
-				fail("Failed to stop framework.", e);
-			} catch (InterruptedException e) {
-				fail("Failed to stop framework.", e);
-			}
+			stop(equinox);
 		}
 	}
 
@@ -3264,24 +2735,14 @@
 			equinox = new Equinox(configuration);
 			equinox.start();
 			doLoggingOnMultipleListeners(equinox);
-			equinox.stop();
-			equinox.waitForStop(1000);
+			stop(equinox);
 			equinox.start();
 			doLoggingOnMultipleListeners(equinox);
 
 		} catch (BundleException e) {
 			fail("Failed init", e);
 		} finally {
-			try {
-				if (equinox != null) {
-					equinox.stop();
-					equinox.waitForStop(1000);
-				}
-			} catch (BundleException e) {
-				fail("Failed to stop framework.", e);
-			} catch (InterruptedException e) {
-				fail("Failed to stop framework.", e);
-			}
+			stop(equinox);
 		}
 	}
 
@@ -3353,8 +2814,7 @@
 				assertNull("Found location.", logEntry.getLocation());
 			}
 		} finally {
-			equinox.stop();
-			equinox.waitForStop(1000);
+			stop(equinox);
 		}
 	}
 
@@ -3397,16 +2857,14 @@
 
 		Framework framework = factory.newFramework(configuration);
 		framework.init();
-		framework.stop();
-		framework.waitForStop(5000);
+		stop(framework);
 
 		BundleRevision systemRevision1 = framework.adapt(BundleRevision.class);
 		int capCount1 = systemRevision1.getCapabilities(null).size();
 
 		framework = factory.newFramework(configuration);
 		framework.init();
-		framework.stop();
-		framework.waitForStop(5000);
+		stop(framework);
 
 		BundleRevision systemRevision2 = framework.adapt(BundleRevision.class);
 		int capCount2 = systemRevision2.getCapabilities(null).size();
@@ -3544,8 +3002,7 @@
 			expectedStopOrder = new ArrayList(expectedStopOrder.subList(0, 3 * (numBundles / 4)));
 
 			long stopTime = System.currentTimeMillis();
-			equinox.stop();
-			equinox.waitForStop(20000);
+			stop(equinox, false, 20000);
 			System.out.println("Stop time: " + (System.currentTimeMillis() - stopTime));
 
 			assertEquals("Size on expected order is wrong.", expectedStopOrder.size(), stoppedBundles.size());
@@ -3555,16 +3012,7 @@
 		} catch (BundleException e) {
 			fail("Failed init", e);
 		} finally {
-			try {
-				if (equinox != null) {
-					equinox.stop();
-					equinox.waitForStop(1000);
-				}
-			} catch (BundleException e) {
-				fail("Failed to stop framework.", e);
-			} catch (InterruptedException e) {
-				fail("Failed to stop framework.", e);
-			}
+			stop(equinox);
 		}
 	}
 
@@ -3614,16 +3062,7 @@
 		} catch (BundleException e) {
 			fail("Failed init", e);
 		} finally {
-			try {
-				if (equinox != null) {
-					equinox.stop();
-					equinox.waitForStop(1000);
-				}
-			} catch (BundleException e) {
-				fail("Failed to stop framework.", e);
-			} catch (InterruptedException e) {
-				fail("Failed to stop framework.", e);
-			}
+			stop(equinox);
 		}
 	}
 
@@ -3739,16 +3178,7 @@
 		} catch (BundleException e) {
 			fail("Failed init", e);
 		} finally {
-			try {
-				if (equinox != null) {
-					equinox.stop();
-					equinox.waitForStop(1000);
-				}
-			} catch (BundleException e) {
-				fail("Failed to stop framework.", e);
-			} catch (InterruptedException e) {
-				fail("Failed to stop framework.", e);
-			}
+			stop(equinox);
 		}
 	}
 
@@ -3774,12 +3204,7 @@
 				fwkWiring.resolveBundles(Collections.singleton(b));
 				b.start();
 			}
-			equinox.stop();
-			try {
-				equinox.waitForStop(1000);
-			} catch (InterruptedException e) {
-				fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-			}
+			stop(equinox);
 			equinox = null;
 			equinox = new Equinox(configuration);
 			equinox.start();
@@ -3796,16 +3221,7 @@
 				}
 			}
 		} finally {
-			try {
-				if (equinox != null) {
-					equinox.stop();
-					equinox.waitForStop(1000);
-				}
-			} catch (BundleException e) {
-				fail("Failed to stop framework.", e);
-			} catch (InterruptedException e) {
-				fail("Failed to stop framework.", e);
-			}
+			stop(equinox);
 		}
 	}
 
@@ -3869,16 +3285,7 @@
 
 		Assert.assertEquals("Errors found.", Collections.emptyList(), errors);
 		Assert.assertEquals("Wrong number of bundles.", numBundles + 1, systemContext.getBundles().length);
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 	}
 
@@ -3947,16 +3354,7 @@
 			}
 		}
 
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 
 		long timeTaken = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime);
@@ -4048,16 +3446,7 @@
 			executor1.shutdown();
 			executor2.shutdown();
 		}
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 
 		if (!errorsAndWarnings.isEmpty()) {
@@ -4100,16 +3489,7 @@
 		} catch (BundleException e) {
 			fail("Failed init", e);
 		} finally {
-			try {
-				if (equinox != null) {
-					equinox.stop();
-					equinox.waitForStop(1000);
-				}
-			} catch (BundleException e) {
-				fail("Failed to stop framework.", e);
-			} catch (InterruptedException e) {
-				fail("Failed to stop framework.", e);
-			}
+			stop(equinox);
 		}
 	}
 
@@ -4149,16 +3529,7 @@
 		} catch (BundleException e) {
 			fail("Unexpected BundleException", e);
 		} finally {
-			try {
-				if (equinox != null) {
-					equinox.stop();
-					equinox.waitForStop(1000);
-				}
-			} catch (BundleException e) {
-				fail("Failed to stop framework.", e);
-			} catch (InterruptedException e) {
-				fail("Failed to stop framework.", e);
-			}
+			stop(equinox);
 		}
 	}
 
@@ -4194,16 +3565,7 @@
 		} catch (BundleException e) {
 			fail("Unexpected BundleException", e);
 		} finally {
-			try {
-				if (equinox != null) {
-					equinox.stop();
-					equinox.waitForStop(1000);
-				}
-			} catch (BundleException e) {
-				fail("Failed to stop framework.", e);
-			} catch (InterruptedException e) {
-				fail("Failed to stop framework.", e);
-			}
+			stop(equinox);
 		}
 	}
 
@@ -4332,15 +3694,6 @@
 		List<BundleWire> providedWires = equinox.adapt(BundleWiring.class).getProvidedWires(PackageNamespace.PACKAGE_NAMESPACE);
 		Assert.assertEquals("Wrong number of provided wires.", numBundles, providedWires.size());
 
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 	}
 }
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/TestModuleContainer.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/TestModuleContainer.java
index 37da06d..d1ce331 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/TestModuleContainer.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/container/TestModuleContainer.java
@@ -3678,7 +3678,7 @@
 		tStop2.start();
 
 		BundleException stopError = stopExceptions.poll(10, TimeUnit.SECONDS);
-		startLatch.countDown();
+		stopLatch.countDown();
 
 		Assert.assertEquals("Wrong cause.", TimeoutException.class, stopError.getCause().getClass());
 		Assert.assertEquals("Wrong cause.", ThreadInfoReport.class, stopError.getCause().getCause().getClass());
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/AbstractFrameworkHookTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/AbstractFrameworkHookTests.java
index e77c2f0..8dd1184 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/AbstractFrameworkHookTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/AbstractFrameworkHookTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013, 2014 IBM Corporation and others.
+ * Copyright (c) 2013, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -13,6 +13,8 @@
  *******************************************************************************/
 package org.eclipse.osgi.tests.hooks.framework;
 
+import static org.eclipse.osgi.tests.bundles.AbstractBundleTests.stop;
+
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URI;
@@ -28,7 +30,6 @@
 import org.eclipse.osgi.tests.OSGiTestsActivator;
 import org.eclipse.osgi.tests.bundles.BundleInstaller;
 import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkEvent;
 import org.osgi.framework.connect.FrameworkUtilHelper;
 import org.osgi.framework.launch.Framework;
 import org.osgi.framework.launch.FrameworkFactory;
@@ -128,34 +129,6 @@
 		setUpClassLoader();
 	}
 
-	protected void stop(Framework framework) throws Exception {
-		stop(framework, false);
-	}
-
-	protected void stopQuietly(Framework framework) {
-		if (framework == null)
-			return;
-		try {
-			stop(framework, true);
-		} catch (Exception e) {
-			// ignore;
-		}
-	}
-
-	private void stop(Framework framework, boolean quietly) throws Exception {
-		try {
-			framework.stop();
-			FrameworkEvent event = framework.waitForStop(10000);
-			if (!quietly) {
-				assertEquals("The framework was not stopped", FrameworkEvent.STOPPED, event.getType());
-			}
-		} catch (Exception e) {
-			if (!quietly) {
-				throw e;
-			}
-		}
-	}
-
 	protected void tearDown() throws Exception {
 		bundleInstaller.shutdown();
 	}
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/ActivatorOrderTest.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/ActivatorOrderTest.java
index 1261d26..6d33025 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/ActivatorOrderTest.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/ActivatorOrderTest.java
@@ -1,5 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2020 IBM Corporation and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
 package org.eclipse.osgi.tests.hooks.framework;
 
+import static org.eclipse.osgi.tests.bundles.AbstractBundleTests.stop;
+
 import java.io.File;
 import java.net.URL;
 import java.util.ArrayList;
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/BundleFileWrapperFactoryHookTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/BundleFileWrapperFactoryHookTests.java
index e9d6602..31688f6 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/BundleFileWrapperFactoryHookTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/BundleFileWrapperFactoryHookTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2015, 2016 IBM Corporation and others.
+ * Copyright (c) 2015, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -13,7 +13,12 @@
  *******************************************************************************/
 package org.eclipse.osgi.tests.hooks.framework;
 
-import java.io.*;
+import static org.eclipse.osgi.tests.bundles.AbstractBundleTests.stopQuietly;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
 import java.net.URL;
 import java.util.HashMap;
 import java.util.Map;
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/ClassLoaderHookTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/ClassLoaderHookTests.java
index e05aea2..89b6f4f 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/ClassLoaderHookTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/ClassLoaderHookTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013, 2018 IBM Corporation and others.
+ * Copyright (c) 2013, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -13,6 +13,8 @@
  *******************************************************************************/
 package org.eclipse.osgi.tests.hooks.framework;
 
+import static org.eclipse.osgi.tests.bundles.AbstractBundleTests.stopQuietly;
+
 import java.io.File;
 import java.net.URL;
 import java.util.Collection;
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/ContextFinderTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/ContextFinderTests.java
index 1f175fc..f2b8c73 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/ContextFinderTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/ContextFinderTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013, 2017 IBM Corporation and others.
+ * Copyright (c) 2013, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -13,6 +13,8 @@
  *******************************************************************************/
 package org.eclipse.osgi.tests.hooks.framework;
 
+import static org.eclipse.osgi.tests.bundles.AbstractBundleTests.stopQuietly;
+
 import java.io.File;
 import java.io.IOException;
 import java.net.URL;
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/DevClassPathWithExtensionTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/DevClassPathWithExtensionTests.java
index 3794b9c..3cec0aa 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/DevClassPathWithExtensionTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/DevClassPathWithExtensionTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013, 2018 IBM Corporation and others.
+ * Copyright (c) 2013, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -13,6 +13,9 @@
  *******************************************************************************/
 package org.eclipse.osgi.tests.hooks.framework;
 
+import static org.eclipse.osgi.tests.bundles.AbstractBundleTests.stop;
+import static org.eclipse.osgi.tests.bundles.AbstractBundleTests.stopQuietly;
+
 import java.io.File;
 import java.util.Collection;
 import java.util.Collections;
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/EmbeddedEquinoxWithURLInClassLoadTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/EmbeddedEquinoxWithURLInClassLoadTests.java
index 9ae57c0..51ac468 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/EmbeddedEquinoxWithURLInClassLoadTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/EmbeddedEquinoxWithURLInClassLoadTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013, 2018 IBM Corporation and others.
+ * Copyright (c) 2013, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -13,6 +13,8 @@
  *******************************************************************************/
 package org.eclipse.osgi.tests.hooks.framework;
 
+import static org.eclipse.osgi.tests.bundles.AbstractBundleTests.stopQuietly;
+
 import java.io.File;
 import java.net.MalformedURLException;
 import java.net.URL;
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/StorageHookTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/StorageHookTests.java
index 4967707..42945b1 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/StorageHookTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/hooks/framework/StorageHookTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013, 2017 IBM Corporation and others.
+ * Copyright (c) 2013, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -13,6 +13,8 @@
  *******************************************************************************/
 package org.eclipse.osgi.tests.hooks.framework;
 
+import static org.eclipse.osgi.tests.bundles.AbstractBundleTests.stop;
+import static org.eclipse.osgi.tests.bundles.AbstractBundleTests.stopQuietly;
 import static org.junit.Assert.assertNotEquals;
 
 import java.io.ByteArrayInputStream;
@@ -199,8 +201,7 @@
 
 		assertNotEquals("Path of updated bundle is the same.", path1, path2);
 
-		framework.stop();
-		framework.waitForStop(5000);
+		stop(framework);
 
 		// create new framework object to test loading of persistent capability.
 		framework = createFramework(configuration);
@@ -296,8 +297,7 @@
 		setFactoryNullStorageHook(true);
 		Bundle b = installBundle();
 		assertNotNull("Expected to have a bundle after install.", b);
-		framework.stop();
-		framework.waitForStop(5000);
+		stop(framework);
 
 		// create new framework to make sure null storage hook works from persistence also.
 		framework = createFramework(configuration);
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/securityadmin/SecurityAdminUnitTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/securityadmin/SecurityAdminUnitTests.java
index 83d7aba..3935b9e 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/securityadmin/SecurityAdminUnitTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/securityadmin/SecurityAdminUnitTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2013 IBM Corporation and others.
+ * Copyright (c) 2008, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -955,8 +955,7 @@
 		updateInfos.add(cpa.newConditionalPermissionInfo(info2));
 		assertTrue("Failed commit", update.commit()); //$NON-NLS-1$
 
-		equinox.stop();
-		equinox.waitForStop(10000);
+		stop(equinox);
 		equinox.init();
 		cpa = equinox.getBundleContext().getService(equinox.getBundleContext().getServiceReference(ConditionalPermissionAdmin.class));
 		pa = equinox.getBundleContext().getService(equinox.getBundleContext().getServiceReference(PermissionAdmin.class));
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/securityadmin/SecurityManagerTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/securityadmin/SecurityManagerTests.java
index 8068ca0..158ed7f 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/securityadmin/SecurityManagerTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/securityadmin/SecurityManagerTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008, 2013 IBM Corporation and others.
+ * Copyright (c) 2008, 2020 IBM Corporation and others.
  *
  * This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License 2.0
@@ -14,21 +14,44 @@
 package org.eclipse.osgi.tests.securityadmin;
 
 import java.io.File;
-import java.security.*;
-import java.util.*;
+import java.security.AllPermission;
+import java.security.CodeSource;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Policy;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
 import junit.framework.Test;
 import junit.framework.TestSuite;
 import org.eclipse.osgi.launch.Equinox;
 import org.eclipse.osgi.tests.OSGiTestsActivator;
 import org.eclipse.osgi.tests.bundles.AbstractBundleTests;
-import org.osgi.framework.*;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.BundlePermission;
+import org.osgi.framework.Constants;
+import org.osgi.framework.PackagePermission;
 import org.osgi.framework.hooks.resolver.ResolverHook;
 import org.osgi.framework.hooks.resolver.ResolverHookFactory;
 import org.osgi.framework.namespace.PackageNamespace;
-import org.osgi.framework.wiring.*;
+import org.osgi.framework.wiring.BundleCapability;
+import org.osgi.framework.wiring.BundleRequirement;
+import org.osgi.framework.wiring.BundleRevision;
 import org.osgi.resource.Namespace;
-import org.osgi.service.condpermadmin.*;
-import org.osgi.service.packageadmin.*;
+import org.osgi.service.condpermadmin.BundleLocationCondition;
+import org.osgi.service.condpermadmin.ConditionInfo;
+import org.osgi.service.condpermadmin.ConditionalPermissionAdmin;
+import org.osgi.service.condpermadmin.ConditionalPermissionInfo;
+import org.osgi.service.condpermadmin.ConditionalPermissionUpdate;
+import org.osgi.service.packageadmin.ExportedPackage;
+import org.osgi.service.packageadmin.PackageAdmin;
+import org.osgi.service.packageadmin.RequiredBundle;
 import org.osgi.service.permissionadmin.PermissionInfo;
 import org.osgi.service.startlevel.StartLevel;
 
@@ -131,16 +154,7 @@
 		}
 		assertEquals("Wrong state for SystemBundle", Bundle.ACTIVE, equinox.getState()); //$NON-NLS-1$
 		// put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 		assertNull("SecurityManager is not null", System.getSecurityManager()); //$NON-NLS-1$
 	}
@@ -185,13 +199,7 @@
 			fail("Failed to start securityA", e); //$NON-NLS-1$
 		} finally {
 			// put the framework back to the RESOLVED state
-			equinox.stop();
-
-			try {
-				equinox.waitForStop(10000);
-			} catch (InterruptedException e) {
-				fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-			}
+			stop(equinox);
 		}
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 		assertNull("SecurityManager is not null", System.getSecurityManager()); //$NON-NLS-1$
@@ -254,13 +262,7 @@
 
 		} finally {
 			// put the framework back to the RESOLVED state
-			equinox.stop();
-
-			try {
-				equinox.waitForStop(10000);
-			} catch (InterruptedException e) {
-				fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-			}
+			stop(equinox);
 		}
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 		assertNull("SecurityManager is not null", System.getSecurityManager()); //$NON-NLS-1$
@@ -324,13 +326,7 @@
 			fail("interrupted", e); //$NON-NLS-1$
 		} finally {
 			// put the framework back to the RESOLVED state
-			equinox.stop();
-
-			try {
-				equinox.waitForStop(10000);
-			} catch (InterruptedException e) {
-				fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-			}
+			stop(equinox);
 		}
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 		assertNull("SecurityManager is not null", System.getSecurityManager()); //$NON-NLS-1$
@@ -373,13 +369,7 @@
 			assertTrue(pa.resolveBundles(new Bundle[] {linkA, linkAClient}));
 		} finally {
 			// put the framework back to the RESOLVED state
-			equinox.stop();
-
-			try {
-				equinox.waitForStop(10000);
-			} catch (InterruptedException e) {
-				fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-			}
+			stop(equinox);
 		}
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 		assertNull("SecurityManager is not null", System.getSecurityManager()); //$NON-NLS-1$
@@ -431,13 +421,7 @@
 			fail("Failed to start securityA", e); //$NON-NLS-1$
 		} finally {
 			// put the framework back to the RESOLVED state
-			equinox.stop();
-
-			try {
-				equinox.waitForStop(10000);
-			} catch (InterruptedException e) {
-				fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-			}
+			stop(equinox);
 		}
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 		assertNull("SecurityManager is not null", System.getSecurityManager()); //$NON-NLS-1$
@@ -487,16 +471,7 @@
 		}
 
 		// put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 
 		try {
 			equinox.start();
@@ -516,16 +491,7 @@
 			fail("Failed to start security.b bundle", e); //$NON-NLS-1$
 		}
 
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 		assertNull("SecurityManager is not null", System.getSecurityManager()); //$NON-NLS-1$
 	}
@@ -575,16 +541,7 @@
 				// nothing
 			}
 		assertEquals("Wrong startlevel", 10, sl.getStartLevel()); //$NON-NLS-1$
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 		assertNull("SecurityManager is not null", System.getSecurityManager()); //$NON-NLS-1$
 	}
@@ -630,16 +587,7 @@
 		}
 
 		// put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 
 		// try again from a cached state
 		try {
@@ -662,16 +610,7 @@
 			// expected failure
 		}
 		// put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected erorr stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 		assertNull("SecurityManager is not null", System.getSecurityManager()); //$NON-NLS-1$
 	}
@@ -744,16 +683,7 @@
 		}
 
 		// put the framework back to the RESOLVED state
-		try {
-			equinox.stop();
-		} catch (BundleException e) {
-			fail("Unexpected error stopping framework", e); //$NON-NLS-1$
-		}
-		try {
-			equinox.waitForStop(10000);
-		} catch (InterruptedException e) {
-			fail("Unexpected interrupted exception", e); //$NON-NLS-1$
-		}
+		stop(equinox);
 		assertEquals("Wrong state for SystemBundle", Bundle.RESOLVED, equinox.getState()); //$NON-NLS-1$
 		assertNull("SecurityManager is not null", System.getSecurityManager()); //$NON-NLS-1$
 	}
diff --git a/bundles/org.eclipse.osgi.util/pom.xml b/bundles/org.eclipse.osgi.util/pom.xml
index d2e126b..25dc11a 100644
--- a/bundles/org.eclipse.osgi.util/pom.xml
+++ b/bundles/org.eclipse.osgi.util/pom.xml
@@ -14,7 +14,7 @@
   <parent>
     <artifactId>rt.equinox.framework</artifactId>
     <groupId>org.eclipse.equinox.framework</groupId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
   <groupId>org.eclipse.osgi</groupId>
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxBundle.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxBundle.java
index db9c00d..56c5eee 100644
--- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxBundle.java
+++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/EquinoxBundle.java
@@ -222,7 +222,7 @@
 									SystemBundle.this.getEquinoxContainer().getLogServices().log(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, "Error stopping the framework.", e); //$NON-NLS-1$
 								}
 							}
-						}, "Framework stop"); //$NON-NLS-1$
+						}, "Framework stop - " + getEquinoxContainer().toString()); //$NON-NLS-1$
 						t.start();
 					}
 				} finally {
@@ -246,7 +246,7 @@
 									SystemBundle.this.getEquinoxContainer().getLogServices().log(EquinoxContainer.NAME, FrameworkLogEntry.ERROR, "Error updating the framework.", e); //$NON-NLS-1$
 								}
 							}
-						}, "Framework update"); //$NON-NLS-1$
+						}, "Framework update - " + getEquinoxContainer().toString()); //$NON-NLS-1$
 						t.start();
 					}
 				} finally {
diff --git a/bundles/org.eclipse.osgi/pom.xml b/bundles/org.eclipse.osgi/pom.xml
index b75f512..8fcf699 100644
--- a/bundles/org.eclipse.osgi/pom.xml
+++ b/bundles/org.eclipse.osgi/pom.xml
@@ -14,7 +14,7 @@
   <parent>
     <artifactId>rt.equinox.framework</artifactId>
     <groupId>org.eclipse.equinox.framework</groupId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
   <groupId>org.eclipse.osgi</groupId>
diff --git a/bundles/org.eclipse.osgi/supplement/pom.xml b/bundles/org.eclipse.osgi/supplement/pom.xml
index b6588fe..8901111 100644
--- a/bundles/org.eclipse.osgi/supplement/pom.xml
+++ b/bundles/org.eclipse.osgi/supplement/pom.xml
@@ -15,7 +15,7 @@
   <parent>
     <artifactId>rt.equinox.framework</artifactId>
     <groupId>org.eclipse.equinox.framework</groupId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
     <relativePath>../../../</relativePath>
   </parent>
 
diff --git a/features/org.eclipse.equinox.executable.feature/bin/cocoa/macosx/x86_64/Eclipse.app/Contents/Info.plist b/features/org.eclipse.equinox.executable.feature/bin/cocoa/macosx/x86_64/Eclipse.app/Contents/Info.plist
index 92f7a2d..1093689 100644
--- a/features/org.eclipse.equinox.executable.feature/bin/cocoa/macosx/x86_64/Eclipse.app/Contents/Info.plist
+++ b/features/org.eclipse.equinox.executable.feature/bin/cocoa/macosx/x86_64/Eclipse.app/Contents/Info.plist
@@ -6,7 +6,7 @@
 	<key>CFBundleExecutable</key>
 		<string>eclipse</string>
 	<key>CFBundleGetInfoString</key>
-		<string>Eclipse 4.16 for Mac OS X, Copyright IBM Corp. and others 2002, 2020. All rights reserved.</string>
+		<string>Eclipse 4.17 for Mac OS X, Copyright IBM Corp. and others 2002, 2020. All rights reserved.</string>
 	<key>CFBundleIconFile</key>
 		<string>Eclipse.icns</string>
 	<key>CFBundleIdentifier</key>
@@ -18,11 +18,11 @@
 	<key>CFBundlePackageType</key>
 		<string>APPL</string>
 	<key>CFBundleShortVersionString</key>
-		<string>4.16</string>
+		<string>4.17</string>
 	<key>CFBundleSignature</key>
 		<string>????</string>
 	<key>CFBundleVersion</key>
-		<string>4.16</string>
+		<string>4.17</string>
 	<key>NSHighResolutionCapable</key>
 		<true/>
 	<key>CFBundleDevelopmentRegion</key>
diff --git a/features/org.eclipse.equinox.executable.feature/feature.xml b/features/org.eclipse.equinox.executable.feature/feature.xml
index aaa8a63..c9675db 100755
--- a/features/org.eclipse.equinox.executable.feature/feature.xml
+++ b/features/org.eclipse.equinox.executable.feature/feature.xml
@@ -2,7 +2,7 @@
 <feature
       id="org.eclipse.equinox.executable"
       label="%featureName"
-      version="3.8.800.qualifier"
+      version="3.8.900.qualifier"
       provider-name="%providerName"
       license-feature="org.eclipse.license"
       license-feature-version="0.0.0">
diff --git a/features/org.eclipse.equinox.executable.feature/library/eclipseConfig.c b/features/org.eclipse.equinox.executable.feature/library/eclipseConfig.c
index 172f202..7111cdd 100644
--- a/features/org.eclipse.equinox.executable.feature/library/eclipseConfig.c
+++ b/features/org.eclipse.equinox.executable.feature/library/eclipseConfig.c
@@ -38,6 +38,59 @@
 
 #endif
 
+static const _TCHAR LHS[] = _T_ECLIPSE("$"); /* left-hand side marker */
+static const _TCHAR RHS[] = _T_ECLIPSE("$"); /* right-hand side marker */
+static const unsigned short LHS_LEN = (sizeof(LHS) - sizeof(_TCHAR)) / sizeof(_TCHAR);
+static const unsigned short RHS_LEN = (sizeof(RHS) - sizeof(_TCHAR)) / sizeof(_TCHAR);
+
+/* we use a function pointer to abstract out the logic from getenv()
+ to ease testing */
+_TCHAR * expandEnvVarsInternal(const _TCHAR * input, _TCHAR* (*resolve)(const _TCHAR *)) {
+	_TCHAR * result;
+	const _TCHAR * lhsOuterPos = _tcsstr(input, LHS);
+
+	if ((lhsOuterPos != NULL) && _tcslen(lhsOuterPos) > LHS_LEN) {
+		const _TCHAR * lhsInnerPos = lhsOuterPos + LHS_LEN - 1;
+		const _TCHAR * rhsInnerPos = _tcsstr(lhsInnerPos, RHS);
+
+		if (rhsInnerPos != NULL) {
+			const _TCHAR * value;
+			_TCHAR * var = (_TCHAR *) calloc((rhsInnerPos - lhsInnerPos), sizeof(_TCHAR));
+
+			_tcsncpy(var, lhsInnerPos + 1, (rhsInnerPos - lhsInnerPos - 1));
+			value = resolve(var);
+
+			free(var);
+
+			if (value != NULL) {
+				/* expand remaining of the original string */
+				_TCHAR * remaining = expandEnvVarsInternal(rhsInnerPos + RHS_LEN, resolve);
+
+				/* length of the beginning of the original string */
+				const unsigned int beginLen = lhsOuterPos - input;
+				size_t len = beginLen
+										+ _tcslen(value) 	 /* de-referenced variable */
+										+ _tcslen(remaining) /* rest of the string (expanded vars) */
+										+ 1; 				 /* string terminator */
+
+				result = (_TCHAR *) calloc(len, sizeof(_TCHAR));
+				_tcsncpy(result, input, beginLen);
+				_tcscat(result, value);
+				_tcscat(result, remaining);
+
+				free(remaining);
+
+				return result;
+			}
+		}
+	}
+
+	/* nothing to expand, just return a copy of the original string */
+	result = _tcsdup(input);
+
+	return result;
+}
+
 int readIniFile(_TCHAR* program, int *argc, _TCHAR ***argv) 
 {
 	_TCHAR* config_file = NULL;
@@ -153,7 +206,7 @@
 			if(argument[0] == _T_ECLIPSE('#'))
 				continue;
 
-			arg = _tcsdup(argument);
+			arg = expandEnvVarsInternal(argument, _tgetenv);
 			length = _tcslen(arg);
 			
 			/* basic whitespace trimming */
diff --git a/features/org.eclipse.equinox.executable.feature/library/make_version.mak b/features/org.eclipse.equinox.executable.feature/library/make_version.mak
index 5af5757..b74e7e6 100644
--- a/features/org.eclipse.equinox.executable.feature/library/make_version.mak
+++ b/features/org.eclipse.equinox.executable.feature/library/make_version.mak
@@ -13,5 +13,5 @@
 #*******************************************************************************
 
 maj_ver=1
-min_ver=1000
+min_ver=1100
 LIB_VERSION = $(maj_ver)$(min_ver)
diff --git a/features/org.eclipse.equinox.executable.feature/pom.xml b/features/org.eclipse.equinox.executable.feature/pom.xml
index 569b29f..8be3a3f 100644
--- a/features/org.eclipse.equinox.executable.feature/pom.xml
+++ b/features/org.eclipse.equinox.executable.feature/pom.xml
@@ -14,12 +14,12 @@
   <parent>
     <artifactId>rt.equinox.framework</artifactId>
     <groupId>org.eclipse.equinox.framework</groupId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
     <relativePath>../../</relativePath>
   </parent>
   <groupId>org.eclipse.equinox.feature</groupId>
   <artifactId>org.eclipse.equinox.executable</artifactId>
-  <version>3.8.800-SNAPSHOT</version>
+  <version>3.8.900-SNAPSHOT</version>
   <packaging>eclipse-feature</packaging>
 
   <build>
diff --git a/launcher-binary-parent/pom.xml b/launcher-binary-parent/pom.xml
index f478b48..30e2195 100644
--- a/launcher-binary-parent/pom.xml
+++ b/launcher-binary-parent/pom.xml
@@ -15,7 +15,7 @@
   <parent>
     <groupId>org.eclipse.equinox.framework</groupId>
     <artifactId>rt.equinox.framework</artifactId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
   </parent>
 
   <artifactId>launcher-binary-parent</artifactId>
diff --git a/pom.xml b/pom.xml
index 379802d..a52b31f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,13 +15,13 @@
   <parent>
     <groupId>org.eclipse</groupId>
     <artifactId>eclipse-platform-parent</artifactId>
-    <version>4.16.0-SNAPSHOT</version>
+    <version>4.17.0-SNAPSHOT</version>
     <relativePath>../eclipse-platform-parent</relativePath>
   </parent>
 
   <groupId>org.eclipse.equinox.framework</groupId>
   <artifactId>rt.equinox.framework</artifactId>
-  <version>4.16.0-SNAPSHOT</version>
+  <version>4.17.0-SNAPSHOT</version>
   <packaging>pom</packaging>
 
   <properties>