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

Commit 67c0d68f authored by Kiwon Park's avatar Kiwon Park Committed by Android (Google) Code Review
Browse files

Merge "Collect metrics for WFC settings." into tm-dev

parents 09db5fd1 148c1056
Loading
Loading
Loading
Loading
+23 −57
Original line number Diff line number Diff line
@@ -16,10 +16,6 @@

package com.android.internal.telephony.metrics;

import static android.telephony.PhoneNumberUtils.areSamePhoneNumber;
import static android.telephony.SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER;
import static android.telephony.SubscriptionManager.PHONE_NUMBER_SOURCE_IMS;
import static android.telephony.SubscriptionManager.PHONE_NUMBER_SOURCE_UICC;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.SECOND_IN_MILLIS;
@@ -55,14 +51,11 @@ import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSIO
import android.annotation.Nullable;
import android.app.StatsManager;
import android.content.Context;
import android.telephony.SubscriptionInfo;
import android.text.TextUtils;
import android.util.StatsEvent;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.SubscriptionController;
import com.android.internal.telephony.TelephonyStatsLog;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
@@ -94,7 +87,6 @@ import com.android.telephony.Rlog;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -137,23 +129,20 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
                    .build();

    private final PersistAtomsStorage mStorage;
    private final TelephonyStatsLogHelper mTelephonyStatsLog;
    private final StatsManager mStatsManager;
    private final AirplaneModeStats mAirplaneModeStats;
    private final Set<DataCallSessionStats> mOngoingDataCallStats = ConcurrentHashMap.newKeySet();
    private static final Random sRandom = new Random();

    public MetricsCollector(Context context) {
        this(context, new PersistAtomsStorage(context), new TelephonyStatsLogHelper());
        this(context, new PersistAtomsStorage(context));
    }

    /** Allows dependency injection. Used during unit tests. */
    @VisibleForTesting
    public MetricsCollector(Context context,
                            PersistAtomsStorage storage,
                            TelephonyStatsLogHelper telephonyStatsLog) {
                            PersistAtomsStorage storage) {
        mStorage = storage;
        mTelephonyStatsLog = telephonyStatsLog;
        mStatsManager = (StatsManager) context.getSystemService(Context.STATS_MANAGER);
        if (mStatsManager != null) {
            registerAtom(CELLULAR_DATA_SERVICE_SWITCH, POLICY_PULL_DAILY);
@@ -656,56 +645,33 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
    }

    private int pullPerSimStatus(List<StatsEvent> data) {
        SubscriptionController subscriptionController = SubscriptionController.getInstance();
        if (subscriptionController == null) {
            return StatsManager.PULL_SKIP;
        }
        int result = StatsManager.PULL_SKIP;
        for (Phone phone : getPhonesIfAny()) {
            int subId = phone.getSubId();
            String countryIso =
                    Optional.ofNullable(subscriptionController.getSubscriptionInfo(subId))
                            .map(SubscriptionInfo::getCountryIso)
                            .orElse("");
            // number[]- hone numbers from each sources:
            // numberState[] - int representation for each number source used in the atom
            // index 0 - PHONE_NUMBER_SOURCE_UICC
            // index 1 - PHONE_NUMBER_SOURCE_CARRIER
            // index 2 - PHONE_NUMBER_SOURCE_IMS
            String[] number = new String[] {
                subscriptionController.getPhoneNumber(subId, PHONE_NUMBER_SOURCE_UICC),  // 0
                subscriptionController.getPhoneNumber(subId, PHONE_NUMBER_SOURCE_CARRIER),  // 1
                subscriptionController.getPhoneNumber(subId, PHONE_NUMBER_SOURCE_IMS),  // 2
            };
            int[] numberState = new int[number.length];  // default value 0
            for (int i = 0, stateForNextUniqueNumber = 1; i < numberState.length; i++) {
                if (TextUtils.isEmpty(number[i])) {
                    // keep state 0 if number not available
            PerSimStatus perSimStatus = PerSimStatus.getCurrentState(phone);
            if (perSimStatus == null) {
                continue;
            }
                // the number is available:
                // try to find the same number from other sources and reuse the state
                for (int j = 0; j < i; j++) {
                    if (!TextUtils.isEmpty(number[j])
                            && areSamePhoneNumber(number[i], number[j], countryIso)) {
                        numberState[i] = numberState[j];
                    }
                }
                // didn't find same number (otherwise should not be state 0), assign a new state
                if (numberState[i] == 0) {
                    numberState[i] = stateForNextUniqueNumber;
                    stateForNextUniqueNumber++;
                }
            }
            StatsEvent statsEvent = mTelephonyStatsLog.buildStatsEvent(
            StatsEvent statsEvent = TelephonyStatsLog.buildStatsEvent(
                    PER_SIM_STATUS,
                    phone.getPhoneId(), // simSlotIndex
                    phone.getCarrierId(), // carrierId
                    numberState[0], // phoneNumberSourceUicc
                    numberState[1], // phoneNumberSourceCarrier
                    numberState[2]); // phoneNumberSourceIms
                    perSimStatus.carrierId, // carrierId
                    perSimStatus.phoneNumberSourceUicc, // phoneNumberSourceUicc
                    perSimStatus.phoneNumberSourceCarrier, // phoneNumberSourceCarrier
                    perSimStatus.phoneNumberSourceIms, // phoneNumberSourceIms
                    perSimStatus.advancedCallingSettingEnabled, // volteEnabled
                    perSimStatus.voWiFiSettingEnabled, // wfcEnabled
                    perSimStatus.voWiFiModeSetting, // wfcMode
                    perSimStatus.voWiFiRoamingModeSetting, // wfcRoamingMode
                    perSimStatus.vtSettingEnabled, // videoCallingEnabled
                    perSimStatus.dataRoamingEnabled, // dataRoamingEnabled
                    perSimStatus.preferredNetworkType, // allowedNetworksByUser
                    perSimStatus.disabled2g, // is2gDisabled
                    false, // TODO(b/215758472): isPin1Enabled
                    0); // TODO(b/215758472): simVoltageClass
            data.add(statsEvent);
            result = StatsManager.PULL_SUCCESS;
        }
        return StatsManager.PULL_SUCCESS;
        return result;
    }

    /** Registers a pulled atom ID {@code atomId} with optional {@code policy} for pulling. */
+199 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.telephony.metrics;

import static android.telephony.PhoneNumberUtils.areSamePhoneNumber;
import static android.telephony.SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER;
import static android.telephony.SubscriptionManager.PHONE_NUMBER_SOURCE_IMS;
import static android.telephony.SubscriptionManager.PHONE_NUMBER_SOURCE_UICC;

import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS__WFC_MODE__CELLULAR_PREFERRED;
import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS__WFC_MODE__UNKNOWN;
import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS__WFC_MODE__WIFI_ONLY;
import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS__WFC_MODE__WIFI_PREFERRED;

import android.annotation.Nullable;
import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsManager;
import android.telephony.ims.ImsMmTelManager;
import android.text.TextUtils;

import com.android.internal.telephony.Phone;
import com.android.internal.telephony.SubscriptionController;

import java.util.Optional;

/** Stores the per SIM status. */
public class PerSimStatus {
    private static final long BITMASK_2G =
            TelephonyManager.NETWORK_TYPE_BITMASK_GSM
                    | TelephonyManager.NETWORK_TYPE_BITMASK_GPRS
                    | TelephonyManager.NETWORK_TYPE_BITMASK_EDGE
                    | TelephonyManager.NETWORK_TYPE_BITMASK_CDMA
                    | TelephonyManager.NETWORK_TYPE_BITMASK_1xRTT;

    public final int carrierId;
    public final int phoneNumberSourceUicc;
    public final int phoneNumberSourceCarrier;
    public final int phoneNumberSourceIms;
    public final boolean advancedCallingSettingEnabled;
    public final boolean voWiFiSettingEnabled;
    public final int voWiFiModeSetting;
    public final int voWiFiRoamingModeSetting;
    public final boolean vtSettingEnabled;
    public final boolean dataRoamingEnabled;
    public final long preferredNetworkType;
    public final boolean disabled2g;

    /** Returns the current sim status of the given {@link Phone}. */
    @Nullable
    public static PerSimStatus getCurrentState(Phone phone) {
        int[] numberState = getNumberState(phone);
        if (numberState == null) return null;
        ImsMmTelManager imsMmTelManager = getImsMmTelManager(phone);
        return new PerSimStatus(
                phone.getCarrierId(),
                numberState[0],
                numberState[1],
                numberState[2],
                imsMmTelManager == null ? false : imsMmTelManager.isAdvancedCallingSettingEnabled(),
                imsMmTelManager == null ? false : imsMmTelManager.isVoWiFiSettingEnabled(),
                imsMmTelManager == null
                        ? PER_SIM_STATUS__WFC_MODE__UNKNOWN
                        : wifiCallingModeToProtoEnum(imsMmTelManager.getVoWiFiModeSetting()),
                imsMmTelManager == null
                        ? PER_SIM_STATUS__WFC_MODE__UNKNOWN
                        : wifiCallingModeToProtoEnum(imsMmTelManager.getVoWiFiRoamingModeSetting()),
                imsMmTelManager == null ? false : imsMmTelManager.isVtSettingEnabled(),
                phone.getDataRoamingEnabled(),
                phone.getAllowedNetworkTypes(TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_USER),
                is2gDisabled(phone));
    }

    private PerSimStatus(
            int carrierId,
            int phoneNumberSourceUicc,
            int phoneNumberSourceCarrier,
            int phoneNumberSourceIms,
            boolean advancedCallingSettingEnabled,
            boolean voWiFiSettingEnabled,
            int voWiFiModeSetting,
            int voWiFiRoamingModeSetting,
            boolean vtSettingEnabled,
            boolean dataRoamingEnabled,
            long preferredNetworkType,
            boolean disabled2g) {
        this.carrierId = carrierId;
        this.phoneNumberSourceUicc = phoneNumberSourceUicc;
        this.phoneNumberSourceCarrier = phoneNumberSourceCarrier;
        this.phoneNumberSourceIms = phoneNumberSourceIms;
        this.advancedCallingSettingEnabled = advancedCallingSettingEnabled;
        this.voWiFiSettingEnabled = voWiFiSettingEnabled;
        this.voWiFiModeSetting = voWiFiModeSetting;
        this.voWiFiRoamingModeSetting = voWiFiRoamingModeSetting;
        this.vtSettingEnabled = vtSettingEnabled;
        this.dataRoamingEnabled = dataRoamingEnabled;
        this.preferredNetworkType = preferredNetworkType;
        this.disabled2g = disabled2g;
    }

    @Nullable
    private static ImsMmTelManager getImsMmTelManager(Phone phone) {
        ImsManager imsManager = phone.getContext().getSystemService(ImsManager.class);
        if (imsManager == null) {
            return null;
        }
        try {
            return imsManager.getImsMmTelManager(phone.getSubId());
        } catch (IllegalArgumentException e) {
            return null; // Invalid subId
        }
    }

    /**
     * Returns an array containing the various phone numbers available on the device.
     * <ul>
     *     <li>Index 0: phone number associated with {@code PHONE_NUMBER_SOURCE_UICC}.</li>
     *     <li>Index 1: phone number associated with {@code PHONE_NUMBER_SOURCE_CARRIER}.</li>
     *     <li>Index 2: phone number associated with {@code PHONE_NUMBER_SOURCE_IMS}.</li>
     * </ul>
     */
    @Nullable
    private static int[] getNumberState(Phone phone) {
        SubscriptionController subscriptionController = SubscriptionController.getInstance();
        if (subscriptionController == null) {
            return null;
        }
        int subId = phone.getSubId();
        String countryIso =
                Optional.ofNullable(subscriptionController.getSubscriptionInfo(subId))
                        .map(SubscriptionInfo::getCountryIso)
                        .orElse("");
        // number[] - hone numbers from each sources:
        String[] number =
                new String[] {
                    subscriptionController.getPhoneNumber(subId, PHONE_NUMBER_SOURCE_UICC), // 0
                    subscriptionController.getPhoneNumber(subId, PHONE_NUMBER_SOURCE_CARRIER), // 1
                    subscriptionController.getPhoneNumber(subId, PHONE_NUMBER_SOURCE_IMS), // 2
                };
        int[] numberState = new int[number.length]; // default value 0
        for (int i = 0, stateForNextUniqueNumber = 1; i < numberState.length; i++) {
            if (TextUtils.isEmpty(number[i])) {
                // keep state 0 if number not available
                continue;
            }
            // the number is available:
            // try to find the same number from other sources and reuse the state
            for (int j = 0; j < i; j++) {
                if (!TextUtils.isEmpty(number[j])
                        && areSamePhoneNumber(number[i], number[j], countryIso)) {
                    numberState[i] = numberState[j];
                }
            }
            // didn't find same number (otherwise should not be state 0), assign a new state
            if (numberState[i] == 0) {
                numberState[i] = stateForNextUniqueNumber++;
            }
        }
        return numberState;
    }

    /**
     * Returns {@code true} if 2G cellular network is disabled (Allow 2G toggle in the settings).
     */
    private static boolean is2gDisabled(Phone phone) {
        return (phone.getAllowedNetworkTypes(
                                TelephonyManager.ALLOWED_NETWORK_TYPES_REASON_ENABLE_2G)
                        & BITMASK_2G)
                == 0;
    }

    /** Converts {@link ImsMmTelManager.WifiCallingMode} to the value of PerSimStatus WfcMode. */
    private static int wifiCallingModeToProtoEnum(@ImsMmTelManager.WiFiCallingMode int mode) {
        switch (mode) {
            case ImsMmTelManager.WIFI_MODE_WIFI_ONLY:
                return PER_SIM_STATUS__WFC_MODE__WIFI_ONLY;
            case ImsMmTelManager.WIFI_MODE_CELLULAR_PREFERRED:
                return PER_SIM_STATUS__WFC_MODE__CELLULAR_PREFERRED;
            case ImsMmTelManager.WIFI_MODE_WIFI_PREFERRED:
                return PER_SIM_STATUS__WFC_MODE__WIFI_PREFERRED;
            default:
                return PER_SIM_STATUS__WFC_MODE__UNKNOWN;
        }
    }
}
+0 −47
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.telephony.metrics;

import android.util.StatsEvent;

import com.android.internal.telephony.TelephonyStatsLog;

/**
 * Wrapper of generated TelephonyStatsLog class. Can be mocked during unit test.
 *
 * <p>Methods here have the same name/arguments/return as their counterparts in TelephonyStatsLog
 * and simply call their counterparts. Do not put any involved logic here as they cannot be
 * covered by unit test.
 */
public class TelephonyStatsLogHelper {
    /** Wraps TelephonyStatsLog.buildStatsEvent(...) for atom PER_SIM_STATUS. */
    public StatsEvent buildStatsEvent(
            int atomId,
            int simSlotIndex,
            int carrierId,
            int phoneNumberSourceUicc,
            int phoneNumberSourceCarrier,
            int phoneNumberSourceIms) {
        return TelephonyStatsLog.buildStatsEvent(
                atomId,
                simSlotIndex,
                carrierId,
                phoneNumberSourceUicc,
                phoneNumberSourceCarrier,
                phoneNumberSourceIms);
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -303,6 +303,8 @@ public class ContextFixture implements TestFixture<Context> {
                    return mLocationManager;
                case Context.NETWORK_POLICY_SERVICE:
                    return mNetworkPolicyManager;
                case Context.TELEPHONY_IMS_SERVICE:
                    return mImsManager;
                default:
                    return null;
            }
@@ -717,6 +719,7 @@ public class ContextFixture implements TestFixture<Context> {
    private final KeyguardManager mKeyguardManager = mock(KeyguardManager.class);
    private final VcnManager mVcnManager = mock(VcnManager.class);
    private final NetworkPolicyManager mNetworkPolicyManager = mock(NetworkPolicyManager.class);
    private final ImsManager mImsManager = mock(ImsManager.class);
    private final Configuration mConfiguration = new Configuration();
    private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
    private final SharedPreferences mSharedPreferences = PreferenceManager
+1 −72
Original line number Diff line number Diff line
@@ -16,13 +16,8 @@

package com.android.internal.telephony.metrics;

import static android.telephony.SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER;
import static android.telephony.SubscriptionManager.PHONE_NUMBER_SOURCE_IMS;
import static android.telephony.SubscriptionManager.PHONE_NUMBER_SOURCE_UICC;

import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_DATA_SERVICE_SWITCH;
import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE;
import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS;
import static com.android.internal.telephony.TelephonyStatsLog.SIM_SLOT_STATE;
import static com.android.internal.telephony.TelephonyStatsLog.SUPPORTED_RADIO_ACCESS_FAMILY;
import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_RAT_USAGE;
@@ -39,14 +34,12 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;

import android.app.StatsManager;
import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyManager;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.StatsEvent;

import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.SubscriptionController;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularDataServiceSwitch;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
@@ -91,7 +84,6 @@ public class MetricsCollectorTest extends TelephonyTest {

    // Mocked classes
    private Phone mSecondPhone;
    private TelephonyStatsLogHelper mTelephonyStatsLog;
    private UiccSlot mPhysicalSlot;
    private UiccSlot mEsimSlot;
    private UiccCard mActiveCard;
@@ -104,14 +96,13 @@ public class MetricsCollectorTest extends TelephonyTest {
    public void setUp() throws Exception {
        super.setUp(getClass().getSimpleName());
        mSecondPhone = mock(Phone.class);
        mTelephonyStatsLog = mock(TelephonyStatsLogHelper.class);
        mPhysicalSlot = mock(UiccSlot.class);
        mEsimSlot = mock(UiccSlot.class);
        mActiveCard = mock(UiccCard.class);
        mActivePort = mock(UiccPort.class);
        mServiceStateStats = mock(ServiceStateStats.class);
        mMetricsCollector =
                new MetricsCollector(mContext, mPersistAtomsStorage, mTelephonyStatsLog);
                new MetricsCollector(mContext, mPersistAtomsStorage);
        doReturn(mSST).when(mSecondPhone).getServiceStateTracker();
        doReturn(mServiceStateStats).when(mSST).getServiceStateStats();
    }
@@ -421,66 +412,4 @@ public class MetricsCollectorTest extends TelephonyTest {
        assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
        // TODO(b/153196254): verify atom contents
    }

    @Test
    @SmallTest
    public void onPullAtom_perSimStatus() throws Exception {
        // Make PhoneFactory.getPhones() return an array of two
        replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone, mSecondPhone});
        // phone 0 setup
        doReturn(0).when(mPhone).getPhoneId();
        doReturn(1).when(mPhone).getSubId();
        doReturn(100).when(mPhone).getCarrierId();
        doReturn("6506953210")
                .when(mSubscriptionController)
                .getPhoneNumber(1, PHONE_NUMBER_SOURCE_UICC);
        doReturn("")
                .when(mSubscriptionController)
                .getPhoneNumber(1, PHONE_NUMBER_SOURCE_CARRIER);
        doReturn("+16506953210")
                .when(mSubscriptionController)
                .getPhoneNumber(1, PHONE_NUMBER_SOURCE_IMS);
        SubscriptionInfo subscriptionInfo1 = mock(SubscriptionInfo.class);
        doReturn("us").when(subscriptionInfo1).getCountryIso();
        doReturn(subscriptionInfo1).when(mSubscriptionController).getSubscriptionInfo(1);
        // phone 1 setup
        doReturn(1).when(mSecondPhone).getPhoneId();
        doReturn(2).when(mSecondPhone).getSubId();
        doReturn(101).when(mSecondPhone).getCarrierId();
        doReturn("0123")
                .when(mSubscriptionController)
                .getPhoneNumber(2, PHONE_NUMBER_SOURCE_UICC);
        doReturn("16506950123")
                .when(mSubscriptionController)
                .getPhoneNumber(2, PHONE_NUMBER_SOURCE_CARRIER);
        doReturn("+16506950123")
                .when(mSubscriptionController)
                .getPhoneNumber(2, PHONE_NUMBER_SOURCE_IMS);
        SubscriptionInfo subscriptionInfo2 = mock(SubscriptionInfo.class);
        doReturn("us").when(subscriptionInfo2).getCountryIso();
        doReturn(subscriptionInfo2).when(mSubscriptionController).getSubscriptionInfo(2);
        List<StatsEvent> actualAtoms = new ArrayList<>();

        int result = mMetricsCollector.onPullAtom(PER_SIM_STATUS, actualAtoms);

        verify(mTelephonyStatsLog).buildStatsEvent(
                PER_SIM_STATUS, 0, 100, 1, 0, 1);
        verify(mTelephonyStatsLog).buildStatsEvent(
                PER_SIM_STATUS, 1, 101, 1, 2, 2);
        assertThat(actualAtoms).hasSize(2);
        assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
    }

    @Test
    @SmallTest
    public void onPullAtom_perSimStatus_noSubscriptionController_skip() throws Exception {
        // Make SubscriptionController.getInstance() return null
        replaceInstance(SubscriptionController.class, "sInstance", null, null);
        List<StatsEvent> actualAtoms = new ArrayList<>();

        int result = mMetricsCollector.onPullAtom(PER_SIM_STATUS, actualAtoms);

        assertThat(actualAtoms).isEmpty();
        assertThat(result).isEqualTo(StatsManager.PULL_SKIP);
    }
}
Loading