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

Commit 6b9f2df3 authored by Yan Yan's avatar Yan Yan
Browse files

VCN: Refactor getPacketLossRatePercentage to return an object

Refactor getPacketLossRatePercentage to return an object instead of
an integer. This is for extending the Packet Loss Detector's ability
to handle inbound sequence number leap

This patch does not include any behavior changes

Bug: 332598276
Test: atest FrameworksVcnTests && atest CtsVcnTestCases
Change-Id: Ied42e581fb331ab0603225865236779f50cc4881
parent 209c1cda
Loading
Loading
Loading
Loading
+97 −11
Original line number Original line Diff line number Diff line
@@ -16,8 +16,10 @@


package com.android.server.vcn.routeselection;
package com.android.server.vcn.routeselection;


import static com.android.internal.annotations.VisibleForTesting.Visibility;
import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;


import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.BroadcastReceiver;
@@ -38,6 +40,10 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.internal.annotations.VisibleForTesting.Visibility;
import com.android.server.vcn.VcnContext;
import com.android.server.vcn.VcnContext;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.BitSet;
import java.util.BitSet;
import java.util.Objects;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeUnit;
@@ -56,8 +62,32 @@ import java.util.concurrent.TimeUnit;
public class IpSecPacketLossDetector extends NetworkMetricMonitor {
public class IpSecPacketLossDetector extends NetworkMetricMonitor {
    private static final String TAG = IpSecPacketLossDetector.class.getSimpleName();
    private static final String TAG = IpSecPacketLossDetector.class.getSimpleName();


    @VisibleForTesting(visibility = Visibility.PRIVATE)
    private static final int PACKET_LOSS_PERCENT_UNAVAILABLE = -1;
    static final int PACKET_LOSS_UNAVALAIBLE = -1;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(
            prefix = {"PACKET_LOSS_"},
            value = {
                PACKET_LOSS_RATE_VALID,
                PACKET_LOSS_RATE_INVALID,
            })
    @Target({ElementType.TYPE_USE})
    private @interface PacketLossResultType {}

    /** Indicates a valid packet loss rate is available */
    private static final int PACKET_LOSS_RATE_VALID = 0;

    /**
     * Indicates that the detector cannot get a valid packet loss rate due to one of the following
     * reasons:
     *
     * <ul>
     *   <li>The replay window did not proceed and thus all packets might have been delivered out of
     *       order
     *   <li>There are unexpected errors
     * </ul>
     */
    private static final int PACKET_LOSS_RATE_INVALID = 1;


    // For VoIP, losses between 5% and 10% of the total packet stream will affect the quality
    // For VoIP, losses between 5% and 10% of the total packet stream will affect the quality
    // significantly (as per "Computer Networking for LANS to WANS: Hardware, Software and
    // significantly (as per "Computer Networking for LANS to WANS: Hardware, Software and
@@ -307,24 +337,24 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
            return;
            return;
        }
        }


        final int packetLossRate =
        final PacketLossCalculationResult calculateResult =
                mPacketLossCalculator.getPacketLossRatePercentage(
                mPacketLossCalculator.getPacketLossRatePercentage(
                        mLastIpSecTransformState, state, getLogPrefix());
                        mLastIpSecTransformState, state, getLogPrefix());


        if (packetLossRate == PACKET_LOSS_UNAVALAIBLE) {
        if (calculateResult.getResultType() == PACKET_LOSS_RATE_INVALID) {
            return;
            return;
        }
        }


        final String logMsg =
        final String logMsg =
                "packetLossRate: "
                "calculateResult: "
                        + packetLossRate
                        + calculateResult
                        + "% in the past "
                        + "% in the past "
                        + (state.getTimestampMillis()
                        + (state.getTimestampMillis()
                                - mLastIpSecTransformState.getTimestampMillis())
                                - mLastIpSecTransformState.getTimestampMillis())
                        + "ms";
                        + "ms";


        mLastIpSecTransformState = state;
        mLastIpSecTransformState = state;
        if (packetLossRate < mPacketLossRatePercentThreshold) {
        if (calculateResult.getPacketLossRatePercent() < mPacketLossRatePercentThreshold) {
            logV(logMsg);
            logV(logMsg);
            onValidationResultReceivedInternal(false /* isFailed */);
            onValidationResultReceivedInternal(false /* isFailed */);
        } else {
        } else {
@@ -343,7 +373,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    @VisibleForTesting(visibility = Visibility.PRIVATE)
    public static class PacketLossCalculator {
    public static class PacketLossCalculator {
        /** Calculate the packet loss rate between two timestamps */
        /** Calculate the packet loss rate between two timestamps */
        public int getPacketLossRatePercentage(
        public PacketLossCalculationResult getPacketLossRatePercentage(
                @NonNull IpSecTransformState oldState,
                @NonNull IpSecTransformState oldState,
                @NonNull IpSecTransformState newState,
                @NonNull IpSecTransformState newState,
                String logPrefix) {
                String logPrefix) {
@@ -359,7 +389,7 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
            if (oldSeqHi == newSeqHi || newSeqHi < replayWindowSize) {
            if (oldSeqHi == newSeqHi || newSeqHi < replayWindowSize) {
                // The replay window did not proceed and all packets might have been delivered out
                // The replay window did not proceed and all packets might have been delivered out
                // of order
                // of order
                return PACKET_LOSS_UNAVALAIBLE;
                return PacketLossCalculationResult.invalid();
            }
            }


            // Get the expected packet count by assuming there is no packet loss. In this case, SA
            // Get the expected packet count by assuming there is no packet loss. In this case, SA
@@ -386,10 +416,11 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
                    || actualPktCntDiff < 0
                    || actualPktCntDiff < 0
                    || actualPktCntDiff > expectedPktCntDiff) {
                    || actualPktCntDiff > expectedPktCntDiff) {
                logWtf(TAG, "Impossible values for expectedPktCntDiff or" + " actualPktCntDiff");
                logWtf(TAG, "Impossible values for expectedPktCntDiff or" + " actualPktCntDiff");
                return PACKET_LOSS_UNAVALAIBLE;
                return PacketLossCalculationResult.invalid();
            }
            }


            return 100 - (int) (actualPktCntDiff * 100 / expectedPktCntDiff);
            final int percent = 100 - (int) (actualPktCntDiff * 100 / expectedPktCntDiff);
            return PacketLossCalculationResult.valid(percent);
        }
        }
    }
    }


