Skip to content

Commit ce7171d

Browse files
Merge branch 'grpc:master' into master
2 parents 1f33b33 + 9193701 commit ce7171d

File tree

10 files changed

+280
-35
lines changed

10 files changed

+280
-35
lines changed

binder/src/main/java/io/grpc/binder/AndroidComponentAddress.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public final class AndroidComponentAddress extends SocketAddress {
5858
@Nullable
5959
private final UserHandle targetUser; // null means the same user that hosts this process.
6060

61-
protected AndroidComponentAddress(Intent bindIntent, @Nullable UserHandle targetUser) {
61+
private AndroidComponentAddress(Intent bindIntent, @Nullable UserHandle targetUser) {
6262
checkArgument(
6363
bindIntent.getComponent() != null || bindIntent.getPackage() != null,
6464
"'bindIntent' must be explicit. Specify either a package or ComponentName.");
@@ -250,7 +250,22 @@ public Builder setBindIntentFromComponent(ComponentName component) {
250250
return this;
251251
}
252252

253-
/** See {@link AndroidComponentAddress#getTargetUser()}. */
253+
/**
254+
* Specifies the Android user in which the built Address' bind Intent will be evaluated.
255+
*
256+
* <p>Connecting to a server in a different Android user is uncommon and requires the client app
257+
* have runtime visibility of &#064;SystemApi's and hold certain &#064;SystemApi permissions.
258+
* The device must also be running Android SDK version 30 or higher.
259+
*
260+
* <p>See https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces
261+
* for details on which apps can call the underlying &#064;SystemApi's needed to make this type
262+
* of connection.
263+
*
264+
* <p>One of the "android.permission.INTERACT_ACROSS_XXX" permissions is required. The exact one
265+
* depends on the calling user's relationship to the target user, whether client and server are
266+
* in the same or different apps, and the version of Android in use. See {@link
267+
* Context#bindServiceAsUser}, the essential underlying Android API, for details.
268+
*/
254269
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/10173")
255270
public Builder setTargetUser(@Nullable UserHandle targetUser) {
256271
this.targetUser = targetUser;

binder/src/main/java/io/grpc/binder/ApiConstants.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,15 @@ private ApiConstants() {}
3535
/**
3636
* Specifies the Android user in which target URIs should be resolved.
3737
*
38-
* <p>{@link UserHandle} can't reasonably be encoded in a target URI string. Instead, all
39-
* {@link io.grpc.NameResolverProvider}s producing {@link AndroidComponentAddress}es should let
40-
* clients address servers in another Android user using this argument.
38+
* <p>{@link UserHandle} can't reasonably be encoded in a target URI string. Instead, all {@link
39+
* io.grpc.NameResolverProvider}s producing {@link AndroidComponentAddress}es should let clients
40+
* address servers in another Android user using this argument.
4141
*
42-
* <p>See also {@link AndroidComponentAddress#getTargetUser()}.
42+
* <p>Connecting to a server in a different Android user is uncommon and can only be done by a
43+
* "system app" client with special permissions. See {@link
44+
* AndroidComponentAddress.Builder#setTargetUser(UserHandle)} for details.
4345
*/
46+
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/10173")
4447
public static final NameResolver.Args.Key<UserHandle> TARGET_ANDROID_USER =
4548
NameResolver.Args.Key.create("target-android-user");
4649
}

binder/src/main/java/io/grpc/binder/BinderChannelBuilder.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,9 @@ public BinderChannelBuilder securityPolicy(SecurityPolicy securityPolicy) {
242242
* specify a {@link UserHandle}. If neither the Channel nor the {@link AndroidComponentAddress}
243243
* specifies a target user, the {@link UserHandle} of the current process will be used.
244244
*
245-
* <p>Targeting a Service in a different Android user is uncommon and requires special permissions
246-
* normally reserved for system apps. See {@link android.content.Context#bindServiceAsUser} for
247-
* details.
245+
* <p>Connecting to a server in a different Android user is uncommon and can only be done by a
246+
* "system app" client with special permissions. See {@link
247+
* AndroidComponentAddress.Builder#setTargetUser(UserHandle)} for details.
248248
*
249249
* @deprecated This method's name is misleading because it implies an impersonated client identity
250250
* when it's actually specifying part of the server's location. It's also no longer necessary
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/*
2+
* Copyright 2025 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.census;
18+
19+
import com.google.common.base.Stopwatch;
20+
import com.google.common.base.Supplier;
21+
import io.grpc.ClientInterceptor;
22+
import io.grpc.ExperimentalApi;
23+
import io.grpc.ManagedChannelBuilder;
24+
import io.grpc.ServerBuilder;
25+
import io.grpc.ServerStreamTracer;
26+
import io.opencensus.trace.Tracing;
27+
28+
/**
29+
* The entrypoint for OpenCensus instrumentation functionality in gRPC.
30+
*
31+
* <p>GrpcCensus uses {@link io.opencensus.api.OpenCensus} APIs for instrumentation.
32+
*
33+
*/
34+
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/12178")
35+
public final class GrpcCensus {
36+
37+
private final boolean statsEnabled;
38+
private final boolean tracingEnabled;
39+
40+
private GrpcCensus(Builder builder) {
41+
this.statsEnabled = builder.statsEnabled;
42+
this.tracingEnabled = builder.tracingEnabled;
43+
}
44+
45+
/**
46+
* Creates a new builder for {@link GrpcCensus}.
47+
*/
48+
public static Builder newBuilder() {
49+
return new Builder();
50+
}
51+
52+
private static final Supplier<Stopwatch> STOPWATCH_SUPPLIER = new Supplier<Stopwatch>() {
53+
@Override
54+
public Stopwatch get() {
55+
return Stopwatch.createUnstarted();
56+
}
57+
};
58+
59+
/**
60+
* Configures a {@link ServerBuilder} to enable census stats and tracing.
61+
*
62+
* @param serverBuilder The server builder to configure.
63+
* @return The configured server builder.
64+
*/
65+
public <T extends ServerBuilder<T>> T configureServerBuilder(T serverBuilder) {
66+
if (statsEnabled) {
67+
serverBuilder.addStreamTracerFactory(newServerStatsStreamTracerFactory());
68+
}
69+
if (tracingEnabled) {
70+
serverBuilder.addStreamTracerFactory(newServerTracingStreamTracerFactory());
71+
}
72+
return serverBuilder;
73+
}
74+
75+
/**
76+
* Configures a {@link ManagedChannelBuilder} to enable census stats and tracing.
77+
*
78+
* @param channelBuilder The channel builder to configure.
79+
* @return The configured channel builder.
80+
*/
81+
public <T extends ManagedChannelBuilder<T>> T configureChannelBuilder(T channelBuilder) {
82+
if (statsEnabled) {
83+
channelBuilder.intercept(newClientStatsInterceptor());
84+
}
85+
if (tracingEnabled) {
86+
channelBuilder.intercept(newClientTracingInterceptor());
87+
}
88+
return channelBuilder;
89+
}
90+
91+
/**
92+
* Returns a {@link ClientInterceptor} with default stats implementation.
93+
*/
94+
private static ClientInterceptor newClientStatsInterceptor() {
95+
CensusStatsModule censusStats =
96+
new CensusStatsModule(
97+
STOPWATCH_SUPPLIER,
98+
true,
99+
true,
100+
true,
101+
false,
102+
true);
103+
return censusStats.getClientInterceptor();
104+
}
105+
106+
/**
107+
* Returns a {@link ClientInterceptor} with default tracing implementation.
108+
*/
109+
private static ClientInterceptor newClientTracingInterceptor() {
110+
CensusTracingModule censusTracing =
111+
new CensusTracingModule(
112+
Tracing.getTracer(),
113+
Tracing.getPropagationComponent().getBinaryFormat());
114+
return censusTracing.getClientInterceptor();
115+
}
116+
117+
/**
118+
* Returns a {@link ServerStreamTracer.Factory} with default stats implementation.
119+
*/
120+
private static ServerStreamTracer.Factory newServerStatsStreamTracerFactory() {
121+
CensusStatsModule censusStats =
122+
new CensusStatsModule(
123+
STOPWATCH_SUPPLIER,
124+
true,
125+
true,
126+
true,
127+
false,
128+
true);
129+
return censusStats.getServerTracerFactory();
130+
}
131+
132+
/**
133+
* Returns a {@link ServerStreamTracer.Factory} with default tracing implementation.
134+
*/
135+
private static ServerStreamTracer.Factory newServerTracingStreamTracerFactory() {
136+
CensusTracingModule censusTracing =
137+
new CensusTracingModule(
138+
Tracing.getTracer(),
139+
Tracing.getPropagationComponent().getBinaryFormat());
140+
return censusTracing.getServerTracerFactory();
141+
}
142+
143+
/**
144+
* Builder for {@link GrpcCensus}.
145+
*/
146+
public static final class Builder {
147+
private boolean statsEnabled = true;
148+
private boolean tracingEnabled = true;
149+
150+
private Builder() {
151+
}
152+
153+
/**
154+
* Disables stats collection.
155+
*/
156+
public Builder disableStats() {
157+
this.statsEnabled = false;
158+
return this;
159+
}
160+
161+
/**
162+
* Disables tracing.
163+
*/
164+
public Builder disableTracing() {
165+
this.tracingEnabled = false;
166+
return this;
167+
}
168+
169+
/**
170+
* Builds a new {@link GrpcCensus}.
171+
*/
172+
public GrpcCensus build() {
173+
return new GrpcCensus(this);
174+
}
175+
}
176+
}

core/src/main/java/io/grpc/internal/ServerImplBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public static ServerBuilder<?> forPort(int port) {
9999
ServerCallExecutorSupplier executorSupplier;
100100

101101
/**
102-
* An interface to provide to provide transport specific information for the server. This method
102+
* An interface to provide transport specific information for the server. This method
103103
* is meant for Transport implementors and should not be used by normal users.
104104
*/
105105
public interface ClientTransportServersBuilder {

rls/src/main/java/io/grpc/rls/CachingRlsLbClient.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,13 @@ void init() {
255255
}
256256
}
257257

258+
Status acceptResolvedAddressFactory(ResolvedAddressFactory childLbResolvedAddressFactory) {
259+
synchronized (lock) {
260+
return refCountedChildPolicyWrapperFactory.acceptResolvedAddressFactory(
261+
childLbResolvedAddressFactory);
262+
}
263+
}
264+
258265
/**
259266
* Convert the status to UNAVAILABLE and enhance the error message.
260267
* @param status status as provided by server

rls/src/main/java/io/grpc/rls/LbPolicyConfiguration.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import io.grpc.LoadBalancerProvider;
3232
import io.grpc.LoadBalancerRegistry;
3333
import io.grpc.NameResolver.ConfigOrError;
34+
import io.grpc.Status;
3435
import io.grpc.internal.ObjectPool;
3536
import io.grpc.rls.ChildLoadBalancerHelper.ChildLoadBalancerHelperProvider;
3637
import io.grpc.rls.RlsProtoData.RouteLookupConfig;
@@ -211,7 +212,7 @@ static final class RefCountedChildPolicyWrapperFactory {
211212
private final ChildLoadBalancerHelperProvider childLbHelperProvider;
212213
private final ChildLbStatusListener childLbStatusListener;
213214
private final ChildLoadBalancingPolicy childPolicy;
214-
private final ResolvedAddressFactory childLbResolvedAddressFactory;
215+
private ResolvedAddressFactory childLbResolvedAddressFactory;
215216

216217
public RefCountedChildPolicyWrapperFactory(
217218
ChildLoadBalancingPolicy childPolicy,
@@ -229,6 +230,19 @@ void init() {
229230
childLbHelperProvider.init();
230231
}
231232

233+
Status acceptResolvedAddressFactory(ResolvedAddressFactory childLbResolvedAddressFactory) {
234+
this.childLbResolvedAddressFactory = childLbResolvedAddressFactory;
235+
Status status = Status.OK;
236+
for (RefCountedChildPolicyWrapper wrapper : childPolicyMap.values()) {
237+
Status newStatus =
238+
wrapper.childPolicyWrapper.acceptResolvedAddressFactory(childLbResolvedAddressFactory);
239+
if (!newStatus.isOk()) {
240+
status = newStatus;
241+
}
242+
}
243+
return status;
244+
}
245+
232246
ChildPolicyWrapper createOrGet(String target) {
233247
// TODO(creamsoup) check if the target is valid or not
234248
RefCountedChildPolicyWrapper pooledChildPolicyWrapper = childPolicyMap.get(target);
@@ -277,6 +291,7 @@ static final class ChildPolicyWrapper {
277291
private final String target;
278292
private final ChildPolicyReportingHelper helper;
279293
private final LoadBalancer lb;
294+
private final Object childLbConfig;
280295
private volatile SubchannelPicker picker;
281296
private ConnectivityState state;
282297

@@ -295,21 +310,26 @@ public ChildPolicyWrapper(
295310
.parseLoadBalancingPolicyConfig(
296311
childPolicy.getEffectiveChildPolicy(target));
297312
this.lb = lbProvider.newLoadBalancer(helper);
313+
this.childLbConfig = lbConfig.getConfig();
298314
helper.getChannelLogger().log(
299-
ChannelLogLevel.DEBUG, "RLS child lb created. config: {0}", lbConfig.getConfig());
315+
ChannelLogLevel.DEBUG, "RLS child lb created. config: {0}", childLbConfig);
300316
helper.getSynchronizationContext().execute(
301317
new Runnable() {
302318
@Override
303319
public void run() {
304-
if (!lb.acceptResolvedAddresses(
305-
childLbResolvedAddressFactory.create(lbConfig.getConfig())).isOk()) {
320+
if (!acceptResolvedAddressFactory(childLbResolvedAddressFactory).isOk()) {
306321
helper.refreshNameResolution();
307322
}
308323
lb.requestConnection();
309324
}
310325
});
311326
}
312327

328+
Status acceptResolvedAddressFactory(ResolvedAddressFactory childLbResolvedAddressFactory) {
329+
helper.getSynchronizationContext().throwIfNotInThisSynchronizationContext();
330+
return lb.acceptResolvedAddresses(childLbResolvedAddressFactory.create(childLbConfig));
331+
}
332+
313333
String getTarget() {
314334
return target;
315335
}

rls/src/main/java/io/grpc/rls/RlsLoadBalancer.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,9 @@ public Status acceptResolvedAddresses(ResolvedAddresses resolvedAddresses) {
7979
// not required.
8080
this.lbPolicyConfiguration = lbPolicyConfiguration;
8181
}
82-
return Status.OK;
82+
return routeLookupClient.acceptResolvedAddressFactory(
83+
new ChildLbResolvedAddressFactory(
84+
resolvedAddresses.getAddresses(), resolvedAddresses.getAttributes()));
8385
}
8486

8587
@Override

xds/src/main/java/io/grpc/xds/XdsNameResolver.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -823,6 +823,9 @@ private void updateRoutes(
823823
if (shouldUpdateResult && routingConfig != null) {
824824
updateResolutionResult(xdsConfig);
825825
shouldUpdateResult = false;
826+
} else {
827+
// Need to update at least once
828+
shouldUpdateResult = true;
826829
}
827830
// Make newly added clusters selectable by config selector and deleted clusters no longer
828831
// selectable.
@@ -993,7 +996,8 @@ private ClusterRefState(
993996
.put("routeLookupConfig", rlsPluginConfig.config())
994997
.put(
995998
"childPolicy",
996-
ImmutableList.of(ImmutableMap.of(XdsLbPolicies.CDS_POLICY_NAME, ImmutableMap.of())))
999+
ImmutableList.of(ImmutableMap.of(XdsLbPolicies.CDS_POLICY_NAME, ImmutableMap.of(
1000+
"is_dynamic", true))))
9971001
.put("childPolicyConfigTargetFieldName", "cluster")
9981002
.buildOrThrow();
9991003
return ImmutableMap.of("rls_experimental", rlsConfig);

0 commit comments

Comments
 (0)