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 static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; 20 21 import android.annotation.CallbackExecutor; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.content.Context; 25 import android.content.SharedPreferences; 26 import android.hardware.display.DisplayManager; 27 import android.net.ConnectivityManager; 28 import android.net.Network; 29 import android.net.NetworkCapabilities; 30 import android.os.AsyncResult; 31 import android.os.Handler; 32 import android.os.HandlerExecutor; 33 import android.os.Looper; 34 import android.os.Message; 35 import android.os.OutcomeReceiver; 36 import android.preference.PreferenceManager; 37 import android.telephony.AccessNetworkConstants; 38 import android.telephony.Annotation.DataActivityType; 39 import android.telephony.CellIdentity; 40 import android.telephony.CellIdentityGsm; 41 import android.telephony.CellIdentityLte; 42 import android.telephony.CellIdentityNr; 43 import android.telephony.CellIdentityTdscdma; 44 import android.telephony.CellIdentityWcdma; 45 import android.telephony.CellInfo; 46 import android.telephony.ModemActivityInfo; 47 import android.telephony.NetworkRegistrationInfo; 48 import android.telephony.ServiceState; 49 import android.telephony.SignalStrength; 50 import android.telephony.TelephonyCallback; 51 import android.telephony.TelephonyManager; 52 import android.text.TextUtils; 53 import android.util.ArrayMap; 54 import android.util.ArraySet; 55 import android.util.LocalLog; 56 import android.util.Pair; 57 import android.view.Display; 58 59 import com.android.internal.annotations.VisibleForTesting; 60 import com.android.internal.telephony.DctConstants; 61 import com.android.internal.telephony.Phone; 62 import com.android.internal.telephony.TelephonyFacade; 63 import com.android.internal.telephony.metrics.TelephonyMetrics; 64 import com.android.internal.telephony.nano.TelephonyProto.NrMode; 65 import com.android.internal.util.IndentingPrintWriter; 66 import com.android.telephony.Rlog; 67 68 import java.io.FileDescriptor; 69 import java.io.PrintWriter; 70 import java.util.Map; 71 import java.util.Objects; 72 import java.util.Set; 73 import java.util.concurrent.Executor; 74 75 /** 76 * Link Bandwidth Estimator based on the byte counts in TrafficStats and the time reported in modem 77 * activity. 78 */ 79 public class LinkBandwidthEstimator extends Handler { 80 private static final String TAG = LinkBandwidthEstimator.class.getSimpleName(); 81 private static final boolean DBG = false; 82 @VisibleForTesting 83 static final int MSG_SCREEN_STATE_CHANGED = 1; 84 @VisibleForTesting 85 static final int MSG_TRAFFIC_STATS_POLL = 2; 86 @VisibleForTesting 87 static final int MSG_MODEM_ACTIVITY_RETURNED = 3; 88 @VisibleForTesting 89 static final int MSG_DEFAULT_NETWORK_CHANGED = 4; 90 @VisibleForTesting 91 static final int MSG_SIGNAL_STRENGTH_CHANGED = 5; 92 @VisibleForTesting 93 static final int MSG_NR_FREQUENCY_CHANGED = 6; 94 @VisibleForTesting 95 static final int MSG_NR_STATE_CHANGED = 7; 96 @VisibleForTesting 97 static final int MSG_ACTIVE_PHONE_CHANGED = 8; 98 @VisibleForTesting 99 static final int MSG_DATA_REG_STATE_OR_RAT_CHANGED = 9; 100 101 @VisibleForTesting 102 static final int UNKNOWN_TAC = CellInfo.UNAVAILABLE; 103 104 // TODO: move the following parameters to xml file 105 private static final int TRAFFIC_STATS_POLL_INTERVAL_MS = 1_000; 106 private static final int MODEM_POLL_MIN_INTERVAL_MS = 5_000; 107 private static final int TRAFFIC_MODEM_POLL_BYTE_RATIO = 8; 108 private static final int TRAFFIC_POLL_BYTE_THRESHOLD_MAX = 20_000; 109 private static final int BYTE_DELTA_ACC_THRESHOLD_MAX_KB = 8_000; 110 private static final int MODEM_POLL_TIME_DELTA_MAX_MS = 10_000; 111 private static final int FILTER_UPDATE_MAX_INTERVAL_MS = 5_100; 112 // BW samples with Tx or Rx time below the following value is ignored. 113 private static final int TX_RX_TIME_MIN_MS = 200; 114 // The large time constant used in BW filter 115 private static final int TIME_CONSTANT_LARGE_SEC = 6; 116 // The small time constant used in BW filter 117 private static final int TIME_CONSTANT_SMALL_SEC = 6; 118 // If RSSI changes by more than the below value, update BW filter with small time constant 119 private static final int RSSI_DELTA_THRESHOLD_DB = 6; 120 // The up-scaling factor of filter coefficient. 121 private static final int FILTER_SCALE = 128; 122 // Force weight to 0 if the elapsed time is above LARGE_TIME_DECAY_RATIO * time constant 123 private static final int LARGE_TIME_DECAY_RATIO = 4; 124 // Modem Tx time may contain Rx time as defined in HAL. To work around the issue, if Tx time 125 // over Rx time ratio is above the following value, use Tx time + Rx time as Rx time. 126 private static final int TX_OVER_RX_TIME_RATIO_THRESHOLD_NUM = 3; 127 private static final int TX_OVER_RX_TIME_RATIO_THRESHOLD_DEN = 2; 128 // Default Link bandwidth value if the RAT entry is not found in static BW table. 129 private static final int DEFAULT_LINK_BAND_WIDTH_KBPS = 14; 130 // If Tx or Rx link bandwidth change is above the following value, send the BW update 131 private static final int BW_UPDATE_THRESHOLD_PERCENT = 15; 132 133 // To be used in link bandwidth estimation, each TrafficStats poll sample needs to be above 134 // a predefine threshold. 135 // For RAT with static BW above HIGH_BANDWIDTH_THRESHOLD_KBPS, it uses the following table. 136 // For others RATs, the thresholds are derived from the static BW values. 137 // The following table is defined per signal level, int [NUM_SIGNAL_LEVEL]. 138 private static final int HIGH_BANDWIDTH_THRESHOLD_KBPS = 5000; 139 //Array dimension : int [NUM_LINK_DIRECTION][NUM_SIGNAL_LEVEL] 140 private static final int[][] BYTE_DELTA_THRESHOLD_KB = 141 {{200, 300, 400, 600, 1000}, {400, 600, 800, 1000, 1000}}; 142 // Used to derive byte count threshold from avg BW 143 private static final int LOW_BW_TO_AVG_BW_RATIO_NUM = 3; 144 private static final int LOW_BW_TO_AVG_BW_RATIO_DEN = 8; 145 private static final int MAX_BW_TO_STATIC_BW_RATIO = 15; 146 private static final int BYTE_DELTA_THRESHOLD_MIN_KB = 10; 147 private static final int MAX_ERROR_PERCENT = 100 * 100; 148 private static final String[] AVG_BW_PER_RAT = { 149 "GPRS:24,24", "EDGE:70,18", "UMTS:115,115", "CDMA:14,14", 150 "CDMA - 1xRTT:30,30", "CDMA - EvDo rev. 0:750,48", "CDMA - EvDo rev. A:950,550", 151 "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "CDMA - EvDo rev. B:1500,550", 152 "CDMA - eHRPD:750,48", "HSPA+:13000,3400", "TD_SCDMA:115,115", 153 "LTE:30000,15000", "NR_NSA:47000,18000", 154 "NR_NSA_MMWAVE:145000,60000", "NR:145000,60000", "NR_MMWAVE:145000,60000"}; 155 private static final Map<String, Pair<Integer, Integer>> AVG_BW_PER_RAT_MAP = new ArrayMap<>(); 156 private static final String UNKNOWN_PLMN = ""; 157 158 // To be used in the long term avg, each count needs to be above the following value 159 public static final int BW_STATS_COUNT_THRESHOLD = 5; 160 public static final int NUM_SIGNAL_LEVEL = 5; 161 public static final int LINK_TX = 0; 162 public static final int LINK_RX = 1; 163 public static final int NUM_LINK_DIRECTION = 2; 164 165 // One common timestamp for all sim to avoid frequent modem polling 166 private final Phone mPhone; 167 private final TelephonyFacade mTelephonyFacade; 168 private final TelephonyManager mTelephonyManager; 169 private final LocalLog mLocalLog = new LocalLog(512); 170 private boolean mScreenOn = false; 171 private boolean mIsOnDefaultRoute = false; 172 private boolean mIsOnActiveData = false; 173 private long mLastModemPollTimeMs; 174 private boolean mLastTrafficValid = true; 175 private long mLastMobileTxBytes; 176 private long mLastMobileRxBytes; 177 private long mTxBytesDeltaAcc; 178 private long mRxBytesDeltaAcc; 179 180 private ModemActivityInfo mLastModemActivityInfo = null; 181 private final TelephonyCallback mTelephonyCallback = new TelephonyCallbackImpl(); 182 private int mSignalStrengthDbm; 183 private int mSignalLevel; 184 private int mDataRat = TelephonyManager.NETWORK_TYPE_UNKNOWN; 185 private int mTac; 186 @NonNull private String mPlmn = UNKNOWN_PLMN; 187 private NetworkCapabilities mNetworkCapabilities; 188 private final NetworkBandwidth mPlaceholderNetwork; 189 private long mFilterUpdateTimeMs; 190 191 private int mBandwidthUpdateSignalDbm = -1; 192 private int mBandwidthUpdateSignalLevel = -1; 193 private int mBandwidthUpdateDataRat = TelephonyManager.NETWORK_TYPE_UNKNOWN; 194 private String mBandwidthUpdatePlmn = UNKNOWN_PLMN; 195 private final BandwidthState mTxState = new BandwidthState(LINK_TX); 196 private final BandwidthState mRxState = new BandwidthState(LINK_RX); 197 private long mLastPlmnOrRatChangeTimeMs; 198 private long mLastDrsOrRatChangeTimeMs; 199 200 private int mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE; 201 202 /** Link bandwidth estimator callbacks. */ 203 @NonNull 204 private final Set<LinkBandwidthEstimatorCallback> mLinkBandwidthEstimatorCallbacks = 205 new ArraySet<>(); 206 207 /** 208 * The link bandwidth estimator callback. Note this is only used for passing information 209 * internally in the data stack, should not be used externally. 210 */ 211 public static class LinkBandwidthEstimatorCallback extends DataCallback { 212 /** 213 * Constructor 214 * 215 * @param executor The executor of the callback. 216 */ LinkBandwidthEstimatorCallback(@onNull @allbackExecutor Executor executor)217 public LinkBandwidthEstimatorCallback(@NonNull @CallbackExecutor Executor executor) { 218 super(executor); 219 } 220 221 /** 222 * Called when data activity changed. 223 * 224 * @param dataActivity The data activity. 225 */ onDataActivityChanged(@ataActivityType int dataActivity)226 public void onDataActivityChanged(@DataActivityType int dataActivity) {} 227 228 /** 229 * Called when bandwidth changed. 230 * 231 * @param uplinkBandwidthKbps Uplink bandwidth estimate in Kbps. 232 * @param downlinkBandwidthKbps Downlink bandwidth estimate in Kbps. 233 */ onBandwidthChanged(int uplinkBandwidthKbps, int downlinkBandwidthKbps)234 public void onBandwidthChanged(int uplinkBandwidthKbps, int downlinkBandwidthKbps) {} 235 } 236 initAvgBwPerRatTable()237 private static void initAvgBwPerRatTable() { 238 for (String config : AVG_BW_PER_RAT) { 239 int rxKbps = 14; 240 int txKbps = 14; 241 String[] kv = config.split(":"); 242 if (kv.length == 2) { 243 String[] split = kv[1].split(","); 244 if (split.length == 2) { 245 try { 246 rxKbps = Integer.parseInt(split[0]); 247 txKbps = Integer.parseInt(split[1]); 248 } catch (NumberFormatException ignored) { 249 } 250 } 251 AVG_BW_PER_RAT_MAP.put(kv[0], new Pair<>(rxKbps, txKbps)); 252 } 253 } 254 } 255 256 private final DisplayManager.DisplayListener mDisplayListener = 257 new DisplayManager.DisplayListener() { 258 @Override 259 public void onDisplayAdded(int displayId) { 260 } 261 262 @Override 263 public void onDisplayRemoved(int displayId) { 264 } 265 266 @Override 267 public void onDisplayChanged(int displayId) { 268 obtainMessage(MSG_SCREEN_STATE_CHANGED, isScreenOn()).sendToTarget(); 269 } 270 }; 271 272 private final OutcomeReceiver<ModemActivityInfo, TelephonyManager.ModemActivityInfoException> 273 mOutcomeReceiver = 274 new OutcomeReceiver<>() { 275 @Override 276 public void onResult(ModemActivityInfo result) { 277 obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, result).sendToTarget(); 278 } 279 280 @Override 281 public void onError(@NonNull TelephonyManager.ModemActivityInfoException e) { 282 Rlog.e(TAG, "error reading modem stats:" + e); 283 obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, null).sendToTarget(); 284 } 285 }; 286 287 private final ConnectivityManager.NetworkCallback mDefaultNetworkCallback = 288 new ConnectivityManager.NetworkCallback() { 289 @Override 290 public void onCapabilitiesChanged(@NonNull Network network, 291 @NonNull NetworkCapabilities networkCapabilities) { 292 obtainMessage(MSG_DEFAULT_NETWORK_CHANGED, networkCapabilities).sendToTarget(); 293 } 294 295 public void onLost(@NonNull Network network) { 296 obtainMessage(MSG_DEFAULT_NETWORK_CHANGED, null).sendToTarget(); 297 } 298 }; 299 LinkBandwidthEstimator(Phone phone, Looper looper, TelephonyFacade telephonyFacade)300 public LinkBandwidthEstimator(Phone phone, Looper looper, TelephonyFacade telephonyFacade) { 301 super(looper); 302 mPhone = phone; 303 mTelephonyFacade = telephonyFacade; 304 mTelephonyManager = phone.getContext() 305 .getSystemService(TelephonyManager.class) 306 .createForSubscriptionId(phone.getSubId()); 307 DisplayManager dm = (DisplayManager) phone.getContext().getSystemService( 308 Context.DISPLAY_SERVICE); 309 if (dm != null) { 310 dm.registerDisplayListener(mDisplayListener, null); 311 } 312 handleScreenStateChanged(isScreenOn()); 313 314 ConnectivityManager cm = phone.getContext() 315 .getSystemService(ConnectivityManager.class); 316 if (cm != null) { 317 cm.registerDefaultNetworkCallback(mDefaultNetworkCallback, this); 318 } 319 mTelephonyManager.registerTelephonyCallback(new HandlerExecutor(this), mTelephonyCallback); 320 mPlaceholderNetwork = new NetworkBandwidth(UNKNOWN_PLMN); 321 initAvgBwPerRatTable(); 322 registerNrStateFrequencyChange(); 323 mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(AccessNetworkConstants 324 .TRANSPORT_TYPE_WWAN, this, MSG_DATA_REG_STATE_OR_RAT_CHANGED, null); 325 mPhone.getSignalStrengthController().registerForSignalStrengthChanged(this, 326 MSG_SIGNAL_STRENGTH_CHANGED, null); 327 } 328 329 @Override handleMessage(Message msg)330 public void handleMessage(Message msg) { 331 switch (msg.what) { 332 case MSG_SCREEN_STATE_CHANGED: 333 handleScreenStateChanged((boolean) msg.obj); 334 break; 335 case MSG_TRAFFIC_STATS_POLL: 336 handleTrafficStatsPoll(); 337 break; 338 case MSG_MODEM_ACTIVITY_RETURNED: 339 handleModemActivityReturned((ModemActivityInfo) msg.obj); 340 break; 341 case MSG_DEFAULT_NETWORK_CHANGED: 342 handleDefaultNetworkChanged((NetworkCapabilities) msg.obj); 343 break; 344 case MSG_SIGNAL_STRENGTH_CHANGED: 345 handleSignalStrengthChanged(); 346 break; 347 case MSG_NR_FREQUENCY_CHANGED: 348 // fall through 349 case MSG_NR_STATE_CHANGED: 350 updateStaticBwValueResetFilter(); 351 break; 352 case MSG_ACTIVE_PHONE_CHANGED: 353 handleActivePhoneChanged((int) msg.obj); 354 break; 355 case MSG_DATA_REG_STATE_OR_RAT_CHANGED: 356 handleDrsOrRatChanged((AsyncResult) msg.obj); 357 break; 358 default: 359 Rlog.e(TAG, "invalid message " + msg.what); 360 break; 361 } 362 } 363 364 /** 365 * Register the callback for receiving information from {@link LinkBandwidthEstimator}. 366 * 367 * @param callback The callback. 368 */ registerCallback(@onNull LinkBandwidthEstimatorCallback callback)369 public void registerCallback(@NonNull LinkBandwidthEstimatorCallback callback) { 370 mLinkBandwidthEstimatorCallbacks.add(callback); 371 } 372 373 /** 374 * Unregister the callback. 375 * 376 * @param callback The previously registered callback. 377 */ unregisterCallback(@onNull LinkBandwidthEstimatorCallback callback)378 public void unregisterCallback(@NonNull LinkBandwidthEstimatorCallback callback) { 379 mLinkBandwidthEstimatorCallbacks.remove(callback); 380 } 381 382 /** 383 * @return True if one the device's screen (e.g. main screen, wifi display, HDMI display etc...) 384 * is on. 385 */ isScreenOn()386 private boolean isScreenOn() { 387 // Note that we don't listen to Intent.SCREEN_ON and Intent.SCREEN_OFF because they are no 388 // longer adequate for monitoring the screen state since they are not sent in cases where 389 // the screen is turned off transiently such as due to the proximity sensor. 390 final DisplayManager dm = (DisplayManager) mPhone.getContext().getSystemService( 391 Context.DISPLAY_SERVICE); 392 if (dm == null) return false; 393 Display[] displays = dm.getDisplays(); 394 395 if (displays != null) { 396 for (Display display : displays) { 397 // Anything other than STATE_ON is treated as screen off, such as STATE_DOZE, 398 // STATE_DOZE_SUSPEND, etc... 399 if (display.getState() == Display.STATE_ON) { 400 return true; 401 } 402 } 403 return false; 404 } 405 406 return false; 407 } 408 handleScreenStateChanged(boolean screenOn)409 private void handleScreenStateChanged(boolean screenOn) { 410 if (mScreenOn == screenOn) { 411 return; 412 } 413 mScreenOn = screenOn; 414 handleTrafficStatsPollConditionChanged(); 415 } 416 handleDefaultNetworkChanged(NetworkCapabilities networkCapabilities)417 private void handleDefaultNetworkChanged(NetworkCapabilities networkCapabilities) { 418 mNetworkCapabilities = networkCapabilities; 419 boolean isOnDefaultRoute; 420 if (networkCapabilities == null) { 421 isOnDefaultRoute = false; 422 } else { 423 isOnDefaultRoute = networkCapabilities.hasTransport(TRANSPORT_CELLULAR); 424 } 425 if (mIsOnDefaultRoute == isOnDefaultRoute) { 426 return; 427 } 428 mIsOnDefaultRoute = isOnDefaultRoute; 429 logd("mIsOnDefaultRoute " + mIsOnDefaultRoute); 430 handleTrafficStatsPollConditionChanged(); 431 } 432 handleActivePhoneChanged(int activeDataSubId)433 private void handleActivePhoneChanged(int activeDataSubId) { 434 boolean isOnActiveData = activeDataSubId == mPhone.getSubId(); 435 if (mIsOnActiveData == isOnActiveData) { 436 return; 437 } 438 mIsOnActiveData = isOnActiveData; 439 logd("mIsOnActiveData " + mIsOnActiveData + " activeDataSubId " + activeDataSubId); 440 handleTrafficStatsPollConditionChanged(); 441 } 442 443 @SuppressWarnings("unchecked") handleDrsOrRatChanged(AsyncResult ar)444 private void handleDrsOrRatChanged(AsyncResult ar) { 445 Pair<Integer, Integer> drsRatPair = (Pair<Integer, Integer>) ar.result; 446 logd("DrsOrRatChanged dataRegState " + drsRatPair.first + " rilRat " + drsRatPair.second); 447 mLastDrsOrRatChangeTimeMs = mTelephonyFacade.getElapsedSinceBootMillis(); 448 } 449 handleTrafficStatsPollConditionChanged()450 private void handleTrafficStatsPollConditionChanged() { 451 removeMessages(MSG_TRAFFIC_STATS_POLL); 452 if (mScreenOn && mIsOnDefaultRoute && mIsOnActiveData) { 453 updateDataRatCellIdentityBandwidth(); 454 handleTrafficStatsPoll(); 455 } else { 456 logd("Traffic status poll stopped"); 457 if (mDataActivity != TelephonyManager.DATA_ACTIVITY_NONE) { 458 mDataActivity = TelephonyManager.DATA_ACTIVITY_NONE; 459 mLinkBandwidthEstimatorCallbacks.forEach(callback -> callback.invokeFromExecutor( 460 () -> callback.onDataActivityChanged(mDataActivity))); 461 } 462 } 463 } 464 handleTrafficStatsPoll()465 private void handleTrafficStatsPoll() { 466 invalidateTxRxSamples(); 467 long mobileTxBytes = mTelephonyFacade.getMobileTxBytes(); 468 long mobileRxBytes = mTelephonyFacade.getMobileRxBytes(); 469 long txBytesDelta = mobileTxBytes - mLastMobileTxBytes; 470 long rxBytesDelta = mobileRxBytes - mLastMobileRxBytes; 471 472 int dataActivity; 473 if (txBytesDelta > 0 && rxBytesDelta > 0) { 474 dataActivity = TelephonyManager.DATA_ACTIVITY_INOUT; 475 } else if (rxBytesDelta > 0) { 476 dataActivity = TelephonyManager.DATA_ACTIVITY_IN; 477 } else if (txBytesDelta > 0) { 478 dataActivity = TelephonyManager.DATA_ACTIVITY_OUT; 479 } else { 480 dataActivity = TelephonyManager.DATA_ACTIVITY_NONE; 481 } 482 483 if (mDataActivity != dataActivity) { 484 mDataActivity = dataActivity; 485 mLinkBandwidthEstimatorCallbacks.forEach(callback -> callback.invokeFromExecutor( 486 () -> callback.onDataActivityChanged(dataActivity))); 487 } 488 489 // Schedule the next traffic stats poll 490 sendEmptyMessageDelayed(MSG_TRAFFIC_STATS_POLL, TRAFFIC_STATS_POLL_INTERVAL_MS); 491 492 mLastMobileTxBytes = mobileTxBytes; 493 mLastMobileRxBytes = mobileRxBytes; 494 // Sometimes TrafficStats byte counts return invalid values 495 // Ignore two polls if it happens 496 boolean trafficValid = txBytesDelta >= 0 && rxBytesDelta >= 0; 497 if (!mLastTrafficValid || !trafficValid) { 498 mLastTrafficValid = trafficValid; 499 Rlog.e(TAG, " run into invalid traffic count"); 500 return; 501 } 502 503 mTxBytesDeltaAcc += txBytesDelta; 504 mRxBytesDeltaAcc += rxBytesDelta; 505 506 boolean doModemPoll = true; 507 // Check if it meets the requirement to request modem activity 508 long txByteDeltaThr = Math.min(mTxState.mByteDeltaAccThr / TRAFFIC_MODEM_POLL_BYTE_RATIO, 509 TRAFFIC_POLL_BYTE_THRESHOLD_MAX); 510 long rxByteDeltaThr = Math.min(mRxState.mByteDeltaAccThr / TRAFFIC_MODEM_POLL_BYTE_RATIO, 511 TRAFFIC_POLL_BYTE_THRESHOLD_MAX); 512 if (txBytesDelta < txByteDeltaThr && rxBytesDelta < rxByteDeltaThr 513 && mTxBytesDeltaAcc < mTxState.mByteDeltaAccThr 514 && mRxBytesDeltaAcc < mRxState.mByteDeltaAccThr) { 515 doModemPoll = false; 516 } 517 518 long currTimeMs = mTelephonyFacade.getElapsedSinceBootMillis(); 519 long timeSinceLastModemPollMs = currTimeMs - mLastModemPollTimeMs; 520 if (timeSinceLastModemPollMs < MODEM_POLL_MIN_INTERVAL_MS) { 521 doModemPoll = false; 522 } 523 524 if (doModemPoll) { 525 StringBuilder sb = new StringBuilder(); 526 logd(sb.append("txByteDelta ").append(txBytesDelta) 527 .append(" rxByteDelta ").append(rxBytesDelta) 528 .append(" txByteDeltaAcc ").append(mTxBytesDeltaAcc) 529 .append(" rxByteDeltaAcc ").append(mRxBytesDeltaAcc) 530 .append(" trigger modem activity request").toString()); 531 updateDataRatCellIdentityBandwidth(); 532 // Filter update will happen after the request 533 makeRequestModemActivity(); 534 return; 535 } 536 537 long timeSinceLastFilterUpdateMs = currTimeMs - mFilterUpdateTimeMs; 538 // Update filter 539 if (timeSinceLastFilterUpdateMs >= FILTER_UPDATE_MAX_INTERVAL_MS) { 540 if (!updateDataRatCellIdentityBandwidth()) { 541 updateTxRxBandwidthFilterSendToDataConnection(); 542 } 543 } 544 } 545 makeRequestModemActivity()546 private void makeRequestModemActivity() { 547 mLastModemPollTimeMs = mTelephonyFacade.getElapsedSinceBootMillis(); 548 // TODO: add CountDown in case that onResult/OnError() never happen 549 mTelephonyManager.requestModemActivityInfo(Runnable::run, mOutcomeReceiver); 550 } 551 handleModemActivityReturned(ModemActivityInfo result)552 private void handleModemActivityReturned(ModemActivityInfo result) { 553 updateBandwidthTxRxSamples(result); 554 updateTxRxBandwidthFilterSendToDataConnection(); 555 mLastModemActivityInfo = result; 556 // Update for next poll 557 resetByteDeltaAcc(); 558 } 559 resetByteDeltaAcc()560 private void resetByteDeltaAcc() { 561 mTxBytesDeltaAcc = 0; 562 mRxBytesDeltaAcc = 0; 563 } 564 invalidateTxRxSamples()565 private void invalidateTxRxSamples() { 566 mTxState.mBwSampleValid = false; 567 mRxState.mBwSampleValid = false; 568 } 569 updateBandwidthTxRxSamples(ModemActivityInfo modemActivityInfo)570 private void updateBandwidthTxRxSamples(ModemActivityInfo modemActivityInfo) { 571 if (mLastModemActivityInfo == null || modemActivityInfo == null 572 || mNetworkCapabilities == null || hasRecentDataRegStatePlmnOrRatChange()) { 573 return; 574 } 575 576 long lastTimeMs = mLastModemActivityInfo.getTimestampMillis(); 577 long currTimeMs = modemActivityInfo.getTimestampMillis(); 578 long timeDeltaMs = currTimeMs - lastTimeMs; 579 580 if (timeDeltaMs > MODEM_POLL_TIME_DELTA_MAX_MS || timeDeltaMs <= 0) { 581 return; 582 } 583 ModemActivityInfo deltaInfo = mLastModemActivityInfo.getDelta(modemActivityInfo); 584 long txTimeDeltaMs = getModemTxTimeMs(deltaInfo); 585 long rxTimeDeltaMs = deltaInfo.getReceiveTimeMillis(); 586 587 // Check if txTimeDeltaMs / rxTimeDeltaMs > TX_OVER_RX_TIME_RATIO_THRESHOLD 588 boolean isTxTimeOverRxTimeRatioLarge = (txTimeDeltaMs * TX_OVER_RX_TIME_RATIO_THRESHOLD_DEN 589 > rxTimeDeltaMs * TX_OVER_RX_TIME_RATIO_THRESHOLD_NUM); 590 long rxTimeBwEstMs = isTxTimeOverRxTimeRatioLarge 591 ? (txTimeDeltaMs + rxTimeDeltaMs) : rxTimeDeltaMs; 592 593 mTxState.updateBandwidthSample(mTxBytesDeltaAcc, txTimeDeltaMs); 594 mRxState.updateBandwidthSample(mRxBytesDeltaAcc, rxTimeBwEstMs); 595 596 int reportedTxTputKbps = mNetworkCapabilities.getLinkUpstreamBandwidthKbps(); 597 int reportedRxTputKbps = mNetworkCapabilities.getLinkDownstreamBandwidthKbps(); 598 599 StringBuilder sb = new StringBuilder(); 600 logd(sb.append("UpdateBwSample") 601 .append(" dBm ").append(mSignalStrengthDbm) 602 .append(" level ").append(mSignalLevel) 603 .append(" rat ").append(getDataRatName(mDataRat)) 604 .append(" plmn ").append(mPlmn) 605 .append(" tac ").append(mTac) 606 .append(" reportedTxKbps ").append(reportedTxTputKbps) 607 .append(" reportedRxKbps ").append(reportedRxTputKbps) 608 .append(" txMs ").append(txTimeDeltaMs) 609 .append(" rxMs ").append(rxTimeDeltaMs) 610 .append(" txKB ").append(mTxBytesDeltaAcc / 1024) 611 .append(" rxKB ").append(mRxBytesDeltaAcc / 1024) 612 .append(" txKBThr ").append(mTxState.mByteDeltaAccThr / 1024) 613 .append(" rxKBThr ").append(mRxState.mByteDeltaAccThr / 1024) 614 .toString()); 615 } 616 hasRecentDataRegStatePlmnOrRatChange()617 private boolean hasRecentDataRegStatePlmnOrRatChange() { 618 if (mLastModemActivityInfo == null) { 619 return false; 620 } 621 return (mLastDrsOrRatChangeTimeMs > mLastModemActivityInfo.getTimestampMillis() 622 || mLastPlmnOrRatChangeTimeMs > mLastModemActivityInfo.getTimestampMillis()); 623 } 624 getModemTxTimeMs(ModemActivityInfo modemActivity)625 private long getModemTxTimeMs(ModemActivityInfo modemActivity) { 626 long txTimeMs = 0; 627 for (int lvl = 0; lvl < ModemActivityInfo.getNumTxPowerLevels(); lvl++) { 628 txTimeMs += modemActivity.getTransmitDurationMillisAtPowerLevel(lvl); 629 } 630 return txTimeMs; 631 } 632 updateTxRxBandwidthFilterSendToDataConnection()633 private void updateTxRxBandwidthFilterSendToDataConnection() { 634 mFilterUpdateTimeMs = mTelephonyFacade.getElapsedSinceBootMillis(); 635 mTxState.updateBandwidthFilter(); 636 mRxState.updateBandwidthFilter(); 637 638 boolean isNetworkChanged = mTxState.hasLargeBwChange() 639 || mRxState.hasLargeBwChange() 640 || mBandwidthUpdateDataRat != mDataRat 641 || mBandwidthUpdateSignalLevel != mSignalLevel 642 || !mBandwidthUpdatePlmn.equals(mPlmn); 643 if (isValidNetwork() && isNetworkChanged) { 644 mTxState.mLastReportedBwKbps = mTxState.mAvgUsedKbps < 0 ? -1 : mTxState.mFilterKbps; 645 mRxState.mLastReportedBwKbps = mRxState.mAvgUsedKbps < 0 ? -1 : mRxState.mFilterKbps; 646 sendLinkBandwidthToDataConnection( 647 mTxState.mLastReportedBwKbps, 648 mRxState.mLastReportedBwKbps); 649 } 650 mBandwidthUpdateSignalDbm = mSignalStrengthDbm; 651 mBandwidthUpdateSignalLevel = mSignalLevel; 652 mBandwidthUpdateDataRat = mDataRat; 653 mBandwidthUpdatePlmn = mPlmn; 654 655 mTxState.calculateError(); 656 mRxState.calculateError(); 657 } 658 659 private boolean isValidNetwork() { 660 return !mPlmn.equals(UNKNOWN_PLMN) && mDataRat != TelephonyManager.NETWORK_TYPE_UNKNOWN; 661 } 662 663 private class BandwidthState { 664 private final int mLink; 665 int mFilterKbps; 666 int mByteDeltaAccThr = BYTE_DELTA_THRESHOLD_KB[0][0]; 667 int mAvgUsedKbps; 668 int mBwSampleKbps; 669 boolean mBwSampleValid; 670 long mBwSampleValidTimeMs; 671 int mStaticBwKbps; 672 int mLastReportedBwKbps; 673 674 BandwidthState(int link) { 675 mLink = link; 676 } 677 678 private void updateBandwidthSample(long bytesDelta, long timeDeltaMs) { 679 updateByteCountThr(); 680 if (bytesDelta < mByteDeltaAccThr) { 681 return; 682 } 683 if (timeDeltaMs < TX_RX_TIME_MIN_MS) { 684 return; 685 } 686 long linkBandwidthLongKbps = bytesDelta * 8 / timeDeltaMs * 1000 / 1024; 687 if (linkBandwidthLongKbps > (long) mStaticBwKbps * MAX_BW_TO_STATIC_BW_RATIO 688 || linkBandwidthLongKbps < 0) { 689 return; 690 } 691 int linkBandwidthKbps = (int) linkBandwidthLongKbps; 692 mBwSampleValid = linkBandwidthKbps > 0; 693 mBwSampleKbps = linkBandwidthKbps; 694 695 String dataRatName = getDataRatName(mDataRat); 696 NetworkBandwidth network = lookupNetwork(mPlmn, dataRatName); 697 // Update per RAT stats of all TAC 698 network.update(linkBandwidthKbps, mLink, mSignalLevel); 699 700 // Update per TAC stats 701 network = lookupNetwork(mPlmn, mTac, dataRatName); 702 network.update(linkBandwidthKbps, mLink, mSignalLevel); 703 } 704 705 private void updateBandwidthFilter() { 706 int avgKbps = getAvgLinkBandwidthKbps(); 707 // Feed the filter with the long term avg if there is no valid BW sample so that filter 708 // will gradually converge the long term avg. 709 int filterInKbps = mBwSampleValid ? mBwSampleKbps : avgKbps; 710 711 long currTimeMs = mTelephonyFacade.getElapsedSinceBootMillis(); 712 int timeDeltaSec = (int) ((currTimeMs - mBwSampleValidTimeMs) / 1000); 713 714 // If the operation condition changes significantly since the last update 715 // or the sample has higher BW, use a faster filter. Otherwise, use a slow filter 716 int timeConstantSec; 717 if (Math.abs(mBandwidthUpdateSignalDbm - mSignalStrengthDbm) > RSSI_DELTA_THRESHOLD_DB 718 || !mBandwidthUpdatePlmn.equals(mPlmn) 719 || mBandwidthUpdateDataRat != mDataRat 720 || (mBwSampleValid && mBwSampleKbps > avgKbps)) { 721 timeConstantSec = TIME_CONSTANT_SMALL_SEC; 722 } else { 723 timeConstantSec = TIME_CONSTANT_LARGE_SEC; 724 } 725 // Update timestamp for next iteration 726 if (mBwSampleValid) { 727 mBwSampleValidTimeMs = currTimeMs; 728 } 729 730 if (filterInKbps == mFilterKbps) { 731 return; 732 } 733 734 int alpha = timeDeltaSec > LARGE_TIME_DECAY_RATIO * timeConstantSec ? 0 735 : (int) (FILTER_SCALE * Math.exp(-1.0 * timeDeltaSec / timeConstantSec)); 736 if (alpha == 0) { 737 mFilterKbps = filterInKbps; 738 return; 739 } 740 long filterOutKbps = (long) mFilterKbps * alpha 741 + (long) filterInKbps * FILTER_SCALE - (long) filterInKbps * alpha; 742 filterOutKbps = filterOutKbps / FILTER_SCALE; 743 mFilterKbps = (int) Math.min(filterOutKbps, Integer.MAX_VALUE); 744 745 StringBuilder sb = new StringBuilder(); 746 logv(sb.append(mLink) 747 .append(" lastSampleWeight=").append(alpha) 748 .append("/").append(FILTER_SCALE) 749 .append(" filterInKbps=").append(filterInKbps) 750 .append(" avgKbps=").append(avgKbps) 751 .append(" filterOutKbps=").append(mFilterKbps) 752 .toString()); 753 } 754 getAvgUsedLinkBandwidthKbps()755 private int getAvgUsedLinkBandwidthKbps() { 756 // Check if current TAC/RAT/level has enough stats 757 String dataRatName = getDataRatName(mDataRat); 758 NetworkBandwidth network = lookupNetwork(mPlmn, mTac, dataRatName); 759 int count = network.getCount(mLink, mSignalLevel); 760 if (count >= BW_STATS_COUNT_THRESHOLD) { 761 return (int) (network.getValue(mLink, mSignalLevel) / count); 762 } 763 764 // Check if current RAT/level has enough stats 765 network = lookupNetwork(mPlmn, dataRatName); 766 count = network.getCount(mLink, mSignalLevel); 767 if (count >= BW_STATS_COUNT_THRESHOLD) { 768 return (int) (network.getValue(mLink, mSignalLevel) / count); 769 } 770 return -1; 771 } 772 getAvgUsedBandwidthAdjacentThreeLevelKbps()773 private int getAvgUsedBandwidthAdjacentThreeLevelKbps() { 774 String dataRatName = getDataRatName(mDataRat); 775 NetworkBandwidth network = lookupNetwork(mPlmn, dataRatName); 776 777 int bandwidthAtLow = getAvgUsedBandwidthAtLevel(network, mSignalLevel - 1); 778 int bandwidthAtHigh = getAvgUsedBandwidthAtLevel(network, mSignalLevel + 1); 779 if (bandwidthAtLow > 0 && bandwidthAtHigh > 0) { 780 return (bandwidthAtLow + bandwidthAtHigh) / 2; 781 } 782 783 int count = 0; 784 long value = 0; 785 for (int i = -1; i <= 1; i++) { 786 int currLevel = mSignalLevel + i; 787 if (currLevel < 0 || currLevel >= NUM_SIGNAL_LEVEL) { 788 continue; 789 } 790 count += network.getCount(mLink, currLevel); 791 value += network.getValue(mLink, currLevel); 792 } 793 794 if (count >= BW_STATS_COUNT_THRESHOLD) { 795 return (int) (value / count); 796 } 797 return -1; 798 } 799 getAvgUsedBandwidthAtLevel(NetworkBandwidth network, int signalLevel)800 private int getAvgUsedBandwidthAtLevel(NetworkBandwidth network, 801 int signalLevel) { 802 if (signalLevel < 0 || signalLevel >= NUM_SIGNAL_LEVEL) { 803 return -1; 804 } 805 int count = network.getCount(mLink, signalLevel); 806 if (count >= BW_STATS_COUNT_THRESHOLD) { 807 return (int) (network.getValue(mLink, signalLevel) / count); 808 } 809 return -1; 810 } 811 getCurrentCount()812 private int getCurrentCount() { 813 String dataRatName = getDataRatName(mDataRat); 814 NetworkBandwidth network = lookupNetwork(mPlmn, dataRatName); 815 return network.getCount(mLink, mSignalLevel); 816 } 817 818 /** get a long term avg value (PLMN/RAT/TAC/level dependent) or static value */ getAvgLinkBandwidthKbps()819 private int getAvgLinkBandwidthKbps() { 820 mAvgUsedKbps = getAvgUsedLinkBandwidthKbps(); 821 if (mAvgUsedKbps > 0) { 822 return mAvgUsedKbps; 823 } 824 mAvgUsedKbps = getAvgUsedBandwidthAdjacentThreeLevelKbps(); 825 if (mAvgUsedKbps > 0) { 826 return mAvgUsedKbps; 827 } 828 // Fall back to static value 829 return mStaticBwKbps; 830 } 831 resetBandwidthFilter()832 private void resetBandwidthFilter() { 833 mBwSampleValid = false; 834 mFilterKbps = getAvgLinkBandwidthKbps(); 835 } 836 updateByteCountThr()837 private void updateByteCountThr() { 838 // For high BW RAT cases, use predefined value + threshold derived from avg usage BW 839 if (mStaticBwKbps > HIGH_BANDWIDTH_THRESHOLD_KBPS) { 840 int lowBytes = calculateByteCountThreshold(getAvgUsedLinkBandwidthKbps(), 841 MODEM_POLL_MIN_INTERVAL_MS); 842 // Start with a predefined value 843 mByteDeltaAccThr = BYTE_DELTA_THRESHOLD_KB[mLink][mSignalLevel] * 1024; 844 if (lowBytes > 0) { 845 // Raise the threshold if the avg usage BW is high 846 mByteDeltaAccThr = Math.max(lowBytes, mByteDeltaAccThr); 847 mByteDeltaAccThr = Math.min(mByteDeltaAccThr, 848 BYTE_DELTA_ACC_THRESHOLD_MAX_KB * 1024); 849 } 850 return; 851 } 852 // For low BW RAT cases, derive the threshold from avg BW values 853 mByteDeltaAccThr = calculateByteCountThreshold(mStaticBwKbps, 854 MODEM_POLL_MIN_INTERVAL_MS); 855 856 mByteDeltaAccThr = Math.max(mByteDeltaAccThr, BYTE_DELTA_THRESHOLD_MIN_KB * 1024); 857 // Low BW RAT threshold value should be no more than high BW one. 858 mByteDeltaAccThr = Math.min(mByteDeltaAccThr, BYTE_DELTA_THRESHOLD_KB[mLink][0] * 1024); 859 } 860 861 // Calculate a byte count threshold for the given avg BW and observation window size calculateByteCountThreshold(int avgBwKbps, int durationMs)862 private int calculateByteCountThreshold(int avgBwKbps, int durationMs) { 863 long avgBytes = (long) avgBwKbps / 8 * durationMs; 864 long result = avgBytes * LOW_BW_TO_AVG_BW_RATIO_NUM / LOW_BW_TO_AVG_BW_RATIO_DEN; 865 return (int) Math.min(result, Integer.MAX_VALUE); 866 } 867 hasLargeBwChange()868 public boolean hasLargeBwChange() { 869 int deltaKbps = Math.abs(mLastReportedBwKbps - mFilterKbps); 870 return mAvgUsedKbps > 0 871 && deltaKbps * 100 > BW_UPDATE_THRESHOLD_PERCENT * mLastReportedBwKbps; 872 } 873 calculateError()874 public void calculateError() { 875 if (!mBwSampleValid || getCurrentCount() <= BW_STATS_COUNT_THRESHOLD + 1 876 || mAvgUsedKbps <= 0) { 877 return; 878 } 879 int bwEstExtErrPercent = calculateErrorPercent(mLastReportedBwKbps, mBwSampleKbps); 880 int bwEstAvgErrPercent = calculateErrorPercent(mAvgUsedKbps, mBwSampleKbps); 881 int bwEstIntErrPercent = calculateErrorPercent(mFilterKbps, mBwSampleKbps); 882 int coldStartErrPercent = calculateErrorPercent(mStaticBwKbps, mBwSampleKbps); 883 884 TelephonyMetrics.getInstance().writeBandwidthStats(mLink, mDataRat, getNrMode(mDataRat), 885 mSignalLevel, bwEstExtErrPercent, coldStartErrPercent, mBwSampleKbps); 886 887 StringBuilder sb = new StringBuilder(); 888 logd(sb.append(mLink) 889 .append(" sampleKbps ").append(mBwSampleKbps) 890 .append(" filterKbps ").append(mFilterKbps) 891 .append(" reportKbps ").append(mLastReportedBwKbps) 892 .append(" avgUsedKbps ").append(mAvgUsedKbps) 893 .append(" csKbps ").append(mStaticBwKbps) 894 .append(" intErrPercent ").append(bwEstIntErrPercent) 895 .append(" avgErrPercent ").append(bwEstAvgErrPercent) 896 .append(" extErrPercent ").append(bwEstExtErrPercent) 897 .append(" csErrPercent ").append(coldStartErrPercent) 898 .toString()); 899 } 900 calculateErrorPercent(int inKbps, int bwSampleKbps)901 private int calculateErrorPercent(int inKbps, int bwSampleKbps) { 902 long errorPercent = 100L * (inKbps - bwSampleKbps) / bwSampleKbps; 903 return (int) Math.max(-MAX_ERROR_PERCENT, Math.min(errorPercent, MAX_ERROR_PERCENT)); 904 } 905 } 906 907 /** 908 * Update the byte count threshold. 909 * It should be called whenever the RAT or signal level is changed. 910 * For the RAT with high BW (4G and beyond), use BYTE_DELTA_THRESHOLD_KB table. 911 * For other RATs, derive the threshold based on the static BW values. 912 */ updateByteCountThr()913 private void updateByteCountThr() { 914 mTxState.updateByteCountThr(); 915 mRxState.updateByteCountThr(); 916 } 917 918 // Reset BW filter to a long term avg value (PLMN/RAT/TAC dependent) or static BW value. 919 // It should be called whenever PLMN/RAT or static BW value is changed; resetBandwidthFilter()920 private void resetBandwidthFilter() { 921 mTxState.resetBandwidthFilter(); 922 mRxState.resetBandwidthFilter(); 923 } 924 sendLinkBandwidthToDataConnection(int linkBandwidthTxKps, int linkBandwidthRxKps)925 private void sendLinkBandwidthToDataConnection(int linkBandwidthTxKps, int linkBandwidthRxKps) { 926 logv("send to DC tx " + linkBandwidthTxKps + " rx " + linkBandwidthRxKps); 927 mLinkBandwidthEstimatorCallbacks.forEach(callback -> callback.invokeFromExecutor( 928 () -> callback.onBandwidthChanged(linkBandwidthTxKps, linkBandwidthRxKps))); 929 } 930 handleSignalStrengthChanged()931 private void handleSignalStrengthChanged() { 932 SignalStrength signalStrength = mPhone.getSignalStrength(); 933 934 mSignalStrengthDbm = signalStrength.getDbm(); 935 mSignalLevel = signalStrength.getLevel(); 936 updateByteCountThr(); 937 if (updateDataRatCellIdentityBandwidth()) { 938 return; 939 } 940 941 if (Math.abs(mBandwidthUpdateSignalDbm - mSignalStrengthDbm) > RSSI_DELTA_THRESHOLD_DB) { 942 updateTxRxBandwidthFilterSendToDataConnection(); 943 } 944 } 945 registerNrStateFrequencyChange()946 private void registerNrStateFrequencyChange() { 947 mPhone.getServiceStateTracker().registerForNrStateChanged(this, 948 MSG_NR_STATE_CHANGED, null); 949 mPhone.getServiceStateTracker().registerForNrFrequencyChanged(this, 950 MSG_NR_FREQUENCY_CHANGED, null); 951 } 952 953 /** 954 * @return The data activity. 955 */ 956 @DataActivityType getDataActivity()957 public int getDataActivity() { 958 return mDataActivity; 959 } 960 961 /** 962 * Get a string based on current RAT 963 */ getDataRatName(int rat)964 public String getDataRatName(int rat) { 965 return getDataRatName(rat, getNrMode(rat)); 966 } 967 getNrMode(int rat)968 private int getNrMode(int rat) { 969 if (rat == TelephonyManager.NETWORK_TYPE_LTE && isNrNsaConnected()) { 970 return mPhone.getServiceState().getNrFrequencyRange() 971 == ServiceState.FREQUENCY_RANGE_MMWAVE 972 ? NrMode.NR_NSA_MMWAVE : NrMode.NR_NSA; 973 } else if (rat == TelephonyManager.NETWORK_TYPE_NR) { 974 return mPhone.getServiceState().getNrFrequencyRange() 975 == ServiceState.FREQUENCY_RANGE_MMWAVE 976 ? NrMode.NR_SA_MMWAVE : NrMode.NR_SA; 977 } 978 return NrMode.NR_NONE; 979 } 980 981 /** 982 * Get a string based on current RAT and NR operation mode. 983 */ getDataRatName(int rat, int nrMode)984 public static String getDataRatName(int rat, int nrMode) { 985 if (rat == TelephonyManager.NETWORK_TYPE_LTE 986 && (nrMode == NrMode.NR_NSA || nrMode == NrMode.NR_NSA_MMWAVE)) { 987 return nrMode == NrMode.NR_NSA 988 ? DctConstants.RAT_NAME_NR_NSA : DctConstants.RAT_NAME_NR_NSA_MMWAVE; 989 } else if (rat == TelephonyManager.NETWORK_TYPE_NR) { 990 return nrMode == NrMode.NR_SA 991 ? TelephonyManager.getNetworkTypeName(rat) : DctConstants.RAT_NAME_NR_SA_MMWAVE; 992 } 993 return TelephonyManager.getNetworkTypeName(rat); 994 } 995 996 /** 997 * Check if the device is connected to NR 5G Non-Standalone network 998 */ isNrNsaConnected()999 private boolean isNrNsaConnected() { 1000 return mPhone.getServiceState().getNrState() 1001 == NetworkRegistrationInfo.NR_STATE_CONNECTED; 1002 } 1003 1004 // Update avg BW values. 1005 // It should be called whenever the RAT could be changed. 1006 // return true if avg value is changed; updateStaticBwValue(int dataRat)1007 private boolean updateStaticBwValue(int dataRat) { 1008 Pair<Integer, Integer> values = getStaticAvgBw(dataRat); 1009 if (values == null) { 1010 mTxState.mStaticBwKbps = DEFAULT_LINK_BAND_WIDTH_KBPS; 1011 mRxState.mStaticBwKbps = DEFAULT_LINK_BAND_WIDTH_KBPS; 1012 return true; 1013 } 1014 if (mTxState.mStaticBwKbps != values.second 1015 || mRxState.mStaticBwKbps != values.first) { 1016 mTxState.mStaticBwKbps = values.second; 1017 mRxState.mStaticBwKbps = values.first; 1018 return true; 1019 } 1020 return false; 1021 } 1022 1023 /** get per-RAT static bandwidth value */ getStaticAvgBw(int dataRat)1024 public Pair<Integer, Integer> getStaticAvgBw(int dataRat) { 1025 String dataRatName = getDataRatName(dataRat); 1026 Pair<Integer, Integer> values = AVG_BW_PER_RAT_MAP.get(dataRatName); 1027 if (values == null) { 1028 Rlog.e(TAG, dataRatName + " is not found in Avg BW table"); 1029 } 1030 return values; 1031 } 1032 updateStaticBwValueResetFilter()1033 private void updateStaticBwValueResetFilter() { 1034 if (updateStaticBwValue(mDataRat)) { 1035 updateByteCountThr(); 1036 resetBandwidthFilter(); 1037 updateTxRxBandwidthFilterSendToDataConnection(); 1038 } 1039 } 1040 getDataNri()1041 private NetworkRegistrationInfo getDataNri() { 1042 return mPhone.getServiceState().getNetworkRegistrationInfo( 1043 NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN); 1044 } 1045 updateDataRatCellIdentityBandwidth()1046 private boolean updateDataRatCellIdentityBandwidth() { 1047 final ServiceState ss = mPhone.getServiceState(); 1048 final CellIdentity cellIdentity = mPhone.getCurrentCellIdentity(); 1049 1050 boolean hasChanged = false; 1051 String plmn; 1052 1053 // Why does updating the TAC not result in hasChanged == true? 1054 // Legacy behavior is currently being preserved for now, but it might very 1055 // well be incorrect. The TAC is part of the network key. This is very fishy. 1056 mTac = getTac(cellIdentity); 1057 1058 /* ss should always be non-null */ 1059 if (!TextUtils.isEmpty(ss.getOperatorNumeric())) { 1060 plmn = ss.getOperatorNumeric(); 1061 } else if (!TextUtils.isEmpty(cellIdentity.getPlmn())) { 1062 plmn = cellIdentity.getPlmn(); 1063 } else { 1064 plmn = UNKNOWN_PLMN; 1065 } 1066 1067 if (!mPlmn.equals(plmn)) { 1068 hasChanged = true; 1069 mPlmn = plmn; 1070 } 1071 1072 NetworkRegistrationInfo nri = getDataNri(); 1073 if (nri != null) { 1074 int dataRat = nri.getAccessNetworkTechnology(); 1075 if (dataRat != mDataRat) { 1076 hasChanged = true; 1077 mDataRat = dataRat; 1078 updateStaticBwValue(mDataRat); 1079 updateByteCountThr(); 1080 } 1081 } 1082 1083 if (hasChanged) { 1084 resetBandwidthFilter(); 1085 updateTxRxBandwidthFilterSendToDataConnection(); 1086 mLastPlmnOrRatChangeTimeMs = mTelephonyFacade.getElapsedSinceBootMillis(); 1087 } 1088 return hasChanged; 1089 } 1090 getTac(@onNull CellIdentity cellIdentity)1091 private int getTac(@NonNull CellIdentity cellIdentity) { 1092 if (cellIdentity instanceof CellIdentityLte) { 1093 return ((CellIdentityLte) cellIdentity).getTac(); 1094 } 1095 if (cellIdentity instanceof CellIdentityNr) { 1096 return ((CellIdentityNr) cellIdentity).getTac(); 1097 } 1098 if (cellIdentity instanceof CellIdentityWcdma) { 1099 return ((CellIdentityWcdma) cellIdentity).getLac(); 1100 } 1101 if (cellIdentity instanceof CellIdentityTdscdma) { 1102 return ((CellIdentityTdscdma) cellIdentity).getLac(); 1103 } 1104 if (cellIdentity instanceof CellIdentityGsm) { 1105 return ((CellIdentityGsm) cellIdentity).getLac(); 1106 } 1107 return UNKNOWN_TAC; 1108 } 1109 1110 private class TelephonyCallbackImpl extends TelephonyCallback implements 1111 TelephonyCallback.ActiveDataSubscriptionIdListener { 1112 @Override onActiveDataSubscriptionIdChanged(int subId)1113 public void onActiveDataSubscriptionIdChanged(int subId) { 1114 obtainMessage(MSG_ACTIVE_PHONE_CHANGED, subId).sendToTarget(); 1115 } 1116 } 1117 logv(String msg)1118 void logv(String msg) { 1119 if (DBG) Rlog.v(TAG, msg); 1120 } 1121 logd(String msg)1122 void logd(String msg) { 1123 if (DBG) Rlog.d(TAG, msg); 1124 mLocalLog.log(msg); 1125 } 1126 1127 // Map with NetworkKey as the key and NetworkBandwidth as the value. 1128 // NetworkKey is specified by the PLMN, data RAT and TAC of network. 1129 // NetworkBandwidth represents the bandwidth related stats of each network. 1130 private final Map<NetworkKey, NetworkBandwidth> mNetworkMap = new ArrayMap<>(); 1131 1132 private static class NetworkKey { 1133 1134 private final String mPlmn; 1135 private final String mDataRat; 1136 private final int mTac; 1137 NetworkKey(String plmn, int tac, String dataRat)1138 NetworkKey(String plmn, int tac, String dataRat) { 1139 mPlmn = plmn; 1140 mTac = tac; 1141 mDataRat = dataRat; 1142 } 1143 @Override equals(@ullable Object o)1144 public boolean equals(@Nullable Object o) { 1145 if (!(o instanceof NetworkKey that) || hashCode() != o.hashCode()) { 1146 return false; 1147 } 1148 1149 if (this == o) { 1150 return true; 1151 } 1152 1153 return mPlmn.equals(that.mPlmn) 1154 && mTac == that.mTac 1155 && mDataRat.equals(that.mDataRat); 1156 } 1157 1158 @Override hashCode()1159 public int hashCode() { 1160 return Objects.hash(mPlmn, mDataRat, mTac); 1161 } 1162 @Override toString()1163 public String toString() { 1164 return "Plmn" + mPlmn + "Rat" + mDataRat + "Tac" + mTac; 1165 } 1166 } 1167 1168 @NonNull lookupNetwork(@onNull String plmn, String dataRat)1169 private NetworkBandwidth lookupNetwork(@NonNull String plmn, String dataRat) { 1170 return lookupNetwork(plmn, UNKNOWN_TAC, dataRat); 1171 } 1172 1173 /** Look up NetworkBandwidth and create a new one if it doesn't exist */ 1174 @VisibleForTesting 1175 @NonNull lookupNetwork(@onNull String plmn, int tac, String dataRat)1176 public NetworkBandwidth lookupNetwork(@NonNull String plmn, int tac, String dataRat) { 1177 if (dataRat.equals( 1178 TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_UNKNOWN))) { 1179 return mPlaceholderNetwork; 1180 } 1181 NetworkKey key = new NetworkKey(plmn, tac, dataRat); 1182 NetworkBandwidth ans = mNetworkMap.get(key); 1183 if (ans == null) { 1184 ans = new NetworkBandwidth(key.toString()); 1185 mNetworkMap.put(key, ans); 1186 } 1187 return ans; 1188 } 1189 1190 /** A class holding link bandwidth related stats */ 1191 @VisibleForTesting 1192 public class NetworkBandwidth { 1193 1194 private final String mKey; 1195 NetworkBandwidth(String key)1196 NetworkBandwidth(String key) { 1197 mKey = key; 1198 } 1199 1200 /** Update link bandwidth stats */ update(long value, int link, int level)1201 public void update(long value, int link, int level) { 1202 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences( 1203 mPhone.getContext()); 1204 String valueKey = getValueKey(link, level); 1205 String countKey = getCountKey(link, level); 1206 SharedPreferences.Editor editor = sp.edit(); 1207 long currValue = sp.getLong(valueKey, 0); 1208 int currCount = sp.getInt(countKey, 0); 1209 editor.putLong(valueKey, currValue + value); 1210 editor.putInt(countKey, currCount + 1); 1211 editor.apply(); 1212 } 1213 getValueKey(int link, int level)1214 private String getValueKey(int link, int level) { 1215 return getDataKey(link, level) + "Data"; 1216 } 1217 getCountKey(int link, int level)1218 private String getCountKey(int link, int level) { 1219 return getDataKey(link, level) + "Count"; 1220 } 1221 getDataKey(int link, int level)1222 private String getDataKey(int link, int level) { 1223 return mKey + "Link" + link + "Level" + level; 1224 } 1225 1226 /** Get the accumulated bandwidth value */ getValue(int link, int level)1227 public long getValue(int link, int level) { 1228 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences( 1229 mPhone.getContext()); 1230 String valueKey = getValueKey(link, level); 1231 return sp.getLong(valueKey, 0); 1232 } 1233 1234 /** Get the accumulated bandwidth count */ getCount(int link, int level)1235 public int getCount(int link, int level) { 1236 SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences( 1237 mPhone.getContext()); 1238 String countKey = getCountKey(link, level); 1239 return sp.getInt(countKey, 0); 1240 } 1241 1242 @Override toString()1243 public String toString() { 1244 StringBuilder sb = new StringBuilder(); 1245 sb.append(mKey); 1246 sb.append("\n"); 1247 for (int link = 0; link < NUM_LINK_DIRECTION; link++) { 1248 sb.append((link == 0 ? "tx" : "rx")); 1249 sb.append("\n avgKbps"); 1250 for (int level = 0; level < NUM_SIGNAL_LEVEL; level++) { 1251 int count = getCount(link, level); 1252 int avgKbps = count == 0 ? 0 : (int) (getValue(link, level) / count); 1253 sb.append(" ").append(avgKbps); 1254 } 1255 sb.append("\n count"); 1256 for (int level = 0; level < NUM_SIGNAL_LEVEL; level++) { 1257 int count = getCount(link, level); 1258 sb.append(" ").append(count); 1259 } 1260 sb.append("\n"); 1261 } 1262 return sb.toString(); 1263 } 1264 } 1265 1266 /** 1267 * Dump the internal state and local logs 1268 */ dump(FileDescriptor fd, PrintWriter printWriter, String[] args)1269 public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { 1270 IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); 1271 pw.increaseIndent(); 1272 pw.println("current PLMN " + mPlmn + " TAC " + mTac + " RAT " + getDataRatName(mDataRat)); 1273 pw.println("all networks visited since device boot"); 1274 for (NetworkBandwidth network : mNetworkMap.values()) { 1275 pw.println(network.toString()); 1276 } 1277 1278 try { 1279 mLocalLog.dump(fd, pw, args); 1280 } catch (Exception e) { 1281 e.printStackTrace(); 1282 } 1283 pw.decreaseIndent(); 1284 pw.println(); 1285 pw.flush(); 1286 } 1287 } 1288