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

Commit 8fe2baab authored by Amit Mahajan's avatar Amit Mahajan
Browse files

Changes to de-dup messages in SMS raw table.

Bug: 27820591
Change-Id: I6b071ec99a90d9f5195825ba3cd73cb54f61631b
parent 3a8b5774
Loading
Loading
Loading
Loading
+51 −49
Original line number Diff line number Diff line
@@ -125,7 +125,8 @@ public abstract class InboundSmsHandler extends StateMachine {
    public static final int ID_COLUMN = 7;

    public static final String SELECT_BY_ID = "_id=?";
    public static final String SELECT_BY_REFERENCE = "address=? AND reference_number=? AND count=?";
    public static final String SELECT_BY_REFERENCE = "address=? AND reference_number=? AND " +
            "count=? AND deleted=0";

    /** New SMS received as an AsyncResult. */
    public static final int EVENT_NEW_SMS = 1;
@@ -161,6 +162,8 @@ public abstract class InboundSmsHandler extends StateMachine {

    /** URI for raw table of SMS provider. */
    private static final Uri sRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw");
    private static final Uri sRawUriPermanentDelete =
            Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw/permanentDelete");

    protected final Context mContext;
    private final ContentResolver mResolver;
@@ -790,13 +793,13 @@ public abstract class InboundSmsHandler extends StateMachine {
            if (result == Activity.RESULT_OK) {
                return true;
            } else {
                deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs());
                deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(), false);
                return false;
            }
        }

        if (BlockChecker.isBlocked(mContext, tracker.getAddress())) {
            deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs());
            deleteFromRawTable(tracker.getDeleteWhere(), tracker.getDeleteWhereArgs(), true);
            return false;
        }

