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