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

Commit 1559e86f authored by Chi Zhang's avatar Chi Zhang Committed by Gerrit Code Review
Browse files

Merge "Add support for new SMS metrics"

parents 72d28cd5 f6238229
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
@@ -36,6 +36,12 @@ message PersistAtoms {

    /* Timestamp of last voice_call_sessions pull. */
    optional int64 voice_call_session_pull_timestamp_millis = 4;

    /* Incoming SMS statistics and information. */
    repeated IncomingSms incoming_sms = 5;

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

// The canonical versions of the following enums live in:
@@ -82,3 +88,20 @@ message RawVoiceCallRatUsage {
    optional int64 total_duration_millis = 3;
    optional int64 call_count = 4;
}

message IncomingSms {
    optional int32 sms_format = 1;
    optional int32 sms_tech = 2;
    optional int32 rat = 3;
    optional int32 sms_type = 4;
    optional int32 total_parts = 5;
    optional int32 received_parts = 6;
    optional bool blocked = 7;
    optional int32 error = 8;
    optional bool is_roaming = 9;
    optional int32 sim_slot_index = 10;
    optional bool is_multi_sim = 11;
    optional bool is_esim = 12;
    optional int32 carrier_id = 13;
    optional int64 message_id = 14;
}
+1 −1
Original line number Diff line number Diff line
@@ -628,7 +628,7 @@ public class IccSmsInterfaceManager {
                "\n format=" + format +
                "\n receivedIntent=" + receivedIntent);
        }
        mDispatchersController.injectSmsPdu(pdu, format,
        mDispatchersController.injectSmsPdu(pdu, format, false /* isOverIms */,
                result -> {
                    if (receivedIntent != null) {
                        try {
+1 −1
Original line number Diff line number Diff line
@@ -245,7 +245,7 @@ public class ImsSmsDispatcher extends SMSDispatcher {
                    } catch (ImsException e) {
                        loge("Failed to acknowledgeSms(). Error: " + e.getMessage());
                    }
                }, true);
                }, true /* ignoreClass */, true /* isOverIms */);
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
+67 −39
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static android.provider.Telephony.Sms.Intents.RESULT_SMS_NULL_PDU;
import static android.service.carrier.CarrierMessagingService.RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_PROTECTED_STORAGE_UNAVAILABLE;
import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;

import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.AppOpsManager;
@@ -80,6 +81,8 @@ import com.android.telephony.Rlog;
import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -183,6 +186,24 @@ public abstract class InboundSmsHandler extends StateMachine {
    /** Wakelock release delay when returning to idle state. */
    private static final int WAKELOCK_TIMEOUT = 3000;

    /** Received SMS was not injected. */
    public static final int SOURCE_NOT_INJECTED = 0;

    /** Received SMS was received over IMS and injected. */
    public static final int SOURCE_INJECTED_FROM_IMS = 1;

    /** Received SMS was injected from source different than IMS. */
    public static final int SOURCE_INJECTED_FROM_UNKNOWN = 2;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = {"SOURCE_"},
            value = {
                SOURCE_NOT_INJECTED,
                SOURCE_INJECTED_FROM_IMS,
                SOURCE_INJECTED_FROM_UNKNOWN
    })
    public @interface SmsSource {}

    // The notitfication tag used when showing a notification. The combination of notification tag
    // and notification id should be unique within the phone app.
    private static final String NOTIFICATION_TAG = "InboundSmsHandler";
@@ -255,10 +276,6 @@ public abstract class InboundSmsHandler extends StateMachine {
    /** Timeout for releasing wakelock */
    private int mWakeLockTimeout;

    /** Indicates if last SMS was injected. This is used to recognize SMS received over IMS from
        others in order to update metrics. */
    private boolean mLastSmsWasInjected = false;

    private List<SmsFilter> mSmsFilters;

    /**
@@ -516,7 +533,7 @@ public abstract class InboundSmsHandler extends StateMachine {

                case EVENT_INJECT_SMS:
                    // handle new injected SMS
                    handleInjectSms((AsyncResult) msg.obj);
                    handleInjectSms((AsyncResult) msg.obj, msg.arg1 == 1 /* isOverIms */);
                    sendMessage(EVENT_RETURN_TO_IDLE);
                    return HANDLED;

@@ -641,8 +658,7 @@ public abstract class InboundSmsHandler extends StateMachine {
        int result;
        try {
            SmsMessage sms = (SmsMessage) ar.result;
            mLastSmsWasInjected = false;
            result = dispatchMessage(sms.mWrappedSmsMessage);
            result = dispatchMessage(sms.mWrappedSmsMessage, SOURCE_NOT_INJECTED);
        } catch (RuntimeException ex) {
            loge("Exception dispatching message", ex);
            result = RESULT_SMS_DISPATCH_FAILURE;
@@ -661,7 +677,7 @@ public abstract class InboundSmsHandler extends StateMachine {
     * @param ar is the AsyncResult that has the SMS PDU to be injected.
     */
    @UnsupportedAppUsage
    private void handleInjectSms(AsyncResult ar) {
    private void handleInjectSms(AsyncResult ar, boolean isOverIms) {
        int result;
        SmsDispatchersController.SmsInjectionCallback callback = null;
        try {
@@ -671,8 +687,9 @@ public abstract class InboundSmsHandler extends StateMachine {
                loge("Null injected sms");
                result = RESULT_SMS_NULL_PDU;
            } else {
                mLastSmsWasInjected = true;
                result = dispatchMessage(sms.mWrappedSmsMessage);
                @SmsSource int smsSource =
                        isOverIms ? SOURCE_INJECTED_FROM_IMS : SOURCE_INJECTED_FROM_UNKNOWN;
                result = dispatchMessage(sms.mWrappedSmsMessage, smsSource);
            }
        } catch (RuntimeException ex) {
            loge("Exception dispatching message", ex);
@@ -689,10 +706,11 @@ public abstract class InboundSmsHandler extends StateMachine {
     * 3GPP2-specific message types.
     *
     * @param smsb the SmsMessageBase object from the RIL
     * @param smsSource the source of the SMS message
     * @return a result code from {@link android.provider.Telephony.Sms.Intents},
     *  or {@link Activity#RESULT_OK} for delayed acknowledgment to SMSC
     */
    private int dispatchMessage(SmsMessageBase smsb) {
    private int dispatchMessage(SmsMessageBase smsb, @SmsSource int smsSource) {
        // If sms is null, there was a parsing error.
        if (smsb == null) {
            loge("dispatchSmsMessage: message is null");
@@ -719,12 +737,13 @@ public abstract class InboundSmsHandler extends StateMachine {
            return Intents.RESULT_SMS_RECEIVED_WHILE_ENCRYPTED;
        }

        int result = dispatchMessageRadioSpecific(smsb);
        int result = dispatchMessageRadioSpecific(smsb, smsSource);

        // In case of error, add to metrics. This is not required in case of success, as the
        // data will be tracked when the message is processed (processMessagePart).
        if (result != Intents.RESULT_SMS_HANDLED) {
            mMetrics.writeIncomingSmsError(mPhone.getPhoneId(), mLastSmsWasInjected, result);
        if (result != Intents.RESULT_SMS_HANDLED && result != Activity.RESULT_OK) {
            mMetrics.writeIncomingSmsError(mPhone.getPhoneId(), smsSource, result);
            mPhone.getSmsStats().onIncomingSmsError(is3gpp2(), smsSource, result);
        }
        return result;
    }
@@ -735,10 +754,12 @@ public abstract class InboundSmsHandler extends StateMachine {
     * {@link #dispatchNormalMessage} from this class.
     *
     * @param smsb the SmsMessageBase object from the RIL
     * @param smsSource the source of the SMS message
     * @return a result code from {@link android.provider.Telephony.Sms.Intents},
     *  or {@link Activity#RESULT_OK} for delayed acknowledgment to SMSC
     */
    protected abstract int dispatchMessageRadioSpecific(SmsMessageBase smsb);
    protected abstract int dispatchMessageRadioSpecific(SmsMessageBase smsb,
            @SmsSource int smsSource);

    /**
     * Send an acknowledge message to the SMSC.
@@ -782,10 +803,11 @@ public abstract class InboundSmsHandler extends StateMachine {
     * {@link #EVENT_BROADCAST_SMS}. Returns {@link Intents#RESULT_SMS_HANDLED} or an error value.
     *
     * @param sms the message to dispatch
     * @param smsSource the source of the SMS message
     * @return {@link Intents#RESULT_SMS_HANDLED} if the message was accepted, or an error status
     */
    @UnsupportedAppUsage
    protected int dispatchNormalMessage(SmsMessageBase sms) {
    protected int dispatchNormalMessage(SmsMessageBase sms, @SmsSource int smsSource) {
        SmsHeader smsHeader = sms.getUserDataHeader();
        InboundSmsTracker tracker;

@@ -803,7 +825,7 @@ public abstract class InboundSmsHandler extends StateMachine {
                            sms.getTimestampMillis(), destPort, is3gpp2(), false,
                            sms.getOriginatingAddress(), sms.getDisplayOriginatingAddress(),
                            sms.getMessageBody(), sms.getMessageClass() == MessageClass.CLASS_0,
                            mPhone.getSubId());
                            mPhone.getSubId(), smsSource);
        } else {
            // Create a tracker for this message segment.
            SmsHeader.ConcatRef concatRef = smsHeader.concatRef;
@@ -812,10 +834,11 @@ public abstract class InboundSmsHandler extends StateMachine {
            tracker = TelephonyComponentFactory.getInstance()
                    .inject(InboundSmsTracker.class.getName())
                    .makeInboundSmsTracker(mContext, sms.getPdu(),
                    sms.getTimestampMillis(), destPort, is3gpp2(), sms.getOriginatingAddress(),
                    sms.getDisplayOriginatingAddress(), concatRef.refNumber, concatRef.seqNumber,
                    concatRef.msgCount, false, sms.getMessageBody(),
                    sms.getMessageClass() == MessageClass.CLASS_0, mPhone.getSubId());
                            sms.getTimestampMillis(), destPort, is3gpp2(),
                            sms.getOriginatingAddress(), sms.getDisplayOriginatingAddress(),
                            concatRef.refNumber, concatRef.seqNumber, concatRef.msgCount, false,
                            sms.getMessageBody(), sms.getMessageClass() == MessageClass.CLASS_0,
                            mPhone.getSubId(), smsSource);
        }

        if (VDBG) log("created tracker: " + tracker);
@@ -975,14 +998,7 @@ public abstract class InboundSmsHandler extends StateMachine {
        }

        final boolean isWapPush = (destPort == SmsHeader.PORT_WAP_PUSH);

        // At this point, all parts of the SMS are received. Update metrics for incoming SMS.
        // WAP-PUSH messages are handled below to also keep track of the result of the processing.
        String format = tracker.getFormat();
        if (!isWapPush) {
            mMetrics.writeIncomingSmsSession(mPhone.getPhoneId(), mLastSmsWasInjected,
                    format, timestamps, block, tracker.getMessageId());
        }

        // Do not process null pdu(s). Check for that and return false in that case.
        List<byte[]> pduList = Arrays.asList(pdus);
@@ -990,6 +1006,8 @@ public abstract class InboundSmsHandler extends StateMachine {
            String errorMsg = "processMessagePart: returning false due to "
                    + (pduList.size() == 0 ? "pduList.size() == 0" : "pduList.contains(null)");
            logeWithLocalLog(errorMsg, tracker.getMessageId());
            mPhone.getSmsStats().onIncomingSmsError(
                    is3gpp2(), tracker.getSource(), RESULT_SMS_NULL_PDU);
            return false;
        }

@@ -1004,9 +1022,11 @@ public abstract class InboundSmsHandler extends StateMachine {
                    } else {
                        loge("processMessagePart: SmsMessage.createFromPdu returned null",
                                tracker.getMessageId());
                        mMetrics.writeIncomingWapPush(mPhone.getPhoneId(), mLastSmsWasInjected,
                        mMetrics.writeIncomingWapPush(mPhone.getPhoneId(), tracker.getSource(),
                                SmsConstants.FORMAT_3GPP, timestamps, false,
                                tracker.getMessageId());
                        mPhone.getSmsStats().onIncomingSmsWapPush(tracker.getSource(),
                                messageCount, RESULT_SMS_NULL_MESSAGE, tracker.getMessageId());
                        return false;
                    }
                }
@@ -1035,13 +1055,12 @@ public abstract class InboundSmsHandler extends StateMachine {
            }
            // Add result of WAP-PUSH into metrics. RESULT_SMS_HANDLED indicates that the WAP-PUSH
            // needs to be ignored, so treating it as a success case.
            if (result == Activity.RESULT_OK || result == Intents.RESULT_SMS_HANDLED) {
                mMetrics.writeIncomingWapPush(mPhone.getPhoneId(), mLastSmsWasInjected,
                        format, timestamps, true, tracker.getMessageId());
            } else {
                mMetrics.writeIncomingWapPush(mPhone.getPhoneId(), mLastSmsWasInjected,
                        format, timestamps, false, tracker.getMessageId());
            }
            boolean wapPushResult =
                    result == Activity.RESULT_OK || result == Intents.RESULT_SMS_HANDLED;
            mMetrics.writeIncomingWapPush(mPhone.getPhoneId(), tracker.getSource(),
                    format, timestamps, wapPushResult, tracker.getMessageId());
            mPhone.getSmsStats().onIncomingSmsWapPush(tracker.getSource(), messageCount,
                    result, tracker.getMessageId());
            // result is Activity.RESULT_OK if an ordered broadcast was sent
            if (result == Activity.RESULT_OK) {
                return true;
@@ -1054,6 +1073,15 @@ public abstract class InboundSmsHandler extends StateMachine {
            }
        }

        // All parts of SMS are received. Update metrics for incoming SMS.
        // The metrics are generated before SMS filters are invoked.
        // For messages composed by multiple parts, the metrics are generated considering the
        // characteristics of the last one.
        mMetrics.writeIncomingSmsSession(mPhone.getPhoneId(), tracker.getSource(),
                format, timestamps, block, tracker.getMessageId());
        mPhone.getSmsStats().onIncomingSmsSuccess(is3gpp2(), tracker.getSource(),
                messageCount, block, tracker.getMessageId());

        // Always invoke SMS filters, even if the number ends up being blocked, to prevent
        // surprising bugs due to blocking numbers that happen to be used for visual voicemail SMS
        // or other carrier system messages.
+14 −2
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ public class InboundSmsTracker {
    private final boolean mIsClass0;
    private final int mSubId;
    private final long mMessageId;
    private final @InboundSmsHandler.SmsSource int mSmsSource;

    // Fields for concatenating multi-part SMS messages
    private final String mAddress;
@@ -117,10 +118,12 @@ public class InboundSmsTracker {
     * @param address originating address
     * @param displayAddress email address if this message was from an email gateway, otherwise same
     *                       as originating address
     * @param smsSource the source of the SMS message
     */
    public InboundSmsTracker(Context context, byte[] pdu, long timestamp, int destPort,
            boolean is3gpp2, boolean is3gpp2WapPdu, String address, String displayAddress,
            String messageBody, boolean isClass0, int subId) {
            String messageBody, boolean isClass0, int subId,
            @InboundSmsHandler.SmsSource int smsSource) {
        mPdu = pdu;
        mTimestamp = timestamp;
        mDestPort = destPort;
@@ -136,6 +139,7 @@ public class InboundSmsTracker {
        mMessageCount = 1;
        mSubId = subId;
        mMessageId = createMessageId(context, timestamp, subId);
        mSmsSource = smsSource;
    }

    /**
@@ -156,11 +160,12 @@ public class InboundSmsTracker {
     * @param sequenceNumber the sequence number of this segment (0-based)
     * @param messageCount the total number of segments
     * @param is3gpp2WapPdu true for 3GPP2 format WAP PDU; false otherwise
     * @param smsSource the source of the SMS message
     */
    public InboundSmsTracker(Context context, byte[] pdu, long timestamp, int destPort,
             boolean is3gpp2, String address, String displayAddress, int referenceNumber,
             int sequenceNumber, int messageCount, boolean is3gpp2WapPdu, String messageBody,
             boolean isClass0, int subId) {
             boolean isClass0, int subId, @InboundSmsHandler.SmsSource int smsSource) {
        mPdu = pdu;
        mTimestamp = timestamp;
        mDestPort = destPort;
@@ -177,6 +182,7 @@ public class InboundSmsTracker {
        mMessageCount = messageCount;
        mSubId = subId;
        mMessageId = createMessageId(context, timestamp, subId);
        mSmsSource = smsSource;
    }

    /**
@@ -241,6 +247,8 @@ public class InboundSmsTracker {
        }
        mMessageBody = cursor.getString(InboundSmsHandler.MESSAGE_BODY_COLUMN);
        mMessageId = createMessageId(context, mTimestamp, mSubId);
        // TODO(b/167713264): Use the correct SMS source
        mSmsSource = InboundSmsHandler.SOURCE_NOT_INJECTED;
    }

    public ContentValues getContentValues() {
@@ -497,4 +505,8 @@ public class InboundSmsTracker {
    public long getMessageId() {
        return mMessageId;
    }

    public @InboundSmsHandler.SmsSource int getSource() {
        return mSmsSource;
    }
}
Loading