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

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

Issue 2283243002: Allow direct executors in cronet. (Closed)
Patch Set: Addressed comments, unified request failure logic in CronetUrlRequest Created 4 years, 3 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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.net.impl; 5 package org.chromium.net.impl;
6 6
7 import android.os.SystemClock; 7 import android.os.SystemClock;
8 import android.support.annotation.Nullable; 8 import android.support.annotation.Nullable;
9 import android.util.Log; 9 import android.util.Log;
10 10
11 import org.chromium.base.VisibleForTesting; 11 import org.chromium.base.VisibleForTesting;
12 import org.chromium.base.annotations.CalledByNative; 12 import org.chromium.base.annotations.CalledByNative;
13 import org.chromium.base.annotations.JNIAdditionalImport; 13 import org.chromium.base.annotations.JNIAdditionalImport;
14 import org.chromium.base.annotations.JNINamespace; 14 import org.chromium.base.annotations.JNINamespace;
15 import org.chromium.base.annotations.NativeClassQualifiedName; 15 import org.chromium.base.annotations.NativeClassQualifiedName;
16 import org.chromium.net.InlineExecutionProhibitedException;
16 import org.chromium.net.Preconditions; 17 import org.chromium.net.Preconditions;
17 import org.chromium.net.QuicException; 18 import org.chromium.net.QuicException;
18 import org.chromium.net.RequestFinishedInfo; 19 import org.chromium.net.RequestFinishedInfo;
19 import org.chromium.net.RequestPriority; 20 import org.chromium.net.RequestPriority;
20 import org.chromium.net.UploadDataProvider; 21 import org.chromium.net.UploadDataProvider;
21 import org.chromium.net.UrlRequest; 22 import org.chromium.net.UrlRequest;
22 import org.chromium.net.UrlRequestException; 23 import org.chromium.net.UrlRequestException;
23 import org.chromium.net.UrlResponseInfo; 24 import org.chromium.net.UrlResponseInfo;
24 25
25 import java.nio.ByteBuffer; 26 import java.nio.ByteBuffer;
(...skipping 16 matching lines...) Expand all
42 * native tasks to native network thread. Because Cancel could be called from 43 * native tasks to native network thread. Because Cancel could be called from
43 * any thread it is protected by mUrlRequestAdapterLock. 44 * any thread it is protected by mUrlRequestAdapterLock.
44 */ 45 */
45 @JNINamespace("cronet") 46 @JNINamespace("cronet")
46 // Qualifies UrlRequest.StatusListener which is used in onStatus, a JNI method. 47 // Qualifies UrlRequest.StatusListener which is used in onStatus, a JNI method.
47 @JNIAdditionalImport(UrlRequest.class) 48 @JNIAdditionalImport(UrlRequest.class)
48 @VisibleForTesting 49 @VisibleForTesting
49 public final class CronetUrlRequest implements UrlRequest { 50 public final class CronetUrlRequest implements UrlRequest {
50 private static final RequestFinishedInfo.Metrics EMPTY_METRICS = 51 private static final RequestFinishedInfo.Metrics EMPTY_METRICS =
51 new RequestFinishedInfo.Metrics(null, null, null, null); 52 new RequestFinishedInfo.Metrics(null, null, null, null);
53 private final boolean mAllowDirectExecutor;
52 54
53 /* Native adapter object, owned by UrlRequest. */ 55 /* Native adapter object, owned by UrlRequest. */
54 @GuardedBy("mUrlRequestAdapterLock") 56 @GuardedBy("mUrlRequestAdapterLock")
55 private long mUrlRequestAdapter; 57 private long mUrlRequestAdapter;
56 58
57 @GuardedBy("mUrlRequestAdapterLock") 59 @GuardedBy("mUrlRequestAdapterLock")
58 private boolean mStarted = false; 60 private boolean mStarted = false;
59 @GuardedBy("mUrlRequestAdapterLock") 61 @GuardedBy("mUrlRequestAdapterLock")
60 private boolean mWaitingOnRedirect = false; 62 private boolean mWaitingOnRedirect = false;
61 @GuardedBy("mUrlRequestAdapterLock") 63 @GuardedBy("mUrlRequestAdapterLock")
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 private Runnable mOnDestroyedCallbackForTesting; 104 private Runnable mOnDestroyedCallbackForTesting;
103 105
104 private static final class HeadersList extends ArrayList<Map.Entry<String, S tring>> {} 106 private static final class HeadersList extends ArrayList<Map.Entry<String, S tring>> {}
105 107
106 private final class OnReadCompletedRunnable implements Runnable { 108 private final class OnReadCompletedRunnable implements Runnable {
107 // Buffer passed back from current invocation of onReadCompleted. 109 // Buffer passed back from current invocation of onReadCompleted.
108 ByteBuffer mByteBuffer; 110 ByteBuffer mByteBuffer;
109 111
110 @Override 112 @Override
111 public void run() { 113 public void run() {
114 checkCallingThread();
112 // Null out mByteBuffer, to pass buffer ownership to callback or rel ease if done. 115 // Null out mByteBuffer, to pass buffer ownership to callback or rel ease if done.
113 ByteBuffer buffer = mByteBuffer; 116 ByteBuffer buffer = mByteBuffer;
114 mByteBuffer = null; 117 mByteBuffer = null;
115 118
116 try { 119 try {
117 synchronized (mUrlRequestAdapterLock) { 120 synchronized (mUrlRequestAdapterLock) {
118 if (isDoneLocked()) { 121 if (isDoneLocked()) {
119 return; 122 return;
120 } 123 }
121 mWaitingOnRead = true; 124 mWaitingOnRead = true;
122 } 125 }
123 mCallback.onReadCompleted(CronetUrlRequest.this, mResponseInfo, buffer); 126 mCallback.onReadCompleted(CronetUrlRequest.this, mResponseInfo, buffer);
124 } catch (Exception e) { 127 } catch (Exception e) {
125 onCallbackException(e); 128 onCallbackException(e);
126 } 129 }
127 } 130 }
128 } 131 }
129 132
130 CronetUrlRequest(CronetUrlRequestContext requestContext, String url, int pri ority, 133 CronetUrlRequest(CronetUrlRequestContext requestContext, String url, int pri ority,
131 UrlRequest.Callback callback, Executor executor, Collection<Object> requestAnnotations, 134 UrlRequest.Callback callback, Executor executor, Collection<Object> requestAnnotations,
132 boolean metricsCollectionEnabled, boolean disableCache, 135 boolean metricsCollectionEnabled, boolean disableCache,
133 boolean disableConnectionMigration) { 136 boolean disableConnectionMigration, boolean allowDirectExecutor) {
134 if (url == null) { 137 if (url == null) {
135 throw new NullPointerException("URL is required"); 138 throw new NullPointerException("URL is required");
136 } 139 }
137 if (callback == null) { 140 if (callback == null) {
138 throw new NullPointerException("Listener is required"); 141 throw new NullPointerException("Listener is required");
139 } 142 }
140 if (executor == null) { 143 if (executor == null) {
141 throw new NullPointerException("Executor is required"); 144 throw new NullPointerException("Executor is required");
142 } 145 }
143 if (requestAnnotations == null) { 146 if (requestAnnotations == null) {
144 throw new NullPointerException("requestAnnotations is required"); 147 throw new NullPointerException("requestAnnotations is required");
145 } 148 }
146 149
150 mAllowDirectExecutor = allowDirectExecutor;
147 mRequestContext = requestContext; 151 mRequestContext = requestContext;
148 mInitialUrl = url; 152 mInitialUrl = url;
149 mUrlChain.add(url); 153 mUrlChain.add(url);
150 mPriority = convertRequestPriority(priority); 154 mPriority = convertRequestPriority(priority);
151 mCallback = callback; 155 mCallback = callback;
152 mExecutor = executor; 156 mExecutor = executor;
153 mRequestAnnotations = requestAnnotations; 157 mRequestAnnotations = requestAnnotations;
154 mRequestMetricsAccumulator = 158 mRequestMetricsAccumulator =
155 metricsCollectionEnabled ? new UrlRequestMetricsAccumulator() : null; 159 metricsCollectionEnabled ? new UrlRequestMetricsAccumulator() : null;
156 mDisableCache = disableCache; 160 mDisableCache = disableCache;
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 throw new IllegalArgumentException( 220 throw new IllegalArgumentException(
217 "Invalid header " + header.getKey() + "=" + head er.getValue()); 221 "Invalid header " + header.getKey() + "=" + head er.getValue());
218 } 222 }
219 } 223 }
220 if (mUploadDataStream != null) { 224 if (mUploadDataStream != null) {
221 if (!hasContentType) { 225 if (!hasContentType) {
222 throw new IllegalArgumentException( 226 throw new IllegalArgumentException(
223 "Requests with upload data must have a Content-T ype."); 227 "Requests with upload data must have a Content-T ype.");
224 } 228 }
225 mStarted = true; 229 mStarted = true;
226 mUploadDataStream.postTaskToExecutor(new Runnable() { 230 mUploadDataStream.initializeWithRequest(CronetUrlRequest.thi s, new Runnable() {
227 @Override 231 @Override
228 public void run() { 232 public void run() {
229 mUploadDataStream.initializeWithRequest(CronetUrlReq uest.this);
230 synchronized (mUrlRequestAdapterLock) { 233 synchronized (mUrlRequestAdapterLock) {
231 if (isDoneLocked()) { 234 if (isDoneLocked()) {
232 return; 235 return;
233 } 236 }
234 mUploadDataStream.attachNativeAdapterToRequest(m UrlRequestAdapter); 237 mUploadDataStream.attachNativeAdapterToRequest(m UrlRequestAdapter);
235 startInternalLocked(); 238 startInternalLocked();
236 } 239 }
237 } 240 }
238 }); 241 });
239 return; 242 return;
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
360 /** 363 /**
361 * Posts task to application Executor. Used for Listener callbacks 364 * Posts task to application Executor. Used for Listener callbacks
362 * and other tasks that should not be executed on network thread. 365 * and other tasks that should not be executed on network thread.
363 */ 366 */
364 private void postTaskToExecutor(Runnable task) { 367 private void postTaskToExecutor(Runnable task) {
365 try { 368 try {
366 mExecutor.execute(task); 369 mExecutor.execute(task);
367 } catch (RejectedExecutionException failException) { 370 } catch (RejectedExecutionException failException) {
368 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception posting task to ex ecutor", 371 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception posting task to ex ecutor",
369 failException); 372 failException);
370 // If posting a task throws an exception, then there is no choice 373 // If posting a task throws an exception, then we fail the request. This exception could
371 // but to destroy the request without invoking the callback. 374 // be permanent (executor shutdown), transient (AbortPolicy, or Call erRunsPolicy with
372 destroyRequestAdapter(false); 375 // direct execution not permitted), or caused the the runnables we s ubmit if
mef 2016/08/31 20:24:25 nit: the the -> by the?
Charles 2016/08/31 22:36:41 Done.
376 // mUserExecutor is a direct executor and direct execution is not pe rmitted. In the
377 // latter two cases, we at least have a chance to inform the embedde r 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.
378 // failure, since failWithException does not enforce that onFailed() is not executed
379 // inline.
380 failWithException(
381 new UrlRequestException("Exception posting task to executor" , failException));
373 } 382 }
374 } 383 }
375 384
376 private static int convertRequestPriority(int priority) { 385 private static int convertRequestPriority(int priority) {
377 switch (priority) { 386 switch (priority) {
378 case Builder.REQUEST_PRIORITY_IDLE: 387 case Builder.REQUEST_PRIORITY_IDLE:
379 return RequestPriority.IDLE; 388 return RequestPriority.IDLE;
380 case Builder.REQUEST_PRIORITY_LOWEST: 389 case Builder.REQUEST_PRIORITY_LOWEST:
381 return RequestPriority.LOWEST; 390 return RequestPriority.LOWEST;
382 case Builder.REQUEST_PRIORITY_LOW: 391 case Builder.REQUEST_PRIORITY_LOW:
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
430 439
431 /** 440 /**
432 * If callback method throws an exception, request gets canceled 441 * If callback method throws an exception, request gets canceled
433 * and exception is reported via onFailed listener callback. 442 * and exception is reported via onFailed listener callback.
434 * Only called on the Executor. 443 * Only called on the Executor.
435 */ 444 */
436 private void onCallbackException(Exception e) { 445 private void onCallbackException(Exception e) {
437 UrlRequestException requestError = 446 UrlRequestException requestError =
438 new UrlRequestException("Exception received from UrlRequest.Call back", e); 447 new UrlRequestException("Exception received from UrlRequest.Call back", e);
439 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in CalledByNative meth od", e); 448 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in CalledByNative meth od", e);
440 // Do not call into listener if request is finished. 449 failWithException(requestError);
441 synchronized (mUrlRequestAdapterLock) {
442 if (isDoneLocked()) {
443 return;
444 }
445 destroyRequestAdapter(false);
446 }
447 try {
448 mCallback.onFailed(this, mResponseInfo, requestError);
449 } catch (Exception failException) {
450 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception notifying of faile d request",
451 failException);
452 }
453 } 450 }
454 451
455 /** 452 /**
456 * Called when UploadDataProvider encounters an error. 453 * Called when UploadDataProvider encounters an error.
457 */ 454 */
458 void onUploadException(Throwable e) { 455 void onUploadException(Throwable e) {
459 UrlRequestException uploadError = 456 UrlRequestException uploadError =
460 new UrlRequestException("Exception received from UploadDataProvi der", e); 457 new UrlRequestException("Exception received from UploadDataProvi der", e);
461 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in upload method", e); 458 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in upload method", e);
462 failWithException(uploadError); 459 failWithException(uploadError);
463 } 460 }
464 461
465 /** 462 /**
466 * Fails the request with an exception. Can be called on any thread. 463 * Fails the request with an exception. Can be called on any thread.
467 */ 464 */
468 private void failWithException(final UrlRequestException exception) { 465 private void failWithException(final UrlRequestException exception) {
466 synchronized (mUrlRequestAdapterLock) {
467 if (isDoneLocked()) {
468 return;
469 }
470 destroyRequestAdapter(false);
471 }
469 Runnable task = new Runnable() { 472 Runnable task = new Runnable() {
470 @Override 473 @Override
471 public void run() { 474 public void run() {
472 synchronized (mUrlRequestAdapterLock) {
473 if (isDoneLocked()) {
474 return;
475 }
476 destroyRequestAdapter(false);
477 }
478 try { 475 try {
479 mCallback.onFailed(CronetUrlRequest.this, mResponseInfo, exc eption); 476 mCallback.onFailed(CronetUrlRequest.this, mResponseInfo, exc eption);
480 } catch (Exception e) { 477 } catch (Exception e) {
481 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in onError method", e); 478 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in onFaile d method", e);
482 } 479 }
483 } 480 }
484 }; 481 };
485 postTaskToExecutor(task); 482 try {
483 mExecutor.execute(task);
484 } catch (RejectedExecutionException e) {
485 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception posting task to ex ecutor", e);
486 }
486 } 487 }
487 488
488 //////////////////////////////////////////////// 489 ////////////////////////////////////////////////
489 // Private methods called by the native code. 490 // Private methods called by the native code.
490 // Always called on network thread. 491 // Always called on network thread.
491 //////////////////////////////////////////////// 492 ////////////////////////////////////////////////
492 493
493 /** 494 /**
494 * Called before following redirects. The redirect will only be followed if 495 * Called before following redirects. The redirect will only be followed if
495 * {@link #followRedirect()} is called. If the redirect response has a body, it will be ignored. 496 * {@link #followRedirect()} is called. If the redirect response has a body, it will be ignored.
(...skipping 14 matching lines...) Expand all
510 httpStatusText, headers, wasCached, negotiatedProtocol, proxySer ver); 511 httpStatusText, headers, wasCached, negotiatedProtocol, proxySer ver);
511 mReceivedBytesCountFromRedirects += receivedBytesCount; 512 mReceivedBytesCountFromRedirects += receivedBytesCount;
512 responseInfo.setReceivedBytesCount(mReceivedBytesCountFromRedirects); 513 responseInfo.setReceivedBytesCount(mReceivedBytesCountFromRedirects);
513 514
514 // Have to do this after creating responseInfo. 515 // Have to do this after creating responseInfo.
515 mUrlChain.add(newLocation); 516 mUrlChain.add(newLocation);
516 517
517 Runnable task = new Runnable() { 518 Runnable task = new Runnable() {
518 @Override 519 @Override
519 public void run() { 520 public void run() {
521 checkCallingThread();
520 synchronized (mUrlRequestAdapterLock) { 522 synchronized (mUrlRequestAdapterLock) {
521 if (isDoneLocked()) { 523 if (isDoneLocked()) {
522 return; 524 return;
523 } 525 }
524 mWaitingOnRedirect = true; 526 mWaitingOnRedirect = true;
525 } 527 }
526 528
527 try { 529 try {
528 mCallback.onRedirectReceived(CronetUrlRequest.this, response Info, newLocation); 530 mCallback.onRedirectReceived(CronetUrlRequest.this, response Info, newLocation);
529 } catch (Exception e) { 531 } catch (Exception e) {
(...skipping 10 matching lines...) Expand all
540 */ 542 */
541 @SuppressWarnings("unused") 543 @SuppressWarnings("unused")
542 @CalledByNative 544 @CalledByNative
543 private void onResponseStarted(int httpStatusCode, String httpStatusText, St ring[] headers, 545 private void onResponseStarted(int httpStatusCode, String httpStatusText, St ring[] headers,
544 boolean wasCached, String negotiatedProtocol, String proxyServer) { 546 boolean wasCached, String negotiatedProtocol, String proxyServer) {
545 mResponseInfo = prepareResponseInfoOnNetworkThread(httpStatusCode, httpS tatusText, headers, 547 mResponseInfo = prepareResponseInfoOnNetworkThread(httpStatusCode, httpS tatusText, headers,
546 wasCached, negotiatedProtocol, proxyServer); 548 wasCached, negotiatedProtocol, proxyServer);
547 Runnable task = new Runnable() { 549 Runnable task = new Runnable() {
548 @Override 550 @Override
549 public void run() { 551 public void run() {
552 checkCallingThread();
550 synchronized (mUrlRequestAdapterLock) { 553 synchronized (mUrlRequestAdapterLock) {
551 if (isDoneLocked()) { 554 if (isDoneLocked()) {
552 return; 555 return;
553 } 556 }
554 if (mRequestMetricsAccumulator != null) { 557 if (mRequestMetricsAccumulator != null) {
555 mRequestMetricsAccumulator.onResponseStarted(); 558 mRequestMetricsAccumulator.onResponseStarted();
556 } 559 }
557 mWaitingOnRead = true; 560 mWaitingOnRead = true;
558 } 561 }
559 562
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after
729 } 732 }
730 } 733 }
731 734
732 private void onResponseStarted() { 735 private void onResponseStarted() {
733 if (mRequestStartTime != null && mTtfbMs == null) { 736 if (mRequestStartTime != null && mTtfbMs == null) {
734 mTtfbMs = SystemClock.elapsedRealtime() - mRequestStartTime; 737 mTtfbMs = SystemClock.elapsedRealtime() - mRequestStartTime;
735 } 738 }
736 } 739 }
737 } 740 }
738 741
742 /** Enforces prohibition of direct execution. */
743 private void checkCallingThread() {
744 if (!mAllowDirectExecutor && mRequestContext.isNetworkThread(Thread.curr entThread())) {
745 throw new InlineExecutionProhibitedException();
746 }
747 }
748
739 // Native methods are implemented in cronet_url_request_adapter.cc. 749 // Native methods are implemented in cronet_url_request_adapter.cc.
740 750
741 private native long nativeCreateRequestAdapter(long urlRequestContextAdapter , String url, 751 private native long nativeCreateRequestAdapter(long urlRequestContextAdapter , String url,
742 int priority, boolean disableCache, boolean disableConnectionMigrati on); 752 int priority, boolean disableCache, boolean disableConnectionMigrati on);
743 753
744 @NativeClassQualifiedName("CronetURLRequestAdapter") 754 @NativeClassQualifiedName("CronetURLRequestAdapter")
745 private native boolean nativeSetHttpMethod(long nativePtr, String method); 755 private native boolean nativeSetHttpMethod(long nativePtr, String method);
746 756
747 @NativeClassQualifiedName("CronetURLRequestAdapter") 757 @NativeClassQualifiedName("CronetURLRequestAdapter")
748 private native boolean nativeAddRequestHeader(long nativePtr, String name, S tring value); 758 private native boolean nativeAddRequestHeader(long nativePtr, String name, S tring value);
749 759
750 @NativeClassQualifiedName("CronetURLRequestAdapter") 760 @NativeClassQualifiedName("CronetURLRequestAdapter")
751 private native void nativeStart(long nativePtr); 761 private native void nativeStart(long nativePtr);
752 762
753 @NativeClassQualifiedName("CronetURLRequestAdapter") 763 @NativeClassQualifiedName("CronetURLRequestAdapter")
754 private native void nativeFollowDeferredRedirect(long nativePtr); 764 private native void nativeFollowDeferredRedirect(long nativePtr);
755 765
756 @NativeClassQualifiedName("CronetURLRequestAdapter") 766 @NativeClassQualifiedName("CronetURLRequestAdapter")
757 private native boolean nativeReadData( 767 private native boolean nativeReadData(
758 long nativePtr, ByteBuffer byteBuffer, int position, int capacity); 768 long nativePtr, ByteBuffer byteBuffer, int position, int capacity);
759 769
760 @NativeClassQualifiedName("CronetURLRequestAdapter") 770 @NativeClassQualifiedName("CronetURLRequestAdapter")
761 private native void nativeDestroy(long nativePtr, boolean sendOnCanceled); 771 private native void nativeDestroy(long nativePtr, boolean sendOnCanceled);
762 772
763 @NativeClassQualifiedName("CronetURLRequestAdapter") 773 @NativeClassQualifiedName("CronetURLRequestAdapter")
764 private native void nativeGetStatus(long nativePtr, UrlRequest.StatusListene r listener); 774 private native void nativeGetStatus(long nativePtr, UrlRequest.StatusListene r listener);
765 } 775 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698