Skip to content

Commit 53a4385

Browse files
Merge branch 'grpc:master' into Issue_fixed_12142
2 parents 03b453b + 64322c3 commit 53a4385

File tree

48 files changed

+330
-113
lines changed

Some content is hidden

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

48 files changed

+330
-113
lines changed

MODULE.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module(
22
name = "grpc-java",
33
compatibility_level = 0,
44
repo_name = "io_grpc_grpc_java",
5-
version = "1.74.0-SNAPSHOT", # CURRENT_GRPC_VERSION
5+
version = "1.75.0-SNAPSHOT", # CURRENT_GRPC_VERSION
66
)
77

88
# GRPC_DEPS_START

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ For [Bazel](https://bazel.build), you can either
102102
https://search.maven.org/search?q=g:io.grpc%20AND%20v:1.73.0
103103

104104
Development snapshots are available in [Sonatypes's snapshot
105-
repository](https://oss.sonatype.org/content/repositories/snapshots/).
105+
repository](https://central.sonatype.com/repository/maven-snapshots/).
106106

107107
Generated Code
108108
--------------

RELEASING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ Tagging the Release
160160
repository can then be `released`, which will begin the process of pushing
161161
the new artifacts to Maven Central (the staging repository will be destroyed
162162
in the process). You can see the complete process for releasing to Maven
163-
Central on the [OSSRH site](https://central.sonatype.org/pages/releasing-the-deployment.html).
163+
Central on the [OSSRH site](https://central.sonatype.org/publish/publish-portal-ossrh-staging-api/#deploying).
164164

165165
10. We have containers for each release to detect compatibility regressions with
166166
old releases. Generate one for the new release by following the [GCR image

binder/src/androidTest/java/io/grpc/binder/internal/BinderClientTransportTest.java

Lines changed: 34 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,16 @@
1717
package io.grpc.binder.internal;
1818

1919
import static com.google.common.truth.Truth.assertThat;
20+
import static java.util.concurrent.TimeUnit.SECONDS;
2021

2122
import android.content.Context;
2223
import android.os.DeadObjectException;
2324
import android.os.Parcel;
2425
import android.os.RemoteException;
2526
import androidx.test.core.app.ApplicationProvider;
2627
import androidx.test.ext.junit.runners.AndroidJUnit4;
27-
import com.google.common.util.concurrent.Futures;
28-
import com.google.common.util.concurrent.ListenableFuture;
2928
import com.google.common.util.concurrent.SettableFuture;
29+
import com.google.errorprone.annotations.CanIgnoreReturnValue;
3030
import com.google.errorprone.annotations.concurrent.GuardedBy;
3131
import com.google.protobuf.Empty;
3232
import io.grpc.CallOptions;
@@ -38,13 +38,13 @@
3838
import io.grpc.Status;
3939
import io.grpc.Status.Code;
4040
import io.grpc.binder.AndroidComponentAddress;
41-
import io.grpc.binder.AsyncSecurityPolicy;
4241
import io.grpc.binder.BinderServerBuilder;
4342
import io.grpc.binder.HostServices;
4443
import io.grpc.binder.SecurityPolicy;
4544
import io.grpc.binder.internal.OneWayBinderProxies.BlackHoleOneWayBinderProxy;
4645
import io.grpc.binder.internal.OneWayBinderProxies.BlockingBinderDecorator;
4746
import io.grpc.binder.internal.OneWayBinderProxies.ThrowingOneWayBinderProxy;
47+
import io.grpc.binder.internal.SettableAsyncSecurityPolicy.AuthRequest;
4848
import io.grpc.internal.ClientStream;
4949
import io.grpc.internal.ClientStreamListener;
5050
import io.grpc.internal.ClientTransportFactory.ClientTransportOptions;
@@ -63,7 +63,6 @@
6363
import java.util.concurrent.Executors;
6464
import java.util.concurrent.LinkedBlockingQueue;
6565
import java.util.concurrent.ScheduledExecutorService;
66-
import java.util.concurrent.TimeUnit;
6766
import javax.annotation.Nullable;
6867
import org.junit.After;
6968
import org.junit.Before;
@@ -154,17 +153,20 @@ private class BinderClientTransportBuilder {
154153
.setScheduledExecutorPool(executorServicePool)
155154
.setOffloadExecutorPool(offloadServicePool);
156155

156+
@CanIgnoreReturnValue
157157
public BinderClientTransportBuilder setSecurityPolicy(SecurityPolicy securityPolicy) {
158158
factoryBuilder.setSecurityPolicy(securityPolicy);
159159
return this;
160160
}
161161

162+
@CanIgnoreReturnValue
162163
public BinderClientTransportBuilder setBinderDecorator(
163164
OneWayBinderProxy.Decorator binderDecorator) {
164165
factoryBuilder.setBinderDecorator(binderDecorator);
165166
return this;
166167
}
167168

169+
@CanIgnoreReturnValue
168170
public BinderClientTransportBuilder setReadyTimeoutMillis(int timeoutMillis) {
169171
factoryBuilder.setReadyTimeoutMillis(timeoutMillis);
170172
return this;
@@ -189,7 +191,7 @@ public void tearDown() throws Exception {
189191
private static void shutdownAndTerminate(ExecutorService executorService)
190192
throws InterruptedException {
191193
executorService.shutdownNow();
192-
if (!executorService.awaitTermination(TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
194+
if (!executorService.awaitTermination(TIMEOUT_SECONDS, SECONDS)) {
193195
throw new AssertionError("executor failed to terminate promptly");
194196
}
195197
}
@@ -371,26 +373,32 @@ public void testBlackHoleEndpointConnectTimeout() throws Exception {
371373

372374
@Test
373375
public void testBlackHoleSecurityPolicyConnectTimeout() throws Exception {
376+
SettableAsyncSecurityPolicy securityPolicy = new SettableAsyncSecurityPolicy();
374377
transport =
375378
new BinderClientTransportBuilder()
376-
.setSecurityPolicy(blockingSecurityPolicy)
379+
.setSecurityPolicy(securityPolicy)
377380
.setReadyTimeoutMillis(1_234)
378381
.build();
379382
transport.start(transportListener).run();
383+
// Take the next authRequest but don't respond to it, in order to trigger the ready timeout.
384+
AuthRequest authRequest = securityPolicy.takeNextAuthRequest(TIMEOUT_SECONDS, SECONDS);
385+
380386
Status transportStatus = transportListener.awaitShutdown();
381387
assertThat(transportStatus.getCode()).isEqualTo(Code.DEADLINE_EXCEEDED);
382388
assertThat(transportStatus.getDescription()).contains("1234");
383389
transportListener.awaitTermination();
384-
blockingSecurityPolicy.provideNextCheckAuthorizationResult(Status.OK);
390+
391+
// If the transport gave up waiting on auth, it should cancel its request.
392+
assertThat(authRequest.isCancelled()).isTrue();
385393
}
386394

387395
@Test
388396
public void testAsyncSecurityPolicyFailure() throws Exception {
389397
SettableAsyncSecurityPolicy securityPolicy = new SettableAsyncSecurityPolicy();
390398
transport = new BinderClientTransportBuilder().setSecurityPolicy(securityPolicy).build();
391399
RuntimeException exception = new NullPointerException();
392-
securityPolicy.setAuthorizationException(exception);
393400
transport.start(transportListener).run();
401+
securityPolicy.takeNextAuthRequest(TIMEOUT_SECONDS, SECONDS).setResult(exception);
394402
Status transportStatus = transportListener.awaitShutdown();
395403
assertThat(transportStatus.getCode()).isEqualTo(Code.INTERNAL);
396404
assertThat(transportStatus.getCause()).isEqualTo(exception);
@@ -401,13 +409,27 @@ public void testAsyncSecurityPolicyFailure() throws Exception {
401409
public void testAsyncSecurityPolicySuccess() throws Exception {
402410
SettableAsyncSecurityPolicy securityPolicy = new SettableAsyncSecurityPolicy();
403411
transport = new BinderClientTransportBuilder().setSecurityPolicy(securityPolicy).build();
404-
securityPolicy.setAuthorizationResult(Status.PERMISSION_DENIED);
405412
transport.start(transportListener).run();
413+
securityPolicy
414+
.takeNextAuthRequest(TIMEOUT_SECONDS, SECONDS)
415+
.setResult(Status.PERMISSION_DENIED);
406416
Status transportStatus = transportListener.awaitShutdown();
407417
assertThat(transportStatus.getCode()).isEqualTo(Code.PERMISSION_DENIED);
408418
transportListener.awaitTermination();
409419
}
410420

421+
@Test
422+
public void testAsyncSecurityPolicyCancelledUponExternalTermination() throws Exception {
423+
SettableAsyncSecurityPolicy securityPolicy = new SettableAsyncSecurityPolicy();
424+
transport = new BinderClientTransportBuilder().setSecurityPolicy(securityPolicy).build();
425+
transport.start(transportListener).run();
426+
AuthRequest authRequest = securityPolicy.takeNextAuthRequest(TIMEOUT_SECONDS, SECONDS);
427+
transport.shutdownNow(Status.UNAVAILABLE); // 'authRequest' remains unanswered!
428+
transportListener.awaitShutdown();
429+
transportListener.awaitTermination();
430+
assertThat(authRequest.isCancelled()).isTrue();
431+
}
432+
411433
private static void startAndAwaitReady(
412434
BinderTransport.BinderClientTransport transport, TestTransportListener transportListener)
413435
throws Exception {
@@ -429,7 +451,7 @@ public void transportShutdown(Status shutdownStatus) {
429451
}
430452

431453
public Status awaitShutdown() throws Exception {
432-
return shutdownStatus.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
454+
return shutdownStatus.get(TIMEOUT_SECONDS, SECONDS);
433455
}
434456

435457
@Override
@@ -440,7 +462,7 @@ public void transportTerminated() {
440462
}
441463

442464
public void awaitTermination() throws Exception {
443-
isTerminated.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
465+
isTerminated.get(TIMEOUT_SECONDS, SECONDS);
444466
}
445467

446468
@Override
@@ -451,7 +473,7 @@ public void transportReady() {
451473
}
452474

453475
public void awaitReady() throws Exception {
454-
isReady.get(TIMEOUT_SECONDS, TimeUnit.SECONDS);
476+
isReady.get(TIMEOUT_SECONDS, SECONDS);
455477
}
456478

457479
@Override
@@ -567,25 +589,4 @@ public Status checkAuthorization(int uid) {
567589
}
568590
}
569591
}
570-
571-
/** An AsyncSecurityPolicy that lets a test specify the outcome of checkAuthorizationAsync(). */
572-
static class SettableAsyncSecurityPolicy extends AsyncSecurityPolicy {
573-
private SettableFuture<Status> result = SettableFuture.create();
574-
575-
public void clearAuthorizationResult() {
576-
result = SettableFuture.create();
577-
}
578-
579-
public boolean setAuthorizationResult(Status status) {
580-
return result.set(status);
581-
}
582-
583-
public boolean setAuthorizationException(Throwable t) {
584-
return result.setException(t);
585-
}
586-
587-
public ListenableFuture<Status> checkAuthorizationAsync(int uid) {
588-
return Futures.nonCancellationPropagating(result);
589-
}
590-
}
591592
}

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,8 @@ public static final class BinderClientTransport extends BinderTransport
582582

583583
@GuardedBy("this")
584584
private ScheduledFuture<?> readyTimeoutFuture; // != null iff timeout scheduled.
585+
@GuardedBy("this")
586+
@Nullable private ListenableFuture<Status> authResultFuture; // null before we check auth.
585587

586588
/**
587589
* Constructs a new transport instance.
@@ -756,6 +758,9 @@ void notifyTerminated() {
756758
readyTimeoutFuture.cancel(false);
757759
readyTimeoutFuture = null;
758760
}
761+
if (authResultFuture != null) {
762+
authResultFuture.cancel(false); // No effect if already complete.
763+
}
759764
serviceBinding.unbind();
760765
clientTransportListener.transportTerminated();
761766
}
@@ -775,13 +780,13 @@ protected void handleSetupTransport(Parcel parcel) {
775780
shutdownInternal(
776781
Status.UNAVAILABLE.withDescription("Malformed SETUP_TRANSPORT data"), true);
777782
} else {
778-
ListenableFuture<Status> authFuture =
783+
authResultFuture =
779784
(securityPolicy instanceof AsyncSecurityPolicy)
780785
? ((AsyncSecurityPolicy) securityPolicy).checkAuthorizationAsync(remoteUid)
781786
: Futures.submit(
782787
() -> securityPolicy.checkAuthorization(remoteUid), offloadExecutor);
783788
Futures.addCallback(
784-
authFuture,
789+
authResultFuture,
785790
new FutureCallback<Status>() {
786791
@Override
787792
public void onSuccess(Status result) {

binder/src/test/java/io/grpc/binder/SecurityPoliciesTest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ public void testIsDeviceOwner_failsWhenNoPackagesForUid() throws Exception {
357357
}
358358

359359
@Test
360-
@Config(sdk = 21)
360+
@Config(sdk = Config.OLDEST_SDK)
361361
public void testIsProfileOwner_succeedsForProfileOwner() throws Exception {
362362
PackageInfo info =
363363
newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
@@ -371,7 +371,7 @@ public void testIsProfileOwner_succeedsForProfileOwner() throws Exception {
371371
}
372372

373373
@Test
374-
@Config(sdk = 21)
374+
@Config(sdk = Config.OLDEST_SDK)
375375
public void testIsProfileOwner_failsForNotProfileOwner() throws Exception {
376376
PackageInfo info =
377377
newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
@@ -385,7 +385,7 @@ public void testIsProfileOwner_failsForNotProfileOwner() throws Exception {
385385
}
386386

387387
@Test
388-
@Config(sdk = 21)
388+
@Config(sdk = Config.OLDEST_SDK)
389389
public void testIsProfileOwner_failsWhenNoPackagesForUid() throws Exception {
390390
policy = SecurityPolicies.isProfileOwner(appContext);
391391

@@ -425,7 +425,7 @@ public void testIsProfileOwnerOnOrgOwned_failsForProfileOwnerOnNonOrgOwned() thr
425425
}
426426

427427
@Test
428-
@Config(sdk = 21)
428+
@Config(sdk = Config.OLDEST_SDK)
429429
public void testIsProfileOwnerOnOrgOwned_failsForNotProfileOwner() throws Exception {
430430
PackageInfo info =
431431
newBuilder().setPackageName(OTHER_UID_PACKAGE_NAME).setSignatures(SIG2).build();
@@ -439,7 +439,7 @@ public void testIsProfileOwnerOnOrgOwned_failsForNotProfileOwner() throws Except
439439
}
440440

441441
@Test
442-
@Config(sdk = 21)
442+
@Config(sdk = Config.OLDEST_SDK)
443443
public void testIsProfileOwnerOnOrgOwned_failsWhenNoPackagesForUid() throws Exception {
444444
policy = SecurityPolicies.isProfileOwnerOnOrganizationOwnedDevice(appContext);
445445

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
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.binder.internal;
18+
19+
import static com.google.common.base.Preconditions.checkState;
20+
21+
import com.google.common.util.concurrent.ListenableFuture;
22+
import com.google.common.util.concurrent.SettableFuture;
23+
import io.grpc.Status;
24+
import io.grpc.binder.AsyncSecurityPolicy;
25+
import java.util.concurrent.LinkedBlockingDeque;
26+
import java.util.concurrent.TimeUnit;
27+
import java.util.concurrent.TimeoutException;
28+
29+
/**
30+
* An {@link AsyncSecurityPolicy} that lets unit tests verify the exact order of authorization
31+
* requests and respond to them one at a time.
32+
*/
33+
public class SettableAsyncSecurityPolicy extends AsyncSecurityPolicy {
34+
private final LinkedBlockingDeque<AuthRequest> pendingRequests = new LinkedBlockingDeque<>();
35+
36+
@Override
37+
public ListenableFuture<Status> checkAuthorizationAsync(int uid) {
38+
AuthRequest request = new AuthRequest(uid);
39+
pendingRequests.add(request);
40+
return request.resultFuture;
41+
}
42+
43+
/**
44+
* Waits for the next "check authorization" request to be made and returns it, throwing in case no
45+
* request arrives in time.
46+
*/
47+
public AuthRequest takeNextAuthRequest(long timeout, TimeUnit unit)
48+
throws InterruptedException, TimeoutException {
49+
AuthRequest nextAuthRequest = pendingRequests.poll(timeout, unit);
50+
if (nextAuthRequest == null) {
51+
throw new TimeoutException();
52+
}
53+
return nextAuthRequest;
54+
}
55+
56+
/** Represents a single call to {@link AsyncSecurityPolicy#checkAuthorizationAsync(int)}. */
57+
public static class AuthRequest {
58+
59+
/** The argument passed to {@link AsyncSecurityPolicy#checkAuthorizationAsync(int)}. */
60+
public final int uid;
61+
62+
private final SettableFuture<Status> resultFuture = SettableFuture.create();
63+
64+
private AuthRequest(int uid) {
65+
this.uid = uid;
66+
}
67+
68+
/** Provides this SecurityPolicy's response to this authorization request. */
69+
public void setResult(Status result) {
70+
checkState(resultFuture.set(result));
71+
}
72+
73+
/** Simulates an exceptional response to this authorization request. */
74+
public void setResult(Throwable t) {
75+
checkState(resultFuture.setException(t));
76+
}
77+
78+
/** Tests if the future returned for this authorization request was cancelled by the caller. */
79+
public boolean isCancelled() {
80+
return resultFuture.isCancelled();
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)