From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Pranav Madapurmath Date: Thu, 25 May 2023 20:49:21 +0000 Subject: [PATCH] Resolve StatusHints image exploit across user. Because of the INTERACT_ACROSS_USERS permission, an app that implements a ConnectionService can upload an image icon belonging to another user by setting it in the StatusHints. Validating the construction of the StatusHints on the calling user would prevent a malicious app from registering a connection service with the embedded image icon from a different user. From additional feedback, this CL also addresses potential vulnerabilities in an app being able to directly invoke the binder for a means to manipulate the contents of the bundle that are passed with it. The targeted points of entry are in ConnectionServiceWrapper for the following APIs: handleCreateConnectionComplete, setStatusHints, addConferenceCall, and addExistingConnection. Fixes: 280797684 Test: Manual (verified that original exploit is no longer an issue). Test: Unit test for validating image in StatusHints constructor. Test: Unit tests to address vulnerabilities via the binder. (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:49d19dd265bee669b230efa29bf98c83650efea6) Merged-In: Ie1f6a8866d31d5f1099dd0630cf8e9ee782d389c Change-Id: Ie1f6a8866d31d5f1099dd0630cf8e9ee782d389c --- .../telecom/ConnectionServiceWrapper.java | 32 ++++ .../server/telecom/tests/BasicCallTests.java | 164 +++++++++++++++++- .../server/telecom/tests/CallExtrasTest.java | 6 +- .../tests/ConnectionServiceFixture.java | 21 ++- .../telecom/tests/TelecomSystemTest.java | 63 +++++-- .../server/telecom/tests/VideoCallTests.java | 16 +- 6 files changed, 263 insertions(+), 39 deletions(-) diff --git a/src/com/android/server/telecom/ConnectionServiceWrapper.java b/src/com/android/server/telecom/ConnectionServiceWrapper.java index 845cd371a..0335b230b 100644 --- a/src/com/android/server/telecom/ConnectionServiceWrapper.java +++ b/src/com/android/server/telecom/ConnectionServiceWrapper.java @@ -19,6 +19,7 @@ package com.android.server.telecom; import android.app.AppOpsManager; import android.content.ComponentName; import android.content.Context; +import android.graphics.drawable.Icon; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -71,10 +72,17 @@ public class ConnectionServiceWrapper extends ServiceBinder { public void handleCreateConnectionComplete(String callId, ConnectionRequest request, ParcelableConnection connection, Session.Info sessionInfo) { Log.startSession(sessionInfo, LogUtils.Sessions.CSW_HANDLE_CREATE_CONNECTION_COMPLETE); + UserHandle callingUserHandle = Binder.getCallingUserHandle(); long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { logIncoming("handleCreateConnectionComplete %s", callId); + // Check status hints image for cross user access + if (connection.getStatusHints() != null) { + Icon icon = connection.getStatusHints().getIcon(); + connection.getStatusHints().setIcon(StatusHints. + validateAccountIconUserBoundary(icon, callingUserHandle)); + } ConnectionServiceWrapper.this .handleCreateConnectionComplete(callId, request, connection); @@ -371,6 +379,15 @@ public class ConnectionServiceWrapper extends ServiceBinder { public void addConferenceCall(String callId, ParcelableConference parcelableConference, Session.Info sessionInfo) { Log.startSession(sessionInfo, LogUtils.Sessions.CSW_ADD_CONFERENCE_CALL); + + UserHandle callingUserHandle = Binder.getCallingUserHandle(); + // Check status hints image for cross user access + if (parcelableConference.getStatusHints() != null) { + Icon icon = parcelableConference.getStatusHints().getIcon(); + parcelableConference.getStatusHints().setIcon(StatusHints. + validateAccountIconUserBoundary(icon, callingUserHandle)); + } + long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { @@ -571,10 +588,17 @@ public class ConnectionServiceWrapper extends ServiceBinder { public void setStatusHints(String callId, StatusHints statusHints, Session.Info sessionInfo) { Log.startSession(sessionInfo, "CSW.sSH"); + UserHandle callingUserHandle = Binder.getCallingUserHandle(); long token = Binder.clearCallingIdentity(); try { synchronized (mLock) { logIncoming("setStatusHints %s %s", callId, statusHints); + // Check status hints image for cross user access + if (statusHints != null) { + Icon icon = statusHints.getIcon(); + statusHints.setIcon(StatusHints.validateAccountIconUserBoundary( + icon, callingUserHandle)); + } Call call = mCallIdMapper.getCall(callId); if (call != null) { call.setStatusHints(statusHints); @@ -735,6 +759,14 @@ public class ConnectionServiceWrapper extends ServiceBinder { } else { connectIdToCheck = callId; } + + // Check status hints image for cross user access + if (connection.getStatusHints() != null) { + Icon icon = connection.getStatusHints().getIcon(); + connection.getStatusHints().setIcon(StatusHints. + validateAccountIconUserBoundary(icon, userHandle)); + } + // Check to see if this Connection has already been added. Call alreadyAddedConnection = mCallsManager .getAlreadyAddedConnection(connectIdToCheck); diff --git a/tests/src/com/android/server/telecom/tests/BasicCallTests.java b/tests/src/com/android/server/telecom/tests/BasicCallTests.java index e18ffb2d1..18bfc41e6 100644 --- a/tests/src/com/android/server/telecom/tests/BasicCallTests.java +++ b/tests/src/com/android/server/telecom/tests/BasicCallTests.java @@ -16,6 +16,8 @@ package com.android.server.telecom.tests; +import static com.android.server.telecom.tests.ConnectionServiceFixture.STATUS_HINTS_EXTRA; + import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; @@ -29,6 +31,8 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.IContentProvider; +import android.content.Intent; +import android.graphics.drawable.Icon; import android.media.AudioManager; import android.net.Uri; import android.os.Bundle; @@ -45,12 +49,15 @@ import android.telecom.Log; import android.telecom.ParcelableCall; import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; +import android.telecom.StatusHints; import android.telecom.TelecomManager; import android.telecom.VideoProfile; import android.support.test.filters.FlakyTest; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.MediumTest; +import androidx.test.filters.SmallTest; + import com.android.internal.telecom.IInCallAdapter; import com.android.internal.telephony.CallerInfo; @@ -151,7 +158,7 @@ public class BasicCallTests extends TelecomSystemTest { @LargeTest public void testTelecomManagerAcceptRingingVideoCall() throws Exception { IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), - VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); + VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA, null); assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); @@ -179,7 +186,7 @@ public class BasicCallTests extends TelecomSystemTest { @LargeTest public void testTelecomManagerAcceptRingingVideoCallAsAudio() throws Exception { IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), - VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); + VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA, null); assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); @@ -206,7 +213,7 @@ public class BasicCallTests extends TelecomSystemTest { @LargeTest public void testTelecomManagerAcceptRingingInvalidVideoState() throws Exception { IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), - VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); + VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA, null); assertEquals(Call.STATE_RINGING, mInCallServiceFixtureX.getCall(ids.mCallId).getState()); assertEquals(Call.STATE_RINGING, mInCallServiceFixtureY.getCall(ids.mCallId).getState()); @@ -599,12 +606,12 @@ public class BasicCallTests extends TelecomSystemTest { @MediumTest public void testBasicConferenceCall() throws Exception { - makeConferenceCall(); + makeConferenceCall(null, null); } @MediumTest public void testAddCallToConference1() throws Exception { - ParcelableCall conferenceCall = makeConferenceCall(); + ParcelableCall conferenceCall = makeConferenceCall(null, null); IdPair callId3 = startAndMakeActiveOutgoingCall("650-555-1214", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); // testAddCallToConference{1,2} differ in the order of arguments to InCallAdapter#conference @@ -621,7 +628,7 @@ public class BasicCallTests extends TelecomSystemTest { @MediumTest public void testAddCallToConference2() throws Exception { - ParcelableCall conferenceCall = makeConferenceCall(); + ParcelableCall conferenceCall = makeConferenceCall(null, null); IdPair callId3 = startAndMakeActiveOutgoingCall("650-555-1214", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); mInCallServiceFixtureX.getInCallAdapter() @@ -887,7 +894,7 @@ public class BasicCallTests extends TelecomSystemTest { public void testOutgoingCallSelectPhoneAccountVideo() throws Exception { startOutgoingPhoneCallPendingCreateConnection("650-555-1212", null, mConnectionServiceFixtureA, - Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL); + Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL, null); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); assert(call.isVideoCallingSupported()); @@ -909,7 +916,7 @@ public class BasicCallTests extends TelecomSystemTest { public void testOutgoingCallSelectPhoneAccountNoVideo() throws Exception { startOutgoingPhoneCallPendingCreateConnection("650-555-1212", null, mConnectionServiceFixtureA, - Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL); + Process.myUserHandle(), VideoProfile.STATE_BIDIRECTIONAL, null); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); assert(call.isVideoCallingSupported()); @@ -975,4 +982,145 @@ public class BasicCallTests extends TelecomSystemTest { assertFalse(mTelecomSystem.getTelecomServiceImpl().getBinder() .isOutgoingCallPermitted(mPhoneAccountSelfManaged.getAccountHandle())); } + + /** + * Verifies that StatusHints image is validated in ConnectionServiceWrapper#addConferenceCall + * when the image doesn't belong to the calling user. Simulates a scenario where an app + * could manipulate the contents of the bundle and send it via the binder to upload an image + * from another user. + * + * @throws Exception + */ + @SmallTest + @Test + public void testValidateStatusHintsImage_addConferenceCall() throws Exception { + Intent callIntent1 = new Intent(); + // Stub intent for call2 + Intent callIntent2 = new Intent(); + Bundle callExtras1 = new Bundle(); + Icon icon = Icon.createWithContentUri("content://10@media/external/images/media/"); + // Load StatusHints extra into TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS to be processed + // as the call extras. This will be leveraged in ConnectionServiceFixture to set the + // StatusHints for the given connection. + StatusHints statusHints = new StatusHints(icon); + assertNotNull(statusHints.getIcon()); + callExtras1.putParcelable(STATUS_HINTS_EXTRA, statusHints); + callIntent1.putExtra(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, callExtras1); + + // Start conference call to invoke ConnectionServiceWrapper#addConferenceCall. + // Note that the calling user would be User 0. + ParcelableCall conferenceCall = makeConferenceCall(callIntent1, callIntent2); + + // Ensure that StatusHints was set. + assertNotNull(mInCallServiceFixtureX.getCall(mInCallServiceFixtureX.mLatestCallId) + .getStatusHints()); + // Ensure that the StatusHints image icon was disregarded. + assertNull(mInCallServiceFixtureX.getCall(mInCallServiceFixtureX.mLatestCallId) + .getStatusHints().getIcon()); + } + + /** + * Verifies that StatusHints image is validated in + * ConnectionServiceWrapper#handleCreateConnectionComplete when the image doesn't belong to the + * calling user. Simulates a scenario where an app could manipulate the contents of the + * bundle and send it via the binder to upload an image from another user. + * + * @throws Exception + */ + @SmallTest + @Test + public void testValidateStatusHintsImage_handleCreateConnectionComplete() throws Exception { + Bundle extras = new Bundle(); + Icon icon = Icon.createWithContentUri("content://10@media/external/images/media/"); + // Load the bundle with the test extra in order to simulate an app directly invoking the + // binder on ConnectionServiceWrapper#handleCreateConnectionComplete. + StatusHints statusHints = new StatusHints(icon); + assertNotNull(statusHints.getIcon()); + extras.putParcelable(STATUS_HINTS_EXTRA, statusHints); + + // Start incoming call with StatusHints extras + // Note that the calling user in ConnectionServiceWrapper#handleCreateConnectionComplete + // would be User 0. + IdPair ids = startIncomingPhoneCallWithExtras("650-555-1212", + mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, extras); + + // Ensure that StatusHints was set. + assertNotNull(mInCallServiceFixtureX.getCall(ids.mCallId).getStatusHints()); + // Ensure that the StatusHints image icon was disregarded. + assertNull(mInCallServiceFixtureX.getCall(ids.mCallId).getStatusHints().getIcon()); + } + + /** + * Verifies that StatusHints image is validated in ConnectionServiceWrapper#setStatusHints + * when the image doesn't belong to the calling user. Simulates a scenario where an app + * could manipulate the contents of the bundle and send it via the binder to upload an image + * from another user. + * + * @throws Exception + */ + @SmallTest + @Test + public void testValidateStatusHintsImage_setStatusHints() throws Exception { + IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1214", + mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); + + // Modify existing connection with StatusHints image exploit + Icon icon = Icon.createWithContentUri("content://10@media/external/images/media/"); + StatusHints statusHints = new StatusHints(icon); + assertNotNull(statusHints.getIcon()); + ConnectionServiceFixture.ConnectionInfo connectionInfo = mConnectionServiceFixtureA + .mConnectionById.get(outgoing.mConnectionId); + connectionInfo.statusHints = statusHints; + + // Invoke ConnectionServiceWrapper#setStatusHints. + // Note that the calling user would be User 0. + mConnectionServiceFixtureA.sendSetStatusHints(outgoing.mConnectionId); + waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), + TEST_TIMEOUT); + + // Ensure that StatusHints was set. + assertNotNull(mInCallServiceFixtureX.getCall(outgoing.mCallId).getStatusHints()); + // Ensure that the StatusHints image icon was disregarded. + assertNull(mInCallServiceFixtureX.getCall(outgoing.mCallId) + .getStatusHints().getIcon()); + } + + /** + * Verifies that StatusHints image is validated in + * ConnectionServiceWrapper#addExistingConnection when the image doesn't belong to the calling + * user. Simulates a scenario where an app could manipulate the contents of the bundle and + * send it via the binder to upload an image from another user. + * + * @throws Exception + */ + @SmallTest + @Test + public void testValidateStatusHintsImage_addExistingConnection() throws Exception { + IdPair outgoing = startAndMakeActiveOutgoingCall("650-555-1214", + mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); + Connection existingConnection = mConnectionServiceFixtureA.mLatestConnection; + + // Modify existing connection with StatusHints image exploit + Icon icon = Icon.createWithContentUri("content://10@media/external/images/media/"); + StatusHints modifiedStatusHints = new StatusHints(icon); + assertNotNull(modifiedStatusHints.getIcon()); + ConnectionServiceFixture.ConnectionInfo connectionInfo = mConnectionServiceFixtureA + .mConnectionById.get(outgoing.mConnectionId); + connectionInfo.statusHints = modifiedStatusHints; + + // Invoke ConnectionServiceWrapper#addExistingConnection. + // Note that the calling user would be User 0. + mConnectionServiceFixtureA.sendAddExistingConnection(outgoing.mConnectionId); + waitForHandlerAction(mConnectionServiceFixtureA.mConnectionServiceDelegate.getHandler(), + TEST_TIMEOUT); + + // Ensure that StatusHints was set. Due to test setup, the ParcelableConnection object that + // is passed into sendAddExistingConnection is instantiated on invocation. The call's + // StatusHints are not updated at the time of completion, so instead, we can verify that + // the ParcelableConnection object was modified. + assertNotNull(mConnectionServiceFixtureA.mLatestParcelableConnection.getStatusHints()); + // Ensure that the StatusHints image icon was disregarded. + assertNull(mConnectionServiceFixtureA.mLatestParcelableConnection + .getStatusHints().getIcon()); + } } diff --git a/tests/src/com/android/server/telecom/tests/CallExtrasTest.java b/tests/src/com/android/server/telecom/tests/CallExtrasTest.java index e9cd73376..c82df24a6 100644 --- a/tests/src/com/android/server/telecom/tests/CallExtrasTest.java +++ b/tests/src/com/android/server/telecom/tests/CallExtrasTest.java @@ -323,7 +323,7 @@ public class CallExtrasTest extends TelecomSystemTest { */ @LargeTest public void testConferenceSetExtras() throws Exception { - ParcelableCall call = makeConferenceCall(); + ParcelableCall call = makeConferenceCall(null, null); String conferenceId = call.getId(); Conference conference = mConnectionServiceFixtureA.mLatestConference; @@ -365,7 +365,7 @@ public class CallExtrasTest extends TelecomSystemTest { */ @LargeTest public void testConferenceExtraOperations() throws Exception { - ParcelableCall call = makeConferenceCall(); + ParcelableCall call = makeConferenceCall(null, null); String conferenceId = call.getId(); Conference conference = mConnectionServiceFixtureA.mLatestConference; assertNotNull(conference); @@ -400,7 +400,7 @@ public class CallExtrasTest extends TelecomSystemTest { */ @LargeTest public void testConferenceICS() throws Exception { - ParcelableCall call = makeConferenceCall(); ++ ParcelableCall call = makeConferenceCall(null, null); String conferenceId = call.getId(); Conference conference = mConnectionServiceFixtureA.mLatestConference; diff --git a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java index 39f70c8c6..01a2a1488 100644 --- a/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java +++ b/tests/src/com/android/server/telecom/tests/ConnectionServiceFixture.java @@ -66,6 +66,7 @@ public class ConnectionServiceFixture implements TestFixture static int INVALID_VIDEO_STATE = -1; public CountDownLatch mExtrasLock = new CountDownLatch(1); static int NOT_SPECIFIED = 0; + public static final String STATUS_HINTS_EXTRA = "updateStatusHints"; /** * Implementation of ConnectionService that performs no-ops for tasks normally meant for @@ -96,6 +97,11 @@ public class ConnectionServiceFixture implements TestFixture if (mProperties != NOT_SPECIFIED) { fakeConnection.setConnectionProperties(mProperties); } + // Testing for StatusHints image icon cross user access + if (request.getExtras() != null) { + fakeConnection.setStatusHints( + request.getExtras().getParcelable(STATUS_HINTS_EXTRA)); + } return fakeConnection; } @@ -112,6 +118,11 @@ public class ConnectionServiceFixture implements TestFixture if (mProperties != NOT_SPECIFIED) { fakeConnection.setConnectionProperties(mProperties); } + // Testing for StatusHints image icon cross user access + if (request.getExtras() != null) { + fakeConnection.setStatusHints( + request.getExtras().getParcelable(STATUS_HINTS_EXTRA)); + } return fakeConnection; } @@ -128,6 +139,12 @@ public class ConnectionServiceFixture implements TestFixture Conference fakeConference = new FakeConference(); fakeConference.addConnection(cxn1); fakeConference.addConnection(cxn2); + if (cxn1.getStatusHints() != null || cxn2.getStatusHints() != null) { + // For testing purposes, pick one of the status hints that isn't null. + StatusHints statusHints = cxn1.getStatusHints() != null + ? cxn1.getStatusHints() : cxn2.getStatusHints(); + fakeConference.setStatusHints(statusHints); + } mLatestConference = fakeConference; addConference(fakeConference); } else { @@ -416,6 +433,7 @@ public class ConnectionServiceFixture implements TestFixture public String mLatestConnectionId; public Connection mLatestConnection; + public ParcelableConnection mLatestParcelableConnection; public Conference mLatestConference; public final Set mConnectionServiceAdapters = new HashSet<>(); public final Map mConnectionById = new HashMap<>(); @@ -646,7 +664,7 @@ public class ConnectionServiceFixture implements TestFixture } private ParcelableConnection parcelable(ConnectionInfo c) { - return new ParcelableConnection( + mLatestParcelableConnection = new ParcelableConnection( c.request.getAccountHandle(), c.state, c.capabilities, @@ -666,5 +684,6 @@ public class ConnectionServiceFixture implements TestFixture c.disconnectCause, c.conferenceableConnectionIds, c.extras); + return mLatestParcelableConnection; } } diff --git a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java index 6b2cf4f0a..fe6f74348 100644 --- a/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java +++ b/tests/src/com/android/server/telecom/tests/TelecomSystemTest.java @@ -369,12 +369,13 @@ public class TelecomSystemTest extends TelecomTestCase { super.tearDown(); } - protected ParcelableCall makeConferenceCall() throws Exception { - IdPair callId1 = startAndMakeActiveOutgoingCall("650-555-1212", - mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); + protected ParcelableCall makeConferenceCall( + Intent callIntentExtras1, Intent callIntentExtras2) throws Exception { + IdPair callId1 = startAndMakeActiveOutgoingCallWithExtras("650-555-1212", + mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, callIntentExtras1); - IdPair callId2 = startAndMakeActiveOutgoingCall("650-555-1213", - mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA); + IdPair callId2 = startAndMakeActiveOutgoingCallWithExtras("650-555-1213", + mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, callIntentExtras2); IInCallAdapter inCallAdapter = mInCallServiceFixtureX.getInCallAdapter(); inCallAdapter.conference(callId1.mCallId, callId2.mCallId); @@ -569,17 +570,17 @@ public class TelecomSystemTest extends TelecomTestCase { throws Exception { return startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture, - initiatingUser, VideoProfile.STATE_AUDIO_ONLY); + initiatingUser, VideoProfile.STATE_AUDIO_ONLY, null); } protected IdPair startOutgoingPhoneCall(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, - int videoState) throws Exception { + int videoState, Intent callIntentExtras) throws Exception { int startingNumConnections = connectionServiceFixture.mConnectionById.size(); int startingNumCalls = mInCallServiceFixtureX.mCallById.size(); startOutgoingPhoneCallPendingCreateConnection(number, phoneAccountHandle, - connectionServiceFixture, initiatingUser, videoState); + connectionServiceFixture, initiatingUser, videoState, callIntentExtras); return outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls, phoneAccountHandle, connectionServiceFixture); @@ -615,7 +616,7 @@ public class TelecomSystemTest extends TelecomTestCase { mIsEmergencyCall = true; // Call will not use the ordered broadcaster, since it is an Emergency Call startOutgoingPhoneCallWaitForBroadcaster(number, phoneAccountHandle, - connectionServiceFixture, initiatingUser, videoState, true /*isEmergency*/); + connectionServiceFixture, initiatingUser, videoState, true /*isEmergency*/, null); return outgoingCallCreateConnectionComplete(startingNumConnections, startingNumCalls, phoneAccountHandle, connectionServiceFixture); @@ -624,7 +625,7 @@ public class TelecomSystemTest extends TelecomTestCase { protected void startOutgoingPhoneCallWaitForBroadcaster(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, - int videoState, boolean isEmergency) throws Exception { + int videoState, boolean isEmergency, Intent actionCallIntent) throws Exception { reset(connectionServiceFixture.getTestDouble(), mInCallServiceFixtureX.getTestDouble(), mInCallServiceFixtureY.getTestDouble()); @@ -637,7 +638,9 @@ public class TelecomSystemTest extends TelecomTestCase { boolean hasInCallAdapter = mInCallServiceFixtureX.mInCallAdapter != null; - Intent actionCallIntent = new Intent(); + if (actionCallIntent == null) { + actionCallIntent = new Intent(); + } actionCallIntent.setData(Uri.parse("tel:" + number)); actionCallIntent.putExtra(Intent.EXTRA_PHONE_NUMBER, number); if(isEmergency) { @@ -683,9 +686,9 @@ public class TelecomSystemTest extends TelecomTestCase { protected String startOutgoingPhoneCallPendingCreateConnection(String number, PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture, UserHandle initiatingUser, - int videoState) throws Exception { + int videoState, Intent callIntentExtras) throws Exception { startOutgoingPhoneCallWaitForBroadcaster(number,phoneAccountHandle, - connectionServiceFixture, initiatingUser, videoState, false /*isEmergency*/); + connectionServiceFixture, initiatingUser, videoState, false /*isEmergency*/, callIntentExtras); ArgumentCaptor newOutgoingCallIntent = ArgumentCaptor.forClass(Intent.class); @@ -779,14 +782,24 @@ public class TelecomSystemTest extends TelecomTestCase { PhoneAccountHandle phoneAccountHandle, final ConnectionServiceFixture connectionServiceFixture) throws Exception { return startIncomingPhoneCall(number, phoneAccountHandle, VideoProfile.STATE_AUDIO_ONLY, - connectionServiceFixture); + connectionServiceFixture, null); + } + + protected IdPair startIncomingPhoneCallWithExtras( + String number, + PhoneAccountHandle phoneAccountHandle, + final ConnectionServiceFixture connectionServiceFixture, + Bundle extras) throws Exception { + return startIncomingPhoneCall(number, phoneAccountHandle, VideoProfile.STATE_AUDIO_ONLY, + connectionServiceFixture, extras); } protected IdPair startIncomingPhoneCall( String number, PhoneAccountHandle phoneAccountHandle, int videoState, - final ConnectionServiceFixture connectionServiceFixture) throws Exception { + final ConnectionServiceFixture connectionServiceFixture, + Bundle extras) throws Exception { reset(connectionServiceFixture.getTestDouble(), mInCallServiceFixtureX.getTestDouble(), mInCallServiceFixtureY.getTestDouble()); @@ -803,7 +816,9 @@ public class TelecomSystemTest extends TelecomTestCase { new IncomingCallAddedListener(incomingCallAddedLatch); mTelecomSystem.getCallsManager().addListener(callAddedListener); - Bundle extras = new Bundle(); + if (extras == null) { + extras = new Bundle(); + } extras.putParcelable( TelecomManager.EXTRA_INCOMING_CALL_ADDRESS, Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null)); @@ -904,7 +919,16 @@ public class TelecomSystemTest extends TelecomTestCase { PhoneAccountHandle phoneAccountHandle, ConnectionServiceFixture connectionServiceFixture) throws Exception { return startAndMakeActiveOutgoingCall(number, phoneAccountHandle, connectionServiceFixture, - VideoProfile.STATE_AUDIO_ONLY); + VideoProfile.STATE_AUDIO_ONLY, null); + } + + protected IdPair startAndMakeActiveOutgoingCallWithExtras( + String number, + PhoneAccountHandle phoneAccountHandle, + ConnectionServiceFixture connectionServiceFixture, + Intent callIntentExtras) throws Exception { + return startAndMakeActiveOutgoingCall(number, phoneAccountHandle, connectionServiceFixture, + VideoProfile.STATE_AUDIO_ONLY, callIntentExtras); } // A simple outgoing call, verifying that the appropriate connection service is contacted, @@ -912,9 +936,10 @@ public class TelecomSystemTest extends TelecomTestCase { protected IdPair startAndMakeActiveOutgoingCall( String number, PhoneAccountHandle phoneAccountHandle, - ConnectionServiceFixture connectionServiceFixture, int videoState) throws Exception { + ConnectionServiceFixture connectionServiceFixture, int videoState, + Intent callIntentExtras) throws Exception { IdPair ids = startOutgoingPhoneCall(number, phoneAccountHandle, connectionServiceFixture, - Process.myUserHandle(), videoState); + Process.myUserHandle(), videoState, callIntentExtras); connectionServiceFixture.sendSetDialing(ids.mConnectionId); if (phoneAccountHandle != mPhoneAccountSelfManaged.getAccountHandle()) { diff --git a/tests/src/com/android/server/telecom/tests/VideoCallTests.java b/tests/src/com/android/server/telecom/tests/VideoCallTests.java index c91f86e56..2384a524e 100644 --- a/tests/src/com/android/server/telecom/tests/VideoCallTests.java +++ b/tests/src/com/android/server/telecom/tests/VideoCallTests.java @@ -80,7 +80,7 @@ public class VideoCallTests extends TelecomSystemTest { // Start an incoming video call. IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, - VideoProfile.STATE_BIDIRECTIONAL); + VideoProfile.STATE_BIDIRECTIONAL, null); verifyAudioRoute(CallAudioState.ROUTE_SPEAKER); } @@ -95,7 +95,7 @@ public class VideoCallTests extends TelecomSystemTest { // Start an incoming video call. IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, - VideoProfile.STATE_TX_ENABLED); + VideoProfile.STATE_TX_ENABLED, null); verifyAudioRoute(CallAudioState.ROUTE_SPEAKER); } @@ -110,7 +110,7 @@ public class VideoCallTests extends TelecomSystemTest { // Start an incoming video call. IdPair ids = startAndMakeActiveOutgoingCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, - VideoProfile.STATE_AUDIO_ONLY); + VideoProfile.STATE_AUDIO_ONLY, null); verifyAudioRoute(CallAudioState.ROUTE_EARPIECE); } @@ -136,7 +136,7 @@ public class VideoCallTests extends TelecomSystemTest { @LargeTest public void testIncomingVideoCallMissedCheckVideoHistory() throws Exception { IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), - VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); + VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA, null); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); @@ -152,7 +152,7 @@ public class VideoCallTests extends TelecomSystemTest { @LargeTest public void testIncomingVideoCallRejectedCheckVideoHistory() throws Exception { IdPair ids = startIncomingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), - VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA); + VideoProfile.STATE_BIDIRECTIONAL, mConnectionServiceFixtureA, null); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); @@ -170,7 +170,7 @@ public class VideoCallTests extends TelecomSystemTest { public void testOutgoingVideoCallCanceledCheckVideoHistory() throws Exception { IdPair ids = startOutgoingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, Process.myUserHandle(), - VideoProfile.STATE_BIDIRECTIONAL); + VideoProfile.STATE_BIDIRECTIONAL, null); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); @@ -187,7 +187,7 @@ public class VideoCallTests extends TelecomSystemTest { public void testOutgoingVideoCallRejectedCheckVideoHistory() throws Exception { IdPair ids = startOutgoingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, Process.myUserHandle(), - VideoProfile.STATE_BIDIRECTIONAL); + VideoProfile.STATE_BIDIRECTIONAL, null); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next(); @@ -204,7 +204,7 @@ public class VideoCallTests extends TelecomSystemTest { public void testOutgoingVideoCallAnsweredAsAudio() throws Exception { IdPair ids = startOutgoingPhoneCall("650-555-1212", mPhoneAccountA0.getAccountHandle(), mConnectionServiceFixtureA, Process.myUserHandle(), - VideoProfile.STATE_BIDIRECTIONAL); + VideoProfile.STATE_BIDIRECTIONAL, null); com.android.server.telecom.Call call = mTelecomSystem.getCallsManager().getCalls() .iterator().next();