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

Commit c4c8296d authored by Amit Mahajan's avatar Amit Mahajan Committed by android-build-merger
Browse files

Merge "Change to improve purging of orphaned segments from raw db."

am: 1d291fc2

Change-Id: I212027033ade0265f70fab2a268d9188852fee95
parents 07626025 1d291fc2
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -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);

@@ -147,7 +147,6 @@ public class IccSmsInterfaceManager {
        mPhone = phone;
        mContext = context;
        mAppOps = appOps;
        mUserManager = userManager;
        mDispatchersController = dispatchersController;
    }

+2 −0
Original line number Diff line number Diff line
@@ -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
+21 −18
Original line number Diff line number Diff line
@@ -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.
@@ -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.
@@ -99,7 +99,8 @@ public class SmsBroadcastUndelivered {

        @Override
        public void run() {
            scanRawTable(context);
            scanRawTable(context, mCdmaInboundSmsHandler, mGsmInboundSmsHandler,
                    System.currentTimeMillis() - getUndeliveredSmsExpirationTime(context));
            InboundSmsHandler.cancelNewMessageNotification(context);
        }
    }
@@ -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;
@@ -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 {
@@ -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 {
@@ -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!");
@@ -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);
+189 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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;
@@ -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();
@@ -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);
@@ -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:
@@ -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);
    }
}
+6 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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