Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(355)

Unified Diff: components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java

Issue 2844803002: [Cronet] Make metrics reporting happen after terminal callbacks. (Closed)
Patch Set: remove an invalid comment Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java
index eb2abaf83195efa16810c38ae43f3583407dbae8..07affb421e4c92cfc368b410a6866eef1648e956 100644
--- a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java
+++ b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequest.java
@@ -51,13 +51,11 @@ public final class CronetUrlRequest extends UrlRequestBase {
private long mUrlRequestAdapter;
@GuardedBy("mUrlRequestAdapterLock")
- private boolean mStarted = false;
+ private boolean mStarted;
@GuardedBy("mUrlRequestAdapterLock")
- private boolean mWaitingOnRedirect = false;
+ private boolean mWaitingOnRedirect;
@GuardedBy("mUrlRequestAdapterLock")
- private boolean mWaitingOnRead = false;
- @GuardedBy("mUrlRequestAdapterLock")
- private RequestFinishedInfo.Metrics mMetrics;
+ private boolean mWaitingOnRead;
/*
* Synchronize access to mUrlRequestAdapter, mStarted, mWaitingOnRedirect,
@@ -81,9 +79,6 @@ public final class CronetUrlRequest extends UrlRequestBase {
private String mInitialMethod;
private final HeadersList mRequestHeaders = new HeadersList();
private final Collection<Object> mRequestAnnotations;
- @RequestFinishedInfoImpl.FinishedReason
- private int mFinishedReason;
- private CronetException mException;
private final boolean mDisableCache;
private final boolean mDisableConnectionMigration;
@@ -91,6 +86,15 @@ public final class CronetUrlRequest extends UrlRequestBase {
private UrlResponseInfoImpl mResponseInfo;
+ // mFinishedReason and mException should only be updated once with mUrlRequestAdapterLock held.
+ // They are read on executor's thread after the last update.
+ @RequestFinishedInfoImpl.FinishedReason
+ private int mFinishedReason;
+ private CronetException mException;
+
+ // Accessed only from the network thread.
+ private boolean mMetricsCollected;
+
/*
* Listener callback is repeatedly invoked when each read is completed, so it
* is cached as a member variable.
@@ -235,8 +239,9 @@ public final class CronetUrlRequest extends UrlRequestBase {
}
} catch (RuntimeException e) {
// If there's an exception, cleanup and then throw the
- // exception to the caller.
- destroyRequestAdapter(false);
+ // exception to the caller. Use null here to avoid rethrowing
+ // in onDestroyed().
+ failWithExceptionFromJava(null);
throw e;
}
mStarted = true;
@@ -298,7 +303,7 @@ public final class CronetUrlRequest extends UrlRequestBase {
if (isDoneLocked() || !mStarted) {
return;
}
- destroyRequestAdapter(true);
+ nativeCancel(mUrlRequestAdapter);
}
}
@@ -309,6 +314,19 @@ public final class CronetUrlRequest extends UrlRequestBase {
}
}
+ private void setIsDone(
+ CronetException exception, @RequestFinishedInfoImpl.FinishedReason int finishedReason) {
+ synchronized (mUrlRequestAdapterLock) {
+ assert mUrlRequestAdapter != 0;
+ assert mException == null;
+ mException = exception;
+ mFinishedReason = finishedReason;
+ assert mException == null || mFinishedReason == RequestFinishedInfo.FAILED;
+ mRequestContext.onRequestDestroyed();
+ mUrlRequestAdapter = 0;
+ }
+ }
+
@GuardedBy("mUrlRequestAdapterLock")
private boolean isDoneLocked() {
return mStarted && mUrlRequestAdapter == 0;
@@ -368,7 +386,7 @@ public final class CronetUrlRequest extends UrlRequestBase {
// latter two cases, there is at least have a chance to inform the embedder of the
// request's failure, since failWithException does not enforce that onFailed() is not
// executed inline.
- failWithException(
+ failWithExceptionFromJava(
new CronetExceptionImpl("Exception posting task to executor", failException));
}
}
@@ -410,20 +428,6 @@ public final class CronetUrlRequest extends UrlRequestBase {
}
}
- private void destroyRequestAdapter(boolean sendOnCanceled) {
- synchronized (mUrlRequestAdapterLock) {
- if (mUrlRequestAdapter == 0) {
- return;
- }
- nativeDestroy(mUrlRequestAdapter, sendOnCanceled);
- mRequestContext.onRequestDestroyed();
- mUrlRequestAdapter = 0;
- if (mOnDestroyedCallbackForTesting != null) {
- mOnDestroyedCallbackForTesting.run();
- }
- }
- }
-
/**
* If callback method throws an exception, request gets canceled
* and exception is reported via onFailed listener callback.
@@ -433,7 +437,7 @@ public final class CronetUrlRequest extends UrlRequestBase {
CallbackException requestError =
new CallbackExceptionImpl("Exception received from UrlRequest.Callback", e);
Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in CalledByNative method", e);
- failWithException(requestError);
+ failWithExceptionFromJava(requestError);
}
/**
@@ -443,34 +447,20 @@ public final class CronetUrlRequest extends UrlRequestBase {
CallbackException uploadError =
new CallbackExceptionImpl("Exception received from UploadDataProvider", e);
Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in upload method", e);
- failWithException(uploadError);
+ failWithExceptionFromJava(uploadError);
}
/**
- * Fails the request with an exception. Can be called on any thread.
+ * Fails the request with an exception on any thread. This method should only be used when error
+ * originates from Java.
*/
- private void failWithException(final CronetException exception) {
- mException = exception;
+ private void failWithExceptionFromJava(final CronetException exception) {
synchronized (mUrlRequestAdapterLock) {
if (isDoneLocked()) {
return;
}
- destroyRequestAdapter(false);
- }
- Runnable task = new Runnable() {
- @Override
- public void run() {
- try {
- mCallback.onFailed(CronetUrlRequest.this, mResponseInfo, exception);
- } catch (Exception e) {
- Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in onFailed method", e);
- }
- }
- };
- try {
- mExecutor.execute(task);
- } catch (RejectedExecutionException e) {
- Log.e(CronetUrlRequestContext.LOG_TAG, "Exception posting task to executor", e);
+ nativeDestroy(mUrlRequestAdapter);
+ setIsDone(exception, RequestFinishedInfo.FAILED);
}
}
@@ -579,7 +569,7 @@ public final class CronetUrlRequest extends UrlRequestBase {
int initialLimit, long receivedByteCount) {
mResponseInfo.setReceivedByteCount(mReceivedByteCountFromRedirects + receivedByteCount);
if (byteBuffer.position() != initialPosition || byteBuffer.limit() != initialLimit) {
- failWithException(
+ failWithExceptionFromJava(
new CronetExceptionImpl("ByteBuffer modified externally during read", null));
return;
}
@@ -600,19 +590,11 @@ public final class CronetUrlRequest extends UrlRequestBase {
@SuppressWarnings("unused")
@CalledByNative
private void onSucceeded(long receivedByteCount) {
- mFinishedReason = RequestFinishedInfo.SUCCEEDED;
+ setIsDone(null, RequestFinishedInfo.SUCCEEDED);
mResponseInfo.setReceivedByteCount(mReceivedByteCountFromRedirects + receivedByteCount);
Runnable task = new Runnable() {
@Override
public void run() {
- synchronized (mUrlRequestAdapterLock) {
- if (isDoneLocked()) {
- return;
- }
- // Destroy adapter first, so request context could be shut
- // down from the listener.
- destroyRequestAdapter(false);
- }
try {
mCallback.onSucceeded(CronetUrlRequest.this, mResponseInfo);
} catch (Exception e) {
@@ -637,18 +619,20 @@ public final class CronetUrlRequest extends UrlRequestBase {
@CalledByNative
private void onError(int errorCode, int nativeError, int nativeQuicError, String errorString,
long receivedByteCount) {
- mFinishedReason = RequestFinishedInfo.FAILED;
if (mResponseInfo != null) {
mResponseInfo.setReceivedByteCount(mReceivedByteCountFromRedirects + receivedByteCount);
}
+ CronetException exception;
if (errorCode == NetworkException.ERROR_QUIC_PROTOCOL_FAILED) {
- failWithException(new QuicExceptionImpl(
- "Exception in CronetUrlRequest: " + errorString, nativeError, nativeQuicError));
+ exception = new QuicExceptionImpl(
+ "Exception in CronetUrlRequest: " + errorString, nativeError, nativeQuicError);
} else {
int javaError = mapUrlRequestErrorToApiErrorCode(errorCode);
- failWithException(new NetworkExceptionImpl(
- "Exception in CronetUrlRequest: " + errorString, javaError, nativeError));
+ exception = new NetworkExceptionImpl(
+ "Exception in CronetUrlRequest: " + errorString, javaError, nativeError);
}
+ setIsDone(exception, RequestFinishedInfo.FAILED);
+ // onDestroyed() will propagate mException to callback.
}
/**
@@ -657,7 +641,7 @@ public final class CronetUrlRequest extends UrlRequestBase {
@SuppressWarnings("unused")
@CalledByNative
private void onCanceled() {
- mFinishedReason = RequestFinishedInfo.CANCELED;
+ setIsDone(null, RequestFinishedInfo.CANCELED);
Runnable task = new Runnable() {
@Override
public void run() {
@@ -698,21 +682,47 @@ public final class CronetUrlRequest extends UrlRequestBase {
long sendingStartMs, long sendingEndMs, long pushStartMs, long pushEndMs,
long responseStartMs, long requestEndMs, boolean socketReused, long sentByteCount,
long receivedByteCount) {
- synchronized (mUrlRequestAdapterLock) {
- if (mMetrics != null) {
- throw new IllegalStateException("Metrics collection should only happen once.");
- }
- mMetrics = new CronetMetrics(requestStartMs, dnsStartMs, dnsEndMs, connectStartMs,
- connectEndMs, sslStartMs, sslEndMs, sendingStartMs, sendingEndMs, pushStartMs,
- pushEndMs, responseStartMs, requestEndMs, socketReused, sentByteCount,
- receivedByteCount);
+ if (mMetricsCollected) {
+ throw new IllegalStateException("Metrics collection should only happen once.");
}
- mRequestContext.reportFinished(getRequestFinishedInfo());
+ mMetricsCollected = true;
+ CronetMetrics metrics = new CronetMetrics(requestStartMs, dnsStartMs, dnsEndMs,
+ connectStartMs, connectEndMs, sslStartMs, sslEndMs, sendingStartMs, sendingEndMs,
+ pushStartMs, pushEndMs, responseStartMs, requestEndMs, socketReused, sentByteCount,
+ receivedByteCount);
+ mRequestContext.reportFinished(new RequestFinishedInfoImpl(mInitialUrl, mRequestAnnotations,
+ metrics, mFinishedReason, mResponseInfo, mException));
}
- private RequestFinishedInfo getRequestFinishedInfo() {
- return new RequestFinishedInfoImpl(mInitialUrl, mRequestAnnotations, mMetrics,
- mFinishedReason, mResponseInfo, mException);
+ /**
+ * Called when the native adapter is destroyed.
+ */
+ @SuppressWarnings("unused")
+ @CalledByNative
+ private void onDestroyed() {
+ synchronized (mUrlRequestAdapterLock) {
+ if (mOnDestroyedCallbackForTesting != null) {
+ mOnDestroyedCallbackForTesting.run();
+ }
+ if (mException == null) {
+ return;
+ }
+ }
+ Runnable task = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ mCallback.onFailed(CronetUrlRequest.this, mResponseInfo, mException);
+ } catch (Exception e) {
+ Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in onFailed method", e);
+ }
+ }
+ };
+ try {
+ mExecutor.execute(task);
+ } catch (RejectedExecutionException e) {
+ Log.e(CronetUrlRequestContext.LOG_TAG, "Exception posting task to executor", e);
+ }
}
/** Enforces prohibition of direct execution. */
@@ -775,7 +785,10 @@ public final class CronetUrlRequest extends UrlRequestBase {
long nativePtr, ByteBuffer byteBuffer, int position, int capacity);
@NativeClassQualifiedName("CronetURLRequestAdapter")
- private native void nativeDestroy(long nativePtr, boolean sendOnCanceled);
+ private native void nativeCancel(long nativePtr);
+
+ @NativeClassQualifiedName("CronetURLRequestAdapter")
+ private native void nativeDestroy(long nativePtr);
@NativeClassQualifiedName("CronetURLRequestAdapter")
private native void nativeGetStatus(

Powered by Google App Engine
This is Rietveld 408576698