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

Commit 8bb1aa38 authored by Chi Zhang's avatar Chi Zhang Committed by Gerrit Code Review
Browse files

Merge "Add support for new outgoing SMS metrics"

parents 1559e86f d3e0df84
Loading
Loading
Loading
Loading
+23 −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: 5
// Next id: 9
message PersistAtoms {
    /* Aggregated RAT usage during the call. */
    repeated RawVoiceCallRatUsage raw_voice_call_rat_usage = 1;
@@ -42,6 +42,12 @@ message PersistAtoms {

    /* Timestamp of last incoming_sms pull. */
    optional int64 incoming_sms_pull_timestamp_millis = 6;

    /* Outgoing SMS statistics and information. */
    repeated OutgoingSms outgoing_sms = 7;

    /* Timestamp of last incoming_sms pull. */
    optional int64 outgoing_sms_pull_timestamp_millis = 8;
}

// The canonical versions of the following enums live in:
@@ -105,3 +111,19 @@ message IncomingSms {
    optional int32 carrier_id = 13;
    optional int64 message_id = 14;
}

message OutgoingSms {
    optional int32 sms_format = 1;
    optional int32 sms_tech = 2;
    optional int32 rat = 3;
    optional int32 send_result = 4;
    optional int32 error_code = 5;
    optional bool is_roaming = 6;
    optional bool is_from_default_app = 7;
    optional int32 sim_slot_index = 8;
    optional bool is_multi_sim = 9;
    optional bool is_esim = 10;
    optional int32 carrier_id = 11;
    optional int64 message_id = 12;
    optional int32 retry_id = 13;
}
+16 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.os.RemoteException;
import android.provider.Telephony.Sms.Intents;
import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
import android.telephony.SmsManager;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.RegistrationManager;
import android.telephony.ims.aidl.IImsSmsListener;
@@ -139,7 +140,7 @@ public class ImsSmsDispatcher extends SMSDispatcher {
    private final IImsSmsListener mImsSmsListener = new IImsSmsListener.Stub() {
        @Override
        public void onSendSmsResult(int token, int messageRef, @SendStatusResult int status,
                int reason, int networkReasonCode) {
                @SmsManager.Result int reason, int networkReasonCode) {
            final long identity = Binder.clearCallingIdentity();
            try {
                logd("onSendSmsResult token=" + token + " messageRef=" + messageRef
@@ -178,6 +179,13 @@ public class ImsSmsDispatcher extends SMSDispatcher {
                        break;
                    default:
                }
                mPhone.getSmsStats().onOutgoingSms(
                        true /* isOverIms */,
                        SmsConstants.FORMAT_3GPP2.equals(getFormat()),
                        status == ImsSmsImplBase.SEND_STATUS_ERROR_FALLBACK,
                        reason,
                        tracker.mMessageId,
                        tracker.isFromDefaultSmsApplication(mContext));
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
@@ -436,6 +444,13 @@ public class ImsSmsDispatcher extends SMSDispatcher {
            fallbackToPstn(tracker);
            mMetrics.writeImsServiceSendSms(mPhone.getPhoneId(), format,
                    ImsSmsImplBase.SEND_STATUS_ERROR_FALLBACK, tracker.mMessageId);
            mPhone.getSmsStats().onOutgoingSms(
                    true /* isOverIms */,
                    SmsConstants.FORMAT_3GPP2.equals(format),
                    true /* fallbackToCs */,
                    SmsManager.RESULT_SYSTEM_ERROR,
                    tracker.mMessageId,
                    tracker.isFromDefaultSmsApplication(mContext));
        }
    }

+67 −13
Original line number Diff line number Diff line
@@ -751,9 +751,10 @@ public abstract class SMSDispatcher extends Handler {
    protected void handleSendComplete(AsyncResult ar) {
        SmsTracker tracker = (SmsTracker) ar.userObj;
        PendingIntent sentIntent = tracker.mSentIntent;
        SmsResponse smsResponse = (SmsResponse) ar.result;

        if (ar.result != null) {
            tracker.mMessageRef = ((SmsResponse)ar.result).mMessageRef;
        if (smsResponse != null) {
            tracker.mMessageRef = smsResponse.mMessageRef;
        } else {
            Rlog.d(TAG, "SmsResponse was null");
        }
@@ -770,10 +771,17 @@ public abstract class SMSDispatcher extends Handler {
            }
            tracker.onSent(mContext);
            mPhone.notifySmsSent(tracker.mDestAddress);

            mPhone.getSmsStats().onOutgoingSms(
                    tracker.mImsRetry > 0 /* isOverIms */,
                    SmsConstants.FORMAT_3GPP2.equals(getFormat()),
                    false /* fallbackToCs */,
                    SmsManager.RESULT_ERROR_NONE,
                    tracker.mMessageId,
                    tracker.isFromDefaultSmsApplication(mContext));
        } else {
            if (DBG) {
                Rlog.d(TAG, "SMS send failed"
                        + " id: " + tracker.mMessageId);
                Rlog.d(TAG, "SMS send failed id: " + tracker.mMessageId);
            }

            int ss = mPhone.getServiceState().getState();
@@ -796,6 +804,13 @@ public abstract class SMSDispatcher extends Handler {
            // if sms over IMS is not supported on data and voice is not available...
            if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
                tracker.onFailed(mContext, getNotInServiceError(ss), NO_ERROR_CODE);
                mPhone.getSmsStats().onOutgoingSms(
                        tracker.mImsRetry > 0 /* isOverIms */,
                        SmsConstants.FORMAT_3GPP2.equals(getFormat()),
                        false /* fallbackToCs */,
                        getNotInServiceError(ss),
                        tracker.mMessageId,
                        tracker.isFromDefaultSmsApplication(mContext));
            } else if ((((CommandException)(ar.exception)).getCommandError()
                    == CommandException.Error.SMS_FAIL_RETRY) &&
                   tracker.mRetryCount < MAX_SEND_RETRIES) {
@@ -808,20 +823,35 @@ public abstract class SMSDispatcher extends Handler {
                //       message, depending on the failure).  Also, in some
                //       implementations this retry is handled by the baseband.
                tracker.mRetryCount++;
                int errorCode = (smsResponse != null) ? smsResponse.mErrorCode : NO_ERROR_CODE;
                Message retryMsg = obtainMessage(EVENT_SEND_RETRY, tracker);
                sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);
                mPhone.getSmsStats().onOutgoingSms(
                        tracker.mImsRetry > 0 /* isOverIms */,
                        SmsConstants.FORMAT_3GPP2.equals(getFormat()),
                        false /* fallbackToCs */,
                        SmsManager.RESULT_RIL_SMS_SEND_FAIL_RETRY,
                        errorCode,
                        tracker.mMessageId,
                        tracker.isFromDefaultSmsApplication(mContext));
            } else {
                int errorCode = NO_ERROR_CODE;
                if (ar.result != null) {
                    errorCode = ((SmsResponse)ar.result).mErrorCode;
                }
                int errorCode = (smsResponse != null) ? smsResponse.mErrorCode : NO_ERROR_CODE;
                int error = rilErrorToSmsManagerResult(((CommandException) (ar.exception))
                        .getCommandError());
                tracker.onFailed(mContext, error, errorCode);
                mPhone.getSmsStats().onOutgoingSms(
                        tracker.mImsRetry > 0 /* isOverIms */,
                        SmsConstants.FORMAT_3GPP2.equals(getFormat()),
                        false /* fallbackToCs */,
                        error,
                        errorCode,
                        tracker.mMessageId,
                        tracker.isFromDefaultSmsApplication(mContext));
            }
        }
    }

    @SmsManager.Result
    private static int rilErrorToSmsManagerResult(CommandException.Error rilError) {
        switch (rilError) {
            case RADIO_NOT_AVAILABLE:
@@ -881,6 +911,7 @@ public abstract class SMSDispatcher extends Handler {
     * @param ss service state
     * @return The result error based on input service state for not in service error
     */
    @SmsManager.Result
    protected static int getNotInServiceError(int ss) {
        if (ss == ServiceState.STATE_POWER_OFF) {
            return RESULT_ERROR_RADIO_OFF;
@@ -1294,7 +1325,7 @@ public abstract class SMSDispatcher extends Handler {
     */
    @VisibleForTesting
    public void sendRawPdu(SmsTracker[] trackers) {
        int error = RESULT_ERROR_NONE;
        @SmsManager.Result int error = RESULT_ERROR_NONE;
        PackageInfo appInfo = null;
        if (mSmsSendDisabled) {
            Rlog.e(TAG, "Device does not support sending sms.");
@@ -1610,10 +1641,22 @@ public abstract class SMSDispatcher extends Handler {
        }
    }

    private void handleSmsTrackersFailure(SmsTracker[] trackers, int error, int errorCode) {
    private void handleSmsTrackersFailure(SmsTracker[] trackers, @SmsManager.Result int error,
            int errorCode) {
        for (SmsTracker tracker : trackers) {
            tracker.onFailed(mContext, error, errorCode);
        }
        if (trackers.length > 0) {
            // This error occurs before the SMS is sent. Make an assumption if it would have
            // been sent over IMS or not.
            mPhone.getSmsStats().onOutgoingSms(
                    isIms(),
                    SmsConstants.FORMAT_3GPP2.equals(getFormat()),
                    false /* fallbackToCs */,
                    error,
                    trackers[0].mMessageId,
                    trackers[0].isFromDefaultSmsApplication(mContext));
        }
    }

    /**
@@ -1678,6 +1721,8 @@ public abstract class SMSDispatcher extends Handler {

        public final long mMessageId;

        private Boolean mIsFromDefaultSmsApplication;

        // SMS anomaly uuid
        private final UUID mAnomalyUUID = UUID.fromString("43043600-ea7a-44d2-9ae6-a58567ac7886");

@@ -1725,6 +1770,16 @@ public abstract class SMSDispatcher extends Handler {
            return mAppInfo != null ? mAppInfo.packageName : null;
        }

        /** Return if the SMS was originated from the default SMS application. */
        public boolean isFromDefaultSmsApplication(Context context) {
            if (mIsFromDefaultSmsApplication == null) {
                // Perform a lazy initialization, due to the cost of the operation.
                mIsFromDefaultSmsApplication =
                        SmsApplication.isDefaultSmsApplication(context, getAppPackageName());
            }
            return mIsFromDefaultSmsApplication;
        }

        /**
         * Update the status of this message if we persisted it
         */
@@ -1775,8 +1830,7 @@ public abstract class SMSDispatcher extends Handler {
         * @return The telephony provider URI if stored
         */
        private Uri persistSentMessageIfRequired(Context context, int messageType, int errorCode) {
            if (!mIsText || !mPersistMessage ||
                    !SmsApplication.shouldWriteMessageForPackage(mAppInfo.packageName, context)) {
            if (!mIsText || !mPersistMessage || isFromDefaultSmsApplication(context)) {
                return null;
            }
            Rlog.d(TAG, "Persist SMS into "
+36 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ 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.INCOMING_SMS;
import static com.android.internal.telephony.TelephonyStatsLog.OUTGOING_SMS;
import static com.android.internal.telephony.TelephonyStatsLog.SIM_SLOT_STATE;
import static com.android.internal.telephony.TelephonyStatsLog.SUPPORTED_RADIO_ACCESS_FAMILY;
import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_RAT_USAGE;
@@ -35,6 +36,7 @@ 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.IncomingSms;
import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms;
import com.android.internal.telephony.nano.PersistAtomsProto.RawVoiceCallRatUsage;
import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallSession;
import com.android.internal.util.ConcurrentUtils;
@@ -95,6 +97,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
            registerAtom(VOICE_CALL_RAT_USAGE, POLICY_PULL_DAILY);
            registerAtom(VOICE_CALL_SESSION, POLICY_PULL_DAILY);
            registerAtom(INCOMING_SMS, POLICY_PULL_DAILY);
            registerAtom(OUTGOING_SMS, POLICY_PULL_DAILY);
            Rlog.d(TAG, "registered");
        } else {
            Rlog.e(TAG, "could not get StatsManager, atoms not registered");
@@ -127,6 +130,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
                return pullVoiceCallSessions(data);
            case INCOMING_SMS:
                return pullIncomingSms(data);
            case OUTGOING_SMS:
                return pullOutgoingSms(data);
            default:
                Rlog.e(TAG, String.format("unexpected atom ID %d", atomTag));
                return StatsManager.PULL_SKIP;
@@ -225,6 +230,18 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
        }
    }

    private int pullOutgoingSms(List<StatsEvent> data) {
        OutgoingSms[] smsList = mStorage.getOutgoingSms(MIN_COOLDOWN_MILLIS);
        if (smsList != null) {
            // SMS list is already shuffled when SMS were inserted
            Arrays.stream(smsList).forEach(sms -> data.add(buildStatsEvent(sms)));
            return StatsManager.PULL_SUCCESS;
        } else {
            Rlog.w(TAG, "OUTGOING_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);
@@ -293,6 +310,25 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
                .build();
    }

    private static StatsEvent buildStatsEvent(OutgoingSms sms) {
        return StatsEvent.newBuilder()
                .setAtomId(OUTGOING_SMS)
                .writeInt(sms.smsFormat)
                .writeInt(sms.smsTech)
                .writeInt(sms.rat)
                .writeInt(sms.sendResult)
                .writeInt(sms.errorCode)
                .writeBoolean(sms.isRoaming)
                .writeBoolean(sms.isFromDefaultApp)
                .writeInt(sms.simSlotIndex)
                .writeBoolean(sms.isMultiSim)
                .writeBoolean(sms.isEsim)
                .writeInt(sms.carrierId)
                .writeLong(sms.messageId)
                .writeInt(sms.retryId)
                .build();
    }

    /** Returns the value rounded to the bucket. */
    private static long round(long value, long bucket) {
        return ((value + bucket / 2) / bucket) * bucket;
+70 −27
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.Context;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.nano.PersistAtomsProto.IncomingSms;
import com.android.internal.telephony.nano.PersistAtomsProto.OutgoingSms;
import com.android.internal.telephony.nano.PersistAtomsProto.PersistAtoms;
import com.android.internal.telephony.nano.PersistAtomsProto.RawVoiceCallRatUsage;
import com.android.internal.telephony.nano.PersistAtomsProto.VoiceCallSession;
@@ -70,21 +71,8 @@ public class PersistAtomsStorage {

    /** Adds a call to the storage. */
    public synchronized void addVoiceCallSession(VoiceCallSession call) {
        int newLength = mAtoms.voiceCallSession.length + 1;
        if (newLength > MAX_NUM_CALL_SESSIONS) {
            // will evict one previous call randomly instead of making the array larger
            newLength = MAX_NUM_CALL_SESSIONS;
        } else {
            mAtoms.voiceCallSession = Arrays.copyOf(mAtoms.voiceCallSession, newLength);
        }
        int insertAt = 0;
        if (newLength > 1) {
            // shuffle when each call is added, or randomly replace a previous call instead if
            // MAX_NUM_CALL_SESSIONS is reached (call at the last index is evicted).
            insertAt = sRandom.nextInt(newLength);
            mAtoms.voiceCallSession[newLength - 1] = mAtoms.voiceCallSession[insertAt];
        }
        mAtoms.voiceCallSession[insertAt] = call;
        mAtoms.voiceCallSession =
                insertAtRandomPlace(mAtoms.voiceCallSession, call, MAX_NUM_CALL_SESSIONS);
        saveAtomsToFile();
    }

@@ -97,25 +85,52 @@ public class PersistAtomsStorage {

    /** Adds an incoming SMS to the storage. */
    public synchronized void addIncomingSms(IncomingSms sms) {
        int newLength = mAtoms.incomingSms.length + 1;
        if (newLength > MAX_NUM_SMS) {
        mAtoms.incomingSms = insertAtRandomPlace(mAtoms.incomingSms, sms, MAX_NUM_SMS);
        saveAtomsToFile();

        // To be removed
        Rlog.d(TAG, "Add new incoming SMS atom: " + sms.toString());
    }

    /** Adds an outgoing SMS to the storage. */
    public synchronized void addOutgoingSms(OutgoingSms 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).
        for (OutgoingSms storedSms : mAtoms.outgoingSms) {
            if (storedSms.messageId == sms.messageId
                    && storedSms.retryId >= sms.retryId) {
                sms.retryId = storedSms.retryId + 1;
            }
        }

        mAtoms.outgoingSms = insertAtRandomPlace(mAtoms.outgoingSms, sms, MAX_NUM_SMS);
        saveAtomsToFile();

        // To be removed
        Rlog.d(TAG, "Add new outgoing SMS atom: " + sms.toString());
    }

    /** Inserts a new element in a random position in an array with a maximum size. */
    private static <T> T[] insertAtRandomPlace(T[] storage, T instance, int maxLength) {
        T[] result;
        int newLength = storage.length + 1;
        if (newLength > maxLength) {
            // will evict one previous call randomly instead of making the array larger
            newLength = MAX_NUM_SMS;
            newLength = maxLength;
            result = storage;
        } else {
            mAtoms.incomingSms = Arrays.copyOf(mAtoms.incomingSms, newLength);
            result = Arrays.copyOf(storage, newLength);
        }
        int insertAt = 0;
        if (newLength > 1) {
            // shuffle when each call is added, or randomly replace a previous call instead if
            // MAX_NUM_SMS is reached (call at the last index is evicted).
            // shuffle when each element is added, or randomly replace a previous element instead
            // if maxLength is reached (entry at the last index is evicted).
            insertAt = sRandom.nextInt(newLength);
            mAtoms.incomingSms[newLength - 1] = mAtoms.incomingSms[insertAt];
            result[newLength - 1] = result[insertAt];
        }
        mAtoms.incomingSms[insertAt] = sms;
        saveAtomsToFile();

        // To be removed
        Rlog.d(TAG, "Add new SMS atom: " + sms.toString());
        result[insertAt] = instance;
        return result;
    }

    /**
@@ -171,6 +186,23 @@ public class PersistAtomsStorage {
        }
    }

    /**
     * Returns and clears the outgoing SMS if last pulled longer than {@code
     * minIntervalMillis} ago, otherwise returns {@code null}.
     */
    @Nullable
    public synchronized OutgoingSms[] getOutgoingSms(long minIntervalMillis) {
        if (getWallTimeMillis() - mAtoms.outgoingSmsPullTimestampMillis > minIntervalMillis) {
            mAtoms.outgoingSmsPullTimestampMillis = getWallTimeMillis();
            OutgoingSms[] previousOutgoingSms = mAtoms.outgoingSms;
            mAtoms.outgoingSms = new OutgoingSms[0];
            saveAtomsToFile();
            return previousOutgoingSms;
        } else {
            return null;
        }
    }

    /** Loads {@link PersistAtoms} from a file in private storage. */
    private PersistAtoms loadAtomsFromFile() {
        try {
@@ -195,6 +227,13 @@ public class PersistAtomsStorage {
                atomsFromFile.incomingSms =
                        Arrays.copyOf(atomsFromFile.incomingSms, MAX_NUM_SMS);
            }
            if (atomsFromFile.outgoingSms == null) {
                atomsFromFile.outgoingSms = new OutgoingSms[0];
            }
            if (atomsFromFile.outgoingSms.length > MAX_NUM_SMS) {
                atomsFromFile.outgoingSms =
                        Arrays.copyOf(atomsFromFile.outgoingSms, MAX_NUM_SMS);
            }
            // out of caution, set timestamps to now if they are missing
            if (atomsFromFile.rawVoiceCallRatUsagePullTimestampMillis == 0L) {
                atomsFromFile.rawVoiceCallRatUsagePullTimestampMillis = getWallTimeMillis();
@@ -205,6 +244,9 @@ public class PersistAtomsStorage {
            if (atomsFromFile.incomingSmsPullTimestampMillis == 0L) {
                atomsFromFile.incomingSmsPullTimestampMillis = getWallTimeMillis();
            }
            if (atomsFromFile.outgoingSmsPullTimestampMillis == 0L) {
                atomsFromFile.outgoingSmsPullTimestampMillis = getWallTimeMillis();
            }
            return atomsFromFile;
        } catch (IOException | NullPointerException e) {
            Rlog.e(TAG, "cannot load/parse PersistAtoms", e);
@@ -229,6 +271,7 @@ public class PersistAtomsStorage {
        atoms.rawVoiceCallRatUsagePullTimestampMillis = currentTime;
        atoms.voiceCallSessionPullTimestampMillis = currentTime;
        atoms.incomingSmsPullTimestampMillis = currentTime;
        atoms.outgoingSmsPullTimestampMillis = currentTime;
        Rlog.d(TAG, "created new PersistAtoms");
        return atoms;
    }
Loading