1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 
18 package com.squareup.okhttp;
19 
20 import libcore.net.event.NetworkEventDispatcher;
21 import libcore.net.event.NetworkEventListener;
22 
23 /**
24  * A provider of the shared Android {@link ConnectionPool}. This class is aware of network
25  * configuration change events: When the network configuration changes the pool object is discarded
26  * and a later calls to {@link #get()} will return a new pool.
27  */
28 public class ConfigAwareConnectionPool {
29 
30   private static final long CONNECTION_POOL_DEFAULT_KEEP_ALIVE_DURATION_MS = 5 * 60 * 1000; // 5 min
31 
32   private static final int CONNECTION_POOL_MAX_IDLE_CONNECTIONS;
33   private static final long CONNECTION_POOL_KEEP_ALIVE_DURATION_MS;
34   static {
35     String keepAliveProperty = System.getProperty("http.keepAlive");
36     String keepAliveDurationProperty = System.getProperty("http.keepAliveDuration");
37     String maxIdleConnectionsProperty = System.getProperty("http.maxConnections");
38     CONNECTION_POOL_KEEP_ALIVE_DURATION_MS = (keepAliveDurationProperty != null
39         ? Long.parseLong(keepAliveDurationProperty)
40         : CONNECTION_POOL_DEFAULT_KEEP_ALIVE_DURATION_MS);
41     if (keepAliveProperty != null && !Boolean.parseBoolean(keepAliveProperty)) {
42       CONNECTION_POOL_MAX_IDLE_CONNECTIONS = 0;
43     } else if (maxIdleConnectionsProperty != null) {
44       CONNECTION_POOL_MAX_IDLE_CONNECTIONS = Integer.parseInt(maxIdleConnectionsProperty);
45     } else {
46       CONNECTION_POOL_MAX_IDLE_CONNECTIONS = 5;
47     }
48   }
49 
50   private static final ConfigAwareConnectionPool instance = new ConfigAwareConnectionPool();
51 
52   private final NetworkEventDispatcher networkEventDispatcher;
53 
54   /**
55    * {@code true} if the ConnectionPool reset has been registered with the
56    * {@link NetworkEventDispatcher}.
57    */
58   private boolean networkEventListenerRegistered;
59 
60   private ConnectionPool connectionPool;
61 
62   /** Visible for testing. Use {@link #getInstance()} */
ConfigAwareConnectionPool(NetworkEventDispatcher networkEventDispatcher)63   protected ConfigAwareConnectionPool(NetworkEventDispatcher networkEventDispatcher) {
64     this.networkEventDispatcher = networkEventDispatcher;
65   }
66 
ConfigAwareConnectionPool()67   private ConfigAwareConnectionPool() {
68     networkEventDispatcher = NetworkEventDispatcher.getInstance();
69   }
70 
getInstance()71   public static ConfigAwareConnectionPool getInstance() {
72     return instance;
73   }
74 
75   /**
76    * Returns the current {@link ConnectionPool} to use.
77    */
get()78   public synchronized ConnectionPool get() {
79     if (connectionPool == null) {
80       // Only register the listener once the first time a ConnectionPool is created.
81       if (!networkEventListenerRegistered) {
82         networkEventDispatcher.addListener(new NetworkEventListener() {
83           @Override
84           public void onNetworkConfigurationChanged() {
85             synchronized (ConfigAwareConnectionPool.this) {
86               // If the network config has changed then existing pooled connections should not be
87               // re-used. By setting connectionPool to null it ensures that the next time
88               // getConnectionPool() is called a new pool will be created.
89               connectionPool = null;
90             }
91           }
92         });
93         networkEventListenerRegistered = true;
94       }
95       connectionPool = new ConnectionPool(
96           CONNECTION_POOL_MAX_IDLE_CONNECTIONS, CONNECTION_POOL_KEEP_ALIVE_DURATION_MS);
97     }
98     return connectionPool;
99   }
100 }
101