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

Commit 354d78de authored by Junyu Lai's avatar Junyu Lai Committed by Gerrit Code Review
Browse files

Merge changes from topics "sp12-getVtDataUsage", "sp13-vtdatausage"

* changes:
  [SP13] Add unit test for VtDataUsageProvider
  [SP12.1] Add VtDataUsageProvider
parents d5c62b55 cce98d06
Loading
Loading
Loading
Loading
+61 −2
Original line number Diff line number Diff line
@@ -16,9 +16,11 @@

package com.android.internal.telephony.imsphone;

import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
import static com.android.internal.telephony.Phone.CS_FALLBACK;

import android.annotation.NonNull;
import android.app.usage.NetworkStatsManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -32,6 +34,8 @@ import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.NetworkStats;
import android.net.netstats.provider.AbstractNetworkStatsProvider;
import android.net.netstats.provider.NetworkStatsProviderCallback;
import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Handler;
@@ -44,6 +48,7 @@ import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.provider.Settings;
import android.sysprop.TelephonyProperties;
import android.telecom.Connection.VideoProvider;
import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import android.telephony.CallQuality;
@@ -255,6 +260,49 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        }
    }

    /**
     * A class implementing {@link AbstractNetworkStatsProvider} to report VT data usage to system.
     */
    // TODO: 1. Directly reports diff in updateVtDataUsage.
    //       2. Remove unused getVtDataUsage.
    @VisibleForTesting(visibility = PRIVATE)
    public class VtDataUsageProvider extends AbstractNetworkStatsProvider {
        private int mToken = 0;
        private NetworkStats mIfaceSnapshot = new NetworkStats(0L, 0);
        private NetworkStats mUidSnapshot = new NetworkStats(0L, 0);
        @Override
        public void requestStatsUpdate(int token) {
            // If there is an ongoing VT call, request the latest VT usage from the modem. The
            // latest usage will return asynchronously so it won't be counted in this round, but it
            // will be eventually counted when next requestStatsUpdate is called.
            if (mState != PhoneConstants.State.IDLE) {
                for (ImsPhoneConnection conn : mConnections) {
                    final VideoProvider videoProvider = conn.getVideoProvider();
                    if (videoProvider != null) {
                        videoProvider.onRequestConnectionDataUsage();
                    }
                }
            }

            final NetworkStats ifaceDiff = mVtDataUsageSnapshot.subtract(mIfaceSnapshot);
            final NetworkStats uidDiff = mVtDataUsageUidSnapshot.subtract(mUidSnapshot);
            mVtDataUsageProviderCb.onStatsUpdated(mToken, ifaceDiff, uidDiff);
            mIfaceSnapshot = mIfaceSnapshot.add(ifaceDiff);
            mUidSnapshot = mUidSnapshot.add(uidDiff);
            mToken = token;
        }

        @Override
        public void setLimit(String iface, long quotaBytes) {
            // No-op
        }

        @Override
        public void setAlert(long quotaBytes) {
            // No-op
        }
    }

    private BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
