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

Commit 40df8ade authored by Chi Zhang's avatar Chi Zhang Committed by Automerger Merge Worker
Browse files

Log service state to statsd. am: f2391e63 am: 0e21bcbe

Original change: https://android-review.googlesource.com/c/platform/frameworks/opt/telephony/+/1544672

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I444712e70165d95f5492ff86e14fce52555ea5b8
parents 1899ece2 0e21bcbe
Loading
Loading
Loading
Loading
+41 −3
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: 13
// Next id: 17
message PersistAtoms {
    /* Aggregated RAT usage during the call. */
    repeated RawVoiceCallRatUsage raw_voice_call_rat_usage = 1;
@@ -60,6 +60,18 @@ message PersistAtoms {

    /* Timestamp of last data_call_session pull. */
    optional int64 data_call_session_pull_timestamp_millis = 12;

    /* Duration spent in each possible service state. */
    repeated CellularServiceState cellular_service_state = 13;

    /* Timestamp of last cellular_service_state pull. */
    optional int64 cellular_service_state_pull_timestamp_millis = 14;

    /* Switch count between data RATs. */
    repeated CellularDataServiceSwitch cellular_data_service_switch = 15;

    /* Timestamp of last cellular_data_service_switch pull. */
    optional int64 cellular_data_service_switch_pull_timestamp_millis = 16;
}

// The canonical versions of the following enums live in:
@@ -99,11 +111,10 @@ message VoiceCallSession {
    optional int64 setup_begin_millis = 10001;
}

// Internal use only
message RawVoiceCallRatUsage {
    optional int32 carrier_id = 1;
    optional int32 rat = 2;
    optional int64 total_duration_millis = 3;
    optional int64 total_duration_millis = 3; // Duration needs to be rounded when pulled
    optional int64 call_count = 4;
}

@@ -166,3 +177,30 @@ message DataCallSession {
    optional int64 duration_minutes = 17;
    optional bool ongoing = 18;
}

message CellularServiceState {
    optional int32 voice_rat = 1;
    optional int32 data_rat = 2;
    optional int32 voice_roaming_type = 3;
    optional int32 data_roaming_type = 4;
    optional bool is_endc = 5;
    optional int32 sim_slot_index = 6;
    optional bool is_multi_sim = 7;
    optional int32 carrier_id = 8;
    optional int64 total_time_millis = 9; // Duration needs to be rounded when pulled

    // Internal use only
    optional int64 last_used_millis = 10001;
}

message CellularDataServiceSwitch {
    optional int32 rat_from = 1;
    optional int32 rat_to = 2;
    optional int32 sim_slot_index = 3;
    optional bool is_multi_sim = 4;
    optional int32 carrier_id = 5;
    optional int32 switch_count = 6;

    // Internal use only
    optional int64 last_used_millis = 10001;
}
+19 −0
Original line number Diff line number Diff line
@@ -99,6 +99,7 @@ import com.android.internal.telephony.cdnr.CarrierDisplayNameResolver;
import com.android.internal.telephony.dataconnection.DataConnection;
import com.android.internal.telephony.dataconnection.DcTracker;
import com.android.internal.telephony.dataconnection.TransportManager;
import com.android.internal.telephony.metrics.ServiceStateStats;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
import com.android.internal.telephony.uicc.IccCardStatus.CardState;
@@ -481,6 +482,8 @@ public class ServiceStateTracker extends Handler {
    private static final int MS_PER_HOUR = 60 * 60 * 1000;
    private final NitzStateMachine mNitzState;

    private ServiceStateStats mServiceStateStats;

    /**
     * Holds the last NITZ signal received. Used only for trying to determine an MCC from a CDMA
     * SID.
@@ -647,6 +650,8 @@ public class ServiceStateTracker extends Handler {
        mPhone = phone;
        mCi = ci;

        mServiceStateStats = new ServiceStateStats(mPhone);

        mCdnr = new CarrierDisplayNameResolver(mPhone);

        mEriManager = TelephonyComponentFactory.getInstance().inject(EriManager.class.getName())
@@ -1717,6 +1722,7 @@ public class ServiceStateTracker extends Handler {
                        TelephonyMetrics.getInstance().writeServiceStateChanged(
                                mPhone.getPhoneId(), mSS);
                        mPhone.getVoiceCallSessionStats().onServiceStateChanged(mSS);
                        mServiceStateStats.onServiceStateChanged(mSS);
                    }
                }
                break;
@@ -2301,6 +2307,7 @@ public class ServiceStateTracker extends Handler {
                    TelephonyMetrics.getInstance().writeServiceStateChanged(
                            mPhone.getPhoneId(), mSS);
                    mPhone.getVoiceCallSessionStats().onServiceStateChanged(mSS);
                    mServiceStateStats.onServiceStateChanged(mSS);
                }

                if (mPhone.isPhoneTypeGsm()) {
@@ -3590,6 +3597,7 @@ public class ServiceStateTracker extends Handler {
        if (hasChanged || hasNrStateChanged) {
            TelephonyMetrics.getInstance().writeServiceStateChanged(mPhone.getPhoneId(), mSS);
            mPhone.getVoiceCallSessionStats().onServiceStateChanged(mSS);
            mServiceStateStats.onServiceStateChanged(mSS);
        }

        boolean shouldLogAttachedChange = false;
@@ -5905,6 +5913,17 @@ public class ServiceStateTracker extends Handler {
        tm.setDataNetworkTypeForPhone(mPhone.getPhoneId(), type);
    }

    /** Returns the {@link ServiceStateStats} for the phone tracked. */
    public ServiceStateStats getServiceStateStats() {
        return mServiceStateStats;
    }

    /** Replaces the {@link ServiceStateStats} for testing purposes. */
    @VisibleForTesting
    public void setServiceStateStats(ServiceStateStats serviceStateStats) {
        mServiceStateStats = serviceStateStats;
    }

    /**
     * Used to insert a ServiceState into the ServiceStateProvider as a ContentValues instance.
     *
+95 −22
Original line number Diff line number Diff line
@@ -16,12 +16,13 @@

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.CELLULAR_DATA_SERVICE_SWITCH;
import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE;
import static com.android.internal.telephony.TelephonyStatsLog.DATA_CALL_SESSION;
import static com.android.internal.telephony.TelephonyStatsLog.INCOMING_SMS;
import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SMS;
@@ -38,6 +39,8 @@ 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.nano.PersistAtomsProto.CellularDataServiceSwitch;
import com.android.internal.telephony.nano.PersistAtomsProto.CellularServiceState;
import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession;
import com.android.internal.telephony.nano.PersistAtomsProto.IncomingSms;
import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms;
@@ -97,6 +100,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
        mStorage = new PersistAtomsStorage(context);
        mStatsManager = (StatsManager) context.getSystemService(Context.STATS_MANAGER);
        if (mStatsManager != null) {
            registerAtom(CELLULAR_DATA_SERVICE_SWITCH, POLICY_PULL_DAILY);
            registerAtom(CELLULAR_SERVICE_STATE, POLICY_PULL_DAILY);
            registerAtom(SIM_SLOT_STATE, null);
            registerAtom(SUPPORTED_RADIO_ACCESS_FAMILY, null);
            registerAtom(VOICE_CALL_RAT_USAGE, POLICY_PULL_DAILY);
@@ -130,6 +135,10 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
    @Override
    public int onPullAtom(int atomTag, List<StatsEvent> data) {
        switch (atomTag) {
            case CELLULAR_DATA_SERVICE_SWITCH:
                return pullCellularDataServiceSwitch(data);
            case CELLULAR_SERVICE_STATE:
                return pullCellularServiceState(data);
            case SIM_SLOT_STATE:
                return pullSimSlotState(data);
            case SUPPORTED_RADIO_ACCESS_FAMILY:
@@ -178,16 +187,16 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
    }

    private static int pullSupportedRadioAccessFamily(List<StatsEvent> data) {
        long rafSupported = 0L;
        try {
        Phone[] phones = getPhonesIfAny();
        if (phones.length == 0) {
            return StatsManager.PULL_SKIP;
        }

        // The bitmask is defined in android.telephony.TelephonyManager.NetworkTypeBitMask
        long rafSupported = 0L;
        for (Phone phone : PhoneFactory.getPhones()) {
            rafSupported |= phone.getRadioAccessFamily();
        }
        } catch (IllegalStateException e) {
            // Phones have not been made yet
            return StatsManager.PULL_SKIP;
        }

        StatsEvent e =
                StatsEvent.newBuilder()
@@ -199,21 +208,13 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
    }

    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) {
        Phone[] phones = getPhonesIfAny();
        if (phones.length == 0) {
            return StatsManager.PULL_SKIP;
        } else {
            // All phones should have the same version of the carrier ID table, so only query the
            // first one.
            int version = phones[0].getCarrierIdListVersion();
            data.add(
                    StatsEvent.newBuilder()
                            .setAtomId(CARRIER_ID_TABLE_VERSION).writeInt(version).build());
@@ -291,11 +292,73 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
        }
    }

    private int pullCellularDataServiceSwitch(List<StatsEvent> data) {
        CellularDataServiceSwitch[] persistAtoms =
                mStorage.getCellularDataServiceSwitches(MIN_COOLDOWN_MILLIS);
        if (persistAtoms != null) {
            // list is already shuffled when instances were inserted
            Arrays.stream(persistAtoms)
                    .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom)));
            return StatsManager.PULL_SUCCESS;
        } else {
            Rlog.w(TAG, "CELLULAR_DATA_SERVICE_SWITCH pull too frequent, skipping");
            return StatsManager.PULL_SKIP;
        }
    }

    private int pullCellularServiceState(List<StatsEvent> data) {
        // Include the latest durations
        for (Phone phone : getPhonesIfAny()) {
            phone.getServiceStateTracker().getServiceStateStats().conclude();
        }

        CellularServiceState[] persistAtoms =
                mStorage.getCellularServiceStates(MIN_COOLDOWN_MILLIS);
        if (persistAtoms != null) {
            // list is already shuffled when instances were inserted
            Arrays.stream(persistAtoms)
                    .forEach(persistAtom -> data.add(buildStatsEvent(persistAtom)));
            return StatsManager.PULL_SUCCESS;
        } else {
            Rlog.w(TAG, "CELLULAR_SERVICE_STATE pull too frequent, skipping");
            return StatsManager.PULL_SKIP;
        }
    }

    /** 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);
    }

    private static StatsEvent buildStatsEvent(CellularDataServiceSwitch serviceSwitch) {
        return StatsEvent.newBuilder()
                .setAtomId(CELLULAR_DATA_SERVICE_SWITCH)
                .writeInt(serviceSwitch.ratFrom)
                .writeInt(serviceSwitch.ratTo)
                .writeInt(serviceSwitch.simSlotIndex)
                .writeBoolean(serviceSwitch.isMultiSim)
                .writeInt(serviceSwitch.carrierId)
                .writeInt(serviceSwitch.switchCount)
                .build();
    }

    private static StatsEvent buildStatsEvent(CellularServiceState state) {
        return StatsEvent.newBuilder()
                .setAtomId(CELLULAR_SERVICE_STATE)
                .writeInt(state.voiceRat)
                .writeInt(state.dataRat)
                .writeInt(state.voiceRoamingType)
                .writeInt(state.dataRoamingType)
                .writeBoolean(state.isEndc)
                .writeInt(state.simSlotIndex)
                .writeBoolean(state.isMultiSim)
                .writeInt(state.carrierId)
                .writeInt(
                        (int) (round(
                                state.totalTimeMillis, DURATION_BUCKET_MILLIS) / SECOND_IN_MILLIS))
                .build();
    }

    private static StatsEvent buildStatsEvent(RawVoiceCallRatUsage usage) {
        return StatsEvent.newBuilder()
                .setAtomId(VOICE_CALL_RAT_USAGE)
@@ -402,6 +465,16 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
                .build();
    }

    /** Returns all phones in {@link PhoneFactory}, or an empty array if phones not made yet. */
    private static Phone[] getPhonesIfAny() {
        try {
            return PhoneFactory.getPhones();
        } catch (IllegalStateException e) {
            // Phones have not been made yet
            return new Phone[0];
        }
    }

    /** Returns the value rounded to the bucket. */
    private static long round(long value, long bucket) {
        return ((value + bucket / 2) / bucket) * bucket;
Loading