Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 742b9521 authored by Kai Shi's avatar Kai Shi Committed by Automerger Merge Worker
Browse files

Merge "Add Bandwidth Estimator metrics" into sc-dev am: 46c1157a

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/opt/telephony/+/13958129

Change-Id: I5fcfef4017ddf87d22e39ad9d074ba9d37e65a3d
parents b46578ed 46c1157a
Loading
Loading
Loading
Loading
+48 −0
Original line number Diff line number Diff line
@@ -53,6 +53,9 @@ message TelephonyLog {

  // The last active subscription info for each slot.
  repeated ActiveSubscriptionInfo last_active_subscription_info = 10;

  // Bandwidth estimator stats
  optional BandwidthEstimatorStats bandwidth_estimator_stats = 11;
}

// The time information
@@ -418,6 +421,20 @@ enum RadioAccessTechnology {
  RAT_NR = 20;
}

// NR (5G) operation mode
enum NrMode {
  // The device is not in a NR network.
  NR_NONE = 1;
  // The device is in a NR non-standalone network at non-MMWAVE frequencies.
  NR_NSA = 2;
  // The device is in a NR non-standalone network at MMWAVE frequencies.
  NR_NSA_MMWAVE = 3;
  // The device is in a NR standalone network at non-MMWAVE frequencies.
  NR_SA = 4;
  // The device is in a NR standalone network at MMWAVE frequencies.
  NR_SA_MMWAVE = 5;
}

// The information about IMS errors
// https://cs.corp.google.com/#android/frameworks/base/telephony/java/com/android/ims/ImsReasonInfo.java
message ImsReasonInfo {
@@ -2680,3 +2697,34 @@ message ModemPowerStats {
  // Actual monitored rail energy consumed by modem (mAh)
  optional double monitored_rail_energy_consumed_mah = 15;
}

// Bandwidth estimator stats
message BandwidthEstimatorStats {
  // Bandwidth stats of each level
  message PerLevel {
    optional uint32 signal_level = 1;
    // Accumulated bandwidth sample count
    optional uint32 count = 2;
    // Average end-to-end bandwidth in kbps
    optional uint32 avg_bw_kbps = 3;
    // Normalized root mean square error (NRMSE) of static BW values in percent
    optional uint32 static_bw_nrmse_percent = 4;
    // Normalized root mean square error (NRMSE) of end-to-end BW estimation in percent
    optional uint32 bw_est_nrmse_percent = 5;
  }

  // Bandwidth stats of each RAT
  message PerRat {
    // radio access technology
    optional RadioAccessTechnology rat = 1;
    // NR (5g) operation mode
    optional NrMode nr_mode = 2;
    // bandwidth stats of signal levels
    repeated PerLevel per_level = 3;
  }

  // Tx Stats of visited RATs
  repeated PerRat per_rat_tx = 1;
  // Rx Stats of visited RATs
  repeated PerRat per_rat_rx = 2;
}
+54 −72
Original line number Diff line number Diff line
@@ -55,6 +55,8 @@ import com.android.internal.telephony.DctConstants;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyFacade;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.telephony.nano.TelephonyProto.NrMode;
import com.android.internal.util.IndentingPrintWriter;
import com.android.telephony.Rlog;

@@ -134,15 +136,15 @@ public class LinkBandwidthEstimator extends Handler {
            "HSDPA:4300,620", "HSUPA:4300,1800", "HSPA:4300,1800", "CDMA - EvDo rev. B:1500,550",
            "CDMA - eHRPD:750,48", "HSPA+:13000,3400", "TD_SCDMA:115,115",
            "LTE:30000,15000", "NR_NSA:47000,18000",
            "NR_NSA_MMWAVE:145000,60000", "NR:145000,60000"};
            "NR_NSA_MMWAVE:145000,60000", "NR:145000,60000", "NR_MMWAVE:145000,60000"};
    private static final Map<String, Pair<Integer, Integer>> AVG_BW_PER_RAT_MAP = new ArrayMap<>();

    // To be used in the long term avg, each count needs to be above the following value
    static final int BW_STATS_COUNT_THRESHOLD = 5;
    static final int NUM_SIGNAL_LEVEL = 5;
    static final int LINK_TX = 0;
    static final int LINK_RX = 1;
    private static final int NUM_LINK_DIRECTION = 2;
    public static final int BW_STATS_COUNT_THRESHOLD = 5;
    public static final int NUM_SIGNAL_LEVEL = 5;
    public static final int LINK_TX = 0;
    public static final int LINK_RX = 1;
    public static final int NUM_LINK_DIRECTION = 2;

    private final Phone mPhone;
    private final TelephonyFacade mTelephonyFacade;
