| OLD | NEW |
| 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; | |
| 8 import android.support.annotation.Nullable; | |
| 9 import android.util.Log; | 7 import android.util.Log; |
| 10 | 8 |
| 11 import org.chromium.base.VisibleForTesting; | 9 import org.chromium.base.VisibleForTesting; |
| 12 import org.chromium.base.annotations.CalledByNative; | 10 import org.chromium.base.annotations.CalledByNative; |
| 13 import org.chromium.base.annotations.JNIAdditionalImport; | 11 import org.chromium.base.annotations.JNIAdditionalImport; |
| 14 import org.chromium.base.annotations.JNINamespace; | 12 import org.chromium.base.annotations.JNINamespace; |
| 15 import org.chromium.base.annotations.NativeClassQualifiedName; | 13 import org.chromium.base.annotations.NativeClassQualifiedName; |
| 16 import org.chromium.net.InlineExecutionProhibitedException; | 14 import org.chromium.net.InlineExecutionProhibitedException; |
| 17 import org.chromium.net.Preconditions; | 15 import org.chromium.net.Preconditions; |
| 18 import org.chromium.net.QuicException; | 16 import org.chromium.net.QuicException; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 41 * and post tasks with listener calls onto Executor. Upon return from listener | 39 * and post tasks with listener calls onto Executor. Upon return from listener |
| 42 * callback native request adapter is called on executive thread and posts | 40 * callback native request adapter is called on executive thread and posts |
| 43 * native tasks to native network thread. Because Cancel could be called from | 41 * native tasks to native network thread. Because Cancel could be called from |
| 44 * any thread it is protected by mUrlRequestAdapterLock. | 42 * any thread it is protected by mUrlRequestAdapterLock. |
| 45 */ | 43 */ |
| 46 @JNINamespace("cronet") | 44 @JNINamespace("cronet") |
| 47 // Qualifies UrlRequest.StatusListener which is used in onStatus, a JNI method. | 45 // Qualifies UrlRequest.StatusListener which is used in onStatus, a JNI method. |
| 48 @JNIAdditionalImport(UrlRequest.class) | 46 @JNIAdditionalImport(UrlRequest.class) |
| 49 @VisibleForTesting | 47 @VisibleForTesting |
| 50 public final class CronetUrlRequest implements UrlRequest { | 48 public final class CronetUrlRequest implements UrlRequest { |
| 51 private static final RequestFinishedInfo.Metrics EMPTY_METRICS = | |
| 52 new CronetMetrics(null, null, null, null); | |
| 53 private final boolean mAllowDirectExecutor; | 49 private final boolean mAllowDirectExecutor; |
| 54 | 50 |
| 55 /* Native adapter object, owned by UrlRequest. */ | 51 /* Native adapter object, owned by UrlRequest. */ |
| 56 @GuardedBy("mUrlRequestAdapterLock") | 52 @GuardedBy("mUrlRequestAdapterLock") |
| 57 private long mUrlRequestAdapter; | 53 private long mUrlRequestAdapter; |
| 58 | 54 |
| 59 @GuardedBy("mUrlRequestAdapterLock") | 55 @GuardedBy("mUrlRequestAdapterLock") |
| 60 private boolean mStarted = false; | 56 private boolean mStarted = false; |
| 61 @GuardedBy("mUrlRequestAdapterLock") | 57 @GuardedBy("mUrlRequestAdapterLock") |
| 62 private boolean mWaitingOnRedirect = false; | 58 private boolean mWaitingOnRedirect = false; |
| 63 @GuardedBy("mUrlRequestAdapterLock") | 59 @GuardedBy("mUrlRequestAdapterLock") |
| 64 private boolean mWaitingOnRead = false; | 60 private boolean mWaitingOnRead = false; |
| 65 @GuardedBy("mUrlRequestAdapterLock") | 61 @GuardedBy("mUrlRequestAdapterLock") |
| 66 @Nullable | |
| 67 private final UrlRequestMetricsAccumulator mRequestMetricsAccumulator; | |
| 68 @GuardedBy("mUrlRequestAdapterLock") | |
| 69 private RequestFinishedInfo.Metrics mMetrics; | 62 private RequestFinishedInfo.Metrics mMetrics; |
| 70 | 63 |
| 71 /* | 64 /* |
| 72 * Synchronize access to mUrlRequestAdapter, mStarted, mWaitingOnRedirect, | 65 * Synchronize access to mUrlRequestAdapter, mStarted, mWaitingOnRedirect, |
| 73 * and mWaitingOnRead. | 66 * and mWaitingOnRead. |
| 74 */ | 67 */ |
| 75 private final Object mUrlRequestAdapterLock = new Object(); | 68 private final Object mUrlRequestAdapterLock = new Object(); |
| 76 private final CronetUrlRequestContext mRequestContext; | 69 private final CronetUrlRequestContext mRequestContext; |
| 77 private final Executor mExecutor; | 70 private final Executor mExecutor; |
| 78 | 71 |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 127 } | 120 } |
| 128 mCallback.onReadCompleted(CronetUrlRequest.this, mResponseInfo,
buffer); | 121 mCallback.onReadCompleted(CronetUrlRequest.this, mResponseInfo,
buffer); |
| 129 } catch (Exception e) { | 122 } catch (Exception e) { |
| 130 onCallbackException(e); | 123 onCallbackException(e); |
| 131 } | 124 } |
| 132 } | 125 } |
| 133 } | 126 } |
| 134 | 127 |
| 135 CronetUrlRequest(CronetUrlRequestContext requestContext, String url, int pri
ority, | 128 CronetUrlRequest(CronetUrlRequestContext requestContext, String url, int pri
ority, |
| 136 UrlRequest.Callback callback, Executor executor, Collection<Object>
requestAnnotations, | 129 UrlRequest.Callback callback, Executor executor, Collection<Object>
requestAnnotations, |
| 137 boolean metricsCollectionEnabled, boolean disableCache, | 130 boolean disableCache, boolean disableConnectionMigration, boolean al
lowDirectExecutor) { |
| 138 boolean disableConnectionMigration, boolean allowDirectExecutor) { | |
| 139 if (url == null) { | 131 if (url == null) { |
| 140 throw new NullPointerException("URL is required"); | 132 throw new NullPointerException("URL is required"); |
| 141 } | 133 } |
| 142 if (callback == null) { | 134 if (callback == null) { |
| 143 throw new NullPointerException("Listener is required"); | 135 throw new NullPointerException("Listener is required"); |
| 144 } | 136 } |
| 145 if (executor == null) { | 137 if (executor == null) { |
| 146 throw new NullPointerException("Executor is required"); | 138 throw new NullPointerException("Executor is required"); |
| 147 } | 139 } |
| 148 if (requestAnnotations == null) { | 140 if (requestAnnotations == null) { |
| 149 throw new NullPointerException("requestAnnotations is required"); | 141 throw new NullPointerException("requestAnnotations is required"); |
| 150 } | 142 } |
| 151 | 143 |
| 152 mAllowDirectExecutor = allowDirectExecutor; | 144 mAllowDirectExecutor = allowDirectExecutor; |
| 153 mRequestContext = requestContext; | 145 mRequestContext = requestContext; |
| 154 mInitialUrl = url; | 146 mInitialUrl = url; |
| 155 mUrlChain.add(url); | 147 mUrlChain.add(url); |
| 156 mPriority = convertRequestPriority(priority); | 148 mPriority = convertRequestPriority(priority); |
| 157 mCallback = callback; | 149 mCallback = callback; |
| 158 mExecutor = executor; | 150 mExecutor = executor; |
| 159 mRequestAnnotations = requestAnnotations; | 151 mRequestAnnotations = requestAnnotations; |
| 160 mRequestMetricsAccumulator = | |
| 161 metricsCollectionEnabled ? new UrlRequestMetricsAccumulator() :
null; | |
| 162 mDisableCache = disableCache; | 152 mDisableCache = disableCache; |
| 163 mDisableConnectionMigration = disableConnectionMigration; | 153 mDisableConnectionMigration = disableConnectionMigration; |
| 164 } | 154 } |
| 165 | 155 |
| 166 @Override | 156 @Override |
| 167 public void setHttpMethod(String method) { | 157 public void setHttpMethod(String method) { |
| 168 checkNotStarted(); | 158 checkNotStarted(); |
| 169 if (method == null) { | 159 if (method == null) { |
| 170 throw new NullPointerException("Method is required."); | 160 throw new NullPointerException("Method is required."); |
| 171 } | 161 } |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 startInternalLocked(); | 245 startInternalLocked(); |
| 256 } | 246 } |
| 257 } | 247 } |
| 258 | 248 |
| 259 /* | 249 /* |
| 260 * Starts fully configured request. Could execute on UploadDataProvider exec
utor. | 250 * Starts fully configured request. Could execute on UploadDataProvider exec
utor. |
| 261 * Caller is expected to ensure that request isn't canceled and mUrlRequestA
dapter is valid. | 251 * Caller is expected to ensure that request isn't canceled and mUrlRequestA
dapter is valid. |
| 262 */ | 252 */ |
| 263 @GuardedBy("mUrlRequestAdapterLock") | 253 @GuardedBy("mUrlRequestAdapterLock") |
| 264 private void startInternalLocked() { | 254 private void startInternalLocked() { |
| 265 if (mRequestMetricsAccumulator != null) { | |
| 266 mRequestMetricsAccumulator.onRequestStarted(); | |
| 267 } | |
| 268 nativeStart(mUrlRequestAdapter); | 255 nativeStart(mUrlRequestAdapter); |
| 269 } | 256 } |
| 270 | 257 |
| 271 @Override | 258 @Override |
| 272 public void followRedirect() { | 259 public void followRedirect() { |
| 273 synchronized (mUrlRequestAdapterLock) { | 260 synchronized (mUrlRequestAdapterLock) { |
| 274 if (!mWaitingOnRedirect) { | 261 if (!mWaitingOnRedirect) { |
| 275 throw new IllegalStateException("No redirect to follow."); | 262 throw new IllegalStateException("No redirect to follow."); |
| 276 } | 263 } |
| 277 mWaitingOnRedirect = false; | 264 mWaitingOnRedirect = false; |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 421 throw new IllegalStateException("Request is already started."); | 408 throw new IllegalStateException("Request is already started."); |
| 422 } | 409 } |
| 423 } | 410 } |
| 424 } | 411 } |
| 425 | 412 |
| 426 private void destroyRequestAdapter(boolean sendOnCanceled) { | 413 private void destroyRequestAdapter(boolean sendOnCanceled) { |
| 427 synchronized (mUrlRequestAdapterLock) { | 414 synchronized (mUrlRequestAdapterLock) { |
| 428 if (mUrlRequestAdapter == 0) { | 415 if (mUrlRequestAdapter == 0) { |
| 429 return; | 416 return; |
| 430 } | 417 } |
| 431 if (mRequestMetricsAccumulator != null) { | |
| 432 mRequestMetricsAccumulator.onRequestFinished(); | |
| 433 } | |
| 434 nativeDestroy(mUrlRequestAdapter, sendOnCanceled); | 418 nativeDestroy(mUrlRequestAdapter, sendOnCanceled); |
| 435 mRequestContext.onRequestDestroyed(); | 419 mRequestContext.onRequestDestroyed(); |
| 436 mUrlRequestAdapter = 0; | 420 mUrlRequestAdapter = 0; |
| 437 if (mOnDestroyedCallbackForTesting != null) { | 421 if (mOnDestroyedCallbackForTesting != null) { |
| 438 mOnDestroyedCallbackForTesting.run(); | 422 mOnDestroyedCallbackForTesting.run(); |
| 439 } | 423 } |
| 440 } | 424 } |
| 441 } | 425 } |
| 442 | 426 |
| 443 /** | 427 /** |
| (...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 550 mResponseInfo = prepareResponseInfoOnNetworkThread(httpStatusCode, httpS
tatusText, headers, | 534 mResponseInfo = prepareResponseInfoOnNetworkThread(httpStatusCode, httpS
tatusText, headers, |
| 551 wasCached, negotiatedProtocol, proxyServer); | 535 wasCached, negotiatedProtocol, proxyServer); |
| 552 Runnable task = new Runnable() { | 536 Runnable task = new Runnable() { |
| 553 @Override | 537 @Override |
| 554 public void run() { | 538 public void run() { |
| 555 checkCallingThread(); | 539 checkCallingThread(); |
| 556 synchronized (mUrlRequestAdapterLock) { | 540 synchronized (mUrlRequestAdapterLock) { |
| 557 if (isDoneLocked()) { | 541 if (isDoneLocked()) { |
| 558 return; | 542 return; |
| 559 } | 543 } |
| 560 if (mRequestMetricsAccumulator != null) { | |
| 561 mRequestMetricsAccumulator.onResponseStarted(); | |
| 562 } | |
| 563 mWaitingOnRead = true; | 544 mWaitingOnRead = true; |
| 564 } | 545 } |
| 565 | 546 |
| 566 try { | 547 try { |
| 567 mCallback.onResponseStarted(CronetUrlRequest.this, mResponse
Info); | 548 mCallback.onResponseStarted(CronetUrlRequest.this, mResponse
Info); |
| 568 } catch (Exception e) { | 549 } catch (Exception e) { |
| 569 onCallbackException(e); | 550 onCallbackException(e); |
| 570 } | 551 } |
| 571 } | 552 } |
| 572 }; | 553 }; |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 722 } | 703 } |
| 723 mRequestContext.reportFinished(getRequestFinishedInfo()); | 704 mRequestContext.reportFinished(getRequestFinishedInfo()); |
| 724 } | 705 } |
| 725 | 706 |
| 726 private RequestFinishedInfo getRequestFinishedInfo() { | 707 private RequestFinishedInfo getRequestFinishedInfo() { |
| 727 // TODO(mgersh): fill in real values for finishedReason and exception | 708 // TODO(mgersh): fill in real values for finishedReason and exception |
| 728 return new RequestFinishedInfo(mInitialUrl, mRequestAnnotations, mMetric
s, | 709 return new RequestFinishedInfo(mInitialUrl, mRequestAnnotations, mMetric
s, |
| 729 RequestFinishedInfo.SUCCEEDED, mResponseInfo, null); | 710 RequestFinishedInfo.SUCCEEDED, mResponseInfo, null); |
| 730 } | 711 } |
| 731 | 712 |
| 732 private final class UrlRequestMetricsAccumulator { | |
| 733 @Nullable | |
| 734 private Long mRequestStartTime; | |
| 735 @Nullable | |
| 736 private Long mTtfbMs; | |
| 737 @Nullable | |
| 738 private Long mTotalTimeMs; | |
| 739 | |
| 740 private RequestFinishedInfo.Metrics getRequestMetrics() { | |
| 741 return new CronetMetrics(mTtfbMs, mTotalTimeMs, | |
| 742 null, // TODO(klm): Compute sentBytesCount. | |
| 743 (mResponseInfo != null ? mResponseInfo.getReceivedBytesCount
() : 0)); | |
| 744 } | |
| 745 | |
| 746 private void onRequestStarted() { | |
| 747 if (mRequestStartTime != null) { | |
| 748 throw new IllegalStateException("onRequestStarted called repeate
dly"); | |
| 749 } | |
| 750 mRequestStartTime = SystemClock.elapsedRealtime(); | |
| 751 } | |
| 752 | |
| 753 private void onRequestFinished() { | |
| 754 if (mRequestStartTime != null && mTotalTimeMs == null) { | |
| 755 mTotalTimeMs = SystemClock.elapsedRealtime() - mRequestStartTime
; | |
| 756 } | |
| 757 } | |
| 758 | |
| 759 private void onResponseStarted() { | |
| 760 if (mRequestStartTime != null && mTtfbMs == null) { | |
| 761 mTtfbMs = SystemClock.elapsedRealtime() - mRequestStartTime; | |
| 762 } | |
| 763 } | |
| 764 } | |
| 765 | |
| 766 /** Enforces prohibition of direct execution. */ | 713 /** Enforces prohibition of direct execution. */ |
| 767 void checkCallingThread() { | 714 void checkCallingThread() { |
| 768 if (!mAllowDirectExecutor && mRequestContext.isNetworkThread(Thread.curr
entThread())) { | 715 if (!mAllowDirectExecutor && mRequestContext.isNetworkThread(Thread.curr
entThread())) { |
| 769 throw new InlineExecutionProhibitedException(); | 716 throw new InlineExecutionProhibitedException(); |
| 770 } | 717 } |
| 771 } | 718 } |
| 772 | 719 |
| 773 // Native methods are implemented in cronet_url_request_adapter.cc. | 720 // Native methods are implemented in cronet_url_request_adapter.cc. |
| 774 | 721 |
| 775 private native long nativeCreateRequestAdapter(long urlRequestContextAdapter
, String url, | 722 private native long nativeCreateRequestAdapter(long urlRequestContextAdapter
, String url, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 791 @NativeClassQualifiedName("CronetURLRequestAdapter") | 738 @NativeClassQualifiedName("CronetURLRequestAdapter") |
| 792 private native boolean nativeReadData( | 739 private native boolean nativeReadData( |
| 793 long nativePtr, ByteBuffer byteBuffer, int position, int capacity); | 740 long nativePtr, ByteBuffer byteBuffer, int position, int capacity); |
| 794 | 741 |
| 795 @NativeClassQualifiedName("CronetURLRequestAdapter") | 742 @NativeClassQualifiedName("CronetURLRequestAdapter") |
| 796 private native void nativeDestroy(long nativePtr, boolean sendOnCanceled); | 743 private native void nativeDestroy(long nativePtr, boolean sendOnCanceled); |
| 797 | 744 |
| 798 @NativeClassQualifiedName("CronetURLRequestAdapter") | 745 @NativeClassQualifiedName("CronetURLRequestAdapter") |
| 799 private native void nativeGetStatus(long nativePtr, UrlRequest.StatusListene
r listener); | 746 private native void nativeGetStatus(long nativePtr, UrlRequest.StatusListene
r listener); |
| 800 } | 747 } |
| OLD | NEW |