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

Commit af0f96e2 authored by Kai Shi's avatar Kai Shi
Browse files

Add Bandwidth Estimator metrics

Add Bandwidth estimator metrics. Separate NR SA MMWAVE from NR SA
non-MMWAVE in bandwidth estimation.

Bug: 176814680
Test: manual
Test: atest FrameworksTelephonyTests:com.android.internal.telephony
Change-Id: I77f3f532ee45e872ce6134be23c7da1a8913e061
parent 5a0d2a8e
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);
        }
    }
}