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

Commit 4a5fd5ca authored by Michele Berionne's avatar Michele Berionne Committed by Android (Google) Code Review
Browse files

Merge "Add metrics for carrier ID matching"

parents 9bcf3ce7 da22daf0
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;
@@ -40,6 +39,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;
@@ -77,6 +77,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
@@ -274,6 +276,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();
                break;
            case PREFER_APN_UPDATE_EVENT:
@@ -326,6 +330,9 @@ public class CarrierResolver extends Handler {
                        mCarrierMatchingRulesOnMccMnc.add(makeCarrierMatchingRule(cursor));
                    }
                    matchSubscriptionCarrier();

                    // Generate metrics related to carrier ID table version.
                    CarrierIdMatchStats.sendCarrierIdTableVersion(getCarrierListVersion());
                }
            } finally {
                if (cursor != null) {
@@ -913,14 +920,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 : "";
    }
}
+26 −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;
@@ -100,6 +102,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");
@@ -136,6 +139,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;
@@ -182,6 +187,27 @@ 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(TelephonyStatsLog.buildStatsEvent(CARRIER_ID_TABLE_VERSION, version));
            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;
    }