@@ -390,6 +438,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {

    private volatile NetworkStats mVtDataUsageSnapshot = null;
    private volatile NetworkStats mVtDataUsageUidSnapshot = null;
    private final NetworkStatsProviderCallback mVtDataUsageProviderCb;

    private final AtomicInteger mDefaultDialerUid = new AtomicInteger(NetworkStats.UID_ALL);

@@ -823,6 +872,11 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        long currentTime = SystemClock.elapsedRealtime();
        mVtDataUsageSnapshot = new NetworkStats(currentTime, 1);
        mVtDataUsageUidSnapshot = new NetworkStats(currentTime, 1);
        final NetworkStatsManager statsManager =
                (NetworkStatsManager) mPhone.getContext().getSystemService(
                        Context.NETWORK_STATS_SERVICE);
        mVtDataUsageProviderCb = statsManager.registerNetworkStatsProvider(LOG_TAG,
                new VtDataUsageProvider());

        // Allow the executor to be specified for testing.
        mImsManagerConnector = new FeatureConnector<>(
@@ -972,6 +1026,10 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        mPhone.getContext().unregisterReceiver(mReceiver);
        mPhone.getDefaultPhone().getDataEnabledSettings().unregisterForDataEnabledChanged(this);
        mImsManagerConnector.disconnect();

        if (mVtDataUsageProviderCb != null) {
            mVtDataUsageProviderCb.unregister();
        }
    }

    @Override
@@ -3865,7 +3923,8 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
     * @param call The IMS call
     * @param dataUsage The aggregated data usage for the call
     */
    private void updateVtDataUsage(ImsCall call, long dataUsage) {
    @VisibleForTesting(visibility = PRIVATE)
    public void updateVtDataUsage(ImsCall call, long dataUsage) {
        long oldUsage = 0L;
        if (mVtDataUsageMap.containsKey(call.uniqueId)) {
            oldUsage = mVtDataUsageMap.get(call.uniqueId);
@@ -4299,7 +4358,7 @@ public class ImsPhoneCallTracker extends CallTracker implements ImsPullCall {
        // eventually counted when next getVtDataUsage is called.
        if (mState != PhoneConstants.State.IDLE) {
            for (ImsPhoneConnection conn : mConnections) {
                android.telecom.Connection.VideoProvider videoProvider = conn.getVideoProvider();
                VideoProvider videoProvider = conn.getVideoProvider();
                if (videoProvider != null) {
                    videoProvider.onRequestConnectionDataUsage();
                }
+1 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@ android_test {
        "frameworks-base-testutils",
        "guava",
        "mockito-target-minus-junit4",
        "net-tests-utils",
        "platform-test-annotations",
        "services.core",
        "services.net",
+4 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import static org.mockito.Mockito.eq;

import android.app.ActivityManager;
import android.app.IActivityManager;
import android.app.usage.NetworkStatsManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.IIntentSender;
@@ -270,6 +271,8 @@ public abstract class TelephonyTest {
    protected MultiSimSettingController mMultiSimSettingController;
    @Mock
    protected IccCard mIccCard;
    @Mock
    protected NetworkStatsManager mStatsManager;

    protected ImsCallProfile mImsCallProfile;
    protected TelephonyManager mTelephonyManager;
@@ -575,6 +578,7 @@ public abstract class TelephonyTest {
        doAnswer((invocation)->Math.max(mTelephonyManager.getActiveModemCount(),
                mTelephonyManager.getPhoneCount()))
                .when(mTelephonyManager).getSupportedModemCount();
        doReturn(mStatsManager).when(mContext).getSystemService(eq(Context.NETWORK_STATS_SERVICE));

        //Data
        //Initial state is: userData enabled, provisioned.
+85 −1
Original line number Diff line number Diff line
@@ -15,11 +15,21 @@
 */
package com.android.internal.telephony.imsphone;

import static android.net.NetworkStats.DEFAULT_NETWORK_YES;
import static android.net.NetworkStats.METERED_YES;
import static android.net.NetworkStats.ROAMING_NO;
import static android.net.NetworkStats.SET_FOREGROUND;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;

import static com.android.testutils.NetworkStatsUtilsKt.assertNetworkStatsEquals;

import static junit.framework.TestCase.fail;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
@@ -32,6 +42,7 @@ import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -40,6 +51,9 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.NetworkStats;
import android.net.NetworkStats.Entry;
import android.net.netstats.provider.NetworkStatsProviderCallback;
import android.os.Bundle;
import android.os.Message;
import android.os.PersistableBundle;
@@ -72,6 +86,7 @@ import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.Connection;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.imsphone.ImsPhoneCallTracker.VtDataUsageProvider;

import org.junit.After;
import org.junit.Assert;
@@ -94,6 +109,8 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
    private ImsCall mImsCall;
    private ImsCall mSecondImsCall;
    private Bundle mBundle = new Bundle();
    private final ArgumentCaptor<VtDataUsageProvider> mVtDataUsageProviderCaptor =
            ArgumentCaptor.forClass(VtDataUsageProvider.class);
    @Mock
    private ImsCallSession mImsCallSession;
    @Mock
@@ -104,6 +121,8 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
    private ImsConfig mImsConfig;
    @Mock
    private ImsPhoneConnection mImsPhoneConnection;
    @Mock
    private NetworkStatsProviderCallback mVtDataUsageProviderCb;

    private void imsCallMocking(final ImsCall imsCall) throws Exception {

@@ -209,6 +228,9 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {

        doNothing().when(mImsManager).addNotifyStatusChangedCallbackIfAvailable(any());

        doReturn(mVtDataUsageProviderCb).when(mStatsManager).registerNetworkStatsProvider(
                anyString(), any());

        mCTUT = new ImsPhoneCallTracker(mImsPhone, Runnable::run);
        mCTUT.addReasonCodeRemapping(null, "Wifi signal lost.", ImsReasonInfo.CODE_WIFI_LOST);
        mCTUT.addReasonCodeRemapping(501, "Call answered elsewhere.",
@@ -224,6 +246,8 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
                "service not allowed in this location",
                ImsReasonInfo.CODE_WFC_SERVICE_NOT_AVAILABLE_IN_THIS_LOCATION);
        mCTUT.setDataEnabled(true);
        verify(mStatsManager).registerNetworkStatsProvider(anyString(),
                mVtDataUsageProviderCaptor.capture());

        logd("ImsPhoneCallTracker initiated");
        processAllMessages();
@@ -1005,6 +1029,66 @@ public class ImsPhoneCallTrackerTest extends TelephonyTest {
        mCTUT.getImsCallListener().onCallHoldFailed(mImsPhoneConnection.getImsCall(), info);
    }

    @Test
    @SmallTest
    public void testVtDataUsageProvider() {
        final VtDataUsageProvider provider = mVtDataUsageProviderCaptor.getValue();

        provider.requestStatsUpdate(11);

        // Verify that requestStatsUpdate triggers onStatsUpdated, where the initial token should
        // be reported with current stats.
        assertVtDataUsageUpdated(0, 0, 0);

        // Establish a MT call.
        testImsMTCallAccept();
        final ImsPhoneConnection connection = mCTUT.mForegroundCall.getFirstConnection();
        final ImsCall call = connection.getImsCall();
        mCTUT.updateVtDataUsage(call, 51);

        // Make another request, and verify stats updated accordingly, with previously issued token.
        reset(mVtDataUsageProviderCb);
        provider.requestStatsUpdate(13);
        assertVtDataUsageUpdated(11, 25, 25);

        // Update accumulated data usage twice. updateVtDataUsage takes accumulated stats from
        // boot up.
        reset(mVtDataUsageProviderCb);
        mCTUT.updateVtDataUsage(call, 70);
        mCTUT.updateVtDataUsage(call, 91);
        verify(mVtDataUsageProviderCb, never()).onStatsUpdated(anyInt(), any(), any());

        // Verify that diff stats from last update is reported accordingly.
        provider.requestStatsUpdate(13);
        // Rounding error occurs so (70-51)/2 + (91-70)/2 = 19 is expected for both direction.
        assertVtDataUsageUpdated(13, 19, 19);
    }

    private void assertVtDataUsageUpdated(int expectedToken, long rxBytes, long txBytes) {
        final ArgumentCaptor<NetworkStats> ifaceStatsCaptor = ArgumentCaptor.forClass(
                NetworkStats.class);
        final ArgumentCaptor<NetworkStats> uidStatsCaptor = ArgumentCaptor.forClass(
                NetworkStats.class);

        verify(mVtDataUsageProviderCb).onStatsUpdated(eq(expectedToken), ifaceStatsCaptor.capture(),
                uidStatsCaptor.capture());

        // Default dialer's package uid is not set during test, thus the uid stats looks the same
        // as iface stats and the records are always merged into the same entry.
        // TODO: Mock different dialer's uid and verify uid stats has corresponding uid in the
        //  records.
        NetworkStats expectedStats = new NetworkStats(0L, 0);

        if (rxBytes != 0 || txBytes != 0) {
            expectedStats = expectedStats.addValues(
                    new Entry(NetworkStats.IFACE_VT, UID_ALL, SET_FOREGROUND,
                            TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, rxBytes, 0L,
                            txBytes, 0L, 0L));
        }
        assertNetworkStatsEquals(expectedStats, ifaceStatsCaptor.getValue());
        assertNetworkStatsEquals(expectedStats, uidStatsCaptor.getValue());
    }

    private ImsPhoneConnection placeCallAndMakeActive() {
        try {
            doAnswer(new Answer<ImsCall>() {