blob: 66f0592e36e50d4a00d4d49b374eb556ab1db5f7 [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;
Olivier Gaillardaed7f122017-12-12 14:26:22 +000045import android.util.StatsLog;
Filip Gruszczynski77d94482015-12-11 13:59:52 -080046
47import com.android.internal.logging.MetricsLogger;
Jorim Jaggi172e99f2017-10-20 14:33:18 +020048import com.android.internal.os.SomeArgs;
Filip Gruszczynski77d94482015-12-11 13:59:52 -080049
Jorim Jaggi1e630c02016-05-16 12:13:13 -070050import java.util.ArrayList;
51
Filip Gruszczynski77d94482015-12-11 13:59:52 -080052/**
53 * Handles logging into Tron.
54 */
55class ActivityMetricsLogger {
Jorim Jaggif9704102016-05-05 19:14:22 -070056
57 private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityMetricsLogger" : TAG_AM;
58
Filip Gruszczynski77d94482015-12-11 13:59:52 -080059 // Window modes we are interested in logging. If we ever introduce a new type, we need to add
60 // a value here and increase the {@link #TRON_WINDOW_STATE_VARZ_STRINGS} array.
61 private static final int WINDOW_STATE_STANDARD = 0;
62 private static final int WINDOW_STATE_SIDE_BY_SIDE = 1;
63 private static final int WINDOW_STATE_FREEFORM = 2;
Winson Chung83471632016-12-13 11:02:12 -080064 private static final int WINDOW_STATE_ASSISTANT = 3;
Filip Gruszczynski77d94482015-12-11 13:59:52 -080065 private static final int WINDOW_STATE_INVALID = -1;
66
Jorim Jaggi275561a2016-02-23 10:11:02 -050067 private static final long INVALID_START_TIME = -1;
68
Jorim Jaggi172e99f2017-10-20 14:33:18 +020069 private static final int MSG_CHECK_VISIBILITY = 0;
70
Filip Gruszczynski77d94482015-12-11 13:59:52 -080071 // Preallocated strings we are sending to tron, so we don't have to allocate a new one every
72 // time we log.
73 private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = {
Winson Chung83471632016-12-13 11:02:12 -080074 "window_time_0", "window_time_1", "window_time_2", "window_time_3"};
Filip Gruszczynski77d94482015-12-11 13:59:52 -080075
76 private int mWindowState = WINDOW_STATE_STANDARD;
77 private long mLastLogTimeSecs;
78 private final ActivityStackSupervisor mSupervisor;
79 private final Context mContext;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080080 private final MetricsLogger mMetricsLogger = new MetricsLogger();
Filip Gruszczynski77d94482015-12-11 13:59:52 -080081
Jorim Jaggi275561a2016-02-23 10:11:02 -050082 private long mCurrentTransitionStartTime = INVALID_START_TIME;
Jorim Jaggi4d27b842017-08-17 17:22:26 +020083 private long mLastTransitionStartTime = INVALID_START_TIME;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080084
85 private int mCurrentTransitionDeviceUptime;
86 private int mCurrentTransitionDelayMs;
Jorim Jaggi275561a2016-02-23 10:11:02 -050087 private boolean mLoggedTransitionStarting;
88
Jorim Jaggi3878ca32017-02-02 17:13:05 -080089 private final SparseArray<StackTransitionInfo> mStackTransitionInfo = new SparseArray<>();
Jorim Jaggi4d27b842017-08-17 17:22:26 +020090 private final SparseArray<StackTransitionInfo> mLastStackTransitionInfo = new SparseArray<>();
Jorim Jaggi172e99f2017-10-20 14:33:18 +020091 private final H mHandler;
92 private final class H extends Handler {
93
94 public H(Looper looper) {
95 super(looper);
96 }
97
98 @Override
99 public void handleMessage(Message msg) {
100 switch (msg.what) {
101 case MSG_CHECK_VISIBILITY:
102 final SomeArgs args = (SomeArgs) msg.obj;
103 checkVisibility((TaskRecord) args.arg1, (ActivityRecord) args.arg2);
104 break;
105 }
106 }
107 };
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800108
109 private final class StackTransitionInfo {
110 private ActivityRecord launchedActivity;
111 private int startResult;
112 private boolean currentTransitionProcessRunning;
113 private int windowsDrawnDelayMs;
Jorim Jaggi515dd682017-05-05 15:05:07 +0200114 private int startingWindowDelayMs = -1;
115 private int bindApplicationDelayMs = -1;
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800116 private int reason = APP_TRANSITION_TIMEOUT;
117 private boolean loggedWindowsDrawn;
118 private boolean loggedStartingWindowDrawn;
119 }
120
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200121 ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context, Looper looper) {
Filip Gruszczynski77d94482015-12-11 13:59:52 -0800122 mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
123 mSupervisor = supervisor;
124 mContext = context;
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200125 mHandler = new H(looper);
Filip Gruszczynski77d94482015-12-11 13:59:52 -0800126 }
127
128 void logWindowState() {
129 final long now = SystemClock.elapsedRealtime() / 1000;
130 if (mWindowState != WINDOW_STATE_INVALID) {
131 // We log even if the window state hasn't changed, because the user might remain in
132 // home/fullscreen move forever and we would like to track this kind of behavior
133 // too.
134 MetricsLogger.count(mContext, TRON_WINDOW_STATE_VARZ_STRINGS[mWindowState],
135 (int) (now - mLastLogTimeSecs));
136 }
137 mLastLogTimeSecs = now;
138
Wale Ogunwale926aade2017-08-29 11:24:37 -0700139 mWindowState = WINDOW_STATE_INVALID;
140 ActivityStack stack = mSupervisor.getFocusedStack();
141 if (stack.isActivityTypeAssistant()) {
142 mWindowState = WINDOW_STATE_ASSISTANT;
Filip Gruszczynskicaae14e2015-12-16 14:40:04 -0800143 return;
Filip Gruszczynski77d94482015-12-11 13:59:52 -0800144 }
Wale Ogunwale926aade2017-08-29 11:24:37 -0700145
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700146 int windowingMode = stack.getWindowingMode();
147 if (windowingMode == WINDOWING_MODE_PINNED) {
Filip Gruszczynskicaae14e2015-12-16 14:40:04 -0800148 stack = mSupervisor.findStackBehind(stack);
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700149 windowingMode = stack.getWindowingMode();
Filip Gruszczynskicaae14e2015-12-16 14:40:04 -0800150 }
Wale Ogunwale926aade2017-08-29 11:24:37 -0700151 switch (windowingMode) {
152 case WINDOWING_MODE_FULLSCREEN:
153 mWindowState = WINDOW_STATE_STANDARD;
154 break;
155 case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
156 case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
157 mWindowState = WINDOW_STATE_SIDE_BY_SIDE;
158 break;
Bryce Lee6c605092017-10-12 11:14:49 -0700159 case WINDOWING_MODE_FREEFORM:
Wale Ogunwale926aade2017-08-29 11:24:37 -0700160 mWindowState = WINDOW_STATE_FREEFORM;
161 break;
162 default:
163 if (windowingMode != WINDOWING_MODE_UNDEFINED) {
164 throw new IllegalStateException("Unknown windowing mode for stack=" + stack
165 + " windowingMode=" + windowingMode);
166 }
Filip Gruszczynski77d94482015-12-11 13:59:52 -0800167 }
168 }
Jorim Jaggi275561a2016-02-23 10:11:02 -0500169
170 /**
171 * Notifies the tracker at the earliest possible point when we are starting to launch an
172 * activity.
173 */
174 void notifyActivityLaunching() {
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800175 if (!isAnyTransitionActive()) {
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200176 if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunching");
Alison Cichowlasb7f67ab2017-04-25 18:04:40 -0400177 mCurrentTransitionStartTime = SystemClock.uptimeMillis();
Jorim Jaggi4d27b842017-08-17 17:22:26 +0200178 mLastTransitionStartTime = mCurrentTransitionStartTime;
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800179 }
Jorim Jaggi275561a2016-02-23 10:11:02 -0500180 }
181
182 /**
Jorim Jaggi1e630c02016-05-16 12:13:13 -0700183 * Notifies the tracker that the activity is actually launching.
184 *
185 * @param resultCode one of the ActivityManager.START_* flags, indicating the result of the
186 * launch
187 * @param launchedActivity the activity that is being launched
188 */
189 void notifyActivityLaunched(int resultCode, ActivityRecord launchedActivity) {
190 final ProcessRecord processRecord = launchedActivity != null
191 ? mSupervisor.mService.mProcessNames.get(launchedActivity.processName,
192 launchedActivity.appInfo.uid)
193 : null;
194 final boolean processRunning = processRecord != null;
Jorim Jaggi1e630c02016-05-16 12:13:13 -0700195
196 // We consider this a "process switch" if the process of the activity that gets launched
197 // didn't have an activity that was in started state. In this case, we assume that lot
198 // of caches might be purged so the time until it produces the first frame is very
199 // interesting.
200 final boolean processSwitch = processRecord == null
201 || !hasStartedActivity(processRecord, launchedActivity);
202
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800203 notifyActivityLaunched(resultCode, launchedActivity, processRunning, processSwitch);
Jorim Jaggi1e630c02016-05-16 12:13:13 -0700204 }
205
206 private boolean hasStartedActivity(ProcessRecord record, ActivityRecord launchedActivity) {
207 final ArrayList<ActivityRecord> activities = record.activities;
208 for (int i = activities.size() - 1; i >= 0; i--) {
209 final ActivityRecord activity = activities.get(i);
210 if (launchedActivity == activity) {
211 continue;
212 }
213 if (!activity.stopped) {
214 return true;
215 }
216 }
217 return false;
218 }
219
220 /**
Jorim Jaggi275561a2016-02-23 10:11:02 -0500221 * Notifies the tracker the the activity is actually launching.
222 *
223 * @param resultCode one of the ActivityManager.START_* flags, indicating the result of the
224 * launch
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800225 * @param launchedActivity the activity being launched
Jorim Jaggi275561a2016-02-23 10:11:02 -0500226 * @param processRunning whether the process that will contains the activity is already running
Jorim Jaggibe67c902016-04-12 00:53:16 -0700227 * @param processSwitch whether the process that will contain the activity didn't have any
228 * activity that was stopped, i.e. the started activity is "switching"
229 * processes
Jorim Jaggi275561a2016-02-23 10:11:02 -0500230 */
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800231 private void notifyActivityLaunched(int resultCode, ActivityRecord launchedActivity,
Jorim Jaggibe67c902016-04-12 00:53:16 -0700232 boolean processRunning, boolean processSwitch) {
Jorim Jaggi275561a2016-02-23 10:11:02 -0500233
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200234 if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched"
235 + " resultCode=" + resultCode
236 + " launchedActivity=" + launchedActivity
237 + " processRunning=" + processRunning
238 + " processSwitch=" + processSwitch);
239
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800240 // If we are already in an existing transition, only update the activity name, but not the
241 // other attributes.
242 final int stackId = launchedActivity != null && launchedActivity.getStack() != null
243 ? launchedActivity.getStack().mStackId
244 : INVALID_STACK_ID;
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200245
246 if (mCurrentTransitionStartTime == INVALID_START_TIME) {
247 return;
248 }
249
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800250 final StackTransitionInfo info = mStackTransitionInfo.get(stackId);
251 if (launchedActivity != null && info != null) {
252 info.launchedActivity = launchedActivity;
Jorim Jaggi275561a2016-02-23 10:11:02 -0500253 return;
254 }
255
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800256 final boolean otherStacksLaunching = mStackTransitionInfo.size() > 0 && info == null;
257 if ((resultCode < 0 || launchedActivity == null || !processSwitch
258 || stackId == INVALID_STACK_ID) && !otherStacksLaunching) {
Alison Cichowlas803054d2016-12-13 14:38:01 -0500259
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800260 // Failed to launch or it was not a process switch, so we don't care about the timing.
261 reset(true /* abort */);
262 return;
263 } else if (otherStacksLaunching) {
264 // Don't log this stack but continue with the other stacks.
265 return;
266 }
267
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200268 if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched successful");
269
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800270 final StackTransitionInfo newInfo = new StackTransitionInfo();
271 newInfo.launchedActivity = launchedActivity;
272 newInfo.currentTransitionProcessRunning = processRunning;
273 newInfo.startResult = resultCode;
Jorim Jaggi4d27b842017-08-17 17:22:26 +0200274 mStackTransitionInfo.put(stackId, newInfo);
275 mLastStackTransitionInfo.put(stackId, newInfo);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800276 mCurrentTransitionDeviceUptime = (int) (SystemClock.uptimeMillis() / 1000);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500277 }
278
279 /**
280 * Notifies the tracker that all windows of the app have been drawn.
281 */
Sudheer Shankac766db02017-06-12 10:37:29 -0700282 void notifyWindowsDrawn(int stackId, long timestamp) {
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200283 if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn stackId=" + stackId);
284
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800285 final StackTransitionInfo info = mStackTransitionInfo.get(stackId);
286 if (info == null || info.loggedWindowsDrawn) {
Jorim Jaggi275561a2016-02-23 10:11:02 -0500287 return;
288 }
Sudheer Shankac766db02017-06-12 10:37:29 -0700289 info.windowsDrawnDelayMs = calculateDelay(timestamp);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800290 info.loggedWindowsDrawn = true;
291 if (allStacksWindowsDrawn() && mLoggedTransitionStarting) {
292 reset(false /* abort */);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500293 }
294 }
295
296 /**
297 * Notifies the tracker that the starting window was drawn.
298 */
Sudheer Shankac766db02017-06-12 10:37:29 -0700299 void notifyStartingWindowDrawn(int stackId, long timestamp) {
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800300 final StackTransitionInfo info = mStackTransitionInfo.get(stackId);
301 if (info == null || info.loggedStartingWindowDrawn) {
Jorim Jaggi275561a2016-02-23 10:11:02 -0500302 return;
303 }
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800304 info.loggedStartingWindowDrawn = true;
Sudheer Shankac766db02017-06-12 10:37:29 -0700305 info.startingWindowDelayMs = calculateDelay(timestamp);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500306 }
307
308 /**
309 * Notifies the tracker that the app transition is starting.
310 *
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800311 * @param stackIdReasons A map from stack id to a reason integer, which must be on of
312 * ActivityManagerInternal.APP_TRANSITION_* reasons.
Jorim Jaggi275561a2016-02-23 10:11:02 -0500313 */
Sudheer Shankac766db02017-06-12 10:37:29 -0700314 void notifyTransitionStarting(SparseIntArray stackIdReasons, long timestamp) {
Jorim Jaggid8a57772017-04-14 16:50:42 -0700315 if (!isAnyTransitionActive() || mLoggedTransitionStarting) {
Jorim Jaggi275561a2016-02-23 10:11:02 -0500316 return;
317 }
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200318 if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting");
Sudheer Shankac766db02017-06-12 10:37:29 -0700319 mCurrentTransitionDelayMs = calculateDelay(timestamp);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500320 mLoggedTransitionStarting = true;
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800321 for (int index = stackIdReasons.size() - 1; index >= 0; index--) {
322 final int stackId = stackIdReasons.keyAt(index);
323 final StackTransitionInfo info = mStackTransitionInfo.get(stackId);
324 if (info == null) {
325 continue;
326 }
327 info.reason = stackIdReasons.valueAt(index);
328 }
329 if (allStacksWindowsDrawn()) {
330 reset(false /* abort */);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500331 }
332 }
333
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200334 /**
335 * Notifies the tracker that the visibility of an app is changing.
336 *
337 * @param activityRecord the app that is changing its visibility
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200338 */
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200339 void notifyVisibilityChanged(ActivityRecord activityRecord) {
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200340 final StackTransitionInfo info = mStackTransitionInfo.get(activityRecord.getStackId());
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200341 if (info == null) {
342 return;
343 }
344 if (info.launchedActivity != activityRecord) {
345 return;
346 }
347 final TaskRecord t = activityRecord.getTask();
348 final SomeArgs args = SomeArgs.obtain();
349 args.arg1 = t;
350 args.arg2 = activityRecord;
351 mHandler.obtainMessage(MSG_CHECK_VISIBILITY, args).sendToTarget();
352 }
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200353
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200354 private void checkVisibility(TaskRecord t, ActivityRecord r) {
355 synchronized (mSupervisor.mService) {
356
357 final StackTransitionInfo info = mStackTransitionInfo.get(r.getStackId());
358
359 // If we have an active transition that's waiting on a certain activity that will be
360 // invisible now, we'll never get onWindowsDrawn, so abort the transition if necessary.
361 if (info != null && !t.isVisible()) {
362 if (DEBUG_METRICS) Slog.i(TAG, "notifyVisibilityChanged to invisible"
363 + " activity=" + r);
364 logAppTransitionCancel(info);
365 mStackTransitionInfo.remove(r.getStackId());
366 if (mStackTransitionInfo.size() == 0) {
367 reset(true /* abort */);
368 }
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200369 }
370 }
371 }
372
Jorim Jaggi515dd682017-05-05 15:05:07 +0200373 /**
374 * Notifies the tracker that we called immediately before we call bindApplication on the client.
375 *
376 * @param app The client into which we'll call bindApplication.
377 */
378 void notifyBindApplication(ProcessRecord app) {
379 for (int i = mStackTransitionInfo.size() - 1; i >= 0; i--) {
380 final StackTransitionInfo info = mStackTransitionInfo.valueAt(i);
381
382 // App isn't attached to record yet, so match with info.
383 if (info.launchedActivity.appInfo == app.info) {
384 info.bindApplicationDelayMs = calculateCurrentDelay();
385 }
386 }
387 }
388
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800389 private boolean allStacksWindowsDrawn() {
390 for (int index = mStackTransitionInfo.size() - 1; index >= 0; index--) {
391 if (!mStackTransitionInfo.valueAt(index).loggedWindowsDrawn) {
392 return false;
393 }
394 }
395 return true;
Jorim Jaggi275561a2016-02-23 10:11:02 -0500396 }
397
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800398 private boolean isAnyTransitionActive() {
399 return mCurrentTransitionStartTime != INVALID_START_TIME
400 && mStackTransitionInfo.size() > 0;
401 }
402
403 private void reset(boolean abort) {
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200404 if (DEBUG_METRICS) Slog.i(TAG, "reset abort=" + abort);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800405 if (!abort && isAnyTransitionActive()) {
406 logAppTransitionMultiEvents();
407 }
Jorim Jaggi275561a2016-02-23 10:11:02 -0500408 mCurrentTransitionStartTime = INVALID_START_TIME;
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800409 mCurrentTransitionDelayMs = -1;
Jorim Jaggi275561a2016-02-23 10:11:02 -0500410 mLoggedTransitionStarting = false;
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800411 mStackTransitionInfo.clear();
Jorim Jaggi275561a2016-02-23 10:11:02 -0500412 }
413
414 private int calculateCurrentDelay() {
415
416 // Shouldn't take more than 25 days to launch an app, so int is fine here.
Alison Cichowlasb7f67ab2017-04-25 18:04:40 -0400417 return (int) (SystemClock.uptimeMillis() - mCurrentTransitionStartTime);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500418 }
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800419
Sudheer Shankac766db02017-06-12 10:37:29 -0700420 private int calculateDelay(long timestamp) {
421 // Shouldn't take more than 25 days to launch an app, so int is fine here.
422 return (int) (timestamp - mCurrentTransitionStartTime);
423 }
424
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200425 private void logAppTransitionCancel(StackTransitionInfo info) {
426 final int type = getTransitionType(info);
427 if (type == -1) {
428 return;
429 }
430 final LogMaker builder = new LogMaker(APP_TRANSITION_CANCELLED);
431 builder.setPackageName(info.launchedActivity.packageName);
432 builder.setType(type);
433 builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name);
434 mMetricsLogger.write(builder);
Olivier Gaillardaed7f122017-12-12 14:26:22 +0000435 StatsLog.write(
436 StatsLog.APP_START_CANCEL_CHANGED,
437 info.launchedActivity.appInfo.uid,
438 info.launchedActivity.packageName,
439 convertAppStartTransitionType(type),
440 info.launchedActivity.info.name);
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200441 }
442
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800443 private void logAppTransitionMultiEvents() {
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200444 if (DEBUG_METRICS) Slog.i(TAG, "logging transition events");
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800445 for (int index = mStackTransitionInfo.size() - 1; index >= 0; index--) {
446 final StackTransitionInfo info = mStackTransitionInfo.valueAt(index);
447 final int type = getTransitionType(info);
448 if (type == -1) {
449 return;
450 }
451 final LogMaker builder = new LogMaker(APP_TRANSITION);
452 builder.setPackageName(info.launchedActivity.packageName);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800453 builder.setType(type);
Jason Monk8c09ac72017-03-16 11:53:40 -0400454 builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name);
Todd Kennedy56279cb2017-04-17 14:53:49 -0700455 final boolean isInstantApp = info.launchedActivity.info.applicationInfo.isInstantApp();
Todd Kennedy7655b292017-08-18 15:05:01 -0700456 if (info.launchedActivity.launchedFromPackage != null) {
Todd Kennedy50d946c12017-03-17 13:55:38 -0700457 builder.addTaggedData(APP_TRANSITION_CALLING_PACKAGE_NAME,
458 info.launchedActivity.launchedFromPackage);
459 }
Olivier Gaillardaed7f122017-12-12 14:26:22 +0000460 String launchToken = info.launchedActivity.info.launchToken;
461 if (launchToken != null) {
462 builder.addTaggedData(FIELD_INSTANT_APP_LAUNCH_TOKEN, launchToken);
Todd Kennedyb3b431302017-03-20 16:05:48 -0700463 info.launchedActivity.info.launchToken = null;
Todd Kennedy50d946c12017-03-17 13:55:38 -0700464 }
Todd Kennedy56279cb2017-04-17 14:53:49 -0700465 builder.addTaggedData(APP_TRANSITION_IS_EPHEMERAL, isInstantApp ? 1 : 0);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800466 builder.addTaggedData(APP_TRANSITION_DEVICE_UPTIME_SECONDS,
467 mCurrentTransitionDeviceUptime);
468 builder.addTaggedData(APP_TRANSITION_DELAY_MS, mCurrentTransitionDelayMs);
469 builder.setSubtype(info.reason);
470 if (info.startingWindowDelayMs != -1) {
471 builder.addTaggedData(APP_TRANSITION_STARTING_WINDOW_DELAY_MS,
472 info.startingWindowDelayMs);
473 }
Jorim Jaggi515dd682017-05-05 15:05:07 +0200474 if (info.bindApplicationDelayMs != -1) {
475 builder.addTaggedData(APP_TRANSITION_BIND_APPLICATION_DELAY_MS,
476 info.bindApplicationDelayMs);
477 }
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800478 builder.addTaggedData(APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS, info.windowsDrawnDelayMs);
479 mMetricsLogger.write(builder);
Olivier Gaillardaed7f122017-12-12 14:26:22 +0000480 StatsLog.write(
481 StatsLog.APP_START_CHANGED,
482 info.launchedActivity.appInfo.uid,
483 info.launchedActivity.packageName,
484 convertAppStartTransitionType(type),
485 info.launchedActivity.info.name,
486 info.launchedActivity.launchedFromPackage,
487 isInstantApp,
488 mCurrentTransitionDeviceUptime * 1000,
489 info.reason,
490 mCurrentTransitionDelayMs,
491 info.startingWindowDelayMs,
492 info.bindApplicationDelayMs,
493 info.windowsDrawnDelayMs,
494 launchToken);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800495 }
496 }
497
Olivier Gaillardaed7f122017-12-12 14:26:22 +0000498 private int convertAppStartTransitionType(int tronType) {
499 if (tronType == TYPE_TRANSITION_COLD_LAUNCH) {
500 return StatsLog.APP_START_CHANGED__TYPE__COLD;
501 }
502 if (tronType == TYPE_TRANSITION_WARM_LAUNCH) {
503 return StatsLog.APP_START_CHANGED__TYPE__WARM;
504 }
505 if (tronType == TYPE_TRANSITION_HOT_LAUNCH) {
506 return StatsLog.APP_START_CHANGED__TYPE__HOT;
507 }
508 return StatsLog.APP_START_CHANGED__TYPE__APP_START_TRANSITION_TYPE_UNKNOWN;
509 }
510
Jorim Jaggi4d27b842017-08-17 17:22:26 +0200511 void logAppTransitionReportedDrawn(ActivityRecord r, boolean restoredFromBundle) {
512 final StackTransitionInfo info = mLastStackTransitionInfo.get(r.getStackId());
513 if (info == null) {
514 return;
515 }
516 final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN);
517 builder.setPackageName(r.packageName);
518 builder.addTaggedData(FIELD_CLASS_NAME, r.info.name);
Olivier Gaillardaed7f122017-12-12 14:26:22 +0000519 long startupTimeMs = SystemClock.uptimeMillis() - mLastTransitionStartTime;
520 builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS, startupTimeMs);
Jorim Jaggi4d27b842017-08-17 17:22:26 +0200521 builder.setType(restoredFromBundle
522 ? TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE
523 : TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE);
524 builder.addTaggedData(APP_TRANSITION_PROCESS_RUNNING,
525 info.currentTransitionProcessRunning ? 1 : 0);
526 mMetricsLogger.write(builder);
Olivier Gaillardaed7f122017-12-12 14:26:22 +0000527 StatsLog.write(
528 StatsLog.APP_START_FULLY_DRAWN_CHANGED,
529 info.launchedActivity.appInfo.uid,
530 info.launchedActivity.packageName,
531 restoredFromBundle
532 ? StatsLog.APP_START_FULLY_DRAWN_CHANGED__TYPE__WITH_BUNDLE
533 : StatsLog.APP_START_FULLY_DRAWN_CHANGED__TYPE__WITHOUT_BUNDLE,
534 info.launchedActivity.info.name,
535 info.currentTransitionProcessRunning,
536 startupTimeMs);
Jorim Jaggi4d27b842017-08-17 17:22:26 +0200537 }
538
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800539 private int getTransitionType(StackTransitionInfo info) {
540 if (info.currentTransitionProcessRunning) {
541 if (info.startResult == START_SUCCESS) {
542 return TYPE_TRANSITION_WARM_LAUNCH;
543 } else if (info.startResult == START_TASK_TO_FRONT) {
544 return TYPE_TRANSITION_HOT_LAUNCH;
545 }
546 } else if (info.startResult == START_SUCCESS) {
547 return TYPE_TRANSITION_COLD_LAUNCH;
548 }
549 return -1;
550 }
Filip Gruszczynski77d94482015-12-11 13:59:52 -0800551}