blob: 64996dbfce5bdb3f18071cb6ca7b26ee646c7e88 [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;
Yan Wang9eac5ec2019-09-30 15:42:18 -070031import static org.mockito.ArgumentMatchers.anyLong;
Igor Murashkinc0b47e42018-11-07 15:54:18 -080032import static org.mockito.ArgumentMatchers.argThat;
Igor Murashkincb76aac2018-11-02 14:46:28 -070033import static org.mockito.ArgumentMatchers.eq;
Igor Murashkinc0b47e42018-11-07 15:54:18 -080034import static org.mockito.Mockito.timeout;
Igor Murashkincb76aac2018-11-02 14:46:28 -070035
36import android.content.Intent;
37import android.os.SystemClock;
38import android.platform.test.annotations.Presubmit;
39import android.util.SparseIntArray;
40
Igor Murashkincb76aac2018-11-02 14:46:28 -070041import androidx.test.filters.SmallTest;
Igor Murashkincb76aac2018-11-02 14:46:28 -070042
Igor Murashkinc0b47e42018-11-07 15:54:18 -080043import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
44
45import org.junit.After;
Igor Murashkincb76aac2018-11-02 14:46:28 -070046import org.junit.Before;
47import org.junit.Test;
Igor Murashkinc0b47e42018-11-07 15:54:18 -080048import org.mockito.ArgumentMatcher;
49
50import java.util.Arrays;
Riddle Hsu7a2fec52019-09-04 00:12:08 +080051import java.util.concurrent.TimeUnit;
Igor Murashkincb76aac2018-11-02 14:46:28 -070052
53/**
54 * Tests for the {@link ActivityMetricsLaunchObserver} class.
55 *
56 * Build/Install/Run:
57 * atest WmTests:ActivityMetricsLaunchObserverTests
58 */
59@SmallTest
60@Presubmit
Igor Murashkincb76aac2018-11-02 14:46:28 -070061public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
62 private ActivityMetricsLogger mActivityMetricsLogger;
63 private ActivityMetricsLaunchObserver mLaunchObserver;
Igor Murashkinc0b47e42018-11-07 15:54:18 -080064 private ActivityMetricsLaunchObserverRegistry mLaunchObserverRegistry;
Igor Murashkincb76aac2018-11-02 14:46:28 -070065
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070066 private ActivityStack mStack;
Igor Murashkincb76aac2018-11-02 14:46:28 -070067 private TaskRecord mTask;
68 private ActivityRecord mActivityRecord;
69 private ActivityRecord mActivityRecordTrampoline;
70
71 @Before
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070072 public void setUpAMLO() {
Igor Murashkincb76aac2018-11-02 14:46:28 -070073 mLaunchObserver = mock(ActivityMetricsLaunchObserver.class);
74
Igor Murashkinc0b47e42018-11-07 15:54:18 -080075 // ActivityStackSupervisor always creates its own instance of ActivityMetricsLogger.
76 mActivityMetricsLogger = mSupervisor.getActivityMetricsLogger();
77
78 mLaunchObserverRegistry = mActivityMetricsLogger.getLaunchObserverRegistry();
79 mLaunchObserverRegistry.registerLaunchObserver(mLaunchObserver);
Igor Murashkincb76aac2018-11-02 14:46:28 -070080
81 // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful.
82 // This seems to be the easiest way to create an ActivityRecord.
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070083 mStack = new StackBuilder(mRootActivityContainer)
84 .setActivityType(ACTIVITY_TYPE_STANDARD)
85 .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
86 .setOnTop(true)
87 .setCreateActivity(true)
88 .build();
89 mTask = mStack.topTask();
90 mActivityRecord = mTask.getTopActivity();
Igor Murashkincb76aac2018-11-02 14:46:28 -070091 mActivityRecordTrampoline = new ActivityBuilder(mService).setTask(mTask).build();
92 }
93
Igor Murashkinc0b47e42018-11-07 15:54:18 -080094 @After
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070095 public void tearDownAMLO() {
Igor Murashkinc0b47e42018-11-07 15:54:18 -080096 if (mLaunchObserverRegistry != null) { // Don't NPE if setUp failed.
97 mLaunchObserverRegistry.unregisterLaunchObserver(mLaunchObserver);
98 }
99 }
100
101 static class ActivityRecordMatcher implements ArgumentMatcher</*@ActivityRecordProto*/ byte[]> {
102 private final @ActivityRecordProto byte[] mExpected;
103
104 public ActivityRecordMatcher(ActivityRecord activityRecord) {
105 mExpected = activityRecordToProto(activityRecord);
106 }
107
108 public boolean matches(@ActivityRecordProto byte[] actual) {
109 return Arrays.equals(mExpected, actual);
110 }
111 }
112
113 static @ActivityRecordProto byte[] activityRecordToProto(ActivityRecord record) {
114 return ActivityMetricsLogger.convertActivityRecordToProto(record);
115 }
116
117 static @ActivityRecordProto byte[] eqProto(ActivityRecord record) {
118 return argThat(new ActivityRecordMatcher(record));
119 }
120
121 static <T> T verifyAsync(T mock) {
122 // AMLO callbacks happen on a separate thread than AML calls, so we need to use a timeout.
Riddle Hsu7a2fec52019-09-04 00:12:08 +0800123 return verify(mock, timeout(TimeUnit.SECONDS.toMillis(5)));
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800124 }
125
Igor Murashkincb76aac2018-11-02 14:46:28 -0700126 @Test
127 public void testOnIntentStarted() throws Exception {
128 Intent intent = new Intent("action 1");
129
130 mActivityMetricsLogger.notifyActivityLaunching(intent);
131
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800132 verifyAsync(mLaunchObserver).onIntentStarted(eq(intent));
Igor Murashkincb76aac2018-11-02 14:46:28 -0700133 verifyNoMoreInteractions(mLaunchObserver);
134 }
135
136 @Test
137 public void testOnIntentFailed() throws Exception {
138 testOnIntentStarted();
139
140 ActivityRecord activityRecord = null;
141
142 // Bringing an intent that's already running 'to front' is not considered
143 // as an ACTIVITY_LAUNCHED state transition.
144 mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
145 activityRecord);
146
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800147 verifyAsync(mLaunchObserver).onIntentFailed();
Igor Murashkincb76aac2018-11-02 14:46:28 -0700148 verifyNoMoreInteractions(mLaunchObserver);
149 }
150
151 @Test
152 public void testOnActivityLaunched() throws Exception {
153 testOnIntentStarted();
154
155 mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
156 mActivityRecord);
157
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800158 verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mActivityRecord), anyInt());
Igor Murashkincb76aac2018-11-02 14:46:28 -0700159 verifyNoMoreInteractions(mLaunchObserver);
160 }
161
162 @Test
163 public void testOnActivityLaunchFinished() throws Exception {
164 testOnActivityLaunched();
165
166 mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
167 SystemClock.uptimeMillis());
168
169 mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecord.getWindowingMode(),
170 SystemClock.uptimeMillis());
171
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800172 verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecord));
Igor Murashkincb76aac2018-11-02 14:46:28 -0700173 verifyNoMoreInteractions(mLaunchObserver);
174 }
175
176 @Test
177 public void testOnActivityLaunchCancelled() throws Exception {
178 testOnActivityLaunched();
179
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800180 mActivityRecord.mDrawn = true;
Igor Murashkincb76aac2018-11-02 14:46:28 -0700181
182 // Cannot time already-visible activities.
183 mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mActivityRecord);
184
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800185 verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mActivityRecord));
Igor Murashkincb76aac2018-11-02 14:46:28 -0700186 verifyNoMoreInteractions(mLaunchObserver);
187 }
188
189 @Test
Yan Wang9eac5ec2019-09-30 15:42:18 -0700190 public void testOnReportFullyDrawn() throws Exception {
191 testOnActivityLaunched();
192
193 mActivityMetricsLogger.logAppTransitionReportedDrawn(mActivityRecord, false);
194
195 verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mActivityRecord), anyLong());
196 verifyNoMoreInteractions(mLaunchObserver);
197 }
198
199 @Test
Igor Murashkincb76aac2018-11-02 14:46:28 -0700200 public void testOnActivityLaunchedTrampoline() throws Exception {
201 testOnIntentStarted();
202
203 mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
204 mActivityRecord);
205
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800206 verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mActivityRecord), anyInt());
Igor Murashkincb76aac2018-11-02 14:46:28 -0700207
208 // A second, distinct, activity launch is coalesced into the the current app launch sequence
209 mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
210 mActivityRecordTrampoline);
211
212 verifyNoMoreInteractions(mLaunchObserver);
213 }
214
215 @Test
216 public void testOnActivityLaunchFinishedTrampoline() throws Exception {
217 testOnActivityLaunchedTrampoline();
218
219 mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
220 SystemClock.uptimeMillis());
221
222 mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecordTrampoline.getWindowingMode(),
223 SystemClock.uptimeMillis());
224
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800225 verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecordTrampoline));
Igor Murashkincb76aac2018-11-02 14:46:28 -0700226 verifyNoMoreInteractions(mLaunchObserver);
227 }
228
229 @Test
230 public void testOnActivityLaunchCancelledTrampoline() throws Exception {
231 testOnActivityLaunchedTrampoline();
232
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800233 mActivityRecordTrampoline.mDrawn = true;
Igor Murashkincb76aac2018-11-02 14:46:28 -0700234
235 // Cannot time already-visible activities.
236 mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
237 mActivityRecordTrampoline);
238
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800239 verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mActivityRecordTrampoline));
Igor Murashkincb76aac2018-11-02 14:46:28 -0700240 verifyNoMoreInteractions(mLaunchObserver);
241 }
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800242
243 @Test
244 public void testActivityRecordProtoIsNotTooBig() throws Exception {
245 // The ActivityRecordProto must not be too big, otherwise converting it at runtime
246 // will become prohibitively expensive.
247 assertWithMessage("mActivityRecord: %s", mActivityRecord).
248 that(activityRecordToProto(mActivityRecord).length).
249 isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
250
251 assertWithMessage("mActivityRecordTrampoline: %s", mActivityRecordTrampoline).
252 that(activityRecordToProto(mActivityRecordTrampoline).length).
253 isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
254 }
Igor Murashkincb76aac2018-11-02 14:46:28 -0700255}