Skip to content

Commit 1670e97

Browse files
authoredJun 6, 2024··
Reject further SETUP_TRANSPORT requests post-BinderServer shutdown (#11260)
Fixes #8931
1 parent a28357e commit 1670e97

File tree

4 files changed

+79
-22
lines changed

4 files changed

+79
-22
lines changed
 

‎binder/src/androidTest/java/io/grpc/binder/internal/BinderTransportTest.java

-5
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,6 @@ public void socketStats() throws Exception {}
122122
@Override
123123
public void flowControlPushBack() throws Exception {}
124124

125-
@Test
126-
@Ignore("Not yet implemented. See https://github.com/grpc/grpc-java/issues/8931")
127-
@Override
128-
public void serverNotListening() throws Exception {}
129-
130125
@Test
131126
@Ignore("This test isn't appropriate for BinderTransport.")
132127
@Override

‎binder/src/androidTest/java/io/grpc/binder/internal/LeakSafeOneWayBinderTest.java

+36-15
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import android.os.Parcel;
2323
import androidx.test.ext.junit.runners.AndroidJUnit4;
24+
import io.grpc.binder.internal.LeakSafeOneWayBinder.TransactionHandler;
2425
import org.junit.Before;
2526
import org.junit.Test;
2627
import org.junit.runner.RunWith;
@@ -29,28 +30,34 @@
2930
public final class LeakSafeOneWayBinderTest {
3031

3132
private LeakSafeOneWayBinder binder;
33+
private final FakeHandler handler = new FakeHandler();
3234

33-
private int transactionsHandled;
34-
private int lastCode;
35-
private Parcel lastParcel;
35+
static class FakeHandler implements TransactionHandler {
36+
int transactionsHandled;
37+
int lastCode;
38+
Parcel lastParcel;
3639

37-
@Before
38-
public void setUp() {
39-
binder = new LeakSafeOneWayBinder((code, parcel) -> {
40+
@Override
41+
public boolean handleTransaction(int code, Parcel parcel) {
4042
transactionsHandled++;
4143
lastCode = code;
4244
lastParcel = parcel;
4345
return true;
44-
});
46+
}
47+
}
48+
49+
@Before
50+
public void setUp() {
51+
binder = new LeakSafeOneWayBinder(handler);
4552
}
4653

4754
@Test
4855
public void testTransaction() {
4956
Parcel p = Parcel.obtain();
5057
assertThat(binder.onTransact(123, p, null, FLAG_ONEWAY)).isTrue();
51-
assertThat(transactionsHandled).isEqualTo(1);
52-
assertThat(lastCode).isEqualTo(123);
53-
assertThat(lastParcel).isSameInstanceAs(p);
58+
assertThat(handler.transactionsHandled).isEqualTo(1);
59+
assertThat(handler.lastCode).isEqualTo(123);
60+
assertThat(handler.lastParcel).isSameInstanceAs(p);
5461
p.recycle();
5562
}
5663

@@ -59,7 +66,7 @@ public void testDropsTwoWayTransactions() {
5966
Parcel p = Parcel.obtain();
6067
Parcel reply = Parcel.obtain();
6168
assertThat(binder.onTransact(123, p, reply, 0)).isFalse();
62-
assertThat(transactionsHandled).isEqualTo(0);
69+
assertThat(handler.transactionsHandled).isEqualTo(0);
6370
p.recycle();
6471
reply.recycle();
6572
}
@@ -71,7 +78,21 @@ public void testDetach() {
7178
assertThat(binder.onTransact(456, p, null, FLAG_ONEWAY)).isFalse();
7279

7380
// The transaction shouldn't have been processed.
74-
assertThat(transactionsHandled).isEqualTo(0);
81+
assertThat(handler.transactionsHandled).isEqualTo(0);
82+
83+
p.recycle();
84+
}
85+
86+
@Test
87+
public void testReplace() {
88+
binder = new LeakSafeOneWayBinder(handler);
89+
Parcel p = Parcel.obtain();
90+
FakeHandler handler2 = new FakeHandler();
91+
binder.setHandler(handler2);
92+
assertThat(binder.onTransact(456, p, null, FLAG_ONEWAY)).isTrue();
93+
94+
assertThat(handler.transactionsHandled).isEqualTo(0);
95+
assertThat(handler2.transactionsHandled).isEqualTo(1);
7596

7697
p.recycle();
7798
}
@@ -81,9 +102,9 @@ public void testMultipleTransactions() {
81102
Parcel p = Parcel.obtain();
82103
assertThat(binder.onTransact(123, p, null, FLAG_ONEWAY)).isTrue();
83104
assertThat(binder.onTransact(456, p, null, FLAG_ONEWAY)).isTrue();
84-
assertThat(transactionsHandled).isEqualTo(2);
85-
assertThat(lastCode).isEqualTo(456);
86-
assertThat(lastParcel).isSameInstanceAs(p);
105+
assertThat(handler.transactionsHandled).isEqualTo(2);
106+
assertThat(handler.lastCode).isEqualTo(456);
107+
assertThat(handler.lastParcel).isSameInstanceAs(p);
87108
p.recycle();
88109
}
89110

‎binder/src/main/java/io/grpc/binder/internal/BinderServer.java

+35-1
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@
1616

1717
package io.grpc.binder.internal;
1818

19+
import static android.os.IBinder.FLAG_ONEWAY;
1920
import static com.google.common.base.Preconditions.checkNotNull;
21+
import static io.grpc.binder.internal.BinderTransport.SHUTDOWN_TRANSPORT;
2022

2123
import android.os.Binder;
2224
import android.os.IBinder;
2325
import android.os.Parcel;
26+
import android.os.RemoteException;
2427
import com.google.common.collect.ImmutableList;
2528
import io.grpc.Attributes;
2629
import io.grpc.Grpc;
@@ -41,6 +44,8 @@
4144
import java.net.SocketAddress;
4245
import java.util.List;
4346
import java.util.concurrent.ScheduledExecutorService;
47+
import java.util.logging.Level;
48+
import java.util.logging.Logger;
4449
import javax.annotation.Nullable;
4550
import javax.annotation.concurrent.GuardedBy;
4651
import javax.annotation.concurrent.ThreadSafe;
@@ -55,6 +60,7 @@
5560
*/
5661
@ThreadSafe
5762
public final class BinderServer implements InternalServer, LeakSafeOneWayBinder.TransactionHandler {
63+
private static final Logger logger = Logger.getLogger(BinderServer.class.getName());
5864

5965
private final ObjectPool<ScheduledExecutorService> executorServicePool;
6066
private final ImmutableList<ServerStreamTracer.Factory> streamTracerFactories;
@@ -121,7 +127,7 @@ public synchronized void shutdown() {
121127
if (!shutdown) {
122128
shutdown = true;
123129
// Break the connection to the binder. We'll receive no more transactions.
124-
hostServiceBinder.detach();
130+
hostServiceBinder.setHandler(GoAwayHandler.INSTANCE);
125131
listener.serverShutdown();
126132
executorService = executorServicePool.returnObject(executorService);
127133
transportSecurityShutdownListener.onServerShutdown();
@@ -136,6 +142,12 @@ public String toString() {
136142
@Override
137143
public synchronized boolean handleTransaction(int code, Parcel parcel) {
138144
if (code == BinderTransport.SETUP_TRANSPORT) {
145+
if (shutdown) {
146+
// An incoming SETUP_TRANSPORT transaction may have already been in-flight when we removed
147+
// ourself as TransactionHandler in #shutdown(). So we must check for shutdown again here.
148+
return GoAwayHandler.INSTANCE.handleTransaction(code, parcel);
149+
}
150+
139151
int version = parcel.readInt();
140152
// If the client-provided version is more recent, we accept the connection,
141153
// but specify the older version which we support.
@@ -165,6 +177,28 @@ public synchronized boolean handleTransaction(int code, Parcel parcel) {
165177
return false;
166178
}
167179

180+
static final class GoAwayHandler implements LeakSafeOneWayBinder.TransactionHandler {
181+
static final GoAwayHandler INSTANCE = new GoAwayHandler();
182+
183+
@Override
184+
public boolean handleTransaction(int code, Parcel parcel) {
185+
if (code == BinderTransport.SETUP_TRANSPORT) {
186+
int version = parcel.readInt();
187+
if (version >= BinderTransport.EARLIEST_SUPPORTED_WIRE_FORMAT_VERSION) {
188+
IBinder callbackBinder = parcel.readStrongBinder();
189+
try (ParcelHolder goAwayReply = ParcelHolder.obtain()) {
190+
// Send empty flags to avoid a memory leak linked to empty parcels (b/207778694).
191+
goAwayReply.get().writeInt(0);
192+
callbackBinder.transact(SHUTDOWN_TRANSPORT, goAwayReply.get(), null, FLAG_ONEWAY);
193+
} catch (RemoteException re) {
194+
logger.log(Level.WARNING, "Couldn't reply to post-shutdown() SETUP_TRANSPORT.", re);
195+
}
196+
}
197+
}
198+
return false;
199+
}
200+
}
201+
168202
/** Fluent builder of {@link BinderServer} instances. */
169203
public static class Builder {
170204
@Nullable AndroidComponentAddress listenAddress;

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

+8-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,14 @@ public LeakSafeOneWayBinder(TransactionHandler handler) {
6868
}
6969

7070
public void detach() {
71-
handler = null;
71+
setHandler(null);
72+
}
73+
74+
/**
75+
* Replaces the current {@link TransactionHandler} with `handler`.
76+
*/
77+
public void setHandler(@Nullable TransactionHandler handler) {
78+
this.handler = handler;
7279
}
7380

7481
@Override

0 commit comments

Comments
 (0)
Please sign in to comment.