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

Commit 088f3ed9 authored by Ling Ma's avatar Ling Ma
Browse files

Add handover failure cause to data call session

Design doc: https://docs.google.com/document/d/1k5DRZEvr-3H3R0W__HWURp20x8LfT9QvEljTb89vlQA/edit?usp=sharing

Change-Id: I00c8974c7b62605bc753b21fa82c7cb8f96a8997
Bug: 222113115
Test: manual
parent 68098a11
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -284,6 +284,7 @@ message DataCallSession {
    optional int64 duration_minutes = 17;
    optional bool ongoing = 18;
    optional int32 band_at_end = 19;
    repeated int32 handover_failure_causes = 20;
}

message CellularServiceState {
+1 −0
Original line number Diff line number Diff line
@@ -2851,6 +2851,7 @@ public class DataNetwork extends StateMachine {
            mDataNetworkCallback.invokeFromExecutor(
                    () -> mDataNetworkCallback.onHandoverFailed(DataNetwork.this,
                            mFailCause, retry, handoverFailureMode));
            mDataCallSessionStats.onHandoverFailure(mFailCause);
        }

        // No matter handover succeeded or not, transit back to connected state.
+46 −13
Original line number Diff line number Diff line
@@ -44,11 +44,13 @@ import com.android.internal.telephony.SubscriptionController;
import com.android.internal.telephony.nano.PersistAtomsProto.DataCallSession;
import com.android.telephony.Rlog;

import java.util.Arrays;
import java.util.Random;

/** Collects data call change events per DataConnection for the pulled atom. */
public class DataCallSessionStats {
    private static final String TAG = DataCallSessionStats.class.getSimpleName();
    private static final int SIZE_LIMIT_HANDOVER_FAILURE_CAUSES = 15;

    private final Phone mPhone;
    private long mStartTime;
@@ -112,12 +114,8 @@ public class DataCallSessionStats {
                    (int) Math.min(response.getRetryDurationMillis(), Integer.MAX_VALUE);
            // If setup has failed, then store the atom
            if (failureCause != DataFailCause.NONE) {
                mDataCallSession.oosAtEnd = getIsOos();
                mDataCallSession.setupFailed = true;
                mDataCallSession.ongoing = false;
                PhoneFactory.getMetricsCollector().unregisterOngoingDataCallStat(this);
                mAtomsStorage.addDataCallSession(mDataCallSession);
                mDataCallSession = null;
                endDataCallSession();
            }
        }
    }
@@ -168,14 +166,28 @@ public class DataCallSessionStats {
            return;
        }
        mDataCallSession.failureCause = failureCause;
        mDataCallSession.oosAtEnd = getIsOos();
        mDataCallSession.ongoing = false;
        mDataCallSession.durationMinutes = convertMillisToMinutes(getTimeMillis() - mStartTime);
        // store for the data call list event, after DataCall is disconnected and entered into
        // inactive mode
        PhoneFactory.getMetricsCollector().unregisterOngoingDataCallStat(this);
        mAtomsStorage.addDataCallSession(mDataCallSession);
        mDataCallSession = null;
        endDataCallSession();
    }

    /**
     * Updates the atom when a handover fails. Note we only record distinct failure causes, as in
     * most cases retry failures are due to the same cause.
     *
     * @param failureCause failure cause as per android.telephony.DataFailCause
     */
    public synchronized void onHandoverFailure(@DataFailureCause int failureCause) {
        if (mDataCallSession != null
                && mDataCallSession.handoverFailureCauses.length
                < SIZE_LIMIT_HANDOVER_FAILURE_CAUSES) {
            int[] failureCauses = mDataCallSession.handoverFailureCauses;
            for (int cause : failureCauses) {
                if (failureCause == cause) return;
            }
            mDataCallSession.handoverFailureCauses = Arrays.copyOf(
                    failureCauses, failureCauses.length + 1);
            mDataCallSession.handoverFailureCauses[failureCauses.length] = failureCause;
        }
    }

    /**
@@ -199,7 +211,13 @@ public class DataCallSessionStats {
        }
    }

    /** Add the on-going data call segment to the atom storage. */
    /**
     * Take a snapshot of the on-going data call segment to add to the atom storage.
     *
     * Note the following fields are reset after the snapshot:
     * - rat switch count
     * - handover failure causes
     */
    public synchronized void conclude() {
        if (mDataCallSession != null) {
            DataCallSession call = copyOf(mDataCallSession);
@@ -207,10 +225,22 @@ public class DataCallSessionStats {
            call.durationMinutes = convertMillisToMinutes(nowMillis - mStartTime);
            mStartTime = nowMillis;
            mDataCallSession.ratSwitchCount = 0L;
            mDataCallSession.handoverFailureCauses = new int[0];
            mAtomsStorage.addDataCallSession(call);
        }
    }

    /** Put the current data call to an end after being uploaded to AtomStorage. */
    private void endDataCallSession() {
        mDataCallSession.oosAtEnd = getIsOos();
        mDataCallSession.ongoing = false;
        // store for the data call list event, after DataCall is disconnected and entered into
        // inactive mode
        PhoneFactory.getMetricsCollector().unregisterOngoingDataCallStat(this);
        mAtomsStorage.addDataCallSession(mDataCallSession);
        mDataCallSession = null;
    }

    private static long convertMillisToMinutes(long millis) {
        return Math.round(millis / 60000.0);
    }
@@ -235,6 +265,8 @@ public class DataCallSessionStats {
        copy.durationMinutes = call.durationMinutes;
        copy.ongoing = call.ongoing;
        copy.bandAtEnd = call.bandAtEnd;
        copy.handoverFailureCauses = Arrays.copyOf(call.handoverFailureCauses,
                call.handoverFailureCauses.length);
        return copy;
    }

@@ -257,6 +289,7 @@ public class DataCallSessionStats {
        proto.deactivateReason = DATA_CALL_SESSION__DEACTIVATE_REASON__DEACTIVATE_REASON_UNKNOWN;
        proto.durationMinutes = 0;
        proto.ongoing = true;
        proto.handoverFailureCauses = new int[0];
        return proto;
    }

+2 −1
Original line number Diff line number Diff line
@@ -811,7 +811,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
                dataCallSession.deactivateReason,
                round(dataCallSession.durationMinutes, DURATION_BUCKET_MILLIS / MINUTE_IN_MILLIS),
                dataCallSession.ongoing,
                dataCallSession.bandAtEnd);
                dataCallSession.bandAtEnd,
                dataCallSession.handoverFailureCauses);
    }

    private static StatsEvent buildStatsEvent(ImsRegistrationStats stats) {
+4 −0
Original line number Diff line number Diff line
@@ -678,6 +678,10 @@ public class PersistAtomsStorage {
            DataCallSession[] previousDataCallSession = mAtoms.dataCallSession;
            mAtoms.dataCallSession = new DataCallSession[0];
            saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_GET_MILLIS);
            for (DataCallSession dataCallSession : previousDataCallSession) {
                // sort to de-correlate any potential pattern for UII concern
                Arrays.sort(dataCallSession.handoverFailureCauses);
            }
            return previousDataCallSession;
        } else {
            return null;