diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 0a68d25..a3a0f46 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -595,6 +595,9 @@ function drupal_override_server_variables($variables = array()) {
  * Initializes the PHP environment.
  */
 function drupal_environment_initialize() {
+  // Make sure the \Drupal class is available.
+  require_once DRUPAL_ROOT . '/core/lib/Drupal.php';
+
   if (!isset($_SERVER['HTTP_REFERER'])) {
     $_SERVER['HTTP_REFERER'] = '';
   }
@@ -982,17 +985,18 @@ function variable_initialize($conf = array()) {
   else {
     // Cache miss. Avoid a stampede.
     $name = 'variable_init';
-    if (!lock()->acquire($name, 1)) {
+    $lock = Drupal::lock();
+    if (!$lock->acquire($name, 1)) {
       // Another request is building the variable cache.
       // Wait, then re-run this function.
-      lock()->wait($name);
+      $lock->wait($name);
       return variable_initialize($conf);
     }
     else {
       // Proceed with variable rebuild.
       $variables = array_map('unserialize', db_query('SELECT name, value FROM {variable}')->fetchAllKeyed());
       cache('bootstrap')->set('variables', $variables);
-      lock()->release($name);
+      $lock->release($name);
     }
   }
 
@@ -2424,29 +2428,15 @@ function drupal_get_bootstrap_phase() {
 /**
  * Retrieves the Drupal Container to standardize object construction.
  *
- * The container is built by the kernel and passed in to this function which
- * stores it statically. The container always contains the services from
- * \Drupal\Core\CoreBundle, the bundles of enabled modules and any other
- * bundles defined in $GLOBALS['conf']['container_bundles'].
- *
- * @see Drupal\Core\DrupalKernel
- *
- * @param Symfony\Component\DependencyInjection\ContainerInterface $new_container
- *   (optional) A new container instance to replace the current.
+ * @deprecated This function has been replaced by the \Drupal class. Use that
+ *   instead.
  *
  * @return Symfony\Component\DependencyInjection\ContainerInterface|bool
  *   The instance of the ContainerInterface used to set up and maintain
  *   object instances or FALSE if none exist yet.
  */
-function drupal_container(ContainerInterface $new_container = NULL) {
-  // We do not use drupal_static() here because we do not have a mechanism by
-  // which to reinitialize the stored objects, so a drupal_static_reset() call
-  // would leave Drupal in a nonfunctional state.
-  static $container;
-  if (isset($new_container)) {
-    $container = $new_container;
-  }
-  return $container;
+function drupal_container() {
+  return Drupal::getContainer();
 }
 
 /**
@@ -3542,10 +3532,13 @@ function drupal_check_memory_limit($required, $memory_limit = NULL) {
 /**
  * Get locking layer instance.
  *
+ * @deprecated Use Drupal::lock() instead, or even better have the lock service
+ *   injected into your object.
+ *
  * @return Drupal\Core\Lock\LockBackendInterface
  */
 function lock() {
-  return drupal_container()->get('lock');
+  return Drupal::lock();
 }
 
 /**
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index 44e5a85..e2e8c27 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -374,7 +374,7 @@ function install_begin_request(&$install_state) {
       ))
       ->addMethodCall('setUserAgent', array('Drupal (+http://drupal.org/)'));
 
-    drupal_container($container);
+    Drupal::setContainer($container);
   }
 
   // Set up $language, so t() caller functions will still work.
diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php
new file mode 100644
index 0000000..5b0b502
--- /dev/null
+++ b/core/lib/Drupal.php
@@ -0,0 +1,143 @@
+<?php
+
+/**
+ * @file
+ * Contains Drupal.
+ */
+
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Static Service Container wrapper.
+ *
+ * Generally, code in Drupal should accept its dependencies via either
+ * constructor injection or setter method injection. However, there are cases,
+ * particularly in legacy procedural code, where that is infeasible. This
+ * class acts as a unified global accessor to arbitrary services within the
+ * system in order to ease the transition from procedural code to injected OO
+ * code.
+ *
+ * The container is built by the kernel and passed in to this class which stores
+ * it statically. The container always contains the services from
+ * \Drupal\Core\CoreBundle, the bundles of enabled modules and any other bundles
+ * defined in $GLOBALS['conf']['container_bundles'].
+ *
+ * This class exists only to support legacy code that cannot be dependency
+ * injected. If your code needs it, consider refactoring it to be object
+ * oriented, if possible. When this is not possible, for instance in the case of
+ * hook implementations, and your code is more than a few non-reusable lines, it
+ * is recommended to instantiate an object implementing the actual logic.
+ *
+ * @code
+ *   // Legacy procedural code.
+ *   function hook_do_stuff() {
+ *     $lock = lock()->acquire('stuff_lock');
+ *     // ...
+ *   }
+ *
+ *   // Correct procedural code.
+ *   function hook_do_stuff() {
+ *     $lock = Drupal::lock()->acquire('stuff_lock');
+ *     // ...
+ *   }
+ *
+ *   // The preferred way: dependency injected code.
+ *   function hook_do_stuff() {
+ *     // Move the actual implementation to a class and instantiate it.
+ *     $instance = new StuffDoingClass(Drupal::lock());
+ *     $instance->doStuff();
+ *
+ *     // Or, even better, rely on the service container to avoid hard coding a
+ *     // specific interface implementation, so that the actual logic can be
+ *     // swapped. This might not always make sense, but in general it is a good
+ *     // practice.
+ *     Drupal::service('stuff.doing')->doStuff();
+ *   }
+ *
+ *   interface StuffDoingInterface {
+ *     public function doStuff();
+ *   }
+ *
+ *   class StuffDoingClass implements StuffDoingInterface {
+ *     protected $lockBackend;
+ *
+ *     public function __construct(LockBackendInterface $lockBackend) {
+ *       $this->lockBackend = $lockBackend;
+ *     }
+ *
+ *     public function doStuff() {
+ *       $lock = $this->lockBackend->acquire('stuff_lock');
+ *       // ...
+ *     }
+ *   }
+ * @endcode
+ *
+ * @see \Drupal\Core\DrupalKernel
+ */
+class Drupal {
+
+  /**
+   * The currently active container object.
+   *
+   * @var \Symfony\Component\DependencyInjection\ContainerInterface
+   */
+  protected static $container;
+
+  /**
+   * Sets a new global container.
+   *
+   * @param \Symfony\Component\DependencyInjection\ContainerInterface $container
+   *   A new container instance to replace the current.
+   */
+  public static function setContainer(ContainerInterface $container) {
+    static::$container = $container;
+  }
+
+  /**
+   * Returns the currently active global container.
+   *
+   * @deprecated This method is only useful for the testing environment, and as
+   *   a BC shiv for drupal_container(). It should not be used otherwise.
+   *
+   * @return \Symfony\Component\DependencyInjection\ContainerInterface
+   */
+  public static function getContainer() {
+    return static::$container;
+  }
+
+  /**
+   * Retrieves a service from the container.
+   *
+   * Use this method if the desired service is not one of those with a dedicated
+   * accessor method below. If it is listed below, those methods are preferred
+   * as they can return useful type hints.
+   *
+   * @param string $id
+   *   The ID of the service to retrieve.
+   * @return mixed
+   *   The specified service.
+   */
+  public static function service($id) {
+    return static::$container->get($id);
+  }
+
+  /**
+   * Returns the current primary database.
+   *
+   * @return \Drupal\Core\Database\Connection
+   *   The current active database's master connection.
+   */
+  public static function database() {
+    return static::$container->get('database');
+  }
+
+  /**
+   * Returns the locking layer instance.
+   *
+   * @return \Drupal\Core\Lock\LockBackendInterface
+   */
+  public static function lock() {
+    return static::$container->get('lock');
+  }
+
+}
diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index 729ff78..ee14fb3 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -326,7 +326,7 @@ protected function initializeContainer() {
     // Set the class loader which was registered as a synthetic service.
     $this->container->set('class_loader', $this->classLoader);
 
-    drupal_container($this->container);
+    \Drupal::setContainer($this->container);
   }
 
   /**
diff --git a/core/modules/contact/contact.pages.inc b/core/modules/contact/contact.pages.inc
index 931a47a..5ee9fb7 100644
--- a/core/modules/contact/contact.pages.inc
+++ b/core/modules/contact/contact.pages.inc
@@ -92,7 +92,7 @@ function contact_flood_control() {
   $config = config('contact.settings');
   $limit = $config->get('flood.limit');
   $interval = $config->get('flood.interval');
-  if (!drupal_container()->get('flood')->isAllowed('contact', $limit, $interval)) {
+  if (!Drupal::service('flood')->isAllowed('contact', $limit, $interval)) {
     drupal_set_message(t("You cannot send more than %limit messages in @interval. Try again later.", array(
       '%limit' => $limit,
       '@interval' => format_interval($interval),
diff --git a/core/modules/contact/lib/Drupal/contact/MessageFormController.php b/core/modules/contact/lib/Drupal/contact/MessageFormController.php
index e536675..c4352cf 100644
--- a/core/modules/contact/lib/Drupal/contact/MessageFormController.php
+++ b/core/modules/contact/lib/Drupal/contact/MessageFormController.php
@@ -191,7 +191,7 @@ public function save(array $form, array &$form_state) {
       drupal_mail('contact', 'page_autoreply', $sender->mail, $language_interface->langcode, $params);
     }
 
-    drupal_container()->get('flood')->register('contact', config('contact.settings')->get('flood.interval'));
+    \Drupal::service('flood')->register('contact', config('contact.settings')->get('flood.interval'));
     if ($message->category) {
       watchdog('contact', '%sender-name (@sender-from) sent an e-mail regarding %category.', array(
         '%sender-name' => $sender->name,
diff --git a/core/modules/contact/lib/Drupal/contact/Tests/ContactSitewideTest.php b/core/modules/contact/lib/Drupal/contact/Tests/ContactSitewideTest.php
index fd5dd75..bdc98ef 100644
--- a/core/modules/contact/lib/Drupal/contact/Tests/ContactSitewideTest.php
+++ b/core/modules/contact/lib/Drupal/contact/Tests/ContactSitewideTest.php
@@ -207,7 +207,7 @@ function testAutoReply() {
     // We are testing the auto-reply, so there should be one e-mail going to the sender.
     $captured_emails = $this->drupalGetMails(array('id' => 'contact_page_autoreply', 'to' => $email));
     $this->assertEqual(count($captured_emails), 1);
-    $this->assertEqual($captured_emails[0]['body'], drupal_html_to_text($foo_autoreply));
+    $this->assertEqual(trim($captured_emails[0]['body']), trim(drupal_html_to_text($foo_autoreply)));
 
     // Test the auto-reply for category 'bar'.
     $email = $this->randomName(32) . '@example.com';
@@ -216,7 +216,7 @@ function testAutoReply() {
     // Auto-reply for category 'bar' should result in one auto-reply e-mail to the sender.
     $captured_emails = $this->drupalGetMails(array('id' => 'contact_page_autoreply', 'to' => $email));
     $this->assertEqual(count($captured_emails), 1);
-    $this->assertEqual($captured_emails[0]['body'], drupal_html_to_text($bar_autoreply));
+    $this->assertEqual(trim($captured_emails[0]['body']), trim(drupal_html_to_text($bar_autoreply)));
 
     // Verify that no auto-reply is sent when the auto-reply field is left blank.
     $email = $this->randomName(32) . '@example.com';
diff --git a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
index e483a0b..35af531 100644
--- a/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
+++ b/core/modules/simpletest/lib/Drupal/simpletest/TestBase.php
@@ -901,7 +901,7 @@ protected function prepareEnvironment() {
 
     // Reset and create a new service container.
     $this->container = new ContainerBuilder();
-    drupal_container($this->container);
+    \Drupal::setContainer($this->container);
 
     // Unset globals.
     unset($GLOBALS['theme_key']);
@@ -1046,7 +1046,7 @@ protected function tearDown() {
     new Settings($this->originalSettings);
 
     // Restore original statics and globals.
-    drupal_container($this->originalContainer);
+    \Drupal::setContainer($this->originalContainer);
     $GLOBALS['config_directories'] = $this->originalConfigDirectories;
     if (isset($this->originalPrefix)) {
       drupal_valid_test_ua($this->originalPrefix);
diff --git a/core/modules/system/lib/Drupal/system/Tests/System/FloodTest.php b/core/modules/system/lib/Drupal/system/Tests/System/FloodTest.php
index 083c968..6af396b 100644
--- a/core/modules/system/lib/Drupal/system/Tests/System/FloodTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/System/FloodTest.php
@@ -30,20 +30,21 @@ function testCleanUp() {
     $name = 'flood_test_cleanup';
 
     // Register expired event.
-    drupal_container()->get('flood')->register($name, $window_expired);
+    $flood = \Drupal::service('flood');
+    $flood->register($name, $window_expired);
     // Verify event is not allowed.
-    $this->assertFalse(drupal_container()->get('flood')->isAllowed($name, $threshold));
+    $this->assertFalse($flood->isAllowed($name, $threshold));
     // Run cron and verify event is now allowed.
     $this->cronRun();
-    $this->assertTrue(drupal_container()->get('flood')->isAllowed($name, $threshold));
+    $this->assertTrue($flood->isAllowed($name, $threshold));
 
     // Register unexpired event.
-    drupal_container()->get('flood')->register($name);
+    $flood->register($name);
     // Verify event is not allowed.
-    $this->assertFalse(drupal_container()->get('flood')->isAllowed($name, $threshold));
+    $this->assertFalse($flood->isAllowed($name, $threshold));
     // Run cron and verify event is still not allowed.
     $this->cronRun();
-    $this->assertFalse(drupal_container()->get('flood')->isAllowed($name, $threshold));
+    $this->assertFalse($flood->isAllowed($name, $threshold));
   }
 
   /**
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 677e5ca..2e8567c 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -3519,7 +3519,7 @@ function system_get_module_admin_tasks($module, $info) {
  */
 function system_cron() {
   // Cleanup the flood.
-  drupal_container()->get('flood')->garbageCollection();
+  Drupal::service('flood')->garbageCollection();
 
   $cache_bins = array_merge(module_invoke_all('cache_flush'), array('form', 'menu'));
   foreach ($cache_bins as $bin) {
diff --git a/core/modules/translation_entity/translation_entity.module b/core/modules/translation_entity/translation_entity.module
index ac00322..b99fdcf 100644
--- a/core/modules/translation_entity/translation_entity.module
+++ b/core/modules/translation_entity/translation_entity.module
@@ -868,7 +868,7 @@ function translation_entity_field_info_alter(&$info) {
 function translation_entity_field_attach_presave(EntityInterface $entity) {
   if (translation_entity_enabled($entity->entityType(), $entity->bundle())) {
     $attributes = drupal_container()->get('request')->attributes;
-    drupal_container()->get('translation_entity.synchronizer')->synchronizeFields($entity, $attributes->get('working_langcode'), $attributes->get('source_langcode'));
+    Drupal::service('translation_entity.synchronizer')->synchronizeFields($entity, $attributes->get('working_langcode'), $attributes->get('source_langcode'));
   }
 }
 
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 58c9ab7..ab5af81 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -1331,13 +1331,14 @@ function user_login_name_validate($form, &$form_state) {
 function user_login_authenticate_validate($form, &$form_state) {
   $password = trim($form_state['values']['pass']);
   $flood_config = config('user.flood');
+  $flood = Drupal::service('flood');
   if (!empty($form_state['values']['name']) && !empty($password)) {
     // Do not allow any login from the current user's IP if the limit has been
     // reached. Default is 50 failed attempts allowed in one hour. This is
     // independent of the per-user limit to catch attempts from one IP to log
     // in to many different user accounts.  We have a reasonably high limit
     // since there may be only one apparent IP for all users at an institution.
-    if (!drupal_container()->get('flood')->isAllowed('user.failed_login_ip', $flood_config->get('ip_limit'), $flood_config->get('ip_window'))) {
+    if (!$flood->isAllowed('user.failed_login_ip', $flood_config->get('ip_limit'), $flood_config->get('ip_window'))) {
       $form_state['flood_control_triggered'] = 'ip';
       return;
     }
@@ -1358,7 +1359,7 @@ function user_login_authenticate_validate($form, &$form_state) {
 
       // Don't allow login if the limit for this user has been reached.
       // Default is to allow 5 failed attempts every 6 hours.
-      if (!drupal_container()->get('flood')->isAllowed('user.failed_login_user', $flood_config->get('user_limit'), $flood_config->get('user_window'), $identifier)) {
+      if (!$flood->isAllowed('user.failed_login_user', $flood_config->get('user_limit'), $flood_config->get('user_window'), $identifier)) {
         $form_state['flood_control_triggered'] = 'user';
         return;
       }
@@ -1378,12 +1379,13 @@ function user_login_authenticate_validate($form, &$form_state) {
  */
 function user_login_final_validate($form, &$form_state) {
   $flood_config = config('user.flood');
+  $flood = Drupal::service('flood');
   if (empty($form_state['uid'])) {
     // Always register an IP-based failed login event.
-    drupal_container()->get('flood')->register('user.failed_login_ip', $flood_config->get('ip_window'));
+    $flood->register('user.failed_login_ip', $flood_config->get('ip_window'));
     // Register a per-user failed login event.
     if (isset($form_state['flood_control_user_identifier'])) {
-      drupal_container()->get('flood')->register('user.failed_login_user', $flood_config->get('user_window'), $form_state['flood_control_user_identifier']);
+      $flood->register('user.failed_login_user', $flood_config->get('user_window'), $form_state['flood_control_user_identifier']);
     }
 
     if (isset($form_state['flood_control_triggered'])) {
@@ -1403,7 +1405,7 @@ function user_login_final_validate($form, &$form_state) {
   elseif (isset($form_state['flood_control_user_identifier'])) {
     // Clear past failures for this user so as not to block a user who might
     // log in and out more than once in an hour.
-    drupal_container()->get('flood')->clear('user.failed_login_user', $form_state['flood_control_user_identifier']);
+    $flood->clear('user.failed_login_user', $form_state['flood_control_user_identifier']);
   }
 }
 
