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