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

Commit 5b388a03 authored by Michele Berionne's avatar Michele Berionne Committed by Chi Zhang
Browse files

Add metrics for carrier ID matching

Bug: 169273187
Test: Manual testing
Merged-In: Ib0915eb1de47018b2850048e1a5c725e1a26bb36
Change-Id: Iba65f01fcd4f86b1552a3b075f39fe39f32e19e0
parent 88a0cb33
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ option java_outer_classname = "PersistAtomsProto";

// Holds atoms to store on persist storage in case of power cycle or process crash.
// NOTE: using int64 rather than google.protobuf.Timestamp for timestamps simplifies implementation.
// Next id: 9
// Next id: 11
message PersistAtoms {
    /* Aggregated RAT usage during the call. */
    repeated RawVoiceCallRatUsage raw_voice_call_rat_usage = 1;
@@ -48,6 +48,12 @@ message PersistAtoms {

    /* Timestamp of last incoming_sms pull. */
    optional int64 outgoing_sms_pull_timestamp_millis = 8;

    /* List of carrier ID mismatch events already sent. */
    repeated CarrierIdMismatch carrier_id_mismatch = 9;

    /* Last version of carrier ID table sent. */
    optional int32 carrier_id_table_version = 10;
}

// The canonical versions of the following enums live in:
@@ -127,3 +133,9 @@ message OutgoingSms {
    optional int64 message_id = 12;
    optional int32 retry_id = 13;
}

message CarrierIdMismatch {
    optional string mcc_mnc = 1;
    optional string gid1 = 2;
    optional string spn = 3;
}
+23 −6
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@
package com.android.internal.telephony;

import static android.provider.Telephony.CarrierId;
import static android.provider.Telephony.Carriers.CONTENT_URI;

import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -41,6 +40,7 @@ import android.util.LocalLog;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.metrics.CarrierIdMatchStats;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.telephony.uicc.IccRecords;
import com.android.internal.telephony.uicc.UiccController;
@@ -78,6 +78,8 @@ public class CarrierResolver extends Handler {
    private static final String TEST_ACTION = "com.android.internal.telephony"
            + ".ACTION_TEST_OVERRIDE_CARRIER_ID";

    // cached version of the carrier list, so that we don't need to re-query it every time.
    private Integer mCarrierListVersion;
    // cached matching rules based mccmnc to speed up resolution
    private List<CarrierMatchingRule> mCarrierMatchingRulesOnMccMnc = new ArrayList<>();
    // cached carrier Id
@@ -275,6 +277,8 @@ public class CarrierResolver extends Handler {
                handleSimLoaded();
                break;
            case CARRIER_ID_DB_UPDATE_EVENT:
                // clean the cached carrier list version, so that a new one will be queried.
                mCarrierListVersion = null;
                loadCarrierMatchingRulesOnMccMnc(true /* update carrier config*/);
                break;
            case PREFER_APN_UPDATE_EVENT:
@@ -327,6 +331,9 @@ public class CarrierResolver extends Handler {
                        mCarrierMatchingRulesOnMccMnc.add(makeCarrierMatchingRule(cursor));
                    }
                    matchSubscriptionCarrier(updateCarrierConfig);

                    // Generate metrics related to carrier ID table version.
                    CarrierIdMatchStats.sendCarrierIdTableVersion(getCarrierListVersion());
                }
            } finally {
                if (cursor != null) {
@@ -931,14 +938,24 @@ public class CarrierResolver extends Handler {
        TelephonyMetrics.getInstance().writeCarrierIdMatchingEvent(
                mPhone.getPhoneId(), getCarrierListVersion(), mCarrierId,
                unknownMccmncToLog, unknownGid1ToLog, simInfo);

        // Generate statsd metrics only when MCC/MNC is unknown or there is no match for GID1.
        if (unknownMccmncToLog != null || unknownGid1ToLog != null) {
            CarrierIdMatchStats.onCarrierIdMismatch(
                    mCarrierId, unknownMccmncToLog, unknownGid1ToLog, subscriptionRule.spn);
        }
    }

    public int getCarrierListVersion() {
        // Use the cached value if it exists, otherwise retrieve it.
        if (mCarrierListVersion == null) {
            final Cursor cursor = mContext.getContentResolver().query(
                    Uri.withAppendedPath(CarrierId.All.CONTENT_URI,
                    "get_version"), null, null, null);
            cursor.moveToFirst();
        return cursor.getInt(0);
            mCarrierListVersion = cursor.getInt(0);
        }
        return mCarrierListVersion;
    }

    public int getCarrierId() {
+63 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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 com.android.internal.telephony.TelephonyStatsLog.CARRIER_ID_MISMATCH_EVENT;
import static com.android.internal.telephony.TelephonyStatsLog.CARRIER_ID_TABLE_UPDATE;

import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.TelephonyStatsLog;
import com.android.internal.telephony.nano.PersistAtomsProto.CarrierIdMismatch;
import com.android.telephony.Rlog;

/** Metrics for the carrier id matching. */
public class CarrierIdMatchStats {
    private static final String TAG = CarrierIdMatchStats.class.getSimpleName();

    private CarrierIdMatchStats() { }

    /** Generate metrics when carrier ID mismatch occurs. */
    public static void onCarrierIdMismatch(int cid, String mccMnc, String gid1, String spn) {
        PersistAtomsStorage storage = PhoneFactory.getMetricsCollector().getAtomsStorage();

        CarrierIdMismatch carrierIdMismatch = new CarrierIdMismatch();
        carrierIdMismatch.mccMnc = nullToEmpty(mccMnc);
        carrierIdMismatch.gid1 = nullToEmpty(gid1);
        carrierIdMismatch.spn = nullToEmpty(spn);

        // Add to storage and generate atom only if it was added (new SIM card).
        boolean isAdded = storage.addCarrierIdMismatch(carrierIdMismatch);
        if (isAdded) {
            Rlog.d(TAG, "New carrier ID mismatch event: " + carrierIdMismatch.toString());
            TelephonyStatsLog.write(CARRIER_ID_MISMATCH_EVENT, cid, mccMnc, gid1, spn);
        }
    }

    /** Generate metrics for the carrier ID table version. */
    public static void sendCarrierIdTableVersion(int carrierIdTableVersion) {
        PersistAtomsStorage storage = PhoneFactory.getMetricsCollector().getAtomsStorage();

        if (storage.setCarrierIdTableVersion(carrierIdTableVersion)) {
            Rlog.d(TAG, "New carrier ID table version: " + carrierIdTableVersion);
            TelephonyStatsLog.write(CARRIER_ID_TABLE_UPDATE, carrierIdTableVersion);
        }
    }

    private static String nullToEmpty(String string) {
        return string != null ? string : "";
    }
}
+28 −0
Original line number Diff line number Diff line
@@ -16,10 +16,12 @@

package com.android.internal.telephony.metrics;

import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID_LIST_VERSION;
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;

import static com.android.internal.telephony.TelephonyStatsLog.CARRIER_ID_TABLE_VERSION;
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.SIM_SLOT_STATE;
@@ -99,6 +101,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
            registerAtom(VOICE_CALL_SESSION, POLICY_PULL_DAILY);
            registerAtom(INCOMING_SMS, POLICY_PULL_DAILY);
            registerAtom(OUTGOING_SMS, POLICY_PULL_DAILY);
            registerAtom(CARRIER_ID_TABLE_VERSION, null);
            Rlog.d(TAG, "registered");
        } else {
            Rlog.e(TAG, "could not get StatsManager, atoms not registered");
@@ -135,6 +138,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
                return pullIncomingSms(data);
            case OUTGOING_SMS:
                return pullOutgoingSms(data);
            case CARRIER_ID_TABLE_VERSION:
                return pullCarrierIdTableVersion(data);
            default:
                Rlog.e(TAG, String.format("unexpected atom ID %d", atomTag));
                return StatsManager.PULL_SKIP;
@@ -187,6 +192,29 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
        return StatsManager.PULL_SUCCESS;
    }

    private static int pullCarrierIdTableVersion(List<StatsEvent> data) {
        int version = UNKNOWN_CARRIER_ID_LIST_VERSION;
        // All phones should have the same version of the carrier ID table, so only query
        // the first one.
        try {
            Phone phone = PhoneFactory.getPhone(0);
            if (phone != null) {
                version = phone.getCarrierIdListVersion();
            }
        } catch (IllegalStateException e) {
            // Nothing to do
        }

        if (version == UNKNOWN_CARRIER_ID_LIST_VERSION) {
            return StatsManager.PULL_SKIP;
        } else {
            data.add(
                    StatsEvent.newBuilder()
                            .setAtomId(CARRIER_ID_TABLE_VERSION).writeInt(version).build());
            return StatsManager.PULL_SUCCESS;
        }
    }

    private int pullVoiceCallRatUsages(List<StatsEvent> data) {
        RawVoiceCallRatUsage[] usages = mStorage.getVoiceCallRatUsages(MIN_COOLDOWN_MILLIS);
        if (usages != null) {
+63 −0
Original line number Diff line number Diff line
@@ -18,8 +18,10 @@ package com.android.internal.telephony.metrics;

import android.annotation.Nullable;
import android.content.Context;
import android.telephony.TelephonyManager;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.nano.PersistAtomsProto.CarrierIdMismatch;
import com.android.internal.telephony.nano.PersistAtomsProto.IncomingSms;
import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms;
import com.android.internal.telephony.nano.PersistAtomsProto.PersistAtoms;
@@ -54,6 +56,12 @@ public class PersistAtomsStorage {
     */
    private static final int MAX_NUM_SMS = 25;

    /**
     * Maximum number of carrier ID mismatch events stored on the device to avoid sending
     * duplicated metrics.
     */
    private static final int MAX_CARRIER_ID_MISMATCH = 40;

    /** Stores persist atoms and persist states of the puller. */
    @VisibleForTesting protected final PersistAtoms mAtoms;

@@ -133,6 +141,53 @@ public class PersistAtomsStorage {
        return result;
    }

    /**
     * Adds a new carrier ID mismatch event to the storage.
     *
     * @return true if the item was not present and was added to the persistent storage, false
     * otherwise.
     */
    public synchronized boolean addCarrierIdMismatch(CarrierIdMismatch carrierIdMismatch) {
        // Check if the details of the SIM cards are already present and in case return.
        for (int i = 0; i < mAtoms.carrierIdMismatch.length; i++) {
            if (mAtoms.carrierIdMismatch[i].mccMnc.equals(carrierIdMismatch.mccMnc)
                    && mAtoms.carrierIdMismatch[i].gid1.equals(carrierIdMismatch.gid1)
                    && mAtoms.carrierIdMismatch[i].spn.equals(carrierIdMismatch.spn)) {
                return false;
            }
        }
        // Add the new CarrierIdMismatch at the end of the array, so that the same atom will not be
        // sent again in future.
        if (mAtoms.carrierIdMismatch.length == MAX_CARRIER_ID_MISMATCH) {
            System.arraycopy(
                    mAtoms.carrierIdMismatch, 1,
                    mAtoms.carrierIdMismatch, 0,
                    MAX_CARRIER_ID_MISMATCH - 1);
            mAtoms.carrierIdMismatch[MAX_CARRIER_ID_MISMATCH - 1] = carrierIdMismatch;
        } else {
            int newLength = mAtoms.carrierIdMismatch.length + 1;
            mAtoms.carrierIdMismatch = Arrays.copyOf(mAtoms.carrierIdMismatch, newLength);
            mAtoms.carrierIdMismatch[newLength - 1] = carrierIdMismatch;
        }
        saveAtomsToFile();
        return true;
    }

    /**
     * Stores the version of the carrier ID matching table.
     *
     * @return true if the version is newer than last available version, false otherwise.
     */
    public synchronized boolean setCarrierIdTableVersion(int carrierIdTableVersion) {
        if (mAtoms.carrierIdTableVersion < carrierIdTableVersion) {
            mAtoms.carrierIdTableVersion = carrierIdTableVersion;
            saveAtomsToFile();
            return true;
        } else {
            return false;
        }
    }

    /**
     * Returns and clears the voice call sessions if last pulled longer than {@code
     * minIntervalMillis} ago, otherwise returns {@code null}.
@@ -234,6 +289,13 @@ public class PersistAtomsStorage {
                atomsFromFile.outgoingSms =
                        Arrays.copyOf(atomsFromFile.outgoingSms, MAX_NUM_SMS);
            }
            if (atomsFromFile.carrierIdMismatch == null) {
                atomsFromFile.carrierIdMismatch = new CarrierIdMismatch[0];
            }
            if (atomsFromFile.carrierIdMismatch.length > MAX_CARRIER_ID_MISMATCH) {
                atomsFromFile.carrierIdMismatch =
                        Arrays.copyOf(atomsFromFile.carrierIdMismatch, MAX_CARRIER_ID_MISMATCH);
            }
            // out of caution, set timestamps to now if they are missing
            if (atomsFromFile.rawVoiceCallRatUsagePullTimestampMillis == 0L) {
                atomsFromFile.rawVoiceCallRatUsagePullTimestampMillis = getWallTimeMillis();
@@ -272,6 +334,7 @@ public class PersistAtomsStorage {
        atoms.voiceCallSessionPullTimestampMillis = currentTime;
        atoms.incomingSmsPullTimestampMillis = currentTime;
        atoms.outgoingSmsPullTimestampMillis = currentTime;
        atoms.carrierIdTableVersion = TelephonyManager.UNKNOWN_CARRIER_ID_LIST_VERSION;
        Rlog.d(TAG, "created new PersistAtoms");
        return atoms;
    }