16
16
17
17
package io .grpc .binder .internal ;
18
18
19
+ import static android .os .IBinder .FLAG_ONEWAY ;
19
20
import static com .google .common .base .Preconditions .checkNotNull ;
21
+ import static io .grpc .binder .internal .BinderTransport .SHUTDOWN_TRANSPORT ;
20
22
21
23
import android .os .Binder ;
22
24
import android .os .IBinder ;
23
25
import android .os .Parcel ;
26
+ import android .os .RemoteException ;
24
27
import com .google .common .collect .ImmutableList ;
25
28
import io .grpc .Attributes ;
26
29
import io .grpc .Grpc ;
41
44
import java .net .SocketAddress ;
42
45
import java .util .List ;
43
46
import java .util .concurrent .ScheduledExecutorService ;
47
+ import java .util .logging .Level ;
48
+ import java .util .logging .Logger ;
44
49
import javax .annotation .Nullable ;
45
50
import javax .annotation .concurrent .GuardedBy ;
46
51
import javax .annotation .concurrent .ThreadSafe ;
55
60
*/
56
61
@ ThreadSafe
57
62
public final class BinderServer implements InternalServer , LeakSafeOneWayBinder .TransactionHandler {
63
+ private static final Logger logger = Logger .getLogger (BinderServer .class .getName ());
58
64
59
65
private final ObjectPool <ScheduledExecutorService > executorServicePool ;
60
66
private final ImmutableList <ServerStreamTracer .Factory > streamTracerFactories ;
@@ -121,7 +127,7 @@ public synchronized void shutdown() {
121
127
if (!shutdown ) {
122
128
shutdown = true ;
123
129
// Break the connection to the binder. We'll receive no more transactions.
124
- hostServiceBinder .detach ( );
130
+ hostServiceBinder .setHandler ( GoAwayHandler . INSTANCE );
125
131
listener .serverShutdown ();
126
132
executorService = executorServicePool .returnObject (executorService );
127
133
transportSecurityShutdownListener .onServerShutdown ();
@@ -136,6 +142,12 @@ public String toString() {
136
142
@ Override
137
143
public synchronized boolean handleTransaction (int code , Parcel parcel ) {
138
144
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
+
139
151
int version = parcel .readInt ();
140
152
// If the client-provided version is more recent, we accept the connection,
141
153
// but specify the older version which we support.
@@ -165,6 +177,28 @@ public synchronized boolean handleTransaction(int code, Parcel parcel) {
165
177
return false ;
166
178
}
167
179
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
+
168
202
/** Fluent builder of {@link BinderServer} instances. */
169
203
public static class Builder {
170
204
@ Nullable AndroidComponentAddress listenAddress ;
0 commit comments