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