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.annotation.UnsupportedAppUsage; 20 import android.content.Context; 21 import android.os.Build; 22 import android.os.Handler; 23 import android.os.Looper; 24 import android.os.Message; 25 import android.os.Messenger; 26 import android.util.Log; 27 import android.util.SparseArray; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 import com.android.internal.util.AsyncChannel; 31 import com.android.internal.util.IndentingPrintWriter; 32 import com.android.internal.util.Protocol; 33 34 import java.io.FileDescriptor; 35 import java.io.PrintWriter; 36 import java.util.ArrayList; 37 import java.util.concurrent.atomic.AtomicInteger; 38 39 /** 40 * A NetworkFactory is an entity that creates NetworkAgent objects. 41 * The bearers register with ConnectivityService using {@link #register} and 42 * their factory will start receiving scored NetworkRequests. NetworkRequests 43 * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by 44 * overridden function. All of these can be dynamic - changing NetworkCapabilities 45 * or score forces re-evaluation of all current requests. 46 * 47 * If any requests pass the filter some overrideable functions will be called. 48 * If the bearer only cares about very simple start/stopNetwork callbacks, those 49 * functions can be overridden. If the bearer needs more interaction, it can 50 * override addNetworkRequest and removeNetworkRequest which will give it each 51 * request that passes their current filters. 52 * @hide 53 **/ 54 public class NetworkFactory extends Handler { 55 /** @hide */ 56 public static class SerialNumber { 57 // Guard used by no network factory. 58 public static final int NONE = -1; 59 // A hardcoded serial number for NetworkAgents representing VPNs. These agents are 60 // not created by any factory, so they use this constant for clarity instead of NONE. 61 public static final int VPN = -2; 62 private static final AtomicInteger sNetworkFactorySerialNumber = new AtomicInteger(1); 63 /** Returns a unique serial number for a factory. */ nextSerialNumber()64 public static final int nextSerialNumber() { 65 return sNetworkFactorySerialNumber.getAndIncrement(); 66 } 67 } 68 69 private static final boolean DBG = true; 70 private static final boolean VDBG = false; 71 72 private static final int BASE = Protocol.BASE_NETWORK_FACTORY; 73 /** 74 * Pass a network request to the bearer. If the bearer believes it can 75 * satisfy the request it should connect to the network and create a 76 * NetworkAgent. Once the NetworkAgent is fully functional it will 77 * register itself with ConnectivityService using registerNetworkAgent. 78 * If the bearer cannot immediately satisfy the request (no network, 79 * user disabled the radio, lower-scored network) it should remember 80 * any NetworkRequests it may be able to satisfy in the future. It may 81 * disregard any that it will never be able to service, for example 82 * those requiring a different bearer. 83 * msg.obj = NetworkRequest 84 * msg.arg1 = score - the score of the network currently satisfying this 85 * request. If this bearer knows in advance it cannot 86 * exceed this score it should not try to connect, holding the request 87 * for the future. 88 * Note that subsequent events may give a different (lower 89 * or higher) score for this request, transmitted to each 90 * NetworkFactory through additional CMD_REQUEST_NETWORK msgs 91 * with the same NetworkRequest but an updated score. 92 * Also, network conditions may change for this bearer 93 * allowing for a better score in the future. 94 * msg.arg2 = the serial number of the factory currently responsible for the 95 * NetworkAgent handling this request, or SerialNumber.NONE if none. 96 */ 97 public static final int CMD_REQUEST_NETWORK = BASE; 98 99 /** 100 * Cancel a network request 101 * msg.obj = NetworkRequest 102 */ 103 public static final int CMD_CANCEL_REQUEST = BASE + 1; 104 105 /** 106 * Internally used to set our best-guess score. 107 * msg.arg1 = new score 108 */ 109 private static final int CMD_SET_SCORE = BASE + 2; 110 111 /** 112 * Internally used to set our current filter for coarse bandwidth changes with 113 * technology changes. 114 * msg.obj = new filter 115 */ 116 private static final int CMD_SET_FILTER = BASE + 3; 117 118 /** 119 * Sent by NetworkFactory to ConnectivityService to indicate that a request is 120 * unfulfillable. 121 * @see #releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest). 122 */ 123 public static final int EVENT_UNFULFILLABLE_REQUEST = BASE + 4; 124 125 private final Context mContext; 126 private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>(); 127 private AsyncChannel mAsyncChannel; 128 private final String LOG_TAG; 129 130 private final SparseArray<NetworkRequestInfo> mNetworkRequests = 131 new SparseArray<NetworkRequestInfo>(); 132 133 private int mScore; 134 private NetworkCapabilities mCapabilityFilter; 135 136 private int mRefCount = 0; 137 private Messenger mMessenger = null; 138 private int mSerialNumber; 139 140 @UnsupportedAppUsage NetworkFactory(Looper looper, Context context, String logTag, NetworkCapabilities filter)141 public NetworkFactory(Looper looper, Context context, String logTag, 142 NetworkCapabilities filter) { 143 super(looper); 144 LOG_TAG = logTag; 145 mContext = context; 146 mCapabilityFilter = filter; 147 } 148 register()149 public void register() { 150 if (DBG) log("Registering NetworkFactory"); 151 if (mMessenger == null) { 152 mMessenger = new Messenger(this); 153 mSerialNumber = ConnectivityManager.from(mContext).registerNetworkFactory(mMessenger, 154 LOG_TAG); 155 } 156 } 157 unregister()158 public void unregister() { 159 if (DBG) log("Unregistering NetworkFactory"); 160 if (mMessenger != null) { 161 ConnectivityManager.from(mContext).unregisterNetworkFactory(mMessenger); 162 mMessenger = null; 163 } 164 } 165 166 @Override handleMessage(Message msg)167 public void handleMessage(Message msg) { 168 switch (msg.what) { 169 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { 170 if (mAsyncChannel != null) { 171 log("Received new connection while already connected!"); 172 break; 173 } 174 if (VDBG) log("NetworkFactory fully connected"); 175 AsyncChannel ac = new AsyncChannel(); 176 ac.connected(null, this, msg.replyTo); 177 ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, 178 AsyncChannel.STATUS_SUCCESSFUL); 179 mAsyncChannel = ac; 180 for (Message m : mPreConnectedQueue) { 181 ac.sendMessage(m); 182 } 183 mPreConnectedQueue.clear(); 184 break; 185 } 186 case AsyncChannel.CMD_CHANNEL_DISCONNECT: { 187 if (VDBG) log("CMD_CHANNEL_DISCONNECT"); 188 if (mAsyncChannel != null) { 189 mAsyncChannel.disconnect(); 190 mAsyncChannel = null; 191 } 192 break; 193 } 194 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { 195 if (DBG) log("NetworkFactory channel lost"); 196 mAsyncChannel = null; 197 break; 198 } 199 case CMD_REQUEST_NETWORK: { 200 handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); 201 break; 202 } 203 case CMD_CANCEL_REQUEST: { 204 handleRemoveRequest((NetworkRequest) msg.obj); 205 break; 206 } 207 case CMD_SET_SCORE: { 208 handleSetScore(msg.arg1); 209 break; 210 } 211 case CMD_SET_FILTER: { 212 handleSetFilter((NetworkCapabilities) msg.obj); 213 break; 214 } 215 } 216 } 217 218 private class NetworkRequestInfo { 219 public final NetworkRequest request; 220 public int score; 221 public boolean requested; // do we have a request outstanding, limited by score 222 public int factorySerialNumber; 223 NetworkRequestInfo(NetworkRequest request, int score, int factorySerialNumber)224 NetworkRequestInfo(NetworkRequest request, int score, int factorySerialNumber) { 225 this.request = request; 226 this.score = score; 227 this.requested = false; 228 this.factorySerialNumber = factorySerialNumber; 229 } 230 231 @Override toString()232 public String toString() { 233 return "{" + request + ", score=" + score + ", requested=" + requested + "}"; 234 } 235 } 236 237 /** 238 * Add a NetworkRequest that the bearer may want to attempt to satisfy. 239 * @see #CMD_REQUEST_NETWORK 240 * 241 * @param request the request to handle. 242 * @param score the score of the NetworkAgent currently satisfying this request. 243 * @param servingFactorySerialNumber the serial number of the NetworkFactory that 244 * created the NetworkAgent currently satisfying this request. 245 */ 246 // TODO : remove this method. It is a stopgap measure to help sheperding a number 247 // of dependent changes that would conflict throughout the automerger graph. Having this 248 // temporarily helps with the process of going through with all these dependent changes across 249 // the entire tree. 250 @VisibleForTesting handleAddRequest(NetworkRequest request, int score)251 protected void handleAddRequest(NetworkRequest request, int score) { 252 handleAddRequest(request, score, SerialNumber.NONE); 253 } 254 255 /** 256 * Add a NetworkRequest that the bearer may want to attempt to satisfy. 257 * @see #CMD_REQUEST_NETWORK 258 * 259 * @param request the request to handle. 260 * @param score the score of the NetworkAgent currently satisfying this request. 261 * @param servingFactorySerialNumber the serial number of the NetworkFactory that 262 * created the NetworkAgent currently satisfying this request. 263 */ 264 @VisibleForTesting handleAddRequest(NetworkRequest request, int score, int servingFactorySerialNumber)265 protected void handleAddRequest(NetworkRequest request, int score, 266 int servingFactorySerialNumber) { 267 NetworkRequestInfo n = mNetworkRequests.get(request.requestId); 268 if (n == null) { 269 if (DBG) { 270 log("got request " + request + " with score " + score 271 + " and serial " + servingFactorySerialNumber); 272 } 273 n = new NetworkRequestInfo(request, score, servingFactorySerialNumber); 274 mNetworkRequests.put(n.request.requestId, n); 275 } else { 276 if (VDBG) { 277 log("new score " + score + " for exisiting request " + request 278 + " with serial " + servingFactorySerialNumber); 279 } 280 n.score = score; 281 n.factorySerialNumber = servingFactorySerialNumber; 282 } 283 if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); 284 285 evalRequest(n); 286 } 287 288 @VisibleForTesting handleRemoveRequest(NetworkRequest request)289 protected void handleRemoveRequest(NetworkRequest request) { 290 NetworkRequestInfo n = mNetworkRequests.get(request.requestId); 291 if (n != null) { 292 mNetworkRequests.remove(request.requestId); 293 if (n.requested) releaseNetworkFor(n.request); 294 } 295 } 296 handleSetScore(int score)297 private void handleSetScore(int score) { 298 mScore = score; 299 evalRequests(); 300 } 301 handleSetFilter(NetworkCapabilities netCap)302 private void handleSetFilter(NetworkCapabilities netCap) { 303 mCapabilityFilter = netCap; 304 evalRequests(); 305 } 306 307 /** 308 * Overridable function to provide complex filtering. 309 * Called for every request every time a new NetworkRequest is seen 310 * and whenever the filterScore or filterNetworkCapabilities change. 311 * 312 * acceptRequest can be overridden to provide complex filter behavior 313 * for the incoming requests 314 * 315 * For output, this class will call {@link #needNetworkFor} and 316 * {@link #releaseNetworkFor} for every request that passes the filters. 317 * If you don't need to see every request, you can leave the base 318 * implementations of those two functions and instead override 319 * {@link #startNetwork} and {@link #stopNetwork}. 320 * 321 * If you want to see every score fluctuation on every request, set 322 * your score filter to a very high number and watch {@link #needNetworkFor}. 323 * 324 * @return {@code true} to accept the request. 325 */ acceptRequest(NetworkRequest request, int score)326 public boolean acceptRequest(NetworkRequest request, int score) { 327 return true; 328 } 329 evalRequest(NetworkRequestInfo n)330 private void evalRequest(NetworkRequestInfo n) { 331 if (VDBG) { 332 log("evalRequest"); 333 log(" n.requests = " + n.requested); 334 log(" n.score = " + n.score); 335 log(" mScore = " + mScore); 336 log(" n.factorySerialNumber = " + n.factorySerialNumber); 337 log(" mSerialNumber = " + mSerialNumber); 338 } 339 if (shouldNeedNetworkFor(n)) { 340 if (VDBG) log(" needNetworkFor"); 341 needNetworkFor(n.request, n.score); 342 n.requested = true; 343 } else if (shouldReleaseNetworkFor(n)) { 344 if (VDBG) log(" releaseNetworkFor"); 345 releaseNetworkFor(n.request); 346 n.requested = false; 347 } else { 348 if (VDBG) log(" done"); 349 } 350 } 351 shouldNeedNetworkFor(NetworkRequestInfo n)352 private boolean shouldNeedNetworkFor(NetworkRequestInfo n) { 353 // If this request is already tracked, it doesn't qualify for need 354 return !n.requested 355 // If the score of this request is higher or equal to that of this factory and some 356 // other factory is responsible for it, then this factory should not track the request 357 // because it has no hope of satisfying it. 358 && (n.score < mScore || n.factorySerialNumber == mSerialNumber) 359 // If this factory can't satisfy the capability needs of this request, then it 360 // should not be tracked. 361 && n.request.networkCapabilities.satisfiedByNetworkCapabilities(mCapabilityFilter) 362 // Finally if the concrete implementation of the factory rejects the request, then 363 // don't track it. 364 && acceptRequest(n.request, n.score); 365 } 366 shouldReleaseNetworkFor(NetworkRequestInfo n)367 private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) { 368 // Don't release a request that's not tracked. 369 return n.requested 370 // The request should be released if it can't be satisfied by this factory. That 371 // means either of the following conditions are met : 372 // - Its score is too high to be satisfied by this factory and it's not already 373 // assigned to the factory 374 // - This factory can't satisfy the capability needs of the request 375 // - The concrete implementation of the factory rejects the request 376 && ((n.score > mScore && n.factorySerialNumber != mSerialNumber) 377 || !n.request.networkCapabilities.satisfiedByNetworkCapabilities( 378 mCapabilityFilter) 379 || !acceptRequest(n.request, n.score)); 380 } 381 evalRequests()382 private void evalRequests() { 383 for (int i = 0; i < mNetworkRequests.size(); i++) { 384 NetworkRequestInfo n = mNetworkRequests.valueAt(i); 385 evalRequest(n); 386 } 387 } 388 389 /** 390 * Post a command, on this NetworkFactory Handler, to re-evaluate all 391 * oustanding requests. Can be called from a factory implementation. 392 */ reevaluateAllRequests()393 protected void reevaluateAllRequests() { 394 post(() -> { 395 evalRequests(); 396 }); 397 } 398 399 /** 400 * Can be called by a factory to release a request as unfulfillable: the request will be 401 * removed, and the caller will get a 402 * {@link ConnectivityManager.NetworkCallback#onUnavailable()} callback after this function 403 * returns. 404 * 405 * Note: this should only be called by factory which KNOWS that it is the ONLY factory which 406 * is able to fulfill this request! 407 */ releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r)408 protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { 409 post(() -> { 410 if (DBG) log("releaseRequestAsUnfulfillableByAnyFactory: " + r); 411 Message msg = obtainMessage(EVENT_UNFULFILLABLE_REQUEST, r); 412 if (mAsyncChannel != null) { 413 mAsyncChannel.sendMessage(msg); 414 } else { 415 mPreConnectedQueue.add(msg); 416 } 417 }); 418 } 419 420 // override to do simple mode (request independent) startNetwork()421 protected void startNetwork() { } stopNetwork()422 protected void stopNetwork() { } 423 424 // override to do fancier stuff needNetworkFor(NetworkRequest networkRequest, int score)425 protected void needNetworkFor(NetworkRequest networkRequest, int score) { 426 if (++mRefCount == 1) startNetwork(); 427 } 428 releaseNetworkFor(NetworkRequest networkRequest)429 protected void releaseNetworkFor(NetworkRequest networkRequest) { 430 if (--mRefCount == 0) stopNetwork(); 431 } 432 433 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) setScoreFilter(int score)434 public void setScoreFilter(int score) { 435 sendMessage(obtainMessage(CMD_SET_SCORE, score, 0)); 436 } 437 setCapabilityFilter(NetworkCapabilities netCap)438 public void setCapabilityFilter(NetworkCapabilities netCap) { 439 sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); 440 } 441 442 @VisibleForTesting getRequestCount()443 protected int getRequestCount() { 444 return mNetworkRequests.size(); 445 } 446 getSerialNumber()447 public int getSerialNumber() { 448 return mSerialNumber; 449 } 450 log(String s)451 protected void log(String s) { 452 Log.d(LOG_TAG, s); 453 } 454 455 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) dump(FileDescriptor fd, PrintWriter writer, String[] args)456 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 457 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 458 pw.println(toString()); 459 pw.increaseIndent(); 460 for (int i = 0; i < mNetworkRequests.size(); i++) { 461 pw.println(mNetworkRequests.valueAt(i)); 462 } 463 pw.decreaseIndent(); 464 } 465 466 @Override toString()467 public String toString() { 468 StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - mSerialNumber=") 469 .append(mSerialNumber).append(", ScoreFilter=") 470 .append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=") 471 .append(mNetworkRequests.size()).append(", refCount=").append(mRefCount) 472 .append("}"); 473 return sb.toString(); 474 } 475 } 476