@@ -983,8 +986,10 @@ public abstract class InboundSmsHandler extends StateMachine {
    /**
     * Helper for {@link SmsBroadcastUndelivered} to delete an old message in the raw table.
     */
    private void deleteFromRawTable(String deleteWhere, String[] deleteWhereArgs) {
        int rows = mResolver.delete(sRawUri, deleteWhere, deleteWhereArgs);
    private void deleteFromRawTable(String deleteWhere, String[] deleteWhereArgs,
                                    boolean permanentDelete) {
        Uri uri = permanentDelete ? sRawUriPermanentDelete : sRawUri;
        int rows = mResolver.delete(uri, deleteWhere, deleteWhereArgs);
        if (rows == 0) {
            loge("No rows were deleted from raw table!");
        } else if (DBG) {
@@ -1074,7 +1079,6 @@ public abstract class InboundSmsHandler extends StateMachine {
     * @return true on success; false on failure to write to database
     */
    private int addTrackerToRawTable(InboundSmsTracker tracker) {
        if (tracker.getMessageCount() != 1) {
        // check for duplicate message segments
        Cursor cursor = null;
        try {
@@ -1085,8 +1089,8 @@ public abstract class InboundSmsHandler extends StateMachine {
            String address = tracker.getAddress();
            String refNumber = Integer.toString(tracker.getReferenceNumber());
            String count = Integer.toString(tracker.getMessageCount());

            String seqNumber = Integer.toString(sequence);
            String date = Long.toString(tracker.getTimestamp());

            // set the delete selection args for multi-part message
            String[] deleteWhereArgs = {address, refNumber, count};
@@ -1094,8 +1098,8 @@ public abstract class InboundSmsHandler extends StateMachine {

            // Check for duplicate message segments
            cursor = mResolver.query(sRawUri, PDU_PROJECTION,
                        "address=? AND reference_number=? AND count=? AND sequence=?",
                        new String[] {address, refNumber, count, seqNumber}, null);
                    "address=? AND reference_number=? AND count=? AND sequence=? AND date=?",
                    new String[] {address, refNumber, count, seqNumber, date}, null);

            // moveToNext() returns false if no duplicates were found
            if (cursor.moveToNext()) {
@@ -1110,7 +1114,6 @@ public abstract class InboundSmsHandler extends StateMachine {
                }
                return Intents.RESULT_SMS_DUPLICATED;   // reject message
            }
                cursor.close();
        } catch (SQLException e) {
            loge("Can't access multipart SMS database", e);
            return Intents.RESULT_SMS_GENERIC_ERROR;    // reject message
@@ -1119,7 +1122,6 @@ public abstract class InboundSmsHandler extends StateMachine {
                cursor.close();
            }
        }
        }

        ContentValues values = tracker.getContentValues();

@@ -1212,7 +1214,7 @@ public abstract class InboundSmsHandler extends StateMachine {
                    log("successful broadcast, deleting from raw table.");
                }

                deleteFromRawTable(mDeleteWhere, mDeleteWhereArgs);
                deleteFromRawTable(mDeleteWhere, mDeleteWhereArgs, false);
                sendMessage(EVENT_BROADCAST_COMPLETE);

                int durationMillis = (int) ((System.nanoTime() - mBroadcastTimeNano) / 1000000);
@@ -1318,7 +1320,7 @@ public abstract class InboundSmsHandler extends StateMachine {
                try {
                    // Needs phone package permissions.
                    deleteFromRawTable(mSmsFilter.mSmsBroadcastReceiver.mDeleteWhere,
                            mSmsFilter.mSmsBroadcastReceiver.mDeleteWhereArgs);
                            mSmsFilter.mSmsBroadcastReceiver.mDeleteWhereArgs, false);
                } finally {
                    Binder.restoreCallingIdentity(token);
                }
+8 −3
Original line number Diff line number Diff line
@@ -65,6 +65,8 @@ public class SmsBroadcastUndelivered {

    /** URI for raw table from SmsProvider. */
    private static final Uri sRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw");
    private static final Uri sRawUriPermanentDelete =
            Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw/permanentDelete");
    private static SmsBroadcastUndelivered instance;

    /** Content resolver to use to access raw table from SmsProvider. */
@@ -135,7 +137,9 @@ public class SmsBroadcastUndelivered {
        HashSet<SmsReferenceKey> oldMultiPartMessages = new HashSet<SmsReferenceKey>(4);
        Cursor cursor = null;
        try {
            cursor = mResolver.query(sRawUri, PDU_PENDING_MESSAGE_PROJECTION, null, null, null);
            // query only non-deleted ones
            cursor = mResolver.query(sRawUri, PDU_PENDING_MESSAGE_PROJECTION, "deleted = 0", null,
                    null);
            if (cursor == null) {
                Rlog.e(TAG, "error getting pending message cursor");
                return;
@@ -182,8 +186,9 @@ public class SmsBroadcastUndelivered {
            }
            // Delete old incomplete message segments
            for (SmsReferenceKey message : oldMultiPartMessages) {
                int rows = mResolver.delete(sRawUri, InboundSmsHandler.SELECT_BY_REFERENCE,
                        message.getDeleteWhereArgs());
                // delete permanently
                int rows = mResolver.delete(sRawUriPermanentDelete,
                        InboundSmsHandler.SELECT_BY_REFERENCE, message.getDeleteWhereArgs());
                if (rows == 0) {
                    Rlog.e(TAG, "No rows were deleted from raw table!");
                } else if (DBG) {
+1 −1
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@ public abstract class SmsMessageBase {
    /** {@hide} */
    protected boolean mIsEmail;

    /** {@hide} */
    /** {@hide} Time when SC (service centre) received the message */
    protected long mScTimeMillis;

    /** {@hide} The raw PDU of the message */
+161 −37
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ import org.mockito.Mock;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class GsmInboundSmsHandlerTest extends TelephonyTest {
    @Mock
@@ -77,6 +78,9 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {

    private FakeSmsContentProvider mContentProvider;
    private static final Uri sRawUri = Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw");
    private static final Uri sRawUriPermanentDelete =
            Uri.withAppendedPath(Telephony.Sms.CONTENT_URI, "raw/permanentDelete");

    private ContentValues mInboundSmsTrackerCV = new ContentValues();
    // For multi-part SMS
    private ContentValues mInboundSmsTrackerCVPart1;
@@ -93,13 +97,56 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
                "destination_port",
                "address",
                "sub_id",
                "pdu"};
        private MatrixCursor mRawCursor = new MatrixCursor(mRawColumns);
                "pdu",
                "deleted"};
        private List<ArrayList<Object>> mListOfRows = new ArrayList<ArrayList<Object>>();
        private int mNumRows = 0;

        private int getColumnIndex(String columnName) {
            int i = 0;
            for (String s : mRawColumns) {
                if (s.equals(columnName)) {
                    break;
                }
                i++;
            }
            return i;
        }

        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            return 0;
            int count = 0;
            if (mNumRows > 0) {
                // parse selection and selectionArgs
                SelectionParams selectionParams = new SelectionParams();
                selectionParams.parseSelectionParams(selection, selectionArgs);

                List<Integer> deleteRows = new ArrayList<Integer>();
                int i = -1;
                for (ArrayList<Object> row : mListOfRows) {
                    i++;
                    // filter based on selection parameters if needed
                    if (selection != null) {
                        if (!selectionParams.isMatch(row)) {
                            continue;
                        }
                    }
                    if (uri.compareTo(sRawUri) == 0) {
                        row.set(getColumnIndex("deleted"), "1");
                    } else {
                        // save index for removal
                        deleteRows.add(i);
                    }
                    count++;
                }

                if (uri.compareTo(sRawUriPermanentDelete) == 0) {
                    for (i = deleteRows.size() - 1; i >= 0; i--) {
                        mListOfRows.remove(i);
                    }
                }
            }
            return count;
        }

        @Override
@@ -107,7 +154,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
            Uri newUri = null;
            if (uri.compareTo(sRawUri) == 0) {
                if (values != null) {
                    mRawCursor.addRow(convertRawCVtoArrayList(values));
                    mListOfRows.add(convertRawCVtoArrayList(values));
                    mNumRows++;
                    newUri = Uri.withAppendedPath(uri, "" + mNumRows);
                }
@@ -120,9 +167,11 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
            ArrayList<Object> newRow = new ArrayList<>();
            for (String key : mRawColumns) {
                if (values.containsKey(key)) {
                    newRow.add(values.get(key));
                    newRow.add(values.getAsString(key));
                } else if (key.equals("_id")) {
                    newRow.add(mNumRows + 1);
                } else if (key.equals("deleted")) {
                    newRow.add("0");
                } else {
                    newRow.add(null);
                }
@@ -130,15 +179,11 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
            return newRow;
        }

        @Override
        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                            String sortOrder) {
            logd("query called for: " + selection);
            MatrixCursor cursor = new MatrixCursor(projection);
            if (mNumRows > 0) {
                // parse selection and selectionArgs
        private class SelectionParams {
            String[] paramName = null;
            String[] paramValue = null;

            private void parseSelectionParams(String selection, String[] selectionArgs) {
                if (selection != null) {
                    selection = selection.toLowerCase();
                    String[] selectionParams = selection.toLowerCase().split("and");
@@ -157,38 +202,52 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
                        }
                    }
                }
            }

                mRawCursor.moveToFirst();
                do {
                    ArrayList<Object> row = new ArrayList<>();
                    // filter based on selection parameters if needed
                    if (selection != null) {
                        boolean match = true;
            private boolean isMatch(ArrayList<Object> row) {
                for (int i = 0; i < paramName.length; i++) {
                    int columnIndex = 0;
                    for (String columnName : mRawColumns) {
                                int columnIndex = mRawCursor.getColumnIndex(columnName);
                                if (columnName.equals(paramName[i]) &&
                                        !mRawCursor.getString(columnIndex).equals(paramValue[i])) {
                                    match = false;
                        if (columnName.equals(paramName[i])) {
                            if (!paramValue[i].equals(row.get(columnIndex))) {
                                return false;
                            } else {
                                // move on to next param
                                break;
                            }
                        }
                            if (!match) {
                                break;
                        columnIndex++;
                    }
                }
                return true;
            }
                        // move on to next row if current one does not satisfy selection criteria
                        if (!match) {
        }

        @Override
        public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
                            String sortOrder) {
            logd("query called for: " + selection);
            MatrixCursor cursor = new MatrixCursor(projection);
            if (mNumRows > 0) {
                // parse selection and selectionArgs
                SelectionParams selectionParams = new SelectionParams();
                selectionParams.parseSelectionParams(selection, selectionArgs);

                for (ArrayList<Object> row : mListOfRows) {
                    ArrayList<Object> retRow = new ArrayList<>();
                    // filter based on selection parameters if needed
                    if (selection != null) {
                        if (!selectionParams.isMatch(row)) {
                            continue;
                        }
                    }

                    for (String columnName : projection) {
                        int columnIndex = mRawCursor.getColumnIndex(columnName);
                        row.add(mRawCursor.getString(columnIndex));
                        int columnIndex = getColumnIndex(columnName);
                        retRow.add(row.get(columnIndex));
                    }
                    cursor.addRow(retRow);
                }
                    cursor.addRow(row);
                } while(mRawCursor.moveToNext());
            }
            if (cursor != null) {
                logd("returning rows: " + cursor.getCount());
@@ -383,6 +442,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
        mInboundSmsTrackerCVPart1.put("reference_number", 1);
        mInboundSmsTrackerCVPart1.put("sequence", 1);
        mInboundSmsTrackerCVPart1.put("count", 2);
        mInboundSmsTrackerCVPart1.put("date", System.currentTimeMillis());

        doReturn(2).when(mInboundSmsTrackerPart1).getMessageCount();
        doReturn(1).when(mInboundSmsTrackerPart1).getReferenceNumber();
@@ -391,6 +451,8 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
        doReturn(1).when(mInboundSmsTrackerPart1).getIndexOffset();
        doReturn(-1).when(mInboundSmsTrackerPart1).getDestPort();
        doReturn(mSmsPdu).when(mInboundSmsTrackerPart1).getPdu();
        doReturn(mInboundSmsTrackerCVPart1.get("date")).when(mInboundSmsTrackerPart1).
                getTimestamp();
        doReturn(mInboundSmsTrackerCVPart1).when(mInboundSmsTrackerPart1).getContentValues();

        // Part 2
@@ -401,6 +463,7 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
        mInboundSmsTrackerCVPart2.put("reference_number", 1);
        mInboundSmsTrackerCVPart2.put("sequence", 2);
        mInboundSmsTrackerCVPart2.put("count", 2);
        mInboundSmsTrackerCVPart2.put("date", System.currentTimeMillis());

        doReturn(2).when(mInboundSmsTrackerPart2).getMessageCount();
        doReturn(1).when(mInboundSmsTrackerPart2).getReferenceNumber();
@@ -409,6 +472,8 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
        doReturn(1).when(mInboundSmsTrackerPart2).getIndexOffset();
        doReturn(-1).when(mInboundSmsTrackerPart2).getDestPort();
        doReturn(mSmsPdu).when(mInboundSmsTrackerPart2).getPdu();
        doReturn(mInboundSmsTrackerCVPart2.get("date")).when(mInboundSmsTrackerPart2).
                getTimestamp();
        doReturn(mInboundSmsTrackerCVPart2).when(mInboundSmsTrackerPart2).getContentValues();
    }

@@ -422,10 +487,10 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {

        mSmsHeader.concatRef = new SmsHeader.ConcatRef();
        doReturn(mSmsHeader).when(mGsmSmsMessage).getUserDataHeader();

        doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory)
                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean());

        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
                mSmsMessage, null));
        waitForMs(100);
@@ -440,7 +505,42 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
                mSmsMessage, null));
        waitForMs(100);

        // verify broadcast intents
        verifySmsIntentBroadcasts(0);

        // if an additional copy of one of the segments above is received, it should not be kept in
        // the db and should not be combined with any subsequent messages received from the same
        // sender

        // additional copy of part 2 of message
        doReturn(mInboundSmsTrackerPart2).when(mTelephonyComponentFactory)
                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean());
        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
                mSmsMessage, null));
        waitForMs(100);

        // verify no additional broadcasts sent
        verify(mContext, times(2)).sendBroadcast(any(Intent.class));

        // part 1 of new sms recieved from same sender with same parameters, just different
        // timestamps, should not be combined with the additional part 2 received above

        // call prepareMultiPartSms() to update timestamps
        prepareMultiPartSms();

        // part 1 of new sms
        doReturn(mInboundSmsTrackerPart1).when(mTelephonyComponentFactory)
                .makeInboundSmsTracker(any(byte[].class), anyLong(), anyInt(), anyBoolean(),
                        anyString(), anyInt(), anyInt(), anyInt(), anyBoolean());
        mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_NEW_SMS, new AsyncResult(null,
                mSmsMessage, null));
        waitForMs(100);

        // verify no additional broadcasts sent
        verify(mContext, times(2)).sendBroadcast(any(Intent.class));

        assertEquals("IdleState", getCurrentState().getName());
    }

    @Test
@@ -498,6 +598,30 @@ public class GsmInboundSmsHandlerTest extends TelephonyTest {
        verifyDataSmsIntentBroadcasts(1);
    }

    @Test
    @MediumTest
    public void testBroadcastUndeliveredDeleted() throws Exception {
        replaceInstance(SmsBroadcastUndelivered.class, "instance", null, null);
        SmsBroadcastUndelivered.initialize(mContext, mGsmInboundSmsHandler, mCdmaInboundSmsHandler);
        doReturn(0).when(mInboundSmsTracker).getDestPort();

        //add a fake entry to db
        ContentValues rawSms = new ContentValues();
        rawSms.put("deleted", 1);
        mContentProvider.insert(sRawUri, rawSms);

        //make it a single-part message
        doReturn(1).when(mInboundSmsTracker).getMessageCount();

        //when user unlocks the device, broadcast should not be sent for new message
        mContext.sendBroadcast(new Intent(Intent.ACTION_USER_UNLOCKED));
        waitForMs(100);

        verify(mContext, times(1)).sendBroadcast(any(Intent.class));
        assertEquals("IdleState", getCurrentState().getName());

    }

    @Test
    @MediumTest
    public void testBroadcastUndeliveredMultiPart() throws Exception {