• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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