blob: db86f1a011df0c7129e1097b8e4204caccdd5c4e [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.ActivityManagerInternal.APP_TRANSITION_TIMEOUT;
Wale Ogunwale926aade2017-08-29 11:24:37 -07006import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
Bryce Lee6c605092017-10-12 11:14:49 -07007import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
Wale Ogunwale3382ab12017-07-27 08:55:03 -07008import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
9import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
Wale Ogunwale926aade2017-08-29 11:24:37 -070010import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
11import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080012import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION;
Jorim Jaggi515dd682017-05-05 15:05:07 +020013import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_BIND_APPLICATION_DELAY_MS;
Todd Kennedy50d946c12017-03-17 13:55:38 -070014import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CALLING_PACKAGE_NAME;
Jorim Jaggi172e99f2017-10-20 14:33:18 +020015import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CANCELLED;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080016import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS;
17import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS;
Todd Kennedy50d946c12017-03-17 13:55:38 -070018import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_IS_EPHEMERAL;
Jorim Jaggi4d27b842017-08-17 17:22:26 +020019import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_PROCESS_RUNNING;
20import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN;
21import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN_MS;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080022import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_STARTING_WINDOW_DELAY_MS;
23import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS;
Jorim Jaggicdfc04e2017-04-28 19:06:24 +020024import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CLASS_NAME;
Todd Kennedy50d946c12017-03-17 13:55:38 -070025import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INSTANT_APP_LAUNCH_TOKEN;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080026import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_COLD_LAUNCH;
27import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_HOT_LAUNCH;
Jorim Jaggi4d27b842017-08-17 17:22:26 +020028import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE;
29import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080030import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
Jorim Jaggi172e99f2017-10-20 14:33:18 +020031import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_METRICS;
Jorim Jaggif9704102016-05-05 19:14:22 -070032import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
33import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
Ng Zhi Anbbefdec2018-01-30 17:12:39 -080034import static com.android.server.am.MemoryStatUtil.MemoryStat;
35import static com.android.server.am.MemoryStatUtil.readMemoryStatFromMemcg;
Filip Gruszczynski77d94482015-12-11 13:59:52 -080036
Filip Gruszczynski77d94482015-12-11 13:59:52 -080037import android.content.Context;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080038import android.metrics.LogMaker;
Jorim Jaggi172e99f2017-10-20 14:33:18 +020039import android.os.Handler;
40import android.os.Looper;
41import android.os.Message;
Filip Gruszczynski77d94482015-12-11 13:59:52 -080042import android.os.SystemClock;
Jorim Jaggi172e99f2017-10-20 14:33:18 +020043import android.util.Slog;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080044import android.util.SparseArray;
45import android.util.SparseIntArray;
Olivier Gaillardaed7f122017-12-12 14:26:22 +000046import android.util.StatsLog;
Filip Gruszczynski77d94482015-12-11 13:59:52 -080047
48import com.android.internal.logging.MetricsLogger;
Jorim Jaggi172e99f2017-10-20 14:33:18 +020049import com.android.internal.os.SomeArgs;
Filip Gruszczynski77d94482015-12-11 13:59:52 -080050
Jorim Jaggi1e630c02016-05-16 12:13:13 -070051import java.util.ArrayList;
52
Filip Gruszczynski77d94482015-12-11 13:59:52 -080053/**
54 * Handles logging into Tron.
55 */
56class ActivityMetricsLogger {
Jorim Jaggif9704102016-05-05 19:14:22 -070057
58 private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityMetricsLogger" : TAG_AM;
59
Filip Gruszczynski77d94482015-12-11 13:59:52 -080060 // Window modes we are interested in logging. If we ever introduce a new type, we need to add
61 // a value here and increase the {@link #TRON_WINDOW_STATE_VARZ_STRINGS} array.
62 private static final int WINDOW_STATE_STANDARD = 0;
63 private static final int WINDOW_STATE_SIDE_BY_SIDE = 1;
64 private static final int WINDOW_STATE_FREEFORM = 2;
Winson Chung83471632016-12-13 11:02:12 -080065 private static final int WINDOW_STATE_ASSISTANT = 3;
Filip Gruszczynski77d94482015-12-11 13:59:52 -080066 private static final int WINDOW_STATE_INVALID = -1;
67
Jorim Jaggi275561a2016-02-23 10:11:02 -050068 private static final long INVALID_START_TIME = -1;
69
Jorim Jaggi172e99f2017-10-20 14:33:18 +020070 private static final int MSG_CHECK_VISIBILITY = 0;
Narayan Kamath203a9ab2018-02-20 17:06:21 +000071 private static final int MSG_LOG_APP_START_MEMORY_STATE_CAPTURE = 1;
Jorim Jaggi172e99f2017-10-20 14:33:18 +020072
Filip Gruszczynski77d94482015-12-11 13:59:52 -080073 // Preallocated strings we are sending to tron, so we don't have to allocate a new one every
74 // time we log.
75 private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = {
Winson Chung83471632016-12-13 11:02:12 -080076 "window_time_0", "window_time_1", "window_time_2", "window_time_3"};
Filip Gruszczynski77d94482015-12-11 13:59:52 -080077
78 private int mWindowState = WINDOW_STATE_STANDARD;
79 private long mLastLogTimeSecs;
80 private final ActivityStackSupervisor mSupervisor;
81 private final Context mContext;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080082 private final MetricsLogger mMetricsLogger = new MetricsLogger();
Filip Gruszczynski77d94482015-12-11 13:59:52 -080083
Jorim Jaggi275561a2016-02-23 10:11:02 -050084 private long mCurrentTransitionStartTime = INVALID_START_TIME;
Jorim Jaggi4d27b842017-08-17 17:22:26 +020085 private long mLastTransitionStartTime = INVALID_START_TIME;
Jorim Jaggi3878ca32017-02-02 17:13:05 -080086
87 private int mCurrentTransitionDeviceUptime;
88 private int mCurrentTransitionDelayMs;
Jorim Jaggi275561a2016-02-23 10:11:02 -050089 private boolean mLoggedTransitionStarting;
90
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +010091 private final SparseArray<WindowingModeTransitionInfo> mWindowingModeTransitionInfo =
92 new SparseArray<>();
93 private final SparseArray<WindowingModeTransitionInfo> mLastWindowingModeTransitionInfo =
94 new SparseArray<>();
Jorim Jaggi172e99f2017-10-20 14:33:18 +020095 private final H mHandler;
96 private final class H extends Handler {
97
98 public H(Looper looper) {
99 super(looper);
100 }
101
102 @Override
103 public void handleMessage(Message msg) {
104 switch (msg.what) {
105 case MSG_CHECK_VISIBILITY:
106 final SomeArgs args = (SomeArgs) msg.obj;
107 checkVisibility((TaskRecord) args.arg1, (ActivityRecord) args.arg2);
108 break;
Narayan Kamath203a9ab2018-02-20 17:06:21 +0000109 case MSG_LOG_APP_START_MEMORY_STATE_CAPTURE:
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100110 logAppStartMemoryStateCapture((WindowingModeTransitionInfo) msg.obj);
Ng Zhi Anbbefdec2018-01-30 17:12:39 -0800111 break;
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200112 }
113 }
Narayan Kamath203a9ab2018-02-20 17:06:21 +0000114 };
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800115
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100116 private final class WindowingModeTransitionInfo {
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800117 private ActivityRecord launchedActivity;
118 private int startResult;
119 private boolean currentTransitionProcessRunning;
120 private int windowsDrawnDelayMs;
Jorim Jaggi515dd682017-05-05 15:05:07 +0200121 private int startingWindowDelayMs = -1;
122 private int bindApplicationDelayMs = -1;
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800123 private int reason = APP_TRANSITION_TIMEOUT;
124 private boolean loggedWindowsDrawn;
125 private boolean loggedStartingWindowDrawn;
126 }
127
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200128 ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context, Looper looper) {
Filip Gruszczynski77d94482015-12-11 13:59:52 -0800129 mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
130 mSupervisor = supervisor;
131 mContext = context;
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200132 mHandler = new H(looper);
Filip Gruszczynski77d94482015-12-11 13:59:52 -0800133 }
134
135 void logWindowState() {
136 final long now = SystemClock.elapsedRealtime() / 1000;
137 if (mWindowState != WINDOW_STATE_INVALID) {
138 // We log even if the window state hasn't changed, because the user might remain in
139 // home/fullscreen move forever and we would like to track this kind of behavior
140 // too.
141 MetricsLogger.count(mContext, TRON_WINDOW_STATE_VARZ_STRINGS[mWindowState],
142 (int) (now - mLastLogTimeSecs));
143 }
144 mLastLogTimeSecs = now;
145
Wale Ogunwale926aade2017-08-29 11:24:37 -0700146 mWindowState = WINDOW_STATE_INVALID;
147 ActivityStack stack = mSupervisor.getFocusedStack();
148 if (stack.isActivityTypeAssistant()) {
149 mWindowState = WINDOW_STATE_ASSISTANT;
Filip Gruszczynskicaae14e2015-12-16 14:40:04 -0800150 return;
Filip Gruszczynski77d94482015-12-11 13:59:52 -0800151 }
Wale Ogunwale926aade2017-08-29 11:24:37 -0700152
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700153 int windowingMode = stack.getWindowingMode();
154 if (windowingMode == WINDOWING_MODE_PINNED) {
Filip Gruszczynskicaae14e2015-12-16 14:40:04 -0800155 stack = mSupervisor.findStackBehind(stack);
Wale Ogunwale3382ab12017-07-27 08:55:03 -0700156 windowingMode = stack.getWindowingMode();
Filip Gruszczynskicaae14e2015-12-16 14:40:04 -0800157 }
Wale Ogunwale926aade2017-08-29 11:24:37 -0700158 switch (windowingMode) {
159 case WINDOWING_MODE_FULLSCREEN:
160 mWindowState = WINDOW_STATE_STANDARD;
161 break;
162 case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
163 case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
164 mWindowState = WINDOW_STATE_SIDE_BY_SIDE;
165 break;
Bryce Lee6c605092017-10-12 11:14:49 -0700166 case WINDOWING_MODE_FREEFORM:
Wale Ogunwale926aade2017-08-29 11:24:37 -0700167 mWindowState = WINDOW_STATE_FREEFORM;
168 break;
169 default:
170 if (windowingMode != WINDOWING_MODE_UNDEFINED) {
171 throw new IllegalStateException("Unknown windowing mode for stack=" + stack
172 + " windowingMode=" + windowingMode);
173 }
Filip Gruszczynski77d94482015-12-11 13:59:52 -0800174 }
175 }
Jorim Jaggi275561a2016-02-23 10:11:02 -0500176
177 /**
178 * Notifies the tracker at the earliest possible point when we are starting to launch an
179 * activity.
180 */
181 void notifyActivityLaunching() {
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800182 if (!isAnyTransitionActive()) {
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200183 if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunching");
Alison Cichowlasb7f67ab2017-04-25 18:04:40 -0400184 mCurrentTransitionStartTime = SystemClock.uptimeMillis();
Jorim Jaggi4d27b842017-08-17 17:22:26 +0200185 mLastTransitionStartTime = mCurrentTransitionStartTime;
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800186 }
Jorim Jaggi275561a2016-02-23 10:11:02 -0500187 }
188
189 /**
Jorim Jaggi1e630c02016-05-16 12:13:13 -0700190 * Notifies the tracker that the activity is actually launching.
191 *
192 * @param resultCode one of the ActivityManager.START_* flags, indicating the result of the
193 * launch
194 * @param launchedActivity the activity that is being launched
195 */
196 void notifyActivityLaunched(int resultCode, ActivityRecord launchedActivity) {
Ng Zhi Anbbefdec2018-01-30 17:12:39 -0800197 final ProcessRecord processRecord = findProcessForActivity(launchedActivity);
Jorim Jaggi1e630c02016-05-16 12:13:13 -0700198 final boolean processRunning = processRecord != null;
Jorim Jaggi1e630c02016-05-16 12:13:13 -0700199
200 // We consider this a "process switch" if the process of the activity that gets launched
201 // didn't have an activity that was in started state. In this case, we assume that lot
202 // of caches might be purged so the time until it produces the first frame is very
203 // interesting.
204 final boolean processSwitch = processRecord == null
205 || !hasStartedActivity(processRecord, launchedActivity);
206
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800207 notifyActivityLaunched(resultCode, launchedActivity, processRunning, processSwitch);
Jorim Jaggi1e630c02016-05-16 12:13:13 -0700208 }
209
210 private boolean hasStartedActivity(ProcessRecord record, ActivityRecord launchedActivity) {
211 final ArrayList<ActivityRecord> activities = record.activities;
212 for (int i = activities.size() - 1; i >= 0; i--) {
213 final ActivityRecord activity = activities.get(i);
214 if (launchedActivity == activity) {
215 continue;
216 }
217 if (!activity.stopped) {
218 return true;
219 }
220 }
221 return false;
222 }
223
224 /**
Jorim Jaggi275561a2016-02-23 10:11:02 -0500225 * Notifies the tracker the the activity is actually launching.
226 *
227 * @param resultCode one of the ActivityManager.START_* flags, indicating the result of the
228 * launch
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800229 * @param launchedActivity the activity being launched
Jorim Jaggi275561a2016-02-23 10:11:02 -0500230 * @param processRunning whether the process that will contains the activity is already running
Jorim Jaggibe67c902016-04-12 00:53:16 -0700231 * @param processSwitch whether the process that will contain the activity didn't have any
232 * activity that was stopped, i.e. the started activity is "switching"
233 * processes
Jorim Jaggi275561a2016-02-23 10:11:02 -0500234 */
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800235 private void notifyActivityLaunched(int resultCode, ActivityRecord launchedActivity,
Jorim Jaggibe67c902016-04-12 00:53:16 -0700236 boolean processRunning, boolean processSwitch) {
Jorim Jaggi275561a2016-02-23 10:11:02 -0500237
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200238 if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched"
239 + " resultCode=" + resultCode
240 + " launchedActivity=" + launchedActivity
241 + " processRunning=" + processRunning
242 + " processSwitch=" + processSwitch);
243
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800244 // If we are already in an existing transition, only update the activity name, but not the
245 // other attributes.
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100246 final int windowingMode = launchedActivity != null
247 ? launchedActivity.getWindowingMode()
248 : WINDOWING_MODE_UNDEFINED;
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200249
250 if (mCurrentTransitionStartTime == INVALID_START_TIME) {
251 return;
252 }
253
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100254 final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800255 if (launchedActivity != null && info != null) {
256 info.launchedActivity = launchedActivity;
Jorim Jaggi275561a2016-02-23 10:11:02 -0500257 return;
258 }
259
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100260 final boolean otherWindowModesLaunching =
261 mWindowingModeTransitionInfo.size() > 0 && info == null;
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800262 if ((resultCode < 0 || launchedActivity == null || !processSwitch
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100263 || windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) {
Alison Cichowlas803054d2016-12-13 14:38:01 -0500264
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800265 // Failed to launch or it was not a process switch, so we don't care about the timing.
266 reset(true /* abort */);
267 return;
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100268 } else if (otherWindowModesLaunching) {
269 // Don't log this windowing mode but continue with the other windowing modes.
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800270 return;
271 }
272
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200273 if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched successful");
274
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100275 final WindowingModeTransitionInfo newInfo = new WindowingModeTransitionInfo();
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800276 newInfo.launchedActivity = launchedActivity;
277 newInfo.currentTransitionProcessRunning = processRunning;
278 newInfo.startResult = resultCode;
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100279 mWindowingModeTransitionInfo.put(windowingMode, newInfo);
280 mLastWindowingModeTransitionInfo.put(windowingMode, newInfo);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800281 mCurrentTransitionDeviceUptime = (int) (SystemClock.uptimeMillis() / 1000);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500282 }
283
284 /**
285 * Notifies the tracker that all windows of the app have been drawn.
286 */
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100287 void notifyWindowsDrawn(int windowingMode, long timestamp) {
288 if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn windowingMode=" + windowingMode);
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200289
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100290 final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800291 if (info == null || info.loggedWindowsDrawn) {
Jorim Jaggi275561a2016-02-23 10:11:02 -0500292 return;
293 }
Sudheer Shankac766db02017-06-12 10:37:29 -0700294 info.windowsDrawnDelayMs = calculateDelay(timestamp);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800295 info.loggedWindowsDrawn = true;
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100296 if (allWindowsDrawn() && mLoggedTransitionStarting) {
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800297 reset(false /* abort */);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500298 }
299 }
300
301 /**
302 * Notifies the tracker that the starting window was drawn.
303 */
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100304 void notifyStartingWindowDrawn(int windowingMode, long timestamp) {
305 final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800306 if (info == null || info.loggedStartingWindowDrawn) {
Jorim Jaggi275561a2016-02-23 10:11:02 -0500307 return;
308 }
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800309 info.loggedStartingWindowDrawn = true;
Sudheer Shankac766db02017-06-12 10:37:29 -0700310 info.startingWindowDelayMs = calculateDelay(timestamp);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500311 }
312
313 /**
314 * Notifies the tracker that the app transition is starting.
315 *
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100316 * @param windowingModeToReason A map from windowing mode to a reason integer, which must be on
317 * of ActivityManagerInternal.APP_TRANSITION_* reasons.
Jorim Jaggi275561a2016-02-23 10:11:02 -0500318 */
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100319 void notifyTransitionStarting(SparseIntArray windowingModeToReason, long timestamp) {
Jorim Jaggid8a57772017-04-14 16:50:42 -0700320 if (!isAnyTransitionActive() || mLoggedTransitionStarting) {
Jorim Jaggi275561a2016-02-23 10:11:02 -0500321 return;
322 }
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200323 if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting");
Sudheer Shankac766db02017-06-12 10:37:29 -0700324 mCurrentTransitionDelayMs = calculateDelay(timestamp);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500325 mLoggedTransitionStarting = true;
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100326 for (int index = windowingModeToReason.size() - 1; index >= 0; index--) {
327 final int windowingMode = windowingModeToReason.keyAt(index);
328 final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(
329 windowingMode);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800330 if (info == null) {
331 continue;
332 }
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100333 info.reason = windowingModeToReason.valueAt(index);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800334 }
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100335 if (allWindowsDrawn()) {
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800336 reset(false /* abort */);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500337 }
338 }
339
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200340 /**
341 * Notifies the tracker that the visibility of an app is changing.
342 *
343 * @param activityRecord the app that is changing its visibility
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200344 */
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200345 void notifyVisibilityChanged(ActivityRecord activityRecord) {
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100346 final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(
347 activityRecord.getWindowingMode());
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200348 if (info == null) {
349 return;
350 }
351 if (info.launchedActivity != activityRecord) {
352 return;
353 }
354 final TaskRecord t = activityRecord.getTask();
355 final SomeArgs args = SomeArgs.obtain();
356 args.arg1 = t;
357 args.arg2 = activityRecord;
358 mHandler.obtainMessage(MSG_CHECK_VISIBILITY, args).sendToTarget();
359 }
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200360
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200361 private void checkVisibility(TaskRecord t, ActivityRecord r) {
362 synchronized (mSupervisor.mService) {
363
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100364 final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(
365 r.getWindowingMode());
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200366
367 // If we have an active transition that's waiting on a certain activity that will be
368 // invisible now, we'll never get onWindowsDrawn, so abort the transition if necessary.
369 if (info != null && !t.isVisible()) {
370 if (DEBUG_METRICS) Slog.i(TAG, "notifyVisibilityChanged to invisible"
371 + " activity=" + r);
372 logAppTransitionCancel(info);
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100373 mWindowingModeTransitionInfo.remove(r.getWindowingMode());
374 if (mWindowingModeTransitionInfo.size() == 0) {
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200375 reset(true /* abort */);
376 }
Jorim Jaggicdfc04e2017-04-28 19:06:24 +0200377 }
378 }
379 }
380
Jorim Jaggi515dd682017-05-05 15:05:07 +0200381 /**
382 * Notifies the tracker that we called immediately before we call bindApplication on the client.
383 *
384 * @param app The client into which we'll call bindApplication.
385 */
386 void notifyBindApplication(ProcessRecord app) {
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100387 for (int i = mWindowingModeTransitionInfo.size() - 1; i >= 0; i--) {
388 final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.valueAt(i);
Jorim Jaggi515dd682017-05-05 15:05:07 +0200389
390 // App isn't attached to record yet, so match with info.
391 if (info.launchedActivity.appInfo == app.info) {
392 info.bindApplicationDelayMs = calculateCurrentDelay();
393 }
394 }
395 }
396
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100397 private boolean allWindowsDrawn() {
398 for (int index = mWindowingModeTransitionInfo.size() - 1; index >= 0; index--) {
399 if (!mWindowingModeTransitionInfo.valueAt(index).loggedWindowsDrawn) {
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800400 return false;
401 }
402 }
403 return true;
Jorim Jaggi275561a2016-02-23 10:11:02 -0500404 }
405
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800406 private boolean isAnyTransitionActive() {
407 return mCurrentTransitionStartTime != INVALID_START_TIME
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100408 && mWindowingModeTransitionInfo.size() > 0;
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800409 }
410
411 private void reset(boolean abort) {
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200412 if (DEBUG_METRICS) Slog.i(TAG, "reset abort=" + abort);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800413 if (!abort && isAnyTransitionActive()) {
414 logAppTransitionMultiEvents();
415 }
Jorim Jaggi275561a2016-02-23 10:11:02 -0500416 mCurrentTransitionStartTime = INVALID_START_TIME;
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800417 mCurrentTransitionDelayMs = -1;
Jorim Jaggi275561a2016-02-23 10:11:02 -0500418 mLoggedTransitionStarting = false;
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100419 mWindowingModeTransitionInfo.clear();
Jorim Jaggi275561a2016-02-23 10:11:02 -0500420 }
421
422 private int calculateCurrentDelay() {
423
424 // Shouldn't take more than 25 days to launch an app, so int is fine here.
Alison Cichowlasb7f67ab2017-04-25 18:04:40 -0400425 return (int) (SystemClock.uptimeMillis() - mCurrentTransitionStartTime);
Jorim Jaggi275561a2016-02-23 10:11:02 -0500426 }
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800427
Sudheer Shankac766db02017-06-12 10:37:29 -0700428 private int calculateDelay(long timestamp) {
429 // Shouldn't take more than 25 days to launch an app, so int is fine here.
430 return (int) (timestamp - mCurrentTransitionStartTime);
431 }
432
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100433 private void logAppTransitionCancel(WindowingModeTransitionInfo info) {
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200434 final int type = getTransitionType(info);
435 if (type == -1) {
436 return;
437 }
438 final LogMaker builder = new LogMaker(APP_TRANSITION_CANCELLED);
439 builder.setPackageName(info.launchedActivity.packageName);
440 builder.setType(type);
441 builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name);
442 mMetricsLogger.write(builder);
Olivier Gaillardaed7f122017-12-12 14:26:22 +0000443 StatsLog.write(
444 StatsLog.APP_START_CANCEL_CHANGED,
445 info.launchedActivity.appInfo.uid,
446 info.launchedActivity.packageName,
447 convertAppStartTransitionType(type),
448 info.launchedActivity.info.name);
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200449 }
450
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800451 private void logAppTransitionMultiEvents() {
Jorim Jaggi172e99f2017-10-20 14:33:18 +0200452 if (DEBUG_METRICS) Slog.i(TAG, "logging transition events");
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100453 for (int index = mWindowingModeTransitionInfo.size() - 1; index >= 0; index--) {
454 final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.valueAt(index);
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800455 final int type = getTransitionType(info);
456 if (type == -1) {
457 return;
458 }
Narayan Kamath203a9ab2018-02-20 17:06:21 +0000459 final LogMaker builder = new LogMaker(APP_TRANSITION);
460 builder.setPackageName(info.launchedActivity.packageName);
461 builder.setType(type);
462 builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name);
463 final boolean isInstantApp = info.launchedActivity.info.applicationInfo.isInstantApp();
464 if (info.launchedActivity.launchedFromPackage != null) {
465 builder.addTaggedData(APP_TRANSITION_CALLING_PACKAGE_NAME,
466 info.launchedActivity.launchedFromPackage);
467 }
468 String launchToken = info.launchedActivity.info.launchToken;
469 if (launchToken != null) {
470 builder.addTaggedData(FIELD_INSTANT_APP_LAUNCH_TOKEN, launchToken);
471 info.launchedActivity.info.launchToken = null;
472 }
473 builder.addTaggedData(APP_TRANSITION_IS_EPHEMERAL, isInstantApp ? 1 : 0);
474 builder.addTaggedData(APP_TRANSITION_DEVICE_UPTIME_SECONDS,
475 mCurrentTransitionDeviceUptime);
476 builder.addTaggedData(APP_TRANSITION_DELAY_MS, mCurrentTransitionDelayMs);
477 builder.setSubtype(info.reason);
478 if (info.startingWindowDelayMs != -1) {
479 builder.addTaggedData(APP_TRANSITION_STARTING_WINDOW_DELAY_MS,
480 info.startingWindowDelayMs);
481 }
482 if (info.bindApplicationDelayMs != -1) {
483 builder.addTaggedData(APP_TRANSITION_BIND_APPLICATION_DELAY_MS,
484 info.bindApplicationDelayMs);
485 }
486 builder.addTaggedData(APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS, info.windowsDrawnDelayMs);
487 mMetricsLogger.write(builder);
488 StatsLog.write(
489 StatsLog.APP_START_CHANGED,
490 info.launchedActivity.appInfo.uid,
491 info.launchedActivity.packageName,
492 convertAppStartTransitionType(type),
493 info.launchedActivity.info.name,
494 info.launchedActivity.launchedFromPackage,
495 isInstantApp,
496 mCurrentTransitionDeviceUptime * 1000,
497 info.reason,
498 mCurrentTransitionDelayMs,
499 info.startingWindowDelayMs,
500 info.bindApplicationDelayMs,
501 info.windowsDrawnDelayMs,
502 launchToken);
503 mHandler.obtainMessage(MSG_LOG_APP_START_MEMORY_STATE_CAPTURE, info).sendToTarget();
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800504 }
505 }
506
Olivier Gaillardaed7f122017-12-12 14:26:22 +0000507 private int convertAppStartTransitionType(int tronType) {
508 if (tronType == TYPE_TRANSITION_COLD_LAUNCH) {
509 return StatsLog.APP_START_CHANGED__TYPE__COLD;
510 }
511 if (tronType == TYPE_TRANSITION_WARM_LAUNCH) {
512 return StatsLog.APP_START_CHANGED__TYPE__WARM;
513 }
514 if (tronType == TYPE_TRANSITION_HOT_LAUNCH) {
515 return StatsLog.APP_START_CHANGED__TYPE__HOT;
516 }
517 return StatsLog.APP_START_CHANGED__TYPE__APP_START_TRANSITION_TYPE_UNKNOWN;
518 }
519
Jorim Jaggi4d27b842017-08-17 17:22:26 +0200520 void logAppTransitionReportedDrawn(ActivityRecord r, boolean restoredFromBundle) {
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100521 final WindowingModeTransitionInfo info = mLastWindowingModeTransitionInfo.get(
522 r.getWindowingMode());
Jorim Jaggi4d27b842017-08-17 17:22:26 +0200523 if (info == null) {
524 return;
525 }
526 final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN);
527 builder.setPackageName(r.packageName);
528 builder.addTaggedData(FIELD_CLASS_NAME, r.info.name);
Olivier Gaillardaed7f122017-12-12 14:26:22 +0000529 long startupTimeMs = SystemClock.uptimeMillis() - mLastTransitionStartTime;
530 builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS, startupTimeMs);
Jorim Jaggi4d27b842017-08-17 17:22:26 +0200531 builder.setType(restoredFromBundle
532 ? TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE
533 : TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE);
534 builder.addTaggedData(APP_TRANSITION_PROCESS_RUNNING,
535 info.currentTransitionProcessRunning ? 1 : 0);
536 mMetricsLogger.write(builder);
Olivier Gaillardaed7f122017-12-12 14:26:22 +0000537 StatsLog.write(
538 StatsLog.APP_START_FULLY_DRAWN_CHANGED,
539 info.launchedActivity.appInfo.uid,
540 info.launchedActivity.packageName,
541 restoredFromBundle
542 ? StatsLog.APP_START_FULLY_DRAWN_CHANGED__TYPE__WITH_BUNDLE
543 : StatsLog.APP_START_FULLY_DRAWN_CHANGED__TYPE__WITHOUT_BUNDLE,
544 info.launchedActivity.info.name,
545 info.currentTransitionProcessRunning,
546 startupTimeMs);
Jorim Jaggi4d27b842017-08-17 17:22:26 +0200547 }
548
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100549 private int getTransitionType(WindowingModeTransitionInfo info) {
Jorim Jaggi3878ca32017-02-02 17:13:05 -0800550 if (info.currentTransitionProcessRunning) {
551 if (info.startResult == START_SUCCESS) {
552 return TYPE_TRANSITION_WARM_LAUNCH;
553 } else if (info.startResult == START_TASK_TO_FRONT) {
554 return TYPE_TRANSITION_HOT_LAUNCH;
555 }
556 } else if (info.startResult == START_SUCCESS) {
557 return TYPE_TRANSITION_COLD_LAUNCH;
558 }
559 return -1;
560 }
Ng Zhi Anbbefdec2018-01-30 17:12:39 -0800561
Jorim Jaggi9b58f2d2018-02-19 17:48:44 +0100562 private void logAppStartMemoryStateCapture(WindowingModeTransitionInfo info) {
Ng Zhi Anbbefdec2018-01-30 17:12:39 -0800563 final ProcessRecord processRecord = findProcessForActivity(info.launchedActivity);
564 if (processRecord == null) {
565 if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture processRecord null");
566 return;
567 }
568
569 final int pid = processRecord.pid;
570 final int uid = info.launchedActivity.appInfo.uid;
571 final MemoryStat memoryStat = readMemoryStatFromMemcg(uid, pid);
572 if (memoryStat == null) {
573 if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture memoryStat null");
574 return;
575 }
576
577 StatsLog.write(
578 StatsLog.APP_START_MEMORY_STATE_CAPTURED,
579 uid,
580 info.launchedActivity.processName,
581 info.launchedActivity.info.name,
582 memoryStat.pgfault,
583 memoryStat.pgmajfault,
584 memoryStat.rssInBytes,
585 memoryStat.cacheInBytes,
586 memoryStat.swapInBytes);
587 }
588
589 private ProcessRecord findProcessForActivity(ActivityRecord launchedActivity) {
590 return launchedActivity != null
591 ? mSupervisor.mService.mProcessNames.get(launchedActivity.processName,
592 launchedActivity.appInfo.uid)
593 : null;
594 }
Filip Gruszczynski77d94482015-12-11 13:59:52 -0800595}