Handle potential SecurityException in PstnIncomingCallNotifier.

There is a potential for the incoming call phone account to not exist
in some rare cases.  I suspect this involves a profile change on
MVNO carriers which aggregate other carriers together.  This change
catches the exception Telecom throws when the phone account is no longer
registered and logs a WTF so that crash clustering can be performed on
the issue.  The logs include detailed information about the phone account
state on the device so we can analyze this further.  The incoming call is
rejected instead of crashing the device.

Test: Change code so that a security exception is always thrown; verify
in logcat that the crash logs include detailed information about the
call and phone account state at the time of the problem. Verified that
the call is silently rejected in this case.
Fixes: 147978774

Change-Id: I7a000a70b3a8b8883d4aaa8d34c99e4eb33335bb
diff --git a/src/com/android/services/telephony/PstnIncomingCallNotifier.java b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
index a917f3d..1c1725f 100644
--- a/src/com/android/services/telephony/PstnIncomingCallNotifier.java
+++ b/src/com/android/services/telephony/PstnIncomingCallNotifier.java
@@ -25,7 +25,6 @@
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telecom.TelecomManager;
-import com.android.telephony.Rlog;
 import android.text.TextUtils;
 
 import com.android.internal.telephony.Call;
@@ -40,8 +39,11 @@
 import com.android.internal.telephony.imsphone.ImsPhoneConnection;
 import com.android.phone.NumberVerificationManager;
 import com.android.phone.PhoneUtils;
+import com.android.telephony.Rlog;
 
+import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 /**
  * Listens to incoming-call events from the associated phone object and notifies Telecom upon each
@@ -291,12 +293,48 @@
             } catch (CallStateException e) {
                 // connection already disconnected. Do nothing
             }
+            Log.wtf(LOG_TAG, "sendIncomingCallIntent: failed to add new call because no phone"
+                    + " account could be found for the call");
         } else {
             TelecomManager tm = mPhone.getContext().getSystemService(TelecomManager.class);
-            if (connection.isMultiparty()) {
-                tm.addNewIncomingConference(handle, extras);
-            } else {
-                tm.addNewIncomingCall(handle, extras);
+            try {
+                if (connection.isMultiparty()) {
+                    tm.addNewIncomingConference(handle, extras);
+                } else {
+                    tm.addNewIncomingCall(handle, extras);
+                }
+            } catch (SecurityException se) {
+                // If we get a security exception, the most likely cause is:
+                // "This PhoneAccountHandle is not registered for this user"
+                // If this happens, then it means that for whatever reason the phone account which
+                // we are trying to use to add the new incoming call no longer exists in Telecom.
+                // This can happen if the handle of the phone account changes.  The likely root
+                // cause of this would be a change in active SIM profile for an MVNO style carrier
+                // which aggregates multiple carriers together.
+
+                // We will log a list of the available handles ourselves here; PhoneAccountHandle
+                // oscures the ID in the toString.  Rlog.pii will do a secure hash on userdebug
+                // builds so at least we could tell if the handle we tried is different from the one
+                // which we attempted to use.
+                List<PhoneAccountHandle> handles = tm.getCallCapablePhoneAccounts();
+                String availableHandles = handles.stream()
+                        .map(h -> "[" + h.getComponentName() + " "
+                                + Rlog.pii(LOG_TAG, h.getId()) + "]")
+                        .collect(Collectors.joining(","));
+                String attemptedHandle = "[" + handle.getComponentName() + " "
+                        + Rlog.pii(LOG_TAG, handle.getId()) + "]";
+                Log.wtf(LOG_TAG, "sendIncomingCallIntent: failed to add new call " + connection
+                        + " because the handle " + attemptedHandle
+                        + " is not in the list of registered handles " + availableHandles
+                        + " - call was rejected.");
+
+                // Since the phone account handle we're trying to use is not valid, we have no other
+                // recourse but to reject the incoming call.
+                try {
+                    connection.hangup();
+                } catch (CallStateException e) {
+                    // connection already disconnected. Do nothing
+                }
             }
         }
     }