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

Commit adf34f8b authored by Grant Menke's avatar Grant Menke Committed by Android (Google) Code Review
Browse files

Merge "Integrate AnomalyReporter with CallAnomalyWatchdog."

parents e18bdaf4 941281b7
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import java.util.Collections;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
@@ -110,6 +111,7 @@ public class CallAnomalyWatchdog extends CallsManagerListenerBase implements Cal
    private final TelecomSystem.SyncRoot mLock;
    private final Timeouts.Adapter mTimeoutAdapter;
    private final ClockProxy mClockProxy;
    private AnomalyReporterAdapter mAnomalyReporter = new AnomalyReporterAdapterImpl();
    // Pre-allocate space for 2 calls; realistically thats all we should ever need (tm)
    private final Map<Call, ScheduledFuture<?>> mScheduledFutureMap = new ConcurrentHashMap<>(2);
    private final Map<Call, WatchdogCallState> mWatchdogCallStateMap = new ConcurrentHashMap<>(2);
@@ -125,6 +127,22 @@ public class CallAnomalyWatchdog extends CallsManagerListenerBase implements Cal
     */
    private static final String ENABLE_DISCONNECT_CALL_ON_STUCK_STATE =
            "enable_disconnect_call_on_stuck_state";
    /**
     * Anomaly Report UUIDs and corresponding event descriptions specific to CallAnomalyWatchdog.
     */
    public static final UUID WATCHDOG_DISCONNECTED_STUCK_CALL_UUID =
            UUID.fromString("4b093985-c78f-45e3-a9fe-5319f397b025");
    public static final String WATCHDOG_DISCONNECTED_STUCK_CALL_MSG =
            "Telecom CallAnomalyWatchdog caught and disconnected a stuck/zombie call.";
    public static final UUID WATCHDOG_DISCONNECTED_STUCK_EMERGENCY_CALL_UUID =
            UUID.fromString("d57d8aab-d723-485e-a0dd-d1abb0f346c8");
    public static final String WATCHDOG_DISCONNECTED_STUCK_EMERGENCY_CALL_MSG =
            "Telecom CallAnomalyWatchdog caught and disconnected a stuck/zombie emergency call.";

    @VisibleForTesting
    public void setAnomalyReporterAdapter(AnomalyReporterAdapter mAnomalyReporterAdapter){
        mAnomalyReporter = mAnomalyReporterAdapter;
    }

    public CallAnomalyWatchdog(ScheduledExecutorService executorService,
            TelecomSystem.SyncRoot lock,
@@ -306,6 +324,15 @@ public class CallAnomalyWatchdog extends CallsManagerListenerBase implements Cal
                    Log.addEvent(call, STATE_TIMEOUT, newState);
                    mLocalLog.log("STATE_TIMEOUT; callId=" + call.getId() + " in state "
                            + newState);
                    if (call.isEmergencyCall()){
                        mAnomalyReporter.reportAnomaly(
                                WATCHDOG_DISCONNECTED_STUCK_EMERGENCY_CALL_UUID,
                                WATCHDOG_DISCONNECTED_STUCK_EMERGENCY_CALL_MSG);
                    } else {
                        mAnomalyReporter.reportAnomaly(
                                WATCHDOG_DISCONNECTED_STUCK_CALL_UUID,
                                WATCHDOG_DISCONNECTED_STUCK_CALL_MSG);
                    }

                    if (isEnabledDisconnect) {
                        call.setOverrideDisconnectCauseCode(
+83 −100
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.ComponentName;
@@ -28,6 +29,7 @@ import android.net.Uri;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;

import com.android.server.telecom.AnomalyReporterAdapter;
import com.android.server.telecom.Call;
import com.android.server.telecom.CallAnomalyWatchdog;
import com.android.server.telecom.CallState;
@@ -81,6 +83,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
    @Mock private ToastFactory mMockToastProxy;
    @Mock private PhoneNumberUtilsAdapter mMockPhoneNumberUtilsAdapter;
    @Mock private ConnectionServiceWrapper mMockConnectionService;
    @Mock private AnomalyReporterAdapter mAnomalyReporterAdapter;

    @Override
    @Before
@@ -114,6 +117,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
                .when(mMockConnectionService).getComponentName();
        mCallAnomalyWatchdog = new CallAnomalyWatchdog(mTestScheduledExecutorService, mLock,
                mTimeouts, mMockClockProxy);
        mCallAnomalyWatchdog.setAnomalyReporterAdapter(mAnomalyReporterAdapter);
    }

    @Override
@@ -122,6 +126,21 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
        super.tearDown();
    }

    /**
     * Helper function that setups the call being tested.
     */
    private Call setupCallHelper(int callState, boolean isCreateConnectionComplete,
            ConnectionServiceWrapper service, boolean isVoipAudioMode, boolean isEmergencyCall) {
        Call call = getCall();
        call.setState(callState, "foo");
        call.setIsCreateConnectionComplete(isCreateConnectionComplete);
        if (service != null) call.setConnectionService(service);
        call.setIsVoipAudioMode(isVoipAudioMode);
        call.setIsEmergencyCall(isEmergencyCall);
        mCallAnomalyWatchdog.onCallAdded(call);
        return call;
    }

    /**
     * Test that the anomaly call state class correctly reports whether the state is transitory or
     * not for the purposes of the call anomaly watchdog.
@@ -269,12 +288,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
     */
     @Test
    public void testAddVoipRingingCall() {
        Call call = getCall();
        call.setState(CallState.RINGING, "foo");
        call.setIsCreateConnectionComplete(false);
        call.setIsVoipAudioMode(true);
        call.setIsEmergencyCall(false);
        mCallAnomalyWatchdog.onCallCreated(call);
        Call call = setupCallHelper(CallState.RINGING, false, null, true, false);

        // Newly created call which hasn't been added; should schedule timeout.
        assertEquals(1, mTestScheduledExecutorService.getNumberOfScheduledRunnables());
@@ -308,12 +322,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
     */
    @Test
    public void testAddVoipEmergencyRingingCall() {
        Call call = getCall();
        call.setState(CallState.RINGING, "foo");
        call.setIsCreateConnectionComplete(false);
        call.setIsVoipAudioMode(true);
        call.setIsEmergencyCall(true);
        mCallAnomalyWatchdog.onCallCreated(call);
        Call call = setupCallHelper(CallState.RINGING, false, null, true, true);

        // Newly created call which hasn't been added; should schedule timeout.
        assertEquals(1, mTestScheduledExecutorService.getNumberOfScheduledRunnables());
@@ -348,12 +357,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
     */
    @Test
    public void testAddNonVoipRingingCall() {
        Call call = getCall();
        call.setState(CallState.RINGING, "foo");
        call.setIsCreateConnectionComplete(false);
        call.setIsVoipAudioMode(false);
        call.setIsEmergencyCall(false);
        mCallAnomalyWatchdog.onCallCreated(call);
        Call call = setupCallHelper(CallState.RINGING, false, null, false, false);

        // Newly created call which hasn't been added; should schedule timeout.
        assertEquals(1, mTestScheduledExecutorService.getNumberOfScheduledRunnables());
@@ -388,12 +392,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
     */
    @Test
    public void testAddNonVoipEmergencyRingingCall() {
        Call call = getCall();
        call.setState(CallState.RINGING, "foo");
        call.setIsCreateConnectionComplete(false);
        call.setIsVoipAudioMode(false);
        call.setIsEmergencyCall(true);
        mCallAnomalyWatchdog.onCallCreated(call);
        Call call = setupCallHelper(CallState.RINGING, false, null, false, true);

        // Newly created call which hasn't been added; should schedule timeout.
        assertEquals(1, mTestScheduledExecutorService.getNumberOfScheduledRunnables());
@@ -426,12 +425,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
     */
    @Test
    public void testAddVoipRingingCallTimeoutWithoutConnection() {
        Call call = getCall();
        call.setState(CallState.RINGING, "foo");
        call.setIsCreateConnectionComplete(false);
        call.setIsVoipAudioMode(true);
        call.setIsEmergencyCall(false);
        mCallAnomalyWatchdog.onCallCreated(call);
        setupCallHelper(CallState.RINGING, false, null, true, false);

        // Newly created call which hasn't been added; should schedule timeout.
        assertEquals(1, mTestScheduledExecutorService.getNumberOfScheduledRunnables());
@@ -454,12 +448,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
     */
    @Test
    public void testAddVoipEmergencyRingingCallTimeoutWithoutConnection() {
        Call call = getCall();
        call.setState(CallState.RINGING, "foo");
        call.setIsCreateConnectionComplete(false);
        call.setIsVoipAudioMode(true);
        call.setIsEmergencyCall(true);
        mCallAnomalyWatchdog.onCallCreated(call);
        setupCallHelper(CallState.RINGING, false, null, true, true);

        // Newly created call which hasn't been added; should schedule timeout.
        assertEquals(1, mTestScheduledExecutorService.getNumberOfScheduledRunnables());
@@ -483,12 +472,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
     */
    @Test
    public void testAddNonVoipRingingCallTimeoutWithoutConnection() {
        Call call = getCall();
        call.setState(CallState.RINGING, "foo");
        call.setIsCreateConnectionComplete(false);
        call.setIsVoipAudioMode(false);
        call.setIsEmergencyCall(false);
        mCallAnomalyWatchdog.onCallCreated(call);
        setupCallHelper(CallState.RINGING, false, null, false, false);;

        // Newly created call which hasn't been added; should schedule timeout.
        assertEquals(1, mTestScheduledExecutorService.getNumberOfScheduledRunnables());
@@ -511,12 +495,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
     */
    @Test
    public void testAddNonVoipEmergencyRingingCallTimeoutWithoutConnection() {
        Call call = getCall();
        call.setState(CallState.RINGING, "foo");
        call.setIsCreateConnectionComplete(false);
        call.setIsVoipAudioMode(false);
        call.setIsEmergencyCall(true);
        mCallAnomalyWatchdog.onCallCreated(call);
        setupCallHelper(CallState.RINGING, false, null, false, true);

        // Newly created call which hasn't been added; should schedule timeout.
        assertEquals(1, mTestScheduledExecutorService.getNumberOfScheduledRunnables());
@@ -540,13 +519,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
     */
    @Test
    public void testAddVoipRingingCallTimeoutWithConnection() {
        Call call = getCall();
        call.setState(CallState.RINGING, "foo");
        call.setIsCreateConnectionComplete(true);
        call.setConnectionService(mMockConnectionService);
        call.setIsVoipAudioMode(true);
        call.setIsEmergencyCall(false);
        mCallAnomalyWatchdog.onCallAdded(call);
        setupCallHelper(CallState.RINGING, true, mMockConnectionService, true, false);

        // Newly created call which hasn't been added; should schedule timeout.
        assertEquals(1, mTestScheduledExecutorService.getNumberOfScheduledRunnables());
@@ -569,13 +542,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
     */
    @Test
    public void testAddVoipEmergencyRingingCallTimeoutWithConnection() {
        Call call = getCall();
        call.setState(CallState.RINGING, "foo");
        call.setIsCreateConnectionComplete(true);
        call.setConnectionService(mMockConnectionService);
        call.setIsVoipAudioMode(true);
        call.setIsEmergencyCall(true);
        mCallAnomalyWatchdog.onCallAdded(call);
        setupCallHelper(CallState.RINGING, true, mMockConnectionService, true, true);

        // Newly created call which hasn't been added; should schedule timeout.
        assertEquals(1, mTestScheduledExecutorService.getNumberOfScheduledRunnables());
@@ -599,13 +566,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
     */
    @Test
    public void testAddNonVoipRingingCallTimeoutWithConnection() {
        Call call = getCall();
        call.setState(CallState.RINGING, "foo");
        call.setIsCreateConnectionComplete(true);
        call.setConnectionService(mMockConnectionService);
        call.setIsVoipAudioMode(false);
        call.setIsEmergencyCall(false);
        mCallAnomalyWatchdog.onCallAdded(call);
        setupCallHelper(CallState.RINGING, true, mMockConnectionService, false, false);

        // Newly created call which hasn't been added; should schedule timeout.
        assertEquals(1, mTestScheduledExecutorService.getNumberOfScheduledRunnables());
@@ -628,13 +589,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
     */
    @Test
    public void testAddNonVoipEmergencyRingingCallTimeoutWithConnection() {
        Call call = getCall();
        call.setState(CallState.RINGING, "foo");
        call.setIsCreateConnectionComplete(true);
        call.setConnectionService(mMockConnectionService);
        call.setIsVoipAudioMode(false);
        call.setIsEmergencyCall(true);
        mCallAnomalyWatchdog.onCallAdded(call);
        setupCallHelper(CallState.RINGING, true, mMockConnectionService, false, true);

        // Newly created call which hasn't been added; should schedule timeout.
        assertEquals(1, mTestScheduledExecutorService.getNumberOfScheduledRunnables());
@@ -659,12 +614,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
    @Test
    public void testVoipPlaceCallTimeout() {
        // Call will start in connecting state
        Call call = getCall();
        call.setState(CallState.CONNECTING, "foo");
        call.setIsCreateConnectionComplete(false);
        call.setIsVoipAudioMode(true);
        call.setIsEmergencyCall(false);
        mCallAnomalyWatchdog.onCallCreated(call);
        Call call = setupCallHelper(CallState.CONNECTING, false, null, true, false);

        // Assume it is created but the app never sets it to a proper state
        call.setIsCreateConnectionComplete(false);
@@ -681,6 +631,54 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
        mTestScheduledExecutorService.advanceTime(TEST_VOIP_TRANSITORY_MILLIS + 1);
    }

    /**
     * Emulate the case where a new outgoing VoIP call is added to the watchdog.
     * In this case, the timeout will fire in transitory state and should report an anomaly.
     */
    @Test
    public void testVoipPlaceCallTimeoutReportAnomaly() {
        // Call will start in connecting state
        Call call = setupCallHelper(CallState.CONNECTING, false, null, true, false);

        // Assume it is created but the app never sets it to a proper state
        call.setIsCreateConnectionComplete(false);
        mCallAnomalyWatchdog.onCallAdded(call);

        // Move the clock to fire the timeout.
        when(mMockClockProxy.elapsedRealtime()).thenReturn(TEST_VOIP_TRANSITORY_MILLIS + 1);
        mTestScheduledExecutorService.advanceTime(TEST_VOIP_TRANSITORY_MILLIS + 1);

        //Ensure an anomaly was reported
        verify(mAnomalyReporterAdapter).reportAnomaly(
                CallAnomalyWatchdog.WATCHDOG_DISCONNECTED_STUCK_CALL_UUID,
                CallAnomalyWatchdog.WATCHDOG_DISCONNECTED_STUCK_CALL_MSG);
    }

    /**
     * Emulate the case where a new outgoing VoIP emergency call is added to the watchdog.
     * In this case, the timeout will fire in transitory state and should report an emergency
     * anomaly.
     */
    @Test
    public void testVoipEmergencyPlaceCallTimeoutReportAnomaly() {
        // Call will start in connecting state
        Call call = setupCallHelper(CallState.CONNECTING, false, null, true, true);

        // Assume it is created but the app never sets it to a proper state
        call.setIsCreateConnectionComplete(false);
        mCallAnomalyWatchdog.onCallAdded(call);

        // Move the clock to fire the timeout.
        when(mMockClockProxy.elapsedRealtime()).
                thenReturn(TEST_VOIP_EMERGENCY_TRANSITORY_MILLIS + 1);
        mTestScheduledExecutorService.advanceTime(TEST_VOIP_EMERGENCY_TRANSITORY_MILLIS + 1);

        //Ensure an anomaly was reported
        verify(mAnomalyReporterAdapter).reportAnomaly(
                CallAnomalyWatchdog.WATCHDOG_DISCONNECTED_STUCK_EMERGENCY_CALL_UUID,
                CallAnomalyWatchdog.WATCHDOG_DISCONNECTED_STUCK_EMERGENCY_CALL_MSG);
    }

    /**
     * Emulate the case where a new outgoing VoIP emergency call is added to the watchdog.
     * In this case, the timeout will fire in transitory state.
@@ -688,12 +686,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
    @Test
    public void testVoipEmergencyPlaceCallTimeout() {
        // Call will start in connecting state
        Call call = getCall();
        call.setState(CallState.CONNECTING, "foo");
        call.setIsCreateConnectionComplete(false);
        call.setIsVoipAudioMode(true);
        call.setIsEmergencyCall(true);
        mCallAnomalyWatchdog.onCallCreated(call);
        Call call = setupCallHelper(CallState.CONNECTING, false, null, true, true);

        // Assume it is created but the app never sets it to a proper state
        call.setIsCreateConnectionComplete(false);
@@ -718,12 +711,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
    @Test
    public void testNonVoipPlaceCallTimeout() {
        // Call will start in connecting state
        Call call = getCall();
        call.setState(CallState.CONNECTING, "foo");
        call.setIsCreateConnectionComplete(false);
        call.setIsVoipAudioMode(false);
        call.setIsEmergencyCall(false);
        mCallAnomalyWatchdog.onCallCreated(call);
        Call call = setupCallHelper(CallState.CONNECTING, false, null, false, false);

        // Assume it is created but the app never sets it to a proper state
        call.setIsCreateConnectionComplete(false);
@@ -747,12 +735,7 @@ public class CallAnomalyWatchdogTest extends TelecomTestCase {
    @Test
    public void testNonVoipEmergencyPlaceCallTimeout() {
        // Call will start in connecting state
        Call call = getCall();
        call.setState(CallState.CONNECTING, "foo");
        call.setIsCreateConnectionComplete(false);
        call.setIsVoipAudioMode(false);
        call.setIsEmergencyCall(true);
        mCallAnomalyWatchdog.onCallCreated(call);
        Call call = setupCallHelper(CallState.CONNECTING, false, null, false, true);

        // Assume it is created but the app never sets it to a proper state
        call.setIsCreateConnectionComplete(false);