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 com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static io.grpc.internal.GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE;
|
import static io.grpc.internal.GrpcUtil.DEFAULT_MAX_MESSAGE_SIZE;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
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.GrpcUtil;
|
||||||
import io.grpc.internal.SharedResourceHolder;
|
import io.grpc.internal.SharedResourceHolder;
|
||||||
import io.grpc.internal.TransportTracer;
|
import io.grpc.internal.TransportTracer;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
@ -46,6 +49,8 @@ import org.chromium.net.ExperimentalCronetEngine;
|
||||||
public final class CronetChannelBuilder extends
|
public final class CronetChannelBuilder extends
|
||||||
AbstractManagedChannelImplBuilder<CronetChannelBuilder> {
|
AbstractManagedChannelImplBuilder<CronetChannelBuilder> {
|
||||||
|
|
||||||
|
private static final String LOG_TAG = "CronetChannelBuilder";
|
||||||
|
|
||||||
/** BidirectionalStream.Builder factory used for getting the gRPC BidirectionalStream. */
|
/** BidirectionalStream.Builder factory used for getting the gRPC BidirectionalStream. */
|
||||||
public static abstract class StreamBuilderFactory {
|
public static abstract class StreamBuilderFactory {
|
||||||
public abstract BidirectionalStream.Builder newBidirectionalStreamBuilder(
|
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.
|
* StreamBuilderFactory impl that applies TrafficStats tags to stream builders that are produced.
|
||||||
*/
|
*/
|
||||||
private static class TaggingStreamFactory extends StreamBuilderFactory {
|
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 CronetEngine cronetEngine;
|
||||||
private final boolean trafficStatsTagSet;
|
private final boolean trafficStatsTagSet;
|
||||||
private final int trafficStatsTag;
|
private final int trafficStatsTag;
|
||||||
|
|
@ -271,12 +281,70 @@ public final class CronetChannelBuilder extends
|
||||||
((ExperimentalCronetEngine) cronetEngine)
|
((ExperimentalCronetEngine) cronetEngine)
|
||||||
.newBidirectionalStreamBuilder(url, callback, executor);
|
.newBidirectionalStreamBuilder(url, callback, executor);
|
||||||
if (trafficStatsTagSet) {
|
if (trafficStatsTagSet) {
|
||||||
builder.setTrafficStatsTag(trafficStatsTag);
|
setTrafficStatsTag(builder, trafficStatsTag);
|
||||||
}
|
}
|
||||||
if (trafficStatsUidSet) {
|
if (trafficStatsUidSet) {
|
||||||
builder.setTrafficStatsUid(trafficStatsUid);
|
setTrafficStatsUid(builder, trafficStatsUid);
|
||||||
}
|
}
|
||||||
return builder;
|
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.TransportFrameUtil;
|
||||||
import io.grpc.internal.TransportTracer;
|
import io.grpc.internal.TransportTracer;
|
||||||
import io.grpc.internal.WritableBuffer;
|
import io.grpc.internal.WritableBuffer;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -65,6 +67,9 @@ class CronetClientStream extends AbstractClientStream {
|
||||||
private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocateDirect(0);
|
private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocateDirect(0);
|
||||||
private static final String LOG_TAG = "grpc-java-cronet";
|
private static final String LOG_TAG = "grpc-java-cronet";
|
||||||
|
|
||||||
|
private static volatile boolean loadAddRequestAnnotationAttempted;
|
||||||
|
private static volatile Method addRequestAnnotationMethod;
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
static final CallOptions.Key<Object> CRONET_ANNOTATION_KEY =
|
static final CallOptions.Key<Object> CRONET_ANNOTATION_KEY =
|
||||||
CallOptions.Key.create("cronet-annotation");
|
CallOptions.Key.create("cronet-annotation");
|
||||||
|
|
@ -182,12 +187,16 @@ class CronetClientStream extends AbstractClientStream {
|
||||||
if (delayRequestHeader) {
|
if (delayRequestHeader) {
|
||||||
builder.delayRequestHeadersUntilFirstFlush(true);
|
builder.delayRequestHeadersUntilFirstFlush(true);
|
||||||
}
|
}
|
||||||
if (annotation != null) {
|
if (annotation != null || annotations != null) {
|
||||||
((ExperimentalBidirectionalStream.Builder) builder).addRequestAnnotation(annotation);
|
ExperimentalBidirectionalStream.Builder expBidiStreamBuilder =
|
||||||
}
|
(ExperimentalBidirectionalStream.Builder) builder;
|
||||||
if (annotations != null) {
|
if (annotation != null) {
|
||||||
for (Object o : annotations) {
|
addRequestAnnotation(expBidiStreamBuilder, annotation);
|
||||||
((ExperimentalBidirectionalStream.Builder) builder).addRequestAnnotation(o);
|
}
|
||||||
|
if (annotations != null) {
|
||||||
|
for (Object o : annotations) {
|
||||||
|
addRequestAnnotation(expBidiStreamBuilder, o);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setGrpcHeaders(builder);
|
setGrpcHeaders(builder);
|
||||||
|
|
@ -359,6 +368,35 @@ class CronetClientStream extends AbstractClientStream {
|
||||||
&& !TE_HEADER.name().equalsIgnoreCase(key);
|
&& !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) {
|
private void setGrpcHeaders(BidirectionalStream.Builder builder) {
|
||||||
// Psuedo-headers are set by cronet.
|
// Psuedo-headers are set by cronet.
|
||||||
// All non-pseudo headers must come after pseudo headers.
|
// All non-pseudo headers must come after pseudo headers.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue