Call Redirection: unbind service when onBind returns null

The call redirection service does not handle the corner case of
onNullBinding (occurs when onBind returns null). This vulnerability
would give the app that has the call redirection role unintentional
access to launch background activities outside the scope of a call
lifecycle.

Fixes: 273260090
Test: Unit test to ensure we unbind the service on null onBind
Test: CTS for similar assertion
Change-Id: Ib9d44d239833131eb055e83801cb635e8efe0b81
diff --git a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java
index 039526b..963e923 100644
--- a/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java
+++ b/src/com/android/server/telecom/callredirection/CallRedirectionProcessor.java
@@ -162,6 +162,19 @@
                     Log.endSession();
                 }
             }
+
+            @Override
+            public void onNullBinding(ComponentName componentName) {
+                // Make sure we unbind the service if onBind returns null
+                Log.startSession("CRSC.oNB");
+                try {
+                    synchronized (mTelecomLock) {
+                        finishCallRedirection();
+                    }
+                } finally {
+                    Log.endSession();
+                }
+            }
         }
 
         private class CallRedirectionAdapter extends ICallRedirectionAdapter.Stub {
diff --git a/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java b/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java
index 51d5960..01446d1 100644
--- a/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java
+++ b/tests/src/com/android/server/telecom/tests/CallRedirectionProcessorTest.java
@@ -354,4 +354,28 @@
         assertEquals(REDIRECTED_GATEWAY_NUMBER_WITH_POST_DIAL,
                 gatewayInfoArgumentCaptor.getValue().getGatewayAddress());
     }
+
+    @Test
+    public void testUnbindOnNullBind() throws Exception {
+        startProcessWithNoGateWayInfo();
+        // To make sure tests are not flaky, clean all the previous handler messages
+        waitForHandlerAction(mProcessor.getHandler(), HANDLER_TIMEOUT_DELAY);
+        enableUserDefinedCallRedirectionService();
+        disableCarrierCallRedirectionService();
+
+        mProcessor.performCallRedirection(UserHandle.CURRENT);
+
+        // Capture the binder
+        ArgumentCaptor<ServiceConnection> serviceConnectionCaptor = ArgumentCaptor.forClass(
+                ServiceConnection.class);
+        // Verify binding occurred
+        verify(mContext, times(1)).bindServiceAsUser(any(Intent.class),
+                serviceConnectionCaptor.capture(), anyInt(), eq(UserHandle.CURRENT));
+        // Simulate null return from onBind
+        serviceConnectionCaptor.getValue().onNullBinding(USER_DEFINED_SERVICE_TEST_COMPONENT_NAME);
+
+        // Verify service was unbound
+        verify(mContext, times(1)).
+                unbindService(any(ServiceConnection.class));
+    }
 }