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 |