@@ -409,4 +440,59 @@ public class IpSecPacketLossDetector extends NetworkMetricMonitor {
    private static long getPacketCntInReplayWindow(@NonNull IpSecTransformState state) {
    private static long getPacketCntInReplayWindow(@NonNull IpSecTransformState state) {
        return BitSet.valueOf(state.getReplayBitmap()).cardinality();
        return BitSet.valueOf(state.getReplayBitmap()).cardinality();
    }
    }

    @VisibleForTesting(visibility = Visibility.PRIVATE)
    public static class PacketLossCalculationResult {
        @PacketLossResultType private final int mResultType;
        private final int mPacketLossRatePercent;

        private PacketLossCalculationResult(@PacketLossResultType int type, int percent) {
            mResultType = type;
            mPacketLossRatePercent = percent;
        }

        /** Construct an instance that contains a valid packet loss rate */
        public static PacketLossCalculationResult valid(int percent) {
            return new PacketLossCalculationResult(PACKET_LOSS_RATE_VALID, percent);
        }

        /** Construct an instance indicating the inability to get a valid packet loss rate */
        public static PacketLossCalculationResult invalid() {
            return new PacketLossCalculationResult(
                    PACKET_LOSS_RATE_INVALID, PACKET_LOSS_PERCENT_UNAVAILABLE);
        }

        @PacketLossResultType
        public int getResultType() {
            return mResultType;
        }

        public int getPacketLossRatePercent() {
            return mPacketLossRatePercent;
        }

        @Override
        public int hashCode() {
            return Objects.hash(mResultType, mPacketLossRatePercent);
        }

        @Override
        public boolean equals(@Nullable Object other) {
            if (!(other instanceof PacketLossCalculationResult)) {
                return false;
            }

            final PacketLossCalculationResult rhs = (PacketLossCalculationResult) other;
            return mResultType == rhs.mResultType
                    && mPacketLossRatePercent == rhs.mPacketLossRatePercent;
        }

        @Override
        public String toString() {
            return "mResultType: "
                    + mResultType
                    + " | mPacketLossRatePercent: "
                    + mPacketLossRatePercent;
        }
    }
}
}
+32 −8
Original line number Original line Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.server.vcn.routeselection;
import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY;
import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY;
import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY;
import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY;


import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.PACKET_LOSS_UNAVALAIBLE;
import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
@@ -44,6 +43,7 @@ import android.net.IpSecTransformState;
import android.os.OutcomeReceiver;
import android.os.OutcomeReceiver;
import android.os.PowerManager;
import android.os.PowerManager;


