blob: 23bae8881aa11c12cd4f34f1da11f5d19863bcfa [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
64 private TestActivityStack mStack;
65 private TaskRecord mTask;
66 private ActivityRecord mActivityRecord;
67 private ActivityRecord mActivityRecordTrampoline;
68
69 @Before
70 public void setUpAMLO() throws Exception {
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 Ogunwaled32da472018-11-16 07:19:28 -080081 mStack = mRootActivityContainer.getDefaultDisplay().createStack(
Igor Murashkincb76aac2018-11-02 14:46:28 -070082 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
83 mTask = new TaskBuilder(mSupervisor).setStack(mStack).build();
84 mActivityRecord = new ActivityBuilder(mService).setTask(mTask).build();
85 mActivityRecordTrampoline = new ActivityBuilder(mService).setTask(mTask).build();
86 }
87
Igor Murashkinc0b47e42018-11-07 15:54:18 -080088 @After
89 public void tearDownAMLO() throws Exception {
90 if (mLaunchObserverRegistry != null) { // Don't NPE if setUp failed.
91 mLaunchObserverRegistry.unregisterLaunchObserver(mLaunchObserver);
92 }
93 }
94
95 static class ActivityRecordMatcher implements ArgumentMatcher</*@ActivityRecordProto*/ byte[]> {
96 private final @ActivityRecordProto byte[] mExpected;
97
98 public ActivityRecordMatcher(ActivityRecord activityRecord) {
99 mExpected = activityRecordToProto(activityRecord);
100 }
101
102 public boolean matches(@ActivityRecordProto byte[] actual) {
103 return Arrays.equals(mExpected, actual);
104 }
105 }
106
107 static @ActivityRecordProto byte[] activityRecordToProto(ActivityRecord record) {
108 return ActivityMetricsLogger.convertActivityRecordToProto(record);
109 }
110
111 static @ActivityRecordProto byte[] eqProto(ActivityRecord record) {
112 return argThat(new ActivityRecordMatcher(record));
113 }
114
115 static <T> T verifyAsync(T mock) {
116 // AMLO callbacks happen on a separate thread than AML calls, so we need to use a timeout.
117 return verify(mock, timeout(100));
118 }
119
Igor Murashkincb76aac2018-11-02 14:46:28 -0700120 @Test
121 public void testOnIntentStarted() throws Exception {
122 Intent intent = new Intent("action 1");
123
124 mActivityMetricsLogger.notifyActivityLaunching(intent);
125
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800126 verifyAsync(mLaunchObserver).onIntentStarted(eq(intent));
Igor Murashkincb76aac2018-11-02 14:46:28 -0700127 verifyNoMoreInteractions(mLaunchObserver);
128 }
129
130 @Test
131 public void testOnIntentFailed() throws Exception {
132 testOnIntentStarted();
133
134 ActivityRecord activityRecord = null;
135
136 // Bringing an intent that's already running 'to front' is not considered
137 // as an ACTIVITY_LAUNCHED state transition.
138 mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
139 activityRecord);
140
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800141 verifyAsync(mLaunchObserver).onIntentFailed();
Igor Murashkincb76aac2018-11-02 14:46:28 -0700142 verifyNoMoreInteractions(mLaunchObserver);
143 }
144
145 @Test
146 public void testOnActivityLaunched() throws Exception {
147 testOnIntentStarted();
148
149 mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
150 mActivityRecord);
151
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800152 verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mActivityRecord), anyInt());
Igor Murashkincb76aac2018-11-02 14:46:28 -0700153 verifyNoMoreInteractions(mLaunchObserver);
154 }
155
156 @Test
157 public void testOnActivityLaunchFinished() throws Exception {
158 testOnActivityLaunched();
159
160 mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
161 SystemClock.uptimeMillis());
162
163 mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecord.getWindowingMode(),
164 SystemClock.uptimeMillis());
165
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800166 verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecord));
Igor Murashkincb76aac2018-11-02 14:46:28 -0700167 verifyNoMoreInteractions(mLaunchObserver);
168 }
169
170 @Test
171 public void testOnActivityLaunchCancelled() throws Exception {
172 testOnActivityLaunched();
173
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800174 mActivityRecord.mDrawn = true;
Igor Murashkincb76aac2018-11-02 14:46:28 -0700175
176 // Cannot time already-visible activities.
177 mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mActivityRecord);
178
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800179 verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mActivityRecord));
Igor Murashkincb76aac2018-11-02 14:46:28 -0700180 verifyNoMoreInteractions(mLaunchObserver);
181 }
182
183 @Test
184 public void testOnActivityLaunchedTrampoline() throws Exception {
185 testOnIntentStarted();
186
187 mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
188 mActivityRecord);
189
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800190 verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mActivityRecord), anyInt());
Igor Murashkincb76aac2018-11-02 14:46:28 -0700191
192 // A second, distinct, activity launch is coalesced into the the current app launch sequence
193 mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS,
194 mActivityRecordTrampoline);
195
196 verifyNoMoreInteractions(mLaunchObserver);
197 }
198
199 @Test
200 public void testOnActivityLaunchFinishedTrampoline() throws Exception {
201 testOnActivityLaunchedTrampoline();
202
203 mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
204 SystemClock.uptimeMillis());
205
206 mActivityMetricsLogger.notifyWindowsDrawn(mActivityRecordTrampoline.getWindowingMode(),
207 SystemClock.uptimeMillis());
208
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800209 verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mActivityRecordTrampoline));
Igor Murashkincb76aac2018-11-02 14:46:28 -0700210 verifyNoMoreInteractions(mLaunchObserver);
211 }
212
213 @Test
214 public void testOnActivityLaunchCancelledTrampoline() throws Exception {
215 testOnActivityLaunchedTrampoline();
216
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800217 mActivityRecordTrampoline.mDrawn = true;
Igor Murashkincb76aac2018-11-02 14:46:28 -0700218
219 // Cannot time already-visible activities.
220 mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
221 mActivityRecordTrampoline);
222
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800223 verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mActivityRecordTrampoline));
Igor Murashkincb76aac2018-11-02 14:46:28 -0700224 verifyNoMoreInteractions(mLaunchObserver);
225 }
Igor Murashkinc0b47e42018-11-07 15:54:18 -0800226
227 @Test
228 public void testActivityRecordProtoIsNotTooBig() throws Exception {
229 // The ActivityRecordProto must not be too big, otherwise converting it at runtime
230 // will become prohibitively expensive.
231 assertWithMessage("mActivityRecord: %s", mActivityRecord).
232 that(activityRecordToProto(mActivityRecord).length).
233 isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
234
235 assertWithMessage("mActivityRecordTrampoline: %s", mActivityRecordTrampoline).
236 that(activityRecordToProto(mActivityRecordTrampoline).length).
237 isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
238 }
Igor Murashkincb76aac2018-11-02 14:46:28 -0700239}