blob: 734761fd8048bac32dd0e37a47a3c806c8e2f8c4 [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;
Igor Murashkincb76aac2018-11-02 14:46:28 -070021
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090022import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
23import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
24import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
Yunfan Chend552c162019-02-08 16:51:28 +090025
Igor Murashkinc0b47e42018-11-07 15:54:18 -080026import static com.google.common.truth.Truth.assertWithMessage;
Tadashi G. Takaokaa7a66952018-11-16 15:04:21 +090027
Igor Murashkincb76aac2018-11-02 14:46:28 -070028import static org.mockito.ArgumentMatchers.anyInt;
Yan Wang9eac5ec2019-09-30 15:42:18 -070029import static org.mockito.ArgumentMatchers.anyLong;
Igor Murashkinc0b47e42018-11-07 15:54:18 -080030import static org.mockito.ArgumentMatchers.argThat;
Igor Murashkincb76aac2018-11-02 14:46:28 -070031import static org.mockito.ArgumentMatchers.eq;
Igor Murashkinc0b47e42018-11-07 15:54:18 -080032import static org.mockito.Mockito.timeout;
Igor Murashkincb76aac2018-11-02 14:46:28 -070033
34import android.content.Intent;
35import android.os.SystemClock;
36import android.platform.test.annotations.Presubmit;
37import android.util.SparseIntArray;
38
Igor Murashkincb76aac2018-11-02 14:46:28 -070039import androidx.test.filters.SmallTest;
Igor Murashkincb76aac2018-11-02 14:46:28 -070040
Igor Murashkinc0b47e42018-11-07 15:54:18 -080041import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
42
43import org.junit.After;
Igor Murashkincb76aac2018-11-02 14:46:28 -070044import org.junit.Before;
45import org.junit.Test;
Igor Murashkinc0b47e42018-11-07 15:54:18 -080046import org.mockito.ArgumentMatcher;
47
48import java.util.Arrays;
Riddle Hsu7a2fec52019-09-04 00:12:08 +080049import java.util.concurrent.TimeUnit;
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
Riddle Hsu1c5d72e2019-10-09 20:54:26 +080064 private ActivityRecord mTrampolineActivity;
65 private ActivityRecord mTopActivity;
Igor Murashkincb76aac2018-11-02 14:46:28 -070066
67 @Before
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070068 public void setUpAMLO() {
Igor Murashkincb76aac2018-11-02 14:46:28 -070069 mLaunchObserver = mock(ActivityMetricsLaunchObserver.class);
70
Igor Murashkinc0b47e42018-11-07 15:54:18 -080071 // ActivityStackSupervisor always creates its own instance of ActivityMetricsLogger.
72 mActivityMetricsLogger = mSupervisor.getActivityMetricsLogger();
73
74 mLaunchObserverRegistry = mActivityMetricsLogger.getLaunchObserverRegistry();
75 mLaunchObserverRegistry.registerLaunchObserver(mLaunchObserver);
Igor Murashkincb76aac2018-11-02 14:46:28 -070076
77 // Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful.
78 // This seems to be the easiest way to create an ActivityRecord.
Riddle Hsu1c5d72e2019-10-09 20:54:26 +080079 mTrampolineActivity = new ActivityBuilder(mService).setCreateTask(true).build();
80 mTopActivity = new ActivityBuilder(mService)
Louis Changcdec0802019-11-11 11:45:07 +080081 .setTask(mTrampolineActivity.getTask())
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070082 .build();
Igor Murashkincb76aac2018-11-02 14:46:28 -070083 }
84
Igor Murashkinc0b47e42018-11-07 15:54:18 -080085 @After
Wale Ogunwale8a1860a2019-06-05 08:57:19 -070086 public void tearDownAMLO() {
Igor Murashkinc0b47e42018-11-07 15:54:18 -080087 if (mLaunchObserverRegistry != null) { // Don't NPE if setUp failed.
88 mLaunchObserverRegistry.unregisterLaunchObserver(mLaunchObserver);
89 }
90 }
91
92 static class ActivityRecordMatcher implements ArgumentMatcher</*@ActivityRecordProto*/ byte[]> {
93 private final @ActivityRecordProto byte[] mExpected;
94
95 public ActivityRecordMatcher(ActivityRecord activityRecord) {
96 mExpected = activityRecordToProto(activityRecord);
97 }
98
99 public boolean matches(@ActivityRecordProto byte[] actual) {
100 return Arrays.equals(mExpected, actual);
101 }
102 }
103
104 static @ActivityRecordProto byte[] activityRecordToProto(ActivityRecord record) {
105 return ActivityMetricsLogger.convertActivityRecordToProto(record);
106 }
107
108 static @ActivityRecordProto byte[] eqProto(ActivityRecord record) {
109 return argThat(new ActivityRecordMatcher(record));
110 }
111
112 static <T> T verifyAsync(T mock) {
113 // AMLO callbacks happen on a separate thread than AML calls, so we need to use a timeout.
Riddle Hsu7a2fec52019-09-04 00:12:08 +0800114 return verify(mock, timeout(TimeUnit.SECONDS.toMillis(5)));
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800115 }
116
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800117 private void onIntentStarted() {
Igor Murashkincb76aac2018-11-02 14:46:28 -0700118 Intent intent = new Intent("action 1");
119
120 mActivityMetricsLogger.notifyActivityLaunching(intent);
121
Yan Wangd47f90b2019-10-03 19:17:15 -0700122 verifyAsync(mLaunchObserver).onIntentStarted(eq(intent), anyLong());
Igor Murashkincb76aac2018-11-02 14:46:28 -0700123 verifyNoMoreInteractions(mLaunchObserver);
124 }
125
126 @Test
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800127 public void testOnIntentFailed() {
128 onIntentStarted();
Igor Murashkincb76aac2018-11-02 14:46:28 -0700129
130 // Bringing an intent that's already running 'to front' is not considered
131 // as an ACTIVITY_LAUNCHED state transition.
132 mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800133 null /* launchedActivity */);
Igor Murashkincb76aac2018-11-02 14:46:28 -0700134
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800135 verifyAsync(mLaunchObserver).onIntentFailed();
Igor Murashkincb76aac2018-11-02 14:46:28 -0700136 verifyNoMoreInteractions(mLaunchObserver);
137 }
138
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800139 private void onActivityLaunched() {
140 onIntentStarted();
Igor Murashkincb76aac2018-11-02 14:46:28 -0700141
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800142 mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity);
Igor Murashkincb76aac2018-11-02 14:46:28 -0700143
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800144 verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt());
Igor Murashkincb76aac2018-11-02 14:46:28 -0700145 verifyNoMoreInteractions(mLaunchObserver);
146 }
147
148 @Test
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800149 public void testOnActivityLaunchFinished() {
150 onActivityLaunched();
Igor Murashkincb76aac2018-11-02 14:46:28 -0700151
Riddle Hsu1063b512019-10-22 21:12:23 +0800152 notifyTransitionStarting();
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800153 notifyWindowsDrawn(mTopActivity);
Igor Murashkincb76aac2018-11-02 14:46:28 -0700154
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800155 verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
Yan Wang9eac5ec2019-09-30 15:42:18 -0700156 verifyNoMoreInteractions(mLaunchObserver);
157 }
158
159 @Test
Riddle Hsu1063b512019-10-22 21:12:23 +0800160 public void testOnActivityLaunchCancelled_hasDrawn() {
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800161 onActivityLaunched();
Igor Murashkincb76aac2018-11-02 14:46:28 -0700162
Issei Suzuki1669ea42019-11-06 14:20:59 +0100163 mTopActivity.mVisibleRequested = mTopActivity.mDrawn = true;
Igor Murashkincb76aac2018-11-02 14:46:28 -0700164
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800165 // Cannot time already-visible activities.
166 mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
167
168 verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity));
169 verifyNoMoreInteractions(mLaunchObserver);
170 }
171
172 @Test
Riddle Hsu1063b512019-10-22 21:12:23 +0800173 public void testOnActivityLaunchCancelled_finishedBeforeDrawn() {
Issei Suzuki1669ea42019-11-06 14:20:59 +0100174 mTopActivity.mVisibleRequested = mTopActivity.mDrawn = true;
Riddle Hsu1063b512019-10-22 21:12:23 +0800175
176 // Suppress resume when creating the record because we want to notify logger manually.
177 mSupervisor.beginDeferResume();
178 // Create an activity with different process that meets process switch.
179 final ActivityRecord noDrawnActivity = new ActivityBuilder(mService)
Louis Changcdec0802019-11-11 11:45:07 +0800180 .setTask(mTopActivity.getTask())
Riddle Hsu1063b512019-10-22 21:12:23 +0800181 .setProcessName("other")
182 .build();
183 mSupervisor.readyToResume();
184
185 mActivityMetricsLogger.notifyActivityLaunching(noDrawnActivity.intent);
186 mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, noDrawnActivity);
187
188 noDrawnActivity.destroyIfPossible("test");
189 mActivityMetricsLogger.notifyVisibilityChanged(noDrawnActivity);
190
191 verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(noDrawnActivity));
192 }
193
194 @Test
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800195 public void testOnReportFullyDrawn() {
196 onActivityLaunched();
197
Riddle Hsuc1f8f9c2019-10-25 16:54:33 +0800198 // The activity reports fully drawn before windows drawn, then the fully drawn event will
199 // be pending (see {@link WindowingModeTransitionInfo#pendingFullyDrawn}).
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800200 mActivityMetricsLogger.logAppTransitionReportedDrawn(mTopActivity, false);
Riddle Hsuc1f8f9c2019-10-25 16:54:33 +0800201 notifyTransitionStarting();
202 // The pending fully drawn event should send when the actual windows drawn event occurs.
203 notifyWindowsDrawn(mTopActivity);
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800204
205 verifyAsync(mLaunchObserver).onReportFullyDrawn(eqProto(mTopActivity), anyLong());
Riddle Hsuc1f8f9c2019-10-25 16:54:33 +0800206 verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800207 verifyNoMoreInteractions(mLaunchObserver);
208 }
209
210 private void onActivityLaunchedTrampoline() {
211 onIntentStarted();
212
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800213 mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTrampolineActivity);
Igor Murashkincb76aac2018-11-02 14:46:28 -0700214
Riddle Hsu1063b512019-10-22 21:12:23 +0800215 verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTrampolineActivity), anyInt());
216
217 // A second, distinct, activity launch is coalesced into the current app launch sequence.
218 mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity);
219
Igor Murashkincb76aac2018-11-02 14:46:28 -0700220 verifyNoMoreInteractions(mLaunchObserver);
221 }
222
Riddle Hsu1063b512019-10-22 21:12:23 +0800223 private void notifyTransitionStarting() {
224 mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
225 SystemClock.elapsedRealtimeNanos());
226 }
227
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800228 private void notifyWindowsDrawn(ActivityRecord r) {
229 mActivityMetricsLogger.notifyWindowsDrawn(r.getWindowingMode(),
230 SystemClock.elapsedRealtimeNanos());
Igor Murashkincb76aac2018-11-02 14:46:28 -0700231 }
232
233 @Test
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800234 public void testOnActivityLaunchFinishedTrampoline() {
235 onActivityLaunchedTrampoline();
Igor Murashkincb76aac2018-11-02 14:46:28 -0700236
Riddle Hsu1063b512019-10-22 21:12:23 +0800237 notifyTransitionStarting();
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800238 notifyWindowsDrawn(mTrampolineActivity);
Igor Murashkincb76aac2018-11-02 14:46:28 -0700239
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800240 notifyWindowsDrawn(mTopActivity);
241
Riddle Hsu1063b512019-10-22 21:12:23 +0800242 verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800243 verifyNoMoreInteractions(mLaunchObserver);
Igor Murashkincb76aac2018-11-02 14:46:28 -0700244 }
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800245
246 @Test
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800247 public void testOnActivityLaunchCancelledTrampoline() {
248 onActivityLaunchedTrampoline();
249
Riddle Hsu1063b512019-10-22 21:12:23 +0800250 mTopActivity.mDrawn = true;
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800251
252 // Cannot time already-visible activities.
Riddle Hsu1063b512019-10-22 21:12:23 +0800253 mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800254
Riddle Hsu1063b512019-10-22 21:12:23 +0800255 verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity));
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800256 verifyNoMoreInteractions(mLaunchObserver);
257 }
258
259 @Test
260 public void testActivityRecordProtoIsNotTooBig() {
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800261 // The ActivityRecordProto must not be too big, otherwise converting it at runtime
262 // will become prohibitively expensive.
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800263 assertWithMessage("mTopActivity: %s", mTopActivity)
264 .that(activityRecordToProto(mTopActivity).length)
265 .isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800266
Riddle Hsu1c5d72e2019-10-09 20:54:26 +0800267 assertWithMessage("mTrampolineActivity: %s", mTrampolineActivity)
268 .that(activityRecordToProto(mTrampolineActivity).length)
269 .isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800270 }
Igor Murashkincb76aac2018-11-02 14:46:28 -0700271}