protected function getAllServices() {
    $container_builder = $this->containerBuilderGetter->getContainerBuilder();
    $definitions = $container_builder->getDefinitions();

    // Get an array of all the tags which are used by service collectors, so
    // we can filter out the services with those tags.
    $collector_tags = [];
    $collectors_info = $container_builder->findTaggedServiceIds('service_collector');
    foreach ($collectors_info as $service_name => $tag_infos) {
      // A single service collector service can collect on more than one tag.
      foreach ($tag_infos as $tag_info) {
        $tag = $tag_info['tag'];
        $collector_tags[$tag] = TRUE;
      }
    }

    $data = [];

    foreach ($definitions as $service_id => $definition) {
      // Skip services from Drush.
      if (substr($service_id, 0, strlen('drush.')) == 'drush.') {
        continue;
      }
      if (substr($service_id, - strlen('.commands')) == '.commands') {
        continue;
      }

      // Skip proxy services.
      if (substr($service_id, 0, strlen('drupal.proxy_original_service.')) == 'drupal.proxy_original_service.') {
        continue;
      }

      // Skip any services which are tagged for a collector, as they should not
      // be directly used by anything else.
      if (array_intersect_key($collector_tags, $definition->getTags())) {
        continue;
      }

      // Skip any services which are marked as deprecated.
      if ($definition->isDeprecated()) {
        continue;
      }

      // Skip entity.manager, which is not marked as deprecated, but is.
      if ($service_id == 'entity.manager') {
        continue;
      }

      $service_class = $definition->getClass();

      // Skip if no class defined, class_loader apparently, WTF?!.
      if (empty($service_class)) {
        continue;
      }

      // Skip if the class isn't loadable by PHP without causing a fatal, as we
      // can't work with just an ID to generate things like injection.
      // (The case of a service class whose parent does not exist happens if
      // a module Foo provides a service for module Bar's collection with a
      // service tag. Metatag module is one such example.)
      if (!$this->codeAnalyser->classIsUsable($service_class)) {
        continue;
      }

      // Skip if the clas doesn't exist.
      // The service class can sometimes actually be an interface, as with
      // cache services. (This is not documented!)
      if (!(class_exists($service_class) || interface_exists($service_class))) {
        continue;
      }

      // Get the short class name to use as a label.
      $service_class_pieces = explode('\\', $service_class);
      $service_short_class = array_pop($service_class_pieces);

      // If the class is in fact secretly an interface (this is the case for
      // cache services!) then remove the 'Interface' suffix.
      $service_short_class = preg_replace('/Interface$/', '', $service_short_class);

      $label = CaseString::pascal($service_short_class)->sentence();

      $data[$service_id] = [
        'id' => $service_id,
        'label' => $label,
        'static_method' => '', // Not used.
        'class' => '\\' . $service_class,
        'interface' => $this->getServiceInterface($service_class),
        'description' => "The {$label} service",
      ];
    }

    ksort($data);

    return $data;
  }