• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
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.impl;
6 
7 import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
8 import static android.os.Process.THREAD_PRIORITY_MORE_FAVORABLE;
9 
10 import android.content.Context;
11 import android.os.Build;
12 import android.util.Log;
13 
14 import org.chromium.net.BidirectionalStream;
15 import org.chromium.net.ExperimentalBidirectionalStream;
16 import org.chromium.net.NetworkQualityRttListener;
17 import org.chromium.net.NetworkQualityThroughputListener;
18 import org.chromium.net.RequestFinishedInfo;
19 import org.chromium.net.UrlRequest;
20 import org.chromium.net.impl.CronetLogger.CronetEngineBuilderInfo;
21 import org.chromium.net.impl.CronetLogger.CronetSource;
22 import org.chromium.net.impl.CronetLogger.CronetVersion;
23 
24 import java.io.IOException;
25 import java.net.Proxy;
26 import java.net.URL;
27 import java.net.URLConnection;
28 import java.net.URLStreamHandler;
29 import java.net.URLStreamHandlerFactory;
30 import java.util.Collection;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.concurrent.Executor;
34 import java.util.concurrent.ExecutorService;
35 import java.util.concurrent.Executors;
36 import java.util.concurrent.LinkedBlockingQueue;
37 import java.util.concurrent.ThreadFactory;
38 import java.util.concurrent.ThreadPoolExecutor;
39 import java.util.concurrent.TimeUnit;
40 import java.util.concurrent.atomic.AtomicInteger;
41 
42 /**
43  * {@link java.net.HttpURLConnection} backed CronetEngine.
44  *
45  * <p>Does not support netlogs, transferred data measurement, bidistream, cache, or priority.
46  */
47 public final class JavaCronetEngine extends CronetEngineBase {
48     private static final String TAG = JavaCronetEngine.class.getSimpleName();
49 
50     private final String mUserAgent;
51     private final ExecutorService mExecutorService;
52     private final int mCronetEngineId;
53     private final CronetLogger mLogger;
54     private final AtomicInteger mActiveRequestCount = new AtomicInteger();
55 
56     /** The network handle to be used for requests that do not explicitly specify one. **/
57     private long mNetworkHandle = DEFAULT_NETWORK_HANDLE;
58 
59     private final Context mContext;
60 
JavaCronetEngine(CronetEngineBuilderImpl builder)61     public JavaCronetEngine(CronetEngineBuilderImpl builder) {
62         mContext = builder.getContext();
63         mCronetEngineId = hashCode();
64         // On android, all background threads (and all threads that are part
65         // of background processes) are put in a cgroup that is allowed to
66         // consume up to 5% of CPU - these worker threads spend the vast
67         // majority of their time waiting on I/O, so making them contend with
68         // background applications for a slice of CPU doesn't make much sense.
69         // We want to hurry up and get idle.
70         final int threadPriority =
71                 builder.threadPriority(THREAD_PRIORITY_BACKGROUND + THREAD_PRIORITY_MORE_FAVORABLE);
72         this.mUserAgent = builder.getUserAgent();
73         // For unbounded work queues, the effective maximum pool size is
74         // equivalent to the core pool size.
75         this.mExecutorService =
76                 new ThreadPoolExecutor(
77                         10,
78                         10,
79                         50,
80                         TimeUnit.SECONDS,
81                         new LinkedBlockingQueue<Runnable>(),
82                         new ThreadFactory() {
83                             @Override
84                             public Thread newThread(final Runnable r) {
85                                 return Executors.defaultThreadFactory()
86                                         .newThread(
87                                                 new Runnable() {
88                                                     @Override
89                                                     public void run() {
90                                                         Thread.currentThread()
91                                                                 .setName("JavaCronetEngine");
92                                                         android.os.Process.setThreadPriority(
93                                                                 threadPriority);
94                                                         r.run();
95                                                     }
96                                                 });
97                             }
98                         });
99         mLogger = CronetLoggerFactory.createNoOpLogger();
100         try {
101             mLogger.logCronetEngineCreation(
102                     mCronetEngineId,
103                     new CronetEngineBuilderInfo(builder),
104                     buildCronetVersion(),
105                     CronetSource.CRONET_SOURCE_FALLBACK);
106         } catch (RuntimeException e) {
107             // Handle any issue gracefully, we should never crash due failures while logging.
108             Log.e(TAG, "Error while trying to log JavaCronetEngine creation: ", e);
109         }
110         Log.w(
111                 TAG,
112                 "using the fallback Cronet Engine implementation. Performance will suffer "
113                         + "and many HTTP client features, including caching, will not work.");
114     }
115 
116     /** Increment the number of active requests. */
incrementActiveRequestCount()117     void incrementActiveRequestCount() {
118         mActiveRequestCount.incrementAndGet();
119     }
120 
121     /** Decrement the number of active requests. */
decrementActiveRequestCount()122     void decrementActiveRequestCount() {
123         mActiveRequestCount.decrementAndGet();
124     }
125 
getCronetEngineId()126     int getCronetEngineId() {
127         return mCronetEngineId;
128     }
129 
getCronetLogger()130     CronetLogger getCronetLogger() {
131         return mLogger;
132     }
133 
getContext()134     Context getContext() {
135         return mContext;
136     }
137 
138     @Override
createRequest( String url, UrlRequest.Callback callback, Executor executor, int priority, Collection<Object> connectionAnnotations, boolean disableCache, boolean disableConnectionMigration, boolean allowDirectExecutor, boolean trafficStatsTagSet, int trafficStatsTag, boolean trafficStatsUidSet, int trafficStatsUid, RequestFinishedInfo.Listener requestFinishedListener, int idempotency, long networkHandle)139     public UrlRequestBase createRequest(
140             String url,
141             UrlRequest.Callback callback,
142             Executor executor,
143             int priority,
144             Collection<Object> connectionAnnotations,
145             boolean disableCache,
146             boolean disableConnectionMigration,
147             boolean allowDirectExecutor,
148             boolean trafficStatsTagSet,
149             int trafficStatsTag,
150             boolean trafficStatsUidSet,
151             int trafficStatsUid,
152             RequestFinishedInfo.Listener requestFinishedListener,
153             int idempotency,
154             long networkHandle) {
155         if (networkHandle != DEFAULT_NETWORK_HANDLE) {
156             mNetworkHandle = networkHandle;
157         }
158         return new JavaUrlRequest(
159                 this,
160                 callback,
161                 mExecutorService,
162                 executor,
163                 url,
164                 mUserAgent,
165                 allowDirectExecutor,
166                 trafficStatsTagSet,
167                 trafficStatsTag,
168                 trafficStatsUidSet,
169                 trafficStatsUid,
170                 mNetworkHandle);
171     }
172 
173     @Override
createBidirectionalStream( String url, BidirectionalStream.Callback callback, Executor executor, String httpMethod, List<Map.Entry<String, String>> requestHeaders, @StreamPriority int priority, boolean delayRequestHeadersUntilFirstFlush, Collection<Object> connectionAnnotations, boolean trafficStatsTagSet, int trafficStatsTag, boolean trafficStatsUidSet, int trafficStatsUid, long networkHandle)174     protected ExperimentalBidirectionalStream createBidirectionalStream(
175             String url,
176             BidirectionalStream.Callback callback,
177             Executor executor,
178             String httpMethod,
179             List<Map.Entry<String, String>> requestHeaders,
180             @StreamPriority int priority,
181             boolean delayRequestHeadersUntilFirstFlush,
182             Collection<Object> connectionAnnotations,
183             boolean trafficStatsTagSet,
184             int trafficStatsTag,
185             boolean trafficStatsUidSet,
186             int trafficStatsUid,
187             long networkHandle) {
188         throw new UnsupportedOperationException(
189                 "Can't create a bidi stream - httpurlconnection doesn't have those APIs");
190     }
191 
192     @Override
newBidirectionalStreamBuilder( String url, BidirectionalStream.Callback callback, Executor executor)193     public ExperimentalBidirectionalStream.Builder newBidirectionalStreamBuilder(
194             String url, BidirectionalStream.Callback callback, Executor executor) {
195         throw new UnsupportedOperationException(
196                 "The bidirectional stream API is not supported by the Java implementation "
197                         + "of Cronet Engine");
198     }
199 
200     @Override
getVersionString()201     public String getVersionString() {
202         return "CronetHttpURLConnection/" + ImplVersion.getCronetVersionWithLastChange();
203     }
204 
buildCronetVersion()205     private CronetVersion buildCronetVersion() {
206         String version = getVersionString();
207         // getVersionString()'s output looks like "Cronet/w.x.y.z@hash". CronetVersion only cares
208         // about the "w.x.y.z" bit.
209         version = version.split("/")[1];
210         version = version.split("@")[0];
211         return new CronetVersion(version);
212     }
213 
214     @Override
shutdown()215     public void shutdown() {
216         mExecutorService.shutdown();
217     }
218 
219     @Override
startNetLogToFile(String fileName, boolean logAll)220     public void startNetLogToFile(String fileName, boolean logAll) {}
221 
222     @Override
startNetLogToDisk(String dirPath, boolean logAll, int maxSize)223     public void startNetLogToDisk(String dirPath, boolean logAll, int maxSize) {}
224 
225     @Override
stopNetLog()226     public void stopNetLog() {}
227 
228     @Override
getGlobalMetricsDeltas()229     public byte[] getGlobalMetricsDeltas() {
230         return new byte[0];
231     }
232 
233     @Override
getEffectiveConnectionType()234     public int getEffectiveConnectionType() {
235         return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
236     }
237 
238     @Override
getHttpRttMs()239     public int getHttpRttMs() {
240         return CONNECTION_METRIC_UNKNOWN;
241     }
242 
243     @Override
getTransportRttMs()244     public int getTransportRttMs() {
245         return CONNECTION_METRIC_UNKNOWN;
246     }
247 
248     @Override
getDownstreamThroughputKbps()249     public int getDownstreamThroughputKbps() {
250         return CONNECTION_METRIC_UNKNOWN;
251     }
252 
253     @Override
getActiveRequestCount()254     public int getActiveRequestCount() {
255         return mActiveRequestCount.get();
256     }
257 
258     @Override
bindToNetwork(long networkHandle)259     public void bindToNetwork(long networkHandle) {
260         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
261             throw new UnsupportedOperationException(
262                     "This multi-network Java implementation is available starting from Android Pie");
263         }
264         mNetworkHandle = networkHandle;
265     }
266 
267     @Override
configureNetworkQualityEstimatorForTesting( boolean useLocalHostRequests, boolean useSmallerResponses, boolean disableOfflineCheck)268     public void configureNetworkQualityEstimatorForTesting(
269             boolean useLocalHostRequests,
270             boolean useSmallerResponses,
271             boolean disableOfflineCheck) {}
272 
273     @Override
addRttListener(NetworkQualityRttListener listener)274     public void addRttListener(NetworkQualityRttListener listener) {}
275 
276     @Override
removeRttListener(NetworkQualityRttListener listener)277     public void removeRttListener(NetworkQualityRttListener listener) {}
278 
279     @Override
addThroughputListener(NetworkQualityThroughputListener listener)280     public void addThroughputListener(NetworkQualityThroughputListener listener) {}
281 
282     @Override
removeThroughputListener(NetworkQualityThroughputListener listener)283     public void removeThroughputListener(NetworkQualityThroughputListener listener) {}
284 
285     @Override
addRequestFinishedListener(RequestFinishedInfo.Listener listener)286     public void addRequestFinishedListener(RequestFinishedInfo.Listener listener) {}
287 
288     @Override
removeRequestFinishedListener(RequestFinishedInfo.Listener listener)289     public void removeRequestFinishedListener(RequestFinishedInfo.Listener listener) {}
290 
291     @Override
openConnection(URL url)292     public URLConnection openConnection(URL url) throws IOException {
293         return url.openConnection();
294     }
295 
296     @Override
openConnection(URL url, Proxy proxy)297     public URLConnection openConnection(URL url, Proxy proxy) throws IOException {
298         return url.openConnection(proxy);
299     }
300 
301     @Override
createURLStreamHandlerFactory()302     public URLStreamHandlerFactory createURLStreamHandlerFactory() {
303         // Returning null causes this factory to pass though, which ends up using the platform's
304         // implementation.
305         return new URLStreamHandlerFactory() {
306             @Override
307             public URLStreamHandler createURLStreamHandler(String protocol) {
308                 return null;
309             }
310         };
311     }
312 }
313