blob: eb022b78d9587ae1473cd04078ec209399bacd94 [file] [log] [blame]
Filip Gruszczynski77d94482015-12-11 13:59:52 -08001package com.android.server.am;
2
Jorim Jaggi3878ca32017-02-02 17:13:05 -08003import static android.app.ActivityManager.START_SUCCESS;
4import static android.app.ActivityManager.START_TASK_TO_FRONT;
Jorim Jaggi3878ca32017-02-02 17:13:05 -08005import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
Jorim Jaggi3878ca32017-02-02 17:13:05 -08006import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT;
Wale Ogunwale926aade2017-08-29 11:24:37 -07007import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
Bryce Lee6c605092017-10-12 11:14:49 -07008import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
Wale Ogunwale3382ab12017-07-27 08:55:03 -07009import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
10import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
Wale Ogunwale926aade2017-08-29 11:24:37 -070011import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
12import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080013import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION;
Jorim Jaggi515dd682017-05-05 15:05:07 +020014import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_BIND_APPLICATION_DELAY_MS;
Todd Kennedy50d946c12017-03-17 13:55:38 -070015import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CALLING_PACKAGE_NAME;
Jorim Jaggi172e99f2017-10-20 14:33:18 +020016import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CANCELLED;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080017import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS;
18import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS;
Todd Kennedy50d946c12017-03-17 13:55:38 -070019import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_IS_EPHEMERAL;
Jorim Jaggi4d27b842017-08-17 17:22:26 +020020import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_PROCESS_RUNNING;
21import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN;
22import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN_MS;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080023import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_STARTING_WINDOW_DELAY_MS;
24import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS;
Jorim Jaggicdfc04e2017-04-28 19:06:24 +020025import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CLASS_NAME;
Todd Kennedy50d946c12017-03-17 13:55:38 -070026import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INSTANT_APP_LAUNCH_TOKEN;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080027import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_COLD_LAUNCH;
28import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_HOT_LAUNCH;
Jorim Jaggi4d27b842017-08-17 17:22:26 +020029import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE;
30import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080031import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
Jorim Jaggi172e99f2017-10-20 14:33:18 +020032import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_METRICS;
Jorim Jaggif9704102016-05-05 19:14:22 -070033import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
34import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
Filip Gruszczynski77d94482015-12-11 13:59:52 -080035
Filip Gruszczynski77d94482015-12-11 13:59:52 -080036import android.content.Context;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080037import android.metrics.LogMaker;
Jorim Jaggi172e99f2017-10-20 14:33:18 +020038import android.os.Handler;
39import android.os.Looper;
40import android.os.Message;
Filip Gruszczynski77d94482015-12-11 13:59:52 -080041import android.os.SystemClock;
Jorim Jaggi172e99f2017-10-20 14:33:18 +020042import android.util.Slog;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080043import android.util.SparseArray;
44import android.util.SparseIntArray;
Filip Gruszczynski77d94482015-12-11 13:59:52 -080045
46import com.android.internal.logging.MetricsLogger;
Jorim Jaggi172e99f2017-10-20 14:33:18 +020047import com.android.internal.os.SomeArgs;
Filip Gruszczynski77d94482015-12-11 13:59:52 -080048
Jorim Jaggi1e630c02016-05-16 12:13:13 -070049import java.util.ArrayList;
50
Filip Gruszczynski77d94482015-12-11 13:59:52 -080051/**
52 * Handles logging into Tron.
53 */
54class ActivityMetricsLogger {
Jorim Jaggif9704102016-05-05 19:14:22 -070055
56 private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityMetricsLogger" : TAG_AM;
57
Filip Gruszczynski77d94482015-12-11 13:59:52 -080058 // Window modes we are interested in logging. If we ever introduce a new type, we need to add
59 // a value here and increase the {@link #TRON_WINDOW_STATE_VARZ_STRINGS} array.
60 private static final int WINDOW_STATE_STANDARD = 0;
61 private static final int WINDOW_STATE_SIDE_BY_SIDE = 1;
62 private static final int WINDOW_STATE_FREEFORM = 2;
Winson Chung83471632016-12-13 11:02:12 -080063 private static final int WINDOW_STATE_ASSISTANT = 3;
Filip Gruszczynski77d94482015-12-11 13:59:52 -080064 private static final int WINDOW_STATE_INVALID = -1;
65
Jorim Jaggi275561a2016-02-23 10:11:02 -050066 private static final long INVALID_START_TIME = -1;
67
Jorim Jaggi172e99f2017-10-20 14:33:18 +020068 private static final int MSG_CHECK_VISIBILITY = 0;
69
Filip Gruszczynski77d94482015-12-11 13:59:52 -080070 // Preallocated strings we are sending to tron, so we don't have to allocate a new one every
71 // time we log.
72 private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = {
Winson Chung83471632016-12-13 11:02:12 -080073 "window_time_0", "window_time_1", "window_time_2", "window_time_3"};
Filip Gruszczynski77d94482015-12-11 13:59:52 -080074
75 private int mWindowState = WINDOW_STATE_STANDARD;
76 private long mLastLogTimeSecs;
77 private final ActivityStackSupervisor mSupervisor;
78 private final Context mContext;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080079 private final MetricsLogger mMetricsLogger = new MetricsLogger();
Filip Gruszczynski77d94482015-12-11 13:59:52 -080080
Jorim Jaggi275561a2016-02-23 10:11:02 -050081 private long mCurrentTransitionStartTime = INVALID_START_TIME;
Jorim Jaggi4d27b842017-08-17 17:22:26 +020082 private long mLastTransitionStartTime = INVALID_START_TIME;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080083
84 private int mCurrentTransitionDeviceUptime;
85 private int mCurrentTransitionDelayMs;
Jorim Jaggi275561a2016-02-23 10:11:02 -050086 private boolean mLoggedTransitionStarting;
87
Jorim Jaggi3878ca32017-02-02 17:13:05 -080088 private final SparseArray<StackTransitionInfo> mStackTransitionInfo = new SparseArray<>();
Jorim Jaggi4d27b842017-08-17 17:22:26 +020089 private final SparseArray<StackTransitionInfo> mLastStackTransitionInfo = new SparseArray<>();
Jorim Jaggi172e99f2017-10-20 14:33:18 +020090 private final H mHandler;
91 private final class H extends Handler {
92
93 public H(Looper looper) {
94 super(looper);
95 }
96
97 @Override
98 public void handleMessage(Message msg) {
99 switch (msg.what) {
100 case MSG_CHECK_VISIBILITY:
101 final SomeArgs args = (SomeArgs) msg.obj;
102 checkVisibility((TaskRecord) args.arg1, (ActivityRecord) args.arg2);
103 break;
104 }
105 }
106 };
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800107
108 private final class StackTransitionInfo {
109 private ActivityRecord launchedActivity;
110 private int startResult;
111 private boolean currentTransitionProcessRunning;
112 private int windowsDrawnDelayMs;
Jorim Jaggi515dd682017-05-05 15:05:07 +0200113 private int startingWindowDelayMs = -1;
114 private int bindApplicationDelayMs = -1;
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800115 private int reason = APP_TRANSITION_TIMEOUT;
116 private boolean loggedWindowsDrawn;
117 private boolean loggedStartingWindowDrawn;
118 }
119
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200120 ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context, Looper looper) {
Filip Gruszczynski77d94482015-12-11 13:59:52 -0800121 mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
122 mSupervisor = supervisor;
123 mContext = context;
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200124 mHandler = new H(looper);
Filip Gruszczynski77d94482015-12-11 13:59:52 -0800125 }
126
127 void logWindowState() {
128 final long now = SystemClock.elapsedRealtime() / 1000;
129 if (mWindowState != WINDOW_STATE_INVALID) {
130 // We log even if the window state hasn't changed, because the user might remain in
131 // home/fullscreen move forever and we would like to track this kind of behavior
132 // too.
133 MetricsLogger.count(mContext, TRON_WINDOW_STATE_VARZ_STRINGS[mWindowState],
134 (int) (now - mLastLogTimeSecs));
135 }
136 mLastLogTimeSecs = now;
137
Wale Ogunwale926aade2017-08-29 11:24:37 -0700138 mWindowState = WINDOW_STATE_INVALID;
139 ActivityStack stack = mSupervisor.getFocusedStack();
140 if (stack.isActivityTypeAssistant()) {
141 mWindowState = WINDOW_STATE_ASSISTANT;
Filip Gruszczynskicaae14e2015-12-16 14:40:04 -0800142 return;
Filip Gruszczynski77d94482015-12-11 13:59:52 -0800143 }
Wale Ogunwale926aade2017-08-29 11:24:37 -0700144
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700145 int windowingMode = stack.getWindowingMode();
146 if (windowingMode == WINDOWING_MODE_PINNED) {
Filip Gruszczynskicaae14e2015-12-16 14:40:04 -0800147 stack = mSupervisor.findStackBehind(stack);
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700148 windowingMode = stack.getWindowingMode();
Filip Gruszczynskicaae14e2015-12-16 14:40:04 -0800149 }
Wale Ogunwale926aade2017-08-29 11:24:37 -0700150 switch (windowingMode) {
151 case WINDOWING_MODE_FULLSCREEN:
152 mWindowState = WINDOW_STATE_STANDARD;
153 break;
154 case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
155 case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
156 mWindowState = WINDOW_STATE_SIDE_BY_SIDE;
157 break;
Bryce Lee6c605092017-10-12 11:14:49 -0700158 case WINDOWING_MODE_FREEFORM:
Wale Ogunwale926aade2017-08-29 11:24:37 -0700159 mWindowState = WINDOW_STATE_FREEFORM;
160 break;
161 default:
162 if (windowingMode != WINDOWING_MODE_UNDEFINED) {
163 throw new IllegalStateException("Unknown windowing mode for stack=" + stack
164 + " windowingMode=" + windowingMode);
165 }
Filip Gruszczynski77d94482015-12-11 13:59:52 -0800166 }
167 }
Jorim Jaggi275561a2016-02-23 10:11:02 -0500168
169 /**
170 * Notifies the tracker at the earliest possible point when we are starting to launch an
171 * activity.
172 */
173 void notifyActivityLaunching() {
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800174 if (!isAnyTransitionActive()) {
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200175 if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunching");
Alison Cichowlasb7f67ab2017-04-25 18:04:40 -0400176 mCurrentTransitionStartTime = SystemClock.uptimeMillis();
Jorim Jaggi4d27b842017-08-17 17:22:26 +0200177 mLastTransitionStartTime = mCurrentTransitionStartTime;
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800178 }
Jorim Jaggi275561a2016-02-23 10:11:02 -0500179 }
180
181 /**
Jorim Jaggi1e630c02016-05-16 12:13:13 -0700182 * Notifies the tracker that the activity is actually launching.
183 *
184 * @param resultCode one of the ActivityManager.START_* flags, indicating the result of the
185 * launch
186 * @param launchedActivity the activity that is being launched
187 */
188 void notifyActivityLaunched(int resultCode, ActivityRecord launchedActivity) {
189 final ProcessRecord processRecord = launchedActivity != null
190 ? mSupervisor.mService.mProcessNames.get(launchedActivity.processName,
191 launchedActivity.appInfo.uid)
192 : null;
193 final boolean processRunning = processRecord != null;
Jorim Jaggi1e630c02016-05-16 12:13:13 -0700194
195 // We consider this a "process switch" if the process of the activity that gets launched
196 // didn't have an activity that was in started state. In this case, we assume that lot
197 // of caches might be purged so the time until it produces the first frame is very
198 // interesting.
199 final boolean processSwitch = processRecord == null
200 || !hasStartedActivity(processRecord, launchedActivity);
201
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800202 notifyActivityLaunched(resultCode, launchedActivity, processRunning, processSwitch);
Jorim Jaggi1e630c02016-05-16 12:13:13 -0700203 }
204
205 private boolean hasStartedActivity(ProcessRecord record, ActivityRecord launchedActivity) {
206 final ArrayList<ActivityRecord> activities = record.activities;
207 for (int i = activities.size() - 1; i >= 0; i--) {
208 final ActivityRecord activity = activities.get(i);
209 if (launchedActivity == activity) {
210 continue;
211 }
212 if (!activity.stopped) {
213 return true;
214 }
215 }
216 return false;
217 }
218
219 /**
Jorim Jaggi275561a2016-02-23 10:11:02 -0500220 * Notifies the tracker the the activity is actually launching.
221 *
222 * @param resultCode one of the ActivityManager.START_* flags, indicating the result of the
223 * launch
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800224 * @param launchedActivity the activity being launched
Jorim Jaggi275561a2016-02-23 10:11:02 -0500225 * @param processRunning whether the process that will contains the activity is already running
Jorim Jaggibe67c902016-04-12 00:53:16 -0700226 * @param processSwitch whether the process that will contain the activity didn't have any
227 * activity that was stopped, i.e. the started activity is "switching"
228 * processes
Jorim Jaggi275561a2016-02-23 10:11:02 -0500229 */
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800230 private void notifyActivityLaunched(int resultCode, ActivityRecord launchedActivity,
Jorim Jaggibe67c902016-04-12 00:53:16 -0700231 boolean processRunning, boolean processSwitch) {
Jorim Jaggi275561a2016-02-23 10:11:02 -0500232
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200233 if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched"
234 + " resultCode=" + resultCode
235 + " launchedActivity=" + launchedActivity
236 + " processRunning=" + processRunning
237 + " processSwitch=" + processSwitch);
238
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800239 // If we are already in an existing transition, only update the activity name, but not the
240 // other attributes.
241 final int stackId = launchedActivity != null && launchedActivity.getStack() != null
242 ? launchedActivity.getStack().mStackId
243 : INVALID_STACK_ID;
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200244
245 if (mCurrentTransitionStartTime == INVALID_START_TIME) {
246 return;
247 }
248
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800249 final StackTransitionInfo info = mStackTransitionInfo.get(stackId);
250 if (launchedActivity != null && info != null) {
251 info.launchedActivity = launchedActivity;
Jorim Jaggi275561a2016-02-23 10:11:02 -0500252 return;
253 }
254
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800255 final boolean otherStacksLaunching = mStackTransitionInfo.size() > 0 && info == null;
256 if ((resultCode < 0 || launchedActivity == null || !processSwitch
257 || stackId == INVALID_STACK_ID) && !otherStacksLaunching) {
Alison Cichowlas803054d2016-12-13 14:38:01 -0500258
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800259 // Failed to launch or it was not a process switch, so we don't care about the timing.
260 reset(true /* abort */);
261 return;
262 } else if (otherStacksLaunching) {
263 // Don't log this stack but continue with the other stacks.
264 return;
265 }
266
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200267 if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched successful");
268
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800269 final StackTransitionInfo newInfo = new StackTransitionInfo();
270 newInfo.launchedActivity = launchedActivity;
271 newInfo.currentTransitionProcessRunning = processRunning;
272 newInfo.startResult = resultCode;
Jorim Jaggi4d27b842017-08-17 17:22:26 +0200273 mStackTransitionInfo.put(stackId, newInfo);
274 mLastStackTransitionInfo.put(stackId, newInfo);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800275 mCurrentTransitionDeviceUptime = (int) (SystemClock.uptimeMillis() / 1000);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500276 }
277
278 /**
279 * Notifies the tracker that all windows of the app have been drawn.
280 */
Sudheer Shankac766db02017-06-12 10:37:29 -0700281 void notifyWindowsDrawn(int stackId, long timestamp) {
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200282 if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn stackId=" + stackId);
283
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800284 final StackTransitionInfo info = mStackTransitionInfo.get(stackId);
285 if (info == null || info.loggedWindowsDrawn) {
Jorim Jaggi275561a2016-02-23 10:11:02 -0500286 return;
287 }
Sudheer Shankac766db02017-06-12 10:37:29 -0700288 info.windowsDrawnDelayMs = calculateDelay(timestamp);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800289 info.loggedWindowsDrawn = true;
290 if (allStacksWindowsDrawn() && mLoggedTransitionStarting) {
291 reset(false /* abort */);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500292 }
293 }
294
295 /**
296 * Notifies the tracker that the starting window was drawn.
297 */
Sudheer Shankac766db02017-06-12 10:37:29 -0700298 void notifyStartingWindowDrawn(int stackId, long timestamp) {
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800299 final StackTransitionInfo info = mStackTransitionInfo.get(stackId);
300 if (info == null || info.loggedStartingWindowDrawn) {
Jorim Jaggi275561a2016-02-23 10:11:02 -0500301 return;
302 }
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800303 info.loggedStartingWindowDrawn = true;
Sudheer Shankac766db02017-06-12 10:37:29 -0700304 info.startingWindowDelayMs = calculateDelay(timestamp);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500305 }
306
307 /**
308 * Notifies the tracker that the app transition is starting.
309 *
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800310 * @param stackIdReasons A map from stack id to a reason integer, which must be on of
311 * ActivityManagerInternal.APP_TRANSITION_* reasons.
Jorim Jaggi275561a2016-02-23 10:11:02 -0500312 */
Sudheer Shankac766db02017-06-12 10:37:29 -0700313 void notifyTransitionStarting(SparseIntArray stackIdReasons, long timestamp) {
Jorim Jaggid8a57772017-04-14 16:50:42 -0700314 if (!isAnyTransitionActive() || mLoggedTransitionStarting) {
Jorim Jaggi275561a2016-02-23 10:11:02 -0500315 return;
316 }
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200317 if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting");
Sudheer Shankac766db02017-06-12 10:37:29 -0700318 mCurrentTransitionDelayMs = calculateDelay(timestamp);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500319 mLoggedTransitionStarting = true;
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800320 for (int index = stackIdReasons.size() - 1; index >= 0; index--) {
321 final int stackId = stackIdReasons.keyAt(index);
322 final StackTransitionInfo info = mStackTransitionInfo.get(stackId);
323 if (info == null) {
324 continue;
325 }
326 info.reason = stackIdReasons.valueAt(index);
327 }
328 if (allStacksWindowsDrawn()) {
329 reset(false /* abort */);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500330 }
331 }
332
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200333 /**
334 * Notifies the tracker that the visibility of an app is changing.
335 *
336 * @param activityRecord the app that is changing its visibility
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200337 */
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200338 void notifyVisibilityChanged(ActivityRecord activityRecord) {
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200339 final StackTransitionInfo info = mStackTransitionInfo.get(activityRecord.getStackId());
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200340 if (info == null) {
341 return;
342 }
343 if (info.launchedActivity != activityRecord) {
344 return;
345 }
346 final TaskRecord t = activityRecord.getTask();
347 final SomeArgs args = SomeArgs.obtain();
348 args.arg1 = t;
349 args.arg2 = activityRecord;
350 mHandler.obtainMessage(MSG_CHECK_VISIBILITY, args).sendToTarget();
351 }
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200352
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200353 private void checkVisibility(TaskRecord t, ActivityRecord r) {
354 synchronized (mSupervisor.mService) {
355
356 final StackTransitionInfo info = mStackTransitionInfo.get(r.getStackId());
357
358 // If we have an active transition that's waiting on a certain activity that will be
359 // invisible now, we'll never get onWindowsDrawn, so abort the transition if necessary.
360 if (info != null && !t.isVisible()) {
361 if (DEBUG_METRICS) Slog.i(TAG, "notifyVisibilityChanged to invisible"
362 + " activity=" + r);
363 logAppTransitionCancel(info);
364 mStackTransitionInfo.remove(r.getStackId());
365 if (mStackTransitionInfo.size() == 0) {
366 reset(true /* abort */);
367 }
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200368 }
369 }
370 }
371
Jorim Jaggi515dd682017-05-05 15:05:07 +0200372 /**
373 * Notifies the tracker that we called immediately before we call bindApplication on the client.
374 *
375 * @param app The client into which we'll call bindApplication.
376 */
377 void notifyBindApplication(ProcessRecord app) {
378 for (int i = mStackTransitionInfo.size() - 1; i >= 0; i--) {
379 final StackTransitionInfo info = mStackTransitionInfo.valueAt(i);
380
381 // App isn't attached to record yet, so match with info.
382 if (info.launchedActivity.appInfo == app.info) {
383 info.bindApplicationDelayMs = calculateCurrentDelay();
384 }
385 }
386 }
387
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800388 private boolean allStacksWindowsDrawn() {
389 for (int index = mStackTransitionInfo.size() - 1; index >= 0; index--) {
390 if (!mStackTransitionInfo.valueAt(index).loggedWindowsDrawn) {
391 return false;
392 }
393 }
394 return true;
Jorim Jaggi275561a2016-02-23 10:11:02 -0500395 }
396
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800397 private boolean isAnyTransitionActive() {
398 return mCurrentTransitionStartTime != INVALID_START_TIME
399 && mStackTransitionInfo.size() > 0;
400 }
401
402 private void reset(boolean abort) {
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200403 if (DEBUG_METRICS) Slog.i(TAG, "reset abort=" + abort);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800404 if (!abort && isAnyTransitionActive()) {
405 logAppTransitionMultiEvents();
406 }
Jorim Jaggi275561a2016-02-23 10:11:02 -0500407 mCurrentTransitionStartTime = INVALID_START_TIME;
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800408 mCurrentTransitionDelayMs = -1;
Jorim Jaggi275561a2016-02-23 10:11:02 -0500409 mLoggedTransitionStarting = false;
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800410 mStackTransitionInfo.clear();
Jorim Jaggi275561a2016-02-23 10:11:02 -0500411 }
412
413 private int calculateCurrentDelay() {
414
415 // Shouldn't take more than 25 days to launch an app, so int is fine here.
Alison Cichowlasb7f67ab2017-04-25 18:04:40 -0400416 return (int) (SystemClock.uptimeMillis() - mCurrentTransitionStartTime);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500417 }
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800418
Sudheer Shankac766db02017-06-12 10:37:29 -0700419 private int calculateDelay(long timestamp) {
420 // Shouldn't take more than 25 days to launch an app, so int is fine here.
421 return (int) (timestamp - mCurrentTransitionStartTime);
422 }
423
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200424 private void logAppTransitionCancel(StackTransitionInfo info) {
425 final int type = getTransitionType(info);
426 if (type == -1) {
427 return;
428 }
429 final LogMaker builder = new LogMaker(APP_TRANSITION_CANCELLED);
430 builder.setPackageName(info.launchedActivity.packageName);
431 builder.setType(type);
432 builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name);
433 mMetricsLogger.write(builder);
434 }
435
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800436 private void logAppTransitionMultiEvents() {
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200437 if (DEBUG_METRICS) Slog.i(TAG, "logging transition events");
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800438 for (int index = mStackTransitionInfo.size() - 1; index >= 0; index--) {
439 final StackTransitionInfo info = mStackTransitionInfo.valueAt(index);
440 final int type = getTransitionType(info);
441 if (type == -1) {
442 return;
443 }
444 final LogMaker builder = new LogMaker(APP_TRANSITION);
445 builder.setPackageName(info.launchedActivity.packageName);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800446 builder.setType(type);
Jason Monk8c09ac72017-03-16 11:53:40 -0400447 builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name);
Todd Kennedy56279cb2017-04-17 14:53:49 -0700448 final boolean isInstantApp = info.launchedActivity.info.applicationInfo.isInstantApp();
Todd Kennedy7655b292017-08-18 15:05:01 -0700449 if (info.launchedActivity.launchedFromPackage != null) {
Todd Kennedy50d946c12017-03-17 13:55:38 -0700450 builder.addTaggedData(APP_TRANSITION_CALLING_PACKAGE_NAME,
451 info.launchedActivity.launchedFromPackage);
452 }
453 if (info.launchedActivity.info.launchToken != null) {
454 builder.addTaggedData(FIELD_INSTANT_APP_LAUNCH_TOKEN,
455 info.launchedActivity.info.launchToken);
Todd Kennedyb3b431302017-03-20 16:05:48 -0700456 info.launchedActivity.info.launchToken = null;
Todd Kennedy50d946c12017-03-17 13:55:38 -0700457 }
Todd Kennedy56279cb2017-04-17 14:53:49 -0700458 builder.addTaggedData(APP_TRANSITION_IS_EPHEMERAL, isInstantApp ? 1 : 0);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800459 builder.addTaggedData(APP_TRANSITION_DEVICE_UPTIME_SECONDS,
460 mCurrentTransitionDeviceUptime);
461 builder.addTaggedData(APP_TRANSITION_DELAY_MS, mCurrentTransitionDelayMs);
462 builder.setSubtype(info.reason);
463 if (info.startingWindowDelayMs != -1) {
464 builder.addTaggedData(APP_TRANSITION_STARTING_WINDOW_DELAY_MS,
465 info.startingWindowDelayMs);
466 }
Jorim Jaggi515dd682017-05-05 15:05:07 +0200467 if (info.bindApplicationDelayMs != -1) {
468 builder.addTaggedData(APP_TRANSITION_BIND_APPLICATION_DELAY_MS,
469 info.bindApplicationDelayMs);
470 }
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800471 builder.addTaggedData(APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS, info.windowsDrawnDelayMs);
472 mMetricsLogger.write(builder);
473 }
474 }
475
Jorim Jaggi4d27b842017-08-17 17:22:26 +0200476 void logAppTransitionReportedDrawn(ActivityRecord r, boolean restoredFromBundle) {
477 final StackTransitionInfo info = mLastStackTransitionInfo.get(r.getStackId());
478 if (info == null) {
479 return;
480 }
481 final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN);
482 builder.setPackageName(r.packageName);
483 builder.addTaggedData(FIELD_CLASS_NAME, r.info.name);
484 builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS,
485 SystemClock.uptimeMillis() - mLastTransitionStartTime);
486 builder.setType(restoredFromBundle
487 ? TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE
488 : TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE);
489 builder.addTaggedData(APP_TRANSITION_PROCESS_RUNNING,
490 info.currentTransitionProcessRunning ? 1 : 0);
491 mMetricsLogger.write(builder);
492 }
493
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800494 private int getTransitionType(StackTransitionInfo info) {
495 if (info.currentTransitionProcessRunning) {
496 if (info.startResult == START_SUCCESS) {
497 return TYPE_TRANSITION_WARM_LAUNCH;
498 } else if (info.startResult == START_TASK_TO_FRONT) {
499 return TYPE_TRANSITION_HOT_LAUNCH;
500 }
501 } else if (info.startResult == START_SUCCESS) {
502 return TYPE_TRANSITION_COLD_LAUNCH;
503 }
504 return -1;
505 }
Filip Gruszczynski77d94482015-12-11 13:59:52 -0800506}