blob: 977dd8e5951edc9c6bb71db799feb840a35010c7 [file] [log] [blame]
Igor Murashkincb76aac2018-11-02 14:46:28 -07001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
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
14 * limitations under the License
15 */
16
17package com.android.server.wm;
18
19import static android.app.ActivityManager.START_SUCCESS;
20import static android.app.ActivityManager.START_TASK_TO_FRONT;
21import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
22import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
23
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090024import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
25import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
26import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
Yunfan Chend552c162019-02-08 16:51:28 +090027
Igor Murashkinc0b47e42018-11-07 15:54:18 -080028import static com.google.common.truth.Truth.assertWithMessage;
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090029
Igor Murashkincb76aac2018-11-02 14:46:28 -070030import static org.mockito.ArgumentMatchers.anyInt;
Igor Murashkinc0b47e42018-11-07 15:54:18 -080031import static org.mockito.ArgumentMatchers.argThat;
Igor Murashkincb76aac2018-11-02 14:46:28 -070032import static org.mockito.ArgumentMatchers.eq;
Igor Murashkinc0b47e42018-11-07 15:54:18 -080033import static org.mockito.Mockito.timeout;
Igor Murashkincb76aac2018-11-02 14:46:28 -070034
35import android.content.Intent;
36import android.os.SystemClock;
37import android.platform.test.annotations.Presubmit;
38import android.util.SparseIntArray;
39
Igor Murashkincb76aac2018-11-02 14:46:28 -070040import androidx.test.filters.SmallTest;
Igor Murashkincb76aac2018-11-02 14:46:28 -070041
Igor Murashkinc0b47e42018-11-07 15:54:18 -080042import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
43
44import org.junit.After;
Igor Murashkincb76aac2018-11-02 14:46:28 -070045import org.junit.Before;
46import org.junit.Test;
Igor Murashkinc0b47e42018-11-07 15:54:18 -080047import org.mockito.ArgumentMatcher;
48
49import java.util.Arrays;
Igor Murashkincb76aac2018-11-02 14:46:28 -070050
51/**
52 * Tests for the {@link ActivityMetricsLaunchObserver} class.
53 *
54 * Build/Install/Run:
55 * atest WmTests:ActivityMetricsLaunchObserverTests
56 */
57@SmallTest
58@Presubmit
Igor Murashkincb76aac2018-11-02 14:46:28 -070059public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
60 private ActivityMetricsLogger mActivityMetricsLogger;
61 private ActivityMetricsLaunchObserver mLaunchObserver;
Igor Murashkinc0b47e42018-11-07 15:54:18 -080062 private ActivityMetricsLaunchObserverRegistry mLaunchObserverRegistry;
Igor Murashkincb76aac2018-11-02 14:46:28 -070063
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070064 private ActivityStack mStack;
Igor Murashkincb76aac2018-11-02 14:46:28 -070065 private TaskRecord mTask;
66 private ActivityRecord mActivityRecord;
67 private ActivityRecord mActivityRecordTrampoline;
68
69 @Before
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070070 public void setUpAMLO() {
Igor Murashkincb76aac2018-11-02 14:46:28 -070071 mLaunchObserver = mock(ActivityMetricsLaunchObserver.class);
72
Igor Murashkinc0b47e42018-11-07 15:54:18 -080073 // ActivityStackSupervisor always creates its own instance of ActivityMetricsLogger.
74 mActivityMetricsLogger = mSupervisor.getActivityMetricsLogger();
75
76 mLaunchObserverRegistry = mActivityMetricsLogger.getLaunchObserverRegistry();
77 mLaunchObserverRegistry.registerLaunchObserver(mLaunchObserver);
Igor Murashkincb76aac2018-11-02 14:46:28 -070078
79 // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful.
80 // This seems to be the easiest way to create an ActivityRecord.
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070081 mStack = new StackBuilder(mRootActivityContainer)
82 .setActivityType(ACTIVITY_TYPE_STANDARD)
83 .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
84 .setOnTop(true)
85 .setCreateActivity(true)
86 .build();
87 mTask = mStack.topTask();
88 mActivityRecord = mTask.getTopActivity();
Igor Murashkincb76aac2018-11-02 14:46:28 -070089 mActivityRecordTrampoline = new ActivityBuilder(mService).setTask(mTask).build();
90 }
91
Igor Murashkinc0b47e42018-11-07 15:54:18 -080092 @After
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070093 public void tearDownAMLO() {
Igor Murashkinc0b47e42018-11-07 15:54:18 -080094 if (mLaunchObserverRegistry != null) { // Don't NPE if setUp failed.
95 mLaunchObserverRegistry.unregisterLaunchObserver(mLaunchObserver);
96 }
97 }
98
99 static class ActivityRecordMatcher implements ArgumentMatcher</*@ActivityRecordProto*/ byte[]> {
100 private final @ActivityRecordProto byte[] mExpected;
101
102 public ActivityRecordMatcher(ActivityRecord activityRecord) {
103 mExpected = activityRecordToProto(activityRecord);
104 }
105
106 public boolean matches(@ActivityRecordProto byte[] actual) {
107 return Arrays.equals(mExpected, actual);
108 }
109 }
110
111 static @ActivityRecordProto byte[] activityRecordToProto(ActivityRecord record) {
112 return ActivityMetricsLogger.convertActivityRecordToProto(record);
113 }
114
115 static @ActivityRecordProto byte[] eqProto(ActivityRecord record) {
116 return argThat(new ActivityRecordMatcher(record));
117 }
118
119 static <T> T verifyAsync(T mock) {
120 // AMLO callbacks happen on a separate thread than AML calls, so we need to use a timeout.
121 return verify(mock, timeout(100));
122 }
123
Igor Murashkincb76aac2018-11-02 14:46:28 -0700124 @Test
125 public void testOnIntentStarted() throws Exception {
126 Intent intent = new Intent("action 1");
127
128 mActivityMetricsLogger.notifyActivityLaunching(intent);
129
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800130 verifyAsync(mLaunchObserver).onIntentStarted(eq(intent));
Igor Murashkincb76aac2018-11-02 14:46:28 -0700131 verifyNoMoreInteractions(mLaunchObserver);
132 }
133
134 @Test
135 public void testOnIntentFailed() throws Exception {
136 testOnIntentStarted();
137
138 ActivityRecord activityRecord = null;
139
140 // Bringing an intent that's already running 'to front' is not considered
141 // as an ACTIVITY_LAUNCHED state transition.
142 mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
143 activityRecord);
144
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800145 verifyAsync(mLaunchObserver).onIntentFailed();
Igor Murashkincb76aac2018-11-02 14:46:28 -0700146 verifyNoMoreInteractions(mLaunchObserver);
147 }
148
149 @Test
150 public void testOnActivityLaunched() throws Exception {
151 testOnIntentStarted();
152
153 mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
154 mActivityRecord);
155
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800156 verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mActivityRecord), anyInt());
Igor Murashkincb76aac2018-11-02 14:46:28 -0700157 verifyNoMoreInteractions(mLaunchObserver);
158 }
159
160 @Test
161 public void testOnActivityLaunchFinished() throws Exception {
162 testOnActivityLaunched();
163
164 mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
165 SystemClock.uptimeMillis());
166
167 mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecord.getWindowingMode(),
168 SystemClock.uptimeMillis());
169
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800170 verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecord));
Igor Murashkincb76aac2018-11-02 14:46:28 -0700171 verifyNoMoreInteractions(mLaunchObserver);
172 }
173
174 @Test
175 public void testOnActivityLaunchCancelled() throws Exception {
176 testOnActivityLaunched();
177
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800178 mActivityRecord.mDrawn = true;
Igor Murashkincb76aac2018-11-02 14:46:28 -0700179
180 // Cannot time already-visible activities.
181 mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mActivityRecord);
182
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800183 verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mActivityRecord));
Igor Murashkincb76aac2018-11-02 14:46:28 -0700184 verifyNoMoreInteractions(mLaunchObserver);
185 }
186
187 @Test
188 public void testOnActivityLaunchedTrampoline() throws Exception {
189 testOnIntentStarted();
190
191 mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
192 mActivityRecord);
193
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800194 verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mActivityRecord), anyInt());
Igor Murashkincb76aac2018-11-02 14:46:28 -0700195
196 // A second, distinct, activity launch is coalesced into the the current app launch sequence
197 mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
198 mActivityRecordTrampoline);
199
200 verifyNoMoreInteractions(mLaunchObserver);
201 }
202
203 @Test
204 public void testOnActivityLaunchFinishedTrampoline() throws Exception {
205 testOnActivityLaunchedTrampoline();
206
207 mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
208 SystemClock.uptimeMillis());
209
210 mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecordTrampoline.getWindowingMode(),
211 SystemClock.uptimeMillis());
212
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800213 verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecordTrampoline));
Igor Murashkincb76aac2018-11-02 14:46:28 -0700214 verifyNoMoreInteractions(mLaunchObserver);
215 }
216
217 @Test
218 public void testOnActivityLaunchCancelledTrampoline() throws Exception {
219 testOnActivityLaunchedTrampoline();
220
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800221 mActivityRecordTrampoline.mDrawn = true;
Igor Murashkincb76aac2018-11-02 14:46:28 -0700222
223 // Cannot time already-visible activities.
224 mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
225 mActivityRecordTrampoline);
226
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800227 verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mActivityRecordTrampoline));
Igor Murashkincb76aac2018-11-02 14:46:28 -0700228 verifyNoMoreInteractions(mLaunchObserver);
229 }
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800230
231 @Test
232 public void testActivityRecordProtoIsNotTooBig() throws Exception {
233 // The ActivityRecordProto must not be too big, otherwise converting it at runtime
234 // will become prohibitively expensive.
235 assertWithMessage("mActivityRecord: %s", mActivityRecord).
236 that(activityRecordToProto(mActivityRecord).length).
237 isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
238
239 assertWithMessage("mActivityRecordTrampoline: %s", mActivityRecordTrampoline).
240 that(activityRecordToProto(mActivityRecordTrampoline).length).
241 isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
242 }
Igor Murashkincb76aac2018-11-02 14:46:28 -0700243}