From 349a2f72cb568afb852f3fad73d2bdfd17b8ec42 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Thu, 5 Nov 2020 15:56:56 -0500 Subject: [PATCH] Fix crash when handling call messaging failures. --- .../securesms/WebRtcCallActivity.java | 3 +- .../securesms/events/WebRtcViewModel.java | 9 +++++- .../securesms/service/WebRtcCallService.java | 23 ++++++++++++--- .../ActiveCallActionProcessorDelegate.java | 2 +- .../service/webrtc/WebRtcActionProcessor.java | 29 +++++++++---------- .../service/webrtc/WebRtcIntentParser.java | 17 +++++++++++ 6 files changed, 61 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/WebRtcCallActivity.java b/app/src/main/java/org/thoughtcrime/securesms/WebRtcCallActivity.java index 5194e57c36..8393d2929d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/WebRtcCallActivity.java +++ b/app/src/main/java/org/thoughtcrime/securesms/WebRtcCallActivity.java @@ -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); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/events/WebRtcViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/events/WebRtcViewModel.java index cd0a62473b..0dad339641 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/events/WebRtcViewModel.java +++ b/app/src/main/java/org/thoughtcrime/securesms/events/WebRtcViewModel.java @@ -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; diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.java b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.java index dc559d110a..4b2493e501 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/WebRtcCallService.java @@ -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); diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java index 61472ca4ea..d4176d334d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/ActiveCallActionProcessorDelegate.java @@ -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) diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java index 518447dc74..ac24541a2f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcActionProcessor.java @@ -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) { + 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(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcIntentParser.java b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcIntentParser.java index 88684092cf..f094fe1b6e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcIntentParser.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/webrtc/WebRtcIntentParser.java @@ -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 getErrorIdentityKey(@NonNull Intent intent) { + IdentityKeyParcelable identityKeyParcelable = (IdentityKeyParcelable) intent.getParcelableExtra(EXTRA_ERROR_IDENTITY_KEY); + if (identityKeyParcelable != null) { + return Optional.fromNullable(identityKeyParcelable.get()); + } + return Optional.absent(); + } }