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..3dea66d9085208e29436dffd68f3b8e9091f3479 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); |
@@ -367,9 +371,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 by the runnables we submit if |
+ // mUserExecutor is a direct executor and direct execution is not permitted. In the |
+ // 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( |
+ new UrlRequestException("Exception posting task to executor", failException)); |
} |
} |
@@ -437,19 +447,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 +464,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 +519,7 @@ public final class CronetUrlRequest implements UrlRequest { |
Runnable task = new Runnable() { |
@Override |
public void run() { |
+ checkCallingThread(); |
synchronized (mUrlRequestAdapterLock) { |
if (isDoneLocked()) { |
return; |
@@ -547,6 +550,7 @@ public final class CronetUrlRequest implements UrlRequest { |
Runnable task = new Runnable() { |
@Override |
public void run() { |
+ checkCallingThread(); |
synchronized (mUrlRequestAdapterLock) { |
if (isDoneLocked()) { |
return; |
@@ -736,6 +740,13 @@ public final class CronetUrlRequest implements UrlRequest { |
} |
} |
+ /** Enforces prohibition of direct execution. */ |
+ 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, |