Loading src/java/com/android/internal/telephony/SubscriptionController.java +5 −2 Original line number Diff line number Diff line Loading @@ -4586,9 +4586,12 @@ public class SubscriptionController extends ISub.Stub { } } // Internal helper method for implementing getPhoneNumber() API. /** * Implements getPhoneNumber() APIs, w/o permission check. * Can be used by other phone internal components. */ @Nullable private String getPhoneNumber(int subId, int source) { public String getPhoneNumber(int subId, int source) { if (source == SubscriptionManager.PHONE_NUMBER_SOURCE_UICC) { Phone phone = PhoneFactory.getPhone(getPhoneId(subId)); return phone != null ? phone.getLine1Number() : null; Loading src/java/com/android/internal/telephony/metrics/MetricsCollector.java +77 −8 Original line number Diff line number Diff line Loading @@ -16,6 +16,10 @@ 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; Loading @@ -33,6 +37,7 @@ import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_ import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_TERMINATION; import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS; import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SMS; import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS; import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT; import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS; import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS; Loading @@ -50,11 +55,14 @@ 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; Loading Loading @@ -86,6 +94,7 @@ 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; Loading Loading @@ -127,14 +136,24 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { .setCoolDownMillis(MIN_COOLDOWN_MILLIS) .build(); private PersistAtomsStorage mStorage; 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) { mStorage = new PersistAtomsStorage(context); this(context, new PersistAtomsStorage(context), new TelephonyStatsLogHelper()); } /** Allows dependency injection. Used during unit tests. */ @VisibleForTesting public MetricsCollector(Context context, PersistAtomsStorage storage, TelephonyStatsLogHelper telephonyStatsLog) { mStorage = storage; mTelephonyStatsLog = telephonyStatsLog; mStatsManager = (StatsManager) context.getSystemService(Context.STATS_MANAGER); if (mStatsManager != null) { registerAtom(CELLULAR_DATA_SERVICE_SWITCH, POLICY_PULL_DAILY); Loading Loading @@ -163,6 +182,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { registerAtom(UCE_EVENT_STATS, POLICY_PULL_DAILY); registerAtom(PRESENCE_NOTIFY_EVENT, POLICY_PULL_DAILY); registerAtom(GBA_EVENT, POLICY_PULL_DAILY); registerAtom(PER_SIM_STATUS, null); Rlog.d(TAG, "registered"); } else { Loading @@ -172,12 +192,6 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { mAirplaneModeStats = new AirplaneModeStats(context); } /** Replaces the {@link PersistAtomsStorage} backing the puller. Used during unit tests. */ @VisibleForTesting public void setPersistAtomsStorage(PersistAtomsStorage storage) { mStorage = storage; } /** * {@inheritDoc} * Loading Loading @@ -240,6 +254,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { return pullPresenceNotifyEvent(data); case GBA_EVENT: return pullGbaEvent(data); case PER_SIM_STATUS: return pullPerSimStatus(data); default: Rlog.e(TAG, String.format("unexpected atom ID %d", atomTag)); return StatsManager.PULL_SKIP; Loading Loading @@ -639,6 +655,59 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { } } private int pullPerSimStatus(List<StatsEvent> data) { SubscriptionController subscriptionController = SubscriptionController.getInstance(); if (subscriptionController == null) { return 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 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( PER_SIM_STATUS, phone.getPhoneId(), // simSlotIndex phone.getCarrierId(), // carrierId numberState[0], // phoneNumberSourceUicc numberState[1], // phoneNumberSourceCarrier numberState[2]); // phoneNumberSourceIms data.add(statsEvent); } return StatsManager.PULL_SUCCESS; } /** Registers a pulled atom ID {@code atomId} with optional {@code policy} for pulling. */ private void registerAtom(int atomId, @Nullable StatsManager.PullAtomMetadata policy) { mStatsManager.setPullAtomCallback(atomId, policy, ConcurrentUtils.DIRECT_EXECUTOR, this); Loading src/java/com/android/internal/telephony/metrics/TelephonyStatsLogHelper.java 0 → 100644 +47 −0 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); } } tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java +73 −2 Original line number Diff line number Diff line Loading @@ -16,8 +16,13 @@ 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; Loading @@ -28,17 +33,20 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.anyLong; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; 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; Loading Loading @@ -83,6 +91,7 @@ public class MetricsCollectorTest extends TelephonyTest { // b/153195691: we cannot verify the contents of StatsEvent as its getters are marked with @hide @Mock private Phone mSecondPhone; @Mock private TelephonyStatsLogHelper mTelephonyStatsLog; @Mock private UiccSlot mPhysicalSlot; @Mock private UiccSlot mEsimSlot; @Mock private UiccCard mActiveCard; Loading @@ -95,8 +104,8 @@ public class MetricsCollectorTest extends TelephonyTest { @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); mMetricsCollector = new MetricsCollector(mContext); mMetricsCollector.setPersistAtomsStorage(mPersistAtomsStorage); mMetricsCollector = new MetricsCollector(mContext, mPersistAtomsStorage, mTelephonyStatsLog); doReturn(mSST).when(mSecondPhone).getServiceStateTracker(); doReturn(mServiceStateStats).when(mSST).getServiceStateStats(); } Loading Loading @@ -405,4 +414,66 @@ 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
src/java/com/android/internal/telephony/SubscriptionController.java +5 −2 Original line number Diff line number Diff line Loading @@ -4586,9 +4586,12 @@ public class SubscriptionController extends ISub.Stub { } } // Internal helper method for implementing getPhoneNumber() API. /** * Implements getPhoneNumber() APIs, w/o permission check. * Can be used by other phone internal components. */ @Nullable private String getPhoneNumber(int subId, int source) { public String getPhoneNumber(int subId, int source) { if (source == SubscriptionManager.PHONE_NUMBER_SOURCE_UICC) { Phone phone = PhoneFactory.getPhone(getPhoneId(subId)); return phone != null ? phone.getLine1Number() : null; Loading
src/java/com/android/internal/telephony/metrics/MetricsCollector.java +77 −8 Original line number Diff line number Diff line Loading @@ -16,6 +16,10 @@ 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; Loading @@ -33,6 +37,7 @@ import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_ import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_TERMINATION; import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS; import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SMS; import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS; import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT; import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS; import static com.android.internal.telephony.TelephonyStatsLog.RCS_CLIENT_PROVISIONING_STATS; Loading @@ -50,11 +55,14 @@ 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; Loading Loading @@ -86,6 +94,7 @@ 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; Loading Loading @@ -127,14 +136,24 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { .setCoolDownMillis(MIN_COOLDOWN_MILLIS) .build(); private PersistAtomsStorage mStorage; 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) { mStorage = new PersistAtomsStorage(context); this(context, new PersistAtomsStorage(context), new TelephonyStatsLogHelper()); } /** Allows dependency injection. Used during unit tests. */ @VisibleForTesting public MetricsCollector(Context context, PersistAtomsStorage storage, TelephonyStatsLogHelper telephonyStatsLog) { mStorage = storage; mTelephonyStatsLog = telephonyStatsLog; mStatsManager = (StatsManager) context.getSystemService(Context.STATS_MANAGER); if (mStatsManager != null) { registerAtom(CELLULAR_DATA_SERVICE_SWITCH, POLICY_PULL_DAILY); Loading Loading @@ -163,6 +182,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { registerAtom(UCE_EVENT_STATS, POLICY_PULL_DAILY); registerAtom(PRESENCE_NOTIFY_EVENT, POLICY_PULL_DAILY); registerAtom(GBA_EVENT, POLICY_PULL_DAILY); registerAtom(PER_SIM_STATUS, null); Rlog.d(TAG, "registered"); } else { Loading @@ -172,12 +192,6 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { mAirplaneModeStats = new AirplaneModeStats(context); } /** Replaces the {@link PersistAtomsStorage} backing the puller. Used during unit tests. */ @VisibleForTesting public void setPersistAtomsStorage(PersistAtomsStorage storage) { mStorage = storage; } /** * {@inheritDoc} * Loading Loading @@ -240,6 +254,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { return pullPresenceNotifyEvent(data); case GBA_EVENT: return pullGbaEvent(data); case PER_SIM_STATUS: return pullPerSimStatus(data); default: Rlog.e(TAG, String.format("unexpected atom ID %d", atomTag)); return StatsManager.PULL_SKIP; Loading Loading @@ -639,6 +655,59 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback { } } private int pullPerSimStatus(List<StatsEvent> data) { SubscriptionController subscriptionController = SubscriptionController.getInstance(); if (subscriptionController == null) { return 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 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( PER_SIM_STATUS, phone.getPhoneId(), // simSlotIndex phone.getCarrierId(), // carrierId numberState[0], // phoneNumberSourceUicc numberState[1], // phoneNumberSourceCarrier numberState[2]); // phoneNumberSourceIms data.add(statsEvent); } return StatsManager.PULL_SUCCESS; } /** Registers a pulled atom ID {@code atomId} with optional {@code policy} for pulling. */ private void registerAtom(int atomId, @Nullable StatsManager.PullAtomMetadata policy) { mStatsManager.setPullAtomCallback(atomId, policy, ConcurrentUtils.DIRECT_EXECUTOR, this); Loading
src/java/com/android/internal/telephony/metrics/TelephonyStatsLogHelper.java 0 → 100644 +47 −0 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); } }
tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java +73 −2 Original line number Diff line number Diff line Loading @@ -16,8 +16,13 @@ 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; Loading @@ -28,17 +33,20 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.anyLong; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; 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; Loading Loading @@ -83,6 +91,7 @@ public class MetricsCollectorTest extends TelephonyTest { // b/153195691: we cannot verify the contents of StatsEvent as its getters are marked with @hide @Mock private Phone mSecondPhone; @Mock private TelephonyStatsLogHelper mTelephonyStatsLog; @Mock private UiccSlot mPhysicalSlot; @Mock private UiccSlot mEsimSlot; @Mock private UiccCard mActiveCard; Loading @@ -95,8 +104,8 @@ public class MetricsCollectorTest extends TelephonyTest { @Before public void setUp() throws Exception { super.setUp(getClass().getSimpleName()); mMetricsCollector = new MetricsCollector(mContext); mMetricsCollector.setPersistAtomsStorage(mPersistAtomsStorage); mMetricsCollector = new MetricsCollector(mContext, mPersistAtomsStorage, mTelephonyStatsLog); doReturn(mSST).when(mSecondPhone).getServiceStateTracker(); doReturn(mServiceStateStats).when(mSST).getServiceStateStats(); } Loading Loading @@ -405,4 +414,66 @@ 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); } }