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

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

Issue 1849753002: [Cronet] Separate Cronet implementation and API by package name. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: sync Created 4 years, 5 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
(Empty)
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
3 // found in the LICENSE file.
4
5 package org.chromium.net;
6
7 import android.content.Context;
8 import android.os.Build;
9 import android.os.ConditionVariable;
10 import android.os.Handler;
11 import android.os.Looper;
12 import android.os.Process;
13 import android.util.Log;
14
15 import org.chromium.base.ObserverList;
16 import org.chromium.base.VisibleForTesting;
17 import org.chromium.base.annotations.CalledByNative;
18 import org.chromium.base.annotations.JNINamespace;
19 import org.chromium.base.annotations.NativeClassQualifiedName;
20 import org.chromium.base.annotations.UsedByReflection;
21 import org.chromium.net.urlconnection.CronetHttpURLConnection;
22 import org.chromium.net.urlconnection.CronetURLStreamHandlerFactory;
23
24 import java.net.Proxy;
25 import java.net.URL;
26 import java.net.URLConnection;
27 import java.net.URLStreamHandlerFactory;
28 import java.util.Collection;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.concurrent.Executor;
32 import java.util.concurrent.RejectedExecutionException;
33 import java.util.concurrent.atomic.AtomicInteger;
34
35 import javax.annotation.concurrent.GuardedBy;
36
37 /**
38 * CronetEngine using Chromium HTTP stack implementation.
39 */
40 @JNINamespace("cronet")
41 @UsedByReflection("CronetEngine.java")
42 class CronetUrlRequestContext extends CronetEngine {
43 private static final int LOG_NONE = 3; // LOG(FATAL), no VLOG.
44 private static final int LOG_DEBUG = -1; // LOG(FATAL...INFO), VLOG(1)
45 private static final int LOG_VERBOSE = -2; // LOG(FATAL...INFO), VLOG(2)
46 static final String LOG_TAG = "ChromiumNetwork";
47
48 /**
49 * Synchronize access to mUrlRequestContextAdapter and shutdown routine.
50 */
51 private final Object mLock = new Object();
52 private final ConditionVariable mInitCompleted = new ConditionVariable(false );
53 private final AtomicInteger mActiveRequestCount = new AtomicInteger(0);
54
55 private long mUrlRequestContextAdapter = 0;
56 private Thread mNetworkThread;
57
58 private Executor mNetworkQualityExecutor;
59 private boolean mNetworkQualityEstimatorEnabled;
60
61 /** Locks operations on network quality listeners, because listener
62 * addition and removal may occur on a different thread from notification.
63 */
64 private final Object mNetworkQualityLock = new Object();
65
66 @GuardedBy("mNetworkQualityLock")
67 private final ObserverList<NetworkQualityRttListener> mRttListenerList =
68 new ObserverList<NetworkQualityRttListener>();
69
70 @GuardedBy("mNetworkQualityLock")
71 private final ObserverList<NetworkQualityThroughputListener> mThroughputList enerList =
72 new ObserverList<NetworkQualityThroughputListener>();
73
74 @GuardedBy("mNetworkQualityLock")
75 private final ObserverList<RequestFinishedListener> mFinishedListenerList =
76 new ObserverList<RequestFinishedListener>();
77
78 /**
79 * Synchronize access to mCertVerifierData.
80 */
81 private ConditionVariable mWaitGetCertVerifierDataComplete = new ConditionVa riable();
82
83 /** Holds CertVerifier data. */
84 private String mCertVerifierData;
85
86 @UsedByReflection("CronetEngine.java")
87 public CronetUrlRequestContext(final CronetEngine.Builder builder) {
88 CronetLibraryLoader.ensureInitialized(builder.getContext(), builder);
89 nativeSetMinLogLevel(getLoggingLevel());
90 synchronized (mLock) {
91 mUrlRequestContextAdapter = nativeCreateRequestContextAdapter(
92 createNativeUrlRequestContextConfig(builder.getContext(), bu ilder));
93 if (mUrlRequestContextAdapter == 0) {
94 throw new NullPointerException("Context Adapter creation failed. ");
95 }
96 mNetworkQualityEstimatorEnabled = builder.networkQualityEstimatorEna bled();
97 }
98
99 // Init native Chromium URLRequestContext on main UI thread.
100 Runnable task = new Runnable() {
101 @Override
102 public void run() {
103 CronetLibraryLoader.ensureInitializedOnMainThread(builder.getCon text());
104 synchronized (mLock) {
105 // mUrlRequestContextAdapter is guaranteed to exist until
106 // initialization on main and network threads completes and
107 // initNetworkThread is called back on network thread.
108 nativeInitRequestContextOnMainThread(mUrlRequestContextAdapt er);
109 }
110 }
111 };
112 // Run task immediately or post it to the UI thread.
113 if (Looper.getMainLooper() == Looper.myLooper()) {
114 task.run();
115 } else {
116 new Handler(Looper.getMainLooper()).post(task);
117 }
118 }
119
120 static long createNativeUrlRequestContextConfig(
121 final Context context, CronetEngine.Builder builder) {
122 final long urlRequestContextConfig = nativeCreateRequestContextConfig(
123 builder.getUserAgent(), builder.storagePath(), builder.quicEnabl ed(),
124 builder.getDefaultQuicUserAgentId(context), builder.http2Enabled (),
125 builder.sdchEnabled(), builder.dataReductionProxyKey(),
126 builder.dataReductionProxyPrimaryProxy(), builder.dataReductionP roxyFallbackProxy(),
127 builder.dataReductionProxySecureProxyCheckUrl(), builder.cacheDi sabled(),
128 builder.httpCacheMode(), builder.httpCacheMaxSize(), builder.exp erimentalOptions(),
129 builder.mockCertVerifier(), builder.networkQualityEstimatorEnabl ed(),
130 builder.publicKeyPinningBypassForLocalTrustAnchorsEnabled(),
131 builder.certVerifierData());
132 for (Builder.QuicHint quicHint : builder.quicHints()) {
133 nativeAddQuicHint(urlRequestContextConfig, quicHint.mHost, quicHint. mPort,
134 quicHint.mAlternatePort);
135 }
136 for (Builder.Pkp pkp : builder.publicKeyPins()) {
137 nativeAddPkp(urlRequestContextConfig, pkp.mHost, pkp.mHashes, pkp.mI ncludeSubdomains,
138 pkp.mExpirationDate.getTime());
139 }
140 return urlRequestContextConfig;
141 }
142
143 @Override
144 public UrlRequest createRequest(String url, UrlRequest.Callback callback, Ex ecutor executor,
145 int priority, Collection<Object> requestAnnotations, boolean disable Cache,
146 boolean disableConnectionMigration) {
147 synchronized (mLock) {
148 checkHaveAdapter();
149 boolean metricsCollectionEnabled = mNetworkQualityEstimatorEnabled;
150 if (metricsCollectionEnabled) { // Collect metrics only if someone i s listening.
151 synchronized (mNetworkQualityLock) {
152 metricsCollectionEnabled = !mFinishedListenerList.isEmpty();
153 }
154 }
155 return new CronetUrlRequest(this, url, priority, callback, executor, requestAnnotations,
156 metricsCollectionEnabled, disableCache, disableConnectionMig ration);
157 }
158 }
159
160 @Override
161 BidirectionalStream createBidirectionalStream(String url, BidirectionalStrea m.Callback callback,
162 Executor executor, String httpMethod, List<Map.Entry<String, String> > requestHeaders,
163 @BidirectionalStream.Builder.StreamPriority int priority, boolean di sableAutoFlush,
164 boolean delayRequestHeadersUntilFirstFlush) {
165 synchronized (mLock) {
166 checkHaveAdapter();
167 return new CronetBidirectionalStream(this, url, priority, callback, executor,
168 httpMethod, requestHeaders, disableAutoFlush,
169 delayRequestHeadersUntilFirstFlush);
170 }
171 }
172
173 @Override
174 public boolean isEnabled() {
175 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
176 }
177
178 @Override
179 public String getVersionString() {
180 return "Cronet/" + Version.getVersion();
181 }
182
183 @Override
184 public void shutdown() {
185 synchronized (mLock) {
186 checkHaveAdapter();
187 if (mActiveRequestCount.get() != 0) {
188 throw new IllegalStateException(
189 "Cannot shutdown with active requests.");
190 }
191 // Destroying adapter stops the network thread, so it cannot be
192 // called on network thread.
193 if (Thread.currentThread() == mNetworkThread) {
194 throw new IllegalThreadStateException(
195 "Cannot shutdown from network thread.");
196 }
197 }
198 // Wait for init to complete on main and network thread (without lock,
199 // so other thread could access it).
200 mInitCompleted.block();
201
202 synchronized (mLock) {
203 // It is possible that adapter is already destroyed on another threa d.
204 if (!haveRequestContextAdapter()) {
205 return;
206 }
207 nativeDestroy(mUrlRequestContextAdapter);
208 mUrlRequestContextAdapter = 0;
209 }
210 }
211
212 @Override
213 public void startNetLogToFile(String fileName, boolean logAll) {
214 synchronized (mLock) {
215 checkHaveAdapter();
216 nativeStartNetLogToFile(mUrlRequestContextAdapter, fileName,
217 logAll);
218 }
219 }
220
221 @Override
222 public void stopNetLog() {
223 synchronized (mLock) {
224 checkHaveAdapter();
225 nativeStopNetLog(mUrlRequestContextAdapter);
226 }
227 }
228
229 @Override
230 public String getCertVerifierData(long timeout) {
231 if (timeout < 0) {
232 throw new IllegalArgumentException("timeout must be a positive value ");
233 } else if (timeout == 0) {
234 timeout = 100;
235 }
236 mWaitGetCertVerifierDataComplete.close();
237 synchronized (mLock) {
238 checkHaveAdapter();
239 nativeGetCertVerifierData(mUrlRequestContextAdapter);
240 }
241 mWaitGetCertVerifierDataComplete.block(timeout);
242 return mCertVerifierData;
243 }
244
245 // This method is intentionally non-static to ensure Cronet native library
246 // is loaded by class constructor.
247 @Override
248 public byte[] getGlobalMetricsDeltas() {
249 return nativeGetHistogramDeltas();
250 }
251
252 /**
253 * TODO(tbansal): http://crbug.com/618034 Remove this API once all
254 * embedders have switched to using a request finished listener that
255 * provides its own executor.
256 */
257 @Override
258 public void setRequestFinishedListenerExecutor(Executor executor) {
259 if (!mNetworkQualityEstimatorEnabled) {
260 throw new IllegalStateException("Network quality estimator not enabl ed");
261 }
262 if (executor == null) {
263 throw new NullPointerException("Request finished listener requires a n executor");
264 }
265 if (mNetworkQualityExecutor != null) {
266 throw new NullPointerException("Request finished listener executor a lready set");
267 }
268 mNetworkQualityExecutor = executor;
269 }
270
271 /**
272 * TODO(tbansal): http://crbug.com/618034 Remove this API once all
273 * embedders have switched to using CronetEngine builder for enabling
274 * network quality estimator.
275 */
276 @Override
277 public void enableNetworkQualityEstimator(Executor executor) {
278 if (mNetworkQualityEstimatorEnabled) {
279 throw new IllegalStateException("Network quality estimator already e nabled");
280 }
281 mNetworkQualityEstimatorEnabled = true;
282 if (executor == null) {
283 throw new NullPointerException("Network quality estimator requires a n executor");
284 }
285 mNetworkQualityExecutor = executor;
286 synchronized (mLock) {
287 checkHaveAdapter();
288 nativeEnableNetworkQualityEstimator(mUrlRequestContextAdapter);
289 }
290 }
291
292 @VisibleForTesting
293 @Override
294 void configureNetworkQualityEstimatorForTesting(
295 boolean useLocalHostRequests, boolean useSmallerResponses) {
296 if (!mNetworkQualityEstimatorEnabled) {
297 throw new IllegalStateException("Network quality estimator must be e nabled");
298 }
299 synchronized (mLock) {
300 checkHaveAdapter();
301 nativeConfigureNetworkQualityEstimatorForTesting(
302 mUrlRequestContextAdapter, useLocalHostRequests, useSmallerR esponses);
303 }
304 }
305
306 @Override
307 public void addRttListener(NetworkQualityRttListener listener) {
308 if (!mNetworkQualityEstimatorEnabled) {
309 throw new IllegalStateException("Network quality estimator must be e nabled");
310 }
311 synchronized (mNetworkQualityLock) {
312 if (mRttListenerList.isEmpty()) {
313 synchronized (mLock) {
314 checkHaveAdapter();
315 nativeProvideRTTObservations(mUrlRequestContextAdapter, true );
316 }
317 }
318 mRttListenerList.addObserver(listener);
319 }
320 }
321
322 @Override
323 public void removeRttListener(NetworkQualityRttListener listener) {
324 if (!mNetworkQualityEstimatorEnabled) {
325 throw new IllegalStateException("Network quality estimator must be e nabled");
326 }
327 synchronized (mNetworkQualityLock) {
328 mRttListenerList.removeObserver(listener);
329 if (mRttListenerList.isEmpty()) {
330 synchronized (mLock) {
331 checkHaveAdapter();
332 nativeProvideRTTObservations(mUrlRequestContextAdapter, fals e);
333 }
334 }
335 }
336 }
337
338 @Override
339 public void addThroughputListener(NetworkQualityThroughputListener listener) {
340 if (!mNetworkQualityEstimatorEnabled) {
341 throw new IllegalStateException("Network quality estimator must be e nabled");
342 }
343 synchronized (mNetworkQualityLock) {
344 if (mThroughputListenerList.isEmpty()) {
345 synchronized (mLock) {
346 checkHaveAdapter();
347 nativeProvideThroughputObservations(mUrlRequestContextAdapte r, true);
348 }
349 }
350 mThroughputListenerList.addObserver(listener);
351 }
352 }
353
354 @Override
355 public void removeThroughputListener(NetworkQualityThroughputListener listen er) {
356 if (!mNetworkQualityEstimatorEnabled) {
357 throw new IllegalStateException("Network quality estimator must be e nabled");
358 }
359 synchronized (mNetworkQualityLock) {
360 mThroughputListenerList.removeObserver(listener);
361 if (mThroughputListenerList.isEmpty()) {
362 synchronized (mLock) {
363 checkHaveAdapter();
364 nativeProvideThroughputObservations(mUrlRequestContextAdapte r, false);
365 }
366 }
367 }
368 }
369
370 /**
371 * TODO(tbansal): http://crbug.com/618034 Remove this API once all
372 * embedders have switched to using a request finished listener that
373 * provides its own executor.
374 */
375 @Override
376 public void addRequestFinishedListener(RequestFinishedListener listener) {
377 if (!mNetworkQualityEstimatorEnabled) {
378 throw new IllegalStateException("Network quality estimator must be e nabled");
379 }
380 // RequestFinishedListener does not provide its own executor.
381 if (mNetworkQualityExecutor == null) {
382 throw new IllegalStateException("Executor must not be null");
383 }
384 synchronized (mNetworkQualityLock) {
385 mFinishedListenerList.addObserver(listener);
386 }
387 }
388
389 /**
390 * TODO(tbansal): http://crbug.com/618034 Remove this API.
391 */
392 @Override
393 public void removeRequestFinishedListener(RequestFinishedListener listener) {
394 if (!mNetworkQualityEstimatorEnabled) {
395 throw new IllegalStateException("Network quality estimator must be e nabled");
396 }
397 synchronized (mNetworkQualityLock) {
398 mFinishedListenerList.removeObserver(listener);
399 }
400 }
401
402 @Override
403 public URLConnection openConnection(URL url) {
404 return openConnection(url, Proxy.NO_PROXY);
405 }
406
407 @Override
408 public URLConnection openConnection(URL url, Proxy proxy) {
409 if (proxy.type() != Proxy.Type.DIRECT) {
410 throw new UnsupportedOperationException();
411 }
412 String protocol = url.getProtocol();
413 if ("http".equals(protocol) || "https".equals(protocol)) {
414 return new CronetHttpURLConnection(url, this);
415 }
416 throw new UnsupportedOperationException("Unexpected protocol:" + protoco l);
417 }
418
419 @Override
420 public URLStreamHandlerFactory createURLStreamHandlerFactory() {
421 return new CronetURLStreamHandlerFactory(this);
422 }
423
424 /**
425 * Mark request as started to prevent shutdown when there are active
426 * requests.
427 */
428 void onRequestStarted() {
429 mActiveRequestCount.incrementAndGet();
430 }
431
432 /**
433 * Mark request as finished to allow shutdown when there are no active
434 * requests.
435 */
436 void onRequestDestroyed() {
437 mActiveRequestCount.decrementAndGet();
438 }
439
440 @VisibleForTesting
441 long getUrlRequestContextAdapter() {
442 synchronized (mLock) {
443 checkHaveAdapter();
444 return mUrlRequestContextAdapter;
445 }
446 }
447
448 private void checkHaveAdapter() throws IllegalStateException {
449 if (!haveRequestContextAdapter()) {
450 throw new IllegalStateException("Engine is shut down.");
451 }
452 }
453
454 private boolean haveRequestContextAdapter() {
455 return mUrlRequestContextAdapter != 0;
456 }
457
458 /**
459 * @return loggingLevel see {@link #LOG_NONE}, {@link #LOG_DEBUG} and
460 * {@link #LOG_VERBOSE}.
461 */
462 private int getLoggingLevel() {
463 int loggingLevel;
464 if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) {
465 loggingLevel = LOG_VERBOSE;
466 } else if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
467 loggingLevel = LOG_DEBUG;
468 } else {
469 loggingLevel = LOG_NONE;
470 }
471 return loggingLevel;
472 }
473
474 @SuppressWarnings("unused")
475 @CalledByNative
476 private void initNetworkThread() {
477 synchronized (mLock) {
478 mNetworkThread = Thread.currentThread();
479 mInitCompleted.open();
480 }
481 Thread.currentThread().setName("ChromiumNet");
482 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
483 }
484
485 @SuppressWarnings("unused")
486 @CalledByNative
487 private void onRttObservation(final int rttMs, final long whenMs, final int source) {
488 synchronized (mNetworkQualityLock) {
489 for (final NetworkQualityRttListener listener : mRttListenerList) {
490 Runnable task = new Runnable() {
491 @Override
492 public void run() {
493 listener.onRttObservation(rttMs, whenMs, source);
494 }
495 };
496 postObservationTaskToExecutor(listener.getExecutor(), task);
497 }
498 }
499 }
500
501 @SuppressWarnings("unused")
502 @CalledByNative
503 private void onThroughputObservation(
504 final int throughputKbps, final long whenMs, final int source) {
505 synchronized (mNetworkQualityLock) {
506 for (final NetworkQualityThroughputListener listener : mThroughputLi stenerList) {
507 Runnable task = new Runnable() {
508 @Override
509 public void run() {
510 listener.onThroughputObservation(throughputKbps, whenMs, source);
511 }
512 };
513 postObservationTaskToExecutor(listener.getExecutor(), task);
514 }
515 }
516 }
517
518 @SuppressWarnings("unused")
519 @CalledByNative
520 private void onGetCertVerifierData(String certVerifierData) {
521 mCertVerifierData = certVerifierData;
522 mWaitGetCertVerifierDataComplete.open();
523 }
524
525 void reportFinished(final CronetUrlRequest request) {
526 if (!mNetworkQualityEstimatorEnabled) {
527 return;
528 }
529 // If no request finished listener has been added, then mNetworkQualityE xecutor may be
530 // null. Exit early to avoid posting to a null executor.
531 synchronized (mNetworkQualityLock) {
532 if (mFinishedListenerList.isEmpty()) {
533 return;
534 }
535 }
536 Runnable task = new Runnable() {
537 @Override
538 public void run() {
539 synchronized (mNetworkQualityLock) {
540 UrlRequestInfo requestInfo = request.getRequestInfo();
541 for (RequestFinishedListener listener : mFinishedListenerLis t) {
542 listener.onRequestFinished(requestInfo);
543 }
544 }
545 }
546 };
547 // Use {@link mNetworkQualityExecutor} since
548 // RequestFInishedListeners do not provide an executor.
549 postObservationTaskToExecutor(mNetworkQualityExecutor, task);
550 }
551
552 private static void postObservationTaskToExecutor(Executor executor, Runnabl e task) {
553 try {
554 executor.execute(task);
555 } catch (RejectedExecutionException failException) {
556 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception posting task to ex ecutor",
557 failException);
558 }
559 }
560
561 // Native methods are implemented in cronet_url_request_context_adapter.cc.
562 private static native long nativeCreateRequestContextConfig(String userAgent ,
563 String storagePath, boolean quicEnabled, String quicUserAgentId, boo lean http2Enabled,
564 boolean sdchEnabled, String dataReductionProxyKey,
565 String dataReductionProxyPrimaryProxy, String dataReductionProxyFall backProxy,
566 String dataReductionProxySecureProxyCheckUrl, boolean disableCache, int httpCacheMode,
567 long httpCacheMaxSize, String experimentalOptions, long mockCertVeri fier,
568 boolean enableNetworkQualityEstimator,
569 boolean bypassPublicKeyPinningForLocalTrustAnchors, String certVerif ierData);
570
571 private static native void nativeAddQuicHint(
572 long urlRequestContextConfig, String host, int port, int alternatePo rt);
573
574 private static native void nativeAddPkp(long urlRequestContextConfig, String host,
575 byte[][] hashes, boolean includeSubdomains, long expirationTime);
576
577 private static native long nativeCreateRequestContextAdapter(long urlRequest ContextConfig);
578
579 private static native int nativeSetMinLogLevel(int loggingLevel);
580
581 private static native byte[] nativeGetHistogramDeltas();
582
583 @NativeClassQualifiedName("CronetURLRequestContextAdapter")
584 private native void nativeDestroy(long nativePtr);
585
586 @NativeClassQualifiedName("CronetURLRequestContextAdapter")
587 private native void nativeStartNetLogToFile(long nativePtr,
588 String fileName, boolean logAll);
589
590 @NativeClassQualifiedName("CronetURLRequestContextAdapter")
591 private native void nativeStopNetLog(long nativePtr);
592
593 @NativeClassQualifiedName("CronetURLRequestContextAdapter")
594 private native void nativeGetCertVerifierData(long nativePtr);
595
596 @NativeClassQualifiedName("CronetURLRequestContextAdapter")
597 private native void nativeInitRequestContextOnMainThread(long nativePtr);
598
599 @NativeClassQualifiedName("CronetURLRequestContextAdapter")
600 private native void nativeConfigureNetworkQualityEstimatorForTesting(
601 long nativePtr, boolean useLocalHostRequests, boolean useSmallerResp onses);
602
603 @NativeClassQualifiedName("CronetURLRequestContextAdapter")
604 private native void nativeEnableNetworkQualityEstimator(long nativePtr);
605
606 @NativeClassQualifiedName("CronetURLRequestContextAdapter")
607 private native void nativeProvideRTTObservations(long nativePtr, boolean sho uld);
608
609 @NativeClassQualifiedName("CronetURLRequestContextAdapter")
610 private native void nativeProvideThroughputObservations(long nativePtr, bool ean should);
611 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698