• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2020 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.checkNotNull;
20 
21 import android.os.Binder;
22 import android.os.IBinder;
23 import android.os.Parcel;
24 import com.google.common.collect.ImmutableList;
25 import io.grpc.Attributes;
26 import io.grpc.Grpc;
27 import io.grpc.InternalChannelz.SocketStats;
28 import io.grpc.InternalInstrumented;
29 import io.grpc.ServerStreamTracer;
30 import io.grpc.binder.AndroidComponentAddress;
31 import io.grpc.binder.InboundParcelablePolicy;
32 import io.grpc.binder.ServerSecurityPolicy;
33 import io.grpc.internal.GrpcUtil;
34 import io.grpc.internal.InternalServer;
35 import io.grpc.internal.ObjectPool;
36 import io.grpc.internal.ServerListener;
37 import io.grpc.internal.SharedResourceHolder;
38 import java.io.IOException;
39 import java.net.SocketAddress;
40 import java.util.List;
41 import java.util.concurrent.ScheduledExecutorService;
42 import javax.annotation.Nullable;
43 import javax.annotation.concurrent.GuardedBy;
44 import javax.annotation.concurrent.ThreadSafe;
45 
46 /**
47  * A gRPC InternalServer which accepts connections via a host AndroidService.
48  *
49  * <p>Multiple incoming connections transports may be active at a time.
50  *
51  * <b>IMPORTANT</b>: This implementation must comply with this published wire format.
52  * https://github.com/grpc/proposal/blob/master/L73-java-binderchannel/wireformat.md
53  */
54 @ThreadSafe
55 public final class BinderServer implements InternalServer, LeakSafeOneWayBinder.TransactionHandler {
56 
57   private final ObjectPool<ScheduledExecutorService> executorServicePool;
58   private final ImmutableList<ServerStreamTracer.Factory> streamTracerFactories;
59   private final AndroidComponentAddress listenAddress;
60   private final LeakSafeOneWayBinder hostServiceBinder;
61   private final ServerSecurityPolicy serverSecurityPolicy;
62   private final InboundParcelablePolicy inboundParcelablePolicy;
63 
64   @GuardedBy("this")
65   private ServerListener listener;
66 
67   @GuardedBy("this")
68   private ScheduledExecutorService executorService;
69 
70   @GuardedBy("this")
71   private boolean shutdown;
72 
BinderServer( AndroidComponentAddress listenAddress, ObjectPool<ScheduledExecutorService> executorServicePool, List<? extends ServerStreamTracer.Factory> streamTracerFactories, ServerSecurityPolicy serverSecurityPolicy, InboundParcelablePolicy inboundParcelablePolicy)73   public BinderServer(
74       AndroidComponentAddress listenAddress,
75       ObjectPool<ScheduledExecutorService> executorServicePool,
76       List<? extends ServerStreamTracer.Factory> streamTracerFactories,
77       ServerSecurityPolicy serverSecurityPolicy,
78       InboundParcelablePolicy inboundParcelablePolicy) {
79     this.listenAddress = listenAddress;
80     this.executorServicePool = executorServicePool;
81     this.streamTracerFactories =
82         ImmutableList.copyOf(checkNotNull(streamTracerFactories, "streamTracerFactories"));
83     this.serverSecurityPolicy = checkNotNull(serverSecurityPolicy, "serverSecurityPolicy");
84     this.inboundParcelablePolicy = inboundParcelablePolicy;
85     hostServiceBinder = new LeakSafeOneWayBinder(this);
86   }
87 
88   /** Return the binder we're listening on. */
getHostBinder()89   public IBinder getHostBinder() {
90     return hostServiceBinder;
91   }
92 
93   @Override
start(ServerListener serverListener)94   public synchronized void start(ServerListener serverListener) throws IOException {
95     this.listener = serverListener;
96     executorService = executorServicePool.getObject();
97   }
98 
99   @Override
getListenSocketAddress()100   public SocketAddress getListenSocketAddress() {
101     return listenAddress;
102   }
103 
104   @Override
getListenSocketAddresses()105   public List<? extends SocketAddress> getListenSocketAddresses() {
106     return ImmutableList.of(listenAddress);
107   }
108 
109   @Override
getListenSocketStats()110   public InternalInstrumented<SocketStats> getListenSocketStats() {
111     return null;
112   }
113 
114   @Override
115   @Nullable
getListenSocketStatsList()116   public List<InternalInstrumented<SocketStats>> getListenSocketStatsList() {
117     return null;
118   }
119 
120   @Override
shutdown()121   public synchronized void shutdown() {
122     if (!shutdown) {
123       shutdown = true;
124       // Break the connection to the binder. We'll receive no more transactions.
125       hostServiceBinder.detach();
126       listener.serverShutdown();
127       executorService = executorServicePool.returnObject(executorService);
128     }
129   }
130 
131   @Override
toString()132   public String toString() {
133     return "BinderServer[" + listenAddress + "]";
134   }
135 
136   @Override
handleTransaction(int code, Parcel parcel)137   public synchronized boolean handleTransaction(int code, Parcel parcel) {
138     if (code == BinderTransport.SETUP_TRANSPORT) {
139       int version = parcel.readInt();
140       // If the client-provided version is more recent, we accept the connection,
141       // but specify the older version which we support.
142       if (version >= BinderTransport.EARLIEST_SUPPORTED_WIRE_FORMAT_VERSION) {
143         IBinder callbackBinder = parcel.readStrongBinder();
144         if (callbackBinder != null) {
145           int callingUid = Binder.getCallingUid();
146           Attributes.Builder attrsBuilder =
147               Attributes.newBuilder()
148                   .set(Grpc.TRANSPORT_ATTR_LOCAL_ADDR, listenAddress)
149                   .set(Grpc.TRANSPORT_ATTR_REMOTE_ADDR, new BoundClientAddress(callingUid))
150                   .set(BinderTransport.REMOTE_UID, callingUid)
151                   .set(BinderTransport.SERVER_AUTHORITY, listenAddress.getAuthority())
152                   .set(BinderTransport.INBOUND_PARCELABLE_POLICY, inboundParcelablePolicy);
153           BinderTransportSecurity.attachAuthAttrs(attrsBuilder, callingUid, serverSecurityPolicy);
154           // Create a new transport and let our listener know about it.
155           BinderTransport.BinderServerTransport transport =
156               new BinderTransport.BinderServerTransport(
157                   executorServicePool, attrsBuilder.build(), streamTracerFactories, callbackBinder);
158           transport.setServerTransportListener(listener.transportCreated(transport));
159           return true;
160         }
161       }
162     }
163     return false;
164   }
165 }
166