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 private static final int PRIORITY_CLASS_INVALID = Integer.MAX_VALUE; 46 47 @NonNull public final Network network; 48 @NonNull public final NetworkCapabilities networkCapabilities; 49 @NonNull public final LinkProperties linkProperties; 50 public final boolean isBlocked; 51 52 private int mPriorityClass = PRIORITY_CLASS_INVALID; 53 54 @VisibleForTesting(visibility = Visibility.PRIVATE) UnderlyingNetworkRecord( @onNull Network network, @NonNull NetworkCapabilities networkCapabilities, @NonNull LinkProperties linkProperties, boolean isBlocked)55 public UnderlyingNetworkRecord( 56 @NonNull Network network, 57 @NonNull NetworkCapabilities networkCapabilities, 58 @NonNull LinkProperties linkProperties, 59 boolean isBlocked) { 60 this.network = network; 61 this.networkCapabilities = networkCapabilities; 62 this.linkProperties = linkProperties; 63 this.isBlocked = isBlocked; 64 } 65 getOrCalculatePriorityClass( VcnContext vcnContext, List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, PersistableBundleWrapper carrierConfig)66 private int getOrCalculatePriorityClass( 67 VcnContext vcnContext, 68 List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, 69 ParcelUuid subscriptionGroup, 70 TelephonySubscriptionSnapshot snapshot, 71 UnderlyingNetworkRecord currentlySelected, 72 PersistableBundleWrapper carrierConfig) { 73 // Never changes after the underlying network record is created. 74 if (mPriorityClass == PRIORITY_CLASS_INVALID) { 75 mPriorityClass = 76 NetworkPriorityClassifier.calculatePriorityClass( 77 vcnContext, 78 this, 79 underlyingNetworkTemplates, 80 subscriptionGroup, 81 snapshot, 82 currentlySelected, 83 carrierConfig); 84 } 85 86 return mPriorityClass; 87 } 88 89 // Used in UnderlyingNetworkController getPriorityClass()90 int getPriorityClass() { 91 return mPriorityClass; 92 } 93 94 @Override equals(Object o)95 public boolean equals(Object o) { 96 if (this == o) return true; 97 if (!(o instanceof UnderlyingNetworkRecord)) return false; 98 final UnderlyingNetworkRecord that = (UnderlyingNetworkRecord) o; 99 100 return network.equals(that.network) 101 && networkCapabilities.equals(that.networkCapabilities) 102 && linkProperties.equals(that.linkProperties) 103 && isBlocked == that.isBlocked; 104 } 105 106 @Override hashCode()107 public int hashCode() { 108 return Objects.hash(network, networkCapabilities, linkProperties, isBlocked); 109 } 110 getComparator( VcnContext vcnContext, List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, ParcelUuid subscriptionGroup, TelephonySubscriptionSnapshot snapshot, UnderlyingNetworkRecord currentlySelected, PersistableBundleWrapper carrierConfig)111 static Comparator<UnderlyingNetworkRecord> getComparator( 112 VcnContext vcnContext, 113 List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, 114 ParcelUuid subscriptionGroup, 115 TelephonySubscriptionSnapshot snapshot, 116 UnderlyingNetworkRecord currentlySelected, 117 PersistableBundleWrapper carrierConfig) { 118 return (left, right) -> { 119 final int leftIndex = 120 left.getOrCalculatePriorityClass( 121 vcnContext, 122 underlyingNetworkTemplates, 123 subscriptionGroup, 124 snapshot, 125 currentlySelected, 126 carrierConfig); 127 final int rightIndex = 128 right.getOrCalculatePriorityClass( 129 vcnContext, 130 underlyingNetworkTemplates, 131 subscriptionGroup, 132 snapshot, 133 currentlySelected, 134 carrierConfig); 135 136 // In the case of networks in the same priority class, prioritize based on other 137 // criteria (eg. actively selected network, link metrics, etc) 138 if (leftIndex == rightIndex) { 139 // TODO: Improve the strategy of network selection when both UnderlyingNetworkRecord 140 // fall into the same priority class. 141 if (isSelected(left, currentlySelected)) { 142 return -1; 143 } 144 if (isSelected(left, currentlySelected)) { 145 return 1; 146 } 147 } 148 return Integer.compare(leftIndex, rightIndex); 149 }; 150 } 151 isSelected( UnderlyingNetworkRecord recordToCheck, UnderlyingNetworkRecord currentlySelected)152 private static boolean isSelected( 153 UnderlyingNetworkRecord recordToCheck, UnderlyingNetworkRecord currentlySelected) { 154 if (currentlySelected == null) { 155 return false; 156 } 157 if (currentlySelected.network == recordToCheck.network) { 158 return true; 159 } 160 return false; 161 } 162 163 /** 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)164 void dump( 165 VcnContext vcnContext, 166 IndentingPrintWriter pw, 167 List<VcnUnderlyingNetworkTemplate> underlyingNetworkTemplates, 168 ParcelUuid subscriptionGroup, 169 TelephonySubscriptionSnapshot snapshot, 170 UnderlyingNetworkRecord currentlySelected, 171 PersistableBundleWrapper carrierConfig) { 172 pw.println("UnderlyingNetworkRecord:"); 173 pw.increaseIndent(); 174 175 final int priorityIndex = 176 getOrCalculatePriorityClass( 177 vcnContext, 178 underlyingNetworkTemplates, 179 subscriptionGroup, 180 snapshot, 181 currentlySelected, 182 carrierConfig); 183 184 pw.println("Priority index: " + priorityIndex); 185 pw.println("mNetwork: " + network); 186 pw.println("mNetworkCapabilities: " + networkCapabilities); 187 pw.println("mLinkProperties: " + linkProperties); 188 189 pw.decreaseIndent(); 190 } 191 192 /** Builder to incrementally construct an UnderlyingNetworkRecord. */ 193 static class Builder { 194 @NonNull private final Network mNetwork; 195 196 @Nullable private NetworkCapabilities mNetworkCapabilities; 197 @Nullable private LinkProperties mLinkProperties; 198 boolean mIsBlocked; 199 boolean mWasIsBlockedSet; 200 201 @Nullable private UnderlyingNetworkRecord mCached; 202 Builder(@onNull Network network)203 Builder(@NonNull Network network) { 204 mNetwork = network; 205 } 206 207 @NonNull getNetwork()208 Network getNetwork() { 209 return mNetwork; 210 } 211 setNetworkCapabilities(@onNull NetworkCapabilities networkCapabilities)212 void setNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { 213 mNetworkCapabilities = networkCapabilities; 214 mCached = null; 215 } 216 217 @Nullable getNetworkCapabilities()218 NetworkCapabilities getNetworkCapabilities() { 219 return mNetworkCapabilities; 220 } 221 setLinkProperties(@onNull LinkProperties linkProperties)222 void setLinkProperties(@NonNull LinkProperties linkProperties) { 223 mLinkProperties = linkProperties; 224 mCached = null; 225 } 226 setIsBlocked(boolean isBlocked)227 void setIsBlocked(boolean isBlocked) { 228 mIsBlocked = isBlocked; 229 mWasIsBlockedSet = true; 230 mCached = null; 231 } 232 isValid()233 boolean isValid() { 234 return mNetworkCapabilities != null && mLinkProperties != null && mWasIsBlockedSet; 235 } 236 build()237 UnderlyingNetworkRecord build() { 238 if (!isValid()) { 239 throw new IllegalArgumentException( 240 "Called build before UnderlyingNetworkRecord was valid"); 241 } 242 243 if (mCached == null) { 244 mCached = 245 new UnderlyingNetworkRecord( 246 mNetwork, mNetworkCapabilities, mLinkProperties, mIsBlocked); 247 } 248 249 return mCached; 250 } 251 } 252 } 253