FileDocCategorySizeDatePackage
SmsBroadcastUndelivered.javaAPI DocAndroid 5.1 API9132Thu Mar 12 22:22:54 GMT 2015com.android.internal.telephony

SmsBroadcastUndelivered

public class SmsBroadcastUndelivered extends Object implements Runnable
Called at boot time to clean out the raw table, collecting all acknowledged messages and deleting any partial message segments older than 30 days. Called from a worker thread to avoid delaying phone app startup. The last step is to broadcast the first pending message from the main thread, then the remaining pending messages will be broadcast after the previous ordered broadcast completes.

Fields Summary
private static final String
TAG
private static final boolean
DBG
static final long
PARTIAL_SEGMENT_EXPIRE_AGE
Delete any partial message segments older than 30 days.
private static final String[]
PDU_PENDING_MESSAGE_PROJECTION
Query projection for dispatching pending messages at boot time. Column order must match the {@code *_COLUMN} constants in {@link InboundSmsHandler}.
private static final android.net.Uri
sRawUri
URI for raw table from SmsProvider.
private final android.content.ContentResolver
mResolver
Content resolver to use to access raw table from SmsProvider.
private final com.android.internal.telephony.gsm.GsmInboundSmsHandler
mGsmInboundSmsHandler
Handler for 3GPP-format messages (may be null).
private final com.android.internal.telephony.cdma.CdmaInboundSmsHandler
mCdmaInboundSmsHandler
Handler for 3GPP2-format messages (may be null).
Constructors Summary
public SmsBroadcastUndelivered(android.content.Context context, com.android.internal.telephony.gsm.GsmInboundSmsHandler gsmInboundSmsHandler, com.android.internal.telephony.cdma.CdmaInboundSmsHandler cdmaInboundSmsHandler)


        
              
        mResolver = context.getContentResolver();
        mGsmInboundSmsHandler = gsmInboundSmsHandler;
        mCdmaInboundSmsHandler = cdmaInboundSmsHandler;
    
Methods Summary
private voidbroadcastSms(InboundSmsTracker tracker)
Send tracker to appropriate (3GPP or 3GPP2) inbound SMS handler for broadcast.

        InboundSmsHandler handler;
        if (tracker.is3gpp2()) {
            handler = mCdmaInboundSmsHandler;
        } else {
            handler = mGsmInboundSmsHandler;
        }
        if (handler != null) {
            handler.sendMessage(InboundSmsHandler.EVENT_BROADCAST_SMS, tracker);
        } else {
            Rlog.e(TAG, "null handler for " + tracker.getFormat() + " format, can't deliver.");
        }
    
public voidrun()

        if (DBG) Rlog.d(TAG, "scanning raw table for undelivered messages");
        scanRawTable();
        // tell handlers to start processing new messages
        if (mGsmInboundSmsHandler != null) {
            mGsmInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_START_ACCEPTING_SMS);
        }
        if (mCdmaInboundSmsHandler != null) {
            mCdmaInboundSmsHandler.sendMessage(InboundSmsHandler.EVENT_START_ACCEPTING_SMS);
        }
    
private voidscanRawTable()
Scan the raw table for complete SMS messages to broadcast, and old PDUs to delete.

        long startTime = System.nanoTime();
        HashMap<SmsReferenceKey, Integer> multiPartReceivedCount =
                new HashMap<SmsReferenceKey, Integer>(4);
        HashSet<SmsReferenceKey> oldMultiPartMessages = new HashSet<SmsReferenceKey>(4);
        Cursor cursor = null;
        try {
            cursor = mResolver.query(sRawUri, PDU_PENDING_MESSAGE_PROJECTION, null, null, null);
            if (cursor == null) {
                Rlog.e(TAG, "error getting pending message cursor");
                return;
            }

            boolean isCurrentFormat3gpp2 = InboundSmsHandler.isCurrentFormat3gpp2();
            while (cursor.moveToNext()) {
                InboundSmsTracker tracker;
                try {
                    tracker = new InboundSmsTracker(cursor, isCurrentFormat3gpp2);
                } catch (IllegalArgumentException e) {
                    Rlog.e(TAG, "error loading SmsTracker: " + e);
                    continue;
                }

                if (tracker.getMessageCount() == 1) {
                    // deliver single-part message
                    broadcastSms(tracker);
                } else {
                    SmsReferenceKey reference = new SmsReferenceKey(tracker);
                    Integer receivedCount = multiPartReceivedCount.get(reference);
                    if (receivedCount == null) {
                        multiPartReceivedCount.put(reference, 1);    // first segment seen
                        if (tracker.getTimestamp() <
                                (System.currentTimeMillis() - PARTIAL_SEGMENT_EXPIRE_AGE)) {
                            // older than 30 days; delete if we don't find all the segments
                            oldMultiPartMessages.add(reference);
                        }
                    } else {
                        int newCount = receivedCount + 1;
                        if (newCount == tracker.getMessageCount()) {
                            // looks like we've got all the pieces; send a single tracker
                            // to state machine which will find the other pieces to broadcast
                            if (DBG) Rlog.d(TAG, "found complete multi-part message");
                            broadcastSms(tracker);
                            // don't delete this old message until after we broadcast it
                            oldMultiPartMessages.remove(reference);
                        } else {
                            multiPartReceivedCount.put(reference, newCount);
                        }
                    }
                }
            }
            // Delete old incomplete message segments
            for (SmsReferenceKey message : oldMultiPartMessages) {
                int rows = mResolver.delete(sRawUri, InboundSmsHandler.SELECT_BY_REFERENCE,
                        message.getDeleteWhereArgs());
                if (rows == 0) {
                    Rlog.e(TAG, "No rows were deleted from raw table!");
                } else if (DBG) {
                    Rlog.d(TAG, "Deleted " + rows + " rows from raw table for incomplete "
                            + message.mMessageCount + " part message");
                }
            }
        } catch (SQLException e) {
            Rlog.e(TAG, "error reading pending SMS messages", e);
        } finally {
            if (cursor != null) {
                cursor.close();
            }
            if (DBG) Rlog.d(TAG, "finished scanning raw table in "
                    + ((System.nanoTime() - startTime) / 1000000) + " ms");
        }