Skip to content

Commit 0a3be77

Browse files
committed
IN PROGRESS: Trigger R8's ServiceLoader optimization
1 parent bc1f146 commit 0a3be77

3 files changed

Lines changed: 61 additions & 10 deletions

File tree

api/src/main/java/io/grpc/InternalServiceProviders.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package io.grpc;
1818

1919
import com.google.common.annotations.VisibleForTesting;
20+
import java.util.Iterator;
2021
import java.util.List;
2122

2223
@Internal
@@ -27,6 +28,7 @@ private InternalServiceProviders() {
2728
/**
2829
* Accessor for method.
2930
*/
31+
//@Deprecated
3032
public static <T> List<T> loadAll(
3133
Class<T> klass,
3234
Iterable<Class<?>> hardCodedClasses,
@@ -35,6 +37,17 @@ public static <T> List<T> loadAll(
3537
return ServiceProviders.loadAll(klass, hardCodedClasses, classLoader, priorityAccessor);
3638
}
3739

40+
/**
41+
* Accessor for method.
42+
*/
43+
public static <T> List<T> loadAll(
44+
Class<T> klass,
45+
Iterator<T> serviceLoader,
46+
Iterable<Class<?>> hardCodedClasses,
47+
PriorityAccessor<T> priorityAccessor) {
48+
return ServiceProviders.loadAll(klass, serviceLoader, hardCodedClasses, priorityAccessor);
49+
}
50+
3851
/**
3952
* Accessor for method.
4053
*/

api/src/main/java/io/grpc/NameResolverRegistry.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.util.List;
3030
import java.util.Locale;
3131
import java.util.Map;
32+
import java.util.ServiceLoader;
3233
import java.util.logging.Level;
3334
import java.util.logging.Logger;
3435
import javax.annotation.Nullable;
@@ -125,8 +126,10 @@ public static synchronized NameResolverRegistry getDefaultRegistry() {
125126
if (instance == null) {
126127
List<NameResolverProvider> providerList = ServiceProviders.loadAll(
127128
NameResolverProvider.class,
129+
ServiceLoader
130+
.load(NameResolverProvider.class, NameResolverProvider.class.getClassLoader())
131+
.iterator(),
128132
getHardCodedClasses(),
129-
NameResolverProvider.class.getClassLoader(),
130133
new NameResolverPriorityAccessor());
131134
if (providerList.isEmpty()) {
132135
logger.warning("No NameResolverProviders found via ServiceLoader, including for DNS. This "

api/src/main/java/io/grpc/ServiceProviders.java

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@
2020
import java.util.ArrayList;
2121
import java.util.Collections;
2222
import java.util.Comparator;
23+
import java.util.Iterator;
2324
import java.util.List;
25+
import java.util.ListIterator;
2426
import java.util.ServiceConfigurationError;
2527
import java.util.ServiceLoader;
2628

@@ -35,19 +37,53 @@ private ServiceProviders() {
3537
* If this is Android, returns all available implementations in {@code hardcoded}.
3638
* The list is sorted in descending priority order.
3739
*/
40+
//@Deprecated
3841
public static <T> List<T> loadAll(
3942
Class<T> klass,
4043
Iterable<Class<?>> hardcoded,
4144
ClassLoader cl,
4245
final PriorityAccessor<T> priorityAccessor) {
43-
Iterable<T> candidates;
44-
if (isAndroid(cl)) {
45-
candidates = getCandidatesViaHardCoded(klass, hardcoded);
46+
return loadAll(klass, ServiceLoader.load(klass, cl).iterator(), hardcoded, priorityAccessor);
47+
}
48+
49+
/**
50+
* If this is not Android, returns all available implementations discovered via
51+
* {@link ServiceLoader}.
52+
* If this is Android, returns all available implementations in {@code hardcoded}.
53+
* The list is sorted in descending priority order.
54+
*
55+
* <p>{@code serviceLoader} should be created with {@code ServiceLoader.load(MyClass.class,
56+
* MyClass.class.getClassLoader()).iterator()} in order to be detected by R8 so that R8 full mode
57+
* will keep the constructors for the provider classes.
58+
*/
59+
public static <T> List<T> loadAll(
60+
Class<T> klass,
61+
Iterator<T> serviceLoader,
62+
Iterable<Class<?>> hardcoded,
63+
final PriorityAccessor<T> priorityAccessor) {
64+
Iterator<T> candidates;
65+
if (serviceLoader instanceof ListIterator) {
66+
// A rewriting tool has replaced the ServiceLoader with a List of some sort (R8 uses
67+
// ArrayList, AppReduce uses singletonList). We prefer to use such iterators on Android as
68+
// they won't need reflection like the hard-coded list does. In addition, the provider
69+
// instances will have already been created, so it seems we should use them.
70+
//
71+
// R8: https://r8.googlesource.com/r8/+/490bc53d9310d4cc2a5084c05df4aadaec8c885d/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
72+
// AppReduce: service_loader_pass.cc
73+
candidates = serviceLoader;
74+
} else if (isAndroid(klass.getClassLoader())) {
75+
// Avoid getResource() on Android, which must read from a zip which uses a lot of memory
76+
candidates = getCandidatesViaHardCoded(klass, hardcoded).iterator();
77+
} else if (!serviceLoader.hasNext()) {
78+
// Attempt to load using the context class loader and ServiceLoader.
79+
// This allows frameworks like http://aries.apache.org/modules/spi-fly.html to plug in.
80+
candidates = ServiceLoader.load(klass).iterator();
4681
} else {
47-
candidates = getCandidatesViaServiceLoader(klass, cl);
82+
candidates = serviceLoader;
4883
}
4984
List<T> list = new ArrayList<>();
50-
for (T current: candidates) {
85+
while (candidates.hasNext()) {
86+
T current = candidates.next();
5187
if (!priorityAccessor.isAvailable(current)) {
5288
continue;
5389
}
@@ -84,15 +120,14 @@ static boolean isAndroid(ClassLoader cl) {
84120
}
85121

86122
/**
87-
* Loads service providers for the {@code klass} service using {@link ServiceLoader}.
123+
* For testing only: Loads service providers for the {@code klass} service using {@link
124+
* ServiceLoader}. Does not support spi-fly and related tricks.
88125
*/
89126
@VisibleForTesting
90127
public static <T> Iterable<T> getCandidatesViaServiceLoader(Class<T> klass, ClassLoader cl) {
91128
Iterable<T> i = ServiceLoader.load(klass, cl);
92-
// Attempt to load using the context class loader and ServiceLoader.
93-
// This allows frameworks like http://aries.apache.org/modules/spi-fly.html to plug in.
94129
if (!i.iterator().hasNext()) {
95-
i = ServiceLoader.load(klass);
130+
return null;
96131
}
97132
return i;
98133
}

0 commit comments

Comments
 (0)