Skip to content

Commit bdaf027

Browse files
committed
Merge branch 'master' into StatusOr-remove-nullable-from-value
2 parents 3b562e1 + d163c06 commit bdaf027

File tree

46 files changed

+1112
-79
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1112
-79
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ public final class EquivalentAddressGroup {
5050
@ExperimentalApi("https://github.com/grpc/grpc-java/issues/6138")
5151
public static final Attributes.Key<String> ATTR_AUTHORITY_OVERRIDE =
5252
Attributes.Key.create("io.grpc.EquivalentAddressGroup.ATTR_AUTHORITY_OVERRIDE");
53+
/**
54+
* The name of the locality that this EquivalentAddressGroup is in.
55+
*/
56+
public static final Attributes.Key<String> ATTR_LOCALITY_NAME =
57+
Attributes.Key.create("io.grpc.EquivalentAddressGroup.LOCALITY");
5358
private final List<SocketAddress> addrs;
5459
private final Attributes attrs;
5560

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
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;
18+
19+
import java.util.List;
20+
21+
/**
22+
* Represents a long-valued up down counter metric instrument.
23+
*/
24+
@Internal
25+
public final class LongUpDownCounterMetricInstrument extends PartialMetricInstrument {
26+
public LongUpDownCounterMetricInstrument(int index, String name, String description, String unit,
27+
List<String> requiredLabelKeys,
28+
List<String> optionalLabelKeys,
29+
boolean enableByDefault) {
30+
super(index, name, description, unit, requiredLabelKeys, optionalLabelKeys, enableByDefault);
31+
}
32+
}

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,47 @@ public LongCounterMetricInstrument registerLongCounter(String name,
144144
}
145145
}
146146

147+
/**
148+
* Registers a new Long Up Down Counter metric instrument.
149+
*
150+
* @param name the name of the metric
151+
* @param description a description of the metric
152+
* @param unit the unit of measurement for the metric
153+
* @param requiredLabelKeys a list of required label keys
154+
* @param optionalLabelKeys a list of optional label keys
155+
* @param enableByDefault whether the metric should be enabled by default
156+
* @return the newly created LongUpDownCounterMetricInstrument
157+
* @throws IllegalStateException if a metric with the same name already exists
158+
*/
159+
public LongUpDownCounterMetricInstrument registerLongUpDownCounter(String name,
160+
String description,
161+
String unit,
162+
List<String> requiredLabelKeys,
163+
List<String> optionalLabelKeys,
164+
boolean enableByDefault) {
165+
checkArgument(!Strings.isNullOrEmpty(name), "missing metric name");
166+
checkNotNull(description, "description");
167+
checkNotNull(unit, "unit");
168+
checkNotNull(requiredLabelKeys, "requiredLabelKeys");
169+
checkNotNull(optionalLabelKeys, "optionalLabelKeys");
170+
synchronized (lock) {
171+
if (registeredMetricNames.contains(name)) {
172+
throw new IllegalStateException("Metric with name " + name + " already exists");
173+
}
174+
int index = nextAvailableMetricIndex;
175+
if (index + 1 == metricInstruments.length) {
176+
resizeMetricInstruments();
177+
}
178+
LongUpDownCounterMetricInstrument instrument = new LongUpDownCounterMetricInstrument(
179+
index, name, description, unit, requiredLabelKeys, optionalLabelKeys,
180+
enableByDefault);
181+
metricInstruments[index] = instrument;
182+
registeredMetricNames.add(name);
183+
nextAvailableMetricIndex += 1;
184+
return instrument;
185+
}
186+
}
187+
147188
/**
148189
* Registers a new Double Histogram metric instrument.
149190
*

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ default void addDoubleCounter(DoubleCounterMetricInstrument metricInstrument, do
5050
* Adds a value for a long valued counter metric instrument.
5151
*
5252
* @param metricInstrument The counter metric instrument to add the value against.
53-
* @param value The value to add.
53+
* @param value The value to add. MUST be non-negative.
5454
* @param requiredLabelValues A list of required label values for the metric.
5555
* @param optionalLabelValues A list of additional, optional label values for the metric.
5656
*/
@@ -66,6 +66,29 @@ default void addLongCounter(LongCounterMetricInstrument metricInstrument, long v
6666
metricInstrument.getOptionalLabelKeys().size());
6767
}
6868

