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