Fix crash when handling call messaging failures.

This commit is contained in:
Cody Henthorne 2020-11-05 15:56:56 -05:00 committed by GitHub
parent 2b4a4d6109
commit 349a2f72cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 61 additions and 22 deletions

View file

@ -451,7 +451,8 @@ public class WebRtcCallActivity extends AppCompatActivity implements SafetyNumbe
public void onSendAnywayAfterSafetyNumberChange() {
Intent intent = new Intent(WebRtcCallActivity.this, WebRtcCallService.class);
intent.setAction(WebRtcCallService.ACTION_OUTGOING_CALL)
.putExtra(WebRtcCallService.EXTRA_REMOTE_PEER, new RemotePeer(viewModel.getRecipient().getId()));
.putExtra(WebRtcCallService.EXTRA_REMOTE_PEER, new RemotePeer(viewModel.getRecipient().getId()))
.putExtra(WebRtcCallService.EXTRA_OFFER_TYPE, OfferMessage.Type.AUDIO_CALL.getCode());
startService(intent);
}

View file

@ -35,7 +35,14 @@ public class WebRtcViewModel {
// Multiring Hangup States
CALL_ACCEPTED_ELSEWHERE,
CALL_DECLINED_ELSEWHERE,
CALL_ONGOING_ELSEWHERE
CALL_ONGOING_ELSEWHERE;
public boolean isErrorState() {
return this == NETWORK_FAILURE ||
this == RECIPIENT_UNAVAILABLE ||
this == NO_SUCH_USER ||
this == UNTRUSTED_IDENTITY;
}
}
private final @NonNull State state;

View file

