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