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