1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net; 18 19 import android.content.Context; 20 import android.os.Handler; 21 import android.os.Looper; 22 import android.os.Message; 23 import android.os.Messenger; 24 import android.util.Log; 25 import android.util.SparseArray; 26 27 import com.android.internal.annotations.VisibleForTesting; 28 import com.android.internal.util.IndentingPrintWriter; 29 import com.android.internal.util.Protocol; 30 31 import java.io.FileDescriptor; 32 import java.io.PrintWriter; 33 34 /** 35 * A NetworkFactory is an entity that creates NetworkAgent objects. 36 * The bearers register with ConnectivityService using {@link #register} and 37 * their factory will start receiving scored NetworkRequests. NetworkRequests 38 * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by 39 * overridden function. All of these can be dynamic - changing NetworkCapabilities 40 * or score forces re-evaluation of all current requests. 41 * 42 * If any requests pass the filter some overrideable functions will be called. 43 * If the bearer only cares about very simple start/stopNetwork callbacks, those 44 * functions can be overridden. If the bearer needs more interaction, it can 45 * override addNetworkRequest and removeNetworkRequest which will give it each 46 * request that passes their current filters. 47 * @hide 48 **/ 49 public class NetworkFactory extends Handler { 50 private static final boolean DBG = true; 51 private static final boolean VDBG = false; 52 53 private static final int BASE = Protocol.BASE_NETWORK_FACTORY; 54 /** 55 * Pass a network request to the bearer. If the bearer believes it can 56 * satisfy the request it should connect to the network and create a 57 * NetworkAgent. Once the NetworkAgent is fully functional it will 58 * register itself with ConnectivityService using registerNetworkAgent. 59 * If the bearer cannot immediately satisfy the request (no network, 60 * user disabled the radio, lower-scored network) it should remember 61 * any NetworkRequests it may be able to satisfy in the future. It may 62 * disregard any that it will never be able to service, for example 63 * those requiring a different bearer. 64 * msg.obj = NetworkRequest 65 * msg.arg1 = score - the score of the any network currently satisfying this 66 * request. If this bearer knows in advance it cannot 67 * exceed this score it should not try to connect, holding the request 68 * for the future. 69 * Note that subsequent events may give a different (lower 70 * or higher) score for this request, transmitted to each 71 * NetworkFactory through additional CMD_REQUEST_NETWORK msgs 72 * with the same NetworkRequest but an updated score. 73 * Also, network conditions may change for this bearer 74 * allowing for a better score in the future. 75 */ 76 public static final int CMD_REQUEST_NETWORK = BASE; 77 78 /** 79 * Cancel a network request 80 * msg.obj = NetworkRequest 81 */ 82 public static final int CMD_CANCEL_REQUEST = BASE + 1; 83 84 /** 85 * Internally used to set our best-guess score. 86 * msg.arg1 = new score 87 */ 88 private static final int CMD_SET_SCORE = BASE + 2; 89 90 /** 91 * Internally used to set our current filter for coarse bandwidth changes with 92 * technology changes. 93 * msg.obj = new filter 94 */ 95 private static final int CMD_SET_FILTER = BASE + 3; 96 97 private final Context mContext; 98 private final String LOG_TAG; 99 100 private final SparseArray<NetworkRequestInfo> mNetworkRequests = 101 new SparseArray<NetworkRequestInfo>(); 102 103 private int mScore; 104 private NetworkCapabilities mCapabilityFilter; 105 106 private int mRefCount = 0; 107 private Messenger mMessenger = null; 108 109 public NetworkFactory(Looper looper, Context context, String logTag, 110 NetworkCapabilities filter) { 111 super(looper); 112 LOG_TAG = logTag; 113 mContext = context; 114 mCapabilityFilter = filter; 115 } 116 117 public void register() { 118 if (DBG) log("Registering NetworkFactory"); 119 if (mMessenger == null) { 120 mMessenger = new Messenger(this); 121 ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, LOG_TAG); 122 } 123 } 124 125 public void unregister() { 126 if (DBG) log("Unregistering NetworkFactory"); 127 if (mMessenger != null) { 128 ConnectivityManager.from(mContext).unregisterNetworkFactory(mMessenger); 129 mMessenger = null; 130 } 131 } 132 133 @Override 134 public void handleMessage(Message msg) { 135 switch (msg.what) { 136 case CMD_REQUEST_NETWORK: { 137 handleAddRequest((NetworkRequest)msg.obj, msg.arg1); 138 break; 139 } 140 case CMD_CANCEL_REQUEST: { 141 handleRemoveRequest((NetworkRequest) msg.obj); 142 break; 143 } 144 case CMD_SET_SCORE: { 145 handleSetScore(msg.arg1); 146 break; 147 } 148 case CMD_SET_FILTER: { 149 handleSetFilter((NetworkCapabilities) msg.obj); 150 break; 151 } 152 } 153 } 154 155 private class NetworkRequestInfo { 156 public final NetworkRequest request; 157 public int score; 158 public boolean requested; // do we have a request outstanding, limited by score 159 160 public NetworkRequestInfo(NetworkRequest request, int score) { 161 this.request = request; 162 this.score = score; 163 this.requested = false; 164 } 165 166 @Override 167 public String toString() { 168 return "{" + request + ", score=" + score + ", requested=" + requested + "}"; 169 } 170 } 171 172 @VisibleForTesting 173 protected void handleAddRequest(NetworkRequest request, int score) { 174 NetworkRequestInfo n = mNetworkRequests.get(request.requestId); 175 if (n == null) { 176 if (DBG) log("got request " + request + " with score " + score); 177 n = new NetworkRequestInfo(request, score); 178 mNetworkRequests.put(n.request.requestId, n); 179 } else { 180 if (VDBG) log("new score " + score + " for exisiting request " + request); 181 n.score = score; 182 } 183 if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); 184 185 evalRequest(n); 186 } 187 188 @VisibleForTesting 189 protected void handleRemoveRequest(NetworkRequest request) { 190 NetworkRequestInfo n = mNetworkRequests.get(request.requestId); 191 if (n != null) { 192 mNetworkRequests.remove(request.requestId); 193 if (n.requested) releaseNetworkFor(n.request); 194 } 195 } 196 197 private void handleSetScore(int score) { 198 mScore = score; 199 evalRequests(); 200 } 201 202 private void handleSetFilter(NetworkCapabilities netCap) { 203 mCapabilityFilter = netCap; 204 evalRequests(); 205 } 206 207 /** 208 * Overridable function to provide complex filtering. 209 * Called for every request every time a new NetworkRequest is seen 210 * and whenever the filterScore or filterNetworkCapabilities change. 211 * 212 * acceptRequest can be overriden to provide complex filter behavior 213 * for the incoming requests 214 * 215 * For output, this class will call {@link #needNetworkFor} and 216 * {@link #releaseNetworkFor} for every request that passes the filters. 217 * If you don't need to see every request, you can leave the base 218 * implementations of those two functions and instead override 219 * {@link #startNetwork} and {@link #stopNetwork}. 220 * 221 * If you want to see every score fluctuation on every request, set 222 * your score filter to a very high number and watch {@link #needNetworkFor}. 223 * 224 * @return {@code true} to accept the request. 225 */ 226 public boolean acceptRequest(NetworkRequest request, int score) { 227 return true; 228 } 229 230 private void evalRequest(NetworkRequestInfo n) { 231 if (VDBG) log("evalRequest"); 232 if (n.requested == false && n.score < mScore && 233 n.request.networkCapabilities.satisfiedByNetworkCapabilities( 234 mCapabilityFilter) && acceptRequest(n.request, n.score)) { 235 if (VDBG) log(" needNetworkFor"); 236 needNetworkFor(n.request, n.score); 237 n.requested = true; 238 } else if (n.requested == true && 239 (n.score > mScore || n.request.networkCapabilities.satisfiedByNetworkCapabilities( 240 mCapabilityFilter) == false || acceptRequest(n.request, n.score) == false)) { 241 if (VDBG) log(" releaseNetworkFor"); 242 releaseNetworkFor(n.request); 243 n.requested = false; 244 } else { 245 if (VDBG) log(" done"); 246 } 247 } 248 249 private void evalRequests() { 250 for (int i = 0; i < mNetworkRequests.size(); i++) { 251 NetworkRequestInfo n = mNetworkRequests.valueAt(i); 252 253 evalRequest(n); 254 } 255 } 256 257 // override to do simple mode (request independent) 258 protected void startNetwork() { } 259 protected void stopNetwork() { } 260 261 // override to do fancier stuff 262 protected void needNetworkFor(NetworkRequest networkRequest, int score) { 263 if (++mRefCount == 1) startNetwork(); 264 } 265 266 protected void releaseNetworkFor(NetworkRequest networkRequest) { 267 if (--mRefCount == 0) stopNetwork(); 268 } 269 270 271 public void addNetworkRequest(NetworkRequest networkRequest, int score) { 272 sendMessage(obtainMessage(CMD_REQUEST_NETWORK, 273 new NetworkRequestInfo(networkRequest, score))); 274 } 275 276 public void removeNetworkRequest(NetworkRequest networkRequest) { 277 sendMessage(obtainMessage(CMD_CANCEL_REQUEST, networkRequest)); 278 } 279 280 public void setScoreFilter(int score) { 281 sendMessage(obtainMessage(CMD_SET_SCORE, score, 0)); 282 } 283 284 public void setCapabilityFilter(NetworkCapabilities netCap) { 285 sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); 286 } 287 288 @VisibleForTesting 289 protected int getRequestCount() { 290 return mNetworkRequests.size(); 291 } 292 293 protected void log(String s) { 294 Log.d(LOG_TAG, s); 295 } 296 297 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 298 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 299 pw.println(toString()); 300 pw.increaseIndent(); 301 for (int i = 0; i < mNetworkRequests.size(); i++) { 302 pw.println(mNetworkRequests.valueAt(i)); 303 } 304 pw.decreaseIndent(); 305 } 306 307 @Override 308 public String toString() { 309 StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - ScoreFilter="). 310 append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests="). 311 append(mNetworkRequests.size()).append(", refCount=").append(mRefCount). 312 append("}"); 313 return sb.toString(); 314 } 315 } 316