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 com.android.server.connectivity; 18 19 import android.annotation.NonNull; 20 import android.net.INetworkOfferCallback; 21 import android.net.NetworkCapabilities; 22 import android.net.NetworkRequest; 23 import android.os.RemoteException; 24 25 import java.util.HashSet; 26 import java.util.Objects; 27 import java.util.Set; 28 29 /** 30 * Represents an offer made by a NetworkProvider to create a network if a need arises. 31 * 32 * This class contains the prospective score and capabilities of the network. The provider 33 * is not obligated to caps able to create a network satisfying this, nor to build a network 34 * with the exact score and/or capabilities passed ; after all, not all providers know in 35 * advance what a network will look like after it's connected. Instead, this is meant as a 36 * filter to limit requests sent to the provider by connectivity to those that this offer stands 37 * a chance to fulfill. 38 * 39 * @see NetworkProvider#offerNetwork. 40 * 41 * @hide 42 */ 43 public class NetworkOffer implements NetworkRanker.Scoreable { 44 @NonNull public final FullScore score; 45 @NonNull public final NetworkCapabilities caps; 46 @NonNull public final INetworkOfferCallback callback; 47 @NonNull public final int providerId; 48 // While this could, in principle, be deduced from the old values of the satisfying networks, 49 // doing so would add a lot of complexity and performance penalties. For each request, the 50 // ranker would have to run again to figure out if this offer used to be able to beat the 51 // previous satisfier to know if there is a change in whether this offer is now needed ; 52 // besides, there would be a need to handle an edge case when a new request comes online, 53 // where it's not satisfied before the first rematch, where starting to satisfy a request 54 // should not result in sending unneeded to this offer. This boolean, while requiring that 55 // the offers are only ever manipulated on the CS thread, is by far a simpler and 56 // economical solution. 57 private final Set<NetworkRequest> mCurrentlyNeeded = new HashSet<>(); 58 NetworkOffer(@onNull final FullScore score, @NonNull final NetworkCapabilities caps, @NonNull final INetworkOfferCallback callback, @NonNull final int providerId)59 public NetworkOffer(@NonNull final FullScore score, 60 @NonNull final NetworkCapabilities caps, 61 @NonNull final INetworkOfferCallback callback, 62 @NonNull final int providerId) { 63 this.score = Objects.requireNonNull(score); 64 this.caps = Objects.requireNonNull(caps); 65 this.callback = Objects.requireNonNull(callback); 66 this.providerId = providerId; 67 } 68 69 /** 70 * Get the score filter of this offer 71 */ getScore()72 @Override @NonNull public FullScore getScore() { 73 return score; 74 } 75 76 /** 77 * Get the capabilities filter of this offer 78 */ getCapsNoCopy()79 @Override @NonNull public NetworkCapabilities getCapsNoCopy() { 80 return caps; 81 } 82 83 /** 84 * Tell the provider for this offer that the network is needed for a request. 85 * @param request the request for which the offer is needed 86 */ onNetworkNeeded(@onNull final NetworkRequest request)87 public void onNetworkNeeded(@NonNull final NetworkRequest request) { 88 if (mCurrentlyNeeded.contains(request)) { 89 throw new IllegalStateException("Network already needed"); 90 } 91 mCurrentlyNeeded.add(request); 92 try { 93 callback.onNetworkNeeded(request); 94 } catch (final RemoteException e) { 95 // The provider is dead. It will be removed by the death recipient. 96 } 97 } 98 99 /** 100 * Tell the provider for this offer that the network is no longer needed for this request. 101 * 102 * onNetworkNeeded will have been called with the same request before. 103 * 104 * @param request the request 105 */ onNetworkUnneeded(@onNull final NetworkRequest request)106 public void onNetworkUnneeded(@NonNull final NetworkRequest request) { 107 if (!mCurrentlyNeeded.contains(request)) { 108 throw new IllegalStateException("Network already unneeded"); 109 } 110 mCurrentlyNeeded.remove(request); 111 try { 112 callback.onNetworkUnneeded(request); 113 } catch (final RemoteException e) { 114 // The provider is dead. It will be removed by the death recipient. 115 } 116 } 117 118 /** 119 * Returns whether this offer is currently needed for this request. 120 * @param request the request 121 * @return whether the offer is currently considered needed 122 */ neededFor(@onNull final NetworkRequest request)123 public boolean neededFor(@NonNull final NetworkRequest request) { 124 return mCurrentlyNeeded.contains(request); 125 } 126 127 /** 128 * Migrate from, and take over, a previous offer. 129 * 130 * When an updated offer is sent from a provider, call this method on the new offer, passing 131 * the old one, to take over the state. 132 * 133 * @param previousOffer the previous offer 134 */ migrateFrom(@onNull final NetworkOffer previousOffer)135 public void migrateFrom(@NonNull final NetworkOffer previousOffer) { 136 if (!callback.asBinder().equals(previousOffer.callback.asBinder())) { 137 throw new IllegalArgumentException("Can only migrate from a previous version of" 138 + " the same offer"); 139 } 140 mCurrentlyNeeded.clear(); 141 mCurrentlyNeeded.addAll(previousOffer.mCurrentlyNeeded); 142 } 143 144 @Override toString()145 public String toString() { 146 return "NetworkOffer [ Score " + score + " Caps " + caps + "]"; 147 } 148 } 149