mirror of https://github.com/grpc/grpc-java.git
cronet: use reflection to load and invoke experimental APIs in ExperimentalBidirectionalStream.Builder (#6111)
* Use reflection to load and invoke setTrafficStats* and addRequestAnnotation methods for ExperimentalBidirectionalStream.Builder. * Load reflection method lazily and cache for later usages.
This commit is contained in:
parent
62e37a6e6b
commit
a234ada5a9
|
|
@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkArgument;
|
|||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static io.grpc.internal.GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE;
|
||||
|
||||
import android.util.Log;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.util.concurrent.MoreExecutors;
|
||||
|
|
@ -31,6 +32,8 @@ import io.grpc.internal.ConnectionClientTransport;
|
|||
import io.grpc.internal.GrpcUtil;
|
||||
import io.grpc.internal.SharedResourceHolder;
|
||||
import io.grpc.internal.TransportTracer;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.concurrent.Executor;
|
||||
|
|
@ -46,6 +49,8 @@ import org.chromium.net.ExperimentalCronetEngine;
|
|||
public final class CronetChannelBuilder extends
|
||||
AbstractManagedChannelImplBuilder<CronetChannelBuilder> {
|
||||
|
||||
private static final String LOG_TAG = "CronetChannelBuilder";
|
||||
|
||||
/** BidirectionalStream.Builder factory used for getting the gRPC BidirectionalStream. */
|
||||
public static abstract class StreamBuilderFactory {
|
||||
public abstract BidirectionalStream.Builder newBidirectionalStreamBuilder(
|
||||
|
|
@ -245,6 +250,11 @@ public final class CronetChannelBuilder extends
|
|||
* StreamBuilderFactory impl that applies TrafficStats tags to stream builders that are produced.
|
||||
*/
|
||||
private static class TaggingStreamFactory extends StreamBuilderFactory {
|
||||
private static volatile boolean loadSetTrafficStatsTagAttempted;
|
||||
private static volatile boolean loadSetTrafficStatsUidAttempted;
|
||||
private static volatile Method setTrafficStatsTagMethod;
|
||||
private static volatile Method setTrafficStatsUidMethod;
|
||||
|
||||
private final CronetEngine cronetEngine;
|
||||
private final boolean trafficStatsTagSet;
|
||||
private final int trafficStatsTag;
|
||||
|
|
@ -271,12 +281,70 @@ public final class CronetChannelBuilder extends
|
|||
((ExperimentalCronetEngine) cronetEngine)
|
||||
.newBidirectionalStreamBuilder(url, callback, executor);
|
||||
if (trafficStatsTagSet) {
|
||||
builder.setTrafficStatsTag(trafficStatsTag);
|
||||
setTrafficStatsTag(builder, trafficStatsTag);
|
||||
}
|
||||
if (trafficStatsUidSet) {
|
||||
builder.setTrafficStatsUid(trafficStatsUid);
|
||||
setTrafficStatsUid(builder, trafficStatsUid);
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static void setTrafficStatsTag(ExperimentalBidirectionalStream.Builder builder,
|
||||
int tag) {
|
||||
if (!loadSetTrafficStatsTagAttempted) {
|
||||
synchronized (TaggingStreamFactory.class) {
|
||||
if (!loadSetTrafficStatsTagAttempted) {
|
||||
try {
|
||||
setTrafficStatsTagMethod = ExperimentalBidirectionalStream.Builder.class
|
||||
.getMethod("setTrafficStatsTag", int.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Log.w(LOG_TAG,
|
||||
"Failed to load method ExperimentalBidirectionalStream.Builder.setTrafficStatsTag",
|
||||
e);
|
||||
} finally {
|
||||
loadSetTrafficStatsTagAttempted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (setTrafficStatsTagMethod != null) {
|
||||
try {
|
||||
setTrafficStatsTagMethod.invoke(builder, tag);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e.getCause() == null ? e.getTargetException() : e.getCause());
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.w(LOG_TAG, "Failed to set traffic stats tag: " + tag, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setTrafficStatsUid(ExperimentalBidirectionalStream.Builder builder,
|
||||
int uid) {
|
||||
if (!loadSetTrafficStatsUidAttempted) {
|
||||
synchronized (TaggingStreamFactory.class) {
|
||||
if (!loadSetTrafficStatsUidAttempted) {
|
||||
try {
|
||||
setTrafficStatsUidMethod = ExperimentalBidirectionalStream.Builder.class
|
||||
.getMethod("setTrafficStatsUid", int.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Log.w(LOG_TAG,
|
||||
"Failed to load method ExperimentalBidirectionalStream.Builder.setTrafficStatsUid",
|
||||
e);
|
||||
} finally {
|
||||
loadSetTrafficStatsUidAttempted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (setTrafficStatsUidMethod != null) {
|
||||
try {
|
||||
setTrafficStatsUidMethod.invoke(builder, uid);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e.getCause() == null ? e.getTargetException() : e.getCause());
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.w(LOG_TAG, "Failed to set traffic stats uid: " + uid, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ import io.grpc.internal.StatsTraceContext;
|
|||
import io.grpc.internal.TransportFrameUtil;
|
||||
import io.grpc.internal.TransportTracer;
|
||||
import io.grpc.internal.WritableBuffer;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -65,6 +67,9 @@ class CronetClientStream extends AbstractClientStream {
|
|||
private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocateDirect(0);
|
||||
private static final String LOG_TAG = "grpc-java-cronet";
|
||||
|
||||
private static volatile boolean loadAddRequestAnnotationAttempted;
|
||||
private static volatile Method addRequestAnnotationMethod;
|
||||
|
||||
@Deprecated
|
||||
static final CallOptions.Key<Object> CRONET_ANNOTATION_KEY =
|
||||
CallOptions.Key.create("cronet-annotation");
|
||||
|
|
@ -182,12 +187,16 @@ class CronetClientStream extends AbstractClientStream {
|
|||
if (delayRequestHeader) {
|
||||
builder.delayRequestHeadersUntilFirstFlush(true);
|
||||
}
|
||||
if (annotation != null) {
|
||||
((ExperimentalBidirectionalStream.Builder) builder).addRequestAnnotation(annotation);
|
||||
}
|
||||
if (annotations != null) {
|
||||
for (Object o : annotations) {
|
||||
((ExperimentalBidirectionalStream.Builder) builder).addRequestAnnotation(o);
|
||||
if (annotation != null || annotations != null) {
|
||||
ExperimentalBidirectionalStream.Builder expBidiStreamBuilder =
|
||||
(ExperimentalBidirectionalStream.Builder) builder;
|
||||
if (annotation != null) {
|
||||
addRequestAnnotation(expBidiStreamBuilder, annotation);
|
||||
}
|
||||
if (annotations != null) {
|
||||
for (Object o : annotations) {
|
||||
addRequestAnnotation(expBidiStreamBuilder, o);
|
||||
}
|
||||
}
|
||||
}
|
||||
setGrpcHeaders(builder);
|
||||
|
|
@ -359,6 +368,35 @@ class CronetClientStream extends AbstractClientStream {
|
|||
&& !TE_HEADER.name().equalsIgnoreCase(key);
|
||||
}
|
||||
|
||||
private static void addRequestAnnotation(ExperimentalBidirectionalStream.Builder builder,
|
||||
Object annotation) {
|
||||
if (!loadAddRequestAnnotationAttempted) {
|
||||
synchronized (CronetClientStream.class) {
|
||||
if (!loadAddRequestAnnotationAttempted) {
|
||||
try {
|
||||
addRequestAnnotationMethod = ExperimentalBidirectionalStream.Builder.class
|
||||
.getMethod("addRequestAnnotation", Object.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Log.w(LOG_TAG,
|
||||
"Failed to load method ExperimentalBidirectionalStream.Builder.addRequestAnnotation",
|
||||
e);
|
||||
} finally {
|
||||
loadAddRequestAnnotationAttempted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (addRequestAnnotationMethod != null) {
|
||||
try {
|
||||
addRequestAnnotationMethod.invoke(builder, annotation);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e.getCause() == null ? e.getTargetException() : e.getCause());
|
||||
} catch (IllegalAccessException e) {
|
||||
Log.w(LOG_TAG, "Failed to add request annotation: " + annotation, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setGrpcHeaders(BidirectionalStream.Builder builder) {
|
||||
// Psuedo-headers are set by cronet.
|
||||
// All non-pseudo headers must come after pseudo headers.
|
||||
|
|
|
|||
Loading…
Reference in New Issue