@@ -523,53 +525,11 @@ public class LinkBandwidthEstimator extends Handler {
        long mBwSampleValidTimeMs;
        int mStaticBwKbps;
        int mLastReportedBwKbps;
        private final Map<String, EstimationError> mErrorMap = new ArrayMap<>();

        private class EstimationError {
            final String mRatName;
            final long[] mBwEstIntNse = new long[NUM_SIGNAL_LEVEL];
            final long[] mBwEstExtNse = new long[NUM_SIGNAL_LEVEL];
            final long[] mStaticBwNse = new long[NUM_SIGNAL_LEVEL];
            final int[] mCount = new int[NUM_SIGNAL_LEVEL];

            EstimationError(String ratName) {
                mRatName = ratName;
            }

            @Override
            public String toString() {
                StringBuilder sb = new StringBuilder();
                return sb.append(mRatName)
                        .append("\n Internal\n").append(printAvgError(mBwEstIntNse, mCount))
                        .append("\n External\n").append(printAvgError(mBwEstExtNse, mCount))
                        .append("\n StaticBw\n").append(printAvgError(mStaticBwNse, mCount))
                        .toString();
            }

            private String printAvgError(long[] stats, int[] count) {
                StringBuilder sb = new StringBuilder();
                for (int k = 0; k < NUM_SIGNAL_LEVEL; k++) {
                    int avgStat = (count[k] >= BW_STATS_COUNT_THRESHOLD && stats[k] >= 0)
                            ? (int) Math.sqrt(stats[k] / count[k]) : 0;
                    sb.append(" " + avgStat);
                }
                return sb.toString();
            }
        }

        BandwidthState(int link) {
            mLink = link;
        }

        private EstimationError lookupEstimationError(String dataRatName) {
            EstimationError ans = mErrorMap.get(dataRatName);
            if (ans == null) {
                ans = new EstimationError(dataRatName);
                mErrorMap.put(dataRatName, ans);
            }
            return ans;
        }

        private void updateBandwidthSample(long bytesDelta, long timeDeltaMs) {
            updateByteCountThr();
            if (bytesDelta < mByteDeltaAccThr) {
@@ -718,11 +678,11 @@ public class LinkBandwidthEstimator extends Handler {
            int bwEstAvgErrPercent = calculateErrorPercent(mAvgUsedKbps, mBwSampleKbps);
            int bwEstIntErrPercent = calculateErrorPercent(mFilterKbps, mBwSampleKbps);
            int coldStartErrPercent = calculateErrorPercent(mStaticBwKbps, mBwSampleKbps);
            EstimationError err = lookupEstimationError(getDataRatName(mDataRat));
            err.mBwEstIntNse[mSignalLevel] += bwEstIntErrPercent * bwEstIntErrPercent;
            err.mBwEstExtNse[mSignalLevel] += bwEstExtErrPercent * bwEstExtErrPercent;
            err.mStaticBwNse[mSignalLevel] += coldStartErrPercent * coldStartErrPercent;
            err.mCount[mSignalLevel]++;

            TelephonyMetrics.getInstance().writeBandwidthStats(mLink, mDataRat, getNrMode(mDataRat),
                    mSignalLevel, bwEstIntErrPercent, bwEstExtErrPercent,
                    coldStartErrPercent, mAvgUsedKbps);

            StringBuilder sb = new StringBuilder();
            logd(sb.append(mLink)
                    .append(" sampKbps ").append(mBwSampleKbps)
@@ -798,15 +758,49 @@ public class LinkBandwidthEstimator extends Handler {
                MSG_NR_FREQUENCY_CHANGED, null);
    }

    private String getDataRatName(int rat) {
        if (rat == TelephonyManager.NETWORK_TYPE_LTE && isNRConnected()) {
    /**
     * Get a string based on current RAT
     */
    public String getDataRatName(int rat) {
        return getDataRatName(rat, getNrMode(rat));
    }

    private int getNrMode(int rat) {
        if (rat == TelephonyManager.NETWORK_TYPE_LTE && isNrNsaConnected()) {
            return mPhone.getServiceState().getNrFrequencyRange()
                    == ServiceState.FREQUENCY_RANGE_MMWAVE
                    ? NrMode.NR_NSA_MMWAVE : NrMode.NR_NSA;
        } else if (rat == TelephonyManager.NETWORK_TYPE_NR) {
            return mPhone.getServiceState().getNrFrequencyRange()
                    == ServiceState.FREQUENCY_RANGE_MMWAVE
                    ? DctConstants.RAT_NAME_NR_NSA_MMWAVE : DctConstants.RAT_NAME_NR_NSA;
                    ? NrMode.NR_SA_MMWAVE : NrMode.NR_SA;
        }
        return NrMode.NR_NONE;
    }

    /**
     * Get a string based on current RAT and NR operation mode.
     */
    public static String getDataRatName(int rat, int nrMode) {
        if (rat == TelephonyManager.NETWORK_TYPE_LTE
                && (nrMode == NrMode.NR_NSA || nrMode == NrMode.NR_NSA_MMWAVE)) {
            return nrMode == NrMode.NR_NSA
                    ? DctConstants.RAT_NAME_NR_NSA : DctConstants.RAT_NAME_NR_NSA_MMWAVE;
        } else if (rat == TelephonyManager.NETWORK_TYPE_NR) {
            return nrMode == NrMode.NR_SA
                    ? TelephonyManager.getNetworkTypeName(rat) : DctConstants.RAT_NAME_NR_SA_MMWAVE;
        }
        return TelephonyManager.getNetworkTypeName(rat);
    }

    /**
     * Check if the device is connected to NR 5G Non-Standalone network
     */
    private boolean isNrNsaConnected() {
        return mPhone.getServiceState().getNrState()
                == NetworkRegistrationInfo.NR_STATE_CONNECTED;
    }

    // Update avg BW values.
    // It should be called whenever the RAT could be changed.
    // return true if avg value is changed;
@@ -844,10 +838,9 @@ public class LinkBandwidthEstimator extends Handler {
        }
    }

    /** Check if the device is connected to NR 5G Non-Standalone network. */
    private boolean isNRConnected() {
        return mPhone.getServiceState().getNrState()
                == NetworkRegistrationInfo.NR_STATE_CONNECTED;
    private NetworkRegistrationInfo getDataNri() {
        return  mPhone.getServiceState().getNetworkRegistrationInfo(
                NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
    }

    private void updateDataRatCellIdentity() {
@@ -870,8 +863,7 @@ public class LinkBandwidthEstimator extends Handler {
        }

        boolean updatedRat = false;
        NetworkRegistrationInfo nri = mPhone.getServiceState().getNetworkRegistrationInfo(
                NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
        NetworkRegistrationInfo nri = getDataNri();
        if (nri != null) {
            int dataRat = nri.getAccessNetworkTechnology();
            if (dataRat != mDataRat) {
@@ -1082,16 +1074,6 @@ public class LinkBandwidthEstimator extends Handler {
            pw.println(network.toString());
        }

        pw.println("Tx NRMSE");
        for (BandwidthState.EstimationError err : mTxState.mErrorMap.values()) {
            pw.println(err.toString());
        }

        pw.println("Rx NRMSE");
        for (BandwidthState.EstimationError err : mRxState.mErrorMap.values()) {
            pw.println(err.toString());
        }

        try {
            mLocalLog.dump(fd, pw, args);
        } catch (Exception e) {
+151 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import static com.android.internal.telephony.RILConstants.RIL_REQUEST_IMS_SEND_S
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SEND_SMS_EXPECT_MORE;
import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SETUP_DATA_CALL;
import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.NUM_SIGNAL_LEVEL;
import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IP;
import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV4V6;
import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV6;
@@ -69,6 +70,7 @@ import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.telephony.ims.stub.ImsSmsImplBase;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Base64;
import android.util.SparseArray;

@@ -82,10 +84,12 @@ import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.SmsController;
import com.android.internal.telephony.SmsResponse;
import com.android.internal.telephony.UUSInfo;
import com.android.internal.telephony.dataconnection.LinkBandwidthEstimator;
import com.android.internal.telephony.emergency.EmergencyNumberTracker;
import com.android.internal.telephony.imsphone.ImsPhoneCall;
import com.android.internal.telephony.nano.TelephonyProto;
import com.android.internal.telephony.nano.TelephonyProto.ActiveSubscriptionInfo;
import com.android.internal.telephony.nano.TelephonyProto.BandwidthEstimatorStats;
import com.android.internal.telephony.nano.TelephonyProto.EmergencyNumberInfo;
import com.android.internal.telephony.nano.TelephonyProto.ImsCapabilities;
import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
@@ -127,6 +131,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;

/**
@@ -230,6 +235,12 @@ public class TelephonyMetrics {
    private final SparseArray<SparseArray<RilDataCall>> mLastRilDataCallEvents =
            new SparseArray<>();

    /**
     * List of Tx and Rx Bandwidth estimation stats maps
     */
    private final List<Map<String, BwEstimationStats>> mBwEstStatsMapList = new ArrayList<>(
            Arrays.asList(new ArrayMap<>(), new ArrayMap<>()));

    /** The start system time of the TelephonyLog in milliseconds*/
    private long mStartSystemTimeMs;

@@ -629,6 +640,20 @@ public class TelephonyMetrics {
                + new DecimalFormat("#.##").format(s.monitoredRailEnergyConsumedMah));
        pw.decreaseIndent();
        pw.println("Hardware Version: " + SystemProperties.get("ro.boot.revision", ""));

        pw.decreaseIndent();
        pw.println("LinkBandwidthEstimator stats:");
        pw.increaseIndent();

        pw.println("Tx");
        for (BwEstimationStats stats : mBwEstStatsMapList.get(0).values()) {
            pw.println(stats.toString());
        }

        pw.println("Rx");
        for (BwEstimationStats stats : mBwEstStatsMapList.get(1).values()) {
            pw.println(stats.toString());
        }
    }

    /**
@@ -649,6 +674,8 @@ public class TelephonyMetrics {
        mTelephonyEvents.clear();
        mCompletedCallSessions.clear();
        mCompletedSmsSessions.clear();
        mBwEstStatsMapList.get(0).clear();
        mBwEstStatsMapList.get(1).clear();

        mTelephonyEventsDropped = false;

@@ -721,6 +748,7 @@ public class TelephonyMetrics {
                        .setDataCalls(dataCalls).build());
            }
        }

    }

    /**
@@ -794,7 +822,7 @@ public class TelephonyMetrics {
            }
        }
        log.lastActiveSubscriptionInfo = activeSubscriptionInfo;

        log.bandwidthEstimatorStats = buildBandwidthEstimatorStats();
        return log;
    }

@@ -2901,4 +2929,126 @@ public class TelephonyMetrics {
                return SimState.SIM_STATE_UNKNOWN;
        }
    }

    /**
     * Write bandwidth estimator stats
     */
    public synchronized void writeBandwidthStats(int link, int rat, int nrMode,
            int signalLevel, int bwEstIntErrPercent,
            int bwEstExtErrPercent, int coldStartErrPercent, int avgUsedKbps) {
        BwEstimationStats stats = lookupEstimationStats(link, rat, nrMode);
        stats.mBwEstIntNse[signalLevel] += bwEstIntErrPercent * bwEstIntErrPercent;
        stats.mBwEstExtNse[signalLevel] += bwEstExtErrPercent * bwEstExtErrPercent;
        stats.mStaticBwNse[signalLevel] += coldStartErrPercent * coldStartErrPercent;
        stats.mAvgBwKbps[signalLevel] = avgUsedKbps;
        stats.mCount[signalLevel]++;
    }

    private BwEstimationStats lookupEstimationStats(int linkIndex, int dataRat, int nrMode) {
        String dataRatName = LinkBandwidthEstimator.getDataRatName(dataRat, nrMode);
        BwEstimationStats ans = mBwEstStatsMapList.get(linkIndex).get(dataRatName);
        if (ans == null) {
            ans = new BwEstimationStats(dataRat, nrMode);
            mBwEstStatsMapList.get(linkIndex).put(dataRatName, ans);
        }
        return ans;
    }

    private BandwidthEstimatorStats buildBandwidthEstimatorStats() {
        BandwidthEstimatorStats stats = new BandwidthEstimatorStats();
        List<BandwidthEstimatorStats.PerRat> ratList;
        ratList = writeBandwidthEstimatorStatsRatList(mBwEstStatsMapList.get(0));
        stats.perRatTx = ratList.toArray(new BandwidthEstimatorStats.PerRat[0]);
        ratList = writeBandwidthEstimatorStatsRatList(mBwEstStatsMapList.get(1));
        stats.perRatRx = ratList.toArray(new BandwidthEstimatorStats.PerRat[0]);
        return stats;
    }

    private List<BandwidthEstimatorStats.PerRat> writeBandwidthEstimatorStatsRatList(
            Map<String, BwEstimationStats> bwEstStatsMap) {
        List<BandwidthEstimatorStats.PerRat> ratList = new ArrayList<>();
        for (BwEstimationStats perRat : bwEstStatsMap.values()) {
            ratList.add(perRat.writeBandwidthStats());
        }
        return ratList;
    }

    private static class BwEstimationStats {
        final int mRadioTechnology;
        final int mNrMode;
        final long[] mBwEstIntNse = new long[NUM_SIGNAL_LEVEL];
        final long[] mBwEstExtNse = new long[NUM_SIGNAL_LEVEL];
        final long[] mStaticBwNse = new long[NUM_SIGNAL_LEVEL];
        final int[] mAvgBwKbps = new int[NUM_SIGNAL_LEVEL];
        final int[] mCount = new int[NUM_SIGNAL_LEVEL];

        BwEstimationStats(int radioTechnology, int nrMode) {
            mRadioTechnology = radioTechnology;
            mNrMode = nrMode;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            return sb.append(LinkBandwidthEstimator.getDataRatName(mRadioTechnology, mNrMode))
                    .append("\n Count\n").append(printValues(mCount))
                    .append("\n AvgKbps\n").append(printValues(mAvgBwKbps))
                    .append("\n Internal NRMSE\n").append(printAvgError(mBwEstIntNse, mCount))
                    .append("\n External NRMSE\n").append(printAvgError(mBwEstExtNse, mCount))
                    .append("\n StaticBw NRMSE\n").append(printAvgError(mStaticBwNse, mCount))
                    .toString();
        }

        private String printValues(int[] values) {
            StringBuilder sb = new StringBuilder();
            for (int k = 0; k < NUM_SIGNAL_LEVEL; k++) {
                sb.append(" " + values[k]);
            }
            return sb.toString();
        }

        private String printAvgError(long[] stats, int[] count) {
            StringBuilder sb = new StringBuilder();
            for (int k = 0; k < NUM_SIGNAL_LEVEL; k++) {
                int avgStat = (count[k] > 0 && stats[k] >= 0)
                        ? (int) Math.sqrt(stats[k] / count[k]) : 0;
                sb.append(" " + avgStat);
            }
            return sb.toString();
        }

        private BandwidthEstimatorStats.PerRat writeBandwidthStats() {
            BandwidthEstimatorStats.PerRat stats = new BandwidthEstimatorStats.PerRat();
            List<BandwidthEstimatorStats.PerLevel> levelList = new ArrayList<>();
            for (int level = 0; level < NUM_SIGNAL_LEVEL; level++) {
                BandwidthEstimatorStats.PerLevel currStats = writeBandwidthStatsPerLevel(level);
                if (currStats != null) {
                    levelList.add(currStats);
                }
            }
            stats.rat = mRadioTechnology;
            stats.perLevel = levelList.toArray(new BandwidthEstimatorStats.PerLevel[0]);
            stats.nrMode = mNrMode;
            return stats;
        }

        private BandwidthEstimatorStats.PerLevel writeBandwidthStatsPerLevel(int level) {
            int count = mCount[level];
            if (count > 0) {
                BandwidthEstimatorStats.PerLevel stats = new BandwidthEstimatorStats.PerLevel();
                stats.signalLevel = level;
                stats.count = count;
                stats.avgBwKbps = mAvgBwKbps[level];
                stats.staticBwNrmsePercent = calculateNrmse(mStaticBwNse[level], count);
                stats.bwEstNrmsePercent = calculateNrmse(mBwEstExtNse[level], count);
                return stats;
            }
            return null;
        }

        private int calculateNrmse(long nse, int count) {
            return (count > 0  && nse >= 0) ? (int) Math.sqrt(nse / count) : 0;
        }
    }

}
+35 −0
Original line number Diff line number Diff line
@@ -121,6 +121,11 @@ public class LinkBandwidthEstimatorTest extends TelephonyTest {
        when(mTelephonyFacade.getMobileRxBytes()).thenReturn(mRxBytes);
    }

    private void subtractRxBytes(long rxBytes) {
        mRxBytes -= rxBytes;
        when(mTelephonyFacade.getMobileRxBytes()).thenReturn(mRxBytes);
    }

    @After
    public void tearDown() throws Exception {
        super.tearDown();
@@ -340,6 +345,10 @@ public class LinkBandwidthEstimatorTest extends TelephonyTest {
        assertEquals(47000, (int) values.first);
        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_NR);
        assertEquals(145_000, (int) values.first);
        when(mServiceState.getNrFrequencyRange()).thenReturn(ServiceState.FREQUENCY_RANGE_MMWAVE);
        values = mLBE.getStaticAvgBw(TelephonyManager.NETWORK_TYPE_NR);
        assertEquals("NR_MMWAVE", mLBE.getDataRatName(TelephonyManager.NETWORK_TYPE_NR));
        assertEquals(145_000, (int) values.first);
    }

    @Test
@@ -386,6 +395,32 @@ public class LinkBandwidthEstimatorTest extends TelephonyTest {
        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(19_597));
    }

    @Test
    public void testAbnormalTrafficCountTriggerLessBwUpdate() throws Exception {
        mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
        processAllMessages();

        for (int i = 0; i < BW_STATS_COUNT_THRESHOLD + 2; i++) {
            if (i == 1) {
                addTxBytes(10_000L);
                subtractRxBytes(500_000L);
            } else {
                addTxBytes(10_000L);
                addRxBytes(500_000L);
            }
            addElapsedTime(5_100);
            moveTimeForward(5_100);
            processAllMessages();
            mLBE.obtainMessage(MSG_MODEM_ACTIVITY_RETURNED, new ModemActivityInfo(
                    i * 5_100L, 0, 0, TX_TIME_2_MS, i * RX_TIME_2_MS)).sendToTarget();
            processAllMessages();
        }

        verify(mTelephonyManager, times(BW_STATS_COUNT_THRESHOLD))
                .requestModemActivityInfo(any(), any());
        verify(mDataConnection, times(1)).updateLinkBandwidthEstimation(eq(-1), eq(-1));
    }

    @Test
    public void testUseCurrentTacStatsWithEnoughData() throws Exception {
        mLBE.obtainMessage(MSG_SCREEN_STATE_CHANGED, true).sendToTarget();
+39 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_D
import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY;
import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME;
import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS;
import static com.android.internal.telephony.dataconnection.LinkBandwidthEstimator.NUM_SIGNAL_LEVEL;
import static com.android.internal.telephony.nano.TelephonyProto.PdpType.PDP_TYPE_IPV4V6;

import static org.junit.Assert.assertArrayEquals;
@@ -59,8 +60,11 @@ import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.SmsResponse;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.UUSInfo;
import com.android.internal.telephony.dataconnection.LinkBandwidthEstimator;
import com.android.internal.telephony.nano.TelephonyProto;
import com.android.internal.telephony.nano.TelephonyProto.BandwidthEstimatorStats;
import com.android.internal.telephony.nano.TelephonyProto.ImsConnectionState;
import com.android.internal.telephony.nano.TelephonyProto.NrMode;
import com.android.internal.telephony.nano.TelephonyProto.RadioAccessTechnology;
import com.android.internal.telephony.nano.TelephonyProto.SmsSession;
import com.android.internal.telephony.nano.TelephonyProto.TelephonyCallSession;
@@ -872,4 +876,39 @@ public class TelephonyMetricsTest extends TelephonyTest {
        assertEquals(false, event.imsCapabilities.videoOverLte);
        assertEquals(false, event.imsCapabilities.utOverLte);
    }


    // Test write Bandwidth Stats
    @Test
    @SmallTest
    public void testWriteBandwidthStats() throws Exception {
        addBandwidthStats(LinkBandwidthEstimator.LINK_TX, TelephonyManager.NETWORK_TYPE_LTE,
                NrMode.NR_NSA_MMWAVE);
        addBandwidthStats(LinkBandwidthEstimator.LINK_RX, TelephonyManager.NETWORK_TYPE_LTE,
                NrMode.NR_NSA_MMWAVE);
        addBandwidthStats(LinkBandwidthEstimator.LINK_RX, TelephonyManager.NETWORK_TYPE_NR,
                NrMode.NR_SA_MMWAVE);
        TelephonyLog log = buildProto();

        BandwidthEstimatorStats stats = log.bandwidthEstimatorStats;
        assertEquals(1, stats.perRatTx.length);
        assertEquals(2, stats.perRatRx.length);
        assertEquals(TelephonyManager.NETWORK_TYPE_LTE, stats.perRatTx[0].rat);
        assertEquals(NrMode.NR_NSA_MMWAVE, stats.perRatTx[0].nrMode);
        assertEquals(NUM_SIGNAL_LEVEL - 1, stats.perRatTx[0].perLevel.length);
        assertEquals(2, stats.perRatTx[0].perLevel[0].count);
        assertEquals(0, stats.perRatTx[0].perLevel[0].signalLevel);
        assertEquals(500_000, stats.perRatTx[0].perLevel[0].avgBwKbps);
        assertEquals(41, stats.perRatTx[0].perLevel[0].staticBwNrmsePercent);
        assertEquals(31, stats.perRatTx[0].perLevel[0].bwEstNrmsePercent);
    }

    private void addBandwidthStats(int link, int dataRat, int nrMode) {
        for (int i = 0; i < NUM_SIGNAL_LEVEL - 1; i++) {
            mMetrics.writeBandwidthStats(link, dataRat, nrMode,
                    i, 10, 20, 30, 300_000);
            mMetrics.writeBandwidthStats(link, dataRat, nrMode,
                    i, 30, 40, 50, 500_000);
        }
    }
}