diff --git a/core/includes/install.inc b/core/includes/install.inc
index 7e0e32e..61ea3bb 100644
--- a/core/includes/install.inc
+++ b/core/includes/install.inc
@@ -107,7 +107,7 @@ function drupal_install_profile_distribution_name() {
   // At all other times, we load the profile via standard methods.
   else {
     $profile = drupal_get_profile();
-    $info = system_get_info('module', $profile);
+    $info = \Drupal::moduleHandler()->getInfo($profile);
   }
   return isset($info['distribution']['name']) ? $info['distribution']['name'] : 'Drupal';
 }
diff --git a/core/includes/module.inc b/core/includes/module.inc
index f65f0b8..0f1b0d8 100644
--- a/core/includes/module.inc
+++ b/core/includes/module.inc
@@ -45,7 +45,7 @@ function system_list($type) {
     \Drupal::cache('bootstrap')->set('system_list', $lists);
   }
   // To avoid a separate database lookup for the filepath, prime the
-  // drupal_get_filename() static cache with all enabled modules and themes.
+  // drupal_get_filename() static cache with all enabled themes.
   foreach ($lists['filepaths'] as $item) {
     system_register($item['type'], $item['name'], $item['filepath']);
   }
diff --git a/core/lib/Drupal/Core/Extension/ModuleHandler.php b/core/lib/Drupal/Core/Extension/ModuleHandler.php
index bb79ae4..30cd583 100644
--- a/core/lib/Drupal/Core/Extension/ModuleHandler.php
+++ b/core/lib/Drupal/Core/Extension/ModuleHandler.php
@@ -709,9 +709,27 @@ public function getModuleDirectories() {
   /**
    * {@inheritdoc}
    */
+  public function getInfo($module = NULL) {
+    if(!$data = \Drupal::state()->get('system.module.data')) {
+      $data = system_rebuild_module_data();
+    }
+    foreach ($this->getModuleList() as $module_name => $filename) {
+      if (isset($data[$module_name])) {
+        $info[$module_name] = $data[$module_name]->info;
+      }
+    }
+    if (isset($module)) {
+      return isset($info[$module]) ? $info[$module] : array();
+    }
+    return $info;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function getName($module) {
-    $module_data = system_rebuild_module_data();
-    return $module_data[$module]->info['name'];
+    $info = $this->getInfo($module);
+    return isset($info['name']) ? $info['name'] : $module;
   }
 
 }
diff --git a/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php b/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php
index 9d12df6..6490a11 100644
--- a/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php
+++ b/core/lib/Drupal/Core/Extension/ModuleHandlerInterface.php
@@ -301,13 +301,33 @@ public function alter($type, &$data, &$context1 = NULL, &$context2 = NULL);
   public function getModuleDirectories();
 
   /**
+   * Returns an array of information about enabled modules.
+   *
+   * This function returns the contents of the .info.yml file for each installed
+   * module.
+   *
+   * @param $module
+   *   (optional) The name of a module or theme whose information shall be
+   *   returned. If omitted, all module records will be returned.
+   *   If $module does not exist in the modules or is not enabled, an empty
+   *   array will be returned.
+   *
+   * @return
+   *   An associative array of module information keyed by name, or only
+   *   information for $module, if given. If no records are available, an empty
+   *   array is returned.
+   */
+  public function getInfo($module = NULL);
+
+  /**
    * Gets the human readable name of a given module.
    *
    * @param string $module
    *   The machine name of the module which title should be shown.
    *
    * @return string
-   *   Returns the human readable name of the module.
+   *   Returns the human readable name of the module or the machine name passed
+   *   in if no matching module is found.
    */
   public function getName($module);
 
diff --git a/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php b/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php
index bf86365..b398219 100644
--- a/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php
+++ b/core/lib/Drupal/Core/Menu/Form/MenuLinkDefaultForm.php
@@ -55,7 +55,7 @@ class MenuLinkDefaultForm implements MenuLinkFormInterface, ContainerInjectionIn
   protected $moduleHandler;
 
   /**
-   * The module data from system_get_info().
+   * The module data from ModuleHandler::getInfo().
    *
    * @var array
    */
@@ -108,7 +108,7 @@ public function buildConfigurationForm(array $form, FormStateInterface $form_sta
     $provider = $this->menuLink->getProvider();
     $form['info'] = array(
       '#type' => 'item',
-      '#title' => $this->t('This link is provided by the @name module. The title and path cannot be edited.', array('@name' => $this->getModuleName($provider))),
+      '#title' => $this->t('This link is provided by the @name module. The title and path cannot be edited.', array('@name' => $this->moduleHandler->getName($provider))),
     );
     $link = array(
       '#type' => 'link',
@@ -187,31 +187,4 @@ public function submitConfigurationForm(array &$form, FormStateInterface $form_s
     return $this->menuLinkManager->updateDefinition($this->menuLink->getPluginId(), $new_definition);
   }
 
-  /**
-   * Gets the name of the module.
-   *
-   * @param string $module
-   *   The machine name of a module.
-   *
-   * @todo This function is horrible, but core has nothing better until we add a
-   * a method to the ModuleHandler that handles this nicely.
-   * https://drupal.org/node/2281989
-   *
-   * @return string
-   *   The human-readable, localized module name, or the machine name passed in
-   *   if no matching module is found.
-   */
-  protected function getModuleName($module) {
-    // Gather module data.
-    if (!isset($this->moduleData)) {
-      $this->moduleData = system_get_info('module');
-    }
-    // If the module exists, return its human-readable name.
-    if (isset($this->moduleData[$module])) {
-      return $this->t($this->moduleData[$module]['name']);
-    }
-    // Otherwise, return the machine name.
-    return $module;
-  }
-
 }
diff --git a/core/modules/field/field.module b/core/modules/field/field.module
index d8be776..b69e6d0 100644
--- a/core/modules/field/field.module
+++ b/core/modules/field/field.module
@@ -92,7 +92,7 @@ function field_help($route_name, RouteMatchInterface $route_match) {
       // enabled, ordered by displayed module name (module names are not
       // translated).
       $items = array();
-      $info = system_get_info('module');
+      $info = \Drupal::moduleHandler()->getInfo();
       $widgets = \Drupal::service('plugin.manager.field.widget')->getDefinitions();
       $field_types = \Drupal::service('plugin.manager.field.field_type')->getUiDefinitions();
       $formatters = \Drupal::service('plugin.manager.field.formatter')->getDefinitions();
diff --git a/core/modules/help/src/Controller/HelpController.php b/core/modules/help/src/Controller/HelpController.php
index 53c3eb8..0f06c15 100644
--- a/core/modules/help/src/Controller/HelpController.php
+++ b/core/modules/help/src/Controller/HelpController.php
@@ -8,6 +8,7 @@
 namespace Drupal\help\Controller;
 
 use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Url;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -27,13 +28,23 @@ class HelpController extends ControllerBase {
   protected $routeMatch;
 
   /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface;
+   */
+  protected $moduleHandler;
+
+  /**
    * Creates a new HelpController.
    *
    * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
    *   The current route match.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
    */
-  public function __construct(RouteMatchInterface $route_match) {
+  public function __construct(RouteMatchInterface $route_match, ModuleHandlerInterface $module_handler) {
     $this->routeMatch = $route_match;
+    $this->moduleHandler = $module_handler;
   }
 
   /**
@@ -41,7 +52,8 @@ public function __construct(RouteMatchInterface $route_match) {
    */
   public static function create(ContainerInterface $container) {
     return new static(
-      $container->get('current_route_match')
+      $container->get('current_route_match'),
+      $container->get('module_handler')
     );
   }
 
@@ -118,7 +130,7 @@ protected function helpLinksAsList() {
   public function helpPage($name) {
     $build = array();
     if ($this->moduleHandler()->implementsHook($name, 'help')) {
-      $info = system_get_info('module');
+      $info = \Drupal::moduleHandler()->getInfo();
       $build['#title'] = SafeMarkup::checkPlain($info[$name]['name']);
 
       $temp = $this->moduleHandler()->invoke($name, 'help', array("help.page.$name", $this->routeMatch));
diff --git a/core/modules/system/src/Controller/AdminController.php b/core/modules/system/src/Controller/AdminController.php
index d9800f0..1870b31 100644
--- a/core/modules/system/src/Controller/AdminController.php
+++ b/core/modules/system/src/Controller/AdminController.php
@@ -8,6 +8,7 @@
 namespace Drupal\system\Controller;
 
 use Drupal\Core\Controller\ControllerBase;
+use Drupal\Core\Extension\ModuleHandlerInterface;
 
 /**
  * Controller for admin section.
@@ -15,13 +16,38 @@
 class AdminController extends ControllerBase {
 
   /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface;
+   */
+  protected $moduleHandler;
+
+  /**
+   * Creates a new HelpController.
+   *
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
+   */
+  public function __construct(ModuleHandlerInterface $module_handler) {
+    $this->moduleHandler = $module_handler;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('module_handler')
+    );
+  }
+  /**
    * Prints a listing of admin tasks, organized by module.
    *
    * @return array
    *  A render array containing the listing.
    */
   public function index() {
-    $module_info = system_get_info('module');
+    $module_info = $this->moduleHandler->getInfo();
     foreach ($module_info as $module => $info) {
       $module_info[$module] = new \stdClass();
       $module_info[$module]->info = $info;
diff --git a/core/modules/system/src/Tests/Module/RequiredTest.php b/core/modules/system/src/Tests/Module/RequiredTest.php
index c14d293..b8d0d8e 100644
--- a/core/modules/system/src/Tests/Module/RequiredTest.php
+++ b/core/modules/system/src/Tests/Module/RequiredTest.php
@@ -17,7 +17,7 @@ class RequiredTest extends ModuleTestBase {
    * Assert that core required modules cannot be disabled.
    */
   function testDisableRequired() {
-    $module_info = system_get_info('module');
+    $module_info = \Drupal::moduleHandler()->getInfo();
     $this->drupalGet('admin/modules');
     foreach ($module_info as $module => $info) {
       // Check to make sure the checkbox for each required module is disabled
diff --git a/core/modules/system/system.install b/core/modules/system/system.install
index 8355a2c..99f503b 100644
--- a/core/modules/system/system.install
+++ b/core/modules/system/system.install
@@ -35,7 +35,7 @@ function system_requirements($phase) {
     // is not running the default installation profile.
     $profile = drupal_get_profile();
     if ($profile != 'standard') {
-      $info = system_get_info('module', $profile);
+      $info = \Drupal::moduleHandler()->getInfo($profile);
       $requirements['install_profile'] = array(
         'title' => t('Installation profile'),
         'value' => t('%profile_name (%profile-%version)', array(
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index d2bda7f..2a164f3 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -854,12 +854,7 @@ function system_check_directory($form_element, FormStateInterface $form_state) {
 function system_get_info($type, $name = NULL) {
   $info = array();
   if ($type == 'module') {
-    $data = system_rebuild_module_data();
-    foreach (\Drupal::moduleHandler()->getModuleList() as $module => $filename) {
-      if (isset($data[$module])) {
-        $info[$module] = $data[$module]->info;
-      }
-    }
+    $info = \Drupal::moduleHandler()->getInfo($name);
   }
   else {
     $list = system_list($type);
@@ -984,7 +979,7 @@ function system_rebuild_module_data() {
   // Only rebuild once per request. $modules and $modules_cache cannot be
   // combined into one variable, because the $modules_cache variable is reset by
   // reference from system_list_reset() during the rebuild.
-  if (!isset($modules_cache)) {
+   if (!isset($modules_cache)) {
     $modules = _system_rebuild_module_data();
     $files = array();
     ksort($modules);
@@ -997,9 +992,14 @@ function system_rebuild_module_data() {
       $files[$name] = $module->getPathname();
     }
     $modules = \Drupal::moduleHandler()->buildModuleDependencies($modules);
+    // Store the module info in state. We rely on consecutive calls to
+    // system_rebuild_module_data() to reset this key, such as when
+    // listing modules, (un)installating modules, importing configuration,
+    // updating the site and when flushing all caches.
+    \Drupal::state()->set('system.module.data', $modules);
     $modules_cache = $modules;
 
-    // Store filenames to allow system_list() and drupal_get_filename() to
+    // Store filenames to allow drupal_get_filename() to
     // retrieve them without having to rebuild or scan the filesystem.
     \Drupal::state()->set('system.module.files', $files);
   }
diff --git a/core/modules/user/src/Plugin/views/access/Permission.php b/core/modules/user/src/Plugin/views/access/Permission.php
index 6dca9bd..0706119 100644
--- a/core/modules/user/src/Plugin/views/access/Permission.php
+++ b/core/modules/user/src/Plugin/views/access/Permission.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Plugin\views\access;
 
 use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\user\PermissionHandlerInterface;
@@ -41,6 +42,13 @@ class Permission extends AccessPluginBase {
   protected $permissionHandler;
 
   /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
    * Constructs a Permission object.
    *
    * @param array $configuration
@@ -51,8 +59,10 @@ class Permission extends AccessPluginBase {
    *   The plugin implementation definition.
    * @param \Drupal\user\PermissionHandlerInterface $permission_handler
    *   The permission handler.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, PermissionHandlerInterface $permission_handler) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, PermissionHandlerInterface $permission_handler, ModuleHandlerInterface $module_handler) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
     $this->permissionHandler = $permission_handler;
   }
@@ -65,7 +75,8 @@ public static function create(ContainerInterface $container, array $configuratio
       $configuration,
       $plugin_id,
       $plugin_definition,
-      $container->get('user.permissions')
+      $container->get('user.permissions'),
+      $container->get('module_handler')
     );
   }
 
@@ -102,7 +113,7 @@ protected function defineOptions() {
 
   public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
-    $module_info = system_get_info('module');
+    $module_info = $this->moduleHandler->getInfo();
 
     // Get list of permissions
     $perms = [];
diff --git a/core/modules/user/src/Plugin/views/field/UserData.php b/core/modules/user/src/Plugin/views/field/UserData.php
index ce3f927..5828c19 100644
--- a/core/modules/user/src/Plugin/views/field/UserData.php
+++ b/core/modules/user/src/Plugin/views/field/UserData.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\user\Plugin\views\field;
 
+use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Plugin\views\field\FieldPluginBase;
@@ -34,19 +35,28 @@ class UserData extends FieldPluginBase {
   protected $userData;
 
   /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+
+  /**
    * {@inheritdoc}
    */
   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
-    return new static($configuration, $plugin_id, $plugin_definition, $container->get('user.data'));
+    return new static($configuration, $plugin_id, $plugin_definition, $container->get('user.data'), $container->get('module_handler'));
   }
 
   /**
    * Constructs a UserData object.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, UserDataInterface $user_data) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, UserDataInterface $user_data, ModuleHandlerInterface $module_handler) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
 
     $this->userData = $user_data;
+    $this->moduleHandler = $module_handler;
   }
 
   /**
@@ -67,7 +77,7 @@ protected function defineOptions() {
   public function buildOptionsForm(&$form, FormStateInterface $form_state) {
     parent::buildOptionsForm($form, $form_state);
 
-    $modules = system_get_info('module');
+    $modules = $this->moduleHandler->getInfo();
     $names = array();
     foreach ($modules as $name => $module) {
       $names[$name] = $module['name'];
diff --git a/core/modules/user/src/Plugin/views/filter/Permissions.php b/core/modules/user/src/Plugin/views/filter/Permissions.php
index 8b1015c..c54d7dd 100644
--- a/core/modules/user/src/Plugin/views/filter/Permissions.php
+++ b/core/modules/user/src/Plugin/views/filter/Permissions.php
@@ -30,6 +30,13 @@ class Permissions extends ManyToOne {
   protected $permissionHandler;
 
   /**
+   * The module handler.
+   *
+   * @var \Drupal\Core\Extension\ModuleHandlerInterface
+   */
+  protected $moduleHandler;
+
+  /**
    * Constructs a Permissions object.
    *
    * @param array $configuration
@@ -39,12 +46,15 @@ class Permissions extends ManyToOne {
    * @param mixed $plugin_definition
    *   The plugin implementation definition.
    * @param \Drupal\user\PermissionHandlerInterface $permission_handler
-   *   The permission handler.
+   *   The module handler.
+   * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+   *   The module handler.
    */
-  public function __construct(array $configuration, $plugin_id, $plugin_definition, PermissionHandlerInterface $permission_handler) {
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, PermissionHandlerInterface $permission_handler, ModuleHandlerInterface $module_handler) {
     parent::__construct($configuration, $plugin_id, $plugin_definition);
 
     $this->permissionHandler = $permission_handler;
+    $this->moduleHandler = $module_handler;
   }
 
   /**
@@ -55,13 +65,14 @@ public static function create(ContainerInterface $container, array $configuratio
       $configuration,
       $plugin_id,
       $plugin_definition,
-      $container->get('user.permissions')
+      $container->get('user.permissions'),
+      $container->get('module_handler')
     );
   }
 
   public function getValueOptions() {
     if (!isset($this->valueOptions)) {
-      $module_info = system_get_info('module');
+      $module_info = $this->moduleHandler->getInfo();
 
       $permissions = $this->permissionHandler->getPermissions();
       foreach ($permissions as $perm => $perm_item) {
