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

Commit 4bd1dec4 authored by Ye Wen's avatar Ye Wen
Browse files

Stop persisting SMS into OUTBOX before sending

Persisting SMS into OUTBOX before sending proved to cause
problems with Messaging app (and potentially other apps) that could try
sending messages in OUTBOX without being asked as manifested in bug
b/18155366. This CL only presists SMS after it is being sent.

b/18202414

Change-Id: Ie0d0e088549bf0853b364e4d33eed2a5d79a7758
parent 0d706917
Loading
Loading
Loading
Loading
+10 −10
Original line number Diff line number Diff line
@@ -17,13 +17,6 @@
package com.android.internal.telephony;

import static android.telephony.SmsManager.RESULT_ERROR_GENERIC_FAILURE;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

import android.app.PendingIntent;
import android.app.PendingIntent.CanceledException;
import android.net.Uri;
@@ -32,10 +25,16 @@ import android.os.Message;
import android.provider.Telephony.Sms.Intents;
import android.telephony.Rlog;

import com.android.internal.telephony.cdma.CdmaInboundSmsHandler;
import com.android.internal.telephony.cdma.CdmaSMSDispatcher;
import com.android.internal.telephony.gsm.GsmSMSDispatcher;
import com.android.internal.telephony.gsm.GsmInboundSmsHandler;
import com.android.internal.telephony.cdma.CdmaInboundSmsHandler;
import com.android.internal.telephony.gsm.GsmSMSDispatcher;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public final class ImsSMSDispatcher extends SMSDispatcher {
    private static final String TAG = "RIL_ImsSms";
@@ -406,7 +405,8 @@ public final class ImsSMSDispatcher extends SMSDispatcher {
    protected void sendNewSubmitPdu(String destinationAddress, String scAddress, String message,
            SmsHeader smsHeader, int format, PendingIntent sentIntent,
            PendingIntent deliveryIntent, boolean lastPart,
            AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri) {
            AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
            String fullMessageText) {
        Rlog.e(TAG, "Error! Not implemented for IMS.");
    }

+86 −67
Original line number Diff line number Diff line
@@ -45,7 +45,6 @@ import android.provider.Telephony.Sms.Intents;
import android.telephony.PhoneNumberUtils;
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SmsManager;
import android.telephony.TelephonyManager;
import android.text.Html;
import android.text.Spanned;
@@ -598,18 +597,7 @@ public abstract class SMSDispatcher extends Handler {
    protected void sendMultipartText(String destAddr, String scAddr,
            ArrayList<String> parts, ArrayList<PendingIntent> sentIntents,
            ArrayList<PendingIntent> deliveryIntents, Uri messageUri, String callingPkg) {
        if (messageUri == null) {
            if (SmsApplication.shouldWriteMessageForPackage(callingPkg, mContext)) {
                messageUri = writeOutboxMessage(
                        getSubId(),
                        destAddr,
                        getMultipartMessageText(parts),
                        deliveryIntents != null && deliveryIntents.size() > 0,
                        callingPkg);
            }
        } else {
            moveToOutbox(getSubId(), messageUri, callingPkg);
        }
        final String fullMessageText = getMultipartMessageText(parts);
        int refNumber = getNextConcatenatedRef() & 0x00FF;
        int msgCount = parts.size();
        int encoding = SmsConstants.ENCODING_UNKNOWN;
@@ -662,7 +650,7 @@ public abstract class SMSDispatcher extends Handler {

            sendNewSubmitPdu(destAddr, scAddr, parts.get(i), smsHeader, encoding,
                    sentIntent, deliveryIntent, (i == (msgCount - 1)),
                    unsentPartCount, anyPartFailed, messageUri);
                    unsentPartCount, anyPartFailed, messageUri, fullMessageText);
        }
    }

@@ -672,7 +660,8 @@ public abstract class SMSDispatcher extends Handler {
    protected abstract void sendNewSubmitPdu(String destinationAddress, String scAddress,
            String message, SmsHeader smsHeader, int encoding,
            PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart,
            AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri);
            AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
            String fullMessageText);

    /**
     * Send a SMS
@@ -1056,11 +1045,16 @@ public abstract class SMSDispatcher extends Handler {
        // Reference to states of a multipart message that this part belongs to
        private AtomicInteger mUnsentPartCount;
        private AtomicBoolean mAnyPartFailed;
        // The full message content of a single part message
        // or a multipart message that this part belongs to
        private String mFullMessageText;

        private int mSubId;

        private SmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
                PendingIntent deliveryIntent, PackageInfo appInfo, String destAddr, String format,
                AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
                SmsHeader smsHeader, boolean isExpectMore) {
                SmsHeader smsHeader, boolean isExpectMore, String fullMessageText, int subId) {
            mData = data;
            mSentIntent = sentIntent;
            mDeliveryIntent = deliveryIntent;
@@ -1075,6 +1069,8 @@ public abstract class SMSDispatcher extends Handler {
            mAnyPartFailed = anyPartFailed;
            mMessageUri = messageUri;
            mSmsHeader = smsHeader;
            mFullMessageText = fullMessageText;
            mSubId = subId;
        }

        /**
@@ -1085,27 +1081,6 @@ public abstract class SMSDispatcher extends Handler {
            return mData.containsKey("parts");
        }

        /**
         * Persist this as a sent message
         */
        void writeSentMessage(Context context) {
            String text = (String)mData.get("text");
            if (text != null) {
                boolean deliveryReport = (mDeliveryIntent != null);
                // Using invalid threadId 0 here. When the message is inserted into the db, the
                // provider looks up the threadId based on the recipient(s).
                mMessageUri = Sms.addMessageToUri(context.getContentResolver(),
                        Telephony.Sms.Sent.CONTENT_URI,
                        mDestAddress,
                        text /*body*/,
                        null /*subject*/,
                        mTimestamp /*date*/,
                        true /*read*/,
                        deliveryReport /*deliveryReport*/,
                        0 /*threadId*/);
            }
        }

        /**
         * Update the status of this message if we persisted it
         */
@@ -1120,22 +1095,24 @@ public abstract class SMSDispatcher extends Handler {
        }

        /**
         * Update the error_code column of a message
         * Set the final state of a message: FAILED or SENT
         *
         * @param context The Context
         * @param messageType The final message type
         * @param errorCode The error code
         */
        private void updateMessageErrorCode(Context context, int errorCode) {
        private void updateMessageState(Context context, int messageType, int errorCode) {
            if (mMessageUri == null) {
                return;
            }
            final ContentValues values = new ContentValues(1);
            final ContentValues values = new ContentValues(2);
            values.put(Sms.TYPE, messageType);
            values.put(Sms.ERROR_CODE, errorCode);
            final long identity = Binder.clearCallingIdentity();
            try {
                if (SqliteWrapper.update(context, context.getContentResolver(), mMessageUri, values,
                        null/*where*/, null/*selectionArgs*/) != 1) {
                    Rlog.e(TAG, "Failed to update message error code");
                    Rlog.e(TAG, "Failed to move message to " + messageType);
                }
            } finally {
                Binder.restoreCallingIdentity(identity);
@@ -1143,28 +1120,74 @@ public abstract class SMSDispatcher extends Handler {
        }

        /**
         * Set the final state of a message: FAILED or SENT
         * Persist a sent SMS if required
         *
         * @param context The Context
         * @param messageType The final message type
         * @param context
         * @param messageType The folder to store (FAILED or SENT)
         * @param errorCode The current error code for this SMS or SMS part
         * @return The telephony provider URI if stored
         */
        private void setMessageFinalState(Context context, int messageType) {
            if (mMessageUri == null) {
                return;
        private Uri persistSentMessageIfRequired(Context context, int messageType, int errorCode) {
            if (!SmsApplication.shouldWriteMessageForPackage(mAppInfo.packageName, context)) {
                return null;
            }
            Rlog.d(TAG, "Persist SMS into "
                    + (messageType == Sms.MESSAGE_TYPE_FAILED ? "FAILED" : "SENT"));
            final ContentValues values = new ContentValues();
            values.put(Sms.SUB_ID, mSubId);
            values.put(Sms.ADDRESS, mDestAddress);
            values.put(Sms.BODY, mFullMessageText);
            values.put(Sms.DATE, System.currentTimeMillis()); // milliseconds
            values.put(Sms.SEEN, 1);
            values.put(Sms.READ, 1);
            final String creator = mAppInfo != null ? mAppInfo.packageName : null;
            if (!TextUtils.isEmpty(creator)) {
                values.put(Sms.CREATOR, creator);
            }
            if (mDeliveryIntent != null) {
                values.put(Sms.STATUS, Telephony.Sms.STATUS_PENDING);
            }
            if (errorCode != 0) {
                values.put(Sms.ERROR_CODE, errorCode);
            }
            final ContentValues values = new ContentValues(1);
            values.put(Sms.TYPE, messageType);
            final long identity = Binder.clearCallingIdentity();
            final ContentResolver resolver = context.getContentResolver();
            try {
                if (SqliteWrapper.update(context, context.getContentResolver(), mMessageUri, values,
                        null/*where*/, null/*selectionArgs*/) != 1) {
                    Rlog.e(TAG, "Failed to move message to " + messageType);
                final Uri uri =  resolver.insert(Telephony.Sms.Sent.CONTENT_URI, values);
                if (uri != null && messageType == Sms.MESSAGE_TYPE_FAILED) {
                    // Since we can't persist a message directly into FAILED box,
                    // we have to update the column after we persist it into SENT box.
                    // The gap between the state change is tiny so I would not expect
                    // it to cause any serious problem
                    // TODO: we should add a "failed" URI for this in SmsProvider?
                    final ContentValues updateValues = new ContentValues(1);
                    updateValues.put(Sms.TYPE, Sms.MESSAGE_TYPE_FAILED);
                    resolver.update(uri, updateValues, null/*where*/, null/*selectionArgs*/);
                }
                return uri;
            } catch (Exception e) {
                Rlog.e(TAG, "writeOutboxMessage: Failed to persist outbox message", e);
                return null;
            } finally {
                Binder.restoreCallingIdentity(identity);
            }
        }

        /**
         * Persist or update an SMS depending on if we send a new message or a stored message
         *
         * @param context
         * @param messageType The message folder for this SMS, FAILED or SENT
         * @param errorCode The current error code for this SMS or SMS part
         */
        private void persistOrUpdateMessage(Context context, int messageType, int errorCode) {
            if (mMessageUri != null) {
                updateMessageState(context, messageType, errorCode);
            } else {
                mMessageUri = persistSentMessageIfRequired(context, messageType, errorCode);
            }
        }

        /**
         * Handle a failure of a single part message or a part of a multipart message
         *
@@ -1181,11 +1204,8 @@ public abstract class SMSDispatcher extends Handler {
            if (mUnsentPartCount != null) {
                isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
            }
            if (errorCode != 0) {
                updateMessageErrorCode(context, errorCode);
            }
            if (isSinglePartOrLastPart) {
                setMessageFinalState(context, Sms.MESSAGE_TYPE_FAILED);
                persistOrUpdateMessage(context, Sms.MESSAGE_TYPE_FAILED, errorCode);
            }
            if (mSentIntent != null) {
                try {
@@ -1221,15 +1241,11 @@ public abstract class SMSDispatcher extends Handler {
                isSinglePartOrLastPart = mUnsentPartCount.decrementAndGet() == 0;
            }
            if (isSinglePartOrLastPart) {
                boolean success = true;
                int messageType = Sms.MESSAGE_TYPE_SENT;
                if (mAnyPartFailed != null && mAnyPartFailed.get()) {
                    success = false;
                }
                if (success) {
                    setMessageFinalState(context, Sms.MESSAGE_TYPE_SENT);
                } else {
                    setMessageFinalState(context, Sms.MESSAGE_TYPE_FAILED);
                    messageType = Sms.MESSAGE_TYPE_FAILED;
                }
                persistOrUpdateMessage(context, messageType, 0/*errorCode*/);
            }
            if (mSentIntent != null) {
                try {
@@ -1254,7 +1270,7 @@ public abstract class SMSDispatcher extends Handler {
    protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
            PendingIntent deliveryIntent, String format, AtomicInteger unsentPartCount,
            AtomicBoolean anyPartFailed, Uri messageUri, SmsHeader smsHeader,
            boolean isExpectMore) {
            boolean isExpectMore, String fullMessageText) {
        // Get calling app package name via UID from Binder call
        PackageManager pm = mContext.getPackageManager();
        String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
@@ -1273,13 +1289,16 @@ public abstract class SMSDispatcher extends Handler {
        // and before displaying the number to the user if confirmation is required.
        String destAddr = PhoneNumberUtils.extractNetworkPortion((String) data.get("destAddr"));
        return new SmsTracker(data, sentIntent, deliveryIntent, appInfo, destAddr, format,
                unsentPartCount, anyPartFailed, messageUri, smsHeader, isExpectMore);
                unsentPartCount, anyPartFailed, messageUri, smsHeader, isExpectMore,
                fullMessageText, getSubId());
    }

    protected SmsTracker getSmsTracker(HashMap<String, Object> data, PendingIntent sentIntent,
            PendingIntent deliveryIntent, String format, Uri messageUri, boolean isExpectMore) {
            PendingIntent deliveryIntent, String format, Uri messageUri, boolean isExpectMore,
            String fullMessageText) {
        return getSmsTracker(data, sentIntent, deliveryIntent, format, null/*unsentPartCount*/,
                null/*anyPartFailed*/, messageUri, null/*smsHeader*/, isExpectMore);
                null/*anyPartFailed*/, messageUri, null/*smsHeader*/, isExpectMore,
                fullMessageText);
    }

    protected HashMap<String, Object> getSmsTrackerMap(String destAddr, String scAddr,
+8 −19
Original line number Diff line number Diff line
@@ -30,19 +30,18 @@ import android.provider.Telephony.Sms.Intents;
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SmsManager;
import android.telephony.TelephonyManager;

import com.android.internal.telephony.GsmAlphabet;
import com.android.internal.telephony.ImsSMSDispatcher;
import com.android.internal.telephony.PhoneBase;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.SMSDispatcher;
import com.android.internal.telephony.SmsApplication;
import com.android.internal.telephony.SmsConstants;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsUsageMonitor;
import com.android.internal.telephony.TelephonyProperties;
import com.android.internal.telephony.cdma.sms.UserData;
import com.android.internal.telephony.PhoneConstants;
import android.telephony.TelephonyManager;

import java.util.HashMap;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -115,7 +114,7 @@ public class CdmaSMSDispatcher extends SMSDispatcher {
                scAddr, destAddr, destPort, data, (deliveryIntent != null));
        HashMap map = getSmsTrackerMap(destAddr, scAddr, destPort, data, pdu);
        SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(),
                null /*messageUri*/, false);
                null /*messageUri*/, false /*isExpectMore*/, null /*fullMessageText*/);
        sendSubmitPdu(tracker);
    }

@@ -126,21 +125,9 @@ public class CdmaSMSDispatcher extends SMSDispatcher {
        SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
                scAddr, destAddr, text, (deliveryIntent != null), null);
        if (pdu != null) {
            if (messageUri == null) {
                if (SmsApplication.shouldWriteMessageForPackage(callingPkg, mContext)) {
                    messageUri = writeOutboxMessage(
                            getSubId(),
                            destAddr,
                            text,
                            deliveryIntent != null,
                            callingPkg);
                }
            } else {
                moveToOutbox(getSubId(), messageUri, callingPkg);
            }
            HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);
            SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(),
                    messageUri, false);
                    messageUri, false /*isExpectMore*/, text);
            sendSubmitPdu(tracker);
        } else {
            Rlog.e(TAG, "CdmaSMSDispatcher.sendText(): getSubmitPdu() returned null");
@@ -165,7 +152,8 @@ public class CdmaSMSDispatcher extends SMSDispatcher {
    protected void sendNewSubmitPdu(String destinationAddress, String scAddress,
            String message, SmsHeader smsHeader, int encoding,
            PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart,
            AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri) {
            AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
            String fullMessageText) {
        UserData uData = new UserData();
        uData.payloadStr = message;
        uData.userDataHeader = smsHeader;
@@ -186,7 +174,8 @@ public class CdmaSMSDispatcher extends SMSDispatcher {
        HashMap map = getSmsTrackerMap(destinationAddress, scAddress,
                message, submitPdu);
        SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent,
                getFormat(), unsentPartCount, anyPartFailed, messageUri, smsHeader, false);
                getFormat(), unsentPartCount, anyPartFailed, messageUri, smsHeader,
                false /*isExpextMore*/, fullMessageText);
        sendSubmitPdu(tracker);
    }

+5 −17
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ import com.android.internal.telephony.ImsSMSDispatcher;
import com.android.internal.telephony.InboundSmsHandler;
import com.android.internal.telephony.PhoneBase;
import com.android.internal.telephony.SMSDispatcher;
import com.android.internal.telephony.SmsApplication;
import com.android.internal.telephony.SmsConstants;
import com.android.internal.telephony.SmsHeader;
import com.android.internal.telephony.SmsUsageMonitor;
@@ -159,7 +158,7 @@ public final class GsmSMSDispatcher extends SMSDispatcher {
        if (pdu != null) {
            HashMap map = getSmsTrackerMap(destAddr, scAddr, destPort, data, pdu);
            SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(),
                    null /*messageUri*/, false);
                    null /*messageUri*/, false /*isExpectMore*/, null /*fullMessageText*/);
            sendRawPdu(tracker);
        } else {
            Rlog.e(TAG, "GsmSMSDispatcher.sendData(): getSubmitPdu() returned null");
@@ -173,21 +172,9 @@ public final class GsmSMSDispatcher extends SMSDispatcher {
        SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(
                scAddr, destAddr, text, (deliveryIntent != null));
        if (pdu != null) {
            if (messageUri == null) {
                if (SmsApplication.shouldWriteMessageForPackage(callingPkg, mContext)) {
                    messageUri = writeOutboxMessage(
                            getSubId(),
                            destAddr,
                            text,
                            deliveryIntent != null,
                            callingPkg);
                }
            } else {
                moveToOutbox(getSubId(), messageUri, callingPkg);
            }
            HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);
            SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(),
                    messageUri, false);
                    messageUri, false /*isExpectMore*/, text /*fullMessageText*/);
            sendRawPdu(tracker);
        } else {
            Rlog.e(TAG, "GsmSMSDispatcher.sendText(): getSubmitPdu() returned null");
@@ -212,7 +199,8 @@ public final class GsmSMSDispatcher extends SMSDispatcher {
    protected void sendNewSubmitPdu(String destinationAddress, String scAddress,
            String message, SmsHeader smsHeader, int encoding,
            PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart,
            AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri) {
            AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri,
            String fullMessageText) {
        SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
                message, deliveryIntent != null, SmsHeader.toByteArray(smsHeader),
                encoding, smsHeader.languageTable, smsHeader.languageShiftTable);
@@ -221,7 +209,7 @@ public final class GsmSMSDispatcher extends SMSDispatcher {
                    message, pdu);
            SmsTracker tracker = getSmsTracker(map, sentIntent,
                    deliveryIntent, getFormat(), unsentPartCount, anyPartFailed, messageUri,
                    smsHeader, !lastPart);
                    smsHeader, !lastPart, fullMessageText);
            sendRawPdu(tracker);
        } else {
            Rlog.e(TAG, "GsmSMSDispatcher.sendNewSubmitPdu(): getSubmitPdu() returned null");