1 /* 2 * Copyright (C) 2020 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.IntRange; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.RequiresPermission; 23 import android.annotation.SystemApi; 24 import android.content.Context; 25 import android.os.Handler; 26 import android.os.Looper; 27 import android.os.Message; 28 import android.os.Messenger; 29 import android.util.Log; 30 31 import com.android.internal.annotations.GuardedBy; 32 33 import java.util.ArrayList; 34 import java.util.concurrent.Executor; 35 36 /** 37 * Base class for network providers such as telephony or Wi-Fi. NetworkProviders connect the device 38 * to networks and makes them available to the core network stack by creating 39 * {@link NetworkAgent}s. The networks can then provide connectivity to apps and can be interacted 40 * with via networking APIs such as {@link ConnectivityManager}. 41 * 42 * Subclasses should implement {@link #onNetworkRequested} and {@link #onNetworkRequestWithdrawn} 43 * to receive {@link NetworkRequest}s sent by the system and by apps. A network that is not the 44 * best (highest-scoring) network for any request is generally not used by the system, and torn 45 * down. 46 * 47 * @hide 48 */ 49 @SystemApi 50 public class NetworkProvider { 51 /** 52 * {@code providerId} value that indicates the absence of a provider. It is the providerId of 53 * any NetworkProvider that is not currently registered, and of any NetworkRequest that is not 54 * currently being satisfied by a network. 55 */ 56 public static final int ID_NONE = -1; 57 58 /** 59 * The first providerId value that will be allocated. 60 * @hide only used by ConnectivityService. 61 */ 62 public static final int FIRST_PROVIDER_ID = 1; 63 64 /** @hide only used by ConnectivityService */ 65 public static final int CMD_REQUEST_NETWORK = 1; 66 /** @hide only used by ConnectivityService */ 67 public static final int CMD_CANCEL_REQUEST = 2; 68 69 private final Messenger mMessenger; 70 private final String mName; 71 private final Context mContext; 72 73 private int mProviderId = ID_NONE; 74 75 /** 76 * Constructs a new NetworkProvider. 77 * 78 * @param looper the Looper on which to run {@link #onNetworkRequested} and 79 * {@link #onNetworkRequestWithdrawn}. 80 * @param name the name of the listener, used only for debugging. 81 * 82 * @hide 83 */ 84 @SystemApi 85 public NetworkProvider(@NonNull Context context, @NonNull Looper looper, @NonNull String name) { 86 // TODO (b/174636568) : this class should be able to cache an instance of 87 // ConnectivityManager so it doesn't have to fetch it again every time. 88 final Handler handler = new Handler(looper) { 89 @Override 90 public void handleMessage(Message m) { 91 switch (m.what) { 92 case CMD_REQUEST_NETWORK: 93 onNetworkRequested((NetworkRequest) m.obj, m.arg1, m.arg2); 94 break; 95 case CMD_CANCEL_REQUEST: 96 onNetworkRequestWithdrawn((NetworkRequest) m.obj); 97 break; 98 default: 99 Log.e(mName, "Unhandled message: " + m.what); 100 } 101 } 102 }; 103 mContext = context; 104 mMessenger = new Messenger(handler); 105 mName = name; 106 } 107 108 // TODO: consider adding a register() method so ConnectivityManager does not need to call this. 109 /** @hide */ 110 public @Nullable Messenger getMessenger() { 111 return mMessenger; 112 } 113 114 /** @hide */ 115 public @NonNull String getName() { 116 return mName; 117 } 118 119 /** 120 * Returns the ID of this provider. This is known only once the provider is registered via 121 * {@link ConnectivityManager#registerNetworkProvider()}, otherwise the ID is {@link #ID_NONE}. 122 * This ID must be used when registering any {@link NetworkAgent}s. 123 */ 124 public int getProviderId() { 125 return mProviderId; 126 } 127 128 /** @hide */ 129 public void setProviderId(int providerId) { 130 mProviderId = providerId; 131 } 132 133 /** 134 * Called when a NetworkRequest is received. The request may be a new request or an existing 135 * request with a different score. 136 * 137 * @param request the NetworkRequest being received 138 * @param score the score of the network currently satisfying the request, or 0 if none. 139 * @param providerId the ID of the provider that created the network currently satisfying this 140 * request, or {@link #ID_NONE} if none. 141 * 142 * @hide 143 */ 144 @SystemApi 145 public void onNetworkRequested(@NonNull NetworkRequest request, 146 @IntRange(from = 0, to = 99) int score, int providerId) {} 147 148 /** 149 * Called when a NetworkRequest is withdrawn. 150 * @hide 151 */ 152 @SystemApi 153 public void onNetworkRequestWithdrawn(@NonNull NetworkRequest request) {} 154 155 /** 156 * Asserts that no provider will ever be able to satisfy the specified request. The provider 157 * must only call this method if it knows that it is the only provider on the system capable of 158 * satisfying this request, and that the request cannot be satisfied. The application filing the 159 * request will receive an {@link NetworkCallback#onUnavailable()} callback. 160 * 161 * @param request the request that permanently cannot be fulfilled 162 * @hide 163 */ 164 @SystemApi 165 @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) 166 public void declareNetworkRequestUnfulfillable(@NonNull NetworkRequest request) { 167 ConnectivityManager.from(mContext).declareNetworkRequestUnfulfillable(request); 168 } 169 170 /** 171 * A callback for parties registering a NetworkOffer. 172 * 173 * This is used with {@link ConnectivityManager#offerNetwork}. When offering a network, 174 * the system will use this callback to inform the caller that a network corresponding to 175 * this offer is needed or unneeded. 176 * 177 * @hide 178 */ 179 @SystemApi 180 public interface NetworkOfferCallback { 181 /** 182 * Called by the system when a network for this offer is needed to satisfy some 183 * networking request. 184 */ 185 void onNetworkNeeded(@NonNull NetworkRequest request); 186 /** 187 * Called by the system when this offer is no longer valuable for this request. 188 */ 189 void onNetworkUnneeded(@NonNull NetworkRequest request); 190 } 191 192 private class NetworkOfferCallbackProxy extends INetworkOfferCallback.Stub { 193 @NonNull public final NetworkOfferCallback callback; 194 @NonNull private final Executor mExecutor; 195 196 NetworkOfferCallbackProxy(@NonNull final NetworkOfferCallback callback, 197 @NonNull final Executor executor) { 198 this.callback = callback; 199 this.mExecutor = executor; 200 } 201 202 @Override 203 public void onNetworkNeeded(final @NonNull NetworkRequest request) { 204 mExecutor.execute(() -> callback.onNetworkNeeded(request)); 205 } 206 207 @Override 208 public void onNetworkUnneeded(final @NonNull NetworkRequest request) { 209 mExecutor.execute(() -> callback.onNetworkUnneeded(request)); 210 } 211 } 212 213 @GuardedBy("mProxies") 214 @NonNull private final ArrayList<NetworkOfferCallbackProxy> mProxies = new ArrayList<>(); 215 216 // Returns the proxy associated with this callback, or null if none. 217 @Nullable 218 private NetworkOfferCallbackProxy findProxyForCallback(@NonNull final NetworkOfferCallback cb) { 219 synchronized (mProxies) { 220 for (final NetworkOfferCallbackProxy p : mProxies) { 221 if (p.callback == cb) return p; 222 } 223 } 224 return null; 225 } 226 227 /** 228 * Register or update an offer for network with the passed capabilities and score. 229 * 230 * A NetworkProvider's role is to provide networks. This method is how a provider tells the 231 * connectivity stack what kind of network it may provide. The score and caps arguments act 232 * as filters that the connectivity stack uses to tell when the offer is valuable. When an 233 * offer might be preferred over existing networks, the provider will receive a call to 234 * the associated callback's {@link NetworkOfferCallback#onNetworkNeeded} method. The provider 235 * should then try to bring up this network. When an offer is no longer useful, the stack 236 * will inform the provider by calling {@link NetworkOfferCallback#onNetworkUnneeded}. The 237 * provider should stop trying to bring up such a network, or disconnect it if it already has 238 * one. 239 * 240 * The stack determines what offers are valuable according to what networks are currently 241 * available to the system, and what networking requests are made by applications. If an 242 * offer looks like it could connect a better network than any existing network for any 243 * particular request, that's when the stack decides the network is needed. If the current 244 * networking requests are all satisfied by networks that this offer couldn't possibly be a 245 * better match for, that's when the offer is no longer valuable. An offer starts out as 246 * unneeded ; the provider should not try to bring up the network until 247 * {@link NetworkOfferCallback#onNetworkNeeded} is called. 248 * 249 * Note that the offers are non-binding to the providers, in particular because providers 250 * often don't know if they will be able to bring up such a network at any given time. For 251 * example, no wireless network may be in range when the offer would be valuable. This is fine 252 * and expected ; the provider should simply continue to try to bring up the network and do so 253 * if/when it becomes possible. In the mean time, the stack will continue to satisfy requests 254 * with the best network currently available, or if none, keep the apps informed that no 255 * network can currently satisfy this request. When/if the provider can bring up the network, 256 * the connectivity stack will match it against requests, and inform interested apps of the 257 * availability of this network. This may, in turn, render the offer of some other provider 258 * low-value if all requests it used to satisfy are now better served by this network. 259 * 260 * A network can become unneeded for a reason like the above : whether the provider managed 261 * to bring up the offered network after it became needed or not, some other provider may 262 * bring up a better network than this one, making this network unneeded. A network may also 263 * become unneeded if the application making the request withdrew it (for example, after it 264 * is done transferring data, or if the user canceled an operation). 265 * 266 * The capabilities and score act as filters as to what requests the provider will see. 267 * They are not promises, but for best performance, the providers should strive to put 268 * as much known information as possible in the offer. For the score, it should put as 269 * strong a score as the networks will have, since this will filter what requests the 270 * provider sees – it's not a promise, it only serves to avoid sending requests that 271 * the provider can't ever hope to satisfy better than any current network. For capabilities, 272 * it should put all NetworkAgent-managed capabilities a network may have, even if it doesn't 273 * have them at first. This applies to INTERNET, for example ; if a provider thinks the 274 * network it can bring up for this offer may offer Internet access it should include the 275 * INTERNET bit. It's fine if the brought up network ends up not actually having INTERNET. 276 * 277 * TODO : in the future, to avoid possible infinite loops, there should be constraints on 278 * what can be put in capabilities of networks brought up for an offer. If a provider might 279 * bring up a network with or without INTERNET, then it should file two offers : this will 280 * let it know precisely what networks are needed, so it can avoid bringing up networks that 281 * won't actually satisfy requests and remove the risk for bring-up-bring-down loops. 282 * 283 * @hide 284 */ 285 @SystemApi 286 @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) 287 public void registerNetworkOffer(@NonNull final NetworkScore score, 288 @NonNull final NetworkCapabilities caps, @NonNull final Executor executor, 289 @NonNull final NetworkOfferCallback callback) { 290 // Can't offer a network with a provider that is not yet registered or already unregistered. 291 final int providerId = mProviderId; 292 if (providerId == ID_NONE) return; 293 NetworkOfferCallbackProxy proxy = null; 294 synchronized (mProxies) { 295 for (final NetworkOfferCallbackProxy existingProxy : mProxies) { 296 if (existingProxy.callback == callback) { 297 proxy = existingProxy; 298 break; 299 } 300 } 301 if (null == proxy) { 302 proxy = new NetworkOfferCallbackProxy(callback, executor); 303 mProxies.add(proxy); 304 } 305 } 306 mContext.getSystemService(ConnectivityManager.class) 307 .offerNetwork(providerId, score, caps, proxy); 308 } 309 310 /** 311 * Withdraw a network offer previously made to the networking stack. 312 * 313 * If a provider can no longer provide a network they offered, it should call this method. 314 * An example of usage could be if the hardware necessary to bring up the network was turned 315 * off in UI by the user. Note that because offers are never binding, the provider might 316 * alternatively decide not to withdraw this offer and simply refuse to bring up the network 317 * even when it's needed. However, withdrawing the request is slightly more resource-efficient 318 * because the networking stack won't have to compare this offer to exiting networks to see 319 * if it could beat any of them, and may be advantageous to the provider's implementation that 320 * can rely on no longer receiving callbacks for a network that they can't bring up anyways. 321 * 322 * @hide 323 */ 324 @SystemApi 325 @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) 326 public void unregisterNetworkOffer(final @NonNull NetworkOfferCallback callback) { 327 final NetworkOfferCallbackProxy proxy = findProxyForCallback(callback); 328 if (null == proxy) return; 329 mProxies.remove(proxy); 330 mContext.getSystemService(ConnectivityManager.class).unofferNetwork(proxy); 331 } 332 } 333