2525import android .os .IBinder ;
2626import android .os .Parcel ;
2727import android .os .Process ;
28+ import androidx .annotation .BinderThread ;
29+ import androidx .annotation .MainThread ;
2830import com .google .common .base .Ticker ;
2931import com .google .common .util .concurrent .FutureCallback ;
3032import com .google .common .util .concurrent .Futures ;
@@ -72,6 +74,9 @@ public final class BinderClientTransport extends BinderTransport
7274 private final SecurityPolicy securityPolicy ;
7375 private final Bindable serviceBinding ;
7476
77+ @ GuardedBy ("this" )
78+ private final ClientHandshake handshake ;
79+
7580 /** Number of ongoing calls which keep this transport "in-use". */
7681 private final AtomicInteger numInUseStreams ;
7782
@@ -115,6 +120,7 @@ public BinderClientTransport(
115120 Boolean preAuthServerOverride = options .getEagAttributes ().get (PRE_AUTH_SERVER_OVERRIDE );
116121 this .preAuthorizeServer =
117122 preAuthServerOverride != null ? preAuthServerOverride : factory .preAuthorizeServers ;
123+ this .handshake = new LegacyClientHandshake ();
118124 numInUseStreams = new AtomicInteger ();
119125 pingTracker = new PingTracker (Ticker .systemTicker (), (id ) -> sendPing (id ));
120126
@@ -137,7 +143,9 @@ void releaseExecutors() {
137143
138144 @ Override
139145 public synchronized void onBound (IBinder binder ) {
140- sendSetupTransaction (binderDecorator .decorate (OneWayBinderProxy .wrap (binder , offloadExecutor )));
146+ OneWayBinderProxy binderProxy = OneWayBinderProxy .wrap (binder , offloadExecutor );
147+ binderProxy = binderDecorator .decorate (binderProxy );
148+ handshake .onBound (binderProxy );
141149 }
142150
143151 @ Override
@@ -315,7 +323,6 @@ void notifyTerminated() {
315323 @ Override
316324 @ GuardedBy ("this" )
317325 protected void handleSetupTransport (Parcel parcel ) {
318- int remoteUid = Binder .getCallingUid ();
319326 if (inState (TransportState .SETUP )) {
320327 int version = parcel .readInt ();
321328 IBinder binder = parcel .readStrongBinder ();
@@ -325,24 +332,8 @@ protected void handleSetupTransport(Parcel parcel) {
325332 shutdownInternal (
326333 Status .UNAVAILABLE .withDescription ("Malformed SETUP_TRANSPORT data" ), true );
327334 } else {
328- restrictIncomingBinderToCallsFrom (remoteUid );
329- attributes = setSecurityAttrs (attributes , remoteUid );
330- ListenableFuture <Status > authResultFuture =
331- register (checkServerAuthorizationAsync (remoteUid ));
332- Futures .addCallback (
333- authResultFuture ,
334- new FutureCallback <Status >() {
335- @ Override
336- public void onSuccess (Status result ) {
337- handleAuthResult (binder , result );
338- }
339-
340- @ Override
341- public void onFailure (Throwable t ) {
342- handleAuthResult (t );
343- }
344- },
345- offloadExecutor );
335+ OneWayBinderProxy binderProxy = OneWayBinderProxy .wrap (binder , offloadExecutor );
336+ handshake .handleSetupTransport (binderProxy );
346337 }
347338 }
348339 }
@@ -353,29 +344,71 @@ private ListenableFuture<Status> checkServerAuthorizationAsync(int remoteUid) {
353344 : Futures .submit (() -> securityPolicy .checkAuthorization (remoteUid ), offloadExecutor );
354345 }
355346
356- private synchronized void handleAuthResult (IBinder binder , Status authorization ) {
357- if (inState (TransportState .SETUP )) {
358- if (!authorization .isOk ()) {
359- shutdownInternal (authorization , true );
360- } else if (!setOutgoingBinder (OneWayBinderProxy .wrap (binder , offloadExecutor ))) {
361- shutdownInternal (
362- Status .UNAVAILABLE .withDescription ("Failed to observe outgoing binder" ), true );
363- } else {
364- // Check state again, since a failure inside setOutgoingBinder (or a callback it
365- // triggers), could have shut us down.
366- if (!isShutdown ()) {
367- setState (TransportState .READY );
368- attributes = clientTransportListener .filterTransport (attributes );
369- clientTransportListener .transportReady ();
370- if (readyTimeoutFuture != null ) {
371- readyTimeoutFuture .cancel (false );
372- readyTimeoutFuture = null ;
347+ private final class LegacyClientHandshake implements ClientHandshake {
348+ @ Override
349+ @ MainThread
350+ @ GuardedBy ("BinderClientTransport.this" ) // By way of @GuardedBy("this") `handshake` member.
351+ public void onBound (OneWayBinderProxy binder ) {
352+ sendSetupTransaction (binder );
353+ }
354+
355+ @ Override
356+ @ BinderThread
357+ @ GuardedBy ("BinderClientTransport.this" ) // By way of @GuardedBy("this") `handshake` member.
358+ public void handleSetupTransport (OneWayBinderProxy binder ) {
359+ int remoteUid = Binder .getCallingUid ();
360+ restrictIncomingBinderToCallsFrom (remoteUid );
361+ attributes = setSecurityAttrs (attributes , remoteUid );
362+ ListenableFuture <Status > authResultFuture =
363+ register (checkServerAuthorizationAsync (remoteUid ));
364+ Futures .addCallback (
365+ authResultFuture ,
366+ new FutureCallback <Status >() {
367+ @ Override
368+ public void onSuccess (Status result ) {
369+ synchronized (BinderClientTransport .this ) {
370+ handleAuthResult (binder , result );
371+ }
372+ }
373+
374+ @ Override
375+ public void onFailure (Throwable t ) {
376+ BinderClientTransport .this .handleAuthResult (t );
377+ }
378+ },
379+ offloadExecutor );
380+ }
381+
382+ @ GuardedBy ("BinderClientTransport.this" )
383+ private void handleAuthResult (OneWayBinderProxy binder , Status authorization ) {
384+ if (inState (TransportState .SETUP )) {
385+ if (!authorization .isOk ()) {
386+ shutdownInternal (authorization , true );
387+ } else if (!setOutgoingBinder (binder )) {
388+ shutdownInternal (
389+ Status .UNAVAILABLE .withDescription ("Failed to observe outgoing binder" ), true );
390+ } else {
391+ // Check state again, since a failure inside setOutgoingBinder (or a callback it
392+ // triggers), could have shut us down.
393+ if (!isShutdown ()) {
394+ onHandshakeComplete ();
373395 }
374396 }
375397 }
376398 }
377399 }
378400
401+ @ GuardedBy ("this" )
402+ private void onHandshakeComplete () {
403+ setState (TransportState .READY );
404+ attributes = clientTransportListener .filterTransport (attributes );
405+ clientTransportListener .transportReady ();
406+ if (readyTimeoutFuture != null ) {
407+ readyTimeoutFuture .cancel (false );
408+ readyTimeoutFuture = null ;
409+ }
410+ }
411+
379412 private synchronized void handleAuthResult (Throwable t ) {
380413 shutdownInternal (
381414 Status .INTERNAL .withDescription ("Could not evaluate SecurityPolicy" ).withCause (t ), true );
@@ -387,6 +420,26 @@ protected void handlePingResponse(Parcel parcel) {
387420 pingTracker .onPingResponse (parcel .readInt ());
388421 }
389422
423+ /**
424+ * A base for all implementations of the client handshake.
425+ *
426+ * <p>Supports a clean migration away from the legacy approach, one client at a time.
427+ */
428+ private interface ClientHandshake {
429+ /**
430+ * Notifies the implementation that the binding has succeeded and we are now connected to the
431+ * server's "endpoint" which can be reached at 'endpointBinder'.
432+ */
433+ @ MainThread
434+ void onBound (OneWayBinderProxy endpointBinder );
435+
436+ /**
437+ * Notifies the implementation that we've received a valid SETUP_TRANSPORT transaction from a
438+ * server that can be reached at 'serverBinder'.
439+ */
440+ @ BinderThread
441+ void handleSetupTransport (OneWayBinderProxy serverBinder );
442+ }
390443
391444 private static ClientStream newFailingClientStream (
392445 Status failure , Attributes attributes , Metadata headers , ClientStreamTracer [] tracers ) {
0 commit comments