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

Commit db6a07e2 authored by Aishwarya Mallampati's avatar Aishwarya Mallampati
Browse files

Implementation of premium sms metrics.

Bug: 243187341
Test: atest com.android.internal.telephony.metrics.MetricsCollectorTest
      atest com.android.internal.telephony.metrics.PersistAtomsStorageTest
      atest CtsTelephonyTestCases
Change-Id: Ie8e7c4ecc23f90d3c3b679f6db71065a588a2faa
parent f4d76e75
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -180,6 +180,12 @@ message PersistAtoms {

    /* Unmetered networks information. */
    repeated UnmeteredNetworks unmetered_networks = 52;

    /* Outgoing Short Code SMS statistics and information. */
    repeated OutgoingShortCodeSms outgoing_short_code_sms = 53;

    /* Timestamp of last outgoing_short_code_sms pull. */
    optional int64 outgoing_short_code_sms_pull_timestamp_millis = 54;
}

// The canonical versions of the following enums live in:
@@ -516,3 +522,9 @@ message UnmeteredNetworks {
    optional int32 carrier_id = 2;
    optional int64 unmetered_networks_bitmask = 3;
}

message OutgoingShortCodeSms {
    optional int32 category = 1;
    optional int32 xml_version = 2;
    optional int32 short_code_sms_count = 3;
}
 No newline at end of file
