SmsBroadcastUndeliveredpublic class SmsBroadcastUndelivered extends Object implements RunnableCalled 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_AGEDelete any partial message segments older than 30 days. | private static final String[] | PDU_PENDING_MESSAGE_PROJECTIONQuery 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 | sRawUriURI for raw table from SmsProvider. | private final android.content.ContentResolver | mResolverContent resolver to use to access raw table from SmsProvider. | private final com.android.internal.telephony.gsm.GsmInboundSmsHandler | mGsmInboundSmsHandlerHandler for 3GPP-format messages (may be null). | private final com.android.internal.telephony.cdma.CdmaInboundSmsHandler | mCdmaInboundSmsHandlerHandler for 3GPP2-format messages (may be null). |
Methods Summary |
---|
private void | broadcastSms(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 void | run()
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 void | scanRawTable()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");
}
|
|