• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

grpc / grpc-java / #20177

23 Feb 2026 03:46PM UTC coverage: 88.701% (-0.01%) from 88.714%
#20177

push

github

web-flow
Trigger R8's ServiceLoader optimization

This simplifies R8 Full Mode's configuration when paired with R8
optimizations (which is made more difficult to avoid in AGP 9), as when
the optimization is triggered Full Mode will automatically keep the
constructor for the relevant classes.

android-interop-test doesn't currently enable R8 optimizations, so it
doesn't actually demonstrate the benefit, but I have manually confirmed
that enabling proguard-android-optimize.txt does cause the ServiceLoader
optimization in android-interop-test. Note that full mode is a separate
configuration and not necessary to get the ServiceLoader optimization.

35461 of 39978 relevant lines covered (88.7%)

0.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.93
/../xds/src/main/java/io/grpc/xds/XdsCredentialsRegistry.java
1
/*
2
 * Copyright 2022 The gRPC Authors
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package io.grpc.xds;
18

19
import static com.google.common.base.Preconditions.checkArgument;
20
import static com.google.common.base.Preconditions.checkNotNull;
21

22
import com.google.common.annotations.VisibleForTesting;
23
import com.google.common.collect.ImmutableMap;
24
import com.google.errorprone.annotations.concurrent.GuardedBy;
25
import io.grpc.InternalServiceProviders;
26
import java.util.ArrayList;
27
import java.util.Collections;
28
import java.util.HashMap;
29
import java.util.LinkedHashSet;
30
import java.util.List;
31
import java.util.Map;
32
import java.util.ServiceLoader;
33
import java.util.logging.Level;
34
import java.util.logging.Logger;
35
import javax.annotation.Nullable;
36
import javax.annotation.concurrent.ThreadSafe;
37

38
/**
39
 * Registry of {@link XdsCredentialsProvider}s. The {@link #getDefaultRegistry default
40
 * instance} loads providers at runtime through the Java service provider mechanism.
41
 */
