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.internal.telephony.data; 18 19 import android.annotation.CurrentTimeMillisLong; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.telephony.TelephonyManager; 23 import android.telephony.data.DataProfile; 24 25 import com.android.internal.annotations.VisibleForTesting; 26 27 import java.util.ArrayList; 28 import java.util.HashSet; 29 import java.util.List; 30 import java.util.Set; 31 32 /** 33 * The class to describe a data evaluation for whether allowing or disallowing certain operations 34 * like setup a data network, sustaining existing data networks, or handover between IWLAN and 35 * cellular. 36 */ 37 public class DataEvaluation { 38 /** The reason for this evaluation */ 39 private final @NonNull DataEvaluationReason mDataEvaluationReason; 40 41 /** Data disallowed reasons. There could be multiple reasons for not allowing data. */ 42 private final @NonNull Set<DataDisallowedReason> mDataDisallowedReasons = new HashSet<>(); 43 44 /** Data allowed reason. It is intended to only have one allowed reason. */ 45 private @NonNull DataAllowedReason mDataAllowedReason = DataAllowedReason.NONE; 46 47 private @Nullable DataProfile mCandidateDataProfile = null; 48 49 /** The timestamp of evaluation time */ 50 private @CurrentTimeMillisLong long mEvaluatedTime = 0; 51 52 /** 53 * Constructor 54 * 55 * @param reason The reason for this evaluation. 56 */ DataEvaluation(DataEvaluationReason reason)57 public DataEvaluation(DataEvaluationReason reason) { 58 mDataEvaluationReason = reason; 59 } 60 61 /** 62 * Add a data disallowed reason. Note that adding a disallowed reason will clean up the 63 * allowed reason because they are mutual exclusive. 64 * 65 * @param reason Disallowed reason. 66 */ addDataDisallowedReason(DataDisallowedReason reason)67 public void addDataDisallowedReason(DataDisallowedReason reason) { 68 mDataAllowedReason = DataAllowedReason.NONE; 69 mDataDisallowedReasons.add(reason); 70 mEvaluatedTime = System.currentTimeMillis(); 71 } 72 73 /** 74 * Remove a data disallowed reason if one exists. 75 * 76 * @param reason Disallowed reason. 77 */ removeDataDisallowedReason(DataDisallowedReason reason)78 public void removeDataDisallowedReason(DataDisallowedReason reason) { 79 mDataDisallowedReasons.remove(reason); 80 mEvaluatedTime = System.currentTimeMillis(); 81 } 82 83 /** 84 * Add a data allowed reason. Note that adding an allowed reason will clean up the disallowed 85 * reasons because they are mutual exclusive. 86 * 87 * @param reason Allowed reason. 88 */ addDataAllowedReason(DataAllowedReason reason)89 public void addDataAllowedReason(DataAllowedReason reason) { 90 mDataDisallowedReasons.clear(); 91 92 // Only higher priority allowed reason can overwrite the old one. See 93 // DataAllowedReason for the oder. 94 if (reason.ordinal() > mDataAllowedReason.ordinal()) { 95 mDataAllowedReason = reason; 96 } 97 mEvaluatedTime = System.currentTimeMillis(); 98 } 99 100 /** 101 * @return List of data disallowed reasons. 102 */ getDataDisallowedReasons()103 public @NonNull List<DataDisallowedReason> getDataDisallowedReasons() { 104 return new ArrayList<>(mDataDisallowedReasons); 105 } 106 107 /** 108 * @return The data allowed reason. 109 */ getDataAllowedReason()110 public @NonNull DataAllowedReason getDataAllowedReason() { 111 return mDataAllowedReason; 112 } 113 114 /** 115 * Set the candidate data profile for setup data network. 116 * 117 * @param dataProfile The candidate data profile. 118 */ setCandidateDataProfile(@onNull DataProfile dataProfile)119 public void setCandidateDataProfile(@NonNull DataProfile dataProfile) { 120 mCandidateDataProfile = dataProfile; 121 } 122 123 /** 124 * @return The candidate data profile for setup data network. 125 */ getCandidateDataProfile()126 public @Nullable DataProfile getCandidateDataProfile() { 127 return mCandidateDataProfile; 128 } 129 130 /** 131 * @return {@code true} if the evaluation contains disallowed reasons. 132 */ containsDisallowedReasons()133 public boolean containsDisallowedReasons() { 134 return mDataDisallowedReasons.size() != 0; 135 } 136 137 /** 138 * Check if it contains a certain disallowed reason. 139 * 140 * @param reason The disallowed reason to check. 141 * @return {@code true} if the provided reason matches one of the disallowed reasons. 142 */ contains(DataDisallowedReason reason)143 public boolean contains(DataDisallowedReason reason) { 144 return mDataDisallowedReasons.contains(reason); 145 } 146 147 /** 148 * Check if only one disallowed reason prevent data connection. 149 * 150 * @param reason The given reason to check 151 * @return {@code true} if the given reason is the only one that prevents data connection 152 */ containsOnly(DataDisallowedReason reason)153 public boolean containsOnly(DataDisallowedReason reason) { 154 return mDataDisallowedReasons.size() == 1 && contains(reason); 155 } 156 157 /** 158 * Check if the any of the disallowed reasons match one of the provided reason. 159 * 160 * @param reasons The given reasons to check. 161 * @return {@code true} if any of the given reasons matches one of the disallowed reasons. 162 */ containsAny(DataDisallowedReason... reasons)163 public boolean containsAny(DataDisallowedReason... reasons) { 164 for (DataDisallowedReason reason : reasons) { 165 if (mDataDisallowedReasons.contains(reason)) return true; 166 } 167 return false; 168 } 169 170 /** 171 * Check if the allowed reason is the specified reason. 172 * 173 * @param reason The allowed reason. 174 * @return {@code true} if the specified reason matches the allowed reason. 175 */ contains(DataAllowedReason reason)176 public boolean contains(DataAllowedReason reason) { 177 return reason == mDataAllowedReason; 178 } 179 180 /** 181 * @return {@code true} if the disallowed reasons contains hard reasons. 182 */ containsHardDisallowedReasons()183 public boolean containsHardDisallowedReasons() { 184 for (DataDisallowedReason reason : mDataDisallowedReasons) { 185 if (reason.isHardReason()) { 186 return true; 187 } 188 } 189 return false; 190 } 191 192 /** 193 * The reason for evaluating unsatisfied network requests, existing data networks, and handover. 194 */ 195 @VisibleForTesting 196 public enum DataEvaluationReason { 197 /** New request from the apps. */ 198 NEW_REQUEST(false), 199 /** Data config changed. */ 200 DATA_CONFIG_CHANGED(true), 201 /** SIM is loaded. */ 202 SIM_LOADED(true), 203 /** SIM is removed. */ 204 SIM_REMOVAL(true), 205 /** Data profiles changed. */ 206 DATA_PROFILES_CHANGED(true), 207 /** When service state changes.(For now only considering data RAT and data registration). */ 208 DATA_SERVICE_STATE_CHANGED(true), 209 /** When data is enabled or disabled (by user, carrier, thermal, etc...) */ 210 DATA_ENABLED_CHANGED(true), 211 /** When data enabled overrides are changed (MMS always allowed, data on non-DDS sub). */ 212 DATA_ENABLED_OVERRIDE_CHANGED(true), 213 /** When data roaming is enabled or disabled. */ 214 ROAMING_ENABLED_CHANGED(true), 215 /** When voice call ended (for concurrent voice/data not supported RAT). */ 216 VOICE_CALL_ENDED(true), 217 /** When network restricts or no longer restricts mobile data. */ 218 DATA_RESTRICTED_CHANGED(true), 219 /** Network capabilities changed. The unsatisfied requests might have chances to attach. */ 220 DATA_NETWORK_CAPABILITIES_CHANGED(true), 221 /** When emergency call started or ended. */ 222 EMERGENCY_CALL_CHANGED(true), 223 /** When data disconnected, re-evaluate later to see if data could be brought up again. */ 224 RETRY_AFTER_DISCONNECTED(true), 225 /** Data setup retry. */ 226 DATA_RETRY(false), 227 /** For handover evaluation, or for network tearing down after handover succeeds/fails. */ 228 DATA_HANDOVER(true), 229 /** Preferred transport changed. */ 230 PREFERRED_TRANSPORT_CHANGED(true), 231 /** Slice config changed. */ 232 SLICE_CONFIG_CHANGED(true), 233 /** 234 * Single data network arbitration. On certain RATs, only one data network is allowed at the 235 * same time. 236 */ 237 SINGLE_DATA_NETWORK_ARBITRATION(true), 238 /** Query from {@link TelephonyManager#isDataConnectivityPossible()}. */ 239 EXTERNAL_QUERY(false), 240 /** Tracking area code changed. */ 241 TAC_CHANGED(true); 242 243 /** 244 * {@code true} if the evaluation is due to environmental changes (i.e. SIM removal, 245 * registration state changes, etc.... 246 */ 247 private final boolean mIsConditionBased; 248 249 /** 250 * @return {@code true} if the evaluation is due to environmental changes (i.e. SIM removal, 251 * registration state changes, etc.... 252 */ isConditionBased()253 public boolean isConditionBased() { 254 return mIsConditionBased; 255 } 256 257 /** 258 * Constructor 259 * 260 * @param isConditionBased {@code true} if the evaluation is due to environmental changes 261 * (i.e. SIM removal, registration state changes, etc....) 262 */ DataEvaluationReason(boolean isConditionBased)263 DataEvaluationReason(boolean isConditionBased) { 264 mIsConditionBased = isConditionBased; 265 } 266 } 267 268 /** Disallowed reasons. There could be multiple reasons if it is not allowed. */ 269 public enum DataDisallowedReason { 270 // Soft failure reasons. A soft reason means that in certain conditions, data is still 271 // allowed. Normally those reasons are due to users settings. 272 /** Data is disabled by the user or policy. */ 273 DATA_DISABLED(false), 274 /** Data roaming is disabled by the user. */ 275 ROAMING_DISABLED(false), 276 /** Default data not selected. */ 277 DEFAULT_DATA_UNSELECTED(false), 278 279 // Belows are all hard failure reasons. A hard reason means no matter what the data should 280 // not be allowed. 281 /** Data registration state is not in service. */ 282 NOT_IN_SERVICE(true), 283 /** Data config is not ready. */ 284 DATA_CONFIG_NOT_READY(true), 285 /** SIM is not ready. */ 286 SIM_NOT_READY(true), 287 /** Concurrent voice and data is not allowed. */ 288 CONCURRENT_VOICE_DATA_NOT_ALLOWED(true), 289 /** Carrier notified data should be restricted. */ 290 DATA_RESTRICTED_BY_NETWORK(true), 291 /** Radio power is off (i.e. airplane mode on) */ 292 RADIO_POWER_OFF(true), 293 /** Data setup now allowed due to pending tear down all networks. */ 294 PENDING_TEAR_DOWN_ALL(true), 295 /** Airplane mode is forcibly turned on by the carrier. */ 296 RADIO_DISABLED_BY_CARRIER(true), 297 /** Underlying data service is not bound. */ 298 DATA_SERVICE_NOT_READY(true), 299 /** Unable to find a suitable data profile. */ 300 NO_SUITABLE_DATA_PROFILE(true), 301 /** Current data network type not allowed. */ 302 DATA_NETWORK_TYPE_NOT_ALLOWED(true), 303 /** Device is currently in CDMA ECBM. */ 304 CDMA_EMERGENCY_CALLBACK_MODE(true), 305 /** There is already a retry setup/handover scheduled. */ 306 RETRY_SCHEDULED(true), 307 /** Network has explicitly request to throttle setup attempt. */ 308 DATA_THROTTLED(true), 309 /** Data profile becomes invalid. (could be removed by the user, or SIM refresh, etc..) */ 310 DATA_PROFILE_INVALID(true), 311 /** Data profile not preferred (i.e. users switch preferred profile in APN editor.) */ 312 DATA_PROFILE_NOT_PREFERRED(true), 313 /** Handover is not allowed by policy. */ 314 NOT_ALLOWED_BY_POLICY(true), 315 /** Data network is not in the right state. */ 316 ILLEGAL_STATE(true), 317 /** VoPS is not supported by the network. */ 318 VOPS_NOT_SUPPORTED(true), 319 /** Only one data network is allowed at one time. */ 320 ONLY_ALLOWED_SINGLE_NETWORK(true), 321 /** Data enabled settings are not ready. */ 322 DATA_SETTINGS_NOT_READY(true); 323 324 private final boolean mIsHardReason; 325 326 /** 327 * @return {@code true} if the disallowed reason is a hard reason. 328 */ isHardReason()329 public boolean isHardReason() { 330 return mIsHardReason; 331 } 332 333 /** 334 * Constructor 335 * 336 * @param isHardReason {@code true} if the disallowed reason is a hard reason. A hard reason 337 * means no matter what the data should not be allowed. A soft reason means that in certain 338 * conditions, data is still allowed. 339 */ DataDisallowedReason(boolean isHardReason)340 DataDisallowedReason(boolean isHardReason) { 341 mIsHardReason = isHardReason; 342 } 343 } 344 345 /** 346 * Data allowed reasons. There will be only one reason if data is allowed. 347 */ 348 public enum DataAllowedReason { 349 // Note that unlike disallowed reasons, we only have one allowed reason every time 350 // when we check data is allowed or not. The order of these allowed reasons is very 351 // important. The lower ones take precedence over the upper ones. 352 /** 353 * None. This is the initial value. 354 */ 355 NONE, 356 /** 357 * The normal reason. This is the most common case. 358 */ 359 NORMAL, 360 /** 361 * The network brought up by this network request is unmetered. Should allowed no matter 362 * the user enables or disables data. 363 */ 364 UNMETERED_USAGE, 365 /** 366 * The network request supports MMS and MMS is always allowed. 367 */ 368 MMS_REQUEST, 369 /** 370 * The network request is restricted (i.e. Only privilege apps can access the network.) 371 */ 372 RESTRICTED_REQUEST, 373 /** 374 * SUPL is allowed while emergency call is ongoing. 375 */ 376 EMERGENCY_SUPL, 377 /** 378 * Data is allowed because the network request is for emergency. This should be always at 379 * the bottom (i.e. highest priority) 380 */ 381 EMERGENCY_REQUEST, 382 } 383 384 @Override toString()385 public String toString() { 386 StringBuilder evaluationStr = new StringBuilder(); 387 evaluationStr.append("Data evaluation: evaluation reason:" + mDataEvaluationReason + ", "); 388 if (mDataDisallowedReasons.size() > 0) { 389 evaluationStr.append("Data disallowed reasons:"); 390 for (DataDisallowedReason reason : mDataDisallowedReasons) { 391 evaluationStr.append(" ").append(reason); 392 } 393 } else { 394 evaluationStr.append("Data allowed reason:"); 395 evaluationStr.append(" ").append(mDataAllowedReason); 396 } 397 evaluationStr.append(", candidate profile=" + mCandidateDataProfile); 398 evaluationStr.append(", time=" + DataUtils.systemTimeToString(mEvaluatedTime)); 399 return evaluationStr.toString(); 400 } 401 402 } 403