diff --git a/core/authorize.php b/core/authorize.php
index 97fbe24..91fe577 100644
--- a/core/authorize.php
+++ b/core/authorize.php
@@ -21,11 +21,14 @@
  */
 
 use Drupal\Component\Utility\Settings;
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
 
 // Change the directory to the Drupal root.
 chdir('..');
 
 require_once __DIR__ . '/vendor/autoload.php';
+require_once __DIR__ . '/includes/bootstrap.inc';
 
 /**
  * Global flag to identify update.php and authorize.php runs.
@@ -51,17 +54,8 @@ function authorize_access_allowed() {
   return Settings::get('allow_authorize_operations', TRUE) && user_access('administer software updates');
 }
 
-// *** Real work of the script begins here. ***
-
-require_once __DIR__ . '/includes/bootstrap.inc';
-require_once __DIR__ . '/includes/common.inc';
-require_once __DIR__ . '/includes/file.inc';
-require_once __DIR__ . '/includes/module.inc';
-require_once __DIR__ . '/includes/ajax.inc';
-
-// Prepare a minimal bootstrap.
-drupal_bootstrap(DRUPAL_BOOTSTRAP_PAGE_CACHE);
-$request = \Drupal::request();
+$request = Request::createFromGlobals();
+$kernel = DrupalKernel::bootKernel($request);
 
 // We have to enable the user and system modules, even to check access and
 // display errors via the maintenance theme.
diff --git a/core/core.services.yml b/core/core.services.yml
index fe8d80d..19ccf5d 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -166,6 +166,11 @@ services:
   theme.negotiator:
     class: Drupal\Core\Theme\ThemeNegotiator
     arguments: ['@access_check.theme', '@request_stack']
+  theme.negotiator.request_subscriber:
+    class: Drupal\Core\EventSubscriber\ThemeNegotiatorRequestSubscriber
+    arguments: ['@theme.negotiator']
+    tags:
+      - { name: event_subscriber }
   theme.negotiator.default:
     class: Drupal\Core\Theme\DefaultNegotiator
     arguments: ['@config.factory']
@@ -538,10 +543,6 @@ services:
     tags:
       - { name: event_subscriber }
     arguments: ['@path.alias_manager.cached', '@path_processor_manager']
-  legacy_request_subscriber:
-    class: Drupal\Core\EventSubscriber\LegacyRequestSubscriber
-    tags:
-      - { name: event_subscriber }
   finish_response_subscriber:
     class: Drupal\Core\EventSubscriber\FinishResponseSubscriber
     tags:
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 36a0627..c660d23 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -127,27 +127,27 @@
 /**
  * First bootstrap phase: initialize configuration.
  */
-const DRUPAL_BOOTSTRAP_CONFIGURATION = 0;
+const DRUPAL_BOOTSTRAP_CONFIGURATION = DrupalKernel::BOOTSTRAP_CONFIGURATION;
 
 /**
- * Second bootstrap phase, initalize a kernel.
+ * @todo Obsolete. Remove once Drush has been updated.
  */
-const DRUPAL_BOOTSTRAP_KERNEL = 1;
+const DRUPAL_BOOTSTRAP_KERNEL = DrupalKernel::BOOTSTRAP_PAGE_CACHE;
 
 /**
  * Third bootstrap phase: try to serve a cached page.
  */
-const DRUPAL_BOOTSTRAP_PAGE_CACHE = 2;
+const DRUPAL_BOOTSTRAP_PAGE_CACHE = DrupalKernel::BOOTSTRAP_PAGE_CACHE;
 
 /**
  * Fourth bootstrap phase: load code for subsystems and modules.
  */
-const DRUPAL_BOOTSTRAP_CODE = 3;
+const DRUPAL_BOOTSTRAP_CODE = DrupalKernel::BOOTSTRAP_CODE;
 
 /**
- * Final bootstrap phase: initialize language, path, theme, and modules.
+ * @todo Obsolete. Remove once Drush has been updated.
  */
-const DRUPAL_BOOTSTRAP_FULL = 4;
+const DRUPAL_BOOTSTRAP_FULL = DrupalKernel::BOOTSTRAP_CODE;
 
 /**
  * Role ID for anonymous users; should match what's in the "role" table.
@@ -227,33 +227,18 @@
  * @param bool $reset
  *   Force a full search for matching directories even if one had been
  *   found previously. Defaults to FALSE.
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ *   The current request.
  *
- * @return
+ * @return string
  *   The path of the matching directory.
- *
  * @see default.settings.php
+ *
+ * @deprecated 8.x
+ *   Use \Drupal\Core\DrupalKernel::confPath().
  */
-function conf_path($require_settings = TRUE, $reset = FALSE) {
-  static $conf_path;
-
-  if (isset($conf_path) && !$reset) {
-    return $conf_path;
-  }
-
-  // Check for a simpletest override.
-  if ($test_prefix = drupal_valid_test_ua()) {
-    $conf_path = 'sites/simpletest/' . substr($test_prefix, 10);
-    return $conf_path;
-  }
-
-  // Otherwise, use the normal $conf_path.
-  $script_name = $_SERVER['SCRIPT_NAME'];
-  if (!$script_name) {
-    $script_name = $_SERVER['SCRIPT_FILENAME'];
-  }
-  $http_host = $_SERVER['HTTP_HOST'];
-  $conf_path = find_conf_path($http_host, $script_name, $require_settings);
-  return $conf_path;
+function conf_path($require_settings = TRUE, $reset = FALSE, Request $request = NULL) {
+  return DrupalKernel::confPath($request, $require_settings, $reset);
 }
 
 /**
@@ -341,207 +326,6 @@ function config_get_config_directory($type = CONFIG_ACTIVE_DIRECTORY) {
 }
 
 /**
- * Initializes the PHP environment.
- */
-function drupal_environment_initialize() {
-  if (!isset($_SERVER['HTTP_REFERER'])) {
-    $_SERVER['HTTP_REFERER'] = '';
-  }
-  if (!isset($_SERVER['SERVER_PROTOCOL']) || ($_SERVER['SERVER_PROTOCOL'] != 'HTTP/1.0' && $_SERVER['SERVER_PROTOCOL'] != 'HTTP/1.1')) {
-    $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.0';
-  }
-
-  if (isset($_SERVER['HTTP_HOST'])) {
-    // As HTTP_HOST is user input, ensure it only contains characters allowed
-    // in hostnames. See RFC 952 (and RFC 2181).
-    // $_SERVER['HTTP_HOST'] is lowercased here per specifications.
-    $_SERVER['HTTP_HOST'] = strtolower($_SERVER['HTTP_HOST']);
-    if (!drupal_valid_http_host($_SERVER['HTTP_HOST'])) {
-      // HTTP_HOST is invalid, e.g. if containing slashes it may be an attack.
-      header($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request');
-      exit;
-    }
-  }
-  else {
-    // Some pre-HTTP/1.1 clients will not send a Host header. Ensure the key is
-    // defined for E_ALL compliance.
-    $_SERVER['HTTP_HOST'] = '';
-  }
-
-  // @todo Refactor with the Symfony Request object.
-  _current_path(request_path());
-
-  // Enforce E_STRICT, but allow users to set levels not part of E_STRICT.
-  error_reporting(E_STRICT | E_ALL | error_reporting());
-
-  // Override PHP settings required for Drupal to work properly.
-  // sites/default/default.settings.php contains more runtime settings.
-  // The .htaccess file contains settings that cannot be changed at runtime.
-
-  // Use session cookies, not transparent sessions that puts the session id in
-  // the query string.
-  ini_set('session.use_cookies', '1');
-  ini_set('session.use_only_cookies', '1');
-  ini_set('session.use_trans_sid', '0');
-  // Don't send HTTP headers using PHP's session handler.
-  // Send an empty string to disable the cache limiter.
-  ini_set('session.cache_limiter', '');
-  // Use httponly session cookies.
-  ini_set('session.cookie_httponly', '1');
-
-  // Set sane locale settings, to ensure consistent string, dates, times and
-  // numbers handling.
-  setlocale(LC_ALL, 'C');
-}
-
-/**
- * Validates that a hostname (for example $_SERVER['HTTP_HOST']) is safe.
- *
- * @return
- *  TRUE if only containing valid characters, or FALSE otherwise.
- */
-function drupal_valid_http_host($host) {
-  return preg_match('/^\[?(?:[a-zA-Z0-9-:\]_]+\.?)+$/', $host);
-}
-
-/**
- * Sets the base URL, cookie domain, and session name from configuration.
- */
-function drupal_settings_initialize() {
-  // Export these settings.php variables to the global namespace.
-  global $base_url, $databases, $cookie_domain, $config_directories, $config;
-  $settings = array();
-  $config = array();
-
-  // Make conf_path() available as local variable in settings.php.
-  $conf_path = conf_path();
-  if (is_readable(DRUPAL_ROOT . '/' . $conf_path . '/settings.php')) {
-    require DRUPAL_ROOT . '/' . $conf_path . '/settings.php';
-  }
-  // Initialize Settings.
-  new Settings($settings);
-}
-
-/**
- * Initializes global request variables.
- *
- * @todo D8: Eliminate this entirely in favor of Request object.
- */
-function _drupal_request_initialize() {
-  // Provided by settings.php.
-  // @see drupal_settings_initialize()
-  global $base_url, $cookie_domain;
-  // Set and derived from $base_url by this function.
-  global $base_path, $base_root, $script_path;
-  global $base_secure_url, $base_insecure_url;
-
-  $is_https = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) == 'on';
-
-  if (isset($base_url)) {
-    // Parse fixed base URL from settings.php.
-    $parts = parse_url($base_url);
-    if (!isset($parts['path'])) {
-      $parts['path'] = '';
-    }
-    $base_path = $parts['path'] . '/';
-    // Build $base_root (everything until first slash after "scheme://").
-    $base_root = substr($base_url, 0, strlen($base_url) - strlen($parts['path']));
-  }
-  else {
-    // Create base URL
-    $http_protocol = $is_https ? 'https' : 'http';
-    $base_root = $http_protocol . '://' . $_SERVER['HTTP_HOST'];
-
-    $base_url = $base_root;
-
-    // For a request URI of '/index.php/foo', $_SERVER['SCRIPT_NAME'] is
-    // '/index.php', whereas $_SERVER['PHP_SELF'] is '/index.php/foo'.
-    if ($dir = rtrim(dirname($_SERVER['SCRIPT_NAME']), '\/')) {
-      // Remove "core" directory if present, allowing install.php, update.php,
-      // and others to auto-detect a base path.
-      $core_position = strrpos($dir, '/core');
-      if ($core_position !== FALSE && strlen($dir) - 5 == $core_position) {
-        $base_path = substr($dir, 0, $core_position);
-      }
-      else {
-        $base_path = $dir;
-      }
-      $base_url .= $base_path;
-      $base_path .= '/';
-    }
-    else {
-      $base_path = '/';
-    }
-  }
-  $base_secure_url = str_replace('http://', 'https://', $base_url);
-  $base_insecure_url = str_replace('https://', 'http://', $base_url);
-
-  // Determine the path of the script relative to the base path, and add a
-  // trailing slash. This is needed for creating URLs to Drupal pages.
-  if (!isset($script_path)) {
-    $script_path = '';
-    // We don't expect scripts outside of the base path, but sanity check
-    // anyway.
-    if (strpos($_SERVER['SCRIPT_NAME'], $base_path) === 0) {
-      $script_path = substr($_SERVER['SCRIPT_NAME'], strlen($base_path)) . '/';
-      // If the request URI does not contain the script name, then clean URLs
-      // are in effect and the script path can be similarly dropped from URL
-      // generation. For servers that don't provide $_SERVER['REQUEST_URI'], we
-      // do not know the actual URI requested by the client, and request_uri()
-      // returns a URI with the script name, resulting in non-clean URLs unless
-      // there's other code that intervenes.
-      if (strpos(request_uri(TRUE) . '/', $base_path . $script_path) !== 0) {
-        $script_path = '';
-      }
-      // @todo Temporary BC for install.php, update.php, and other scripts.
-      //   - http://drupal.org/node/1547184
-      //   - http://drupal.org/node/1546082
-      if ($script_path !== 'index.php/') {
-        $script_path = '';
-      }
-    }
-  }
-
-  if ($cookie_domain) {
-    // If the user specifies the cookie domain, also use it for session name.
-    $session_name = $cookie_domain;
-  }
-  else {
-    // Otherwise use $base_url as session name, without the protocol
-    // to use the same session identifiers across HTTP and HTTPS.
-    list( , $session_name) = explode('://', $base_url, 2);
-    // HTTP_HOST can be modified by a visitor, but we already sanitized it
-    // in drupal_settings_initialize().
-    if (!empty($_SERVER['HTTP_HOST'])) {
-      $cookie_domain = $_SERVER['HTTP_HOST'];
-      // Strip leading periods, www., and port numbers from cookie domain.
-      $cookie_domain = ltrim($cookie_domain, '.');
-      if (strpos($cookie_domain, 'www.') === 0) {
-        $cookie_domain = substr($cookie_domain, 4);
-      }
-      $cookie_domain = explode(':', $cookie_domain);
-      $cookie_domain = '.' . $cookie_domain[0];
-    }
-  }
-  // Per RFC 2109, cookie domains must contain at least one dot other than the
-  // first. For hosts such as 'localhost' or IP Addresses we don't set a cookie domain.
-  if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) {
-    ini_set('session.cookie_domain', $cookie_domain);
-  }
-  // To prevent session cookies from being hijacked, a user can configure the
-  // SSL version of their website to only transfer session cookies via SSL by
-  // using PHP's session.cookie_secure setting. The browser will then use two
-  // separate session cookies for the HTTPS and HTTP versions of the site. So we
-  // must use different session identifiers for HTTPS and HTTP to prevent a
-  // cookie collision.
-  if ($is_https) {
-    ini_set('session.cookie_secure', TRUE);
-  }
-  $prefix = ini_get('session.cookie_secure') ? 'SSESS' : 'SESS';
-  session_name($prefix . substr(hash('sha256', $session_name), 0, 32));
-}
-
-/**
  * Returns and optionally sets the filename for a system resource.
  *
  * The filename, whether provided, cached, or retrieved from the database, is
@@ -1343,136 +1127,37 @@ function drupal_anonymous_user() {
 }
 
 /**
- * Ensures Drupal is bootstrapped to the specified phase.
- *
- * In order to bootstrap Drupal from another PHP script, you can use this code:
- * @code
- *   require_once '/path/to/drupal/core/vendor/autoload.php';
- *   require_once '/path/to/drupal/core/includes/bootstrap.inc';
- *   drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
- * @endcode
+ * Bootstraps DrupalKernel to a given boot level.
  *
- * @param $phase
- *   A constant telling which phase to bootstrap to. When you bootstrap to a
- *   particular phase, all earlier phases are run automatically. Possible
- *   values:
+ * @param int $phase
+ *   The boot level to bootstrap to. Possible values:
  *   - DRUPAL_BOOTSTRAP_CONFIGURATION: Initializes configuration.
- *   - DRUPAL_BOOTSTRAP_KERNEL: Initalizes a kernel.
  *   - DRUPAL_BOOTSTRAP_PAGE_CACHE: Tries to serve a cached page.
  *   - DRUPAL_BOOTSTRAP_CODE: Loads code for subsystems and modules.
- *   - DRUPAL_BOOTSTRAP_FULL: Fully loads Drupal. Validates and fixes input
  *     data.
  *
- * @return
- *   The most recently completed phase.
- */
-function drupal_bootstrap($phase = NULL) {
-  // Not drupal_static(), because does not depend on any run-time information.
-  static $phases = array(
-    DRUPAL_BOOTSTRAP_CONFIGURATION,
-    DRUPAL_BOOTSTRAP_KERNEL,
-    DRUPAL_BOOTSTRAP_PAGE_CACHE,
-    DRUPAL_BOOTSTRAP_CODE,
-    DRUPAL_BOOTSTRAP_FULL,
-  );
-  // Not drupal_static(), because the only legitimate API to control this is to
-  // call drupal_bootstrap() with a new phase parameter.
-  static $final_phase = -1;
-  // Not drupal_static(), because it's impossible to roll back to an earlier
-  // bootstrap state.
-  static $stored_phase = -1;
-
-  // Store the phase name so it's not forgotten during recursion. Additionally,
-  // ensure that $final_phase is never rolled back to an earlier bootstrap
-  // state.
-  if ($phase > $final_phase) {
-    $final_phase = $phase;
-  }
-  if (isset($phase)) {
-    // Call a phase if it has not been called before and is below the requested
-    // phase.
-    while ($phases && $phase > $stored_phase && $final_phase > $stored_phase) {
-      $current_phase = array_shift($phases);
-
-      // This function is re-entrant. Only update the completed phase when the
-      // current call actually resulted in a progress in the bootstrap process.
-      if ($current_phase > $stored_phase) {
-        $stored_phase = $current_phase;
-      }
-
-      switch ($current_phase) {
-        case DRUPAL_BOOTSTRAP_CONFIGURATION:
-          _drupal_bootstrap_configuration();
-          break;
-
-        case DRUPAL_BOOTSTRAP_KERNEL:
-          _drupal_bootstrap_kernel();
-          break;
-
-        case DRUPAL_BOOTSTRAP_PAGE_CACHE:
-          _drupal_bootstrap_page_cache();
-          break;
-
-        case DRUPAL_BOOTSTRAP_CODE:
-          require_once __DIR__ . '/common.inc';
-          _drupal_bootstrap_code();
-          break;
-
-        case DRUPAL_BOOTSTRAP_FULL:
-          _drupal_bootstrap_full();
-          break;
-      }
-    }
-  }
-  return $stored_phase;
-}
-
-/**
- * Handles an entire PHP request.
- *
- * This function may be called by PHP scripts (e.g., Drupal's index.php) that
- * want Drupal to take over the entire PHP processing of the request. The only
- * expectation is that PHP's superglobals are initialized as desired (PHP does
- * this automatically, but some scripts might want to alter them) and that the
- * DRUPAL_ROOT constant is defined and set to the absolute server directory of
- * Drupal's codebase.
+ * @return int
+ *   The current bootstrap level.
  *
- * Scripts and applications that want to invoke multiple Drupal requests within
- * a single PHP request, or Drupal request handling within some larger workflow,
- * should not call this function, but instead instantiate and use
- * \Drupal\Core\DrupalKernel as needed.
+ * @deprecated 8.x
+ *   Use \Drupal\Core\DrupalKernel::bootKernel() et al instead.
  *
- * @param boolean $test_only
- *   Whether to restrict handling to only requests invoked by SimpleTest.
- *
- * @see index.php
+ * @todo Obsolete. Remove once Drush has been updated.
  */