69+
/**
70+
* Adds a value for a long valued up down counter metric instrument.
71+
*
72+
* @param metricInstrument The counter metric instrument to add the value against.
73+
* @param value The value to add. May be positive, negative or zero.
74+
* @param requiredLabelValues A list of required label values for the metric.
75+
* @param optionalLabelValues A list of additional, optional label values for the metric.
76+
*/
77+
default void addLongUpDownCounter(LongUpDownCounterMetricInstrument metricInstrument,
78+
long value,
79+
List<String> requiredLabelValues,
80+
List<String> optionalLabelValues) {
81+
checkArgument(requiredLabelValues != null
82+
&& requiredLabelValues.size() == metricInstrument.getRequiredLabelKeys().size(),
83+
"Incorrect number of required labels provided. Expected: %s",
84+
metricInstrument.getRequiredLabelKeys().size());
85+
checkArgument(optionalLabelValues != null
86+
&& optionalLabelValues.size() == metricInstrument.getOptionalLabelKeys().size(),
87+
"Incorrect number of optional labels provided. Expected: %s",
88+
metricInstrument.getOptionalLabelKeys().size());
89+
}
90+
91+
6992
/**
7093
* Records a value for a double-precision histogram metric instrument.
7194
*

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

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,26 @@ default void addDoubleCounter(DoubleCounterMetricInstrument metricInstrument, do
6565
* Adds a value for a long valued counter metric associated with specified metric instrument.
6666
*
6767
* @param metricInstrument The counter metric instrument identifies metric measure to add.
68-
* @param value The value to record.
68+
* @param value The value to record. MUST be non-negative.
6969
* @param requiredLabelValues A list of required label values for the metric.
7070
* @param optionalLabelValues A list of additional, optional label values for the metric.
7171
*/
7272
default void addLongCounter(LongCounterMetricInstrument metricInstrument, long value,
73-
List<String> requiredLabelValues, List<String> optionalLabelValues) {
73+
List<String> requiredLabelValues, List<String> optionalLabelValues) {
74+
}
75+
76+
/**
77+
* Adds a value for a long valued up down counter metric associated with specified metric
78+
* instrument.
79+
*
80+
* @param metricInstrument The counter metric instrument identifies metric measure to add.
81+
* @param value The value to record. May be positive, negative or zero.
82+
* @param requiredLabelValues A list of required label values for the metric.
83+
* @param optionalLabelValues A list of additional, optional label values for the metric.
84+
*/
85+
default void addLongUpDownCounter(LongUpDownCounterMetricInstrument metricInstrument, long value,
86+
List<String> requiredLabelValues,
87+
List<String> optionalLabelValues) {
7488
}
7589

7690
/**

binder/src/main/java/io/grpc/binder/internal/BinderClientTransport.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ protected void handleSetupTransport(Parcel parcel) {
339339
shutdownInternal(
340340
Status.UNAVAILABLE.withDescription("Malformed SETUP_TRANSPORT data"), true);
341341
} else {
342+
restrictIncomingBinderToCallsFrom(remoteUid);
342343
attributes = setSecurityAttrs(attributes, remoteUid);
343344
authResultFuture = checkServerAuthorizationAsync(remoteUid);
344345
Futures.addCallback(

binder/src/main/java/io/grpc/binder/internal/BinderTransport.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static com.google.common.base.Preconditions.checkNotNull;
2020
import static com.google.common.base.Preconditions.checkState;
2121
import static com.google.common.util.concurrent.Futures.immediateFuture;
22+
import static io.grpc.binder.internal.TransactionUtils.newCallerFilteringHandler;
2223

2324
import android.os.DeadObjectException;
2425
import android.os.IBinder;
@@ -31,12 +32,15 @@
3132
import com.google.common.util.concurrent.ListenableFuture;
3233
import com.google.errorprone.annotations.concurrent.GuardedBy;
3334
import io.grpc.Attributes;
35+
import io.grpc.Grpc;
3436
import io.grpc.Internal;
37+
import io.grpc.InternalChannelz;
3538
import io.grpc.InternalChannelz.SocketStats;
3639
import io.grpc.InternalLogId;
3740
import io.grpc.Status;
3841
import io.grpc.StatusException;
3942
import io.grpc.binder.InboundParcelablePolicy;
43+
import io.grpc.binder.internal.LeakSafeOneWayBinder.TransactionHandler;
4044
import io.grpc.internal.ObjectPool;
4145
import java.util.ArrayList;
4246
import java.util.Iterator;
@@ -153,6 +157,7 @@ protected enum TransportState {
153157
private final ObjectPool<ScheduledExecutorService> executorServicePool;
154158
private final ScheduledExecutorService scheduledExecutorService;
155159
private final InternalLogId logId;
160+
@GuardedBy("this")
156161
private final LeakSafeOneWayBinder incomingBinder;
157162

158163
protected final ConcurrentHashMap<Integer, Inbound<?>> ongoingCalls;
@@ -205,7 +210,15 @@ public final ScheduledExecutorService getScheduledExecutorService() {
205210

206211
// Override in child class.
207212
public final ListenableFuture<SocketStats> getStats() {
208-
return immediateFuture(null);
213+
Attributes attributes = getAttributes();
214+
return immediateFuture(
215+
new InternalChannelz.SocketStats(
216+
/* data= */ null, // TODO: Keep track of these stats with TransportTracer or similar.
217+
/* local= */ attributes.get(Grpc.TRANSPORT_ATTR_LOCAL_ADDR),
218+
/* remote= */ attributes.get(Grpc.TRANSPORT_ATTR_REMOTE_ADDR),
219+
// TODO: SocketOptions are meaningless for binder but we're still forced to provide one.
220+
new InternalChannelz.SocketOptions.Builder().build(),
221+
/* security= */ null));
209222
}
210223

