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