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

Commit d1986aba authored by Grant Menke's avatar Grant Menke
Browse files

Add support for AnomalyReporter in Telecom.

Initialized AnomalyReporter class for use in Telecom. Reported anomalies at 4 points inside of CallsManager for now. Made an AnomalyReporterAdapter class to abstract out the static dependency introduced by AnomalyReporter#reportAnomaly.

Bug: 222560141
Test: CallsManagerTest#testAnomalyReportedWhenMakeRoomForOutgoingCallConnecting
Change-Id: Iae1323a1d900db23a3b9c0e6b2becda365cde9f7
parent 0066fcda
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.telecom;

import java.util.UUID;

/**
 * Interface to avoid static calls to AnomalyReporter. Add methods to this interface as needed for
 * refactoring.
 */
public interface AnomalyReporterAdapter {
    void reportAnomaly(UUID eventId, String description);
}
+27 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.telecom;

import android.telephony.AnomalyReporter;
import java.util.UUID;

public class AnomalyReporterAdapterImpl implements AnomalyReporterAdapter {
    @Override
    public void reportAnomaly(UUID eventId, String description) {
        AnomalyReporter.reportAnomaly(eventId, description);
    }
}
+45 −2
Original line number Diff line number Diff line
@@ -145,6 +145,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -237,6 +238,27 @@ public class CallsManager extends Call.ListenerBase
    private static final int MAXIMUM_TOP_LEVEL_CALLS = 2;
    private static final int MAXIMUM_SELF_MANAGED_CALLS = 10;

    /**
     * Anomaly Report UUIDs and corresponding error descriptions specific to CallsManager.
     */
    public static final UUID LIVE_CALL_STUCK_CONNECTING_ERROR_UUID =
            UUID.fromString("3f95808c-9134-11ed-a1eb-0242ac120002");
    public static final String LIVE_CALL_STUCK_CONNECTING_ERROR_MSG =
            "Force disconnected a live call that was stuck in CONNECTING state.";
    public static final UUID LIVE_CALL_STUCK_CONNECTING_EMERGENCY_ERROR_UUID =
            UUID.fromString("744fdf86-9137-11ed-a1eb-0242ac120002");
    public static final String LIVE_CALL_STUCK_CONNECTING_EMERGENCY_ERROR_MSG =
            "Found a live call that was stuck in CONNECTING state while attempting to place an "
                    + "emergency call.";
    public static final UUID CALL_REMOVAL_EXECUTION_ERROR_UUID =
            UUID.fromString("030b8b16-9139-11ed-a1eb-0242ac120002");
    public static final String CALL_REMOVAL_EXECUTION_ERROR_MSG =
            "Exception thrown while executing call removal";
    public static final UUID EXCEPTION_WHILE_ESTABLISHING_CONNECTION_ERROR_UUID =
            UUID.fromString("1c4eed7c-9132-11ed-a1eb-0242ac120002");
    public static final String EXCEPTION_WHILE_ESTABLISHING_CONNECTION_ERROR_MSG =
            "Exception thrown while establishing connection.";

    private static final int[] OUTGOING_CALL_STATES =
            {CallState.CONNECTING, CallState.SELECT_PHONE_ACCOUNT, CallState.DIALING,
                    CallState.PULLING};
@@ -414,6 +436,8 @@ public class CallsManager extends Call.ListenerBase

    private boolean mHasActiveRttCall = false;

    private AnomalyReporterAdapter mAnomalyReporter = new AnomalyReporterAdapterImpl();

    /**
     * Listener to PhoneAccountRegistrar events.
     */
@@ -1285,6 +1309,11 @@ public class CallsManager extends Call.ListenerBase
        mListeners.remove(listener);
    }

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

    void processIncomingConference(PhoneAccountHandle phoneAccountHandle, Bundle extras) {
        Log.d(this, "processIncomingCallConference");
        processIncomingCallIntent(phoneAccountHandle, extras, true);
@@ -2513,8 +2542,12 @@ public class CallsManager extends Call.ListenerBase
                try {
                    call.startCreateConnection(mPhoneAccountRegistrar);
                } catch (Exception exception) {
                    // If an exceptions is thrown while creating the connection, disconnect.
                    // If an exceptions is thrown while creating the connection, prompt the user to
                    // generate a bugreport and force disconnect.
                    Log.e(TAG, exception, "Exception thrown while establishing connection.");
                    mAnomalyReporter.reportAnomaly(
                            EXCEPTION_WHILE_ESTABLISHING_CONNECTION_ERROR_UUID,
                            EXCEPTION_WHILE_ESTABLISHING_CONNECTION_ERROR_MSG);
                    markCallAsDisconnected(call,
                            new DisconnectCause(DisconnectCause.ERROR,
                            "Failed to create the connection."));
@@ -3475,6 +3508,8 @@ public class CallsManager extends Call.ListenerBase
        }, new LoggedHandlerExecutor(mHandler, "CM.pR", mLock))
                .exceptionally((throwable) -> {
                    Log.e(TAG, throwable, "Error while executing call removal");
                    mAnomalyReporter.reportAnomaly(CALL_REMOVAL_EXECUTION_ERROR_UUID,
                            CALL_REMOVAL_EXECUTION_ERROR_MSG);
                    return null;
                });
    }
