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