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

Commit dcdb5ee5 authored by Hakjun Choi's avatar Hakjun Choi
Browse files

[DO NOT MERGE] Implement RCS Dedicated Bearer metrics

Implement and update to store and pull Dedicated Bearer event atoms.

BUG: 174871215
Test: atest QosCallbackTrackerTest
Change-Id: I1ef3137cea1092c2a54b6669a94631bd5350fc0f
Merged-In: I1ef3137cea1092c2a54b6669a94631bd5350fc0f
Merged-In: Ice9c745fbbd74bb5ebb1c3901751b1a3f2920eb4
parent 3d22075c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -118,7 +118,7 @@ public class DcNetworkAgent extends NetworkAgent {
        } else {
            loge("The connection does not have a valid link properties.");
        }
        mQosCallbackTracker = new QosCallbackTracker(this);
        mQosCallbackTracker = new QosCallbackTracker(this, mPhone.getPhoneId());
    }

    private @NetworkType int getNetworkType() {
+127 −3
Original line number Diff line number Diff line
@@ -17,16 +17,18 @@
package com.android.internal.telephony.dataconnection;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.LinkAddress;
import android.net.QosSession;
import android.telephony.TelephonyProtoEnums;
import android.telephony.data.EpsBearerQosSessionAttributes;
import android.telephony.data.EpsQos;
import android.telephony.data.NrQos;
import android.telephony.data.EpsBearerQosSessionAttributes;
import android.telephony.data.NrQosSessionAttributes;
import android.telephony.data.QosBearerFilter;
import android.telephony.data.QosBearerSession;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.metrics.RcsStats;
import com.android.telephony.Rlog;

import java.net.InetAddress;
@@ -44,21 +46,48 @@ import java.util.Map;
 * {@hide}
 */
public class QosCallbackTracker {
    private static final int DedicatedBearerEvent_STATE_NONE = 0;
    private static final int DedicatedBearerEvent_STATE_ADDED = 1;
    private static final int DedicatedBearerEvent_STATE_MODIFIED = 2;
    private static final int DedicatedBearerEvent_STATE_DELETED = 3;

    @NonNull private final String mTag;
    @NonNull private final DcNetworkAgent mDcNetworkAgent;
    @NonNull private final Map<Integer, QosBearerSession> mQosBearerSessions;
    @NonNull private final RcsStats mRcsStats;

    // We perform an exact match on the address
    @NonNull private final Map<Integer, IFilter> mCallbacksToFilter;

    @NonNull private final int mPhoneID;

    /**
     * Construct a new tracker
     * @param dcNetworkAgent the network agent to send events to
     */
    public QosCallbackTracker(@NonNull final DcNetworkAgent dcNetworkAgent,
            @NonNull final int phoneID) {
        mQosBearerSessions = new HashMap<>();
        mCallbacksToFilter = new HashMap<>();
        mDcNetworkAgent = dcNetworkAgent;
        mPhoneID = phoneID;
        mRcsStats = RcsStats.getInstance();
        mTag = "QosCallbackTracker" + "-" + mDcNetworkAgent.getNetwork().getNetId();
    }

    /**
     * Construct a new tracker
     * @param dcNetworkAgent the network agent to send events to
     * @param rcsStats metrics package to store QoS event info
     */
    public QosCallbackTracker(@NonNull final DcNetworkAgent dcNetworkAgent) {
    @VisibleForTesting
    public QosCallbackTracker(@NonNull final DcNetworkAgent dcNetworkAgent,
            @NonNull final int phoneID, @NonNull final RcsStats rcsStats) {
        mQosBearerSessions = new HashMap<>();
        mCallbacksToFilter = new HashMap<>();
        mDcNetworkAgent = dcNetworkAgent;
        mPhoneID = phoneID;
        mRcsStats = rcsStats;
        mTag = "QosCallbackTracker" + "-" + mDcNetworkAgent.getNetwork().getNetId();
    }

@@ -77,6 +106,8 @@ public class QosCallbackTracker {
        for (final QosBearerSession session : mQosBearerSessions.values()) {
            if (doFiltersMatch(session, filter)) {
                sendSessionAvailable(callbackId, session, filter);

                notifyMetricDedicatedBearerListenerAdded(callbackId, session);
            }
        }
    }
@@ -89,6 +120,7 @@ public class QosCallbackTracker {
    public void removeFilter(final int callbackId) {
        logd("removeFilter: callbackId=" + callbackId);
        mCallbacksToFilter.remove(callbackId);
        notifyMetricDedicatedBearerListenerRemoved(callbackId);
    }

    /**
@@ -98,6 +130,8 @@ public class QosCallbackTracker {
     */
    public void updateSessions(@NonNull final List<QosBearerSession> sessions) {
        logd("updateSessions: sessions size=" + sessions.size());

        int bearerState = DedicatedBearerEvent_STATE_NONE;
        final List<QosBearerSession> sessionsToAdd = new ArrayList<>();
        final Map<Integer, QosBearerSession> incomingSessions = new HashMap<>();
        for (final QosBearerSession incomingSession : sessions) {
@@ -115,6 +149,8 @@ public class QosCallbackTracker {
                if (!existingSessionMatch && incomingSessionMatch) {
                    // The filter matches now and didn't match earlier
                    sendSessionAvailable(callbackId, incomingSession, filter);

                    bearerState = DedicatedBearerEvent_STATE_ADDED;
                }

                if (existingSessionMatch && incomingSessionMatch) {
@@ -122,8 +158,11 @@ public class QosCallbackTracker {
                    // the callback still needs to be notified
                    if (!incomingSession.getQos().equals(existingSession.getQos())) {
                        sendSessionAvailable(callbackId, incomingSession, filter);
                        bearerState = DedicatedBearerEvent_STATE_MODIFIED;
                    }
                }

                notifyMetricDedicatedBearerEvent(incomingSession, filter, bearerState);
            }
            sessionsToAdd.add(incomingSession);
        }
@@ -136,7 +175,9 @@ public class QosCallbackTracker {
                    final IFilter filter = mCallbacksToFilter.get(callbackId);
                    // The filter matches which means it was previously available, and now is lost
                    if (doFiltersMatch(existingSession, filter)) {
                        bearerState = DedicatedBearerEvent_STATE_DELETED;
                        sendSessionLost(callbackId, existingSession);
                        notifyMetricDedicatedBearerEvent(existingSession, filter, bearerState);
                    }
                }
                sessionsToRemove.add(existingSession.getQosBearerSessionId());
@@ -262,6 +303,9 @@ public class QosCallbackTracker {
                    callbackId, session.getQosBearerSessionId(), nrQosAttr);
        }

        /** added to notify to Metric for passing DedicatedBearerEstablished info */
        notifyMetricDedicatedBearerListenerBearerUpdateSession(callbackId, session);

        logd("sendSessionAvailable, callbackId=" + callbackId);
    }

@@ -272,6 +316,86 @@ public class QosCallbackTracker {
        logd("sendSessionLost, callbackId=" + callbackId);
    }

    private void notifyMetricDedicatedBearerListenerAdded(
            final int callbackId, final QosBearerSession session) {

        final int slotId = mPhoneID;
        final int rat = getRatInfoFromSessionInfo(session);
        final int qci = getQCIFromSessionInfo(session);

        mRcsStats.onImsDedicatedBearerListenerAdded(callbackId, slotId, rat, qci);
    }

    private void notifyMetricDedicatedBearerListenerBearerUpdateSession(
            final int callbackId, final QosBearerSession session) {

        final int slotId = mPhoneID;
        final int rat = getRatInfoFromSessionInfo(session);
        final int qci = getQCIFromSessionInfo(session);

        mRcsStats.onImsDedicatedBearerListenerUpdateSession(callbackId, slotId, rat, qci, true);
    }

    private void notifyMetricDedicatedBearerListenerRemoved(final int callbackId) {
        mRcsStats.onImsDedicatedBearerListenerRemoved(callbackId);
    }

    private int getQCIFromSessionInfo(final QosBearerSession session) {
        if (session.getQos() instanceof EpsQos) {
            return ((EpsQos) session.getQos()).getQci();
        } else if (session.getQos() instanceof NrQos) {
            return ((NrQos) session.getQos()).get5Qi();
        }

        return 0;
    }

    private int getRatInfoFromSessionInfo(final QosBearerSession session) {
        if (session.getQos() instanceof EpsQos) {
            return TelephonyProtoEnums.NETWORK_TYPE_LTE;
        } else if (session.getQos() instanceof NrQos) {
            return TelephonyProtoEnums.NETWORK_TYPE_NR;
        }

        return 0;
    }

    private void notifyMetricDedicatedBearerEvent(final QosBearerSession session,
            final IFilter filter, final int bearerState) {

        final int slotId = mPhoneID;
        int ratAtEnd = 0;
        int qci = 0;
        boolean localConnectionInfoReceived = false;
        boolean remoteConnectionInfoReceived = false;


        QosBearerFilter qosBearerFilter = getMatchingQosBearerFilter(session, filter);
        if (session.getQos() instanceof EpsQos) {
            ratAtEnd = TelephonyProtoEnums.NETWORK_TYPE_LTE;
            qci = ((EpsQos) session.getQos()).getQci();
        } else if (session.getQos() instanceof NrQos) {
            ratAtEnd = TelephonyProtoEnums.NETWORK_TYPE_NR;
            qci = ((NrQos) session.getQos()).get5Qi();
        } else {
            return;
        }

        if (qosBearerFilter != null) {
            if (!qosBearerFilter.getLocalAddresses().isEmpty()
                    && qosBearerFilter.getLocalPortRange().isValid()) {
                localConnectionInfoReceived = true;
            }
            if (!qosBearerFilter.getRemoteAddresses().isEmpty()
                    && qosBearerFilter.getRemotePortRange().isValid()) {
                remoteConnectionInfoReceived = true;
            }
        }

        mRcsStats.onImsDedicatedBearerEvent(slotId, ratAtEnd, qci, bearerState,
                localConnectionInfoReceived, remoteConnectionInfoReceived, true);
    }

    public interface IFilter {
        public boolean matchesLocalAddress(InetAddress address, int startPort, int endPort);
        public boolean matchesRemoteAddress(InetAddress address, int startPort, int endPort);
+47 −10
Original line number Diff line number Diff line
@@ -16,13 +16,10 @@

package com.android.internal.telephony.dataconnection;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
@@ -32,31 +29,28 @@ import android.annotation.NonNull;
import android.net.InetAddresses;
import android.net.LinkAddress;
import android.net.Network;
import android.net.NetworkAgent;
import android.telephony.data.EpsBearerQosSessionAttributes;
import android.telephony.data.EpsQos;
import android.telephony.data.QosBearerFilter;
import android.telephony.data.QosBearerSession;

import android.test.suitebuilder.annotation.SmallTest;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;

import com.android.internal.telephony.Phone;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.metrics.RcsStats;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;

import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -93,10 +87,14 @@ public class QosCallbackTrackerTest extends TelephonyTest {
        }
    }

    @Mock
    private Phone mPhone;
    @Mock
    private DcNetworkAgent mDcNetworkAgent;
    @Mock
    private Network mNetwork;
    @Mock
    private RcsStats mRcsStats;

    private QosCallbackTracker mQosCallbackTracker;

@@ -105,7 +103,9 @@ public class QosCallbackTrackerTest extends TelephonyTest {
        super.setUp(getClass().getSimpleName());
        doReturn(mNetwork).when(mDcNetworkAgent).getNetwork();
        doReturn(100).when(mNetwork).getNetId();
        mQosCallbackTracker = new QosCallbackTracker(mDcNetworkAgent);
        doReturn(0).when(mPhone).getPhoneId();
        mQosCallbackTracker = new QosCallbackTracker(mDcNetworkAgent, mPhone.getPhoneId(),
                mRcsStats);
        processAllMessages();
    }

@@ -486,5 +486,42 @@ public class QosCallbackTrackerTest extends TelephonyTest {
                eq(1235), any(EpsBearerQosSessionAttributes.class));

    }

    @Test
    @SmallTest
    public void testQosMetrics() throws Exception {
        final int callbackId = 1;
        final int slotId = mPhone.getPhoneId();
        // Add filter before update session
        Filter filter1 = new Filter(new InetSocketAddress(
                InetAddresses.parseNumericAddress("155.55.55.55"), 2222),
                new InetSocketAddress(InetAddresses.parseNumericAddress("144.44.44.44"), 2223));

        mQosCallbackTracker.addFilter(callbackId, filter1);
        verify(mRcsStats, never()).onImsDedicatedBearerListenerAdded(eq(callbackId), eq(slotId),
                anyInt(), anyInt());

        // QosBearerFilter
        ArrayList<QosBearerFilter> qosFilters1 = new ArrayList<>();
        qosFilters1.add(createIpv4QosFilter("155.55.55.55", "144.44.44.44",
                new QosBearerFilter.PortRange(2222, 2222),
                new QosBearerFilter.PortRange(2223, 2223), 45));

        ArrayList<QosBearerSession> qosSessions = new ArrayList<>();
        qosSessions.add(new QosBearerSession(1234, createEpsQos(5, 6, 7, 8), qosFilters1));
        mQosCallbackTracker.updateSessions(qosSessions);

        verify(mRcsStats, times(1))
                .onImsDedicatedBearerListenerUpdateSession(
                        eq(callbackId), eq(slotId), anyInt(), anyInt(), eq(true));

        mQosCallbackTracker.addFilter(callbackId, filter1);
        verify(mRcsStats, times(1)).onImsDedicatedBearerListenerAdded(
                anyInt(), anyInt(), anyInt(), anyInt());

        mQosCallbackTracker.removeFilter(callbackId);
        verify(mRcsStats, times(1))
                .onImsDedicatedBearerListenerRemoved(callbackId);
    }
}