import com.android.server.vcn.routeselection.IpSecPacketLossDetector.PacketLossCalculationResult;
import com.android.server.vcn.routeselection.IpSecPacketLossDetector.PacketLossCalculator;
import com.android.server.vcn.routeselection.IpSecPacketLossDetector.PacketLossCalculator;
import com.android.server.vcn.routeselection.NetworkMetricMonitor.IpSecTransformWrapper;
import com.android.server.vcn.routeselection.NetworkMetricMonitor.IpSecTransformWrapper;
import com.android.server.vcn.routeselection.NetworkMetricMonitor.NetworkMetricMonitorCallback;
import com.android.server.vcn.routeselection.NetworkMetricMonitor.NetworkMetricMonitorCallback;
@@ -293,7 +293,9 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase {
    }
    }


    private void checkHandleLossRate(
    private void checkHandleLossRate(
            int mockPacketLossRate, boolean isLastStateExpectedToUpdate, boolean isCallbackExpected)
            PacketLossCalculationResult mockPacketLossRate,
            boolean isLastStateExpectedToUpdate,
            boolean isCallbackExpected)
            throws Exception {
            throws Exception {
        final OutcomeReceiver<IpSecTransformState, RuntimeException> xfrmStateReceiver =
        final OutcomeReceiver<IpSecTransformState, RuntimeException> xfrmStateReceiver =
                startMonitorAndCaptureStateReceiver();
                startMonitorAndCaptureStateReceiver();
@@ -327,26 +329,32 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase {
    @Test
    @Test
    public void testHandleLossRate_validationPass() throws Exception {
    public void testHandleLossRate_validationPass() throws Exception {
        checkHandleLossRate(
        checkHandleLossRate(
                2, true /* isLastStateExpectedToUpdate */, true /* isCallbackExpected */);
                PacketLossCalculationResult.valid(2),
                true /* isLastStateExpectedToUpdate */,
                true /* isCallbackExpected */);
    }
    }


    @Test
    @Test
    public void testHandleLossRate_validationFail() throws Exception {
    public void testHandleLossRate_validationFail() throws Exception {
        checkHandleLossRate(
        checkHandleLossRate(
                22, true /* isLastStateExpectedToUpdate */, true /* isCallbackExpected */);
                PacketLossCalculationResult.valid(22),
                true /* isLastStateExpectedToUpdate */,
                true /* isCallbackExpected */);
        verify(mConnectivityManager).reportNetworkConnectivity(mNetwork, false);
        verify(mConnectivityManager).reportNetworkConnectivity(mNetwork, false);
    }
    }


    @Test
    @Test
    public void testHandleLossRate_resultUnavalaible() throws Exception {
    public void testHandleLossRate_resultUnavalaible() throws Exception {
        checkHandleLossRate(
        checkHandleLossRate(
                PACKET_LOSS_UNAVALAIBLE,
                PacketLossCalculationResult.invalid(),
                false /* isLastStateExpectedToUpdate */,
                false /* isLastStateExpectedToUpdate */,
                false /* isCallbackExpected */);
                false /* isCallbackExpected */);
    }
    }


    private void checkGetPacketLossRate(
    private void checkGetPacketLossRate(
            IpSecTransformState oldState, IpSecTransformState newState, int expectedLossRate)
            IpSecTransformState oldState,
            IpSecTransformState newState,
            PacketLossCalculationResult expectedLossRate)
            throws Exception {
            throws Exception {
        assertEquals(
        assertEquals(
                expectedLossRate,
                expectedLossRate,
@@ -362,14 +370,30 @@ public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase {
            throws Exception {
            throws Exception {
        final IpSecTransformState newState =
        final IpSecTransformState newState =
                newTransformState(rxSeqNo, packetCount, newReplayBitmap(packetInWin));
                newTransformState(rxSeqNo, packetCount, newReplayBitmap(packetInWin));
        checkGetPacketLossRate(
                oldState, newState, PacketLossCalculationResult.valid(expectedDataLossRate));
    }

    private void checkGetPacketLossRate(
            IpSecTransformState oldState,
            int rxSeqNo,
            int packetCount,
            int packetInWin,
            PacketLossCalculationResult expectedDataLossRate)
            throws Exception {
        final IpSecTransformState newState =
                newTransformState(rxSeqNo, packetCount, newReplayBitmap(packetInWin));
        checkGetPacketLossRate(oldState, newState, expectedDataLossRate);
        checkGetPacketLossRate(oldState, newState, expectedDataLossRate);
    }
    }


    @Test
    @Test
    public void testGetPacketLossRate_replayWindowUnchanged() throws Exception {
    public void testGetPacketLossRate_replayWindowUnchanged() throws Exception {
        checkGetPacketLossRate(
        checkGetPacketLossRate(
                mTransformStateInitial, mTransformStateInitial, PACKET_LOSS_UNAVALAIBLE);
                mTransformStateInitial,
        checkGetPacketLossRate(mTransformStateInitial, 3000, 2000, 2000, PACKET_LOSS_UNAVALAIBLE);
                mTransformStateInitial,
                PacketLossCalculationResult.invalid());
        checkGetPacketLossRate(
                mTransformStateInitial, 3000, 2000, 2000, PacketLossCalculationResult.invalid());
    }
    }


    @Test
    @Test