42
@ThreadSafe
43
final class XdsCredentialsRegistry {
1✔
44
  private static final Logger logger = Logger.getLogger(XdsCredentialsRegistry.class.getName());
1✔
45
  private static XdsCredentialsRegistry instance;
46

47
  @GuardedBy("this")
1✔
48
  private final LinkedHashSet<XdsCredentialsProvider> allProviders = new LinkedHashSet<>();
49

50
  /**
51
   * Generated from {@code allProviders}. Is mapping from scheme key to the
52
   * highest priority {@link XdsCredentialsProvider}.
53
   * Is replaced instead of mutating.
54
   */
55
  @GuardedBy("this")
1✔
56
  private ImmutableMap<String, XdsCredentialsProvider> effectiveProviders = ImmutableMap.of();
1✔
57

58
  /**
59
   * Register a provider.
60
   *
61
   * <p>If the provider's {@link XdsCredentialsProvider#isAvailable isAvailable()}
62
   * returns {@code false}, this method will throw {@link IllegalArgumentException}.
63
   *
64
   * <p>Providers will be used in priority order. In case of ties, providers are used
65
   * in registration order.
66
   */
67
  public synchronized void register(XdsCredentialsProvider provider) {
68
    addProvider(provider);
1✔
69
    refreshProviders();
1✔
70
  }
1✔
71

72
  private synchronized void addProvider(XdsCredentialsProvider provider) {
73
    checkArgument(provider.isAvailable(), "isAvailable() returned false");
1✔
74
    allProviders.add(provider);
1✔
75
  }
1✔
76

77
  /**
78
   * Deregisters a provider. No-op if the provider is not in the registry.
79
   *
80
   * @param provider the provider that was added to the register via
81
   *                 {@link #register}.
82
   */
83
  public synchronized void deregister(XdsCredentialsProvider provider) {
84
    allProviders.remove(provider);
1✔
85
    refreshProviders();
1✔
86
  }
1✔
87

88
  private synchronized void refreshProviders() {
89
    Map<String, XdsCredentialsProvider> refreshedProviders = new HashMap<>();
1✔
90
    int maxPriority = Integer.MIN_VALUE;
1✔
91
    // We prefer first-registered providers.
92
    for (XdsCredentialsProvider provider : allProviders) {
1✔
93
      String credsName = provider.getName();
1✔
94
      XdsCredentialsProvider existing = refreshedProviders.get(credsName);
1✔
95
      if (existing == null || existing.priority() < provider.priority()) {
1✔
96
        refreshedProviders.put(credsName, provider);
1✔
97
      }
98
      if (maxPriority < provider.priority()) {
1✔
99
        maxPriority = provider.priority();
1✔
100
      }
101
    }
1✔
102
    effectiveProviders = ImmutableMap.copyOf(refreshedProviders);
1✔
103
  }
1✔
104

105
  /**
106
   * Returns the default registry that loads providers via the Java service loader
107
   * mechanism.
108
   */
109
  public static synchronized XdsCredentialsRegistry getDefaultRegistry() {
110
    if (instance == null) {
1✔
111
      List<XdsCredentialsProvider> providerList = InternalServiceProviders.loadAll(
1✔
112
              XdsCredentialsProvider.class,
113
              ServiceLoader
114
                .load(XdsCredentialsProvider.class, XdsCredentialsProvider.class.getClassLoader())
1✔
115
                .iterator(),
1✔
116
              XdsCredentialsRegistry::getHardCodedClasses,
117
              new XdsCredentialsProviderPriorityAccessor());
118
      if (providerList.isEmpty()) {
1✔
119
        logger.warning("No XdsCredsRegistry found via ServiceLoader, including for GoogleDefault, "
×
120
            + "TLS and Insecure. This is probably due to a broken build.");
121
      }
122
      instance = new XdsCredentialsRegistry();
1✔
123
      for (XdsCredentialsProvider provider : providerList) {
1✔
124
        logger.fine("Service loader found " + provider);
1✔
125
        if (provider.isAvailable()) {
1✔
126
          instance.addProvider(provider);
1✔
127
        }
128
      }
1✔
129
      instance.refreshProviders();
1✔
130
    }
131
    return instance;
1✔
132
  }
133

134
  /**
135
   * Returns effective providers map from scheme to the highest priority
136
   * XdsCredsProvider of that scheme. 
137
   */
138
  @VisibleForTesting
139
  synchronized Map<String, XdsCredentialsProvider> providers() {
140
    return effectiveProviders;
1✔
141
  }
142

143
  /**
144
   * Returns the effective provider for the given xds credential name, or {@code null} if no
145
   * suitable provider can be found. 
146
   * Each provider declares its name via {@link XdsCredentialsProvider#getName}.
147
   */
148
  @Nullable
149
  public synchronized XdsCredentialsProvider getProvider(String name) {
150
    return effectiveProviders.get(checkNotNull(name, "name"));
1✔
151
  }
152

153
  @VisibleForTesting
154
  static List<Class<?>> getHardCodedClasses() {
155
    // Class.forName(String) is used to remove the need for ProGuard configuration. Note that
156
    // ProGuard does not detect usages of Class.forName(String, boolean, ClassLoader):
157
    // https://sourceforge.net/p/proguard/bugs/418/
158
    ArrayList<Class<?>> list = new ArrayList<>();
1✔
159
    try {
160
      list.add(Class.forName("io.grpc.xds.internal.GoogleDefaultXdsCredentialsProvider")); 
1✔
161
    } catch (ClassNotFoundException e) {
×
162
      logger.log(Level.WARNING, "Unable to find GoogleDefaultXdsCredentialsProvider", e);
×
163
    }
1✔
164

165
    try {
166
      list.add(Class.forName("io.grpc.xds.internal.InsecureXdsCredentialsProvider"));
1✔
167
    }  catch (ClassNotFoundException e) {
×
168
      logger.log(Level.WARNING, "Unable to find InsecureXdsCredentialsProvider", e);
×
169
    }
1✔
170

171
    try {
172
      list.add(Class.forName("io.grpc.xds.internal.TlsXdsCredentialsProvider"));
1✔
173
    } catch (ClassNotFoundException e) {
×
174
      logger.log(Level.WARNING, "Unable to find TlsXdsCredentialsProvider", e);
×
175
    }
1✔
176
      
177
    return Collections.unmodifiableList(list);
1✔
178
  }
179

180
  private static final class XdsCredentialsProviderPriorityAccessor
181
          implements InternalServiceProviders.PriorityAccessor<XdsCredentialsProvider> {
182
    @Override
183
    public boolean isAvailable(XdsCredentialsProvider provider) {
184
      return provider.isAvailable();
1✔
185
    }
186

187
    @Override
188
    public int getPriority(XdsCredentialsProvider provider) {
189
      return provider.priority();
1✔
190
    }
191
  }
192
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc