Loading src/java/com/android/internal/telephony/IccSmsInterfaceManager.java +2 −3 Original line number Diff line number Diff line Loading @@ -86,8 +86,8 @@ public class IccSmsInterfaceManager { protected Phone mPhone; final protected Context mContext; final protected AppOpsManager mAppOps; final private UserManager mUserManager; protected SmsDispatchersController mDispatchersController; @VisibleForTesting public SmsDispatchersController mDispatchersController; private final LocalLog mCellBroadcastLocalLog = new LocalLog(100); Loading Loading @@ -147,7 +147,6 @@ public class IccSmsInterfaceManager { mPhone = phone; mContext = context; mAppOps = appOps; mUserManager = userManager; mDispatchersController = dispatchersController; } Loading src/java/com/android/internal/telephony/InboundSmsHandler.java +2 −0 Original line number Diff line number Diff line Loading @@ -518,6 +518,8 @@ public abstract class InboundSmsHandler extends StateMachine { // Before moving to idle state, set wakelock timeout to WAKE_LOCK_TIMEOUT milliseconds // to give any receivers time to take their own wake locks setWakeLockTimeout(WAKELOCK_TIMEOUT); mPhone.getIccSmsInterfaceManager().mDispatchersController.sendEmptyMessage( SmsDispatchersController.EVENT_SMS_HANDLER_EXITING_WAITING_STATE); } @Override Loading src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java +21 −18 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ import java.util.HashSet; /** * Called when the credential-encrypted storage is unlocked, collecting all acknowledged messages * and deleting any partial message segments older than 30 days. Called from a worker thread to * and deleting any partial message segments older than 7 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. Loading @@ -46,8 +46,8 @@ public class SmsBroadcastUndelivered { private static final String TAG = "SmsBroadcastUndelivered"; private static final boolean DBG = InboundSmsHandler.DBG; /** Delete any partial message segments older than 30 days. */ static final long DEFAULT_PARTIAL_SEGMENT_EXPIRE_AGE = (long) (60 * 60 * 1000) * 24 * 30; /** Delete any partial message segments older than 7 days. */ static final long DEFAULT_PARTIAL_SEGMENT_EXPIRE_AGE = (long) (60 * 60 * 1000) * 24 * 7; /** * Query projection for dispatching pending messages at boot time. Loading Loading @@ -99,7 +99,8 @@ public class SmsBroadcastUndelivered { @Override public void run() { scanRawTable(context); scanRawTable(context, mCdmaInboundSmsHandler, mGsmInboundSmsHandler, System.currentTimeMillis() - getUndeliveredSmsExpirationTime(context)); InboundSmsHandler.cancelNewMessageNotification(context); } } Loading Loading @@ -142,18 +143,19 @@ public class SmsBroadcastUndelivered { /** * Scan the raw table for complete SMS messages to broadcast, and old PDUs to delete. */ private void scanRawTable(Context context) { static void scanRawTable(Context context, CdmaInboundSmsHandler cdmaInboundSmsHandler, GsmInboundSmsHandler gsmInboundSmsHandler, long oldMessageTimestamp) { if (DBG) Rlog.d(TAG, "scanning raw table for undelivered messages"); long startTime = System.nanoTime(); ContentResolver contentResolver = context.getContentResolver(); HashMap<SmsReferenceKey, Integer> multiPartReceivedCount = new HashMap<SmsReferenceKey, Integer>(4); HashSet<SmsReferenceKey> oldMultiPartMessages = new HashSet<SmsReferenceKey>(4); Cursor cursor = null; try { // query only non-deleted ones cursor = mResolver.query(InboundSmsHandler.sRawUri, PDU_PENDING_MESSAGE_PROJECTION, "deleted = 0", null, null); cursor = contentResolver.query(InboundSmsHandler.sRawUri, PDU_PENDING_MESSAGE_PROJECTION, "deleted = 0", null, null); if (cursor == null) { Rlog.e(TAG, "error getting pending message cursor"); return; Loading @@ -172,16 +174,15 @@ public class SmsBroadcastUndelivered { if (tracker.getMessageCount() == 1) { // deliver single-part message broadcastSms(tracker); broadcastSms(tracker, cdmaInboundSmsHandler, gsmInboundSmsHandler); } else { SmsReferenceKey reference = new SmsReferenceKey(tracker); Integer receivedCount = multiPartReceivedCount.get(reference); if (receivedCount == null) { multiPartReceivedCount.put(reference, 1); // first segment seen long expirationTime = getUndeliveredSmsExpirationTime(context); if (tracker.getTimestamp() < (System.currentTimeMillis() - expirationTime)) { // older than 30 days; delete if we don't find all the segments if (tracker.getTimestamp() < oldMessageTimestamp) { // older than oldMessageTimestamp; delete if we don't find all the // segments oldMultiPartMessages.add(reference); } } else { Loading @@ -190,7 +191,7 @@ public class SmsBroadcastUndelivered { // 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); broadcastSms(tracker, cdmaInboundSmsHandler, gsmInboundSmsHandler); // don't delete this old message until after we broadcast it oldMultiPartMessages.remove(reference); } else { Loading @@ -202,7 +203,7 @@ public class SmsBroadcastUndelivered { // Delete old incomplete message segments for (SmsReferenceKey message : oldMultiPartMessages) { // delete permanently int rows = mResolver.delete(InboundSmsHandler.sRawUriPermanentDelete, int rows = contentResolver.delete(InboundSmsHandler.sRawUriPermanentDelete, message.getDeleteWhere(), message.getDeleteWhereArgs()); if (rows == 0) { Rlog.e(TAG, "No rows were deleted from raw table!"); Loading @@ -225,12 +226,14 @@ public class SmsBroadcastUndelivered { /** * Send tracker to appropriate (3GPP or 3GPP2) inbound SMS handler for broadcast. */ private void broadcastSms(InboundSmsTracker tracker) { private static void broadcastSms(InboundSmsTracker tracker, CdmaInboundSmsHandler cdmaInboundSmsHandler, GsmInboundSmsHandler gsmInboundSmsHandler) { InboundSmsHandler handler; if (tracker.is3gpp2()) { handler = mCdmaInboundSmsHandler; handler = cdmaInboundSmsHandler; } else { handler = mGsmInboundSmsHandler; handler = gsmInboundSmsHandler; } if (handler != null) { handler.sendMessage(InboundSmsHandler.EVENT_BROADCAST_SMS, tracker); Loading src/java/com/android/internal/telephony/SmsDispatchersController.java +189 −0 Original line number Diff line number Diff line Loading @@ -22,15 +22,19 @@ import static com.android.internal.telephony.IccSmsInterfaceManager.SMS_MESSAGE_ import android.app.Activity; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.os.UserManager; import android.provider.Telephony.Sms; import android.provider.Telephony.Sms.Intents; import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.SmsManager; import android.telephony.SmsMessage; import android.util.Pair; Loading @@ -51,6 +55,7 @@ import java.util.HashMap; */ public class SmsDispatchersController extends Handler { private static final String TAG = "SmsDispatchersController"; private static final boolean VDBG = false; // STOPSHIP if true /** Radio is ON */ private static final int EVENT_RADIO_ON = 11; Loading @@ -61,6 +66,29 @@ public class SmsDispatchersController extends Handler { /** Callback from RIL_REQUEST_IMS_REGISTRATION_STATE */ private static final int EVENT_IMS_STATE_DONE = 13; /** Service state changed */ private static final int EVENT_SERVICE_STATE_CHANGED = 14; /** Purge old message segments */ private static final int EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY = 15; /** User unlocked the device */ private static final int EVENT_USER_UNLOCKED = 16; /** InboundSmsHandler exited WaitingState */ protected static final int EVENT_SMS_HANDLER_EXITING_WAITING_STATE = 17; /** Delete any partial message segments after being IN_SERVICE for 1 day. */ private static final long PARTIAL_SEGMENT_WAIT_DURATION = (long) (60 * 60 * 1000) * 24; /** Constant for invalid time */ private static final long INVALID_TIME = -1; /** Time at which last IN_SERVICE event was received */ private long mLastInServiceTime = INVALID_TIME; /** Current IN_SERVICE duration */ private long mCurrentWaitElapsedDuration = 0; /** Time at which the current PARTIAL_SEGMENT_WAIT_DURATION timer was started */ private long mCurrentWaitStartTime = INVALID_TIME; private SMSDispatcher mCdmaDispatcher; private SMSDispatcher mGsmDispatcher; private ImsSmsDispatcher mImsSmsDispatcher; Loading Loading @@ -102,11 +130,39 @@ public class SmsDispatchersController extends Handler { mCi.registerForOn(this, EVENT_RADIO_ON, null); mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null); UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); if (userManager.isUserUnlocked()) { if (VDBG) { logd("SmsDispatchersController: user unlocked; registering for service" + "state changed"); } mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); resetPartialSegmentWaitTimer(); } else { if (VDBG) { logd("SmsDispatchersController: user locked; waiting for USER_UNLOCKED"); } IntentFilter userFilter = new IntentFilter(); userFilter.addAction(Intent.ACTION_USER_UNLOCKED); mContext.registerReceiver(mBroadcastReceiver, userFilter); } } private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, Intent intent) { Rlog.d(TAG, "Received broadcast " + intent.getAction()); if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { sendMessage(obtainMessage(EVENT_USER_UNLOCKED)); } } }; public void dispose() { mCi.unregisterForOn(this); mCi.unregisterForImsNetworkStateChanged(this); mPhone.unregisterForServiceStateChanged(this); mGsmDispatcher.dispose(); mCdmaDispatcher.dispose(); mGsmInboundSmsHandler.dispose(); Loading Loading @@ -139,6 +195,23 @@ public class SmsDispatchersController extends Handler { } break; case EVENT_SERVICE_STATE_CHANGED: case EVENT_SMS_HANDLER_EXITING_WAITING_STATE: reevaluateTimerStatus(); break; case EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY: handlePartialSegmentTimerExpiry((Long) msg.obj); break; case EVENT_USER_UNLOCKED: if (VDBG) { logd("handleMessage: EVENT_USER_UNLOCKED"); } mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); resetPartialSegmentWaitTimer(); break; default: if (isCdmaMo()) { mCdmaDispatcher.handleMessage(msg); Loading @@ -148,6 +221,118 @@ public class SmsDispatchersController extends Handler { } } private void reevaluateTimerStatus() { long currentTime = System.currentTimeMillis(); // Remove unhandled timer expiry message. A new message will be posted if needed. removeMessages(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY); // Update timer duration elapsed time (add time since last IN_SERVICE to now). // This is needed for IN_SERVICE as well as OUT_OF_SERVICE because same events can be // received back to back if (mLastInServiceTime != INVALID_TIME) { mCurrentWaitElapsedDuration += (currentTime - mLastInServiceTime); } if (VDBG) { logd("reevaluateTimerStatus: currentTime: " + currentTime + " mCurrentWaitElapsedDuration: " + mCurrentWaitElapsedDuration); } if (mCurrentWaitElapsedDuration > PARTIAL_SEGMENT_WAIT_DURATION) { // handle this event as timer expiry handlePartialSegmentTimerExpiry(mCurrentWaitStartTime); } else { if (isInService()) { handleInService(currentTime); } else { handleOutOfService(currentTime); } } } private void handleInService(long currentTime) { if (VDBG) { logd("handleInService: timer expiry in " + (PARTIAL_SEGMENT_WAIT_DURATION - mCurrentWaitElapsedDuration) + "ms"); } // initialize mCurrentWaitStartTime if needed if (mCurrentWaitStartTime == INVALID_TIME) mCurrentWaitStartTime = currentTime; // Post a message for timer expiry time. mCurrentWaitElapsedDuration is the duration already // elapsed from the timer. sendMessageDelayed( obtainMessage(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY, mCurrentWaitStartTime), PARTIAL_SEGMENT_WAIT_DURATION - mCurrentWaitElapsedDuration); // update mLastInServiceTime as the current time mLastInServiceTime = currentTime; } private void handleOutOfService(long currentTime) { if (VDBG) { logd("handleOutOfService: currentTime: " + currentTime + " mCurrentWaitElapsedDuration: " + mCurrentWaitElapsedDuration); } // mLastInServiceTime is not relevant now since state is OUT_OF_SERVICE; set it to INVALID mLastInServiceTime = INVALID_TIME; } private void handlePartialSegmentTimerExpiry(long waitTimerStart) { if (mGsmInboundSmsHandler.getCurrentState().getName().equals("WaitingState") || mCdmaInboundSmsHandler.getCurrentState().getName().equals("WaitingState")) { logd("handlePartialSegmentTimerExpiry: ignoring timer expiry as InboundSmsHandler is" + " in WaitingState"); return; } if (VDBG) { logd("handlePartialSegmentTimerExpiry: calling scanRawTable()"); } // Timer expired. This indicates that device has been in service for // PARTIAL_SEGMENT_WAIT_DURATION since waitTimerStart. Delete orphaned message segments // older than waitTimerStart. SmsBroadcastUndelivered.scanRawTable(mContext, mCdmaInboundSmsHandler, mGsmInboundSmsHandler, waitTimerStart); if (VDBG) { logd("handlePartialSegmentTimerExpiry: scanRawTable() done"); } resetPartialSegmentWaitTimer(); } private void resetPartialSegmentWaitTimer() { long currentTime = System.currentTimeMillis(); removeMessages(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY); if (isInService()) { if (VDBG) { logd("resetPartialSegmentWaitTimer: currentTime: " + currentTime + " IN_SERVICE"); } mCurrentWaitStartTime = currentTime; mLastInServiceTime = currentTime; sendMessageDelayed( obtainMessage(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY, mCurrentWaitStartTime), PARTIAL_SEGMENT_WAIT_DURATION); } else { if (VDBG) { logd("resetPartialSegmentWaitTimer: currentTime: " + currentTime + " not IN_SERVICE"); } mCurrentWaitStartTime = INVALID_TIME; mLastInServiceTime = INVALID_TIME; } mCurrentWaitElapsedDuration = 0; } private boolean isInService() { ServiceState serviceState = mPhone.getServiceState(); return serviceState != null && serviceState.getState() == ServiceState.STATE_IN_SERVICE; } private void setImsSmsFormat(int format) { switch (format) { case PhoneConstants.PHONE_TYPE_GSM: Loading Loading @@ -625,4 +810,8 @@ public class SmsDispatchersController extends Handler { mGsmInboundSmsHandler.dump(fd, pw, args); mCdmaInboundSmsHandler.dump(fd, pw, args); } private void logd(String msg) { Rlog.d(TAG, msg); } } tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +6 −0 Original line number Diff line number Diff line Loading @@ -185,6 +185,10 @@ public abstract class TelephonyTest { @Mock protected AppSmsManager mAppSmsManager; @Mock protected IccSmsInterfaceManager mIccSmsInterfaceManager; @Mock protected SmsDispatchersController mSmsDispatchersController; @Mock protected DeviceStateMonitor mDeviceStateMonitor; @Mock protected AccessNetworksManager mAccessNetworksManager; Loading Loading @@ -386,6 +390,8 @@ public abstract class TelephonyTest { doReturn(mCarrierSignalAgent).when(mPhone).getCarrierSignalAgent(); doReturn(mCarrierActionAgent).when(mPhone).getCarrierActionAgent(); doReturn(mAppSmsManager).when(mPhone).getAppSmsManager(); doReturn(mIccSmsInterfaceManager).when(mPhone).getIccSmsInterfaceManager(); mIccSmsInterfaceManager.mDispatchersController = mSmsDispatchersController; mPhone.mEriManager = mEriManager; //mUiccController Loading Loading
src/java/com/android/internal/telephony/IccSmsInterfaceManager.java +2 −3 Original line number Diff line number Diff line Loading @@ -86,8 +86,8 @@ public class IccSmsInterfaceManager { protected Phone mPhone; final protected Context mContext; final protected AppOpsManager mAppOps; final private UserManager mUserManager; protected SmsDispatchersController mDispatchersController; @VisibleForTesting public SmsDispatchersController mDispatchersController; private final LocalLog mCellBroadcastLocalLog = new LocalLog(100); Loading Loading @@ -147,7 +147,6 @@ public class IccSmsInterfaceManager { mPhone = phone; mContext = context; mAppOps = appOps; mUserManager = userManager; mDispatchersController = dispatchersController; } Loading
src/java/com/android/internal/telephony/InboundSmsHandler.java +2 −0 Original line number Diff line number Diff line Loading @@ -518,6 +518,8 @@ public abstract class InboundSmsHandler extends StateMachine { // Before moving to idle state, set wakelock timeout to WAKE_LOCK_TIMEOUT milliseconds // to give any receivers time to take their own wake locks setWakeLockTimeout(WAKELOCK_TIMEOUT); mPhone.getIccSmsInterfaceManager().mDispatchersController.sendEmptyMessage( SmsDispatchersController.EVENT_SMS_HANDLER_EXITING_WAITING_STATE); } @Override Loading
src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java +21 −18 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ import java.util.HashSet; /** * Called when the credential-encrypted storage is unlocked, collecting all acknowledged messages * and deleting any partial message segments older than 30 days. Called from a worker thread to * and deleting any partial message segments older than 7 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. Loading @@ -46,8 +46,8 @@ public class SmsBroadcastUndelivered { private static final String TAG = "SmsBroadcastUndelivered"; private static final boolean DBG = InboundSmsHandler.DBG; /** Delete any partial message segments older than 30 days. */ static final long DEFAULT_PARTIAL_SEGMENT_EXPIRE_AGE = (long) (60 * 60 * 1000) * 24 * 30; /** Delete any partial message segments older than 7 days. */ static final long DEFAULT_PARTIAL_SEGMENT_EXPIRE_AGE = (long) (60 * 60 * 1000) * 24 * 7; /** * Query projection for dispatching pending messages at boot time. Loading Loading @@ -99,7 +99,8 @@ public class SmsBroadcastUndelivered { @Override public void run() { scanRawTable(context); scanRawTable(context, mCdmaInboundSmsHandler, mGsmInboundSmsHandler, System.currentTimeMillis() - getUndeliveredSmsExpirationTime(context)); InboundSmsHandler.cancelNewMessageNotification(context); } } Loading Loading @@ -142,18 +143,19 @@ public class SmsBroadcastUndelivered { /** * Scan the raw table for complete SMS messages to broadcast, and old PDUs to delete. */ private void scanRawTable(Context context) { static void scanRawTable(Context context, CdmaInboundSmsHandler cdmaInboundSmsHandler, GsmInboundSmsHandler gsmInboundSmsHandler, long oldMessageTimestamp) { if (DBG) Rlog.d(TAG, "scanning raw table for undelivered messages"); long startTime = System.nanoTime(); ContentResolver contentResolver = context.getContentResolver(); HashMap<SmsReferenceKey, Integer> multiPartReceivedCount = new HashMap<SmsReferenceKey, Integer>(4); HashSet<SmsReferenceKey> oldMultiPartMessages = new HashSet<SmsReferenceKey>(4); Cursor cursor = null; try { // query only non-deleted ones cursor = mResolver.query(InboundSmsHandler.sRawUri, PDU_PENDING_MESSAGE_PROJECTION, "deleted = 0", null, null); cursor = contentResolver.query(InboundSmsHandler.sRawUri, PDU_PENDING_MESSAGE_PROJECTION, "deleted = 0", null, null); if (cursor == null) { Rlog.e(TAG, "error getting pending message cursor"); return; Loading @@ -172,16 +174,15 @@ public class SmsBroadcastUndelivered { if (tracker.getMessageCount() == 1) { // deliver single-part message broadcastSms(tracker); broadcastSms(tracker, cdmaInboundSmsHandler, gsmInboundSmsHandler); } else { SmsReferenceKey reference = new SmsReferenceKey(tracker); Integer receivedCount = multiPartReceivedCount.get(reference); if (receivedCount == null) { multiPartReceivedCount.put(reference, 1); // first segment seen long expirationTime = getUndeliveredSmsExpirationTime(context); if (tracker.getTimestamp() < (System.currentTimeMillis() - expirationTime)) { // older than 30 days; delete if we don't find all the segments if (tracker.getTimestamp() < oldMessageTimestamp) { // older than oldMessageTimestamp; delete if we don't find all the // segments oldMultiPartMessages.add(reference); } } else { Loading @@ -190,7 +191,7 @@ public class SmsBroadcastUndelivered { // 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); broadcastSms(tracker, cdmaInboundSmsHandler, gsmInboundSmsHandler); // don't delete this old message until after we broadcast it oldMultiPartMessages.remove(reference); } else { Loading @@ -202,7 +203,7 @@ public class SmsBroadcastUndelivered { // Delete old incomplete message segments for (SmsReferenceKey message : oldMultiPartMessages) { // delete permanently int rows = mResolver.delete(InboundSmsHandler.sRawUriPermanentDelete, int rows = contentResolver.delete(InboundSmsHandler.sRawUriPermanentDelete, message.getDeleteWhere(), message.getDeleteWhereArgs()); if (rows == 0) { Rlog.e(TAG, "No rows were deleted from raw table!"); Loading @@ -225,12 +226,14 @@ public class SmsBroadcastUndelivered { /** * Send tracker to appropriate (3GPP or 3GPP2) inbound SMS handler for broadcast. */ private void broadcastSms(InboundSmsTracker tracker) { private static void broadcastSms(InboundSmsTracker tracker, CdmaInboundSmsHandler cdmaInboundSmsHandler, GsmInboundSmsHandler gsmInboundSmsHandler) { InboundSmsHandler handler; if (tracker.is3gpp2()) { handler = mCdmaInboundSmsHandler; handler = cdmaInboundSmsHandler; } else { handler = mGsmInboundSmsHandler; handler = gsmInboundSmsHandler; } if (handler != null) { handler.sendMessage(InboundSmsHandler.EVENT_BROADCAST_SMS, tracker); Loading
src/java/com/android/internal/telephony/SmsDispatchersController.java +189 −0 Original line number Diff line number Diff line Loading @@ -22,15 +22,19 @@ import static com.android.internal.telephony.IccSmsInterfaceManager.SMS_MESSAGE_ import android.app.Activity; import android.app.PendingIntent; import android.app.PendingIntent.CanceledException; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.os.AsyncResult; import android.os.Handler; import android.os.Message; import android.os.UserManager; import android.provider.Telephony.Sms; import android.provider.Telephony.Sms.Intents; import android.telephony.Rlog; import android.telephony.ServiceState; import android.telephony.SmsManager; import android.telephony.SmsMessage; import android.util.Pair; Loading @@ -51,6 +55,7 @@ import java.util.HashMap; */ public class SmsDispatchersController extends Handler { private static final String TAG = "SmsDispatchersController"; private static final boolean VDBG = false; // STOPSHIP if true /** Radio is ON */ private static final int EVENT_RADIO_ON = 11; Loading @@ -61,6 +66,29 @@ public class SmsDispatchersController extends Handler { /** Callback from RIL_REQUEST_IMS_REGISTRATION_STATE */ private static final int EVENT_IMS_STATE_DONE = 13; /** Service state changed */ private static final int EVENT_SERVICE_STATE_CHANGED = 14; /** Purge old message segments */ private static final int EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY = 15; /** User unlocked the device */ private static final int EVENT_USER_UNLOCKED = 16; /** InboundSmsHandler exited WaitingState */ protected static final int EVENT_SMS_HANDLER_EXITING_WAITING_STATE = 17; /** Delete any partial message segments after being IN_SERVICE for 1 day. */ private static final long PARTIAL_SEGMENT_WAIT_DURATION = (long) (60 * 60 * 1000) * 24; /** Constant for invalid time */ private static final long INVALID_TIME = -1; /** Time at which last IN_SERVICE event was received */ private long mLastInServiceTime = INVALID_TIME; /** Current IN_SERVICE duration */ private long mCurrentWaitElapsedDuration = 0; /** Time at which the current PARTIAL_SEGMENT_WAIT_DURATION timer was started */ private long mCurrentWaitStartTime = INVALID_TIME; private SMSDispatcher mCdmaDispatcher; private SMSDispatcher mGsmDispatcher; private ImsSmsDispatcher mImsSmsDispatcher; Loading Loading @@ -102,11 +130,39 @@ public class SmsDispatchersController extends Handler { mCi.registerForOn(this, EVENT_RADIO_ON, null); mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null); UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); if (userManager.isUserUnlocked()) { if (VDBG) { logd("SmsDispatchersController: user unlocked; registering for service" + "state changed"); } mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); resetPartialSegmentWaitTimer(); } else { if (VDBG) { logd("SmsDispatchersController: user locked; waiting for USER_UNLOCKED"); } IntentFilter userFilter = new IntentFilter(); userFilter.addAction(Intent.ACTION_USER_UNLOCKED); mContext.registerReceiver(mBroadcastReceiver, userFilter); } } private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, Intent intent) { Rlog.d(TAG, "Received broadcast " + intent.getAction()); if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { sendMessage(obtainMessage(EVENT_USER_UNLOCKED)); } } }; public void dispose() { mCi.unregisterForOn(this); mCi.unregisterForImsNetworkStateChanged(this); mPhone.unregisterForServiceStateChanged(this); mGsmDispatcher.dispose(); mCdmaDispatcher.dispose(); mGsmInboundSmsHandler.dispose(); Loading Loading @@ -139,6 +195,23 @@ public class SmsDispatchersController extends Handler { } break; case EVENT_SERVICE_STATE_CHANGED: case EVENT_SMS_HANDLER_EXITING_WAITING_STATE: reevaluateTimerStatus(); break; case EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY: handlePartialSegmentTimerExpiry((Long) msg.obj); break; case EVENT_USER_UNLOCKED: if (VDBG) { logd("handleMessage: EVENT_USER_UNLOCKED"); } mPhone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null); resetPartialSegmentWaitTimer(); break; default: if (isCdmaMo()) { mCdmaDispatcher.handleMessage(msg); Loading @@ -148,6 +221,118 @@ public class SmsDispatchersController extends Handler { } } private void reevaluateTimerStatus() { long currentTime = System.currentTimeMillis(); // Remove unhandled timer expiry message. A new message will be posted if needed. removeMessages(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY); // Update timer duration elapsed time (add time since last IN_SERVICE to now). // This is needed for IN_SERVICE as well as OUT_OF_SERVICE because same events can be // received back to back if (mLastInServiceTime != INVALID_TIME) { mCurrentWaitElapsedDuration += (currentTime - mLastInServiceTime); } if (VDBG) { logd("reevaluateTimerStatus: currentTime: " + currentTime + " mCurrentWaitElapsedDuration: " + mCurrentWaitElapsedDuration); } if (mCurrentWaitElapsedDuration > PARTIAL_SEGMENT_WAIT_DURATION) { // handle this event as timer expiry handlePartialSegmentTimerExpiry(mCurrentWaitStartTime); } else { if (isInService()) { handleInService(currentTime); } else { handleOutOfService(currentTime); } } } private void handleInService(long currentTime) { if (VDBG) { logd("handleInService: timer expiry in " + (PARTIAL_SEGMENT_WAIT_DURATION - mCurrentWaitElapsedDuration) + "ms"); } // initialize mCurrentWaitStartTime if needed if (mCurrentWaitStartTime == INVALID_TIME) mCurrentWaitStartTime = currentTime; // Post a message for timer expiry time. mCurrentWaitElapsedDuration is the duration already // elapsed from the timer. sendMessageDelayed( obtainMessage(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY, mCurrentWaitStartTime), PARTIAL_SEGMENT_WAIT_DURATION - mCurrentWaitElapsedDuration); // update mLastInServiceTime as the current time mLastInServiceTime = currentTime; } private void handleOutOfService(long currentTime) { if (VDBG) { logd("handleOutOfService: currentTime: " + currentTime + " mCurrentWaitElapsedDuration: " + mCurrentWaitElapsedDuration); } // mLastInServiceTime is not relevant now since state is OUT_OF_SERVICE; set it to INVALID mLastInServiceTime = INVALID_TIME; } private void handlePartialSegmentTimerExpiry(long waitTimerStart) { if (mGsmInboundSmsHandler.getCurrentState().getName().equals("WaitingState") || mCdmaInboundSmsHandler.getCurrentState().getName().equals("WaitingState")) { logd("handlePartialSegmentTimerExpiry: ignoring timer expiry as InboundSmsHandler is" + " in WaitingState"); return; } if (VDBG) { logd("handlePartialSegmentTimerExpiry: calling scanRawTable()"); } // Timer expired. This indicates that device has been in service for // PARTIAL_SEGMENT_WAIT_DURATION since waitTimerStart. Delete orphaned message segments // older than waitTimerStart. SmsBroadcastUndelivered.scanRawTable(mContext, mCdmaInboundSmsHandler, mGsmInboundSmsHandler, waitTimerStart); if (VDBG) { logd("handlePartialSegmentTimerExpiry: scanRawTable() done"); } resetPartialSegmentWaitTimer(); } private void resetPartialSegmentWaitTimer() { long currentTime = System.currentTimeMillis(); removeMessages(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY); if (isInService()) { if (VDBG) { logd("resetPartialSegmentWaitTimer: currentTime: " + currentTime + " IN_SERVICE"); } mCurrentWaitStartTime = currentTime; mLastInServiceTime = currentTime; sendMessageDelayed( obtainMessage(EVENT_PARTIAL_SEGMENT_TIMER_EXPIRY, mCurrentWaitStartTime), PARTIAL_SEGMENT_WAIT_DURATION); } else { if (VDBG) { logd("resetPartialSegmentWaitTimer: currentTime: " + currentTime + " not IN_SERVICE"); } mCurrentWaitStartTime = INVALID_TIME; mLastInServiceTime = INVALID_TIME; } mCurrentWaitElapsedDuration = 0; } private boolean isInService() { ServiceState serviceState = mPhone.getServiceState(); return serviceState != null && serviceState.getState() == ServiceState.STATE_IN_SERVICE; } private void setImsSmsFormat(int format) { switch (format) { case PhoneConstants.PHONE_TYPE_GSM: Loading Loading @@ -625,4 +810,8 @@ public class SmsDispatchersController extends Handler { mGsmInboundSmsHandler.dump(fd, pw, args); mCdmaInboundSmsHandler.dump(fd, pw, args); } private void logd(String msg) { Rlog.d(TAG, msg); } }
tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java +6 −0 Original line number Diff line number Diff line Loading @@ -185,6 +185,10 @@ public abstract class TelephonyTest { @Mock protected AppSmsManager mAppSmsManager; @Mock protected IccSmsInterfaceManager mIccSmsInterfaceManager; @Mock protected SmsDispatchersController mSmsDispatchersController; @Mock protected DeviceStateMonitor mDeviceStateMonitor; @Mock protected AccessNetworksManager mAccessNetworksManager; Loading Loading @@ -386,6 +390,8 @@ public abstract class TelephonyTest { doReturn(mCarrierSignalAgent).when(mPhone).getCarrierSignalAgent(); doReturn(mCarrierActionAgent).when(mPhone).getCarrierActionAgent(); doReturn(mAppSmsManager).when(mPhone).getAppSmsManager(); doReturn(mIccSmsInterfaceManager).when(mPhone).getIccSmsInterfaceManager(); mIccSmsInterfaceManager.mDispatchersController = mSmsDispatchersController; mPhone.mEriManager = mEriManager; //mUiccController Loading