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

Commit 3d5db252 authored by Hakjun Choi's avatar Hakjun Choi Committed by Hyunho
Browse files

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
parent ccf14643
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 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.internal.telephony.dataconnection;

import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
@@ -37,7 +38,9 @@ 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;
@@ -85,10 +88,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;

@@ -97,7 +104,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();
    }

@@ -479,5 +488,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);
    }
}