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

Commit 99d42e84 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add count and logic for sms metrics." into tm-qpr-dev

parents ba7bd6e4 03720395
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -248,6 +248,10 @@ message IncomingSms {
    optional bool is_esim = 12;
    optional int32 carrier_id = 13;
    optional int64 message_id = 14;
    optional int32 count = 15;

    // Internal use only
    optional int32 hashCode = 10001;
}

message OutgoingSms {
@@ -265,6 +269,10 @@ message OutgoingSms {
    optional int64 message_id = 12;
    optional int32 retry_id = 13;
    optional int64 interval_millis = 14;
    optional int32 count = 15;

    // Internal use only
    optional int32 hashCode = 10001;
}

message CarrierIdMismatch {
+4 −2
Original line number Diff line number Diff line
@@ -787,7 +787,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
                sms.isMultiSim,
                sms.isEsim,
                sms.carrierId,
                sms.messageId);
                sms.messageId,
                sms.count);
    }

    private static StatsEvent buildStatsEvent(OutgoingSms sms) {
@@ -806,7 +807,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
                sms.carrierId,
                sms.messageId,
                sms.retryId,
                sms.intervalMillis);
                sms.intervalMillis,
                sms.count);
    }

    private static StatsEvent buildStatsEvent(DataCallSession dataCallSession) {
+95 −3
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager.NetworkTypeBitMask;
import android.util.SparseIntArray;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.nano.PersistAtomsProto.CarrierIdMismatch;
@@ -257,6 +258,7 @@ public class PersistAtomsStorage {

    /** Adds an incoming SMS to the storage. */
    public synchronized void addIncomingSms(IncomingSms sms) {
        sms.hashCode = SmsStats.getSmsHashCode(sms);
        mAtoms.incomingSms = insertAtRandomPlace(mAtoms.incomingSms, sms, mMaxNumSms);
        saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS);

@@ -266,6 +268,7 @@ public class PersistAtomsStorage {

    /** Adds an outgoing SMS to the storage. */
    public synchronized void addOutgoingSms(OutgoingSms sms) {
        sms.hashCode = SmsStats.getSmsHashCode(sms);
        // Update the retry id, if needed, so that it's unique and larger than all
        // previous ones. (this algorithm ignores the fact that some SMS atoms might
        // be dropped due to limit in size of the array).
@@ -1682,8 +1685,9 @@ public class PersistAtomsStorage {
    }

    /**
     * Inserts a new element in a random position in an array with a maximum size, replacing the
     * least recent item if possible.
     * Inserts a new element in a random position in an array with a maximum size.
     *
     * <p>If the array is full, merge with existing item if possible or replace one item randomly.
     */
    private static <T> T[] insertAtRandomPlace(T[] storage, T instance, int maxLength) {
        final int newLength = storage.length + 1;
@@ -1692,7 +1696,11 @@ public class PersistAtomsStorage {
        if (newLength == 1) {
            result[0] = instance;
        } else if (arrayFull) {
            if (instance instanceof OutgoingSms || instance instanceof IncomingSms) {
                mergeSmsOrEvictInFullStorage(result, instance);
            } else {
                result[findItemToEvict(storage)] = instance;
            }
        } else {
            // insert at random place (by moving the item at the random place to the end)
            int insertAt = sRandom.nextInt(newLength);
@@ -1702,6 +1710,90 @@ public class PersistAtomsStorage {
        return result;
    }

    /**
     * Merge new sms in a full storage.
     *
     * <p>If new sms is similar to old sms, merge them.
     * If not, merge 2 old similar sms and add the new sms.
     * If not, replace old sms with the lowest count.
     */
    private static <T> void mergeSmsOrEvictInFullStorage(T[] storage, T instance) {
        // key: hashCode, value: smsIndex
        SparseIntArray map = new SparseIntArray();
        int smsIndex1 = -1;
        int smsIndex2 = -1;
        int indexLowestCount = -1;
        int minCount = Integer.MAX_VALUE;

        for (int i = 0; i < storage.length; i++) {
            // If the new SMS can be merged to an existing item, merge it and return immediately.
            if (areSmsMergeable(storage[i], instance)) {
                storage[i] = mergeSms(storage[i], instance);
                return;
            }

            // Keep sms index with lowest count to evict, in case we cannot merge any 2 messages.
            int smsCount = getSmsCount(storage[i]);
            if (smsCount < minCount) {
                indexLowestCount = i;
                minCount = smsCount;
            }

            // Find any 2 messages in the storage that can be merged together.
            if (smsIndex1 != -1) {
                int smsHashCode = getSmsHashCode(storage[i]);
                if (map.indexOfKey(smsHashCode) < 0) {
                    map.append(smsHashCode, i);
                } else {
                    smsIndex1 = map.get(smsHashCode);
                    smsIndex2 = i;
                }
            }
        }

        // Merge 2 similar old sms and add the new sms
        if (smsIndex1 != -1) {
            storage[smsIndex1] = mergeSms(storage[smsIndex1], storage[smsIndex2]);
            storage[smsIndex2] = instance;
            return;
        }

        // Or replace old sms that has the lowest count
        storage[indexLowestCount] = instance;
        return;
    }

    private static <T> int getSmsHashCode(T sms) {
        return sms instanceof OutgoingSms
                ? ((OutgoingSms) sms).hashCode : ((IncomingSms) sms).hashCode;
    }

    private static <T> int getSmsCount(T sms) {
        return sms instanceof OutgoingSms
                ? ((OutgoingSms) sms).count : ((IncomingSms) sms).count;
    }

    /** Compares 2 SMS hash codes to check if they can be clubbed together in the metrics. */
    private static <T> boolean areSmsMergeable(T instance1, T instance2) {
        return getSmsHashCode(instance1) == getSmsHashCode(instance2);
    }

    /** Merges sms2 data on top of sms1 and returns the merged value. */
    private static <T> T mergeSms(T sms1, T sms2) {
        if (sms1 instanceof OutgoingSms) {
            OutgoingSms tSms1 = (OutgoingSms) sms1;
            OutgoingSms tSms2 = (OutgoingSms) sms2;
            tSms1.intervalMillis = (tSms1.intervalMillis * tSms1.count
                    + tSms2.intervalMillis * tSms2.count) / (tSms1.count + tSms2.count);
            tSms1.count += tSms2.count;
        } else if (sms1 instanceof IncomingSms) {
            IncomingSms tSms1 = (IncomingSms) sms1;
            IncomingSms tSms2 = (IncomingSms) sms2;
            tSms1.count += tSms2.count;
        }
        return sms1;
    }

    /** Returns index of the item suitable for eviction when the array is full. */
    private static <T> int findItemToEvict(T[] array) {
        if (array instanceof CellularServiceState[]) {
+23 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ import com.android.internal.telephony.nano.PersistAtomsProto.IncomingSms;
import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms;
import com.android.telephony.Rlog;

import java.util.Objects;
import java.util.Random;

/** Collects sms events per phone ID for the pulled atom. */
@@ -214,6 +215,7 @@ public class SmsStats {
        // Message ID is initialized with random number, as it is not available for all incoming
        // SMS messages (e.g. those handled by OS or error cases).
        proto.messageId = RANDOM.nextLong();
        proto.count = 1;
        return proto;
    }

@@ -238,6 +240,7 @@ public class SmsStats {
        // in the persistent storage.
        proto.retryId = 0;
        proto.intervalMillis = intervalMillis;
        proto.count = 1;
        return proto;
    }

@@ -304,6 +307,26 @@ public class SmsStats {
        }
    }

    /**
     * Returns a hash value to identify messages that are identical for the purpose of merging them
     * together when storage is full.
     */
    static int getSmsHashCode(OutgoingSms sms) {
        return Objects.hash(sms.smsFormat, sms.smsTech, sms.rat, sms.sendResult, sms.errorCode,
                    sms.isRoaming, sms.isFromDefaultApp, sms.simSlotIndex, sms.isMultiSim,
                    sms.isEsim, sms.carrierId);
    }

    /**
     * Returns a hash value to identify messages that are identical for the purpose of merging them
     * together when storage is full.
     */
    static int getSmsHashCode(IncomingSms sms) {
        return Objects.hash(sms.smsFormat, sms.smsTech, sms.rat, sms.smsType,
            sms.totalParts, sms.receivedParts, sms.blocked, sms.error,
            sms.isRoaming, sms.simSlotIndex, sms.isMultiSim, sms.isEsim, sms.carrierId);
    }

    private int getPhoneId() {
        Phone phone = mPhone;
        if (mPhone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) {