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