docs: public void launchFramework(BootstrapConfig config, LogProvider logProvider) {
          if (config == null)
              throw new IllegalArgumentException("bootstrap config must not be null");
          boolean isClient = config.getProcessType().equals(BootstrapConstants.LOC_PROCESS_TYPE_CLIENT);
          try {
              String nTime = config.get(BootstrapConstants.LAUNCH_TIME);
              startTime = nTime == null ? System.nanoTime() : Long.parseLong(nTime);
              if (isClient) {
                  Tr.audit(tc, "audit.launchTime.client", config.getProcessName());
              } else {
                  Tr.audit(tc, "audit.launchTime", config.getProcessName());
              }
  
              outputLicenseRestrictionMessage();
  
              outputEmbeddedProductExtensions();
  
              outputEnvironmentVariableProductExtensions();
  
              // Save the bootstrap config locally
              this.config = config;
  
              boolean j2secManager = false;
              if (config.get(BootstrapConstants.JAVA_2_SECURITY_PROPERTY) != null) {
                  j2secManager = true;
              }
  
              String j2secNoRethrow = config.get(BootstrapConstants.JAVA_2_SECURITY_NORETHROW);
  
              if (j2secManager) {
  
                  if (j2secNoRethrow == null || j2secNoRethrow.equals("false")) {
                      try {
                          AccessController.doPrivileged(new java.security.PrivilegedExceptionAction<Void>() {
                              @Override
                              public Void run() throws Exception {
                                  System.setSecurityManager(new SecurityManager());
                                  return null;
                              }
                          });
                      } catch (Exception ex) {
  
                          Tr.error(tc, "error.set.securitymanager", ex.getMessage());
                      }
                  } else {
                      if ("true".equals(config.get(BootstrapConstants.JAVA_2_SECURITY_UNIQUE)))
                          MissingDoPrivDetectionSecurityManager.setUniqueOnly(true);
                      try {
                          AccessController.doPrivileged(new java.security.PrivilegedExceptionAction<Void>() {
                              @Override
                              public Void run() throws Exception {
                                  System.setSecurityManager(new MissingDoPrivDetectionSecurityManager());
                                  return null;
                              }
                          });
                      } catch (Exception ex) {
  
                          Tr.error(tc, "error.set.trace.securitymanager", ex.getMessage());
                      }
  
                  }
                  Tr.info(tc, "info.java2security.started", config.getProcessName());
  
              }
  
              // Start the framework.
              Framework fwk = startFramework(config);
  
              if (fwk == null) {
                  Tr.error(tc, "error.unableToLaunch");
                  return;
              }
              // Set the framework variables only if everything succeeded.
              systemBundleCtx = fwk.getBundleContext();
              framework = fwk;
          } catch (BundleException e) {
              throw new RuntimeException(e);
          } finally {
              // If an error occurred, notify anyone that was waiting for the
              // framework so they know it's not coming.
              frameworkLatch.countDown();
  
              try {
                  if (framework != null) {
                      try {
                          addShutdownHook(isClient);
                          startServerCommandListener();
                          innerLaunchFramework(isClient);
  
                          // Indicate that kernel has been started
                          Tr.info(tc, "audit.kernelStartTime", getElapsedTime(false));
                          frameworkLaunchSuccess = true;
                      } finally {
                          // If an error occurred, notify anyone that was waiting
                          // for launch so they know we're done.
                          frameworkLaunched.countDown();
                          try {
                              if (!frameworkLaunchSuccess) {
                                  stopFramework();
                              } else if (isClient) {
                                  try {
                                      if (waitForReady()) {
                                          launchClient();
                                      }
                                  } catch (InterruptedException e) {
                                      // Ignore
                                  } catch (Throwable t) {
                                      throw new ClientRunnerException("Error while executing running the application", BootstrapConstants.messages.getString("error.client.runner"), t);
  
                                  } finally {
                                      stopFramework();
                                  }
                              }
                          } finally {
                              // Run the server: wait indefinitely until framework stop.
                              // (It might have been stopped above if an error occurred.)
                              waitForFrameworkStop();
  
                              // Remove the shutdown hook in case someone stopped the OSGi
                              // framework without calling our shutdownFramework() method.
                              removeShutdownHook();
  
                              // Close the command listener port, and stop any of its threads.
                              if (sc != null) {
                                  sc.close();
                              }
  
                              if (frameworkLaunchSuccess) {
                                  if (isClient) {
                                      Tr.audit(tc, "audit.kernelUpTime.client", config.getProcessName(), getElapsedTime(true));
                                  } else {
                                      Tr.audit(tc, "audit.kernelUpTime", config.getProcessName(), getElapsedTime(true));
                                  }
                              }
                          }
                      }
                  }
              } finally {
                  // Stop the log provider.
                  if (logProvider != null) {
                      logProvider.stop();
                  }
  
                  // Finally, notify any waiters that the kernel has been shutdown.
                  // This is done after stopping the log provider so that logs are
                  // flushed in case the shutdown hook will immediately exit the JVM.
                  frameworkShutdownLatch.countDown();
              }
          }
      }