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.vcn.routeselection; 18 19 import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper; 20 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.net.LinkProperties; 24 import android.net.Network; 25 import android.net.NetworkCapabilities; 26 import android.net.vcn.VcnUnderlyingNetworkTemplate; 27 import android.os.ParcelUuid; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 import com.android.internal.annotations.VisibleForTesting.Visibility; 31 import com.android.internal.util.IndentingPrintWriter; 32 import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; 33 import com.android.server.vcn.VcnContext; 34 35 import java.util.Comparator; 36 import java.util.List; 37 import java.util.Objects; 38 39 /** 40 * A record of a single underlying network, caching relevant fields. 41 * 42 * @hide 43 */ 44 public class UnderlyingNetworkRecord { 45 @NonNull public final Network network; 46 @NonNull public final NetworkCapabilities networkCapabilities; 47 @NonNull public final LinkProperties linkProperties; 48 public final boolean isBlocked; 49 public final boolean isSelected; 50 public final int priorityClass; 51 52 @VisibleForTesting(visibility = Visibility.PRIVATE) UnderlyingNetworkRecord( @onNull Network network, @NonNull NetworkCapabilities networkCapabilities, @NonNull LinkProperties linkProperties, boolean isBlocked, VcnContext vcnContext, List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, PersistableBundleWrapper carrierConfig)53 public UnderlyingNetworkRecord( 54 @NonNull Network network, 55 @NonNull NetworkCapabilities networkCapabilities, 56 @NonNull LinkProperties linkProperties, 57 boolean isBlocked, 58 VcnContext vcnContext, 59 List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, 60 ParcelUuid subscriptionGroup, 61 TelephonySubscriptionSnapshot snapshot, 62 UnderlyingNetworkRecord currentlySelected, 63 PersistableBundleWrapper carrierConfig) { 64 this.network = network; 65 this.networkCapabilities = networkCapabilities; 66 this.linkProperties = linkProperties; 67 this.isBlocked = isBlocked; 68 69 this.isSelected = isSelected(this.network, currentlySelected); 70 71 priorityClass = 72 NetworkPriorityClassifier.calculatePriorityClass( 73 vcnContext, 74 this, 75 underlyingNetworkTemplates, 76 subscriptionGroup, 77 snapshot, 78 currentlySelected, 79 carrierConfig); 80 } 81 82 @VisibleForTesting(visibility = Visibility.PRIVATE) UnderlyingNetworkRecord( @onNull Network network, @NonNull NetworkCapabilities networkCapabilities, @NonNull LinkProperties linkProperties, boolean isBlocked, boolean isSelected, int priorityClass)83 public UnderlyingNetworkRecord( 84 @NonNull Network network, 85 @NonNull NetworkCapabilities networkCapabilities, 86 @NonNull LinkProperties linkProperties, 87 boolean isBlocked, 88 boolean isSelected, 89 int priorityClass) { 90 this.network = network; 91 this.networkCapabilities = networkCapabilities; 92 this.linkProperties = linkProperties; 93 this.isBlocked = isBlocked; 94 this.isSelected = isSelected; 95 96 this.priorityClass = priorityClass; 97 } 98 99 @Override equals(Object o)100 public boolean equals(Object o) { 101 if (this == o) return true; 102 if (!(o instanceof UnderlyingNetworkRecord)) return false; 103 final UnderlyingNetworkRecord that = (UnderlyingNetworkRecord) o; 104 105 return network.equals(that.network) 106 && networkCapabilities.equals(that.networkCapabilities) 107 && linkProperties.equals(that.linkProperties) 108 && isBlocked == that.isBlocked; 109 } 110 111 @Override hashCode()112 public int hashCode() { 113 return Objects.hash(network, networkCapabilities, linkProperties, isBlocked); 114 } 115 116 /** Returns if two records are equal including their priority classes. */ isEqualIncludingPriorities( UnderlyingNetworkRecord left, UnderlyingNetworkRecord right)117 public static boolean isEqualIncludingPriorities( 118 UnderlyingNetworkRecord left, UnderlyingNetworkRecord right) { 119 if (left != null && right != null) { 120 return left.equals(right) 121 && left.isSelected == right.isSelected 122 && left.priorityClass == right.priorityClass; 123 } 124 125 return left == right; 126 } 127 getComparator()128 static Comparator<UnderlyingNetworkRecord> getComparator() { 129 return (left, right) -> { 130 final int leftIndex = left.priorityClass; 131 final int rightIndex = right.priorityClass; 132 133 // In the case of networks in the same priority class, prioritize based on other 134 // criteria (eg. actively selected network, link metrics, etc) 135 if (leftIndex == rightIndex) { 136 // TODO: Improve the strategy of network selection when both UnderlyingNetworkRecord 137 // fall into the same priority class. 138 if (left.isSelected) { 139 return -1; 140 } 141 if (right.isSelected) { 142 return 1; 143 } 144 } 145 return Integer.compare(leftIndex, rightIndex); 146 }; 147 } 148 isSelected( Network networkToCheck, UnderlyingNetworkRecord currentlySelected)149 private static boolean isSelected( 150 Network networkToCheck, UnderlyingNetworkRecord currentlySelected) { 151 if (currentlySelected == null) { 152 return false; 153 } 154 if (currentlySelected.network.equals(networkToCheck)) { 155 return true; 156 } 157 return false; 158 } 159 160 /** Dumps the state of this record for logging and debugging purposes. */ dump( VcnContext vcnContext, IndentingPrintWriter pw, List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, PersistableBundleWrapper carrierConfig)161 void dump( 162 VcnContext vcnContext, 163 IndentingPrintWriter pw, 164 List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, 165 ParcelUuid subscriptionGroup, 166 TelephonySubscriptionSnapshot snapshot, 167 UnderlyingNetworkRecord currentlySelected, 168 PersistableBundleWrapper carrierConfig) { 169 pw.println("UnderlyingNetworkRecord:"); 170 pw.increaseIndent(); 171 172 pw.println("priorityClass: " + priorityClass); 173 pw.println("isSelected: " + isSelected); 174 pw.println("mNetwork: " + network); 175 pw.println("mNetworkCapabilities: " + networkCapabilities); 176 pw.println("mLinkProperties: " + linkProperties); 177 178 pw.decreaseIndent(); 179 } 180 181 /** Builder to incrementally construct an UnderlyingNetworkRecord. */ 182 static class Builder { 183 @NonNull private final Network mNetwork; 184 185 @Nullable private NetworkCapabilities mNetworkCapabilities; 186 @Nullable private LinkProperties mLinkProperties; 187 boolean mIsBlocked; 188 boolean mWasIsBlockedSet; 189 Builder(@onNull Network network)190 Builder(@NonNull Network network) { 191 mNetwork = network; 192 } 193 194 @NonNull getNetwork()195 Network getNetwork() { 196 return mNetwork; 197 } 198 setNetworkCapabilities(@onNull NetworkCapabilities networkCapabilities)199 void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { 200 mNetworkCapabilities = networkCapabilities; 201 } 202 203 @Nullable getNetworkCapabilities()204 NetworkCapabilities getNetworkCapabilities() { 205 return mNetworkCapabilities; 206 } 207 setLinkProperties(@onNull LinkProperties linkProperties)208 void setLinkProperties(@NonNull LinkProperties linkProperties) { 209 mLinkProperties = linkProperties; 210 } 211 setIsBlocked(boolean isBlocked)212 void setIsBlocked(boolean isBlocked) { 213 mIsBlocked = isBlocked; 214 mWasIsBlockedSet = true; 215 } 216 isValid()217 boolean isValid() { 218 return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet; 219 } 220 build( VcnContext vcnContext, List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, PersistableBundleWrapper carrierConfig)221 UnderlyingNetworkRecord build( 222 VcnContext vcnContext, 223 List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, 224 ParcelUuid subscriptionGroup, 225 TelephonySubscriptionSnapshot snapshot, 226 UnderlyingNetworkRecord currentlySelected, 227 PersistableBundleWrapper carrierConfig) { 228 if (!isValid()) { 229 throw new IllegalArgumentException( 230 "Called build before UnderlyingNetworkRecord was valid"); 231 } 232 233 return new UnderlyingNetworkRecord( 234 mNetwork, 235 mNetworkCapabilities, 236 mLinkProperties, 237 mIsBlocked, 238 vcnContext, 239 underlyingNetworkTemplates, 240 subscriptionGroup, 241 snapshot, 242 currentlySelected, 243 carrierConfig); 244 } 245 } 246 } 247