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