+6 −0
Original line number Diff line number Diff line
@@ -1861,6 +1861,12 @@ public abstract class SMSDispatcher extends Handler {
                                                trackers[0].mDestAddress, networkCountryIso));
            }

            if (smsCategory != SmsManager.SMS_CATEGORY_NOT_SHORT_CODE) {
                int xmlVersion = mSmsDispatchersController.getUsageMonitor()
                        .getShortCodeXmlFileVersion();
                mPhone.getSmsStats().onOutgoingShortCodeSms(smsCategory, xmlVersion);
            }

            if (smsCategory == SmsManager.SMS_CATEGORY_NOT_SHORT_CODE
                    || smsCategory == SmsManager.SMS_CATEGORY_FREE_SHORT_CODE
                    || smsCategory == SmsManager.SMS_CATEGORY_STANDARD_SHORT_CODE) {
+38 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -73,6 +74,8 @@ public class SmsUsageMonitor {

    private static final String SHORT_CODE_PATH = "/data/misc/sms/codes";

    private static final String SHORT_CODE_VERSION_PATH = "/data/misc/sms/metadata/version";

    /** Default checking period for SMS sent without user permission. */
    private static final int DEFAULT_SMS_CHECK_PERIOD = 60000;      // 1 minute

@@ -128,6 +131,8 @@ public class SmsUsageMonitor {
    /** Last modified time for pattern file */
    private long mPatternFileLastModified = 0;

    private int mPatternFileVersion = -1;

    private RoleManager mRoleManager;

    /** Directory for per-app SMS permission XML file. */
@@ -415,9 +420,11 @@ public class SmsUsageMonitor {
                    if (mPatternFile.exists()) {
                        if (DBG) Rlog.d(TAG, "Loading SMS Short Code patterns from file");
                        mCurrentPatternMatcher = getPatternMatcherFromFile(countryIso);
                        mPatternFileVersion = getPatternFileVersionFromFile();
                    } else {
                        if (DBG) Rlog.d(TAG, "Loading SMS Short Code patterns from resource");
                        mCurrentPatternMatcher = getPatternMatcherFromResource(countryIso);
                        mPatternFileVersion = -1;
                    }
                    mCurrentCountry = countryIso;
                }
@@ -655,6 +662,37 @@ public class SmsUsageMonitor {
        return false;
    }

    private int getPatternFileVersionFromFile() {
        File versionFile = new File(SHORT_CODE_VERSION_PATH);
        if (versionFile.exists()) {
            BufferedReader reader = null;
            try {
                reader = new BufferedReader(new FileReader(versionFile));
                String version = reader.readLine();
                if (version != null) {
                    return Integer.parseInt(version);
                }
            } catch (IOException e) {
                Rlog.e(TAG, "File reader exception reading short code "
                        + "pattern file version", e);
            } finally {
                try {
                    if (reader != null) {
                        reader.close();
                    }
                } catch (IOException e) {
                    Rlog.e(TAG, "File reader exception closing short code "
                            + "pattern file version reader", e);
                }
            }
        }
        return -1;
    }

    public int getShortCodeXmlFileVersion() {
        return mPatternFileVersion;
    }

    private static void log(String msg) {
        Rlog.d(TAG, msg);
    }
+26 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_
import static com.android.internal.telephony.TelephonyStatsLog.IMS_REGISTRATION_TERMINATION;
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.OUTGOING_SHORT_CODE_SMS;
import static com.android.internal.telephony.TelephonyStatsLog.PER_SIM_STATUS;
import static com.android.internal.telephony.TelephonyStatsLog.PRESENCE_NOTIFY_EVENT;
import static com.android.internal.telephony.TelephonyStatsLog.RCS_ACS_PROVISIONING_STATS;
@@ -69,6 +70,7 @@ import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTerm
import com.android.internal.telephony.nano.PersistAtomsProto.IncomingSms;
import com.android.internal.telephony.nano.PersistAtomsProto.NetworkRequestsV2;
import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms;
import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingShortCodeSms;
import com.android.internal.telephony.nano.PersistAtomsProto.PresenceNotifyEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.RcsAcsProvisioningStats;
import com.android.internal.telephony.nano.PersistAtomsProto.RcsClientProvisioningStats;
@@ -176,6 +178,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
            registerAtom(PRESENCE_NOTIFY_EVENT, POLICY_PULL_DAILY);
            registerAtom(GBA_EVENT, POLICY_PULL_DAILY);
            registerAtom(PER_SIM_STATUS, null);
            registerAtom(OUTGOING_SHORT_CODE_SMS, POLICY_PULL_DAILY);

            Rlog.d(TAG, "registered");
        } else {
@@ -251,6 +254,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
                return pullGbaEvent(data);
            case PER_SIM_STATUS:
                return pullPerSimStatus(data);
            case OUTGOING_SHORT_CODE_SMS:
                return pullOutgoingShortCodeSms(data);
            default:
                Rlog.e(TAG, String.format("unexpected atom ID %d", atomTag));
                return StatsManager.PULL_SKIP;
@@ -693,6 +698,19 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
        return result;
    }

    private int pullOutgoingShortCodeSms(List<StatsEvent> data) {
        OutgoingShortCodeSms[] outgoingShortCodeSmsList = mStorage
                .getOutgoingShortCodeSms(MIN_COOLDOWN_MILLIS);
        if (outgoingShortCodeSmsList != null) {
            // Outgoing short code SMS list is already shuffled when SMS were inserted
            Arrays.stream(outgoingShortCodeSmsList).forEach(sms -> data.add(buildStatsEvent(sms)));
            return StatsManager.PULL_SUCCESS;
        } else {
            Rlog.w(TAG, "OUTGOING_SHORT_CODE_SMS 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);
@@ -1026,6 +1044,14 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
                stats.count);
    }

    private static StatsEvent buildStatsEvent(OutgoingShortCodeSms shortCodeSms) {
        return TelephonyStatsLog.buildStatsEvent(
                OUTGOING_SHORT_CODE_SMS,
                shortCodeSms.category,
                shortCodeSms.xmlVersion,
                shortCodeSms.shortCodeSmsCount);
    }

    /** Returns all phones in {@link PhoneFactory}, or an empty array if phones not made yet. */
    private static Phone[] getPhonesIfAny() {
        try {
+57 −1
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import com.android.internal.telephony.nano.PersistAtomsProto.ImsRegistrationTerm
import com.android.internal.telephony.nano.PersistAtomsProto.IncomingSms;
import com.android.internal.telephony.nano.PersistAtomsProto.NetworkRequestsV2;
import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms;
import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingShortCodeSms;
import com.android.internal.telephony.nano.PersistAtomsProto.PersistAtoms;
import com.android.internal.telephony.nano.PersistAtomsProto.PresenceNotifyEvent;
import com.android.internal.telephony.nano.PersistAtomsProto.RcsAcsProvisioningStats;
@@ -159,6 +160,10 @@ public class PersistAtomsStorage {
    /** Maximum number of GBA Event to store between pulls. */
    private final int mMaxNumGbaEventStats;


     /** Maximum number of outgoing short code sms to store between pulls. */
    private final int mMaxOutgoingShortCodeSms;

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

@@ -207,6 +212,7 @@ public class PersistAtomsStorage {
            mMaxNumUceEventStats = 5;
            mMaxNumPresenceNotifyEventStats = 10;
            mMaxNumGbaEventStats = 5;
            mMaxOutgoingShortCodeSms = 5;
        } else {
            mMaxNumVoiceCallSessions = 50;
            mMaxNumSms = 25;
@@ -229,6 +235,7 @@ public class PersistAtomsStorage {
            mMaxNumUceEventStats = 25;
            mMaxNumPresenceNotifyEventStats = 50;
            mMaxNumGbaEventStats = 10;
            mMaxOutgoingShortCodeSms = 10;
        }

        mAtoms = loadAtomsFromFile();
@@ -655,6 +662,18 @@ public class PersistAtomsStorage {
        }
    }

    /** Adds an outgoing short code sms to the storage. */
    public synchronized void addOutgoingShortCodeSms(OutgoingShortCodeSms shortCodeSms) {
        OutgoingShortCodeSms existingOutgoingShortCodeSms = find(shortCodeSms);
        if (existingOutgoingShortCodeSms != null) {
            existingOutgoingShortCodeSms.shortCodeSmsCount += 1;
        } else {
            mAtoms.outgoingShortCodeSms = insertAtRandomPlace(mAtoms.outgoingShortCodeSms,
                    shortCodeSms, mMaxOutgoingShortCodeSms);
        }
        saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_UPDATE_MILLIS);
    }

    /**
     * Returns and clears the voice call sessions if last pulled longer than {@code
     * minIntervalMillis} ago, otherwise returns {@code null}.
@@ -1174,6 +1193,24 @@ public class PersistAtomsStorage {
        return bitmask;
    }

    /**
     * Returns and clears the OutgoingShortCodeSms if last pulled longer than {@code
     * minIntervalMillis} ago, otherwise returns {@code null}.
     */
    @Nullable
    public synchronized OutgoingShortCodeSms[] getOutgoingShortCodeSms(long minIntervalMillis) {
        if ((getWallTimeMillis() - mAtoms.outgoingShortCodeSmsPullTimestampMillis)
                > minIntervalMillis) {
            mAtoms.outgoingShortCodeSmsPullTimestampMillis = getWallTimeMillis();
            OutgoingShortCodeSms[] previousOutgoingShortCodeSms = mAtoms.outgoingShortCodeSms;
            mAtoms.outgoingShortCodeSms = new OutgoingShortCodeSms[0];
            saveAtomsToFile(SAVE_TO_FILE_DELAY_FOR_GET_MILLIS);
            return previousOutgoingShortCodeSms;
        } else {
            return null;
        }
    }

    /** Saves {@link PersistAtoms} to a file in private storage immediately. */
    public synchronized void flushAtoms() {
        saveAtomsToFile(0);
@@ -1309,6 +1346,8 @@ public class PersistAtomsStorage {
                            atoms.unmeteredNetworks,
                            UnmeteredNetworks.class
                    );
            atoms.outgoingShortCodeSms = sanitizeAtoms(atoms.outgoingShortCodeSms,
                    OutgoingShortCodeSms.class, mMaxOutgoingShortCodeSms);

            // out of caution, sanitize also the timestamps
            atoms.voiceCallRatUsagePullTimestampMillis =
@@ -1357,6 +1396,8 @@ public class PersistAtomsStorage {
                    sanitizeTimestamp(atoms.presenceNotifyEventPullTimestampMillis);
            atoms.gbaEventPullTimestampMillis =
                    sanitizeTimestamp(atoms.gbaEventPullTimestampMillis);
            atoms.outgoingShortCodeSmsPullTimestampMillis =
                    sanitizeTimestamp(atoms.outgoingShortCodeSmsPullTimestampMillis);

            return atoms;
        } catch (NoSuchFileException e) {
@@ -1724,6 +1765,20 @@ public class PersistAtomsStorage {
        return null;
    }

    /**
     * Returns OutgoingShortCodeSms atom that has same category, xmlVersion as the given one,
     * or {@code null} if it does not exist.
     */
    private @Nullable OutgoingShortCodeSms find(OutgoingShortCodeSms key) {
        for (OutgoingShortCodeSms shortCodeSms : mAtoms.outgoingShortCodeSms) {
            if (shortCodeSms.category == key.category
                    && shortCodeSms.xmlVersion == key.xmlVersion) {
                return shortCodeSms;
            }
        }
        return null;
    }

    /**
     * Inserts a new element in a random position in an array with a maximum size.
     *
@@ -1969,6 +2024,7 @@ public class PersistAtomsStorage {
        atoms.uceEventStatsPullTimestampMillis = currentTime;
        atoms.presenceNotifyEventPullTimestampMillis = currentTime;
        atoms.gbaEventPullTimestampMillis = currentTime;
        atoms.outgoingShortCodeSmsPullTimestampMillis = currentTime;

        Rlog.d(TAG, "created new PersistAtoms");
        return atoms;
Loading