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