211224
// Override in child class.
@@ -466,6 +479,15 @@ private boolean handleTransactionInternal(int code, Parcel parcel) {
466479
}
467480
}
468481

482+
@BinderThread
483+
@GuardedBy("this")
484+
protected void restrictIncomingBinderToCallsFrom(int allowedCallingUid) {
485+
TransactionHandler currentHandler = incomingBinder.getHandler();
486+
if (currentHandler != null) {
487+
incomingBinder.setHandler(newCallerFilteringHandler(allowedCallingUid, currentHandler));
488+
}
489+
}
490+
469491
@Nullable
470492
@GuardedBy("this")
471493
protected Inbound<?> createInbound(int callId) {
@@ -551,6 +573,11 @@ Map<Integer, Inbound<?>> getOngoingCalls() {
551573
return ongoingCalls;
552574
}
553575

576+
@VisibleForTesting
577+
LeakSafeOneWayBinder getIncomingBinderForTesting() {
578+
return this.incomingBinder;
579+
}
580+
554581
private static Status statusFromRemoteException(RemoteException e) {
555582
if (e instanceof DeadObjectException || e instanceof TransactionTooLargeException) {
556583
// These are to be expected from time to time and can simply be retried.

binder/src/main/java/io/grpc/binder/internal/LeakSafeOneWayBinder.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,21 @@ public void detach() {
7373
setHandler(null);
7474
}
7575

76-
/** Replaces the current {@link TransactionHandler} with `handler`. */
76+
/** Returns the current {@link TransactionHandler} or null if already detached. */
77+
public @Nullable TransactionHandler getHandler() {
78+
return handler;
79+
}
80+
81+
/**
82+
* Replaces the current {@link TransactionHandler} with `handler`.
83+
*
84+
* <p>{@link TransactionHandler} mutations race against incoming transactions except in the
85+
* special case where the caller is already handling an incoming transaction on this same {@link
86+
* LeakSafeOneWayBinder} instance. In that case, mutations are safe and the provided 'handler' is
87+
* guaranteed to be used for the very next transaction. This follows from the one-at-a-time
88+
* property of one-way Binder transactions as explained by {@link
89+
* TransactionHandler#handleTransaction}.
90+
*/
7791
public void setHandler(@Nullable TransactionHandler handler) {
7892
this.handler = handler;
7993
}

binder/src/main/java/io/grpc/binder/internal/TransactionUtils.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@
1616

1717
package io.grpc.binder.internal;
1818

19+
import android.os.Binder;
1920
import android.os.Parcel;
2021
import io.grpc.MethodDescriptor.MethodType;
2122
import io.grpc.Status;
23+
import java.util.logging.Level;
24+
import java.util.logging.Logger;
25+
import io.grpc.binder.internal.LeakSafeOneWayBinder.TransactionHandler;
2226
import javax.annotation.Nullable;
2327

2428
/** Constants and helpers for managing inbound / outbound transactions. */
@@ -99,4 +103,24 @@ static void fillInFlags(Parcel parcel, int flags) {
99103
parcel.writeInt(flags);
100104
parcel.setDataPosition(pos);
101105
}
106+
107+
/**
108+
* Decorates the given {@link TransactionHandler} with a wrapper that only forwards transactions
109+
* from the given `allowedCallingUid`.
110+
*/
111+
static TransactionHandler newCallerFilteringHandler(
112+
int allowedCallingUid, TransactionHandler wrapped) {
113+
final Logger logger = Logger.getLogger(TransactionUtils.class.getName());
114+
return new TransactionHandler() {
115+
@Override
116+
public boolean handleTransaction(int code, Parcel data) {
117+
int callingUid = Binder.getCallingUid();
118+
if (callingUid != allowedCallingUid) {
119+
logger.log(Level.WARNING, "dropped txn from " + callingUid + " !=" + allowedCallingUid);
120+
return false;
121+
}
122+
return wrapped.handleTransaction(code, data);
123+
}
124+
};
125+
}
102126
}

0 commit comments

Comments
 (0)