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