@ -24,6 +24,7 @@ import org.signal.ringrtc.IceCandidate;
import org.signal.ringrtc.Remote;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.WebRtcCallActivity;
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
@ -52,9 +53,11 @@ import org.thoughtcrime.securesms.webrtc.locks.LockManager;
import org.whispersystems.libsignal.util.Pair;
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage;
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
import java.util.ArrayList;
import java.util.List;
@ -97,7 +100,8 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
public static final String EXTRA_ENABLE = "enable_value";
public static final String EXTRA_BROADCAST = "broadcast";
public static final String EXTRA_ANSWER_WITH_VIDEO = "enable_video";
public static final String EXTRA_ERROR = "error";
public static final String EXTRA_ERROR_CALL_STATE = "error_call_state";
public static final String EXTRA_ERROR_IDENTITY_KEY = "remote_identity_key";
public static final String EXTRA_CAMERA_STATE = "camera_state";
public static final String EXTRA_IS_ALWAYS_TURN = "is_always_turn";
public static final String EXTRA_TURN_SERVER_INFO = "turn_server_info";
@ -580,10 +584,22 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
@Override
public void onFailureContinue(@Nullable Throwable error) {
Log.i(TAG, "onFailureContinue: ", error);
Intent intent = new Intent(WebRtcCallService.this, WebRtcCallService.class);
intent.setAction(ACTION_MESSAGE_SENT_ERROR)
.putExtra(EXTRA_CALL_ID, getCallId().longValue())
.putExtra(EXTRA_ERROR, error);
.putExtra(EXTRA_CALL_ID, getCallId().longValue());
WebRtcViewModel.State state = WebRtcViewModel.State.NETWORK_FAILURE;
if (error instanceof UntrustedIdentityException) {
intent.putExtra(EXTRA_ERROR_IDENTITY_KEY, new IdentityKeyParcelable(((UntrustedIdentityException) error).getIdentityKey()));
state = WebRtcViewModel.State.UNTRUSTED_IDENTITY;
} else if (error instanceof UnregisteredUserException) {
state = WebRtcViewModel.State.NO_SUCH_USER;
}
intent.putExtra(EXTRA_ERROR_CALL_STATE, state);
startService(intent);
}
@ -603,7 +619,6 @@ public class WebRtcCallService extends Service implements CallManager.Observer,
if (serviceState.getCallInfoState().getPeer(remotePeer.hashCode()) == null) {
Log.w(TAG, "remotePeer not found in map with key: " + remotePeer.hashCode() + "! Dropping.");
try {
//noinspection ConstantConditions
callManager.drop(callId);
} catch (CallException e) {
serviceState = serviceState.getActionProcessor().callFailure(serviceState, "callManager.drop() failed: ", e);

View file

@ -232,7 +232,7 @@ public class ActiveCallActionProcessorDelegate extends WebRtcActionProcessor {
protected @NonNull WebRtcServiceState handleEnded(@NonNull WebRtcServiceState currentState, @NonNull String action, @NonNull RemotePeer remotePeer) {
Log.i(tag, "handleEnded(): call_id: " + remotePeer.getCallId() + " action: " + action);
if (remotePeer.callIdEquals(currentState.getCallInfoState().getActivePeer())) {
if (remotePeer.callIdEquals(currentState.getCallInfoState().getActivePeer()) && !currentState.getCallInfoState().getCallState().isErrorState()) {
currentState = currentState.builder()
.changeCallInfoState()
.callState(WebRtcViewModel.State.NETWORK_FAILURE)

View file

@ -26,15 +26,14 @@ import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceStateBuilder
import org.thoughtcrime.securesms.util.TelephonyUtil;
import org.thoughtcrime.securesms.webrtc.locks.LockManager;
import org.webrtc.PeerConnection;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.InvalidKeyException;
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.messages.calls.BusyMessage;
import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import org.whispersystems.signalservice.api.messages.calls.SignalServiceCallMessage;
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@ -92,7 +91,6 @@ import static org.thoughtcrime.securesms.service.WebRtcCallService.ACTION_WIRED_
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_ANSWER_WITH_VIDEO;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_BLUETOOTH;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_CAMERA_STATE;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_ERROR;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_IS_ALWAYS_TURN;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_MUTE;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_RESULT_RECEIVER;
@ -104,6 +102,8 @@ import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getAv
import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getBroadcastFlag;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getCallId;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getEnable;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getErrorCallState;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getErrorIdentityKey;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getIceCandidates;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getIceServers;
import static org.thoughtcrime.securesms.service.webrtc.WebRtcIntentParser.getOfferMessageType;
@ -173,7 +173,7 @@ public abstract class WebRtcActionProcessor {
case ACTION_LOCAL_HANGUP: return handleLocalHangup(currentState);
case ACTION_SEND_HANGUP: return handleSendHangup(currentState, CallMetadata.fromIntent(intent), HangupMetadata.fromIntent(intent), getBroadcastFlag(intent));
case ACTION_MESSAGE_SENT_SUCCESS: return handleMessageSentSuccess(currentState, getCallId(intent));
case ACTION_MESSAGE_SENT_ERROR: return handleMessageSentError(currentState, getCallId(intent), (Throwable) intent.getSerializableExtra(EXTRA_ERROR));
case ACTION_MESSAGE_SENT_ERROR: return handleMessageSentError(currentState, getCallId(intent), getErrorCallState(intent), getErrorIdentityKey(intent));
// Call Setup Actions
case ACTION_RECEIVE_ICE_CANDIDATES: return handleReceivedIceCandidates(currentState, CallMetadata.fromIntent(intent), getIceCandidates(intent));
@ -453,8 +453,11 @@ public abstract class WebRtcActionProcessor {
return currentState;
}
protected @NonNull WebRtcServiceState handleMessageSentError(@NonNull WebRtcServiceState currentState, @NonNull CallId callId, @Nullable Throwable error) {
Log.w(tag, error);
protected @NonNull WebRtcServiceState handleMessageSentError(@NonNull WebRtcServiceState currentState,
@NonNull CallId callId,
@NonNull WebRtcViewModel.State errorCallState,
@NonNull Optional<IdentityKey> identityKey) {
Log.w(tag, "handleMessageSentError():");
try {
webRtcInteractor.getCallManager().messageSendFailure(callId);
@ -469,21 +472,17 @@ public abstract class WebRtcActionProcessor {
WebRtcServiceStateBuilder builder = currentState.builder();
if (error instanceof UntrustedIdentityException) {
if (errorCallState == WebRtcViewModel.State.UNTRUSTED_IDENTITY) {
CallParticipant participant = Objects.requireNonNull(currentState.getCallInfoState().getRemoteParticipant(activePeer.getRecipient()));
CallParticipant untrusted = participant.withIdentityKey(((UntrustedIdentityException) error).getIdentityKey());
CallParticipant untrusted = participant.withIdentityKey(identityKey.get());
builder.changeCallInfoState()
.callState(WebRtcViewModel.State.UNTRUSTED_IDENTITY)
.putParticipant(activePeer.getRecipient(), untrusted)
.commit();
} else if (error instanceof UnregisteredUserException) {
} else {
builder.changeCallInfoState()
.callState(WebRtcViewModel.State.NO_SUCH_USER)
.commit();
} else if (error instanceof IOException) {
builder.changeCallInfoState()
.callState(WebRtcViewModel.State.NETWORK_FAILURE)
.callState(errorCallState)
.commit();
}

View file

@ -6,6 +6,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.signal.ringrtc.CallId;
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
import org.thoughtcrime.securesms.events.WebRtcViewModel;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.ringrtc.IceCandidateParcel;
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
@ -13,6 +15,8 @@ import org.thoughtcrime.securesms.ringrtc.TurnServerInfoParcel;
import org.thoughtcrime.securesms.service.WebRtcCallService;
import org.thoughtcrime.securesms.service.webrtc.state.WebRtcServiceState;
import org.webrtc.PeerConnection;
import org.whispersystems.libsignal.IdentityKey;
import org.whispersystems.libsignal.util.guava.Optional;
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
import java.util.ArrayList;
@ -26,6 +30,8 @@ import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_AVAILAB
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_BROADCAST;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_CALL_ID;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_ENABLE;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_ERROR_CALL_STATE;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_ERROR_IDENTITY_KEY;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_ICE_CANDIDATES;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_MULTI_RING;
import static org.thoughtcrime.securesms.service.WebRtcCallService.EXTRA_OFFER_OPAQUE;
@ -143,4 +149,15 @@ public final class WebRtcIntentParser {
return intent.getBooleanExtra(EXTRA_ENABLE, false);
}
public static @NonNull WebRtcViewModel.State getErrorCallState(@NonNull Intent intent) {
return (WebRtcViewModel.State) Objects.requireNonNull(intent.getSerializableExtra(EXTRA_ERROR_CALL_STATE));
}
public static @NonNull Optional<IdentityKey> getErrorIdentityKey(@NonNull Intent intent) {
IdentityKeyParcelable identityKeyParcelable = (IdentityKeyParcelable) intent.getParcelableExtra(EXTRA_ERROR_IDENTITY_KEY);
if (identityKeyParcelable != null) {
return Optional.fromNullable(identityKeyParcelable.get());
}
return Optional.absent();
}
}