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 d7da13995e5e93778193615b2acd737971a373fa..818ecb2959671bb2f5a3d0cf7a94059281e58da0 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 |
@@ -13,6 +13,7 @@ import org.chromium.base.annotations.CalledByNative; |
import org.chromium.base.annotations.JNIAdditionalImport; |
import org.chromium.base.annotations.JNINamespace; |
import org.chromium.base.annotations.NativeClassQualifiedName; |
+import org.chromium.net.InlineExecutionProhibitedException; |
import org.chromium.net.Preconditions; |
import org.chromium.net.QuicException; |
import org.chromium.net.RequestFinishedInfo; |
@@ -49,6 +50,7 @@ import javax.annotation.concurrent.GuardedBy; |
public final class CronetUrlRequest implements UrlRequest { |
private static final RequestFinishedInfo.Metrics EMPTY_METRICS = |
new RequestFinishedInfo.Metrics(null, null, null, null); |
+ private final boolean mAllowDirectExecutor; |
/* Native adapter object, owned by UrlRequest. */ |
@GuardedBy("mUrlRequestAdapterLock") |
@@ -109,6 +111,7 @@ public final class CronetUrlRequest implements UrlRequest { |
@Override |
public void run() { |
+ checkCallingThread(); |
// Null out mByteBuffer, to pass buffer ownership to callback or release if done. |
ByteBuffer buffer = mByteBuffer; |
mByteBuffer = null; |
@@ -130,7 +133,7 @@ public final class CronetUrlRequest implements UrlRequest { |
CronetUrlRequest(CronetUrlRequestContext requestContext, String url, int priority, |
UrlRequest.Callback callback, Executor executor, Collection<Object> requestAnnotations, |
boolean metricsCollectionEnabled, boolean disableCache, |
- boolean disableConnectionMigration) { |
+ boolean disableConnectionMigration, boolean allowDirectExecutor) { |
if (url == null) { |
throw new NullPointerException("URL is required"); |
} |
@@ -144,6 +147,7 @@ public final class CronetUrlRequest implements UrlRequest { |
throw new NullPointerException("requestAnnotations is required"); |
} |
+ mAllowDirectExecutor = allowDirectExecutor; |
mRequestContext = requestContext; |
mInitialUrl = url; |
mUrlChain.add(url); |
@@ -223,10 +227,9 @@ public final class CronetUrlRequest implements UrlRequest { |
"Requests with upload data must have a Content-Type."); |
} |
mStarted = true; |
- mUploadDataStream.postTaskToExecutor(new Runnable() { |
+ mUploadDataStream.initializeWithRequest(CronetUrlRequest.this, new Runnable() { |
@Override |
public void run() { |
- mUploadDataStream.initializeWithRequest(CronetUrlRequest.this); |
synchronized (mUrlRequestAdapterLock) { |
if (isDoneLocked()) { |
return; |
@@ -367,9 +370,15 @@ public final class CronetUrlRequest implements UrlRequest { |
} catch (RejectedExecutionException failException) { |
Log.e(CronetUrlRequestContext.LOG_TAG, "Exception posting task to executor", |
failException); |
- // If posting a task throws an exception, then there is no choice |
- // but to destroy the request without invoking the callback. |
- destroyRequestAdapter(false); |
+ // If posting a task throws an exception, then we fail the request. This exception could |
+ // be permanent (executor shutdown), transient (AbortPolicy, or CallerRunsPolicy with |
+ // direct execution not permitted), or caused the the runnables we submit if |
mef
2016/08/31 20:24:25
nit: the the -> by the?
Charles
2016/08/31 22:36:41
Done.
|
+ // mUserExecutor is a direct executor and direct execution is not permitted. In the |
+ // latter two cases, we at least have a chance to inform the embedder of the request's |
mef
2016/08/31 20:24:25
nit: We don't use 'we' in Chromium comments. :)
Charles
2016/08/31 22:36:41
Done.
|
+ // failure, since failWithException does not enforce that onFailed() is not executed |
+ // inline. |
+ failWithException( |
+ new UrlRequestException("Exception posting task to executor", failException)); |
} |
} |
@@ -437,19 +446,7 @@ public final class CronetUrlRequest implements UrlRequest { |
UrlRequestException requestError = |
new UrlRequestException("Exception received from UrlRequest.Callback", e); |
Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in CalledByNative method", e); |
- // Do not call into listener if request is finished. |
- synchronized (mUrlRequestAdapterLock) { |
- if (isDoneLocked()) { |
- return; |
- } |
- destroyRequestAdapter(false); |
- } |
- try { |
- mCallback.onFailed(this, mResponseInfo, requestError); |
- } catch (Exception failException) { |
- Log.e(CronetUrlRequestContext.LOG_TAG, "Exception notifying of failed request", |
- failException); |
- } |
+ failWithException(requestError); |
} |
/** |
@@ -466,23 +463,27 @@ public final class CronetUrlRequest implements UrlRequest { |
* Fails the request with an exception. Can be called on any thread. |
*/ |
private void failWithException(final UrlRequestException exception) { |
+ synchronized (mUrlRequestAdapterLock) { |
+ if (isDoneLocked()) { |
+ return; |
+ } |
+ destroyRequestAdapter(false); |
+ } |
Runnable task = new Runnable() { |
@Override |
public void run() { |
- synchronized (mUrlRequestAdapterLock) { |
- if (isDoneLocked()) { |
- return; |
- } |
- destroyRequestAdapter(false); |
- } |
try { |
mCallback.onFailed(CronetUrlRequest.this, mResponseInfo, exception); |
} catch (Exception e) { |
- Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in onError method", e); |
+ Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in onFailed method", e); |
} |
} |
}; |
- postTaskToExecutor(task); |
+ try { |
+ mExecutor.execute(task); |
+ } catch (RejectedExecutionException e) { |
+ Log.e(CronetUrlRequestContext.LOG_TAG, "Exception posting task to executor", e); |
+ } |
} |
//////////////////////////////////////////////// |
@@ -517,6 +518,7 @@ public final class CronetUrlRequest implements UrlRequest { |
Runnable task = new Runnable() { |
@Override |
public void run() { |
+ checkCallingThread(); |
synchronized (mUrlRequestAdapterLock) { |
if (isDoneLocked()) { |
return; |
@@ -547,6 +549,7 @@ public final class CronetUrlRequest implements UrlRequest { |
Runnable task = new Runnable() { |
@Override |
public void run() { |
+ checkCallingThread(); |
synchronized (mUrlRequestAdapterLock) { |
if (isDoneLocked()) { |
return; |
@@ -736,6 +739,13 @@ public final class CronetUrlRequest implements UrlRequest { |
} |
} |
+ /** Enforces prohibition of direct execution. */ |
+ private void checkCallingThread() { |
+ if (!mAllowDirectExecutor && mRequestContext.isNetworkThread(Thread.currentThread())) { |
+ throw new InlineExecutionProhibitedException(); |
+ } |
+ } |
+ |
// Native methods are implemented in cronet_url_request_adapter.cc. |
private native long nativeCreateRequestAdapter(long urlRequestContextAdapter, String url, |