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