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

Commit 020a7db8 authored by Tyler Gunn's avatar Tyler Gunn
Browse files

Call streaming implementation cleanups.

1. Pass call id to service.
2. Fix bug in CallAudioManager where we would not clear the mStreamingCall
if the call is removed.
3. Fix broken log tag.
4. Change CallStreamingController to use Telecom logs.
5. Add call event for START_STREAMING/STOP_STREAMING.
6. Remove sLock from TransactionManager - it was causing a 100% repro
deadlock.
7. Add missed null check in stopFGSDelegation which was causing a system
service crash.
8. Handle lack of ongoing calls in CallAudioModeStateMachine to try to
set them mode back to normal.
9. Fix CallAudioModeStateMachine to set the correct mode for streaming a
voip call.

Test: Added CTS test for this behavior.
Bug: 279650527
Fixes: 279937487
Change-Id: I58bb50e43cd694933cb3716eab6c6b251f5599f9
parent 2ab0678e
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -4575,7 +4575,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
            throw new UnsupportedOperationException(
            throw new UnsupportedOperationException(
                    "Can't streaming call created by non voip apps");
                    "Can't streaming call created by non voip apps");
        }
        }

        Log.addEvent(this, LogUtils.Events.START_STREAMING);
        synchronized (mLock) {
        synchronized (mLock) {
            if (mIsStreaming) {
            if (mIsStreaming) {
                // ignore
                // ignore
@@ -4595,7 +4595,7 @@ public class Call implements CreateConnectionResponse, EventManager.Loggable,
                // ignore
                // ignore
                return;
                return;
            }
            }

            Log.addEvent(this, LogUtils.Events.STOP_STREAMING);
            mIsStreaming = false;
            mIsStreaming = false;
            for (Listener listener : mListeners) {
            for (Listener listener : mListeners) {
                listener.onCallStreamingStateChanged(this, false /** isStreaming */);
                listener.onCallStreamingStateChanged(this, false /** isStreaming */);
+4 −1
Original line number Original line Diff line number Diff line
@@ -146,6 +146,9 @@ public class CallAudioManager extends CallsManagerListenerBase {


    @Override
    @Override
    public void onCallRemoved(Call call) {
    public void onCallRemoved(Call call) {
        if (mStreamingCall == call) {
            mStreamingCall = null;
        }
        if (shouldIgnoreCallForAudio(call)) {
        if (shouldIgnoreCallForAudio(call)) {
            return; // Don't do audio handling for calls in a conference, or external calls.
            return; // Don't do audio handling for calls in a conference, or external calls.
        }
        }
@@ -238,7 +241,7 @@ public class CallAudioManager extends CallsManagerListenerBase {
                        makeArgsForModeStateMachine());
                        makeArgsForModeStateMachine());
            } else {
            } else {
                Log.w(LOG_TAG, "Unexpected streaming call request for call %s while call "
                Log.w(LOG_TAG, "Unexpected streaming call request for call %s while call "
                        + "s is streaming.", call.getId(), mStreamingCall.getId());
                        + "%s is streaming.", call.getId(), mStreamingCall.getId());
            }
            }
        } else {
        } else {
            if (mStreamingCall == call) {
            if (mStreamingCall == call) {
+5 −2
Original line number Original line Diff line number Diff line
@@ -665,7 +665,9 @@ public class CallAudioModeStateMachine extends StateMachine {
        @Override
        @Override
        public void enter() {
        public void enter() {
            Log.i(LOG_TAG, "Audio focus entering streaming state");
            Log.i(LOG_TAG, "Audio focus entering streaming state");
            mAudioManager.setMode(AudioManager.MODE_CALL_REDIRECT);
            mLocalLog.log("Enter Streaming");
            mLocalLog.log("Mode MODE_COMMUNICATION_REDIRECT");
            mAudioManager.setMode(AudioManager.MODE_COMMUNICATION_REDIRECT);
            mMostRecentMode = AudioManager.MODE_NORMAL;
            mMostRecentMode = AudioManager.MODE_NORMAL;
            mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS);
            mCallAudioManager.setCallAudioRouteFocusState(CallAudioRouteStateMachine.ACTIVE_FOCUS);
            mCallAudioManager.getCallAudioRouteStateMachine().sendMessageWithSessionInfo(
            mCallAudioManager.getCallAudioRouteStateMachine().sendMessageWithSessionInfo(
@@ -685,7 +687,8 @@ public class CallAudioModeStateMachine extends StateMachine {
            MessageArgs args = (MessageArgs) msg.obj;
            MessageArgs args = (MessageArgs) msg.obj;
            switch (msg.what) {
            switch (msg.what) {
                case NO_MORE_ACTIVE_OR_DIALING_CALLS:
                case NO_MORE_ACTIVE_OR_DIALING_CALLS:
                    // Do nothing.
                    // Switch to either ringing, holding, or inactive
                    transitionTo(calculateProperStateFromArgs(args));
                    return HANDLED;
                    return HANDLED;
                case NO_MORE_RINGING_CALLS:
                case NO_MORE_RINGING_CALLS:
                    // Do nothing.
                    // Do nothing.
+19 −20
Original line number Original line Diff line number Diff line
@@ -36,7 +36,7 @@ import android.os.UserHandle;
import android.telecom.CallException;
import android.telecom.CallException;
import android.telecom.CallStreamingService;
import android.telecom.CallStreamingService;
import android.telecom.StreamingCall;
import android.telecom.StreamingCall;
import android.util.Log;
import android.telecom.Log;


import com.android.internal.telecom.ICallStreamingService;
import com.android.internal.telecom.ICallStreamingService;
import com.android.server.telecom.voip.VoipCallTransaction;
import com.android.server.telecom.voip.VoipCallTransaction;
@@ -65,6 +65,9 @@ public class CallStreamingController extends CallsManagerListenerBase {
    private void onConnectedInternal(Call call, TransactionalServiceWrapper wrapper,
    private void onConnectedInternal(Call call, TransactionalServiceWrapper wrapper,
            IBinder service) throws RemoteException {
            IBinder service) throws RemoteException {
        synchronized (mLock) {
        synchronized (mLock) {
            Log.i(this, "onConnectedInternal: callid=%s", call.getId());
            Bundle extras = new Bundle();
            extras.putString(StreamingCall.EXTRA_CALL_ID, call.getId());
            mStreamingCall = call;
            mStreamingCall = call;
            mTransactionalServiceWrapper = wrapper;
            mTransactionalServiceWrapper = wrapper;
            mService = ICallStreamingService.Stub.asInterface(service);
            mService = ICallStreamingService.Stub.asInterface(service);
@@ -74,7 +77,7 @@ public class CallStreamingController extends CallsManagerListenerBase {
            mService.onCallStreamingStarted(new StreamingCall(
            mService.onCallStreamingStarted(new StreamingCall(
                    mTransactionalServiceWrapper.getComponentName(),
                    mTransactionalServiceWrapper.getComponentName(),
                    mStreamingCall.getCallerDisplayName(),
                    mStreamingCall.getCallerDisplayName(),
                    mStreamingCall.getContactUri(), new Bundle()));
                    mStreamingCall.getHandle(), extras));
            mIsStreaming = true;
            mIsStreaming = true;
        }
        }
    }
    }
@@ -99,7 +102,6 @@ public class CallStreamingController extends CallsManagerListenerBase {
    }
    }


    public static class QueryCallStreamingTransaction extends VoipCallTransaction {
    public static class QueryCallStreamingTransaction extends VoipCallTransaction {
        private static final String TAG = QueryCallStreamingTransaction.class.getSimpleName();
        private final CallsManager mCallsManager;
        private final CallsManager mCallsManager;


        public QueryCallStreamingTransaction(CallsManager callsManager) {
        public QueryCallStreamingTransaction(CallsManager callsManager) {
@@ -109,7 +111,7 @@ public class CallStreamingController extends CallsManagerListenerBase {


        @Override
        @Override
        public CompletableFuture<VoipCallTransactionResult> processTransaction(Void v) {
        public CompletableFuture<VoipCallTransactionResult> processTransaction(Void v) {
            Log.d(TAG, "processTransaction");
            Log.i(this, "processTransaction");
            CompletableFuture<VoipCallTransactionResult> future = new CompletableFuture<>();
            CompletableFuture<VoipCallTransactionResult> future = new CompletableFuture<>();


            if (mCallsManager.getCallStreamingController().isStreaming()) {
            if (mCallsManager.getCallStreamingController().isStreaming()) {
@@ -126,8 +128,6 @@ public class CallStreamingController extends CallsManagerListenerBase {
    }
    }


    public static class AudioInterceptionTransaction extends VoipCallTransaction {
    public static class AudioInterceptionTransaction extends VoipCallTransaction {
        private static final String TAG = AudioInterceptionTransaction.class.getSimpleName();

        private Call mCall;
        private Call mCall;
        private boolean mEnterInterception;
        private boolean mEnterInterception;


@@ -140,7 +140,7 @@ public class CallStreamingController extends CallsManagerListenerBase {


        @Override
        @Override
        public CompletableFuture<VoipCallTransactionResult> processTransaction(Void v) {
        public CompletableFuture<VoipCallTransactionResult> processTransaction(Void v) {
            Log.d(TAG, "processTransaction");
            Log.d(this, "processTransaction");
            CompletableFuture<VoipCallTransactionResult> future = new CompletableFuture<>();
            CompletableFuture<VoipCallTransactionResult> future = new CompletableFuture<>();


            if (mEnterInterception) {
            if (mEnterInterception) {
@@ -160,7 +160,6 @@ public class CallStreamingController extends CallsManagerListenerBase {
    }
    }


    public class StreamingServiceTransaction extends VoipCallTransaction {
    public class StreamingServiceTransaction extends VoipCallTransaction {
        private static final String TAG = "StreamingServiceTransaction";
        public static final String MESSAGE = "STREAMING_FAILED_NO_SENDER";
        public static final String MESSAGE = "STREAMING_FAILED_NO_SENDER";
        private final TransactionalServiceWrapper mWrapper;
        private final TransactionalServiceWrapper mWrapper;
        private final Context mContext;
        private final Context mContext;
@@ -179,13 +178,13 @@ public class CallStreamingController extends CallsManagerListenerBase {
        @SuppressLint("LongLogTag")
        @SuppressLint("LongLogTag")
        @Override
        @Override
        public CompletionStage<VoipCallTransactionResult> processTransaction(Void v) {
        public CompletionStage<VoipCallTransactionResult> processTransaction(Void v) {
            Log.d(TAG, "processTransaction");
            Log.d(this, "processTransaction");
            CompletableFuture<VoipCallTransactionResult> future = new CompletableFuture<>();
            CompletableFuture<VoipCallTransactionResult> future = new CompletableFuture<>();


            RoleManager roleManager = mContext.getSystemService(RoleManager.class);
            RoleManager roleManager = mContext.getSystemService(RoleManager.class);
            PackageManager packageManager = mContext.getPackageManager();
            PackageManager packageManager = mContext.getPackageManager();
            if (roleManager == null || packageManager == null) {
            if (roleManager == null || packageManager == null) {
                Log.e(TAG, "Can't find system service");
                Log.w(this, "processTransaction: Can't find system service");
                future.complete(new VoipCallTransactionResult(
                future.complete(new VoipCallTransactionResult(
                        VoipCallTransactionResult.RESULT_FAILED, MESSAGE));
                        VoipCallTransactionResult.RESULT_FAILED, MESSAGE));
                return future;
                return future;
@@ -194,7 +193,7 @@ public class CallStreamingController extends CallsManagerListenerBase {
            List<String> holders = roleManager.getRoleHoldersAsUser(
            List<String> holders = roleManager.getRoleHoldersAsUser(
                    RoleManager.ROLE_SYSTEM_CALL_STREAMING, mUserHandle);
                    RoleManager.ROLE_SYSTEM_CALL_STREAMING, mUserHandle);
            if (holders.isEmpty()) {
            if (holders.isEmpty()) {
                Log.e(TAG, "Can't find streaming app");
                Log.w(this, "processTransaction: Can't find streaming app");
                future.complete(new VoipCallTransactionResult(
                future.complete(new VoipCallTransactionResult(
                        VoipCallTransactionResult.RESULT_FAILED, MESSAGE));
                        VoipCallTransactionResult.RESULT_FAILED, MESSAGE));
                return future;
                return future;
@@ -205,7 +204,7 @@ public class CallStreamingController extends CallsManagerListenerBase {
            List<ResolveInfo> infos = packageManager.queryIntentServicesAsUser(serviceIntent,
            List<ResolveInfo> infos = packageManager.queryIntentServicesAsUser(serviceIntent,
                    PackageManager.GET_META_DATA, mUserHandle);
                    PackageManager.GET_META_DATA, mUserHandle);
            if (infos.isEmpty()) {
            if (infos.isEmpty()) {
                Log.e(TAG, "Can't find streaming service");
                Log.w(this, "processTransaction: Can't find streaming service");
                future.complete(new VoipCallTransactionResult(
                future.complete(new VoipCallTransactionResult(
                        VoipCallTransactionResult.RESULT_FAILED, MESSAGE));
                        VoipCallTransactionResult.RESULT_FAILED, MESSAGE));
                return future;
                return future;
@@ -215,7 +214,7 @@ public class CallStreamingController extends CallsManagerListenerBase {


            if (serviceInfo.permission == null || !serviceInfo.permission.equals(
            if (serviceInfo.permission == null || !serviceInfo.permission.equals(
                    Manifest.permission.BIND_CALL_STREAMING_SERVICE)) {
                    Manifest.permission.BIND_CALL_STREAMING_SERVICE)) {
                android.telecom.Log.w(TAG, "Must require BIND_CALL_STREAMING_SERVICE: " +
                Log.w(this, "Must require BIND_CALL_STREAMING_SERVICE: " +
                        serviceInfo.packageName);
                        serviceInfo.packageName);
                future.complete(new VoipCallTransactionResult(
                future.complete(new VoipCallTransactionResult(
                        VoipCallTransactionResult.RESULT_FAILED, MESSAGE));
                        VoipCallTransactionResult.RESULT_FAILED, MESSAGE));
@@ -228,7 +227,7 @@ public class CallStreamingController extends CallsManagerListenerBase {
            if (!mContext.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE
            if (!mContext.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE
                    | Context.BIND_FOREGROUND_SERVICE
                    | Context.BIND_FOREGROUND_SERVICE
                    | Context.BIND_SCHEDULE_LIKE_TOP_APP, mUserHandle)) {
                    | Context.BIND_SCHEDULE_LIKE_TOP_APP, mUserHandle)) {
                Log.e(TAG, "Can't bind to streaming service");
                Log.w(this, "Can't bind to streaming service");
                future.complete(new VoipCallTransactionResult(
                future.complete(new VoipCallTransactionResult(
                        VoipCallTransactionResult.RESULT_FAILED,
                        VoipCallTransactionResult.RESULT_FAILED,
                        "STREAMING_FAILED_SENDER_BINDING_ERROR"));
                        "STREAMING_FAILED_SENDER_BINDING_ERROR"));
@@ -243,8 +242,6 @@ public class CallStreamingController extends CallsManagerListenerBase {
    }
    }


    public class UnbindStreamingServiceTransaction extends VoipCallTransaction {
    public class UnbindStreamingServiceTransaction extends VoipCallTransaction {
        private static final String TAG = "UnbindStreamingServiceTransaction";

        public UnbindStreamingServiceTransaction() {
        public UnbindStreamingServiceTransaction() {
            super(mTelecomLock);
            super(mTelecomLock);
        }
        }
@@ -252,7 +249,7 @@ public class CallStreamingController extends CallsManagerListenerBase {
        @SuppressLint("LongLogTag")
        @SuppressLint("LongLogTag")
        @Override
        @Override
        public CompletionStage<VoipCallTransactionResult> processTransaction(Void v) {
        public CompletionStage<VoipCallTransactionResult> processTransaction(Void v) {
            Log.d(TAG, "processTransaction");
            Log.d(this, "processTransaction");
            CompletableFuture<VoipCallTransactionResult> future = new CompletableFuture<>();
            CompletableFuture<VoipCallTransactionResult> future = new CompletableFuture<>();


            resetController();
            resetController();
@@ -285,6 +282,7 @@ public class CallStreamingController extends CallsManagerListenerBase {
                            StreamingCall.STATE_HOLDING);
                            StreamingCall.STATE_HOLDING);
                case CallState.DISCONNECTING:
                case CallState.DISCONNECTING:
                case CallState.DISCONNECTED:
                case CallState.DISCONNECTED:
                    Log.addEvent(call, LogUtils.Events.STOP_STREAMING);
                    transaction = new CallStreamingStateChangeTransaction(
                    transaction = new CallStreamingStateChangeTransaction(
                            StreamingCall.STATE_DISCONNECTED);
                            StreamingCall.STATE_DISCONNECTED);
                default:
                default:
@@ -300,8 +298,8 @@ public class CallStreamingController extends CallsManagerListenerBase {


                            @Override
                            @Override
                            public void onError(CallException exception) {
                            public void onError(CallException exception) {
                                Log.e(String.valueOf(this), "Exception when set call "
                                Log.e(this, exception, "Exception when set call "
                                        + "streaming state to streaming app: " + exception);
                                        + "streaming state to streaming app");
                            }
                            }
                        });
                        });
            }
            }
@@ -348,6 +346,7 @@ public class CallStreamingController extends CallsManagerListenerBase {
        @Override
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
        public void onServiceConnected(ComponentName name, IBinder service) {
            try {
            try {
                Log.i(this, "onServiceConnected: " + name);
                onConnectedInternal(mCall, mWrapper, service);
                onConnectedInternal(mCall, mWrapper, service);
                mFuture.complete(new VoipCallTransactionResult(
                mFuture.complete(new VoipCallTransactionResult(
                        VoipCallTransactionResult.RESULT_SUCCEED, null));
                        VoipCallTransactionResult.RESULT_SUCCEED, null));
@@ -380,7 +379,7 @@ public class CallStreamingController extends CallsManagerListenerBase {
                    mService.onCallStreamingStopped();
                    mService.onCallStreamingStopped();
                }
                }
            } catch (RemoteException e) {
            } catch (RemoteException e) {
                Log.w(String.valueOf(this), "Exception when stop call streaming:" + e);
                Log.e(this, e, "Exception when stop call streaming");
            }
            }
            resetController();
            resetController();
            if (!mFuture.isDone()) {
            if (!mFuture.isDone()) {
+2 −0
Original line number Original line Diff line number Diff line
@@ -225,6 +225,8 @@ public class LogUtils {
        public static final String FLASH_NOTIFICATION_STOP = "FLASH_NOTIFICATION_STOP";
        public static final String FLASH_NOTIFICATION_STOP = "FLASH_NOTIFICATION_STOP";
        public static final String GAINED_FGS_DELEGATION = "GAINED_FGS_DELEGATION";
        public static final String GAINED_FGS_DELEGATION = "GAINED_FGS_DELEGATION";
        public static final String LOST_FGS_DELEGATION = "LOST_FGS_DELEGATION";
        public static final String LOST_FGS_DELEGATION = "LOST_FGS_DELEGATION";
        public static final String START_STREAMING = "START_STREAMING";
        public static final String STOP_STREAMING = "STOP_STREAMING";


        public static class Timings {
        public static class Timings {
            public static final String ACCEPT_TIMING = "accept";
            public static final String ACCEPT_TIMING = "accept";
Loading