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

Commit cfaab432 authored by Tyler Gunn's avatar Tyler Gunn Committed by Android (Google) Code Review
Browse files

Merge "Fix issue where Telecom ANRs due to call into AudioManager." into udc-dev

parents 79dbb49e 4d9ddf06
Loading
Loading
Loading
Loading
+30 −12
Original line number Diff line number Diff line
@@ -154,6 +154,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@@ -455,6 +456,9 @@ public class CallsManager extends Call.ListenerBase

    private LinkedList<HandlerThread> mGraphHandlerThreads;

    // An executor that can be used to fire off async tasks that do not block Telecom in any manner.
    private final Executor mAsyncTaskExecutor;

    private boolean mHasActiveRttCall = false;

    private AnomalyReporterAdapter mAnomalyReporter = new AnomalyReporterAdapterImpl();
@@ -553,7 +557,8 @@ public class CallsManager extends Call.ListenerBase
            RoleManagerAdapter roleManagerAdapter,
            ToastFactory toastFactory,
            CallEndpointControllerFactory callEndpointControllerFactory,
            CallAnomalyWatchdog callAnomalyWatchdog) {
            CallAnomalyWatchdog callAnomalyWatchdog,
            Executor asyncTaskExecutor) {
        mContext = context;
        mLock = lock;
        mPhoneNumberUtilsAdapter = phoneNumberUtilsAdapter;
@@ -670,6 +675,7 @@ public class CallsManager extends Call.ListenerBase
        mGraphHandlerThreads = new LinkedList<>();

        mCallAnomalyWatchdog = callAnomalyWatchdog;
        mAsyncTaskExecutor = asyncTaskExecutor;
    }

    public void setIncomingCallNotifier(IncomingCallNotifier incomingCallNotifier) {
@@ -3327,7 +3333,8 @@ public class CallsManager extends Call.ListenerBase
        setCallState(call, CallState.RINGING, "ringing set explicitly");
    }

    void markCallAsDialing(Call call) {
    @VisibleForTesting
    public void markCallAsDialing(Call call) {
        setCallState(call, CallState.DIALING, "dialing set explicitly");
        maybeMoveToSpeakerPhone(call);
        maybeTurnOffMute(call);
@@ -4893,17 +4900,28 @@ public class CallsManager extends Call.ListenerBase
        }
    }

    /**
     * Ensures that the call will be audible to the user by checking if the voice call stream is
     * audible, and if not increasing the volume to the default value.
     */
    private void ensureCallAudible() {
        // Audio manager APIs can be somewhat slow.  To prevent a potential ANR we will fire off
        // this opreation on the async task executor.  Note that this operation does not have any
        // dependency on any Telecom state, so we can safely launch this on a different thread
        // without worrying that it is in the Telecom sync lock.
        mAsyncTaskExecutor.execute(() -> {
            AudioManager am = mContext.getSystemService(AudioManager.class);
            if (am == null) {
                Log.w(this, "ensureCallAudible: audio manager is null");
                return;
            }
            if (am.getStreamVolume(AudioManager.STREAM_VOICE_CALL) == 0) {
            Log.i(this, "ensureCallAudible: voice call stream has volume 0. Adjusting to default.");
                Log.i(this,
                        "ensureCallAudible: voice call stream has volume 0. Adjusting to default.");
                am.setStreamVolume(AudioManager.STREAM_VOICE_CALL,
                        AudioSystem.getDefaultStreamVolume(AudioManager.STREAM_VOICE_CALL), 0);
            }
        });
    }

    /**
+2 −1
Original line number Diff line number Diff line
@@ -363,7 +363,8 @@ public class TelecomSystem {
                    roleManagerAdapter,
                    toastFactory,
                    callEndpointControllerFactory,
                    callAnomalyWatchdog);
                    callAnomalyWatchdog,
                    Executors.newSingleThreadExecutor());

            mIncomingCallNotifier = incomingCallNotifier;
            incomingCallNotifier.setCallsManagerProxy(new IncomingCallNotifier.CallsManagerProxy() {
+49 −1
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -136,6 +137,7 @@ import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

@@ -294,7 +296,9 @@ public class CallsManagerTest extends TelecomTestCase {
                mRoleManagerAdapter,
                mToastFactory,
                mCallEndpointControllerFactory,
                mCallAnomalyWatchdog);
                mCallAnomalyWatchdog,
                // Just do async tasks synchronously to support testing.
                command -> command.run());

        when(mPhoneAccountRegistrar.getPhoneAccount(
                eq(SELF_MANAGED_HANDLE), any())).thenReturn(SELF_MANAGED_ACCOUNT);
@@ -2413,6 +2417,50 @@ public class CallsManagerTest extends TelecomTestCase {
        verify(listener).onRingbackRequested(call, ringback);
    }

    @MediumTest
    @Test
    public void testSetCallDialingAndDontIncreaseVolume() {
        // Start with a non zero volume.
        mComponentContextFixture.getAudioManager().setStreamVolume(AudioManager.STREAM_VOICE_CALL,
                4, 0 /* flags */);

        Call call = mock(Call.class);
        mCallsManager.markCallAsDialing(call);

        // We set the volume to non-zero above, so expect 1
        verify(mComponentContextFixture.getAudioManager(), times(1)).setStreamVolume(
                eq(AudioManager.STREAM_VOICE_CALL), anyInt(), anyInt());
    }
    @MediumTest
    @Test
    public void testSetCallDialingAndIncreaseVolume() {
        // Start with a zero volume stream.
        mComponentContextFixture.getAudioManager().setStreamVolume(AudioManager.STREAM_VOICE_CALL,
                0, 0 /* flags */);

        Call call = mock(Call.class);
        mCallsManager.markCallAsDialing(call);

        // We set the volume to zero above, so expect 2
        verify(mComponentContextFixture.getAudioManager(), times(2)).setStreamVolume(
                eq(AudioManager.STREAM_VOICE_CALL), anyInt(), anyInt());
    }

    @MediumTest
    @Test
    public void testSetCallActiveAndDontIncreaseVolume() {
        // Start with a non-zero volume.
        mComponentContextFixture.getAudioManager().setStreamVolume(AudioManager.STREAM_VOICE_CALL,
                4, 0 /* flags */);

        Call call = mock(Call.class);
        mCallsManager.markCallAsActive(call);

        // We set the volume to non-zero above, so expect 1 only.
        verify(mComponentContextFixture.getAudioManager(), times(1)).setStreamVolume(
                eq(AudioManager.STREAM_VOICE_CALL), anyInt(), anyInt());
    }

    @MediumTest
    @Test
    public void testHandoverToIsAccepted() {
+4 −0
Original line number Diff line number Diff line
@@ -783,6 +783,10 @@ public class ComponentContextFixture implements TestFixture<Context> {
        return mTelephonyManager;
    }

    public AudioManager getAudioManager() {
        return mAudioManager;
    }

    public CarrierConfigManager getCarrierConfigManager() {
        return mCarrierConfigManager;
    }