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 android.net; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.SystemApi; 22 import android.os.Parcel; 23 import android.os.Parcelable; 24 25 import com.android.internal.annotations.VisibleForTesting; 26 27 import java.lang.annotation.Retention; 28 import java.lang.annotation.RetentionPolicy; 29 30 /** 31 * Object representing the quality of a network as perceived by the user. 32 * 33 * A NetworkScore object represents the characteristics of a network that affects how good the 34 * network is considered for a particular use. 35 * @hide 36 */ 37 @SystemApi 38 public final class NetworkScore implements Parcelable { 39 // This will be removed soon. Do *NOT* depend on it for any new code that is not part of 40 // a migration. 41 private final int mLegacyInt; 42 43 /** @hide */ 44 @Retention(RetentionPolicy.SOURCE) 45 @IntDef(value = { 46 KEEP_CONNECTED_NONE, 47 KEEP_CONNECTED_FOR_HANDOVER 48 }) 49 public @interface KeepConnectedReason { } 50 51 /** 52 * Do not keep this network connected if there is no outstanding request for it. 53 */ 54 public static final int KEEP_CONNECTED_NONE = 0; 55 /** 56 * Keep this network connected even if there is no outstanding request for it, because it 57 * is being considered for handover. 58 */ 59 public static final int KEEP_CONNECTED_FOR_HANDOVER = 1; 60 61 // Agent-managed policies 62 // This network should lose to a wifi that has ever been validated 63 // NOTE : temporarily this policy is managed by ConnectivityService, because of legacy. The 64 // legacy design has this bit global to the system and tacked on WiFi which means it will affect 65 // networks from carriers who don't want it and non-carrier networks, which is bad for users. 66 // The S design has this on mobile networks only, so this can be fixed eventually ; as CS 67 // doesn't know what carriers need this bit, the initial S implementation will continue to 68 // affect other carriers but will at least leave non-mobile networks alone. Eventually Telephony 69 // should set this on networks from carriers that require it. 70 /** @hide */ 71 public static final int POLICY_YIELD_TO_BAD_WIFI = 1; 72 // This network is primary for this transport. 73 /** @hide */ 74 public static final int POLICY_TRANSPORT_PRIMARY = 2; 75 // This network is exiting : it will likely disconnect in a few seconds. 76 /** @hide */ 77 public static final int POLICY_EXITING = 3; 78 79 /** @hide */ 80 public static final int MIN_AGENT_MANAGED_POLICY = POLICY_YIELD_TO_BAD_WIFI; 81 /** @hide */ 82 public static final int MAX_AGENT_MANAGED_POLICY = POLICY_EXITING; 83 84 // Bitmask of all the policies applied to this score. 85 private final long mPolicies; 86 87 private final int mKeepConnectedReason; 88 89 /** @hide */ NetworkScore(final int legacyInt, final long policies, @KeepConnectedReason final int keepConnectedReason)90 NetworkScore(final int legacyInt, final long policies, 91 @KeepConnectedReason final int keepConnectedReason) { 92 mLegacyInt = legacyInt; 93 mPolicies = policies; 94 mKeepConnectedReason = keepConnectedReason; 95 } 96 NetworkScore(@onNull final Parcel in)97 private NetworkScore(@NonNull final Parcel in) { 98 mLegacyInt = in.readInt(); 99 mPolicies = in.readLong(); 100 mKeepConnectedReason = in.readInt(); 101 } 102 103 /** 104 * Get the legacy int score embedded in this NetworkScore. 105 * @see Builder#setLegacyInt(int) 106 */ getLegacyInt()107 public int getLegacyInt() { 108 return mLegacyInt; 109 } 110 111 /** 112 * Returns the keep-connected reason, or KEEP_CONNECTED_NONE. 113 */ getKeepConnectedReason()114 public int getKeepConnectedReason() { 115 return mKeepConnectedReason; 116 } 117 118 /** 119 * @return whether this score has a particular policy. 120 * 121 * @hide 122 */ 123 @VisibleForTesting hasPolicy(final int policy)124 public boolean hasPolicy(final int policy) { 125 return 0 != (mPolicies & (1L << policy)); 126 } 127 128 /** 129 * To the exclusive usage of FullScore 130 * @hide 131 */ getPolicies()132 public long getPolicies() { 133 return mPolicies; 134 } 135 136 /** 137 * Whether this network should yield to a previously validated wifi gone bad. 138 * 139 * If this policy is set, other things being equal, the device will prefer a previously 140 * validated WiFi even if this network is validated and the WiFi is not. 141 * If this policy is not set, the device prefers the validated network. 142 * 143 * @hide 144 */ 145 // TODO : Unhide this for telephony and have telephony call it on the relevant carriers. 146 // In the mean time this is handled by Connectivity in a backward-compatible manner. shouldYieldToBadWifi()147 public boolean shouldYieldToBadWifi() { 148 return hasPolicy(POLICY_YIELD_TO_BAD_WIFI); 149 } 150 151 /** 152 * Whether this network is primary for this transport. 153 * 154 * When multiple networks of the same transport are active, the device prefers the ones that 155 * are primary. This is meant in particular for DS-DA devices with a user setting to choose the 156 * default SIM card, or for WiFi STA+STA and make-before-break cases. 157 * 158 * @hide 159 */ 160 @SystemApi isTransportPrimary()161 public boolean isTransportPrimary() { 162 return hasPolicy(POLICY_TRANSPORT_PRIMARY); 163 } 164 165 /** 166 * Whether this network is exiting. 167 * 168 * If this policy is set, the device will expect this network to disconnect within seconds. 169 * It will try to migrate to some other network if any is available, policy permitting, to 170 * avoid service disruption. 171 * This is useful in particular when a good cellular network is available and WiFi is getting 172 * weak and risks disconnecting soon. The WiFi network should be marked as exiting so that 173 * the device will prefer the reliable mobile network over this soon-to-be-lost WiFi. 174 * 175 * @hide 176 */ 177 @SystemApi isExiting()178 public boolean isExiting() { 179 return hasPolicy(POLICY_EXITING); 180 } 181 182 @Override toString()183 public String toString() { 184 return "Score(" + mLegacyInt + " ; Policies : " + mPolicies + ")"; 185 } 186 187 @Override writeToParcel(@onNull final Parcel dest, final int flags)188 public void writeToParcel(@NonNull final Parcel dest, final int flags) { 189 dest.writeInt(mLegacyInt); 190 dest.writeLong(mPolicies); 191 dest.writeInt(mKeepConnectedReason); 192 } 193 194 @Override describeContents()195 public int describeContents() { 196 return 0; 197 } 198 199 @NonNull public static final Creator<NetworkScore> CREATOR = new Creator<>() { 200 @Override 201 @NonNull 202 public NetworkScore createFromParcel(@NonNull final Parcel in) { 203 return new NetworkScore(in); 204 } 205 206 @Override 207 @NonNull 208 public NetworkScore[] newArray(int size) { 209 return new NetworkScore[size]; 210 } 211 }; 212 213 /** 214 * A builder for NetworkScore. 215 */ 216 public static final class Builder { 217 private static final long POLICY_NONE = 0L; 218 private static final int INVALID_LEGACY_INT = Integer.MIN_VALUE; 219 private int mLegacyInt = INVALID_LEGACY_INT; 220 private int mKeepConnectedReason = KEEP_CONNECTED_NONE; 221 private int mPolicies = 0; 222 223 /** 224 * Sets the legacy int for this score. 225 * 226 * This will be used for measurements and logs, but will no longer be used for ranking 227 * networks against each other. Callers that existed before Android S should send what 228 * they used to send as the int score. 229 * 230 * @param score the legacy int 231 * @return this 232 */ 233 @NonNull setLegacyInt(final int score)234 public Builder setLegacyInt(final int score) { 235 mLegacyInt = score; 236 return this; 237 } 238 239 240 /** 241 * Set for a network that should never be preferred to a wifi that has ever been validated 242 * 243 * If this policy is set, other things being equal, the device will prefer a previously 244 * validated WiFi even if this network is validated and the WiFi is not. 245 * If this policy is not set, the device prefers the validated network. 246 * 247 * @return this builder 248 * @hide 249 */ 250 // TODO : Unhide this for telephony and have telephony call it on the relevant carriers. 251 // In the mean time this is handled by Connectivity in a backward-compatible manner. 252 @NonNull setShouldYieldToBadWifi(final boolean val)253 public Builder setShouldYieldToBadWifi(final boolean val) { 254 if (val) { 255 mPolicies |= (1L << POLICY_YIELD_TO_BAD_WIFI); 256 } else { 257 mPolicies &= ~(1L << POLICY_YIELD_TO_BAD_WIFI); 258 } 259 return this; 260 } 261 262 /** 263 * Set for a network that is primary for this transport. 264 * 265 * When multiple networks of the same transport are active, the device prefers the ones that 266 * are primary. This is meant in particular for DS-DA devices with a user setting to choose 267 * the default SIM card, or for WiFi STA+STA and make-before-break cases. 268 * 269 * @return this builder 270 * @hide 271 */ 272 @SystemApi 273 @NonNull setTransportPrimary(final boolean val)274 public Builder setTransportPrimary(final boolean val) { 275 if (val) { 276 mPolicies |= (1L << POLICY_TRANSPORT_PRIMARY); 277 } else { 278 mPolicies &= ~(1L << POLICY_TRANSPORT_PRIMARY); 279 } 280 return this; 281 } 282 283 /** 284 * Set for a network that will likely disconnect in a few seconds. 285 * 286 * If this policy is set, the device will expect this network to disconnect within seconds. 287 * It will try to migrate to some other network if any is available, policy permitting, to 288 * avoid service disruption. 289 * This is useful in particular when a good cellular network is available and WiFi is 290 * getting weak and risks disconnecting soon. The WiFi network should be marked as exiting 291 * so that the device will prefer the reliable mobile network over this soon-to-be-lost 292 * WiFi. 293 * 294 * @return this builder 295 * @hide 296 */ 297 @SystemApi 298 @NonNull setExiting(final boolean val)299 public Builder setExiting(final boolean val) { 300 if (val) { 301 mPolicies |= (1L << POLICY_EXITING); 302 } else { 303 mPolicies &= ~(1L << POLICY_EXITING); 304 } 305 return this; 306 } 307 308 /** 309 * Set the keep-connected reason. 310 * 311 * This can be reset by calling it again with {@link KEEP_CONNECTED_NONE}. 312 */ 313 @NonNull setKeepConnectedReason(@eepConnectedReason final int reason)314 public Builder setKeepConnectedReason(@KeepConnectedReason final int reason) { 315 mKeepConnectedReason = reason; 316 return this; 317 } 318 319 /** 320 * Builds this NetworkScore. 321 * @return The built NetworkScore object. 322 */ 323 @NonNull build()324 public NetworkScore build() { 325 return new NetworkScore(mLegacyInt, mPolicies, mKeepConnectedReason); 326 } 327 } 328 } 329