do not unbind if the connection has been cleared already

It's possible that during the wait of bind/fetch complete,
the connection to carrier service has been cleared due to clear event e.g,
sim card status change. Then we should not unbind again when handling
bind/fetch timeout event to avoid NPE.

Bug: 131637624
Test: manual
Change-Id: Ie87d7270e7f1094601c97c5e992006d8dcaecb99
diff --git a/src/com/android/phone/CarrierConfigLoader.java b/src/com/android/phone/CarrierConfigLoader.java
index cf7bafd..390ee7b 100644
--- a/src/com/android/phone/CarrierConfigLoader.java
+++ b/src/com/android/phone/CarrierConfigLoader.java
@@ -316,12 +316,17 @@
                 case EVENT_BIND_DEFAULT_TIMEOUT:
                 case EVENT_FETCH_DEFAULT_TIMEOUT:
                 {
-                    // If a ResponseReceiver callback is in the queue when this happens, we will
-                    // unbind twice and throw an exception.
-                    mContext.unbindService(mServiceConnection[phoneId]);
-                    removeMessages(EVENT_FETCH_DEFAULT_TIMEOUT);
-                    broadcastConfigChangedIntent(phoneId);
                     loge("bind/fetch time out from " + mPlatformCarrierConfigPackage);
+                    removeMessages(EVENT_FETCH_DEFAULT_TIMEOUT);
+                    // If we attempted to bind to the app, but the service connection is null due to
+                    // the race condition that clear config event happens before bind/fetch complete
+                    // then config was cleared while we were waiting and we should not continue.
+                    if (mServiceConnection[phoneId] != null) {
+                        // If a ResponseReceiver callback is in the queue when this happens, we will
+                        // unbind twice and throw an exception.
+                        mContext.unbindService(mServiceConnection[phoneId]);
+                        broadcastConfigChangedIntent(phoneId);
+                    }
                     notifySubscriptionInfoUpdater(phoneId);
                     break;
                 }
@@ -441,16 +446,20 @@
                 case EVENT_BIND_CARRIER_TIMEOUT:
                 case EVENT_FETCH_CARRIER_TIMEOUT:
                 {
-                    // If a ResponseReceiver callback is in the queue when this happens, we will
-                    // unbind twice and throw an exception.
-                    mContext.unbindService(mServiceConnection[phoneId]);
-                    removeMessages(EVENT_FETCH_CARRIER_TIMEOUT);
-                    broadcastConfigChangedIntent(phoneId);
                     loge("bind/fetch from carrier app timeout");
+                    removeMessages(EVENT_FETCH_CARRIER_TIMEOUT);
+                    // If we attempted to bind to the app, but the service connection is null due to
+                    // the race condition that clear config event happens before bind/fetch complete
+                    // then config was cleared while we were waiting and we should not continue.
+                    if (mServiceConnection[phoneId] != null) {
+                        // If a ResponseReceiver callback is in the queue when this happens, we will
+                        // unbind twice and throw an exception.
+                        mContext.unbindService(mServiceConnection[phoneId]);
+                        broadcastConfigChangedIntent(phoneId);
+                    }
                     notifySubscriptionInfoUpdater(phoneId);
                     break;
                 }
-
                 case EVENT_FETCH_CARRIER_DONE:
                 {
                     // If we attempted to bind to the app, but the service connection is null, then