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.annotation.Nullable; 21 import android.content.Context; 22 import android.net.NetworkProvider.NetworkOfferCallback; 23 import android.os.Looper; 24 import android.os.Message; 25 26 import java.io.FileDescriptor; 27 import java.io.PrintWriter; 28 import java.util.LinkedHashMap; 29 import java.util.Map; 30 import java.util.concurrent.Executor; 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 NetworkFactoryLegacyImpl 48 class NetworkFactoryImpl extends NetworkFactoryLegacyImpl { 49 private static final boolean DBG = NetworkFactory.DBG; 50 private static final boolean VDBG = NetworkFactory.VDBG; 51 52 // A score that will win against everything, so that score filtering will let all requests 53 // through 54 // TODO : remove this and replace with an API to listen to all requests. 55 @NonNull 56 private static final NetworkScore INVINCIBLE_SCORE = 57 new NetworkScore.Builder().setLegacyInt(1000).build(); 58 59 // TODO(b/187082970): Replace CMD_* with Handler.post(() -> { ... }) since all the CMDs do is to 60 // run the tasks asynchronously on the Handler thread. 61 62 /** 63 * Pass a network request to the bearer. If the bearer believes it can 64 * satisfy the request it should connect to the network and create a 65 * NetworkAgent. Once the NetworkAgent is fully functional it will 66 * register itself with ConnectivityService using registerNetworkAgent. 67 * If the bearer cannot immediately satisfy the request (no network, 68 * user disabled the radio, lower-scored network) it should remember 69 * any NetworkRequests it may be able to satisfy in the future. It may 70 * disregard any that it will never be able to service, for example 71 * those requiring a different bearer. 72 * msg.obj = NetworkRequest 73 */ 74 // TODO : this and CANCEL_REQUEST are only used by telephony tests. Replace it in the tests 75 // and remove them and the associated code. 76 private static final int CMD_REQUEST_NETWORK = NetworkFactory.CMD_REQUEST_NETWORK; 77 78 /** 79 * Cancel a network request 80 * msg.obj = NetworkRequest 81 */ 82 private static final int CMD_CANCEL_REQUEST = NetworkFactory.CMD_CANCEL_REQUEST; 83 84 /** 85 * Internally used to set our best-guess score. 86 * msg.obj = new score 87 */ 88 private static final int CMD_SET_SCORE = 3; 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 = 4; 96 97 /** 98 * Internally used to send the network offer associated with this factory. 99 * No arguments, will read from members 100 */ 101 private static final int CMD_OFFER_NETWORK = 5; 102 103 /** 104 * Internally used to send the request to listen to all requests. 105 * No arguments, will read from members 106 */ 107 private static final int CMD_LISTEN_TO_ALL_REQUESTS = 6; 108 109 private final Map<NetworkRequest, NetworkRequestInfo> mNetworkRequests = 110 new LinkedHashMap<>(); 111 112 @NonNull private NetworkScore mScore = new NetworkScore.Builder().setLegacyInt(0).build(); 113 114 private final NetworkOfferCallback mRequestCallback = new NetworkOfferCallback() { 115 @Override 116 public void onNetworkNeeded(@NonNull final NetworkRequest request) { 117 handleAddRequest(request); 118 } 119 120 @Override 121 public void onNetworkUnneeded(@NonNull final NetworkRequest request) { 122 handleRemoveRequest(request); 123 } 124 }; 125 @NonNull private final Executor mExecutor = command -> post(command); 126 127 128 // Ideally the filter argument would be non-null, but null has historically meant to see 129 // no requests and telephony passes null. NetworkFactoryImpl(NetworkFactory parent, Looper looper, Context context, @Nullable final NetworkCapabilities filter)130 NetworkFactoryImpl(NetworkFactory parent, Looper looper, Context context, 131 @Nullable final NetworkCapabilities filter) { 132 super(parent, looper, context, 133 null != filter ? filter : 134 NetworkCapabilities.Builder.withoutDefaultCapabilities().build()); 135 } 136 137 /* Registers this NetworkFactory with the system. May only be called once per factory. */ register(final String logTag)138 @Override public void register(final String logTag) { 139 register(logTag, false); 140 } 141 142 /** 143 * Registers this NetworkFactory with the system ignoring the score filter. This will let 144 * the factory always see all network requests matching its capabilities filter. 145 * May only be called once per factory. 146 */ registerIgnoringScore(final String logTag)147 @Override public void registerIgnoringScore(final String logTag) { 148 register(logTag, true); 149 } 150 register(final String logTag, final boolean listenToAllRequests)151 private void register(final String logTag, final boolean listenToAllRequests) { 152 if (mProvider != null) { 153 throw new IllegalStateException("A NetworkFactory must only be registered once"); 154 } 155 if (DBG) mParent.log("Registering NetworkFactory"); 156 157 mProvider = new NetworkProvider(mContext, NetworkFactoryImpl.this.getLooper(), logTag) { 158 @Override 159 public void onNetworkRequested(@NonNull NetworkRequest request, int score, 160 int servingProviderId) { 161 handleAddRequest(request); 162 } 163 164 @Override 165 public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) { 166 handleRemoveRequest(request); 167 } 168 }; 169 170 ((ConnectivityManager) mContext.getSystemService( 171 Context.CONNECTIVITY_SERVICE)).registerNetworkProvider(mProvider); 172 173 // The mScore and mCapabilityFilter members can only be accessed on the handler thread. 174 // TODO : offer a separate API to listen to all requests instead 175 if (listenToAllRequests) { 176 sendMessage(obtainMessage(CMD_LISTEN_TO_ALL_REQUESTS)); 177 } else { 178 sendMessage(obtainMessage(CMD_OFFER_NETWORK)); 179 } 180 } 181 handleOfferNetwork(@onNull final NetworkScore score)182 private void handleOfferNetwork(@NonNull final NetworkScore score) { 183 mProvider.registerNetworkOffer(score, mCapabilityFilter, mExecutor, mRequestCallback); 184 } 185 186 @Override handleMessage(Message msg)187 public void handleMessage(Message msg) { 188 switch (msg.what) { 189 case CMD_REQUEST_NETWORK: { 190 handleAddRequest((NetworkRequest) msg.obj); 191 break; 192 } 193 case CMD_CANCEL_REQUEST: { 194 handleRemoveRequest((NetworkRequest) msg.obj); 195 break; 196 } 197 case CMD_SET_SCORE: { 198 handleSetScore((NetworkScore) msg.obj); 199 break; 200 } 201 case CMD_SET_FILTER: { 202 handleSetFilter((NetworkCapabilities) msg.obj); 203 break; 204 } 205 case CMD_OFFER_NETWORK: { 206 handleOfferNetwork(mScore); 207 break; 208 } 209 case CMD_LISTEN_TO_ALL_REQUESTS: { 210 handleOfferNetwork(INVINCIBLE_SCORE); 211 break; 212 } 213 } 214 } 215 216 private static class NetworkRequestInfo { 217 @NonNull public final NetworkRequest request; 218 public boolean requested; // do we have a request outstanding, limited by score 219 NetworkRequestInfo(@onNull final NetworkRequest request)220 NetworkRequestInfo(@NonNull final NetworkRequest request) { 221 this.request = request; 222 this.requested = false; 223 } 224 225 @Override toString()226 public String toString() { 227 return "{" + request + ", requested=" + requested + "}"; 228 } 229 } 230 231 /** 232 * Add a NetworkRequest that the bearer may want to attempt to satisfy. 233 * @see #CMD_REQUEST_NETWORK 234 * 235 * @param request the request to handle. 236 */ handleAddRequest(@onNull final NetworkRequest request)237 private void handleAddRequest(@NonNull final NetworkRequest request) { 238 NetworkRequestInfo n = mNetworkRequests.get(request); 239 if (n == null) { 240 if (DBG) mParent.log("got request " + request); 241 n = new NetworkRequestInfo(request); 242 mNetworkRequests.put(n.request, n); 243 } else { 244 if (VDBG) mParent.log("handle existing request " + request); 245 } 246 if (VDBG) mParent.log(" my score=" + mScore + ", my filter=" + mCapabilityFilter); 247 248 if (mParent.acceptRequest(request)) { 249 n.requested = true; 250 mParent.needNetworkFor(request); 251 } 252 } 253 handleRemoveRequest(NetworkRequest request)254 private void handleRemoveRequest(NetworkRequest request) { 255 NetworkRequestInfo n = mNetworkRequests.get(request); 256 if (n != null) { 257 mNetworkRequests.remove(request); 258 if (n.requested) mParent.releaseNetworkFor(n.request); 259 } 260 } 261 handleSetScore(@onNull final NetworkScore score)262 private void handleSetScore(@NonNull final NetworkScore score) { 263 if (mScore.equals(score)) return; 264 mScore = score; 265 mParent.reevaluateAllRequests(); 266 } 267 handleSetFilter(@onNull final NetworkCapabilities netCap)268 private void handleSetFilter(@NonNull final NetworkCapabilities netCap) { 269 if (netCap.equals(mCapabilityFilter)) return; 270 mCapabilityFilter = netCap; 271 mParent.reevaluateAllRequests(); 272 } 273 reevaluateAllRequests()274 @Override public final void reevaluateAllRequests() { 275 if (mProvider == null) return; 276 mProvider.registerNetworkOffer(mScore, mCapabilityFilter, mExecutor, mRequestCallback); 277 } 278 279 /** 280 * @deprecated this method was never part of the API (system or public) and is only added 281 * for migration of existing clients. 282 */ 283 @Deprecated setScoreFilter(final int score)284 public void setScoreFilter(final int score) { 285 setScoreFilter(new NetworkScore.Builder().setLegacyInt(score).build()); 286 } 287 288 /** 289 * Set a score filter for this factory. 290 * 291 * This should include the transports the factory knows its networks will have, and 292 * an optimistic view of the attributes it may have. This does not commit the factory 293 * to being able to bring up such a network ; it only lets it avoid hearing about 294 * requests that it has no chance of fulfilling. 295 * 296 * @param score the filter 297 */ setScoreFilter(@onNull final NetworkScore score)298 @Override public void setScoreFilter(@NonNull final NetworkScore score) { 299 sendMessage(obtainMessage(CMD_SET_SCORE, score)); 300 } 301 setCapabilityFilter(NetworkCapabilities netCap)302 @Override public void setCapabilityFilter(NetworkCapabilities netCap) { 303 sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap))); 304 } 305 getRequestCount()306 @Override public int getRequestCount() { 307 return mNetworkRequests.size(); 308 } 309 dump(FileDescriptor fd, PrintWriter writer, String[] args)310 @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 311 writer.println(toString()); 312 for (NetworkRequestInfo n : mNetworkRequests.values()) { 313 writer.println(" " + n); 314 } 315 } 316 toString()317 @Override public String toString() { 318 return "providerId=" 319 + mProvider.getProviderId() + ", ScoreFilter=" 320 + mScore + ", Filter=" + mCapabilityFilter + ", requests=" 321 + mNetworkRequests.size(); 322 } 323 } 324