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.NonNull; 20 import android.content.Context; 21 import android.os.Handler; 22 import android.os.Looper; 23 import android.os.Message; 24 import android.util.Log; 25 26 import com.android.internal.annotations.VisibleForTesting; 27 28 import java.io.FileDescriptor; 29 import java.io.PrintWriter; 30 import java.util.LinkedHashMap; 31 import java.util.Map; 32 33 /** 34 * A NetworkFactory is an entity that creates NetworkAgent objects. 35 * The bearers register with ConnectivityService using {@link #register} and 36 * their factory will start receiving scored NetworkRequests. NetworkRequests 37 * can be filtered 3 ways: by NetworkCapabilities, by score and more complexly by 38 * overridden function. All of these can be dynamic - changing NetworkCapabilities 39 * or score forces re-evaluation of all current requests. 40 * 41 * If any requests pass the filter some overrideable functions will be called. 42 * If the bearer only cares about very simple start/stopNetwork callbacks, those 43 * functions can be overridden. If the bearer needs more interaction, it can 44 * override addNetworkRequest and removeNetworkRequest which will give it each 45 * request that passes their current filters. 46 * @hide 47 **/ 48 public class NetworkFactory extends Handler { 49 private static final boolean DBG = true; 50 private static final boolean VDBG = false; 51 /** 52 * Pass a network request to the bearer. If the bearer believes it can 53 * satisfy the request it should connect to the network and create a 54 * NetworkAgent. Once the NetworkAgent is fully functional it will 55 * register itself with ConnectivityService using registerNetworkAgent. 56 * If the bearer cannot immediately satisfy the request (no network, 57 * user disabled the radio, lower-scored network) it should remember 58 * any NetworkRequests it may be able to satisfy in the future. It may 59 * disregard any that it will never be able to service, for example 60 * those requiring a different bearer. 61 * msg.obj = NetworkRequest 62 * msg.arg1 = score - the score of the network currently satisfying this 63 * request. If this bearer knows in advance it cannot 64 * exceed this score it should not try to connect, holding the request 65 * for the future. 66 * Note that subsequent events may give a different (lower 67 * or higher) score for this request, transmitted to each 68 * NetworkFactory through additional CMD_REQUEST_NETWORK msgs 69 * with the same NetworkRequest but an updated score. 70 * Also, network conditions may change for this bearer 71 * allowing for a better score in the future. 72 * msg.arg2 = the ID of the NetworkProvider currently responsible for the 73 * NetworkAgent handling this request, or NetworkProvider.ID_NONE if none. 74 */ 75 public static final int CMD_REQUEST_NETWORK = 1; 76 77 /** 78 * Cancel a network request 79 * msg.obj = NetworkRequest 80 */ 81 public static final int CMD_CANCEL_REQUEST = 2; 82 83 /** 84 * Internally used to set our best-guess score. 85 * msg.arg1 = new score 86 */ 87 private static final int CMD_SET_SCORE = 3; 88 89 /** 90 * Internally used to set our current filter for coarse bandwidth changes with 91 * technology changes. 92 * msg.obj = new filter 93 */ 94 private static final int CMD_SET_FILTER = 4; 95 96 private final Context mContext; 97 private final String LOG_TAG; 98 99 private final Map<NetworkRequest, NetworkRequestInfo> mNetworkRequests = 100 new LinkedHashMap<>(); 101 102 private int mScore; 103 private NetworkCapabilities mCapabilityFilter; 104 105 private int mRefCount = 0; 106 private NetworkProvider mProvider = null; 107 NetworkFactory(Looper looper, Context context, String logTag, NetworkCapabilities filter)108 public NetworkFactory(Looper looper, Context context, String logTag, 109 NetworkCapabilities filter) { 110 super(looper); 111 LOG_TAG = logTag; 112 mContext = context; 113 mCapabilityFilter = filter; 114 } 115 116 /* Registers this NetworkFactory with the system. May only be called once per factory. */ register()117 public void register() { 118 if (mProvider != null) { 119 throw new IllegalStateException("A NetworkFactory must only be registered once"); 120 } 121 if (DBG) log("Registering NetworkFactory"); 122 123 mProvider = new NetworkProvider(mContext, NetworkFactory.this.getLooper(), LOG_TAG) { 124 @Override 125 public void onNetworkRequested(@NonNull NetworkRequest request, int score, 126 int servingProviderId) { 127 handleAddRequest(request, score, servingProviderId); 128 } 129 130 @Override 131 public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { 132 handleRemoveRequest(request); 133 } 134 }; 135 136 ((ConnectivityManager) mContext.getSystemService( 137 Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); 138 } 139 140 /** Unregisters this NetworkFactory. After this call, the object can no longer be used. */ terminate()141 public void terminate() { 142 if (mProvider == null) { 143 throw new IllegalStateException("This NetworkFactory was never registered"); 144 } 145 if (DBG) log("Unregistering NetworkFactory"); 146 147 ((ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) 148 .unregisterNetworkProvider(mProvider); 149 150 // Remove all pending messages, since this object cannot be reused. Any message currently 151 // being processed will continue to run. 152 removeCallbacksAndMessages(null); 153 } 154 155 @Override handleMessage(Message msg)156 public void handleMessage(Message msg) { 157 switch (msg.what) { 158 case CMD_REQUEST_NETWORK: { 159 handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2); 160 break; 161 } 162 case CMD_CANCEL_REQUEST: { 163 handleRemoveRequest((NetworkRequest) msg.obj); 164 break; 165 } 166 case CMD_SET_SCORE: { 167 handleSetScore(msg.arg1); 168 break; 169 } 170 case CMD_SET_FILTER: { 171 handleSetFilter((NetworkCapabilities) msg.obj); 172 break; 173 } 174 } 175 } 176 177 private static class NetworkRequestInfo { 178 public final NetworkRequest request; 179 public int score; 180 public boolean requested; // do we have a request outstanding, limited by score 181 public int providerId; 182 NetworkRequestInfo(NetworkRequest request, int score, int providerId)183 NetworkRequestInfo(NetworkRequest request, int score, int providerId) { 184 this.request = request; 185 this.score = score; 186 this.requested = false; 187 this.providerId = providerId; 188 } 189 190 @Override toString()191 public String toString() { 192 return "{" + request + ", score=" + score + ", requested=" + requested + "}"; 193 } 194 } 195 196 /** 197 * Add a NetworkRequest that the bearer may want to attempt to satisfy. 198 * @see #CMD_REQUEST_NETWORK 199 * 200 * @param request the request to handle. 201 * @param score the score of the NetworkAgent currently satisfying this request. 202 * @param servingProviderId the ID of the NetworkProvider that created the NetworkAgent 203 * currently satisfying this request. 204 */ 205 @VisibleForTesting handleAddRequest(NetworkRequest request, int score, int servingProviderId)206 protected void handleAddRequest(NetworkRequest request, int score, int servingProviderId) { 207 NetworkRequestInfo n = mNetworkRequests.get(request); 208 if (n == null) { 209 if (DBG) { 210 log("got request " + request + " with score " + score 211 + " and providerId " + servingProviderId); 212 } 213 n = new NetworkRequestInfo(request, score, servingProviderId); 214 mNetworkRequests.put(n.request, n); 215 } else { 216 if (VDBG) { 217 log("new score " + score + " for existing request " + request 218 + " and providerId " + servingProviderId); 219 } 220 n.score = score; 221 n.providerId = servingProviderId; 222 } 223 if (VDBG) log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); 224 225 evalRequest(n); 226 } 227 228 @VisibleForTesting handleRemoveRequest(NetworkRequest request)229 protected void handleRemoveRequest(NetworkRequest request) { 230 NetworkRequestInfo n = mNetworkRequests.get(request); 231 if (n != null) { 232 mNetworkRequests.remove(request); 233 if (n.requested) releaseNetworkFor(n.request); 234 } 235 } 236 handleSetScore(int score)237 private void handleSetScore(int score) { 238 mScore = score; 239 evalRequests(); 240 } 241 handleSetFilter(NetworkCapabilities netCap)242 private void handleSetFilter(NetworkCapabilities netCap) { 243 mCapabilityFilter = netCap; 244 evalRequests(); 245 } 246 247 /** 248 * Overridable function to provide complex filtering. 249 * Called for every request every time a new NetworkRequest is seen 250 * and whenever the filterScore or filterNetworkCapabilities change. 251 * 252 * acceptRequest can be overridden to provide complex filter behavior 253 * for the incoming requests 254 * 255 * For output, this class will call {@link #needNetworkFor} and 256 * {@link #releaseNetworkFor} for every request that passes the filters. 257 * If you don't need to see every request, you can leave the base 258 * implementations of those two functions and instead override 259 * {@link #startNetwork} and {@link #stopNetwork}. 260 * 261 * If you want to see every score fluctuation on every request, set 262 * your score filter to a very high number and watch {@link #needNetworkFor}. 263 * 264 * @return {@code true} to accept the request. 265 */ acceptRequest(NetworkRequest request, int score)266 public boolean acceptRequest(NetworkRequest request, int score) { 267 return true; 268 } 269 evalRequest(NetworkRequestInfo n)270 private void evalRequest(NetworkRequestInfo n) { 271 if (VDBG) { 272 log("evalRequest"); 273 log(" n.requests = " + n.requested); 274 log(" n.score = " + n.score); 275 log(" mScore = " + mScore); 276 log(" request.providerId = " + n.providerId); 277 log(" mProvider.id = " + mProvider.getProviderId()); 278 } 279 if (shouldNeedNetworkFor(n)) { 280 if (VDBG) log(" needNetworkFor"); 281 needNetworkFor(n.request, n.score); 282 n.requested = true; 283 } else if (shouldReleaseNetworkFor(n)) { 284 if (VDBG) log(" releaseNetworkFor"); 285 releaseNetworkFor(n.request); 286 n.requested = false; 287 } else { 288 if (VDBG) log(" done"); 289 } 290 } 291 shouldNeedNetworkFor(NetworkRequestInfo n)292 private boolean shouldNeedNetworkFor(NetworkRequestInfo n) { 293 // If this request is already tracked, it doesn't qualify for need 294 return !n.requested 295 // If the score of this request is higher or equal to that of this factory and some 296 // other factory is responsible for it, then this factory should not track the request 297 // because it has no hope of satisfying it. 298 && (n.score < mScore || n.providerId == mProvider.getProviderId()) 299 // If this factory can't satisfy the capability needs of this request, then it 300 // should not be tracked. 301 && n.request.canBeSatisfiedBy(mCapabilityFilter) 302 // Finally if the concrete implementation of the factory rejects the request, then 303 // don't track it. 304 && acceptRequest(n.request, n.score); 305 } 306 shouldReleaseNetworkFor(NetworkRequestInfo n)307 private boolean shouldReleaseNetworkFor(NetworkRequestInfo n) { 308 // Don't release a request that's not tracked. 309 return n.requested 310 // The request should be released if it can't be satisfied by this factory. That 311 // means either of the following conditions are met : 312 // - Its score is too high to be satisfied by this factory and it's not already 313 // assigned to the factory 314 // - This factory can't satisfy the capability needs of the request 315 // - The concrete implementation of the factory rejects the request 316 && ((n.score > mScore && n.providerId != mProvider.getProviderId()) 317 || !n.request.canBeSatisfiedBy(mCapabilityFilter) 318 || !acceptRequest(n.request, n.score)); 319 } 320 evalRequests()321 private void evalRequests() { 322 for (NetworkRequestInfo n : mNetworkRequests.values()) { 323 evalRequest(n); 324 } 325 } 326 327 /** 328 * Post a command, on this NetworkFactory Handler, to re-evaluate all 329 * outstanding requests. Can be called from a factory implementation. 330 */ reevaluateAllRequests()331 protected void reevaluateAllRequests() { 332 post(this::evalRequests); 333 } 334 335 /** 336 * Can be called by a factory to release a request as unfulfillable: the request will be 337 * removed, and the caller will get a 338 * {@link ConnectivityManager.NetworkCallback#onUnavailable()} callback after this function 339 * returns. 340 * 341 * Note: this should only be called by factory which KNOWS that it is the ONLY factory which 342 * is able to fulfill this request! 343 */ releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r)344 protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) { 345 post(() -> { 346 if (DBG) log("releaseRequestAsUnfulfillableByAnyFactory: " + r); 347 final NetworkProvider provider = mProvider; 348 if (provider == null) { 349 Log.e(LOG_TAG, "Ignoring attempt to release unregistered request as unfulfillable"); 350 return; 351 } 352 provider.declareNetworkRequestUnfulfillable(r); 353 }); 354 } 355 356 // override to do simple mode (request independent) startNetwork()357 protected void startNetwork() { } stopNetwork()358 protected void stopNetwork() { } 359 360 // override to do fancier stuff needNetworkFor(NetworkRequest networkRequest, int score)361 protected void needNetworkFor(NetworkRequest networkRequest, int score) { 362 if (++mRefCount == 1) startNetwork(); 363 } 364 releaseNetworkFor(NetworkRequest networkRequest)365 protected void releaseNetworkFor(NetworkRequest networkRequest) { 366 if (--mRefCount == 0) stopNetwork(); 367 } 368 setScoreFilter(int score)369 public void setScoreFilter(int score) { 370 sendMessage(obtainMessage(CMD_SET_SCORE, score, 0)); 371 } 372 setCapabilityFilter(NetworkCapabilities netCap)373 public void setCapabilityFilter(NetworkCapabilities netCap) { 374 sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); 375 } 376 377 @VisibleForTesting getRequestCount()378 protected int getRequestCount() { 379 return mNetworkRequests.size(); 380 } 381 382 /* TODO: delete when all callers have migrated to NetworkProvider IDs. */ getSerialNumber()383 public int getSerialNumber() { 384 return mProvider.getProviderId(); 385 } 386 getProvider()387 public NetworkProvider getProvider() { 388 return mProvider; 389 } 390 log(String s)391 protected void log(String s) { 392 Log.d(LOG_TAG, s); 393 } 394 dump(FileDescriptor fd, PrintWriter writer, String[] args)395 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 396 writer.println(toString()); 397 for (NetworkRequestInfo n : mNetworkRequests.values()) { 398 writer.println(" " + n); 399 } 400 } 401 402 @Override toString()403 public String toString() { 404 return "{" + LOG_TAG + " - providerId=" 405 + mProvider.getProviderId() + ", ScoreFilter=" 406 + mScore + ", Filter=" + mCapabilityFilter + ", requests=" 407 + mNetworkRequests.size() + ", refCount=" + mRefCount 408 + "}"; 409 } 410 } 411