blob: 07d9f803d9fa5ada002eedb46336a660127897ec [file] [log] [blame]
Bryce Lee4e4a3ec2017-09-27 08:25:03 -07001/*
Wale Ogunwale59507092018-10-29 09:00:30 -07002 * Copyright (C) 2018 The Android Open Source Project
Bryce Lee4e4a3ec2017-09-27 08:25:03 -07003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
Wale Ogunwale59507092018-10-29 09:00:30 -070014 * limitations under the License
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070015 */
16
Wale Ogunwale59507092018-10-29 09:00:30 -070017package com.android.server.wm;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070018
Michal Karpinski8596ded2018-11-14 14:43:48 +000019import static android.app.ActivityManager.PROCESS_STATE_TOP;
Bryce Lee93e7f792017-10-25 15:54:55 -070020import static android.app.ActivityManager.START_ABORTED;
21import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
Bryce Lee32e09ef2018-03-19 15:29:49 -070022import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
Bryce Lee93e7f792017-10-25 15:54:55 -070023import static android.app.ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
Bryce Lee32e09ef2018-03-19 15:29:49 -070024import static android.app.ActivityManager.START_INTENT_NOT_RESOLVED;
Bryce Lee93e7f792017-10-25 15:54:55 -070025import static android.app.ActivityManager.START_NOT_VOICE_COMPATIBLE;
Bryce Lee32e09ef2018-03-19 15:29:49 -070026import static android.app.ActivityManager.START_PERMISSION_DENIED;
Bryce Lee2b8e0372018-04-05 17:01:37 -070027import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
Bryce Lee93e7f792017-10-25 15:54:55 -070028import static android.app.ActivityManager.START_SUCCESS;
29import static android.app.ActivityManager.START_SWITCHES_CANCELED;
Bryce Lee32e09ef2018-03-19 15:29:49 -070030import static android.app.ActivityManager.START_TASK_TO_FRONT;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070031import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
32import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
33import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
Bryce Lee32e09ef2018-03-19 15:29:49 -070034import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
35import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
Riddle Hsub70b36d2018-09-11 21:20:02 +080036import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
Brett Chabota26eda92018-07-23 13:08:30 -070037import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
Riddle Hsub70b36d2018-09-11 21:20:02 +080038import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
Brett Chabota26eda92018-07-23 13:08:30 -070039
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090040import static com.android.dx.mockito.inline.extended.ExtendedMockito.clearInvocations;
41import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
42import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
43import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
44import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
45import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
46import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
47import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
48import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
Wale Ogunwale59507092018-10-29 09:00:30 -070049import static com.android.server.wm.ActivityDisplay.POSITION_BOTTOM;
50import static com.android.server.wm.ActivityDisplay.POSITION_TOP;
51import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
Brett Chabota26eda92018-07-23 13:08:30 -070052
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090053import static com.google.common.truth.Truth.assertThat;
54
Brett Chabota26eda92018-07-23 13:08:30 -070055import static org.junit.Assert.assertEquals;
Riddle Hsub70b36d2018-09-11 21:20:02 +080056import static org.mockito.ArgumentMatchers.any;
57import static org.mockito.ArgumentMatchers.anyBoolean;
58import static org.mockito.ArgumentMatchers.anyInt;
59import static org.mockito.ArgumentMatchers.anyObject;
60import static org.mockito.ArgumentMatchers.eq;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070061
Bryce Lee93e7f792017-10-25 15:54:55 -070062import android.app.ActivityOptions;
63import android.app.IApplicationThread;
Riddle Hsub70b36d2018-09-11 21:20:02 +080064import android.content.ComponentName;
Bryce Lee93e7f792017-10-25 15:54:55 -070065import android.content.Intent;
66import android.content.pm.ActivityInfo;
Bryce Leead5b8322018-03-08 14:28:52 -080067import android.content.pm.ActivityInfo.WindowLayout;
Bryce Lee93e7f792017-10-25 15:54:55 -070068import android.content.pm.ApplicationInfo;
69import android.content.pm.IPackageManager;
Philip P. Moltmann6c644e62018-07-18 15:41:24 -070070import android.content.pm.PackageManagerInternal;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070071import android.graphics.Rect;
Bryce Lee93e7f792017-10-25 15:54:55 -070072import android.os.IBinder;
Michal Karpinski8596ded2018-11-14 14:43:48 +000073import android.os.Process;
Bryce Lee93e7f792017-10-25 15:54:55 -070074import android.os.RemoteException;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070075import android.platform.test.annotations.Presubmit;
Bryce Lee93e7f792017-10-25 15:54:55 -070076import android.service.voice.IVoiceInteractionSession;
Bryce Leead5b8322018-03-08 14:28:52 -080077import android.view.Gravity;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070078
Brett Chabota26eda92018-07-23 13:08:30 -070079import androidx.test.filters.SmallTest;
Brett Chabota26eda92018-07-23 13:08:30 -070080
Wale Ogunwale59507092018-10-29 09:00:30 -070081import com.android.server.wm.LaunchParamsController.LaunchParamsModifier;
Bryce Lee93e7f792017-10-25 15:54:55 -070082
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090083import org.junit.Before;
Brett Chabota26eda92018-07-23 13:08:30 -070084import org.junit.Test;
Bryce Lee2b8e0372018-04-05 17:01:37 -070085
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070086/**
Bryce Leed3624e12017-11-30 08:51:45 -080087 * Tests for the {@link ActivityStarter} class.
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070088 *
89 * Build/Install/Run:
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +090090 * atest WmTests:ActivityStarterTests
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070091 */
92@SmallTest
93@Presubmit
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070094public class ActivityStarterTests extends ActivityTestsBase {
Bryce Lee4e4a3ec2017-09-27 08:25:03 -070095 private ActivityStarter mStarter;
Bryce Leed3624e12017-11-30 08:51:45 -080096 private ActivityStartController mController;
Michal Karpinski201bc0c2018-07-20 15:32:00 +010097 private ActivityMetricsLogger mActivityMetricsLogger;
Bryce Lee93e7f792017-10-25 15:54:55 -070098
99 private static final int PRECONDITION_NO_CALLER_APP = 1;
100 private static final int PRECONDITION_NO_INTENT_COMPONENT = 1 << 1;
101 private static final int PRECONDITION_NO_ACTIVITY_INFO = 1 << 2;
102 private static final int PRECONDITION_SOURCE_PRESENT = 1 << 3;
103 private static final int PRECONDITION_REQUEST_CODE = 1 << 4;
104 private static final int PRECONDITION_SOURCE_VOICE_SESSION = 1 << 5;
105 private static final int PRECONDITION_NO_VOICE_SESSION_SUPPORT = 1 << 6;
106 private static final int PRECONDITION_DIFFERENT_UID = 1 << 7;
107 private static final int PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION = 1 << 8;
108 private static final int PRECONDITION_CANNOT_START_ANY_ACTIVITY = 1 << 9;
109 private static final int PRECONDITION_DISALLOW_APP_SWITCHING = 1 << 10;
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700110
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100111 private static final int FAKE_CALLING_UID = 666;
112 private static final int FAKE_REAL_CALLING_UID = 667;
113 private static final String FAKE_CALLING_PACKAGE = "com.whatever.dude";
Michal Karpinski8596ded2018-11-14 14:43:48 +0000114 private static final int UNIMPORTANT_UID = 12345;
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000115 private static final int UNIMPORTANT_UID2 = 12346;
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100116
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900117 @Before
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700118 public void setUp() throws Exception {
Bryce Leed3624e12017-11-30 08:51:45 -0800119 mController = mock(ActivityStartController.class);
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100120 mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
121 clearInvocations(mActivityMetricsLogger);
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700122 mStarter = new ActivityStarter(mController, mService, mService.mStackSupervisor,
Bryce Leed3624e12017-11-30 08:51:45 -0800123 mock(ActivityStartInterceptor.class));
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700124 }
125
126 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900127 public void testUpdateLaunchBounds() {
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700128 // When in a non-resizeable stack, the task bounds should be updated.
Bryce Lee18d51592017-10-25 10:22:19 -0700129 final TaskRecord task = new TaskBuilder(mService.mStackSupervisor)
Wale Ogunwaled32da472018-11-16 07:19:28 -0800130 .setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
Bryce Lee18d51592017-10-25 10:22:19 -0700131 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
132 .build();
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700133 final Rect bounds = new Rect(10, 10, 100, 100);
134
135 mStarter.updateBounds(task, bounds);
Evan Roskydfe3da72018-10-26 17:21:06 -0700136 assertEquals(bounds, task.getRequestedOverrideBounds());
137 assertEquals(new Rect(), task.getStack().getRequestedOverrideBounds());
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700138
139 // When in a resizeable stack, the stack bounds should be updated as well.
Bryce Lee18d51592017-10-25 10:22:19 -0700140 final TaskRecord task2 = new TaskBuilder(mService.mStackSupervisor)
Wale Ogunwaled32da472018-11-16 07:19:28 -0800141 .setStack(mService.mRootActivityContainer.getDefaultDisplay().createStack(
Bryce Lee18d51592017-10-25 10:22:19 -0700142 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */))
143 .build();
Yunfan Chen279f5582018-12-12 15:24:50 -0800144 assertThat((Object) task2.getStack()).isInstanceOf(ActivityStack.class);
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700145 mStarter.updateBounds(task2, bounds);
146
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700147 verify(mService, times(1)).resizeStack(eq(task2.getStack().mStackId),
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700148 eq(bounds), anyBoolean(), anyBoolean(), anyBoolean(), anyInt());
149
150 // In the case of no animation, the stack and task bounds should be set immediately.
151 if (!ANIMATE) {
Evan Roskydfe3da72018-10-26 17:21:06 -0700152 assertEquals(bounds, task2.getStack().getRequestedOverrideBounds());
153 assertEquals(bounds, task2.getRequestedOverrideBounds());
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700154 } else {
Evan Roskydfe3da72018-10-26 17:21:06 -0700155 assertEquals(new Rect(), task2.getRequestedOverrideBounds());
Bryce Lee4e4a3ec2017-09-27 08:25:03 -0700156 }
157 }
Bryce Lee93e7f792017-10-25 15:54:55 -0700158
159 @Test
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900160 public void testStartActivityPreconditions() {
Bryce Lee93e7f792017-10-25 15:54:55 -0700161 verifyStartActivityPreconditions(PRECONDITION_NO_CALLER_APP, START_PERMISSION_DENIED);
162 verifyStartActivityPreconditions(PRECONDITION_NO_INTENT_COMPONENT,
163 START_INTENT_NOT_RESOLVED);
164 verifyStartActivityPreconditions(PRECONDITION_NO_ACTIVITY_INFO, START_CLASS_NOT_FOUND);
165 verifyStartActivityPreconditions(PRECONDITION_SOURCE_PRESENT | PRECONDITION_REQUEST_CODE,
166 Intent.FLAG_ACTIVITY_FORWARD_RESULT, START_FORWARD_AND_REQUEST_CONFLICT);
167 verifyStartActivityPreconditions(
168 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
169 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID,
170 START_NOT_VOICE_COMPATIBLE);
171 verifyStartActivityPreconditions(
172 PRECONDITION_SOURCE_PRESENT | PRECONDITION_NO_VOICE_SESSION_SUPPORT
173 | PRECONDITION_SOURCE_VOICE_SESSION | PRECONDITION_DIFFERENT_UID
174 | PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION,
175 START_NOT_VOICE_COMPATIBLE);
176 verifyStartActivityPreconditions(PRECONDITION_CANNOT_START_ANY_ACTIVITY, START_ABORTED);
177 verifyStartActivityPreconditions(PRECONDITION_DISALLOW_APP_SWITCHING,
178 START_SWITCHES_CANCELED);
179 }
180
181 private static boolean containsConditions(int preconditions, int mask) {
182 return (preconditions & mask) == mask;
183 }
184
185 private void verifyStartActivityPreconditions(int preconditions, int expectedResult) {
186 verifyStartActivityPreconditions(preconditions, 0 /*launchFlags*/, expectedResult);
187 }
188
189 /**
190 * Excercises how the {@link ActivityStarter} reacts to various preconditions. The caller
191 * provides a bitmask of all the set conditions (such as {@link #PRECONDITION_NO_CALLER_APP})
192 * and the launch flags specified in the intent. The method constructs a call to
Bryce Lee4c9a5972017-12-01 22:14:24 -0800193 * {@link ActivityStarter#execute} based on these preconditions and ensures the result matches
194 * the expected. It is important to note that the method also checks side effects of the start,
195 * such as ensuring {@link ActivityOptions#abort()} is called in the relevant scenarios.
Bryce Lee93e7f792017-10-25 15:54:55 -0700196 * @param preconditions A bitmask representing the preconditions for the launch
197 * @param launchFlags The launch flags to be provided by the launch {@link Intent}.
198 * @param expectedResult The expected result from the launch.
199 */
200 private void verifyStartActivityPreconditions(int preconditions, int launchFlags,
201 int expectedResult) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700202 final ActivityTaskManagerService service = mService;
Bryce Lee93e7f792017-10-25 15:54:55 -0700203 final IPackageManager packageManager = mock(IPackageManager.class);
Bryce Leed3624e12017-11-30 08:51:45 -0800204 final ActivityStartController controller = mock(ActivityStartController.class);
Bryce Lee93e7f792017-10-25 15:54:55 -0700205
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700206 final ActivityStarter starter = new ActivityStarter(controller, service,
Bryce Leed3624e12017-11-30 08:51:45 -0800207 service.mStackSupervisor, mock(ActivityStartInterceptor.class));
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700208 prepareStarter(launchFlags);
Bryce Lee93e7f792017-10-25 15:54:55 -0700209 final IApplicationThread caller = mock(IApplicationThread.class);
210
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700211 final WindowProcessController wpc =
212 containsConditions(preconditions, PRECONDITION_NO_CALLER_APP)
213 ? null : new WindowProcessController(
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900214 service, mock(ApplicationInfo.class), null, 0, -1, null, null);
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700215 doReturn(wpc).when(service).getProcessController(anyObject());
Bryce Lee93e7f792017-10-25 15:54:55 -0700216
217 final Intent intent = new Intent();
218 intent.setFlags(launchFlags);
219
220 final ActivityInfo aInfo = containsConditions(preconditions, PRECONDITION_NO_ACTIVITY_INFO)
221 ? null : new ActivityInfo();
222
Bryce Lee93e7f792017-10-25 15:54:55 -0700223 IVoiceInteractionSession voiceSession =
224 containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
225 ? mock(IVoiceInteractionSession.class) : null;
226
227 // Create source token
228 final ActivityBuilder builder = new ActivityBuilder(service).setTask(
229 new TaskBuilder(service.mStackSupervisor).setVoiceSession(voiceSession).build());
230
Bryce Leefbd263b42018-03-07 10:33:55 -0800231 if (aInfo != null) {
232 aInfo.applicationInfo = new ApplicationInfo();
Bryce Leead5b8322018-03-08 14:28:52 -0800233 aInfo.applicationInfo.packageName =
234 ActivityBuilder.getDefaultComponent().getPackageName();
Bryce Leefbd263b42018-03-07 10:33:55 -0800235 }
236
Bryce Lee93e7f792017-10-25 15:54:55 -0700237 // Offset uid by one from {@link ActivityInfo} to simulate different uids.
238 if (containsConditions(preconditions, PRECONDITION_DIFFERENT_UID)) {
239 builder.setUid(aInfo.applicationInfo.uid + 1);
240 }
241
242 final ActivityRecord source = builder.build();
243
244 if (!containsConditions(preconditions, PRECONDITION_NO_INTENT_COMPONENT)) {
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800245 intent.setComponent(source.mActivityComponent);
Bryce Lee93e7f792017-10-25 15:54:55 -0700246 }
247
248 if (containsConditions(preconditions, PRECONDITION_DISALLOW_APP_SWITCHING)) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700249 doReturn(false).when(service).checkAppSwitchAllowedLocked(
Wale Ogunwalea6191b42018-05-09 07:41:32 -0700250 anyInt(), anyInt(), anyInt(), anyInt(), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700251 }
252
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900253 if (containsConditions(preconditions, PRECONDITION_CANNOT_START_ANY_ACTIVITY)) {
Bryce Lee93e7f792017-10-25 15:54:55 -0700254 doReturn(false).when(service.mStackSupervisor).checkStartAnyActivityPermission(
Jorim Jaggi4d8d32c2018-01-19 15:57:41 +0100255 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
Winson Chungc9804e72018-05-15 11:01:44 -0700256 anyBoolean(), anyBoolean(), any(), any(), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700257 }
258
259 try {
260 if (containsConditions(preconditions,
261 PRECONDITION_ACTIVITY_SUPPORTS_INTENT_EXCEPTION)) {
262 doAnswer((inv) -> {
263 throw new RemoteException();
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800264 }).when(packageManager).activitySupportsIntent(
265 eq(source.mActivityComponent), eq(intent), any());
Bryce Lee93e7f792017-10-25 15:54:55 -0700266 } else {
267 doReturn(!containsConditions(preconditions, PRECONDITION_NO_VOICE_SESSION_SUPPORT))
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800268 .when(packageManager).activitySupportsIntent(eq(source.mActivityComponent),
Bryce Lee93e7f792017-10-25 15:54:55 -0700269 eq(intent), any());
270 }
271 } catch (RemoteException e) {
272 }
273
274 final IBinder resultTo = containsConditions(preconditions, PRECONDITION_SOURCE_PRESENT)
275 || containsConditions(preconditions, PRECONDITION_SOURCE_VOICE_SESSION)
276 ? source.appToken : null;
277
278 final int requestCode = containsConditions(preconditions, PRECONDITION_REQUEST_CODE)
279 ? 1 : 0;
280
Bryce Lee4c9a5972017-12-01 22:14:24 -0800281 final int result = starter.setCaller(caller)
282 .setIntent(intent)
283 .setActivityInfo(aInfo)
284 .setResultTo(resultTo)
285 .setRequestCode(requestCode)
286 .setReason("testLaunchActivityPermissionDenied")
287 .execute();
Bryce Lee93e7f792017-10-25 15:54:55 -0700288
289 // In some cases the expected result internally is different than the published result. We
290 // must use ActivityStarter#getExternalResult to translate.
291 assertEquals(ActivityStarter.getExternalResult(expectedResult), result);
292
293 // Ensure that {@link ActivityOptions} are aborted with unsuccessful result.
294 if (expectedResult != START_SUCCESS) {
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700295 final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
Bryce Lee4c9a5972017-12-01 22:14:24 -0800296 mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
Bryce Lee93e7f792017-10-25 15:54:55 -0700297 final ActivityOptions options = spy(ActivityOptions.makeBasic());
Bryce Lee4c9a5972017-12-01 22:14:24 -0800298
299 final int optionResult = optionStarter.setCaller(caller)
300 .setIntent(intent)
301 .setActivityInfo(aInfo)
302 .setResultTo(resultTo)
303 .setRequestCode(requestCode)
304 .setReason("testLaunchActivityPermissionDenied")
Jorim Jaggi4d8d32c2018-01-19 15:57:41 +0100305 .setActivityOptions(new SafeActivityOptions(options))
Bryce Lee4c9a5972017-12-01 22:14:24 -0800306 .execute();
Bryce Lee93e7f792017-10-25 15:54:55 -0700307 verify(options, times(1)).abort();
308 }
309 }
Bryce Leeb802ea12017-11-15 21:25:03 -0800310
Riddle Hsub70b36d2018-09-11 21:20:02 +0800311 private ActivityStarter prepareStarter(@Intent.Flags int launchFlags) {
312 return prepareStarter(launchFlags, true /* mockGetLaunchStack */);
313 }
314
315 /**
316 * Creates a {@link ActivityStarter} with default parameters and necessary mocks.
317 *
318 * @param launchFlags The intent flags to launch activity.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800319 * @param mockGetLaunchStack Whether to mock {@link RootActivityContainer#getLaunchStack} for
Riddle Hsub70b36d2018-09-11 21:20:02 +0800320 * always launching to the testing stack. Set to false when allowing
321 * the activity can be launched to any stack that is decided by real
322 * implementation.
323 * @return A {@link ActivityStarter} with default setup.
324 */
325 private ActivityStarter prepareStarter(@Intent.Flags int launchFlags,
326 boolean mockGetLaunchStack) {
Bryce Leead5b8322018-03-08 14:28:52 -0800327 // always allow test to start activity.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800328 doReturn(true).when(mSupervisor).checkStartAnyActivityPermission(
Bryce Leead5b8322018-03-08 14:28:52 -0800329 any(), any(), any(), anyInt(), anyInt(), anyInt(), any(),
Winson Chungc9804e72018-05-15 11:01:44 -0700330 anyBoolean(), anyBoolean(), any(), any(), any());
Bryce Leead5b8322018-03-08 14:28:52 -0800331
Riddle Hsuff9e8282019-04-24 23:55:11 +0800332 // Use factory that only returns spy task.
333 mockTaskRecordFactory();
Bryce Leead5b8322018-03-08 14:28:52 -0800334
Riddle Hsub70b36d2018-09-11 21:20:02 +0800335 if (mockGetLaunchStack) {
Riddle Hsuff9e8282019-04-24 23:55:11 +0800336 // Instrument the stack and task used.
337 final ActivityStack stack = mRootActivityContainer.getDefaultDisplay().createStack(
338 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
339
Riddle Hsub70b36d2018-09-11 21:20:02 +0800340 // Direct starter to use spy stack.
Wale Ogunwaled32da472018-11-16 07:19:28 -0800341 doReturn(stack).when(mRootActivityContainer)
Riddle Hsub70b36d2018-09-11 21:20:02 +0800342 .getLaunchStack(any(), any(), any(), anyBoolean());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800343 doReturn(stack).when(mRootActivityContainer)
lumarkaf0629a2019-09-14 19:25:21 +0800344 .getLaunchStack(any(), any(), any(), anyBoolean(), any(), anyInt(), anyInt());
Riddle Hsub70b36d2018-09-11 21:20:02 +0800345 }
Bryce Leead5b8322018-03-08 14:28:52 -0800346
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700347 // Set up mock package manager internal and make sure no unmocked methods are called
348 PackageManagerInternal mockPackageManager = mock(PackageManagerInternal.class,
349 invocation -> {
350 throw new RuntimeException("Not stubbed");
351 });
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700352 doReturn(mockPackageManager).when(mService).getPackageManagerInternalLocked();
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700353
354 // Never review permissions
355 doReturn(false).when(mockPackageManager).isPermissionsReviewRequired(any(), anyInt());
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700356 doNothing().when(mockPackageManager).grantEphemeralAccess(
357 anyInt(), any(), anyInt(), anyInt());
Philip P. Moltmann6c644e62018-07-18 15:41:24 -0700358
Bryce Lee32e09ef2018-03-19 15:29:49 -0700359 final Intent intent = new Intent();
360 intent.addFlags(launchFlags);
361 intent.setComponent(ActivityBuilder.getDefaultComponent());
362
363 final ActivityInfo info = new ActivityInfo();
364
365 info.applicationInfo = new ApplicationInfo();
366 info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
367
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700368 return new ActivityStarter(mController, mService,
Bryce Lee32e09ef2018-03-19 15:29:49 -0700369 mService.mStackSupervisor, mock(ActivityStartInterceptor.class))
370 .setIntent(intent)
371 .setActivityInfo(info);
Bryce Leead5b8322018-03-08 14:28:52 -0800372 }
373
374 /**
375 * Ensures that values specified at launch time are passed to {@link LaunchParamsModifier}
376 * when we are laying out a new task.
377 */
378 @Test
379 public void testCreateTaskLayout() {
380 // modifier for validating passed values.
381 final LaunchParamsModifier modifier = mock(LaunchParamsModifier.class);
382 mService.mStackSupervisor.getLaunchParamsController().registerModifier(modifier);
383
384 // add custom values to activity info to make unique.
385 final ActivityInfo info = new ActivityInfo();
386 final Rect launchBounds = new Rect(0, 0, 20, 30);
Bryce Leead5b8322018-03-08 14:28:52 -0800387
388 final WindowLayout windowLayout =
389 new WindowLayout(10, .5f, 20, 1.0f, Gravity.NO_GRAVITY, 1, 1);
390
391 info.windowLayout = windowLayout;
392 info.applicationInfo = new ApplicationInfo();
393 info.applicationInfo.packageName = ActivityBuilder.getDefaultComponent().getPackageName();
394
395 // create starter.
Bryce Lee32e09ef2018-03-19 15:29:49 -0700396 final ActivityStarter optionStarter = prepareStarter(0 /* launchFlags */);
Bryce Leead5b8322018-03-08 14:28:52 -0800397
398 final ActivityOptions options = ActivityOptions.makeBasic();
399 options.setLaunchBounds(launchBounds);
400
401 // run starter.
402 optionStarter
Bryce Leead5b8322018-03-08 14:28:52 -0800403 .setReason("testCreateTaskLayout")
404 .setActivityInfo(info)
405 .setActivityOptions(new SafeActivityOptions(options))
406 .execute();
407
Louis Chang6fb1e842018-12-03 16:07:50 +0800408 // verify that values are passed to the modifier. Values are passed thrice -- two for
Garfield Tan706dbcb2018-10-15 11:33:02 -0700409 // setting initial state, another when task is created.
Louis Chang6fb1e842018-12-03 16:07:50 +0800410 verify(modifier, times(3)).onCalculate(any(), eq(windowLayout), any(), any(), eq(options),
411 anyInt(), any(), any());
Bryce Leead5b8322018-03-08 14:28:52 -0800412 }
Bryce Lee32e09ef2018-03-19 15:29:49 -0700413
414 /**
415 * This test ensures that if the intent is being delivered to a
416 */
417 @Test
418 public void testSplitScreenDeliverToTop() {
419 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
420
421 final ActivityRecord focusActivity = new ActivityBuilder(mService)
422 .setCreateTask(true)
423 .build();
424
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800425 focusActivity.getActivityStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700426
427 final ActivityRecord reusableActivity = new ActivityBuilder(mService)
428 .setCreateTask(true)
429 .build();
430
431 // Create reusable activity after entering split-screen so that it is the top secondary
432 // stack.
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800433 reusableActivity.getActivityStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700434
435 // Set focus back to primary.
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800436 final ActivityStack focusStack = focusActivity.getActivityStack();
Andrii Kulian6a6c4f12018-07-16 21:23:33 -0700437 focusStack.moveToFront("testSplitScreenDeliverToTop");
Bryce Lee32e09ef2018-03-19 15:29:49 -0700438
Wale Ogunwaled32da472018-11-16 07:19:28 -0800439 doReturn(reusableActivity).when(mRootActivityContainer).findTask(any(), anyInt());
Bryce Lee32e09ef2018-03-19 15:29:49 -0700440
441 final int result = starter.setReason("testSplitScreenDeliverToTop").execute();
442
443 // Ensure result is delivering intent to top.
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900444 assertEquals(START_DELIVERED_TO_TOP, result);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700445 }
446
447 /**
448 * This test ensures that if the intent is being delivered to a split-screen unfocused task
449 * reports it is brought to front instead of delivering to top.
450 */
451 @Test
452 public void testSplitScreenTaskToFront() {
453 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
454
455 // Create reusable activity here first. Setting the windowing mode of the primary stack
456 // will move the existing standard full screen stack to secondary, putting this one on the
457 // bottom.
458 final ActivityRecord reusableActivity = new ActivityBuilder(mService)
459 .setCreateTask(true)
460 .build();
461
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800462 reusableActivity.getActivityStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700463
464 final ActivityRecord focusActivity = new ActivityBuilder(mService)
465 .setCreateTask(true)
466 .build();
467
468 // Enter split-screen. Primary stack should have focus.
Wale Ogunwale8b19de92018-11-29 19:58:26 -0800469 focusActivity.getActivityStack().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700470
Wale Ogunwaled32da472018-11-16 07:19:28 -0800471 doReturn(reusableActivity).when(mRootActivityContainer).findTask(any(), anyInt());
Bryce Lee32e09ef2018-03-19 15:29:49 -0700472
473 final int result = starter.setReason("testSplitScreenMoveToFront").execute();
474
475 // Ensure result is moving task to front.
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900476 assertEquals(START_TASK_TO_FRONT, result);
Bryce Lee32e09ef2018-03-19 15:29:49 -0700477 }
Bryce Lee2b8e0372018-04-05 17:01:37 -0700478
479 /**
480 * Tests activity is cleaned up properly in a task mode violation.
481 */
482 @Test
483 public void testTaskModeViolation() {
Wale Ogunwaled32da472018-11-16 07:19:28 -0800484 final ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
Andrii Kulian6a6c4f12018-07-16 21:23:33 -0700485 ((TestActivityDisplay) display).removeAllTasks();
Bryce Lee2b8e0372018-04-05 17:01:37 -0700486 assertNoTasks(display);
487
488 final ActivityStarter starter = prepareStarter(0);
489
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -0700490 final LockTaskController lockTaskController = mService.getLockTaskController();
Bryce Lee2b8e0372018-04-05 17:01:37 -0700491 doReturn(true).when(lockTaskController).isLockTaskModeViolation(any());
492
493 final int result = starter.setReason("testTaskModeViolation").execute();
494
495 assertEquals(START_RETURN_LOCK_TASK_MODE_VIOLATION, result);
496 assertNoTasks(display);
497 }
498
499 private void assertNoTasks(ActivityDisplay display) {
500 for (int i = display.getChildCount() - 1; i >= 0; --i) {
501 final ActivityStack stack = display.getChildAt(i);
Tadashi G. Takaoka74ccec22018-10-23 11:07:13 +0900502 assertThat(stack.getAllTasks()).isEmpty();
Bryce Lee2b8e0372018-04-05 17:01:37 -0700503 }
504 }
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100505
506 /**
507 * This test ensures that activity starts are not being logged when the logging is disabled.
508 */
509 @Test
510 public void testActivityStartsLogging_noLoggingWhenDisabled() {
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700511 doReturn(false).when(mService).isActivityStartsLoggingEnabled();
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100512 doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
513
514 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK);
515 starter.setReason("testActivityStartsLogging_noLoggingWhenDisabled").execute();
516
517 // verify logging wasn't done
Michal Karpinski4fd5b842019-01-28 15:13:32 +0000518 verify(mActivityMetricsLogger, never()).logAbortedBgActivityStart(any(), any(), anyInt(),
519 any(), anyInt(), anyBoolean(), anyInt(), anyInt(), anyBoolean(), anyBoolean());
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100520 }
521
522 /**
523 * This test ensures that activity starts are being logged when the logging is enabled.
524 */
525 @Test
526 public void testActivityStartsLogging_logsWhenEnabled() {
527 // note: conveniently this package doesn't have any activity visible
Wale Ogunwale342fbe92018-10-09 08:44:10 -0700528 doReturn(true).when(mService).isActivityStartsLoggingEnabled();
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100529 doReturn(mActivityMetricsLogger).when(mService.mStackSupervisor).getActivityMetricsLogger();
530
531 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
532 .setCallingUid(FAKE_CALLING_UID)
533 .setRealCallingUid(FAKE_REAL_CALLING_UID)
534 .setCallingPackage(FAKE_CALLING_PACKAGE)
535 .setOriginatingPendingIntent(null);
536
537 starter.setReason("testActivityStartsLogging_logsWhenEnabled").execute();
538
539 // verify the above activity start was logged
Michal Karpinski4fd5b842019-01-28 15:13:32 +0000540 verify(mActivityMetricsLogger, times(1)).logAbortedBgActivityStart(any(), any(),
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100541 eq(FAKE_CALLING_UID), eq(FAKE_CALLING_PACKAGE), anyInt(), anyBoolean(),
Michal Karpinski4fd5b842019-01-28 15:13:32 +0000542 eq(FAKE_REAL_CALLING_UID), anyInt(), anyBoolean(), eq(false));
Michal Karpinski201bc0c2018-07-20 15:32:00 +0100543 }
Riddle Hsub70b36d2018-09-11 21:20:02 +0800544
545 /**
Michal Karpinski8596ded2018-11-14 14:43:48 +0000546 * This test ensures that unsupported usecases aren't aborted when background starts are
547 * allowed.
548 */
549 @Test
550 public void testBackgroundActivityStartsAllowed_noStartsAborted() {
551 doReturn(true).when(mService).isBackgroundActivityStartsEnabled();
552
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000553 runAndVerifyBackgroundActivityStartsSubtest("allowed_noStartsAborted", false,
554 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
555 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100556 false, false, false, false, false);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000557 }
558
559 /**
560 * This test ensures that unsupported usecases are aborted when background starts are
561 * disallowed.
562 */
563 @Test
564 public void testBackgroundActivityStartsDisallowed_unsupportedStartsAborted() {
565 doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
566
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000567 runAndVerifyBackgroundActivityStartsSubtest(
568 "disallowed_unsupportedUsecase_aborted", true,
569 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
570 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100571 false, false, false, false, false);
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100572 runAndVerifyBackgroundActivityStartsSubtest(
573 "disallowed_callingUidProcessStateTop_aborted", true,
574 UNIMPORTANT_UID, false, PROCESS_STATE_TOP,
575 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100576 false, false, false, false, false);
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100577 runAndVerifyBackgroundActivityStartsSubtest(
578 "disallowed_realCallingUidProcessStateTop_aborted", true,
579 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
580 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP,
Alan Stokes9e245762019-05-21 14:54:28 +0100581 false, false, false, false, false);
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100582 runAndVerifyBackgroundActivityStartsSubtest(
583 "disallowed_hasForegroundActivities_aborted", true,
584 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
585 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100586 true, false, false, false, false);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000587 }
588
589 /**
590 * This test ensures that supported usecases aren't aborted when background starts are
591 * disallowed.
Alan Stokeseea8d3e2019-04-10 17:37:25 +0100592 * The scenarios each have only one condition that makes them supported.
Michal Karpinski8596ded2018-11-14 14:43:48 +0000593 */
594 @Test
595 public void testBackgroundActivityStartsDisallowed_supportedStartsNotAborted() {
596 doReturn(false).when(mService).isBackgroundActivityStartsEnabled();
597
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000598 runAndVerifyBackgroundActivityStartsSubtest("disallowed_rootUid_notAborted", false,
599 Process.ROOT_UID, false, PROCESS_STATE_TOP + 1,
600 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100601 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000602 runAndVerifyBackgroundActivityStartsSubtest("disallowed_systemUid_notAborted", false,
603 Process.SYSTEM_UID, false, PROCESS_STATE_TOP + 1,
604 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100605 false, false, false, false, false);
Michal Karpinskib416f472019-01-24 14:34:28 +0000606 runAndVerifyBackgroundActivityStartsSubtest("disallowed_nfcUid_notAborted", false,
607 Process.NFC_UID, false, PROCESS_STATE_TOP + 1,
608 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100609 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000610 runAndVerifyBackgroundActivityStartsSubtest(
611 "disallowed_callingUidHasVisibleWindow_notAborted", false,
612 UNIMPORTANT_UID, true, PROCESS_STATE_TOP + 1,
613 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100614 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000615 runAndVerifyBackgroundActivityStartsSubtest(
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000616 "disallowed_realCallingUidHasVisibleWindow_notAborted", false,
617 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
618 UNIMPORTANT_UID2, true, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100619 false, false, false, false, false);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000620 runAndVerifyBackgroundActivityStartsSubtest(
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000621 "disallowed_callerIsRecents_notAborted", false,
622 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
623 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100624 false, true, false, false, false);
Michal Karpinskiac116df2018-12-10 17:51:42 +0000625 runAndVerifyBackgroundActivityStartsSubtest(
626 "disallowed_callerIsWhitelisted_notAborted", false,
627 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
628 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100629 false, false, true, false, false);
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000630 runAndVerifyBackgroundActivityStartsSubtest(
631 "disallowed_callerIsInstrumentingWithBackgroundActivityStartPrivileges_notAborted",
632 false,
633 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
634 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100635 false, false, false, true, false);
Michal Karpinski302dcec2019-02-01 11:48:25 +0000636 runAndVerifyBackgroundActivityStartsSubtest(
Michal Karpinski4026cae2019-02-12 11:51:47 +0000637 "disallowed_callingPackageNameIsDeviceOwner_notAborted", false,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000638 UNIMPORTANT_UID, false, PROCESS_STATE_TOP + 1,
639 UNIMPORTANT_UID2, false, PROCESS_STATE_TOP + 1,
Alan Stokes9e245762019-05-21 14:54:28 +0100640 false, false, false, false, true);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000641 }
642
643 private void runAndVerifyBackgroundActivityStartsSubtest(String name, boolean shouldHaveAborted,
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000644 int callingUid, boolean callingUidHasVisibleWindow, int callingUidProcState,
645 int realCallingUid, boolean realCallingUidHasVisibleWindow, int realCallingUidProcState,
Michal Karpinskiac116df2018-12-10 17:51:42 +0000646 boolean hasForegroundActivities, boolean callerIsRecents,
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000647 boolean callerIsTempWhitelisted,
Michal Karpinski302dcec2019-02-01 11:48:25 +0000648 boolean callerIsInstrumentingWithBackgroundActivityStartPrivileges,
Alan Stokes9e245762019-05-21 14:54:28 +0100649 boolean isCallingUidDeviceOwner) {
Michal Karpinski8596ded2018-11-14 14:43:48 +0000650 // window visibility
Michal Karpinskia606a292019-01-12 17:29:52 +0000651 doReturn(callingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
652 .isAnyNonToastWindowVisibleForUid(callingUid);
653 doReturn(realCallingUidHasVisibleWindow).when(mService.mWindowManager.mRoot)
654 .isAnyNonToastWindowVisibleForUid(realCallingUid);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000655 // process importance
Riddle Hsua0536432019-02-16 00:38:59 +0800656 doReturn(callingUidProcState).when(mService).getUidState(callingUid);
657 doReturn(realCallingUidProcState).when(mService).getUidState(realCallingUid);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000658 // foreground activities
659 final IApplicationThread caller = mock(IApplicationThread.class);
660 final ApplicationInfo ai = new ApplicationInfo();
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000661 ai.uid = callingUid;
Michal Karpinski8596ded2018-11-14 14:43:48 +0000662 final WindowProcessController callerApp =
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000663 new WindowProcessController(mService, ai, null, callingUid, -1, null, null);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000664 callerApp.setHasForegroundActivities(hasForegroundActivities);
665 doReturn(callerApp).when(mService).getProcessController(caller);
Michal Karpinski82bb5902018-11-28 15:52:52 +0000666 // caller is recents
667 RecentTasks recentTasks = mock(RecentTasks.class);
668 mService.mStackSupervisor.setRecentTasks(recentTasks);
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000669 doReturn(callerIsRecents).when(recentTasks).isCallerRecents(callingUid);
Michal Karpinskiac116df2018-12-10 17:51:42 +0000670 // caller is temp whitelisted
671 callerApp.setAllowBackgroundActivityStarts(callerIsTempWhitelisted);
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000672 // caller is instrumenting with background activity starts privileges
Michal Karpinski4bc56492019-01-31 12:07:33 +0000673 callerApp.setInstrumenting(callerIsInstrumentingWithBackgroundActivityStartPrivileges,
Michal Karpinskidaef80f2019-01-29 16:50:51 +0000674 callerIsInstrumentingWithBackgroundActivityStartPrivileges);
Ricky Wai96f5c352019-04-10 18:40:17 +0100675 // callingUid is the device owner
676 doReturn(isCallingUidDeviceOwner).when(mService).isDeviceOwner(callingUid);
Michal Karpinski8596ded2018-11-14 14:43:48 +0000677
678 final ActivityOptions options = spy(ActivityOptions.makeBasic());
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000679 ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK)
Michal Karpinski666631b2019-02-26 16:59:11 +0000680 .setCallingPackage("com.whatever.dude")
Michal Karpinski0ad4e2f2018-11-29 16:22:34 +0000681 .setCaller(caller)
682 .setCallingUid(callingUid)
683 .setRealCallingUid(realCallingUid)
684 .setActivityOptions(new SafeActivityOptions(options));
Michal Karpinski8596ded2018-11-14 14:43:48 +0000685
686 final int result = starter.setReason("testBackgroundActivityStarts_" + name).execute();
687
688 assertEquals(ActivityStarter.getExternalResult(
689 shouldHaveAborted ? START_ABORTED : START_SUCCESS), result);
690 verify(options, times(shouldHaveAborted ? 1 : 0)).abort();
691 }
692
693 /**
Riddle Hsu273e9992019-04-29 22:40:59 +0800694 * This test ensures that {@link ActivityStarter#setTargetStackAndMoveToFrontIfNeeded} will
695 * move the existing task to front if the current focused stack doesn't have running task.
696 */
697 @Test
698 public void testBringTaskToFrontWhenFocusedStackIsFinising() {
699 // Put 2 tasks in the same stack (simulate the behavior of home stack).
700 final ActivityRecord activity = new ActivityBuilder(mService)
701 .setCreateTask(true).build();
702 new ActivityBuilder(mService)
703 .setStack(activity.getActivityStack())
704 .setCreateTask(true).build();
705
706 // Create a top finishing activity.
707 final ActivityRecord finishingTopActivity = new ActivityBuilder(mService)
708 .setCreateTask(true).build();
709 finishingTopActivity.getActivityStack().moveToFront("finishingTopActivity");
710
711 assertEquals(finishingTopActivity, mRootActivityContainer.topRunningActivity());
712 finishingTopActivity.finishing = true;
713
714 // Launch the bottom task of the target stack.
715 prepareStarter(FLAG_ACTIVITY_NEW_TASK, false /* mockGetLaunchStack */)
716 .setReason("testBringTaskToFrontWhenTopStackIsFinising")
717 .setIntent(activity.intent)
718 .execute();
719 // The hierarchies of the activity should move to front.
720 assertEquals(activity, mRootActivityContainer.topRunningActivity());
721 }
722
723 /**
Riddle Hsub70b36d2018-09-11 21:20:02 +0800724 * This test ensures that when starting an existing single task activity on secondary display
725 * which is not the top focused display, it should deliver new intent to the activity and not
726 * create a new stack.
727 */
728 @Test
729 public void testDeliverIntentToTopActivityOfNonTopDisplay() {
730 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
731 false /* mockGetLaunchStack */);
732
733 // Create a secondary display at bottom.
Riddle Hsufd4a0502018-10-16 01:05:16 +0800734 final TestActivityDisplay secondaryDisplay = spy(createNewActivityDisplay());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800735 mRootActivityContainer.addChild(secondaryDisplay, POSITION_BOTTOM);
Riddle Hsub70b36d2018-09-11 21:20:02 +0800736 final ActivityStack stack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
737 ACTIVITY_TYPE_STANDARD, true /* onTop */);
738
739 // Create an activity record on the top of secondary display.
Riddle Hsufd4a0502018-10-16 01:05:16 +0800740 final ActivityRecord topActivityOnSecondaryDisplay = createSingleTaskActivityOn(stack);
Riddle Hsub70b36d2018-09-11 21:20:02 +0800741
742 // Put an activity on default display as the top focused activity.
743 new ActivityBuilder(mService).setCreateTask(true).build();
744
745 // Start activity with the same intent as {@code topActivityOnSecondaryDisplay}
746 // on secondary display.
747 final ActivityOptions options = ActivityOptions.makeBasic()
748 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
749 final int result = starter.setReason("testDeliverIntentToTopActivityOfNonTopDisplay")
750 .setIntent(topActivityOnSecondaryDisplay.intent)
751 .setActivityOptions(options.toBundle())
752 .execute();
753
754 // Ensure result is delivering intent to top.
755 assertEquals(START_DELIVERED_TO_TOP, result);
756
757 // Ensure secondary display only creates one stack.
758 verify(secondaryDisplay, times(1)).createStack(anyInt(), anyInt(), anyBoolean());
759 }
760
761 /**
Riddle Hsufd4a0502018-10-16 01:05:16 +0800762 * This test ensures that when starting an existing non-top single task activity on secondary
763 * display which is the top focused display, it should bring the task to front without creating
764 * unused stack.
765 */
766 @Test
767 public void testBringTaskToFrontOnSecondaryDisplay() {
768 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
769 false /* mockGetLaunchStack */);
770
771 // Create a secondary display with an activity.
772 final TestActivityDisplay secondaryDisplay = spy(createNewActivityDisplay());
Wale Ogunwaled32da472018-11-16 07:19:28 -0800773 mRootActivityContainer.addChild(secondaryDisplay, POSITION_TOP);
Riddle Hsufd4a0502018-10-16 01:05:16 +0800774 final ActivityRecord singleTaskActivity = createSingleTaskActivityOn(
775 secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
776 ACTIVITY_TYPE_STANDARD, false /* onTop */));
777
778 // Create another activity on top of the secondary display.
779 final ActivityStack topStack = secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN,
780 ACTIVITY_TYPE_STANDARD, true /* onTop */);
781 final TaskRecord topTask = new TaskBuilder(mSupervisor).setStack(topStack).build();
782 new ActivityBuilder(mService).setTask(topTask).build();
783
784 // Start activity with the same intent as {@code singleTaskActivity} on secondary display.
785 final ActivityOptions options = ActivityOptions.makeBasic()
786 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
787 final int result = starter.setReason("testBringTaskToFrontOnSecondaryDisplay")
788 .setIntent(singleTaskActivity.intent)
789 .setActivityOptions(options.toBundle())
790 .execute();
791
792 // Ensure result is moving existing task to front.
793 assertEquals(START_TASK_TO_FRONT, result);
794
795 // Ensure secondary display only creates two stacks.
796 verify(secondaryDisplay, times(2)).createStack(anyInt(), anyInt(), anyBoolean());
797 }
798
799 private ActivityRecord createSingleTaskActivityOn(ActivityStack stack) {
800 final ComponentName componentName = ComponentName.createRelative(
801 DEFAULT_COMPONENT_PACKAGE_NAME,
802 DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
803 final TaskRecord taskRecord = new TaskBuilder(mSupervisor)
804 .setComponent(componentName)
805 .setStack(stack)
806 .build();
807 return new ActivityBuilder(mService)
808 .setComponent(componentName)
809 .setLaunchMode(LAUNCH_SINGLE_TASK)
810 .setTask(taskRecord)
811 .build();
812 }
813
814 /**
Riddle Hsub70b36d2018-09-11 21:20:02 +0800815 * This test ensures that a reused top activity in the top focused stack is able to be
816 * reparented to another display.
817 */
818 @Test
819 public void testReparentTopFocusedActivityToSecondaryDisplay() {
820 final ActivityStarter starter = prepareStarter(FLAG_ACTIVITY_NEW_TASK,
821 false /* mockGetLaunchStack */);
822
823 // Create a secondary display at bottom.
824 final TestActivityDisplay secondaryDisplay = addNewActivityDisplayAt(POSITION_BOTTOM);
825 secondaryDisplay.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD,
826 true /* onTop */);
827
828 // Put an activity on default display as the top focused activity.
829 final ActivityRecord topActivity = new ActivityBuilder(mService)
830 .setCreateTask(true)
831 .setLaunchMode(LAUNCH_SINGLE_TASK)
832 .build();
833
834 // Start activity with the same intent as {@code topActivity} on secondary display.
835 final ActivityOptions options = ActivityOptions.makeBasic()
836 .setLaunchDisplayId(secondaryDisplay.mDisplayId);
837 starter.setReason("testReparentTopFocusedActivityToSecondaryDisplay")
838 .setIntent(topActivity.intent)
839 .setActivityOptions(options.toBundle())
840 .execute();
841
842 // Ensure the activity is moved to secondary display.
843 assertEquals(secondaryDisplay, topActivity.getDisplay());
844 }
Winson Chunge219ae12019-07-18 13:43:23 -0700845
846 /**
847 * This test ensures that starting an activity with the freeze-task-list activity option will
848 * actually freeze the task list
849 */
850 @Test
851 public void testFreezeTaskListActivityOption() {
852 RecentTasks recentTasks = mock(RecentTasks.class);
853 mService.mStackSupervisor.setRecentTasks(recentTasks);
854 doReturn(true).when(recentTasks).isCallerRecents(anyInt());
855
856 final ActivityStarter starter = prepareStarter(0 /* flags */);
857 final ActivityOptions options = ActivityOptions.makeBasic();
858 options.setFreezeRecentTasksReordering();
859
860 starter.setReason("testFreezeTaskListActivityOption")
861 .setActivityOptions(new SafeActivityOptions(options))
862 .execute();
863
864 verify(recentTasks, times(1)).setFreezeTaskListReordering();
865 verify(recentTasks, times(0)).resetFreezeTaskListReorderingOnTimeout();
866 }
867
868 /**
869 * This test ensures that if we froze the task list as a part of starting an activity that fails
870 * to start, that we also reset the task list.
871 */
872 @Test
873 public void testFreezeTaskListActivityOptionFailedStart_expectResetFreezeTaskList() {
874 RecentTasks recentTasks = mock(RecentTasks.class);
875 mService.mStackSupervisor.setRecentTasks(recentTasks);
876 doReturn(true).when(recentTasks).isCallerRecents(anyInt());
877
878 final ActivityStarter starter = prepareStarter(0 /* flags */);
879 final ActivityOptions options = ActivityOptions.makeBasic();
880 options.setFreezeRecentTasksReordering();
881
882 starter.setReason("testFreezeTaskListActivityOptionFailedStart")
883 .setActivityOptions(new SafeActivityOptions(options))
884 .execute();
885
886 // Simulate a failed start
887 starter.postStartActivityProcessing(null, START_ABORTED, null);
888
889 verify(recentTasks, times(1)).setFreezeTaskListReordering();
890 verify(recentTasks, times(1)).resetFreezeTaskListReorderingOnTimeout();
891 }
Wale Ogunwale44f036f2017-09-29 05:09:09 -0700892}