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

Commit 73983ae3 authored by Tyler Gunn's avatar Tyler Gunn
Browse files

Fix issue where call timeout is triggered for canceled calls.

If you disconnect a call quickly before it's created, the timeout never
gets cleaned up.

Flag: com.android.server.telecom.flags.dont_timeout_destroyed_calls
Fixes: 381684580
Test: Manually reproduced and verified this prevents the anomaly.
Change-Id: I658d66436e8290db06e18fe27ea46ec3035d56a2
parent 6b2d00fc
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -16,3 +16,14 @@ flag {
  description: "If a self-managed call is stuck in certain states, disconnect it"
  bug: "360298368"
}

# OWNER=tgunn TARGET=25Q2
flag {
  name: "dont_timeout_destroyed_calls"
  namespace: "telecom"
  description: "When create connection timeout is hit, if call is already destroyed, skip anomaly"
  bug: "381684580"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}
+36 −10
Original line number Diff line number Diff line
@@ -130,11 +130,7 @@ public class ConnectionServiceWrapper extends ServiceBinder implements
                synchronized (mLock) {
                    logIncoming("handleCreateConnectionComplete %s", callId);
                    Call call = mCallIdMapper.getCall(callId);
                    if (call != null && mScheduledFutureMap.containsKey(call)) {
                        ScheduledFuture<?> existingTimeout = mScheduledFutureMap.get(call);
                        existingTimeout.cancel(false /* cancelIfRunning */);
                        mScheduledFutureMap.remove(call);
                    }
                    maybeRemoveCleanupFuture(call);
                    // Check status hints image for cross user access
                    if (connection.getStatusHints() != null) {
                        Icon icon = connection.getStatusHints().getIcon();
@@ -174,11 +170,7 @@ public class ConnectionServiceWrapper extends ServiceBinder implements
                synchronized (mLock) {
                    logIncoming("handleCreateConferenceComplete %s", callId);
                    Call call = mCallIdMapper.getCall(callId);
                    if (call != null && mScheduledFutureMap.containsKey(call)) {
                        ScheduledFuture<?> existingTimeout = mScheduledFutureMap.get(call);
                        existingTimeout.cancel(false /* cancelIfRunning */);
                        mScheduledFutureMap.remove(call);
                    }
                    maybeRemoveCleanupFuture(call);
                    // Check status hints image for cross user access
                    if (conference.getStatusHints() != null) {
                        Icon icon = conference.getStatusHints().getIcon();
@@ -1678,6 +1670,9 @@ public class ConnectionServiceWrapper extends ServiceBinder implements
                            Log.getExternalSession(TELECOM_ABBREVIATION));
                } catch (RemoteException e) {
                    Log.e(this, e, "Failure to createConference -- %s", getComponentName());
                    if (mFlags.dontTimeoutDestroyedCalls()) {
                        maybeRemoveCleanupFuture(call);
                    }
                    mPendingResponses.remove(callId).handleCreateConferenceFailure(
                            new DisconnectCause(DisconnectCause.ERROR, e.toString()));
                }
@@ -1708,6 +1703,9 @@ public class ConnectionServiceWrapper extends ServiceBinder implements
                    Log.i(ConnectionServiceWrapper.this, "Call not present"
                            + " in call id mapper, maybe it was aborted before the bind"
                            + " completed successfully?");
                    if (mFlags.dontTimeoutDestroyedCalls()) {
                        maybeRemoveCleanupFuture(call);
                    }
                    response.handleCreateConnectionFailure(
                            new DisconnectCause(DisconnectCause.CANCELED));
                    return;
@@ -1793,6 +1791,9 @@ public class ConnectionServiceWrapper extends ServiceBinder implements
                mScheduledFutureMap.put(call, future);
                try {
                    if (mFlags.cswServiceInterfaceIsNull() && mServiceInterface == null) {
                        if (mFlags.dontTimeoutDestroyedCalls()) {
                            maybeRemoveCleanupFuture(call);
                        }
                        mPendingResponses.remove(callId).handleCreateConnectionFailure(
                                new DisconnectCause(DisconnectCause.ERROR,
                                        "CSW#oCC ServiceInterface is null"));
@@ -1807,6 +1808,9 @@ public class ConnectionServiceWrapper extends ServiceBinder implements
                    }
                } catch (RemoteException e) {
                    Log.e(this, e, "Failure to createConnection -- %s", getComponentName());
                    if (mFlags.dontTimeoutDestroyedCalls()) {
                        maybeRemoveCleanupFuture(call);
                    }
                    mPendingResponses.remove(callId).handleCreateConnectionFailure(
                            new DisconnectCause(DisconnectCause.ERROR, e.toString()));
                }
@@ -2286,6 +2290,9 @@ public class ConnectionServiceWrapper extends ServiceBinder implements
        if (response != null) {
            response.handleCreateConnectionFailure(disconnectCause);
        }
        if (mFlags.dontTimeoutDestroyedCalls()) {
            maybeRemoveCleanupFuture(mCallIdMapper.getCall(callId));
        }

        mCallIdMapper.removeCall(callId);
    }
@@ -2295,6 +2302,9 @@ public class ConnectionServiceWrapper extends ServiceBinder implements
        if (response != null) {
            response.handleCreateConnectionFailure(disconnectCause);
        }
        if (mFlags.dontTimeoutDestroyedCalls()) {
            maybeRemoveCleanupFuture(call);
        }

        mCallIdMapper.removeCall(call);
    }
@@ -2754,4 +2764,20 @@ public class ConnectionServiceWrapper extends ServiceBinder implements
    public void setAnomalyReporterAdapter(AnomalyReporterAdapter mAnomalyReporterAdapter){
        mAnomalyReporter = mAnomalyReporterAdapter;
    }

    /**
     * Given a call, unschedule and cancel the cleanup future.
     * @param call the call.
     */
    private void maybeRemoveCleanupFuture(Call call) {
        if (call == null) {
            return;
        }
        ScheduledFuture<?> future = mScheduledFutureMap.remove(call);
        if (future == null) {
            return;
        }
        future.cancel(false /* interrupt */);

    }
}