-function drupal_handle_request($test_only = FALSE) {
-  // Initialize the environment, load settings.php, and activate a PSR-0 class
-  // autoloader with required namespaces registered.
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+function drupal_bootstrap($phase = NULL) {
+  switch ($phase) {
+    case DRUPAL_BOOTSTRAP_CONFIGURATION:
+      DrupalKernel::bootConfiguration(Request::createFromGlobals());
+      break;
 
-  // Exit if we should be in a test environment but aren't.
-  if ($test_only && !drupal_valid_test_ua()) {
-    header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');
-    exit;
+    case DRUPAL_BOOTSTRAP_KERNEL:
+    case DRUPAL_BOOTSTRAP_PAGE_CACHE:
+    case DRUPAL_BOOTSTRAP_CODE:
+    case DRUPAL_BOOTSTRAP_FULL:
+      DrupalKernel::bootKernel(Request::createFromGlobals());
+      break;
   }
-
-  $kernel = new DrupalKernel('prod', drupal_classloader(), !$test_only);
-
-  // @todo Remove this once everything in the bootstrap has been
-  //   converted to services in the DIC.
-  $kernel->boot();
-
-  // Create a request object from the HttpFoundation.
-  $request = Request::createFromGlobals();
-  \Drupal::getContainer()->set('request', $request);
-
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE);
-
-  $response = $kernel->handle($request)->prepare($request)->send();
-
-  $kernel->terminate($request, $response);
+  return DrupalKernel::getBootLevel();
 }
 
 /**
@@ -1558,120 +1243,17 @@ function _drupal_exception_handler($exception) {
 }
 
 /**
- * Sets up the script environment and loads settings.php.
- */
-function _drupal_bootstrap_configuration() {
-  drupal_environment_initialize();
-
-  // Indicate that code is operating in a test child site.
-  if ($test_prefix = drupal_valid_test_ua()) {
-    // Only code that interfaces directly with tests should rely on this
-    // constant; e.g., the error/exception handler conditionally adds further
-    // error information into HTTP response headers that are consumed by
-    // Simpletest's internal browser.
-    define('DRUPAL_TEST_IN_CHILD_SITE', TRUE);
-
-    // Log fatal errors to the test site directory.
-    ini_set('log_errors', 1);
-    ini_set('error_log', DRUPAL_ROOT . '/sites/simpletest/' . substr($test_prefix, 10) . '/error.log');
-  }
-  else {
-    // Ensure that no other code defines this.
-    define('DRUPAL_TEST_IN_CHILD_SITE', FALSE);
-  }
-
-  // Initialize the configuration, including variables from settings.php.
-  drupal_settings_initialize();
-  _drupal_request_initialize();
-
-  // Activate the class loader.
-  drupal_classloader();
-
-  // Start a page timer:
-  Timer::start('page');
-
-  // Detect string handling method.
-  Unicode::check();
-
-  // Set the Drupal custom error handler. (requires \Drupal::config())
-  set_error_handler('_drupal_error_handler');
-  set_exception_handler('_drupal_exception_handler');
-
-  // Redirect the user to the installation script if Drupal has not been
-  // installed yet (i.e., if no $databases array has been defined in the
-  // settings.php file) and we are not already installing.
-  if (empty($GLOBALS['databases']) && !drupal_installation_attempted() && !drupal_is_cli()) {
-    include_once __DIR__ . '/install.inc';
-    install_goto('core/install.php');
-  }
-}
-
-/**
- * Initialize the kernel / service container.
- */
-function _drupal_bootstrap_kernel() {
-  // Normally, index.php puts a container in the Drupal class by creating a
-  // kernel. If there is no container yet, create one.
-  if (!\Drupal::getContainer()) {
-    $kernel = new DrupalKernel('prod', drupal_classloader());
-    $kernel->boot();
-    $request = Request::createFromGlobals();
-    \Drupal::getContainer()->set('request', $request);
-  }
-}
-
-/**
- * Attempts to serve a page from the cache.
- */
-function _drupal_bootstrap_page_cache() {
-  global $user;
-
-  require_once __DIR__ . '/database.inc';
-  // Check for a cache mode force from settings.php.
-  if (Settings::get('page_cache_without_database')) {
-    $cache_enabled = TRUE;
-  }
-  else {
-    $config = \Drupal::config('system.performance');
-    $cache_enabled = $config->get('cache.page.use_internal');
-  }
-
-  $request = Request::createFromGlobals();
-  // If there is no session cookie and cache is enabled (or forced), try
-  // to serve a cached page.
-  if (!$request->cookies->has(session_name()) && $cache_enabled) {
-    // Make sure there is a user object because its timestamp will be checked.
-    $user = new AnonymousUserSession();
-    // Get the page from the cache.
-    $cache = drupal_page_get_cache($request);
-    // If there is a cached page, display it.
-    if (is_object($cache)) {
-      $response = new Response();
-      $response->headers->set('X-Drupal-Cache', 'HIT');
-      date_default_timezone_set(drupal_get_user_timezone());
-
-      drupal_serve_page_from_cache($cache, $response, $request);
-
-      // We are done.
-      $response->prepare($request);
-      $response->send();
-      exit;
-    }
-    else {
-      drupal_add_http_header('X-Drupal-Cache', 'MISS');
-    }
-  }
-}
-
-/**
  * Returns the current bootstrap phase for this Drupal process.
  *
  * The current phase is the one most recently completed by drupal_bootstrap().
  *
  * @see drupal_bootstrap()
+ *
+ * @deprecated 8.x
+ *   Use \Drupal\Core\DrupalKernel::getBootLevel().
  */
 function drupal_get_bootstrap_phase() {
-  return drupal_bootstrap();
+  return DrupalKernel::getBootLevel();
 }
 
 /**
@@ -1957,6 +1539,9 @@ function language_default() {
 /**
  * Returns the requested URL path of the page being viewed.
  *
+ * @param \Symfony\Component\HttpFoundation\Request|null $request
+ *   (optional) The request to derive the request path from. Defaults to NULL
+ *
  * Examples:
  * - http://example.com/node/306 returns "node/306".
  * - http://example.com/drupalfolder/node/306 returns "node/306" while
@@ -1970,50 +1555,23 @@ function language_default() {
  *   The requested Drupal URL path.
  *
  * @see current_path()
+ *
+ * @deprecated 8.x
+ *   Use \Drupal\Core\DrupalKernel::requestPath().
  */
-function request_path() {
-  static $path;
-
-  if (isset($path)) {
-    return $path;
-  }
-
-  // Get the part of the URI between the base path of the Drupal installation
-  // and the query string, and unescape it.
-  $request_path = request_uri(TRUE);
-  $base_path_len = strlen(rtrim(dirname($_SERVER['SCRIPT_NAME']), '\/'));
-  $path = substr(urldecode($request_path), $base_path_len + 1);
-
-  // Depending on server configuration, the URI might or might not include the
-  // script name. For example, the front page might be accessed as
-  // http://example.com or as http://example.com/index.php, and the "user"
-  // page might be accessed as http://example.com/user or as
-  // http://example.com/index.php/user. Strip the script name from $path.
-  $script = basename($_SERVER['SCRIPT_NAME']);
-  if ($path == $script) {
-    $path = '';
-  }
-  elseif (strpos($path, $script . '/') === 0) {
-    $path = substr($path, strlen($script) + 1);
-  }
-
-  // Extra slashes can appear in URLs or under some conditions, added by Apache,
-  // so normalize.
-  $path = trim($path, '/');
-
-  return $path;
+function request_path(Request $request = NULL) {
+  return DrupalKernel::requestPath($request);
 }
 
 /**
  * @todo This is a temporary function pending refactoring Drupal to use
  *   Symfony's Request object exclusively.
+ *
+ * @deprecated 8.x
+ *   Use \Drupal\Core\DrupalKernel::currentPath().
  */
 function _current_path($path = NULL) {
-  static $current_path = '';
-  if (isset($path)) {
-    $current_path = $path;
-  }
-  return $current_path;
+  return DrupalKernel::currentPath($path);
 }
 
 /**
diff --git a/core/includes/common.inc b/core/includes/common.inc
index 658c1b6..4d20d02 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -2910,70 +2910,6 @@ function drupal_valid_token($token, $value = '', $skip_anonymous = FALSE) {
 }
 
 /**
- * Loads code for subsystems and modules, and registers stream wrappers.
- */
-function _drupal_bootstrap_code() {
-  require_once __DIR__ . '/../../' . Settings::get('path_inc', 'core/includes/path.inc');
-  require_once __DIR__ . '/module.inc';
-  require_once __DIR__ . '/theme.inc';
-  require_once __DIR__ . '/pager.inc';
-  require_once __DIR__ . '/../../' . Settings::get('menu_inc', 'core/includes/menu.inc');
-  require_once __DIR__ . '/tablesort.inc';
-  require_once __DIR__ . '/file.inc';
-  require_once __DIR__ . '/unicode.inc';
-  require_once __DIR__ . '/form.inc';
-  require_once __DIR__ . '/mail.inc';
-  require_once __DIR__ . '/ajax.inc';
-  require_once __DIR__ . '/errors.inc';
-  require_once __DIR__ . '/schema.inc';
-  require_once __DIR__ . '/entity.inc';
-
-  // Load all enabled modules
-  \Drupal::moduleHandler()->loadAll();
-
-  // Make sure all stream wrappers are registered.
-  file_get_stream_wrappers();
-  // Ensure mt_rand() is reseeded to prevent random values from one page load
-  // being exploited to predict random values in subsequent page loads.
-  $seed = unpack("L", Crypt::randomBytes(4));
-  mt_srand($seed[1]);
-
-  // Set the allowed protocols once we have the config available.
-  $allowed_protocols = \Drupal::config('system.filter')->get('protocols');
-  if (!isset($allowed_protocols)) {
-    // \Drupal\Component\Utility\UrlHelper::filterBadProtocol() is called by the
-    // installer and update.php, in which case the configuration may not exist
-    // (yet). Provide a minimal default set of allowed protocols for these
-    // cases.
-    $allowed_protocols = array('http', 'https');
-  }
-  UrlHelper::setAllowedProtocols($allowed_protocols);
-}
-
-/**
- * Temporary BC function for scripts not using DrupalKernel.
- *
- * DrupalKernel skips this and replicates it via event listeners.
- *
- * @see \Drupal\Core\EventSubscriber\PathSubscriber;
- * @see \Drupal\Core\EventSubscriber\LegacyRequestSubscriber;
- */
-function _drupal_bootstrap_full($skip = FALSE) {
-  static $called = FALSE;
-
-  if ($called || $skip) {
-    $called = TRUE;
-    return;
-  }
-
-  // Let all modules take action before the menu system handles the request.
-  // We do not want this while running update.php.
-  if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
-    drupal_theme_initialize();
-  }
-}
-
-/**
  * Stores the current page in the cache.
  *
  * If page_compression is enabled, a gzipped version of the page is stored in
diff --git a/core/includes/errors.inc b/core/includes/errors.inc
index 1abcdaa..73c5580 100644
--- a/core/includes/errors.inc
+++ b/core/includes/errors.inc
@@ -6,6 +6,7 @@
  */
 
 use Drupal\Component\Utility\Xss;
+use Drupal\Core\DrupalKernel;
 use Drupal\Core\Utility\Error;
 use Drupal\Component\Utility\String;
 use Symfony\Component\HttpFoundation\Response;
@@ -123,7 +124,7 @@ function _drupal_log_error($error, $fatal = FALSE) {
   $is_installer = drupal_installation_attempted();
   // Initialize a maintenance theme if the bootstrap was not complete.
   // Do it early because drupal_set_message() triggers a drupal_theme_initialize().
-  if ($fatal && (drupal_get_bootstrap_phase() != DRUPAL_BOOTSTRAP_FULL)) {
+  if ($fatal && !DrupalKernel::isBootLevelReached(DrupalKernel::BOOTSTRAP_CODE)) {
     // The installer initializes a maintenance theme at the earliest possible
     // point in time already. Do not unset that.
     if (!$is_installer) {
@@ -252,8 +253,8 @@ function _drupal_log_error($error, $fatal = FALSE) {
 /**
  * Returns the current error level.
  *
- * This function should only be used to get the current error level pre
- * DRUPAL_BOOTSTRAP_KERNEL or before Drupal is installed. In all other
+ * This function should only be used to get the current error level prior to
+ * DurpalKernel::BOOTSTRAP_KERNEL or before Drupal is installed. In all other
  * situations the following code is preferred:
  * @code
  * \Drupal::config('system.logging')->get('error_level');
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index aa158a2..f1da46e 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -277,7 +277,7 @@ function install_begin_request(&$install_state) {
   // This primes the site path to be used during installation. By not requiring
   // settings.php, a bare site folder can be prepared in the /sites directory,
   // which will be used for installing Drupal.
-  conf_path(FALSE);
+  conf_path(FALSE, FALSE, $request);
 
   // If the hash salt leaks, it becomes possible to forge a valid testing user
   // agent, install a new copy of Drupal, and take over the original site.
@@ -289,7 +289,7 @@ function install_begin_request(&$install_state) {
     exit;
   }
 
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+  DrupalKernel::bootConfiguration($request);
 
   // Ensure that procedural dependencies are loaded as early as possible,
   // since the error/exception handlers depend on them.
@@ -358,15 +358,8 @@ function install_begin_request(&$install_state) {
     $environment = 'prod';
   }
 
-  $kernel = new DrupalKernel($environment, drupal_classloader(), FALSE);
-  $kernel->boot();
-
-  // Enter the request scope and add the Request.
-  // @todo Remove this after converting all installer screens into controllers.
+  $kernel = DrupalKernel::bootKernel($request, $environment, FALSE);
   $container = $kernel->getContainer();
-  $container->enterScope('request');
-  $container->set('request', $request, 'request');
-  $container->get('request_stack')->push($request);
 
   // Register the file translation service.
   if (isset($GLOBALS['config']['locale.settings']['translation.path'])) {
@@ -1779,7 +1772,6 @@ function install_load_profile(&$install_state) {
  *   An array of information about the current installation state.
  */
 function install_bootstrap_full() {
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
   require_once DRUPAL_ROOT . '/' . Settings::get('session_inc', 'core/includes/session.inc');
   drupal_session_initialize();
 }
diff --git a/core/includes/install.inc b/core/includes/install.inc
index ab818ba..7fa6087 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -633,18 +633,12 @@ function drupal_verify_profile($install_state) {
  *   to set the default language.
  */
 function drupal_install_system($install_state) {
-  // Boot a new kernel into a regular production environment.
-  $request = \Drupal::hasRequest() ? \Drupal::request() : FALSE;
+  // Immediately boot a new kernel into the regular production environment.
+  $request = \Drupal::request();
 
   unset($GLOBALS['conf']['container_service_providers']['InstallerServiceProvider']);
-  $kernel = new DrupalKernel('prod', drupal_classloader(), FALSE);
-  $kernel->boot();
 
-  if ($request) {
-    $kernel->getContainer()->enterScope('request');
-    $kernel->getContainer()->set('request', $request, 'request');
-    $kernel->getContainer()->get('request_stack')->push($request);
-  }
+  $kernel = \Drupal::service('kernel')->reboot($request, 'prod', FALSE);
 
   // Install base system configuration.
   \Drupal::service('config.installer')->installDefaultConfig('core', 'core');
@@ -652,6 +646,15 @@ function drupal_install_system($install_state) {
   // Install System module.
   \Drupal::moduleHandler()->install(array('system'), FALSE);
 
+  // DrupalKernel::reboot() above calls into DrupalKernel::bootCode(), which
+  // primes file_get_stream_wrappers()'s static list of custom stream wrappers
+  // that are based on the currently enabled list of modules (none).
+  // @todo Custom stream wrappers of a new module have to be registered as soon
+  //   as the module is installed/enabled. Fix either ModuleHandler::install()
+  //   and/or DrupalKernel::updateModules().
+  // @see https://drupal.org/node/2028109
+  drupal_static_reset('file_get_stream_wrappers');
+
   // Ensure default language is saved.
   if (isset($install_state['parameters']['langcode'])) {
     \Drupal::config('system.site')
diff --git a/core/includes/module.inc b/core/includes/module.inc
index b5d189c..0594249 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -48,7 +48,7 @@ function system_list($type) {
     // @see http://drupal.org/node/1067408
     $theme_data = \Drupal::state()->get('system.theme.data');
     if (empty($theme_data)) {
-      // @todo: system_list() may be called from _drupal_bootstrap_code(), in
+      // @todo: system_list() may be called from DrupalKernel::bootKernel(), in
       // which case system.module is not loaded yet.
       // Prevent a filesystem scan in drupal_load() and include it directly.
       // @see http://drupal.org/node/1067408
diff --git a/core/includes/path.inc b/core/includes/path.inc
index f60292b..580330d 100644
--- a/core/includes/path.inc
+++ b/core/includes/path.inc
@@ -74,7 +74,7 @@ function drupal_match_path($path, $patterns) {
  * - http://example.com/path/alias (which is a path alias for node/306) returns
  *   "node/306" as opposed to the path alias.
  *
- * This function is available only after DRUPAL_BOOTSTRAP_FULL.
+ * This function is available only after DrupalKernel::BOOTSTRAP_CODE.
  *
  * @return
  *   The current Drupal URL path.
diff --git a/core/includes/schema.inc b/core/includes/schema.inc
index a386e62..5858c7b 100644
--- a/core/includes/schema.inc
+++ b/core/includes/schema.inc
@@ -7,6 +7,7 @@
 
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Database\Database;
+use Drupal\Core\DrupalKernel;
 
 /**
  * @addtogroup schemaapi
@@ -86,7 +87,7 @@ function drupal_get_complete_schema($rebuild = FALSE) {
 
       // If the schema is empty, avoid saving it: some database engines require
       // the schema to perform queries, and this could lead to infinite loops.
-      if (!empty($schema) && (drupal_get_bootstrap_phase() == DRUPAL_BOOTSTRAP_FULL)) {
+      if (!empty($schema) && DrupalKernel::isBootLevelReached(DrupalKernel::BOOTSTRAP_CODE)) {
         \Drupal::cache()->set('schema', $schema, Cache::PERMANENT);
       }
     }
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 52ce316..d0c267a 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -21,6 +21,7 @@
 use Drupal\Core\Theme\ThemeSettings;
 use Drupal\Component\Utility\NestedArray;
 use Drupal\Core\Render\Element;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * @defgroup content_flags Content markers
@@ -88,8 +89,11 @@ function drupal_theme_access($theme) {
 
 /**
  * Initializes the theme system by loading the theme.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ *   The request to initialize the theme for.
  */
-function drupal_theme_initialize() {
+function drupal_theme_initialize(Request $request = NULL) {
   global $theme, $theme_key;
 
   // If $theme is already set, assume the others are set, too, and do nothing
@@ -102,7 +106,9 @@ function drupal_theme_initialize() {
   // @todo Let the theme.negotiator listen to the kernel request event.
   // Determine the active theme for the theme negotiator service. This includes
   // the default theme as well as really specific ones like the ajax base theme.
-  $request = \Drupal::request();
+  if (!$request) {
+    $request = \Drupal::request();
+  }
   $theme = \Drupal::service('theme.negotiator')->determineActiveTheme($request) ?: 'stark';
 
   // Store the identifier for retrieving theme settings with.
diff --git a/core/includes/utility.inc b/core/includes/utility.inc
index 6603166..1f52e36 100644
--- a/core/includes/utility.inc
+++ b/core/includes/utility.inc
@@ -8,6 +8,8 @@
 use Drupal\Component\Utility\Variable;
 use Drupal\Core\PhpStorage\PhpStorageFactory;
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Drupal-friendly var_export().
@@ -30,19 +32,21 @@ function drupal_var_export($var, $prefix = '') {
 /**
  * Rebuilds all caches even when Drupal itself does not work.
  *
- * Requires DRUPAL_BOOTSTRAP_CONFIGURATION.
+ * Requires \Drupal\Core\DrupalKernel::BOOTSTRAP_CONFIGURATION.
+ *
+ * @param \Symfony\Component\HttpFoundation\Request $request
+ *   The current request.
  *
  * @see rebuild.php
  */
-function drupal_rebuild() {
+function drupal_rebuild(Request $request) {
   // Remove Drupal's error and exception handlers; they rely on a working
   // service container and other subsystems and will only cause a fatal error
   // that hides the actual error.
   restore_error_handler();
   restore_exception_handler();
 
-  // drupal_bootstrap(DRUPAL_BOOTSTRAP_KERNEL) will build a new kernel. This
-  // comes before DRUPAL_BOOTSTRAP_PAGE_CACHE.
+  // Force DrupalKernel::bootKernel() to build a new kernel.
   PhpStorageFactory::get('service_container')->deleteAll();
   PhpStorageFactory::get('twig')->deleteAll();
 
@@ -50,16 +54,15 @@ function drupal_rebuild() {
   drupal_page_is_cacheable(FALSE);
 
   // Bootstrap up to where caches exist and clear them.
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_PAGE_CACHE);
+  DrupalKernel::bootKernel($request);
   foreach (Cache::getBins() as $bin) {
     $bin->deleteAll();
   }
 
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
   drupal_flush_all_caches();
 
   // Restore Drupal's error and exception handlers.
-  // @see _drupal_bootstrap_configuration()
+  // @see \Drupal\Core\DrupalKernel::bootConfiguration()
   set_error_handler('_drupal_error_handler');
   set_exception_handler('_drupal_exception_handler');
 }
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index 8812cab..02e9b59 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -7,7 +7,12 @@
 
 namespace Drupal\Core;
 
-use Drupal\Core\PhpStorage\PhpStorageFactory;
+use Drupal\Component\Utility\Crypt;
+use Drupal\Component\Utility\Settings;
+use Drupal\Component\Utility\String;
+use Drupal\Component\Utility\Timer;
+use Drupal\Component\Utility\Unicode;
+use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Config\BootstrapConfigStorageFactory;
 use Drupal\Core\Config\NullStorage;
 use Drupal\Core\CoreServiceProvider;
@@ -16,6 +21,8 @@
 use Drupal\Core\DependencyInjection\YamlFileLoader;
 use Drupal\Core\Extension\ExtensionDiscovery;
 use Drupal\Core\Language\Language;
+use Drupal\Core\PhpStorage\PhpStorageFactory;
+use Drupal\Core\Session\AnonymousUserSession;
 use Symfony\Component\Config\Loader\LoaderInterface;
 use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
 use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
@@ -43,6 +50,70 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
   const CONTAINER_BASE_CLASS = '\Drupal\Core\DependencyInjection\Container';
 
   /**
+   * Pre bootstrap phase: initialize environment based on incoming Request.
+   */
+  const BOOTSTRAP_ENVIRONMENT = 1;
+
+  /**
+   * First bootstrap phase: initialize configuration.
+   */
+  const BOOTSTRAP_CONFIGURATION = 2;
+
+  /**
+   * Third bootstrap phase: try to serve a cached page.
+   */
+  const BOOTSTRAP_PAGE_CACHE = 3;
+
+  /**
+   * Fourth bootstrap phase: load code for subsystems and modules.
+   */
+  const BOOTSTRAP_CODE = 4;
+
+  /**
+   * Current boot level.
+   *
+   * @var int
+   */
+  protected static $bootLevel = NULL;
+
+  /**
+   * Global DrupalKernel singleton.
+   *
+   * @var self
+   */
+  protected static $singleton = FALSE;
+
+  /**
+   * The current request path.
+   *
+   * @var string
+   */
+  protected static $requestPath;
+
+  /**
+   * The current request path.
+   *
+   * @var string
+   */
+  protected static $currentPath = '';
+
+  /**
+   * Whether the environment has been initialized for the request.
+   *
+   * @todo Refactor/remove initializeRequest().
+   *
+   * @var bool
+   */
+  protected static $isRequestInitialized = FALSE;
+
+  /**
+   * The conf path for the given request.
+   *
+   * @var string
+   */
+  protected static $confPath;
+
+  /**
    * Holds the container instance.
    *
    * @var \Symfony\Component\DependencyInjection\ContainerInterface
@@ -148,9 +219,7 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
    * Constructs a DrupalKernel object.
    *
    * @param string $environment
-   *   String indicating the environment, e.g. 'prod' or 'dev'. Used by
-   *   Symfony\Component\HttpKernel\Kernel::__construct(). Drupal does not use
-   *   this value currently. Pass 'prod'.
+   *   String indicating the environment, e.g. 'prod' or 'dev'.
    * @param \Composer\Autoload\ClassLoader $class_loader
    *   (optional) The classloader is only used if $storage is not given or
    *   the load from storage fails and a container rebuild is required. In
@@ -159,12 +228,30 @@ class DrupalKernel implements DrupalKernelInterface, TerminableInterface {
    * @param bool $allow_dumping
    *   (optional) FALSE to stop the container from being written to or read
    *   from disk. Defaults to TRUE.
+   * @param bool $test_only
+   *   (optional) Whether the DrupalKernel object is for testing purposes only.
+   *   Defaults to FALSE.
    */
-  public function __construct($environment, ClassLoader $class_loader, $allow_dumping = TRUE) {
+  public function __construct($environment, ClassLoader $class_loader = NULL, $allow_dumping = TRUE, $test_only = FALSE) {
     $this->environment = $environment;
-    $this->booted = FALSE;
-    $this->classLoader = $class_loader;
     $this->allowDumping = $allow_dumping;
+    $this->testOnly = $test_only;
+    if ($class_loader) {
+      $this->classLoader = $class_loader;
+    }
+    else {
+      $this->classLoader = drupal_classloader();
+    }
+  }
+
+  /**
+   * Sets the classloader.
+   *
+   * @param \Composer\Autoload\ClassLoader $class_loader
+   *   The class loader.
+   */
+  public function setClassLoader(ClassLoader $class_loader) {
+    $this->classLoader = $class_loader;
   }
 
   /**
@@ -190,6 +277,19 @@ public function shutdown() {
     }
     $this->booted = FALSE;
     $this->container = NULL;
+    static::resetSingleton();
+  }
+
+  /**
+   * Resets kernel singleton.
+   */
+  public static function resetSingleton() {
+    // static::$currentPath and static::$requestPath cannot be reset, since
+    // BOOTSTRAP_ENVIRONMENT as well as DrupalKernel::initializeRequest() are
+    // changing global parameters of the PHP process (affecting session handling
+    // and other global state).
+    static::$bootLevel = self::BOOTSTRAP_ENVIRONMENT;
+    static::$singleton = NULL;
   }
 
   /**
@@ -200,7 +300,637 @@ public function getContainer() {
   }
 
   /**
-   * {@inheritdoc}
+   * Sets testOnly property.
+   *
+   * @param bool $test_only
+   *   Whether this is a test only.
+   *
+   * @see core/modules/system/tests/https.php
+   * @see core/modules/system/tests/http.php
+   *
+   * @return $this
+   */
+  public function setTestOnly($test_only) {
+    $this->testOnly = $test_only;
+    return $this;
+  }
+
+  /**
+   * Returns the appropriate configuration directory.
+   *
+   * Returns the configuration path based on the site's hostname, port, and
+   * pathname. Uses find_conf_path() to find the current configuration
+   * directory. See default.settings.php for examples on how the URL is
+   * converted to a directory.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   (optional) The current request. If not passed, defaults to request as
+   *   stored in the container at \Drupal::request().
+   * @param bool $require_settings
+   *   Only configuration directories with an existing settings.php file
+   *   will be recognized. Defaults to TRUE. During initial installation,
+   *   this is set to FALSE so that Drupal can detect a matching directory,
+   *   then create a new settings.php file in it.
+   * @param bool $reset
+   *   Force a full search for matching directories even if one had been
+   *   found previously. Defaults to FALSE.
+   *
+   * @return string
+   *   The path of the matching directory.
+   *
+   * @see default.settings.php
+   */
+  public static function confPath(Request $request = NULL, $require_settings = TRUE, $reset = FALSE) {
+    if (isset(static::$confPath) && !$reset) {
+      return static::$confPath;
+    }
+
+    if (isset($request)) {
+      $request = $request;
+    }
+    // @todo This case cannot be possible. Remove?
+    elseif (\Drupal::hasRequest()) {
+      $request = \Drupal::request();
+    }
+    // @todo Remove once external CLI scripts (Drush) are updated.
+    else {
+      $request = Request::createFromGlobals();
+    }
+
+    // Check for a simpletest override.
+    if ($test_prefix = drupal_valid_test_ua()) {
+      static::$confPath = 'sites/simpletest/' . substr($test_prefix, 10);
+      return static::$confPath;
+    }
+
+    // Otherwise, use the normal $conf_path.
+    $script_name = $request->server->get('SCRIPT_NAME');
+    if (!$script_name) {
+      $script_name = $request->server->get('SCRIPT_FILENAME');
+    }
+    $http_host = $request->server->get('HTTP_HOST');
+    static::$confPath = find_conf_path($http_host, $script_name, $require_settings);
+    return static::$confPath;
+  }
+
+  /**
+   * Bootstraps the environment.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   */
+  public static function bootEnvironment(Request $request) {
+    if (static::$bootLevel >= self::BOOTSTRAP_ENVIRONMENT) {
+      return;
+    }
+
+    // @todo File upstream issue for HeaderBag::getReferer().
+    if (!$request->server->has('HTTP_REFERER')) {
+      $request->server->set('HTTP_REFERER', '');
+    }
+    // @todo File upstream issue to add this validation to Request::create().
+    if (!$request->server->has('SERVER_PROTOCOL') || (!in_array($request->server->get('SERVER_PROTOCOL'), array('HTTP/1.0', 'HTTP/1.1')))) {
+      $request->server->set('SERVER_PROTOCOL', 'HTTP/1.0');
+    }
+
+    // As HTTP_HOST is user input, ensure it only contains characters allowed
+    // in hostnames. See RFC 952 (and RFC 2181).
+    try {
+      $request->getHost();
+    }
+    catch (\UnexpectedValueException $e) {
+      // HTTP_HOST is invalid, e.g. if containing slashes it may be an attack.
+      header($request->server->get('SERVER_PROTOCOL') . ' 400 Bad Request');
+      exit;
+    }
+
+    // @todo Remove this legacy/BC construct.
+    static::currentPath(static::requestPath($request));
+
+    // Enforce E_STRICT, but allow users to set levels not part of E_STRICT.
+    error_reporting(E_STRICT | E_ALL | error_reporting());
+
+    // Override PHP settings required for Drupal to work properly.
+    // sites/default/default.settings.php contains more runtime settings.
+    // The .htaccess file contains settings that cannot be changed at runtime.
+
+    // Use session cookies, not transparent sessions that puts the session id in
+    // the query string.
+    ini_set('session.use_cookies', '1');
+    ini_set('session.use_only_cookies', '1');
+    ini_set('session.use_trans_sid', '0');
+    // Don't send HTTP headers using PHP's session handler.
+    // Send an empty string to disable the cache limiter.
+    ini_set('session.cache_limiter', '');
+    // Use httponly session cookies.
+    ini_set('session.cookie_httponly', '1');
+
+    // Set sane locale settings, to ensure consistent string, dates, times and
+    // numbers handling.
+    setlocale(LC_ALL, 'C');
+
+    // Indicate that code is operating in a test child site.
+    if ($test_prefix = drupal_valid_test_ua()) {
+      // Only code that interfaces directly with tests should rely on this
+      // constant; e.g., the error/exception handler conditionally adds further
+      // error information into HTTP response headers that are consumed by
+      // Simpletest's internal browser.
+      define('DRUPAL_TEST_IN_CHILD_SITE', TRUE);
+
+      // Log fatal errors to the test site directory.
+      ini_set('log_errors', 1);
+      ini_set('error_log', DRUPAL_ROOT . '/sites/simpletest/' . substr($test_prefix, 10) . '/error.log');
+    }
+    else {
+      // Ensure that no other code defines this.
+      define('DRUPAL_TEST_IN_CHILD_SITE', FALSE);
+    }
+
+    // Detect string handling method.
+    Unicode::check();
+
+    static::$bootLevel = self::BOOTSTRAP_ENVIRONMENT;
+  }
+
+  /**
+   * Bootstraps settings.php and the Settings singleton.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   */
+  public static function initializeSettings(Request $request) {
+    // Export these settings.php variables to the global namespace.
+    global $base_url, $databases, $cookie_domain, $config_directories, $config;
+    $settings = array();
+    $config = array();
+
+    // Make conf_path() available as local variable in settings.php.
+    $conf_path = static::confPath($request);
+    if (is_readable(DRUPAL_ROOT . '/' . $conf_path . '/settings.php')) {
+      require DRUPAL_ROOT . '/' . $conf_path . '/settings.php';
+    }
+    // Initialize Settings.
+    new Settings($settings);
+  }
+
+  /**
+   * Bootstraps the legacy global request variables.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   *
+   * @todo D8: Eliminate this entirely in favor of Request object.
+   */
+  public static function initializeRequest(Request $request) {
+    // Provided by settings.php.
+    global $base_url, $cookie_domain;
+    // Set and derived from $base_url by this function.
+    global $base_path, $base_root, $script_path;
+    global $base_secure_url, $base_insecure_url;
+
+    $is_https = $request->isSecure();
+
+    if (isset($base_url)) {
+      // Parse fixed base URL from settings.php.
+      $parts = parse_url($base_url);
+      if (!isset($parts['path'])) {
+        $parts['path'] = '';
+      }
+      $base_path = $parts['path'] . '/';
+      // Build $base_root (everything until first slash after "scheme://").
+      $base_root = substr($base_url, 0, strlen($base_url) - strlen($parts['path']));
+    }
+    else {
+      // Create base URL.
+      $http_protocol = $is_https ? 'https' : 'http';
+      $base_root = $http_protocol . '://' . $request->server->get('HTTP_HOST');
+
+      $base_url = $base_root;
+
+      // For a request URI of '/index.php/foo', $_SERVER['SCRIPT_NAME'] is
+      // '/index.php', whereas $_SERVER['PHP_SELF'] is '/index.php/foo'.
+      if ($dir = rtrim(dirname($request->server->get('SCRIPT_NAME')), '\/')) {
+        // Remove "core" directory if present, allowing install.php, update.php,
+        // and others to auto-detect a base path.
+        $core_position = strrpos($dir, '/core');
+        if ($core_position !== FALSE && strlen($dir) - 5 == $core_position) {
+          $base_path = substr($dir, 0, $core_position);
+        }
+        else {
+          $base_path = $dir;
+        }
+        $base_url .= $base_path;
+        $base_path .= '/';
+      }
+      else {
+        $base_path = '/';
+      }
+    }
+    $base_secure_url = str_replace('http://', 'https://', $base_url);
+    $base_insecure_url = str_replace('https://', 'http://', $base_url);
+
+    // Determine the path of the script relative to the base path, and add a
+    // trailing slash. This is needed for creating URLs to Drupal pages.
+    if (!isset($script_path)) {
+      $script_path = '';
+      // We don't expect scripts outside of the base path, but sanity check
+      // anyway.
+      if (strpos($request->server->get('SCRIPT_NAME'), $base_path) === 0) {
+        $script_path = substr($request->server->get('SCRIPT_NAME'), strlen($base_path)) . '/';
+        // If the request URI does not contain the script name, then clean URLs
+        // are in effect and the script path can be similarly dropped from URL
+        // generation. For servers that don't provide $_SERVER['REQUEST_URI'],
+        // we do not know the actual URI requested by the client, and
+        // request_uri() returns a URI with the script name, resulting in
+        // non-clean URLs unless
+        // there's other code that intervenes.
+        if (strpos(request_uri(TRUE) . '/', $base_path . $script_path) !== 0) {
+          $script_path = '';
+        }
+        // @todo Temporary BC for install.php, update.php, and other scripts.
+        //   - http://drupal.org/node/1547184
+        //   - http://drupal.org/node/1546082
+        if ($script_path !== 'index.php/') {
+          $script_path = '';
+        }
+      }
+    }
+
+    if ($cookie_domain) {
+      // If the user specifies the cookie domain, also use it for session name.
+      $session_name = $cookie_domain;
+    }
+    else {
+      // Otherwise use $base_url as session name, without the protocol
+      // to use the same session identifiers across HTTP and HTTPS.
+      list(, $session_name) = explode('://', $base_url, 2);
+      // HTTP_HOST can be modified by a visitor, but has been sanitized already
+      // in DrupalKernel::bootEnvironment().
+      if ($cookie_domain = $request->server->get('HTTP_HOST')) {
+        // Strip leading periods, www., and port numbers from cookie domain.
+        $cookie_domain = ltrim($cookie_domain, '.');
+        if (strpos($cookie_domain, 'www.') === 0) {
+          $cookie_domain = substr($cookie_domain, 4);
+        }
+        $cookie_domain = explode(':', $cookie_domain);
+        $cookie_domain = '.' . $cookie_domain[0];
+      }
+    }
+    // Per RFC 2109, cookie domains must contain at least one dot other than the
+    // first. For hosts such as 'localhost' or IP Addresses we don't set a
+    // cookie domain.
+    if (count(explode('.', $cookie_domain)) > 2 && !is_numeric(str_replace('.', '', $cookie_domain))) {
+      ini_set('session.cookie_domain', $cookie_domain);
+    }
+    // To prevent session cookies from being hijacked, a user can configure the
+    // SSL version of their website to only transfer session cookies via SSL by
+    // using PHP's session.cookie_secure setting. The browser will then use two
+    // separate session cookies for the HTTPS and HTTP versions of the site. So
+    // we must use different session identifiers for HTTPS and HTTP to prevent a
+    // cookie collision.
+    if ($is_https) {
+      ini_set('session.cookie_secure', TRUE);
+    }
+    $prefix = ini_get('session.cookie_secure') ? 'SSESS' : 'SESS';
+    session_name($prefix . substr(hash('sha256', $session_name), 0, 32));
+  }
+
+  /**
+   * Bootstraps configuration.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   */
+  public static function bootConfiguration(Request $request) {
+    if (static::$bootLevel >= self::BOOTSTRAP_CONFIGURATION) {
+      return;
+    }
+    static::bootEnvironment($request);
+
+    // Initialize the configuration, including variables from settings.php.
+    static::initializeSettings($request);
+
+    // @todo Refactor initializeRequest() to remove this condition. Note:
+    //   All of the globals are legacy and obsolete, but the cookie domain and
+    //   session name setup depends on settings.php and can only be run once.
+    if (!static::$isRequestInitialized) {
+      static::$isRequestInitialized = TRUE;
+      static::initializeRequest($request);
+
+      // Start a page timer:
+      Timer::start('page');
+
+      // Set the Drupal custom error handler.
+      // @todo Move into bootKernel() or remove entirely.
+      set_error_handler('_drupal_error_handler');
+      set_exception_handler('_drupal_exception_handler');
+    }
+
+    // Redirect the user to the installation script if Drupal has not been
+    // installed yet (i.e., if no $databases array has been defined in the
+    // settings.php file) and we are not already installing.
+    if (empty($GLOBALS['databases']) && !drupal_installation_attempted() && !drupal_is_cli()) {
+      include_once DRUPAL_ROOT . '/core/includes/install.inc';
+      install_goto('core/install.php');
+    }
+
+    static::$bootLevel = self::BOOTSTRAP_CONFIGURATION;
+  }
+
+  /**
+   * Attempts to serve a page from the cache.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   *
+   * @return $this
+   */
+  public function bootPageCache(Request $request) {
+    // @todo Use the current_user proxy.
+    global $user;
+
+    // Check for a cache mode force from settings.php.
+    if (Settings::get('page_cache_without_database')) {
+      $cache_enabled = TRUE;
+    }
+    else {
+      $config = $this->container->get('config.factory')->get('system.performance');
+      $cache_enabled = $config->get('cache.page.use_internal');
+    }
+
+    // If there is no session cookie and cache is enabled (or forced), try
+    // to serve a cached page.
+    if (!$request->cookies->has(session_name()) && $cache_enabled) {
+      // Make sure there is a user object because its timestamp will be checked.
+      $user = new AnonymousUserSession();
+      // Get the page from the cache.
+      $cache = drupal_page_get_cache($request);
+      // If there is a cached page, display it.
+      if (is_object($cache)) {
+        $response = new Response();
+        $response->headers->set('X-Drupal-Cache', 'HIT');
+        date_default_timezone_set(drupal_get_user_timezone());
+
+        drupal_serve_page_from_cache($cache, $response, $request);
+
+        // We are done.
+        $response->prepare($request);
+        $response->send();
+        exit;
+      }
+      else {
+        drupal_add_http_header('X-Drupal-Cache', 'MISS');
+      }
+    }
+    return $this;
+  }
+
+  /**
+   * Bootstraps code from include and module files.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   * @param string $environment
+   *   (optional) The environment to bootstrap. Defaults to 'prod'.
+   * @param bool $allow_dumping
+   *   (optional) Allow dumping the container. Defaults to TRUE.
+   *
+   * @return \Drupal\Core\DrupalKernel
+   *   The bootstapped kernel.
+   */
+  public static function bootKernel(Request $request, $environment = 'prod', $allow_dumping = TRUE) {
+    if (static::$bootLevel >= self::BOOTSTRAP_CODE) {
+      return static::$singleton;
+    }
+    static::bootConfiguration($request);
+
+    require_once DRUPAL_ROOT . '/core/includes/common.inc';
+    require_once DRUPAL_ROOT . '/core/includes/database.inc';
+
+    return static::createKernel($request, $environment, $allow_dumping);
+  }
+
+  /**
+   * Performs the actual kernel bootstrap.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   * @param string $environment
+   *   (optional) The environment to bootstrap. Defaults to 'prod'.
+   * @param bool $allow_dumping
+   *   (optional) Allow dumping the container. Defaults to TRUE.
+   *
+   * @return static
+   */
+  public static function createKernel(Request $request, $environment = 'prod', $allow_dumping = TRUE) {
+    // @todo DRUPAL_TEST_IN_CHILD_SITE must not be passed here.
+    //   DrupalKernel::bootConfiguration() negotiates a test request via
+    //   drupal_valid_test_ua() already. This parameter here only exists for the
+    //   http[s].php test front-controllers.
+    $kernel = new static($environment, drupal_classloader(), $allow_dumping, DRUPAL_TEST_IN_CHILD_SITE);
+    static::$singleton = $kernel;
+    $kernel->boot();
+
+    // Enter the request scope so that current_user service is available for
+    // locale/translation sake.
+    $kernel->container->enterScope('request');
+    $kernel->container->set('request', $request);
+    $kernel->container->get('request_stack')->push($request);
+
+    // The page cache may prematurely end the request on a cache hit.
+    // @todo Invoke proper request/response/terminate events.
+    $kernel->bootPageCache($request);
+    static::$bootLevel = self::BOOTSTRAP_PAGE_CACHE;
+
+    $kernel->bootCode();
+    static::$bootLevel = self::BOOTSTRAP_CODE;
+    return $kernel;
+  }
+
+  /**
+   * Reboots the kernel.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   * @param string $environment
+   *   (optional) The environment to bootstrap. Defaults to 'prod'.
+   * @param bool $allow_dumping
+   *   (optional) Allow dumping the container. Defaults to TRUE.
+   *
+   * @return \Drupal\Core\DrupalKernel
+   *   The bootstapped kernel.
+   */
+  public function reboot(Request $request, $environment = 'prod', $allow_dumping = TRUE) {
+    $this->shutdown();
+    static::createKernel($request, $environment, $allow_dumping);
+    return static::$singleton;
+  }
+
+  /**
+   * Finishes booting by loading remaining includes and enabled modules.
+   *
+   * @return $this
+   */
+  public function bootCode() {
+    require_once DRUPAL_ROOT . '/' . Settings::get('path_inc', 'core/includes/path.inc');
+    require_once DRUPAL_ROOT . '/core/includes/module.inc';
+    require_once DRUPAL_ROOT . '/core/includes/theme.inc';
+    require_once DRUPAL_ROOT . '/core/includes/pager.inc';
+    require_once DRUPAL_ROOT . '/' . Settings::get('menu_inc', 'core/includes/menu.inc');
+    require_once DRUPAL_ROOT . '/core/includes/tablesort.inc';
+    require_once DRUPAL_ROOT . '/core/includes/file.inc';
+    require_once DRUPAL_ROOT . '/core/includes/unicode.inc';
+    require_once DRUPAL_ROOT . '/core/includes/form.inc';
+    require_once DRUPAL_ROOT . '/core/includes/mail.inc';
+    require_once DRUPAL_ROOT . '/core/includes/ajax.inc';
+    require_once DRUPAL_ROOT . '/core/includes/errors.inc';
+    require_once DRUPAL_ROOT . '/core/includes/schema.inc';
+    require_once DRUPAL_ROOT . '/core/includes/entity.inc';
+
+    // Load all enabled modules.
+    $this->container->get('module_handler')->loadAll();
+
+    // Make sure all stream wrappers are registered.
+    file_get_stream_wrappers();
+
+    // Ensure mt_rand() is reseeded to prevent random values from one page load
+    // being exploited to predict random values in subsequent page loads.
+    $seed = unpack("L", Crypt::randomBytes(4));
+    mt_srand($seed[1]);
+
+    // Set the allowed protocols once we have the config available.
+    $allowed_protocols = $this->container->get('config.factory')->get('system.filter')->get('protocols');
+    if (!isset($allowed_protocols)) {
+      // \Drupal\Component\Utility\UrlHelper::filterBadProtocol() is called by
+      // the installer and update.php, in which case the configuration may not
+      // exist (yet). Provide a minimal default set of allowed protocols for
+      // these cases.
+      $allowed_protocols = array('http', 'https');
+    }
+    UrlHelper::setAllowedProtocols($allowed_protocols);
+
+    // Back out scope required to initialize the file stream wrappers.
+    if ($this->container->isScopeActive('request')) {
+      $this->container->leaveScope('request');
+    }
+    return $this;
+  }
+
+  /**
+   * Returns the current boot level of the kernel.
+   *
+   * @return int
+   *   The current boot level.
+   *
+   * @see \Drupal\Core\DrupalKernel::$bootLevel
+   */
+  public static function getBootLevel() {
+    return static::$bootLevel;
+  }
+
+  /**
+   * Sets the current boot level of the kernel.
+   *
+   * Internal use only.
+   *
+   * @param int $level
+   *   The boot level to set.
+   *
+   * @internal
+   */
+  public static function setBootLevel($level) {
+    static::$bootLevel = $level;
+  }
+
+  /**
+   * Returns whether a given boot level has been reached.
+   *
+   * @param int $boot_level
+   *   The boot level to check.
+   *
+   * @return bool
+   *   Whether the given $boot_level has been reached.
+   */
+  public static function isBootLevelReached($boot_level) {
+    return static::$bootLevel >= $boot_level;
+  }
+
+  /**
+   * Returns the requested URL path of the page being viewed.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request|NULL $request
+   *   (Optional) The request to derive the request path from. Defaults to NULL
+   *
+   * Examples:
+   * - http://example.com/node/306 returns "node/306".
+   * - http://example.com/drupalfolder/node/306 returns "node/306" while
+   *   base_path() returns "/drupalfolder/".
+   * - http://example.com/path/alias (which is a path alias for node/306)
+   *   returns "path/alias" as opposed to the internal path.
+   * - http://example.com/index.php returns an empty string (meaning: front
+   *   page).
+   * - http://example.com/index.php?page=1 returns an empty string.
+   *
+   * @return string
+   *   The requested Drupal URL path.
+   */
+  public static function requestPath(Request $request = NULL) {
+    if (isset(static::$requestPath)) {
+      return static::$requestPath;
+    }
+    if (!$request) {
+      // @todo Do we even need this?
+      $request = \Drupal::request();
+    }
+
+    // Get the part of the URI between the base path of the Drupal installation
+    // and the query string, and unescape it.
+    $request_path = request_uri(TRUE);
+    $base_path_len = strlen(rtrim(dirname($request->server->get('SCRIPT_NAME')), '\/'));
+    static::$requestPath = substr(urldecode($request_path), $base_path_len + 1);
+
+    // Depending on server configuration, the URI might or might not include the
+    // script name. For example, the front page might be accessed as
+    // http://example.com or as http://example.com/index.php, and the "user"
+    // page might be accessed as http://example.com/user or as
+    // http://example.com/index.php/user. Strip the script name from $path.
+    $script = basename($request->server->get('SCRIPT_NAME'));
+    if (static::$requestPath == $script) {
+      static::$requestPath = '';
+    }
+    elseif (strpos(static::$requestPath, $script . '/') === 0) {
+      static::$requestPath = substr(static::$requestPath, strlen($script) + 1);
+    }
+
+    // Extra slashes can appear in URLs or under some conditions, added by
+    // Apache so normalize.
+    static::$requestPath = trim(static::$requestPath, '/');
+
+    return static::$requestPath;
+  }
+
+  /**
+   * Sets or returns the current request path.
+   *
+   * @param string $path
+   *   (optional) Path to set as the current path. If NULL, returns the current
+   *   path. Defaults to NULL.
+   *
+   * @return string
+   *   The current path.
+   */
+  public static function currentPath($path = NULL) {
+    if (isset($path)) {
+      self::$currentPath = $path;
+    }
+    return self::$currentPath;
+  }
+
+  /**
+   * Returns an array of available bundles.
+   *
+   * @return array
+   *   The available bundles.
    */
   public function discoverServiceProviders() {
     $serviceProviders = array(
@@ -273,9 +1003,11 @@ public function terminate(Request $request, Response $response) {
   /**
    * {@inheritdoc}
    */
-  public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = TRUE) {
-    if (FALSE === $this->booted) {
-      $this->boot();
+  public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = TRUE) {
+    // Exit if we should be in a test environment but aren't.
+    if ($this->testOnly && !drupal_valid_test_ua()) {
+      header($request->server->get('SERVER_PROTOCOL') . ' 403 Forbidden');
+      exit;
     }
 
     return $this->getHttpKernel()->handle($request, $type, $catch);
@@ -611,7 +1343,7 @@ protected function dumpDrupalContainer(ContainerBuilder $container, $baseClass)
   /**
    * Gets a http kernel from the container
    *
-   * @return HttpKernel
+   * @return \Symfony\Component\HttpKernel\HttpKernelInterface
    */
   protected function getHttpKernel() {
     return $this->container->get('http_kernel');
diff --git a/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php
deleted file mode 100644
index aa7774e..0000000
--- a/core/lib/Drupal/Core/EventSubscriber/LegacyRequestSubscriber.php
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-
-/**
- * @file
- * Definition of Drupal\Core\EventSubscriber\LegacyRequestSubscriber.
- */
-
-namespace Drupal\Core\EventSubscriber;
-
-use Symfony\Component\HttpKernel\HttpKernelInterface;
-use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\HttpKernel\Event\GetResponseEvent;
-use Symfony\Component\EventDispatcher\EventSubscriberInterface;
-
-/**
- * KernelEvents::REQUEST event subscriber to initialize theme and modules.
- *
- * @todo Remove this subscriber when all of the code in it has been refactored.
- */
-class LegacyRequestSubscriber implements EventSubscriberInterface {
-
-  /**
-   * Initializes the rest of the legacy Drupal subsystems.
-   *
-   * @param Symfony\Component\HttpKernel\Event\GetResponseEvent $event
-   *   The Event to process.
-   */
-  public function onKernelRequestLegacy(GetResponseEvent $event) {
-    if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
-      // Tell Drupal it is now fully bootstrapped (for the benefit of code that
-      // calls drupal_get_bootstrap_phase()), but without having
-      // _drupal_bootstrap_full() do anything, since we've already done the
-      // equivalent above and in earlier listeners.
-      _drupal_bootstrap_full(TRUE);
-      drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
-    }
-  }
-
-  /**
-   * Initializes the theme system after the routing system.
-   *
-   * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
-   *   The Event to process.
-   */
-  public function onKernelRequestLegacyAfterRouting(GetResponseEvent $event) {
-    if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
-      drupal_theme_initialize();
-    }
-  }
-
-  /**
-   * Registers the methods in this class that should be listeners.
-   *
-   * @return array
-   *   An array of event listener definitions.
-   */
-  static function getSubscribedEvents() {
-    $events[KernelEvents::REQUEST][] = array('onKernelRequestLegacy', 90);
-    // Initialize the theme system after the routing system.
-    $events[KernelEvents::REQUEST][] = array('onKernelRequestLegacyAfterRouting', 30);
-
-    return $events;
-  }
-}
diff --git a/core/lib/Drupal/Core/EventSubscriber/ThemeNegotiatorRequestSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/ThemeNegotiatorRequestSubscriber.php
new file mode 100644
index 0000000..52c115a
--- /dev/null
+++ b/core/lib/Drupal/Core/EventSubscriber/ThemeNegotiatorRequestSubscriber.php
@@ -0,0 +1,65 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\EventSubscriber\ThemeNegotiatorRequestSubscriber.
+ */
+
+namespace Drupal\Core\EventSubscriber;
+
+use Drupal\Core\Theme\ThemeNegotiatorInterface;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+
+/**
+ * Initializes the theme for the current request.
+ */
+class ThemeNegotiatorRequestSubscriber implements EventSubscriberInterface {
+
+  /**
+   * The theme negotiator service.
+   *
+   * @var \Drupal\Core\Theme\ThemeNegotiatorInterface
+   */
+  protected $themeNegotiator;
+
+  /**
+   * Constructs a ThemeNegotiatorRequestSubscriber object.
+   *
+   * @param \Drupal\Core\Theme\ThemeNegotiatorInterface $theme_negotiator
+   *   The theme negotiator service.
+   */
+  public function __construct(ThemeNegotiatorInterface $theme_negotiator) {
+    $this->themeNegotiator = $theme_negotiator;
+  }
+
+  /**
+   * Initializes the theme system after the routing system.
+   *
+   * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
+   *   The Event to process.
+   */
+  public function onKernelRequestThemeNegotiator(GetResponseEvent $event) {
+    if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) {
+      if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
+        // @todo Refactor drupal_theme_initialize() into a request subscriber.
+        // @see https://drupal.org/node/2228093
+        drupal_theme_initialize($event->getRequest());
+      }
+    }
+  }
+
+  /**
+   * Registers the methods in this class that should be listeners.
+   *
+   * @return array
+   *   An array of event listener definitions.
+   */
+  public static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('onKernelRequestThemeNegotiator', 29);
+    return $events;
+  }
+
+}
diff --git a/core/modules/dblog/lib/Drupal/dblog/Tests/DbLogTest.php b/core/modules/dblog/lib/Drupal/dblog/Tests/DbLogTest.php
index 850b6e1..32d0489 100644
--- a/core/modules/dblog/lib/Drupal/dblog/Tests/DbLogTest.php
+++ b/core/modules/dblog/lib/Drupal/dblog/Tests/DbLogTest.php
@@ -138,7 +138,7 @@ private function generateLogEntries($count, $type = 'custom', $severity = WATCHD
       'user'        => $this->big_user,
       'uid'         => $this->big_user->id(),
       'request_uri' => $base_root . request_uri(),
-      'referer'     => $_SERVER['HTTP_REFERER'],
+      'referer'     => \Drupal::request()->server->get('HTTP_REFERER'),
       'ip'          => '127.0.0.1',
       'timestamp'   => REQUEST_TIME,
       );
@@ -421,7 +421,7 @@ protected function testDBLogAddAndClear() {
       'user'        => $this->big_user,
       'uid'         => $this->big_user->id(),
       'request_uri' => $base_root . request_uri(),
-      'referer'     => $_SERVER['HTTP_REFERER'],
+      'referer'     => \Drupal::request()->server->get('HTTP_REFERER'),
       'ip'          => '127.0.0.1',
       'timestamp'   => REQUEST_TIME,
     );
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php
index 36adb8b..40acafe 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/DrupalUnitTestBase.php
@@ -139,9 +139,11 @@ protected function setUp() {
     \Drupal::state()->set('system.theme.files', $this->themeFiles);
 
     // Bootstrap the kernel.
-    // No need to dump it; this test runs in-memory.
-    $this->kernel = new DrupalKernel('unit_testing', drupal_classloader(), FALSE);
-    $this->kernel->boot();
+    // Since there is no settings.php, the BOOTSTRAP_CONFIGURATION phase has to
+    // be skipped, since Settings would be reset to be empty otherwise.
+    DrupalKernel::setBootLevel(DrupalKernel::BOOTSTRAP_CONFIGURATION);
+    $request = Request::create('/');
+    $this->kernel = DrupalKernel::bootKernel($request, 'testing', FALSE);
 
     // Create a minimal core.extension configuration object so that the list of
     // enabled modules can be maintained allowing
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/InstallerTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/InstallerTestBase.php
index ffcef7a..08dbab9 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/InstallerTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/InstallerTestBase.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\simpletest;
 
+use Drupal\Core\DrupalKernel;
 use Drupal\Core\Session\UserSession;
 
 /**
@@ -109,7 +110,7 @@ protected function setUp() {
     $this->setUpSite();
 
     // Import new settings.php written by the installer.
-    drupal_settings_initialize();
+    DrupalKernel::initializeSettings($this->container->get('request'));
     foreach ($GLOBALS['config_directories'] as $type => $path) {
       $this->configDirectories[$type] = $path;
     }
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
index e19169f..a4e5ce4 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
@@ -653,7 +653,7 @@ protected function assertIdenticalObject($object1, $object2, $message = '', $gro
    *   TRUE if the assertion succeeded, FALSE otherwise.
    *
    * @see TestBase::prepareEnvironment()
-   * @see _drupal_bootstrap_configuration()
+   * @see \Drupal\Core\DrupalKernel::bootConfiguration()
    */
   protected function assertNoErrorsLogged() {
     // Since PHP only creates the error.log file when an actual error is
@@ -1109,6 +1109,7 @@ private function prepareEnvironment() {
 
     // After preparing the environment and changing the database prefix, we are
     // in a valid test environment.
+    DrupalKernel::resetSingleton();
     drupal_valid_test_ua($this->databasePrefix);
     conf_path(FALSE, TRUE);
 
@@ -1139,27 +1140,15 @@ private function prepareEnvironment() {
    */
   protected function rebuildContainer($environment = 'testing') {
     // Preserve the request object after the container rebuild.
+    // @todo SessionManager requires the request stack to persist, too.
+    // @see https://drupal.org/node/2228341
     $request = \Drupal::request();
-    // When called from InstallerTestBase, the current container is the minimal
-    // container from TestBase::prepareEnvironment(), which does not contain a
-    // request stack.
-    if (\Drupal::getContainer()->initialized('request_stack')) {
-      $request_stack = \Drupal::service('request_stack');
-    }
 
-    $this->kernel = new DrupalKernel($environment, drupal_classloader(), FALSE);
-    $this->kernel->boot();
+    $this->kernel = DrupalKernel::createKernel($request, $environment, FALSE);
     // DrupalKernel replaces the container in \Drupal::getContainer() with a
     // different object, so we need to replace the instance on this test class.
     $this->container = \Drupal::getContainer();
-    // The current user is set in TestBase::prepareEnvironment().
-    $this->container->set('request', $request);
-    if (isset($request_stack)) {
-      $this->container->set('request_stack', $request_stack);
-    }
-    else {
-      $this->container->get('request_stack')->push($request);
-    }
+
     $this->container->get('current_user')->setAccount(\Drupal::currentUser());
   }
 
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
index 3383391..197cb18 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php
@@ -171,6 +171,8 @@
 
   /**
    * The kernel used in this test.
+   *
+   * @var \Drupal\Core\DrupalKernel
    */
   protected $kernel;
 
@@ -801,17 +803,11 @@ protected function setUp() {
     );
     $this->writeSettings($settings);
 
-    // Since Drupal is bootstrapped already, install_begin_request() will not
-    // bootstrap into DRUPAL_BOOTSTRAP_CONFIGURATION (again). Hence, we have to
-    // reload the newly written custom settings.php manually.
-    drupal_settings_initialize();
-
     // Execute the non-interactive installer.
     require_once DRUPAL_ROOT . '/core/includes/install.core.inc';
     install_drupal($parameters);
 
     // Import new settings.php written by the installer.
-    drupal_settings_initialize();
     foreach ($GLOBALS['config_directories'] as $type => $path) {
       $this->configDirectories[$type] = $path;
     }
@@ -865,14 +861,11 @@ protected function setUp() {
       $this->rebuildContainer();
     }
 
-    // Like DRUPAL_BOOTSTRAP_CONFIGURATION above, any further bootstrap phases
-    // are not re-executed by the installer, as Drupal is bootstrapped already.
     // Reset/rebuild all data structures after enabling the modules, primarily
     // to synchronize all data structures and caches between the test runner and
     // the child site.
     // Affects e.g. file_get_stream_wrappers().
-    // @see _drupal_bootstrap_code()
-    // @see _drupal_bootstrap_full()
+    // @see \Drupal\Core\DrupalKernel::bootKernel()
     // @todo Test-specific setUp() methods may set up further fixtures; find a
     //   way to execute this after setUp() is done, or to eliminate it entirely.
     $this->resetAll();
@@ -1332,7 +1325,7 @@ protected function curlClose() {
    *   TRUE if this test was instantiated in a request within the test site,
    *   FALSE otherwise.
    *
-   * @see _drupal_bootstrap_configuration()
+   * @see \Drupal\Core\DrupalKernel::bootConfiguration()
    */
   protected function isInChildSite() {
     return DRUPAL_TEST_IN_CHILD_SITE;
diff --git a/core/modules/statistics/statistics.php b/core/modules/statistics/statistics.php
index 85864e1..a79d9ef 100644
--- a/core/modules/statistics/statistics.php
+++ b/core/modules/statistics/statistics.php
@@ -5,13 +5,15 @@
  * Handles counts of node views via AJAX with minimal bootstrap.
  */
 
-// Change the directory to the Drupal root.
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
+
 chdir('../../..');
 
-// Load the Drupal bootstrap.
 require_once dirname(dirname(__DIR__)) . '/vendor/autoload.php';
 require_once dirname(dirname(__DIR__)) . '/includes/bootstrap.inc';
-drupal_bootstrap(DRUPAL_BOOTSTRAP_KERNEL);
+
+DrupalKernel::bootKernel(Request::createFromGlobals());
 
 if (\Drupal::config('statistics.settings')->get('count_content_views')) {
   $nid = filter_input(INPUT_POST, 'nid', FILTER_VALIDATE_INT);
diff --git a/core/modules/system/tests/http.php b/core/modules/system/tests/http.php
index 662031f..15e7414 100644
--- a/core/modules/system/tests/http.php
+++ b/core/modules/system/tests/http.php
@@ -5,19 +5,27 @@
  * Fake an HTTP request, for use during testing.
  */
 
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
+
+chdir('../../../..');
+
+require_once './core/vendor/autoload.php';
+require_once './core/includes/bootstrap.inc';
+
 // Set a global variable to indicate a mock HTTP request.
 $is_http_mock = !empty($_SERVER['HTTPS']);
 
 // Change to HTTP.
 $_SERVER['HTTPS'] = NULL;
 ini_set('session.cookie_secure', FALSE);
-foreach ($_SERVER as $key => $value) {
-  $_SERVER[$key] = str_replace('core/modules/system/tests/http.php', 'index.php', $value);
-  $_SERVER[$key] = str_replace('https://', 'http://', $_SERVER[$key]);
+foreach ($_SERVER as &$value) {
+  $value = str_replace('core/modules/system/tests/http.php', 'index.php', $value);
+  $value = str_replace('https://', 'http://', $value);
 }
 
-// Change current directory to the Drupal root.
-chdir('../../../..');
-require_once dirname(dirname(dirname(__DIR__))) . '/vendor/autoload.php';
-require_once dirname(dirname(dirname(__DIR__))) . '/includes/bootstrap.inc';
-drupal_handle_request(TRUE);
+$request = Request::createFromGlobals();
+$kernel = DrupalKernel::bootKernel($request);
+$kernel->setTestOnly(TRUE);
+$response = $kernel->handle($request)->prepare($request)->send();
+$kernel->terminate($request, $response);
diff --git a/core/modules/system/tests/https.php b/core/modules/system/tests/https.php
index 247e6e5..97aee40 100644
--- a/core/modules/system/tests/https.php
+++ b/core/modules/system/tests/https.php
@@ -8,18 +8,26 @@
  *   see http.php.
  */
 
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
+
+chdir('../../../..');
+
+require_once './core/vendor/autoload.php';
+require_once './core/includes/bootstrap.inc';
+
 // Set a global variable to indicate a mock HTTPS request.
 $is_https_mock = empty($_SERVER['HTTPS']);
 
 // Change to HTTPS.
 $_SERVER['HTTPS'] = 'on';
-foreach ($_SERVER as $key => $value) {
-  $_SERVER[$key] = str_replace('core/modules/system/tests/https.php', 'index.php', $value);
-  $_SERVER[$key] = str_replace('http://', 'https://', $_SERVER[$key]);
+foreach ($_SERVER as &$value) {
+  $value = str_replace('core/modules/system/tests/https.php', 'index.php', $value);
+  $value = str_replace('http://', 'https://', $value);
 }
 
-// Change current directory to the Drupal root.
-chdir('../../../..');
-require_once dirname(dirname(dirname(__DIR__))) . '/vendor/autoload.php';
-require_once dirname(dirname(dirname(__DIR__))) . '/includes/bootstrap.inc';
-drupal_handle_request(TRUE);
+$request = Request::createFromGlobals();
+$kernel = DrupalKernel::bootKernel($request);
+$kernel->setTestOnly(TRUE);
+$response = $kernel->handle($request)->prepare($request)->send();
+$kernel->terminate($request, $response);
diff --git a/core/modules/toolbar/toolbar.module b/core/modules/toolbar/toolbar.module
index 0f58cb2..0ed220b 100644
--- a/core/modules/toolbar/toolbar.module
+++ b/core/modules/toolbar/toolbar.module
@@ -108,7 +108,7 @@ function toolbar_element_info() {
  * Use Drupal's page cache for toolbar/subtrees/*, even for authenticated users.
  *
  * This gets invoked after full bootstrap, so must duplicate some of what's
- * done by _drupal_bootstrap_page_cache().
+ * done by \Drupal\Core\DrupalKernel::bootPageCache().
  *
  * @todo Replace this hack with something better integrated with DrupalKernel
  *   once Drupal's page caching itself is properly integrated.
@@ -118,7 +118,7 @@ function _toolbar_initialize_page_cache() {
   drupal_page_is_cacheable(TRUE);
 
   // If we have a cache, serve it.
-  // @see _drupal_bootstrap_page_cache()
+  // @see \Drupal\Core\DrupalKernel::bootPageCache()
   $request = \Drupal::request();
   $cache = drupal_page_get_cache($request);
   if (is_object($cache)) {
diff --git a/core/rebuild.php b/core/rebuild.php
index 382387c..039e197 100644
--- a/core/rebuild.php
+++ b/core/rebuild.php
@@ -12,6 +12,8 @@
 
 use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\Settings;
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
 
 // Change the directory to the Drupal root.
 chdir('..');
@@ -20,7 +22,8 @@
 require_once __DIR__ . '/includes/bootstrap.inc';
 require_once __DIR__ . '/includes/utility.inc';
 
-drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+$request = Request::createFromGlobals();
+DrupalKernel::bootConfiguration($request);
 
 if (Settings::get('rebuild_access', FALSE) ||
   (isset($_GET['token'], $_GET['timestamp']) &&
@@ -28,7 +31,7 @@
     ($_GET['token'] === Crypt::hmacBase64($_GET['timestamp'], Settings::get('hash_salt')))
   )) {
 
-  drupal_rebuild();
+  drupal_rebuild($request);
   drupal_set_message('Cache rebuild complete.');
 }
 
diff --git a/core/scripts/password-hash.sh b/core/scripts/password-hash.sh
index 8c6ebb1..3c15471 100755
--- a/core/scripts/password-hash.sh
+++ b/core/scripts/password-hash.sh
@@ -12,6 +12,9 @@
  *  Plain-text passwords in quotes (or with spaces backslash escaped).
  */
 
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
+
 if (version_compare(PHP_VERSION, "5.2.0", "<")) {
   $version  = PHP_VERSION;
   echo <<<EOF
@@ -82,10 +85,10 @@
 require_once $core . '/vendor/autoload.php';
 require_once $core . '/includes/bootstrap.inc';
 
-// Bootstrap the code so we have the container.
-drupal_bootstrap(DRUPAL_BOOTSTRAP_CODE);
+$request = Request::createFromGlobals();
+$kernel = DrupalKernel::bootKernel($request);
 
-$password_hasher = \Drupal::service('password');
+$password_hasher = $kernel->getContainer()->get('password');
 
 foreach ($passwords as $password) {
   print("\npassword: $password \t\thash: ". $password_hasher->hash($password) ."\n");
diff --git a/core/scripts/rebuild_token_calculator.sh b/core/scripts/rebuild_token_calculator.sh
index c206e0b..864b0cd 100755
--- a/core/scripts/rebuild_token_calculator.sh
+++ b/core/scripts/rebuild_token_calculator.sh
@@ -1,5 +1,4 @@
 #!/usr/bin/env php
-
 <?php
 
 /**
@@ -7,17 +6,19 @@
  * Command line token calculator for rebuild.php.
  */
 
-require_once __DIR__ . '/../vendor/autoload.php';
-require_once dirname(__DIR__) . '/includes/bootstrap.inc';
-
 use Drupal\Component\Utility\Crypt;
 use Drupal\Component\Utility\Settings;
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
 
-drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+require_once __DIR__ . '/../vendor/autoload.php';
+require_once dirname(__DIR__) . '/includes/bootstrap.inc';
 
 if (!drupal_is_cli()) {
   exit;
 }
+$request = Request::createFromGlobals();
+DrupalKernel::bootConfiguration($request);
 
 $timestamp = time();
 $token = Crypt::hmacBase64($timestamp, Settings::get('hash_salt'));
diff --git a/core/scripts/run-tests.sh b/core/scripts/run-tests.sh
index 1f09534..036b2af 100755
--- a/core/scripts/run-tests.sh
+++ b/core/scripts/run-tests.sh
@@ -365,7 +365,8 @@ function simpletest_script_bootstrap() {
   // Replace services with in-memory and null implementations.
   $GLOBALS['conf']['container_service_providers']['InstallerServiceProvider'] = 'Drupal\Core\Installer\InstallerServiceProvider';
 
-  drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
+  $request = Request::createFromGlobals();
+  DrupalKernel::bootConfiguration($request);
 
   // Remove Drupal's error/exception handlers; they are designed for HTML
   // and there is no storage nor a (watchdog) logger here.
@@ -382,10 +383,8 @@ function simpletest_script_bootstrap() {
     ));
   }
 
-  $kernel = new DrupalKernel('testing', drupal_classloader(), FALSE);
-  $kernel->boot();
+  $kernel = DrupalKernel::bootKernel($request, 'testing', FALSE);
 
-  $request = Request::createFromGlobals();
   $container = $kernel->getContainer();
   $container->enterScope('request');
   $container->set('request', $request, 'request');
diff --git a/core/tests/bootstrap.php b/core/tests/bootstrap.php
index c69a52f..9f24891 100644
--- a/core/tests/bootstrap.php
+++ b/core/tests/bootstrap.php
@@ -86,7 +86,7 @@ function drupal_phpunit_register_extension_dirs(Composer\Autoload\ClassLoader $l
 
 // Set sane locale settings, to ensure consistent string, dates, times and
 // numbers handling.
-// @see drupal_environment_initialize()
+// @see \Drupal\Core\DrupalKernel::bootEnvironment()
 setlocale(LC_ALL, 'C');
 
 // Set the default timezone. While this doesn't cause any tests to fail, PHP
diff --git a/core/update.php b/core/update.php
index 45904a2..dc440fe 100644
--- a/core/update.php
+++ b/core/update.php
@@ -309,12 +309,11 @@ function update_task_list($active = NULL) {
 require_once __DIR__ . '/includes/unicode.inc';
 require_once __DIR__ . '/includes/install.inc';
 require_once __DIR__ . '/includes/schema.inc';
-// Bootstrap to configuration.
-drupal_bootstrap(DRUPAL_BOOTSTRAP_CONFIGURATION);
-
-// Bootstrap the database.
 require_once __DIR__ . '/includes/database.inc';
 
+$request = Request::createFromGlobals();
+DrupalKernel::bootConfiguration($request);
+
 // Updating from a site schema version prior to 8000 should block the update
 // process. Ensure that the site is not attempting to update a database
 // created in a previous version of Drupal.
@@ -331,22 +330,9 @@ function update_task_list($active = NULL) {
 $GLOBALS['conf']['container_service_providers']['UpdateServiceProvider'] = 'Drupal\Core\DependencyInjection\UpdateServiceProvider';
 $GLOBALS['conf']['update_service_provider_overrides'] = TRUE;
 
-// module.inc is not yet loaded but there are calls to module_config_sort()
-// below.
-require_once __DIR__ . '/includes/module.inc';
-
-$settings = Settings::getAll();
-new Settings($settings);
-$kernel = new DrupalKernel('update', drupal_classloader(), FALSE);
-$kernel->boot();
-$request = Request::createFromGlobals();
-$container = \Drupal::getContainer();
-$container->set('request', $request);
-$container->get('request_stack')->push($request);
+$kernel = DrupalKernel::bootKernel($request, 'update', FALSE);
 
 // Determine if the current user has access to run update.php.
-drupal_bootstrap(DRUPAL_BOOTSTRAP_PAGE_CACHE);
-
 require_once DRUPAL_ROOT . '/' . Settings::get('session_inc', 'core/includes/session.inc');
 drupal_session_initialize();
 
@@ -384,7 +370,6 @@ function update_task_list($active = NULL) {
   install_goto('core/update.php?op=info');
 }
 
-drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
 drupal_maintenance_theme();
 
 // Turn error reporting back on. From now on, only fatal errors (which are
diff --git a/index.php b/index.php
index 4916a6c..7eec1c0 100644
--- a/index.php
+++ b/index.php
@@ -8,11 +8,17 @@
  * See COPYRIGHT.txt and LICENSE.txt files in the "core" directory.
  */
 
+use Drupal\Core\DrupalKernel;
+use Symfony\Component\HttpFoundation\Request;
+
 require_once __DIR__ . '/core/vendor/autoload.php';
 require_once __DIR__ . '/core/includes/bootstrap.inc';
 
 try {
-  drupal_handle_request();
+  $request = Request::createFromGlobals();
+  $kernel = DrupalKernel::bootKernel($request);
+  $response = $kernel->handle($request)->prepare($request)->send();
+  $kernel->terminate($request, $response);
 }
 catch (Exception $e) {
   $message = 'If you have just changed code (for example deployed a new module or moved an existing one) read <a href="http://drupal.org/documentation/rebuild">http://drupal.org/documentation/rebuild</a>';
