Telephony: Ignore events on a destroyed phone
Wink Saville [Thu, 12 Sep 2013 20:40:41 +0000 (13:40 -0700)]
It is possible to receive responses from RIL after phone has released
it's references. Ignore events in such cases, since those events no
longer make sense, and some phone members have been de-initialized.

Make CallTrackers notify UI when ending calls in dispose, since
it has already unregistered, and won't receive the CALL_STATE_CHANGED

Change-Id: I5d8fd9ce3f74b9ae9b5b645565bd24d11be0aebc
CRs-Fixed: 228731, 228005, 415801, 350739

src/java/com/android/internal/telephony/PhoneBase.java
src/java/com/android/internal/telephony/cdma/CDMAPhone.java
src/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
src/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
src/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
src/java/com/android/internal/telephony/gsm/GSMPhone.java
src/java/com/android/internal/telephony/gsm/GsmCallTracker.java
src/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java

index 4208326..c78b6c2 100644 (file)
@@ -341,6 +341,11 @@ public abstract class PhoneBase extends Handler implements Phone {
     public void handleMessage(Message msg) {
         AsyncResult ar;
 
+        if (!mIsTheCurrentActivePhone) {
+            Rlog.e(LOG_TAG, "Received message " + msg +
+                    "[" + msg.what + "] while being destroyed. Ignoring.");
+            return;
+        }
         switch(msg.what) {
             case EVENT_CALL_RING:
                 Rlog.d(LOG_TAG, "Event EVENT_CALL_RING Received state=" + getState());
index f3798ca..f783e79 100644 (file)
@@ -1080,6 +1080,11 @@ public class CDMAPhone extends PhoneBase {
         AsyncResult ar;
         Message     onComplete;
 
+        if (!mIsTheCurrentActivePhone) {
+            Rlog.e(LOG_TAG, "Received message " + msg +
+                    "[" + msg.what + "] while being destroyed. Ignoring.");
+            return;
+        }
         switch(msg.what) {
             case EVENT_RADIO_AVAILABLE: {
                 mCi.getBasebandVersion(obtainMessage(EVENT_GET_BASEBAND_VERSION_DONE));
index 7f76701..cfcc003 100644 (file)
@@ -110,16 +110,26 @@ public final class CdmaCallTracker extends CallTracker {
         mCi.unregisterForCallWaitingInfo(this);
         for(CdmaConnection c : mConnections) {
             try {
-                if(c != null) hangup(c);
+                if(c != null) {
+                    hangup(c);
+                    // Since by now we are unregistered, we won't notify
+                    // PhoneApp that the call is gone. Do that here
+                    Rlog.d(LOG_TAG, "dispose: call connnection onDisconnect, cause LOST_SIGNAL");
+                    c.onDisconnect(Connection.DisconnectCause.LOST_SIGNAL);
+                }
             } catch (CallStateException ex) {
-                Rlog.e(LOG_TAG, "unexpected error on hangup during dispose");
+                Rlog.e(LOG_TAG, "dispose: unexpected error on hangup", ex);
             }
         }
 
         try {
-            if(mPendingMO != null) hangup(mPendingMO);
+            if(mPendingMO != null) {
+                hangup(mPendingMO);
+                Rlog.d(LOG_TAG, "dispose: call mPendingMO.onDsiconnect, cause LOST_SIGNAL");
+                mPendingMO.onDisconnect(Connection.DisconnectCause.LOST_SIGNAL);
+            }
         } catch (CallStateException ex) {
-            Rlog.e(LOG_TAG, "unexpected error on hangup during dispose");
+            Rlog.e(LOG_TAG, "dispose: unexpected error on hangup", ex);
         }
 
         clearDisconnected();
@@ -922,6 +932,10 @@ public final class CdmaCallTracker extends CallTracker {
     handleMessage (Message msg) {
         AsyncResult ar;
 
+        if (!mPhone.mIsTheCurrentActivePhone) {
+            Rlog.w(LOG_TAG, "Ignoring events received on inactive CdmaPhone");
+            return;
+        }
         switch (msg.what) {
             case EVENT_POLL_CALLS_RESULT:{
                 Rlog.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received");
index 4ca0405..6d1084b 100644 (file)
@@ -66,6 +66,13 @@ public class CdmaLteServiceStateTracker extends CdmaServiceStateTracker {
         AsyncResult ar;
         int[] ints;
         String[] strings;
+
+        if (!mPhone.mIsTheCurrentActivePhone) {
+            loge("Received message " + msg + "[" + msg.what + "]" +
+                    " while being destroyed. Ignoring.");
+            return;
+        }
+
         switch (msg.what) {
         case EVENT_POLL_STATE_GPRS:
             if (DBG) log("handleMessage EVENT_POLL_STATE_GPRS");
index 6d94d7c..1e08c37 100644 (file)
@@ -203,6 +203,8 @@ public class CdmaServiceStateTracker extends ServiceStateTracker {
     @Override
     public void dispose() {
         checkCorrectThread();
+        log("ServiceStateTracker dispose");
+
         // Unregister for all events.
         mCi.unregisterForRadioStateChanged(this);
         mCi.unregisterForVoiceNetworkStateChanged(this);
index 18a2e25..95dd084 100644 (file)
@@ -1227,6 +1227,11 @@ public class GSMPhone extends PhoneBase {
         AsyncResult ar;
         Message onComplete;
 
+        if (!mIsTheCurrentActivePhone) {
+            Rlog.e(LOG_TAG, "Received message " + msg +
+                    "[" + msg.what + "] while being destroyed. Ignoring.");
+            return;
+        }
         switch (msg.what) {
             case EVENT_RADIO_AVAILABLE: {
                 mCi.getBasebandVersion(
index 8287088..96978fa 100644 (file)
@@ -78,7 +78,7 @@ public final class GsmCallTracker extends CallTracker {
     GsmCall mForegroundCall = new GsmCall(this);
     GsmCall mBackgroundCall = new GsmCall(this);
 
-    GsmConnection pendingMO;
+    GsmConnection mPendingMO;
     boolean mHangupPendingMO;
 
     GSMPhone mPhone;
@@ -112,16 +112,26 @@ public final class GsmCallTracker extends CallTracker {
 
         for(GsmConnection c : mConnections) {
             try {
-                if(c != null) hangup(c);
+                if(c != null) {
+                    hangup(c);
+                    // Since by now we are unregistered, we won't notify
+                    // PhoneApp that the call is gone. Do that here
+                    Rlog.d(LOG_TAG, "dispose: call connnection onDisconnect, cause LOST_SIGNAL");
+                    c.onDisconnect(Connection.DisconnectCause.LOST_SIGNAL);
+                }
             } catch (CallStateException ex) {
-                Rlog.e(LOG_TAG, "unexpected error on hangup during dispose");
+                Rlog.e(LOG_TAG, "dispose: unexpected error on hangup", ex);
             }
         }
 
         try {
-            if(pendingMO != null) hangup(pendingMO);
+            if(mPendingMO != null) {
+                hangup(mPendingMO);
+                Rlog.d(LOG_TAG, "dispose: call mPendingMO.onDsiconnect, cause LOST_SIGNAL");
+                mPendingMO.onDisconnect(Connection.DisconnectCause.LOST_SIGNAL);
+            }
         } catch (CallStateException ex) {
-            Rlog.e(LOG_TAG, "unexpected error on hangup during dispose");
+            Rlog.e(LOG_TAG, "dispose: unexpected error on hangup", ex);
         }
 
         clearDisconnected();
@@ -206,15 +216,15 @@ public final class GsmCallTracker extends CallTracker {
             throw new CallStateException("cannot dial in current state");
         }
 
-        pendingMO = new GsmConnection(mPhone.getContext(), checkForTestEmergencyNumber(dialString),
+        mPendingMO = new GsmConnection(mPhone.getContext(), checkForTestEmergencyNumber(dialString),
                 this, mForegroundCall);
         mHangupPendingMO = false;
 
-        if (pendingMO.mAddress == null || pendingMO.mAddress.length() == 0
-            || pendingMO.mAddress.indexOf(PhoneNumberUtils.WILD) >= 0
+        if (mPendingMO.mAddress == null || mPendingMO.mAddress.length() == 0
+            || mPendingMO.mAddress.indexOf(PhoneNumberUtils.WILD) >= 0
         ) {
             // Phone number is invalid
-            pendingMO.mCause = Connection.DisconnectCause.INVALID_NUMBER;
+            mPendingMO.mCause = Connection.DisconnectCause.INVALID_NUMBER;
 
             // handlePollCalls() will notice this call not present
             // and will mark it as dropped.
@@ -223,13 +233,13 @@ public final class GsmCallTracker extends CallTracker {
             // Always unmute when initiating a new call
             setMute(false);
 
-            mCi.dial(pendingMO.mAddress, clirMode, uusInfo, obtainCompleteMessage());
+            mCi.dial(mPendingMO.mAddress, clirMode, uusInfo, obtainCompleteMessage());
         }
 
         updatePhoneState();
         mPhone.notifyPreciseCallStateChanged();
 
-        return pendingMO;
+        return mPendingMO;
     }
 
     Connection
@@ -322,7 +332,7 @@ public final class GsmCallTracker extends CallTracker {
                 TelephonyProperties.PROPERTY_DISABLE_CALL, "false");
 
         ret = (serviceState != ServiceState.STATE_POWER_OFF)
-                && pendingMO == null
+                && mPendingMO == null
                 && !mRingingCall.isRinging()
                 && !disableCall.equals("true")
                 && (!mForegroundCall.getState().isAlive()
@@ -394,7 +404,7 @@ public final class GsmCallTracker extends CallTracker {
 
         if (mRingingCall.isRinging()) {
             mState = PhoneConstants.State.RINGING;
-        } else if (pendingMO != null ||
+        } else if (mPendingMO != null ||
                 !(mForegroundCall.isIdle() && mBackgroundCall.isIdle())) {
             mState = PhoneConstants.State.OFFHOOK;
         } else {
@@ -460,15 +470,15 @@ public final class GsmCallTracker extends CallTracker {
 
             if (conn == null && dc != null) {
                 // Connection appeared in CLCC response that we don't know about
-                if (pendingMO != null && pendingMO.compareTo(dc)) {
+                if (mPendingMO != null && mPendingMO.compareTo(dc)) {
 
-                    if (DBG_POLL) log("poll: pendingMO=" + pendingMO);
+                    if (DBG_POLL) log("poll: pendingMO=" + mPendingMO);
 
                     // It's our pending mobile originating call
-                    mConnections[i] = pendingMO;
-                    pendingMO.mIndex = i;
-                    pendingMO.update(dc);
-                    pendingMO = null;
+                    mConnections[i] = mPendingMO;
+                    mPendingMO.mIndex = i;
+                    mPendingMO.update(dc);
+                    mPendingMO = null;
 
                     // Someone has already asked to hangup this call
                     if (mHangupPendingMO) {
@@ -562,12 +572,12 @@ public final class GsmCallTracker extends CallTracker {
         // This is the first poll after an ATD.
         // We expect the pending call to appear in the list
         // If it does not, we land here
-        if (pendingMO != null) {
+        if (mPendingMO != null) {
             Rlog.d(LOG_TAG,"Pending MO dropped before poll fg state:"
                             + mForegroundCall.getState());
 
-            mDroppedDuringPoll.add(pendingMO);
-            pendingMO = null;
+            mDroppedDuringPoll.add(mPendingMO);
+            mPendingMO = null;
             mHangupPendingMO = false;
         }
 
@@ -681,7 +691,7 @@ public final class GsmCallTracker extends CallTracker {
                                     + "does not belong to GsmCallTracker " + this);
         }
 
-        if (conn == pendingMO) {
+        if (conn == mPendingMO) {
             // We're hanging up an outgoing call that doesn't have it's
             // GSM index assigned yet
 
@@ -843,6 +853,11 @@ public final class GsmCallTracker extends CallTracker {
     handleMessage (Message msg) {
         AsyncResult ar;
 
+        if (!mPhone.mIsTheCurrentActivePhone) {
+            Rlog.e(LOG_TAG, "Received message " + msg +
+                    "[" + msg.what + "] while being destroyed. Ignoring.");
+            return;
+        }
         switch (msg.what) {
             case EVENT_POLL_CALLS_RESULT:
                 ar = (AsyncResult)msg.obj;
@@ -952,7 +967,7 @@ public final class GsmCallTracker extends CallTracker {
         pw.println(" mRingingCall=" + mRingingCall);
         pw.println(" mForegroundCall=" + mForegroundCall);
         pw.println(" mBackgroundCall=" + mBackgroundCall);
-        pw.println(" mPendingMO=" + pendingMO);
+        pw.println(" mPendingMO=" + mPendingMO);
         pw.println(" mHangupPendingMO=" + mHangupPendingMO);
         pw.println(" mPhone=" + mPhone);
         pw.println(" mDesiredMute=" + mDesiredMute);
index 1cf5a76..aacd50a 100644 (file)
@@ -168,6 +168,12 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
+            if (!mPhone.mIsTheCurrentActivePhone) {
+                Rlog.e(LOG_TAG, "Received Intent " + intent +
+                        " while being destroyed. Ignoring.");
+                return;
+            }
+
             if (intent.getAction().equals(Intent.ACTION_LOCALE_CHANGED)) {
                 // update emergency string whenever locale changed
                 updateSpnDisplay();
@@ -237,6 +243,8 @@ final class GsmServiceStateTracker extends ServiceStateTracker {
     @Override
     public void dispose() {
         checkCorrectThread();
+        log("ServiceStateTracker dispose");
+
         // Unregister for all events.
         mCi.unregisterForAvailable(this);
         mCi.unregisterForRadioStateChanged(this);