@@ -4492,6 +4527,12 @@ public class CallsManager extends Call.ListenerBase
            return true;
        }

        // If the live call is stuck in a connecting state, prompt the user to generate a bugreport.
        if (liveCall.getState() == CallState.CONNECTING) {
            mAnomalyReporter.reportAnomaly(LIVE_CALL_STUCK_CONNECTING_EMERGENCY_ERROR_UUID,
                    LIVE_CALL_STUCK_CONNECTING_EMERGENCY_ERROR_MSG);
        }

        // If we have the max number of held managed calls and we're placing an emergency call,
        // we'll disconnect the ongoing call if it cannot be held.
        if (hasMaximumManagedHoldingCalls(emergencyCall) && !canHold(liveCall)) {
@@ -4591,8 +4632,10 @@ public class CallsManager extends Call.ListenerBase
        }

        // If the live call is stuck in a connecting state, then we should disconnect it in favor
        // of the new outgoing call.
        // of the new outgoing call and prompt the user to generate a bugreport.
        if (liveCall.getState() == CallState.CONNECTING) {
            mAnomalyReporter.reportAnomaly(LIVE_CALL_STUCK_CONNECTING_ERROR_UUID,
                    LIVE_CALL_STUCK_CONNECTING_ERROR_MSG);
            liveCall.disconnect("Force disconnect CONNECTING call.");
            return true;
        }
+2 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import android.os.UserHandle;
import android.os.UserManager;
import android.telecom.Log;
import android.telecom.PhoneAccountHandle;
import android.telephony.AnomalyReporter;
import android.widget.Toast;

import androidx.annotation.NonNull;
@@ -211,6 +212,7 @@ public class TelecomSystem {
            DeviceIdleControllerAdapter deviceIdleControllerAdapter) {
        mContext = context.getApplicationContext();
        LogUtils.initLogging(mContext);
        AnomalyReporter.initialize(mContext);
        DefaultDialerManagerAdapter defaultDialerAdapter =
                new DefaultDialerCache.DefaultDialerManagerAdapterImpl();

+25 −0
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ import android.test.suitebuilder.annotation.SmallTest;
import android.util.Pair;
import android.widget.Toast;

import com.android.server.telecom.AnomalyReporterAdapter;
import com.android.server.telecom.AsyncRingtonePlayer;
import com.android.server.telecom.Call;
import com.android.server.telecom.CallAudioManager;
@@ -126,6 +127,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
@@ -216,6 +218,7 @@ public class CallsManagerTest extends TelecomTestCase {
    @Mock private RoleManagerAdapter mRoleManagerAdapter;
    @Mock private ToastFactory mToastFactory;
    @Mock private Toast mToast;
    @Mock private AnomalyReporterAdapter mAnomalyReporterAdapter;

    private CallsManager mCallsManager;

@@ -1315,6 +1318,28 @@ public class CallsManagerTest extends TelecomTestCase {
        verify(ongoingCall).disconnect(anyLong(), anyString());
    }

    /**
     * Verifies that an anomaly report is triggered when a stuck/zombie call is found and force
     * disconnected when making room for an outgoing call.
     */
    @SmallTest
    @Test
    public void testAnomalyReportedWhenMakeRoomForOutgoingCallConnecting() {
        mCallsManager.setAnomalyReporterAdapter(mAnomalyReporterAdapter);
        Call ongoingCall = addSpyCall(SIM_2_HANDLE, CallState.CONNECTING);

        Call newCall = createCall(SIM_1_HANDLE, CallState.NEW);
        when(mComponentContextFixture.getTelephonyManager().isEmergencyNumber(any()))
                .thenReturn(false);
        newCall.setHandle(TEST_ADDRESS, TelecomManager.PRESENTATION_ALLOWED);

        assertTrue(mCallsManager.makeRoomForOutgoingCall(newCall));
        verify(mAnomalyReporterAdapter).reportAnomaly(
                CallsManager.LIVE_CALL_STUCK_CONNECTING_ERROR_UUID,
                CallsManager.LIVE_CALL_STUCK_CONNECTING_ERROR_MSG);
        verify(ongoingCall).disconnect(anyLong(), anyString());
    }

    /**
     * Verifies that changes to a {@link PhoneAccount}'s
     * {@link PhoneAccount#CAPABILITY_VIDEO_CALLING} capability will be reflected on a call.