• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.server.wm;
2 
3 import static android.app.ActivityManager.START_SUCCESS;
4 import static android.app.ActivityManager.START_TASK_TO_FRONT;
5 import static android.app.ActivityManager.processStateAmToProto;
6 import static android.app.WaitResult.INVALID_DELAY;
7 import static android.app.WaitResult.LAUNCH_STATE_COLD;
8 import static android.app.WaitResult.LAUNCH_STATE_HOT;
9 import static android.app.WaitResult.LAUNCH_STATE_RELAUNCH;
10 import static android.app.WaitResult.LAUNCH_STATE_WARM;
11 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
12 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
13 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
14 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
15 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
16 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
17 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
18 
19 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_ACTIVITY_START;
20 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION;
21 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_BIND_APPLICATION_DELAY_MS;
22 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CALLING_PACKAGE_NAME;
23 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CANCELLED;
24 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS;
25 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS;
26 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_IS_EPHEMERAL;
27 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_PROCESS_RUNNING;
28 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN;
29 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN_MS;
30 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_STARTING_WINDOW_DELAY_MS;
31 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS;
32 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_PACKAGE_NAME;
33 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_UID;
34 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_UID_HAS_ANY_VISIBLE_WINDOW;
35 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_UID_PROC_STATE;
36 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CLASS_NAME;
37 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_COMING_FROM_PENDING_INTENT;
38 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INSTANT_APP_LAUNCH_TOKEN;
39 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INTENT_ACTION;
40 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_CUR_PROC_STATE;
41 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_CLIENT_ACTIVITIES;
42 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_FOREGROUND_ACTIVITIES;
43 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_FOREGROUND_SERVICES;
44 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_OVERLAY_UI;
45 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_TOP_UI;
46 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_MILLIS_SINCE_FG_INTERACTION;
47 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_MILLIS_SINCE_LAST_INTERACTION_EVENT;
48 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_MILLIS_SINCE_UNIMPORTANT;
49 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_PENDING_UI_CLEAN;
50 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_PROCESS_NAME;
51 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID;
52 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID_HAS_ANY_VISIBLE_WINDOW;
53 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID_PROC_STATE;
54 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_SHORT_COMPONENT_NAME;
55 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PACKAGE_OPTIMIZATION_COMPILATION_FILTER;
56 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PACKAGE_OPTIMIZATION_COMPILATION_REASON;
57 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_COLD_LAUNCH;
58 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_HOT_LAUNCH;
59 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE;
60 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE;
61 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
62 import static com.android.server.am.MemoryStatUtil.MemoryStat;
63 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
64 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_METRICS;
65 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
66 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
67 import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT;
68 import static com.android.server.wm.EventLogTags.WM_ACTIVITY_LAUNCH_TIME;
69 
70 import android.annotation.NonNull;
71 import android.annotation.Nullable;
72 import android.app.ActivityOptions;
73 import android.app.ActivityOptions.SourceInfo;
74 import android.app.WaitResult;
75 import android.app.WindowConfiguration.WindowingMode;
76 import android.content.ComponentName;
77 import android.content.Intent;
78 import android.content.pm.ApplicationInfo;
79 import android.content.pm.IncrementalStatesInfo;
80 import android.content.pm.dex.ArtManagerInternal;
81 import android.content.pm.dex.PackageOptimizationInfo;
82 import android.metrics.LogMaker;
83 import android.os.Handler;
84 import android.os.Looper;
85 import android.os.SystemClock;
86 import android.os.Trace;
87 import android.os.incremental.IncrementalManager;
88 import android.util.ArrayMap;
89 import android.util.EventLog;
90 import android.util.Log;
91 import android.util.Slog;
92 import android.util.TimeUtils;
93 import android.util.proto.ProtoOutputStream;
94 
95 import com.android.internal.annotations.VisibleForTesting;
96 import com.android.internal.logging.MetricsLogger;
97 import com.android.internal.util.FrameworkStatsLog;
98 import com.android.internal.util.function.pooled.PooledLambda;
99 import com.android.server.FgThread;
100 import com.android.server.LocalServices;
101 import com.android.server.apphibernation.AppHibernationManagerInternal;
102 import com.android.server.apphibernation.AppHibernationService;
103 
104 import java.util.ArrayList;
105 import java.util.concurrent.TimeUnit;
106 
107 /**
108  * Listens to activity launches, transitions, visibility changes and window drawn callbacks to
109  * determine app launch times and draw delays. Source of truth for activity metrics and provides
110  * data for Tron, logcat, event logs and {@link android.app.WaitResult}.
111  * <p>
112  * A typical sequence of a launch event could be:
113  * {@link #notifyActivityLaunching}, {@link #notifyActivityLaunched},
114  * {@link #notifyStartingWindowDrawn} (optional), {@link #notifyTransitionStarting}
115  * {@link #notifyWindowsDrawn}.
116  * <p>
117  * Tests:
118  * atest CtsWindowManagerDeviceTestCases:ActivityMetricsLoggerTests
119  */
120 class ActivityMetricsLogger {
121 
122     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityMetricsLogger" : TAG_ATM;
123 
124     // Window modes we are interested in logging. If we ever introduce a new type, we need to add
125     // a value here and increase the {@link #TRON_WINDOW_STATE_VARZ_STRINGS} array.
126     private static final int WINDOW_STATE_STANDARD = 0;
127     private static final int WINDOW_STATE_SIDE_BY_SIDE = 1;
128     private static final int WINDOW_STATE_FREEFORM = 2;
129     private static final int WINDOW_STATE_ASSISTANT = 3;
130     private static final int WINDOW_STATE_MULTI_WINDOW = 4;
131     private static final int WINDOW_STATE_INVALID = -1;
132 
133     /**
134      * If a launching activity isn't visible within this duration when the device is sleeping, e.g.
135      * keyguard is locked, its transition info will be dropped.
136      */
137     private static final long UNKNOWN_VISIBILITY_CHECK_DELAY_MS = 3000;
138 
139     /**
140      * The flag for {@link #notifyActivityLaunching} to skip associating a new launch with an active
141      * transition, in the case the launch is standalone (e.g. from recents).
142      */
143     private static final int IGNORE_CALLER = -1;
144 
145     // Preallocated strings we are sending to tron, so we don't have to allocate a new one every
146     // time we log.
147     private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = {
148             "window_time_0", "window_time_1", "window_time_2", "window_time_3", "window_time_4"};
149 
150     private int mWindowState = WINDOW_STATE_STANDARD;
151     private long mLastLogTimeSecs;
152     private final ActivityTaskSupervisor mSupervisor;
153     private final MetricsLogger mMetricsLogger = new MetricsLogger();
154     private final Handler mLoggerHandler = FgThread.getHandler();
155 
156     /** All active transitions. */
157     private final ArrayList<TransitionInfo> mTransitionInfoList = new ArrayList<>();
158     /** Map : Last launched activity => {@link TransitionInfo} */
159     private final ArrayMap<ActivityRecord, TransitionInfo> mLastTransitionInfo = new ArrayMap<>();
160 
161     private ArtManagerInternal mArtManagerInternal;
162     private final StringBuilder mStringBuilder = new StringBuilder();
163 
164     /**
165      * Due to the global single concurrent launch sequence, all calls to this observer must be made
166      * in-order on the same thread to fulfill the "happens-before" guarantee in LaunchObserver.
167      */
168     private final LaunchObserverRegistryImpl mLaunchObserver;
169     @VisibleForTesting static final int LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE = 512;
170     private final ArrayMap<String, Boolean> mLastHibernationStates = new ArrayMap<>();
171     private AppHibernationManagerInternal mAppHibernationManagerInternal;
172 
173     /**
174      * The information created when an intent is incoming but we do not yet know whether it will be
175      * launched successfully.
176      */
177     static final class LaunchingState {
178         /** The device uptime of {@link #notifyActivityLaunching}. */
179         private final long mCurrentUpTimeMs = SystemClock.uptimeMillis();
180         /** The timestamp of {@link #notifyActivityLaunching}. */
181         private long mCurrentTransitionStartTimeNs;
182         /** Non-null when a {@link TransitionInfo} is created for this state. */
183         private TransitionInfo mAssociatedTransitionInfo;
184 
185         @VisibleForTesting
allDrawn()186         boolean allDrawn() {
187             return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.allDrawn();
188         }
189 
contains(ActivityRecord r)190         boolean contains(ActivityRecord r) {
191             return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.contains(r);
192         }
193     }
194 
195     /** The information created when an activity is confirmed to be launched. */
196     private static final class TransitionInfo {
197         /**
198          * The field to lookup and update an existing transition efficiently between
199          * {@link #notifyActivityLaunching} and {@link #notifyActivityLaunched}.
200          *
201          * @see LaunchingState#mAssociatedTransitionInfo
202          */
203         final LaunchingState mLaunchingState;
204         /**
205          * The timestamp of the first {@link #notifyActivityLaunching}. It can be used as a key for
206          * observer to identify which callbacks belong to a launch event.
207          */
208         final long mTransitionStartTimeNs;
209         /** The device uptime in millis when this transition info is created. */
210         final long mTransitionDeviceUptimeMs;
211         /** The type can be cold (new process), warm (new activity), or hot (bring to front). */
212         final int mTransitionType;
213         /** Whether the process was already running when the transition started. */
214         final boolean mProcessRunning;
215         /** whether the process of the launching activity didn't have any active activity. */
216         final boolean mProcessSwitch;
217         /** The activities that should be drawn. */
218         final ArrayList<ActivityRecord> mPendingDrawActivities = new ArrayList<>(2);
219         /** The latest activity to have been launched. */
220         @NonNull ActivityRecord mLastLaunchedActivity;
221 
222         /** The type of the source that triggers the launch event. */
223         @SourceInfo.SourceType int mSourceType;
224         /** The time from the source event (e.g. touch) to {@link #notifyActivityLaunching}. */
225         int mSourceEventDelayMs = INVALID_DELAY;
226         /** The time from {@link #mTransitionStartTimeNs} to {@link #notifyTransitionStarting}. */
227         int mCurrentTransitionDelayMs;
228         /** The time from {@link #mTransitionStartTimeNs} to {@link #notifyStartingWindowDrawn}. */
229         int mStartingWindowDelayMs = INVALID_DELAY;
230         /** The time from {@link #mTransitionStartTimeNs} to {@link #notifyBindApplication}. */
231         int mBindApplicationDelayMs = INVALID_DELAY;
232         /** Elapsed time from when we launch an activity to when its windows are drawn. */
233         int mWindowsDrawnDelayMs;
234         /** The reason why the transition started (see ActivityManagerInternal.APP_TRANSITION_*). */
235         int mReason = APP_TRANSITION_TIMEOUT;
236         /** The flag ensures that {@link #mStartingWindowDelayMs} is only set once. */
237         boolean mLoggedStartingWindowDrawn;
238         /** If the any app transitions have been logged as starting. */
239         boolean mLoggedTransitionStarting;
240         /** Whether any activity belonging to this transition has relaunched. */
241         boolean mRelaunched;
242 
243         /** Non-null if the application has reported drawn but its window hasn't. */
244         @Nullable Runnable mPendingFullyDrawn;
245         /** Non-null if the trace is active. */
246         @Nullable String mLaunchTraceName;
247 
248         /** @return Non-null if there will be a window drawn event for the launch. */
249         @Nullable
create(@onNull ActivityRecord r, @NonNull LaunchingState launchingState, @Nullable ActivityOptions options, boolean processRunning, boolean processSwitch, boolean newActivityCreated, int startResult)250         static TransitionInfo create(@NonNull ActivityRecord r,
251                 @NonNull LaunchingState launchingState, @Nullable ActivityOptions options,
252                 boolean processRunning, boolean processSwitch, boolean newActivityCreated,
253                 int startResult) {
254             if (startResult != START_SUCCESS && startResult != START_TASK_TO_FRONT) {
255                 return null;
256             }
257             final int transitionType;
258             if (processRunning) {
259                 transitionType = !newActivityCreated && r.attachedToProcess()
260                         ? TYPE_TRANSITION_HOT_LAUNCH
261                         : TYPE_TRANSITION_WARM_LAUNCH;
262             } else {
263                 // Task may still exist when cold launching an activity and the start result will be
264                 // set to START_TASK_TO_FRONT. Treat this as a COLD launch.
265                 transitionType = TYPE_TRANSITION_COLD_LAUNCH;
266             }
267             return new TransitionInfo(r, launchingState, options, transitionType, processRunning,
268                     processSwitch);
269         }
270 
271         /** Use {@link TransitionInfo#create} instead to ensure the transition type is valid. */
TransitionInfo(ActivityRecord r, LaunchingState launchingState, ActivityOptions options, int transitionType, boolean processRunning, boolean processSwitch)272         private TransitionInfo(ActivityRecord r, LaunchingState launchingState,
273                 ActivityOptions options, int transitionType, boolean processRunning,
274                 boolean processSwitch) {
275             mLaunchingState = launchingState;
276             mTransitionStartTimeNs = launchingState.mCurrentTransitionStartTimeNs;
277             mTransitionType = transitionType;
278             mProcessRunning = processRunning;
279             mProcessSwitch = processSwitch;
280             mTransitionDeviceUptimeMs = launchingState.mCurrentUpTimeMs;
281             setLatestLaunchedActivity(r);
282             launchingState.mAssociatedTransitionInfo = this;
283             if (options != null) {
284                 final SourceInfo sourceInfo = options.getSourceInfo();
285                 if (sourceInfo != null) {
286                     mSourceType = sourceInfo.type;
287                     mSourceEventDelayMs =
288                             (int) (launchingState.mCurrentUpTimeMs - sourceInfo.eventTimeMs);
289                 }
290             }
291         }
292 
293         /**
294          * Remembers the latest launched activity to represent the final transition. This also
295          * tracks the activities that should be drawn, so a consecutive launching sequence can be
296          * coalesced as one event.
297          */
setLatestLaunchedActivity(ActivityRecord r)298         void setLatestLaunchedActivity(ActivityRecord r) {
299             if (mLastLaunchedActivity == r) {
300                 return;
301             }
302             if (mLastLaunchedActivity != null) {
303                 // Transfer the launch cookie because it is a consecutive launch event.
304                 r.mLaunchCookie = mLastLaunchedActivity.mLaunchCookie;
305                 mLastLaunchedActivity.mLaunchCookie = null;
306             }
307             mLastLaunchedActivity = r;
308             if (!r.noDisplay && !r.isReportedDrawn()) {
309                 if (DEBUG_METRICS) Slog.i(TAG, "Add pending draw " + r);
310                 mPendingDrawActivities.add(r);
311             }
312         }
313 
314         /** Returns {@code true} if the incoming activity can belong to this transition. */
canCoalesce(ActivityRecord r)315         boolean canCoalesce(ActivityRecord r) {
316             return mLastLaunchedActivity.mDisplayContent == r.mDisplayContent
317                     && mLastLaunchedActivity.getWindowingMode() == r.getWindowingMode();
318         }
319 
320         /** @return {@code true} if the activity matches a launched activity in this transition. */
contains(ActivityRecord r)321         boolean contains(ActivityRecord r) {
322             return r != null && (r == mLastLaunchedActivity || mPendingDrawActivities.contains(r));
323         }
324 
325         /** Called when the activity is drawn or won't be drawn. */
removePendingDrawActivity(ActivityRecord r)326         void removePendingDrawActivity(ActivityRecord r) {
327             if (DEBUG_METRICS) Slog.i(TAG, "Remove pending draw " + r);
328             mPendingDrawActivities.remove(r);
329         }
330 
allDrawn()331         boolean allDrawn() {
332             return mPendingDrawActivities.isEmpty();
333         }
334 
335         /** Only keep the records which can be drawn. */
updatePendingDraw()336         void updatePendingDraw() {
337             for (int i = mPendingDrawActivities.size() - 1; i >= 0; i--) {
338                 final ActivityRecord r = mPendingDrawActivities.get(i);
339                 if (!r.mVisibleRequested) {
340                     if (DEBUG_METRICS) Slog.i(TAG, "Discard pending draw " + r);
341                     mPendingDrawActivities.remove(i);
342                 }
343             }
344         }
345 
346         /**
347          * @return {@code true} if the transition info should be sent to MetricsLogger, StatsLog, or
348          *         LaunchObserver.
349          */
isInterestingToLoggerAndObserver()350         boolean isInterestingToLoggerAndObserver() {
351             return mProcessSwitch;
352         }
353 
calculateCurrentDelay()354         int calculateCurrentDelay() {
355             return calculateDelay(SystemClock.elapsedRealtimeNanos());
356         }
357 
calculateDelay(long timestampNs)358         int calculateDelay(long timestampNs) {
359             // Shouldn't take more than 25 days to launch an app, so int is fine here.
360             return (int) TimeUnit.NANOSECONDS.toMillis(timestampNs - mTransitionStartTimeNs);
361         }
362 
363         @Override
toString()364         public String toString() {
365             return "TransitionInfo{" + Integer.toHexString(System.identityHashCode(this))
366                     + " a=" + mLastLaunchedActivity + " ua=" + mPendingDrawActivities + "}";
367         }
368     }
369 
370     static final class TransitionInfoSnapshot {
371         final private ApplicationInfo applicationInfo;
372         final private WindowProcessController processRecord;
373         final String packageName;
374         final String launchedActivityName;
375         final private String launchedActivityLaunchedFromPackage;
376         final private String launchedActivityLaunchToken;
377         final private String launchedActivityAppRecordRequiredAbi;
378         final String launchedActivityShortComponentName;
379         final private String processName;
380         @VisibleForTesting final @SourceInfo.SourceType int sourceType;
381         @VisibleForTesting final int sourceEventDelayMs;
382         final private int reason;
383         final private int startingWindowDelayMs;
384         final private int bindApplicationDelayMs;
385         final int windowsDrawnDelayMs;
386         final int type;
387         final int userId;
388         /**
389          * Elapsed time from when we launch an activity to when the app reported it was
390          * fully drawn. If this is not reported then the value is set to INVALID_DELAY.
391          */
392         final int windowsFullyDrawnDelayMs;
393         final int activityRecordIdHashCode;
394         final boolean relaunched;
395 
TransitionInfoSnapshot(TransitionInfo info)396         private TransitionInfoSnapshot(TransitionInfo info) {
397             this(info, info.mLastLaunchedActivity, INVALID_DELAY);
398         }
399 
TransitionInfoSnapshot(TransitionInfo info, ActivityRecord launchedActivity, int windowsFullyDrawnDelayMs)400         private TransitionInfoSnapshot(TransitionInfo info, ActivityRecord launchedActivity,
401                 int windowsFullyDrawnDelayMs) {
402             applicationInfo = launchedActivity.info.applicationInfo;
403             packageName = launchedActivity.packageName;
404             launchedActivityName = launchedActivity.info.name;
405             launchedActivityLaunchedFromPackage = launchedActivity.launchedFromPackage;
406             launchedActivityLaunchToken = launchedActivity.info.launchToken;
407             launchedActivityAppRecordRequiredAbi = launchedActivity.app == null
408                     ? null
409                     : launchedActivity.app.getRequiredAbi();
410             reason = info.mReason;
411             sourceEventDelayMs = info.mSourceEventDelayMs;
412             startingWindowDelayMs = info.mStartingWindowDelayMs;
413             bindApplicationDelayMs = info.mBindApplicationDelayMs;
414             windowsDrawnDelayMs = info.mWindowsDrawnDelayMs;
415             type = info.mTransitionType;
416             processRecord = launchedActivity.app;
417             processName = launchedActivity.processName;
418             sourceType = info.mSourceType;
419             userId = launchedActivity.mUserId;
420             launchedActivityShortComponentName = launchedActivity.shortComponentName;
421             activityRecordIdHashCode = System.identityHashCode(launchedActivity);
422             this.windowsFullyDrawnDelayMs = windowsFullyDrawnDelayMs;
423             relaunched = info.mRelaunched;
424         }
425 
getLaunchState()426         @WaitResult.LaunchState int getLaunchState() {
427             switch (type) {
428                 case TYPE_TRANSITION_WARM_LAUNCH:
429                     return LAUNCH_STATE_WARM;
430                 case TYPE_TRANSITION_HOT_LAUNCH:
431                     return relaunched ? LAUNCH_STATE_RELAUNCH : LAUNCH_STATE_HOT;
432                 case TYPE_TRANSITION_COLD_LAUNCH:
433                     return LAUNCH_STATE_COLD;
434                 default:
435                     return -1;
436             }
437         }
438 
getPackageOptimizationInfo(ArtManagerInternal artManagerInternal)439         PackageOptimizationInfo getPackageOptimizationInfo(ArtManagerInternal artManagerInternal) {
440             return artManagerInternal == null || launchedActivityAppRecordRequiredAbi == null
441                     ? PackageOptimizationInfo.createWithNoInfo()
442                     : artManagerInternal.getPackageOptimizationInfo(applicationInfo,
443                             launchedActivityAppRecordRequiredAbi, launchedActivityName);
444         }
445     }
446 
ActivityMetricsLogger(ActivityTaskSupervisor supervisor, Looper looper)447     ActivityMetricsLogger(ActivityTaskSupervisor supervisor, Looper looper) {
448         mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
449         mSupervisor = supervisor;
450         mLaunchObserver = new LaunchObserverRegistryImpl(looper);
451     }
452 
logWindowState()453     void logWindowState() {
454         final long now = SystemClock.elapsedRealtime() / 1000;
455         if (mWindowState != WINDOW_STATE_INVALID) {
456             // We log even if the window state hasn't changed, because the user might remain in
457             // home/fullscreen move forever and we would like to track this kind of behavior
458             // too.
459             mMetricsLogger.count(TRON_WINDOW_STATE_VARZ_STRINGS[mWindowState],
460                     (int) (now - mLastLogTimeSecs));
461         }
462         mLastLogTimeSecs = now;
463 
464         mWindowState = WINDOW_STATE_INVALID;
465         Task rootTask = mSupervisor.mRootWindowContainer.getTopDisplayFocusedRootTask();
466         if (rootTask == null) {
467             return;
468         }
469 
470         if (rootTask.isActivityTypeAssistant()) {
471             mWindowState = WINDOW_STATE_ASSISTANT;
472             return;
473         }
474 
475         @WindowingMode int windowingMode = rootTask.getWindowingMode();
476         if (windowingMode == WINDOWING_MODE_PINNED) {
477             rootTask = mSupervisor.mRootWindowContainer.findRootTaskBehind(rootTask);
478             windowingMode = rootTask.getWindowingMode();
479         }
480         switch (windowingMode) {
481             case WINDOWING_MODE_FULLSCREEN:
482                 mWindowState = WINDOW_STATE_STANDARD;
483                 break;
484             case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
485             case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
486                 mWindowState = WINDOW_STATE_SIDE_BY_SIDE;
487                 break;
488             case WINDOWING_MODE_FREEFORM:
489                 mWindowState = WINDOW_STATE_FREEFORM;
490                 break;
491             case WINDOWING_MODE_MULTI_WINDOW:
492                 mWindowState = WINDOW_STATE_MULTI_WINDOW;
493                 break;
494             default:
495                 if (windowingMode != WINDOWING_MODE_UNDEFINED) {
496                     throw new IllegalStateException("Unknown windowing mode for task=" + rootTask
497                             + " windowingMode=" + windowingMode);
498                 }
499         }
500     }
501 
502     /** @return Non-null {@link TransitionInfo} if the activity is found in an active transition. */
503     @Nullable
getActiveTransitionInfo(ActivityRecord r)504     private TransitionInfo getActiveTransitionInfo(ActivityRecord r) {
505         for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
506             final TransitionInfo info = mTransitionInfoList.get(i);
507             if (info.contains(r)) {
508                 return info;
509             }
510         }
511         return null;
512     }
513 
514     /**
515      * This method should be only used by starting recents and starting from recents, or internal
516      * tests. Because it doesn't lookup caller and always creates a new launching state.
517      *
518      * @see #notifyActivityLaunching(Intent, ActivityRecord, int)
519      */
notifyActivityLaunching(Intent intent)520     LaunchingState notifyActivityLaunching(Intent intent) {
521         return notifyActivityLaunching(intent, null /* caller */, IGNORE_CALLER);
522     }
523 
524     /**
525      * Notifies the tracker at the earliest possible point when we are starting to launch an
526      * activity. The caller must ensure that {@link #notifyActivityLaunched} will be called later
527      * with the returned {@link LaunchingState}. If the caller is found in an active transition,
528      * it will be considered as consecutive launch and coalesced into the active transition.
529      */
notifyActivityLaunching(Intent intent, @Nullable ActivityRecord caller, int callingUid)530     LaunchingState notifyActivityLaunching(Intent intent, @Nullable ActivityRecord caller,
531             int callingUid) {
532         final long transitionStartTimeNs = SystemClock.elapsedRealtimeNanos();
533         TransitionInfo existingInfo = null;
534         if (callingUid != IGNORE_CALLER) {
535             // Associate the launching event to an active transition if the caller is found in its
536             // launched activities.
537             for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
538                 final TransitionInfo info = mTransitionInfoList.get(i);
539                 if (caller != null && info.contains(caller)) {
540                     existingInfo = info;
541                     break;
542                 }
543                 if (existingInfo == null && callingUid == info.mLastLaunchedActivity.getUid()) {
544                     // Fallback to check the most recent matched uid for the case that the caller is
545                     // not an activity.
546                     existingInfo = info;
547                 }
548             }
549         }
550         if (DEBUG_METRICS) {
551             Slog.i(TAG, "notifyActivityLaunching intent=" + intent
552                     + " existingInfo=" + existingInfo);
553         }
554 
555         if (existingInfo == null) {
556             // Only notify the observer for a new launching event.
557             launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);
558             final LaunchingState launchingState = new LaunchingState();
559             launchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
560             return launchingState;
561         }
562         existingInfo.mLaunchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
563         return existingInfo.mLaunchingState;
564     }
565 
566     /**
567      * Notifies the tracker that the activity is actually launching.
568      *
569      * @param launchingState The launching state to track the new or active transition.
570      * @param resultCode One of the {@link android.app.ActivityManager}.START_* flags, indicating
571      *                   the result of the launch.
572      * @param launchedActivity The activity that is being launched
573      * @param newActivityCreated Whether a new activity instance is created.
574      * @param options The given options of the launching activity.
575      */
notifyActivityLaunched(@onNull LaunchingState launchingState, int resultCode, boolean newActivityCreated, @Nullable ActivityRecord launchedActivity, @Nullable ActivityOptions options)576     void notifyActivityLaunched(@NonNull LaunchingState launchingState, int resultCode,
577             boolean newActivityCreated, @Nullable ActivityRecord launchedActivity,
578             @Nullable ActivityOptions options) {
579         if (launchedActivity == null) {
580             // The launch is aborted, e.g. intent not resolved, class not found.
581             abort(null /* info */, "nothing launched");
582             return;
583         }
584 
585         final WindowProcessController processRecord = launchedActivity.app != null
586                 ? launchedActivity.app
587                 : mSupervisor.mService.getProcessController(
588                         launchedActivity.processName, launchedActivity.info.applicationInfo.uid);
589         // Whether the process that will contains the activity is already running.
590         final boolean processRunning = processRecord != null;
591         // We consider this a "process switch" if the process of the activity that gets launched
592         // didn't have an activity that was in started state. In this case, we assume that lot
593         // of caches might be purged so the time until it produces the first frame is very
594         // interesting.
595         final boolean processSwitch = !processRunning
596                 || !processRecord.hasStartedActivity(launchedActivity);
597 
598         final TransitionInfo info = launchingState.mAssociatedTransitionInfo;
599         if (DEBUG_METRICS) {
600             Slog.i(TAG, "notifyActivityLaunched" + " resultCode=" + resultCode
601                     + " launchedActivity=" + launchedActivity + " processRunning=" + processRunning
602                     + " processSwitch=" + processSwitch
603                     + " newActivityCreated=" + newActivityCreated + " info=" + info);
604         }
605 
606         if (launchedActivity.isReportedDrawn() && launchedActivity.isVisible()) {
607             // Launched activity is already visible. We cannot measure windows drawn delay.
608             abort(info, "launched activity already visible");
609             return;
610         }
611 
612         // If the launched activity is started from an existing active transition, it will be put
613         // into the transition info.
614         if (info != null && info.canCoalesce(launchedActivity)) {
615             if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched consecutive launch");
616 
617             final boolean crossPackage =
618                     !info.mLastLaunchedActivity.packageName.equals(launchedActivity.packageName);
619             // The trace name uses package name so different packages should be separated.
620             if (crossPackage) {
621                 stopLaunchTrace(info);
622             }
623 
624             mLastTransitionInfo.remove(info.mLastLaunchedActivity);
625             // Coalesce multiple (trampoline) activities from a single sequence together.
626             info.setLatestLaunchedActivity(launchedActivity);
627             // Update the latest one so it can be found when reporting fully-drawn.
628             mLastTransitionInfo.put(launchedActivity, info);
629 
630             if (crossPackage) {
631                 startLaunchTrace(info);
632             }
633             return;
634         }
635 
636         final TransitionInfo newInfo = TransitionInfo.create(launchedActivity, launchingState,
637                 options, processRunning, processSwitch, newActivityCreated, resultCode);
638         if (newInfo == null) {
639             abort(info, "unrecognized launch");
640             return;
641         }
642 
643         if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched successful");
644         // A new launch sequence has begun. Start tracking it.
645         mTransitionInfoList.add(newInfo);
646         mLastTransitionInfo.put(launchedActivity, newInfo);
647         startLaunchTrace(newInfo);
648         if (newInfo.isInterestingToLoggerAndObserver()) {
649             launchObserverNotifyActivityLaunched(newInfo);
650         } else {
651             // As abort for no process switch.
652             launchObserverNotifyIntentFailed();
653         }
654         if (launchedActivity.mDisplayContent.isSleeping()) {
655             // It is unknown whether the activity can be drawn or not, e.g. it depends on the
656             // keyguard states and the attributes or flags set by the activity. If the activity
657             // keeps invisible in the grace period, the tracker will be cancelled so it won't get
658             // a very long launch time that takes unlocking as the end of launch.
659             scheduleCheckActivityToBeDrawn(launchedActivity, UNKNOWN_VISIBILITY_CHECK_DELAY_MS);
660         }
661 
662         // If the previous transitions are no longer visible, abort them to avoid counting the
663         // launch time when resuming from back stack. E.g. launch 2 independent tasks in a short
664         // time, the transition info of the first task should not keep active until it becomes
665         // visible such as after the top task is finished.
666         for (int i = mTransitionInfoList.size() - 2; i >= 0; i--) {
667             final TransitionInfo prevInfo = mTransitionInfoList.get(i);
668             prevInfo.updatePendingDraw();
669             if (prevInfo.allDrawn()) {
670                 abort(prevInfo, "nothing will be drawn");
671             }
672         }
673     }
674 
675     /**
676      * Notifies the tracker that all windows of the app have been drawn.
677      *
678      * @return Non-null info if the activity was pending to draw, otherwise it might have been set
679      *         to invisible (removed from active transition) or it was already drawn.
680      */
681     @Nullable
notifyWindowsDrawn(@onNull ActivityRecord r, long timestampNs)682     TransitionInfoSnapshot notifyWindowsDrawn(@NonNull ActivityRecord r, long timestampNs) {
683         if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn " + r);
684 
685         final TransitionInfo info = getActiveTransitionInfo(r);
686         if (info == null || info.allDrawn()) {
687             if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn no activity to be drawn");
688             return null;
689         }
690         // Always calculate the delay because the caller may need to know the individual drawn time.
691         info.mWindowsDrawnDelayMs = info.calculateDelay(timestampNs);
692         info.removePendingDrawActivity(r);
693         final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
694         if (info.mLoggedTransitionStarting && info.allDrawn()) {
695             done(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", timestampNs);
696         }
697         if (r.mWmService.isRecentsAnimationTarget(r)) {
698             r.mWmService.getRecentsAnimationController().logRecentsAnimationStartTime(
699                     info.mSourceEventDelayMs + info.mWindowsDrawnDelayMs);
700         }
701         return infoSnapshot;
702     }
703 
704     /**
705      * Notifies the tracker that the starting window was drawn.
706      */
notifyStartingWindowDrawn(@onNull ActivityRecord r)707     void notifyStartingWindowDrawn(@NonNull ActivityRecord r) {
708         final TransitionInfo info = getActiveTransitionInfo(r);
709         if (info == null || info.mLoggedStartingWindowDrawn) {
710             return;
711         }
712         if (DEBUG_METRICS) Slog.i(TAG, "notifyStartingWindowDrawn " + r);
713         info.mLoggedStartingWindowDrawn = true;
714         info.mStartingWindowDelayMs = info.calculateDelay(SystemClock.elapsedRealtimeNanos());
715     }
716 
717     /**
718      * Notifies the tracker that the app transition is starting.
719      *
720      * @param activityToReason A map from activity to a reason integer, which must be on of
721      *                         ActivityTaskManagerInternal.APP_TRANSITION_* reasons.
722      */
notifyTransitionStarting(ArrayMap<WindowContainer, Integer> activityToReason)723     void notifyTransitionStarting(ArrayMap<WindowContainer, Integer> activityToReason) {
724         if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting " + activityToReason);
725 
726         final long timestampNs = SystemClock.elapsedRealtimeNanos();
727         for (int index = activityToReason.size() - 1; index >= 0; index--) {
728             final WindowContainer<?> wc = activityToReason.keyAt(index);
729             final ActivityRecord activity = wc.asActivityRecord();
730             final ActivityRecord r = activity != null ? activity
731                     : wc.getTopActivity(false /* includeFinishing */, true /* includeOverlays */);
732             final TransitionInfo info = getActiveTransitionInfo(r);
733             if (info == null || info.mLoggedTransitionStarting) {
734                 // Ignore any subsequent notifyTransitionStarting.
735                 continue;
736             }
737             if (DEBUG_METRICS) {
738                 Slog.i(TAG, "notifyTransitionStarting activity=" + wc + " info=" + info);
739             }
740 
741             info.mCurrentTransitionDelayMs = info.calculateDelay(timestampNs);
742             info.mReason = activityToReason.valueAt(index);
743             info.mLoggedTransitionStarting = true;
744             info.updatePendingDraw();
745             if (info.allDrawn()) {
746                 done(false /* abort */, info, "notifyTransitionStarting - all windows drawn",
747                         timestampNs);
748             }
749         }
750     }
751 
notifyActivityRelaunched(ActivityRecord r)752     void notifyActivityRelaunched(ActivityRecord r) {
753         final TransitionInfo info = getActiveTransitionInfo(r);
754         if (info != null) {
755             info.mRelaunched = true;
756         }
757     }
758 
759     /** Makes sure that the reference to the removed activity is cleared. */
notifyActivityRemoved(@onNull ActivityRecord r)760     void notifyActivityRemoved(@NonNull ActivityRecord r) {
761         mLastTransitionInfo.remove(r);
762     }
763 
764     /**
765      * Notifies the tracker that the visibility of an app is changing.
766      *
767      * @param r the app that is changing its visibility
768      */
notifyVisibilityChanged(@onNull ActivityRecord r)769     void notifyVisibilityChanged(@NonNull ActivityRecord r) {
770         final TransitionInfo info = getActiveTransitionInfo(r);
771         if (info == null) {
772             return;
773         }
774         if (DEBUG_METRICS) {
775             Slog.i(TAG, "notifyVisibilityChanged " + r + " visible=" + r.mVisibleRequested
776                     + " state=" + r.getState() + " finishing=" + r.finishing);
777         }
778         if (r.isState(Task.ActivityState.RESUMED) && r.mDisplayContent.isSleeping()) {
779             // The activity may be launching while keyguard is locked. The keyguard may be dismissed
780             // after the activity finished relayout, so skip the visibility check to avoid aborting
781             // the tracking of launch event.
782             return;
783         }
784         if (!r.mVisibleRequested || r.finishing) {
785             info.removePendingDrawActivity(r);
786             if (info.mLastLaunchedActivity == r) {
787                 // Check if the tracker can be cancelled because the last launched activity may be
788                 // no longer visible.
789                 scheduleCheckActivityToBeDrawn(r, 0 /* delay */);
790             }
791         }
792     }
793 
scheduleCheckActivityToBeDrawn(@onNull ActivityRecord r, long delay)794     private void scheduleCheckActivityToBeDrawn(@NonNull ActivityRecord r, long delay) {
795         // The activity and its task are passed separately because it is possible that the activity
796         // is removed from the task later.
797         r.mAtmService.mH.sendMessageDelayed(PooledLambda.obtainMessage(
798                 ActivityMetricsLogger::checkActivityToBeDrawn, this, r.getTask(), r), delay);
799     }
800 
801     /** Cancels the tracking of launch if there won't be an activity to be drawn. */
checkActivityToBeDrawn(Task t, ActivityRecord r)802     private void checkActivityToBeDrawn(Task t, ActivityRecord r) {
803         synchronized (mSupervisor.mService.mGlobalLock) {
804             final TransitionInfo info = getActiveTransitionInfo(r);
805 
806             // If we have an active transition that's waiting on a certain activity that will be
807             // invisible now, we'll never get onWindowsDrawn, so abort the transition if necessary.
808 
809             // We have no active transitions.
810             if (info == null) {
811                 return;
812             }
813 
814             // The notified activity whose visibility changed is no longer the launched activity.
815             // We can still wait to get onWindowsDrawn.
816             if (info.mLastLaunchedActivity != r) {
817                 return;
818             }
819 
820             // If the task of the launched activity contains any activity to be drawn, then the
821             // window drawn event should report later to complete the transition. Otherwise all
822             // activities in this task may be finished, invisible or drawn, so the transition event
823             // should be cancelled.
824             if (t != null && t.forAllActivities(
825                     a -> a.mVisibleRequested && !a.isReportedDrawn() && !a.finishing)) {
826                 return;
827             }
828 
829             if (DEBUG_METRICS) Slog.i(TAG, "checkActivityToBeDrawn cancels activity=" + r);
830             logAppTransitionCancel(info);
831             abort(info, "checkActivityToBeDrawn (invisible or drawn already)");
832         }
833     }
834 
835     @Nullable
getAppHibernationManagerInternal()836     private AppHibernationManagerInternal getAppHibernationManagerInternal() {
837         if (!AppHibernationService.isAppHibernationEnabled()) return null;
838         if (mAppHibernationManagerInternal == null) {
839             mAppHibernationManagerInternal =
840                     LocalServices.getService(AppHibernationManagerInternal.class);
841         }
842         return mAppHibernationManagerInternal;
843     }
844 
845     /**
846      * Notifies the tracker before the package is unstopped because of launching activity.
847      * @param packageName The package to be unstopped.
848      */
notifyBeforePackageUnstopped(@onNull String packageName)849     void notifyBeforePackageUnstopped(@NonNull String packageName) {
850         final AppHibernationManagerInternal ahmInternal = getAppHibernationManagerInternal();
851         if (ahmInternal != null) {
852             mLastHibernationStates.put(packageName, ahmInternal.isHibernatingGlobally(packageName));
853         }
854     }
855 
856     /**
857      * Notifies the tracker that we called immediately before we call bindApplication on the client.
858      *
859      * @param appInfo The client into which we'll call bindApplication.
860      */
notifyBindApplication(ApplicationInfo appInfo)861     void notifyBindApplication(ApplicationInfo appInfo) {
862         for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
863             final TransitionInfo info = mTransitionInfoList.get(i);
864 
865             // App isn't attached to record yet, so match with info.
866             if (info.mLastLaunchedActivity.info.applicationInfo == appInfo) {
867                 info.mBindApplicationDelayMs = info.calculateCurrentDelay();
868             }
869         }
870     }
871 
872     /** Aborts tracking of current launch metrics. */
abort(TransitionInfo info, String cause)873     private void abort(TransitionInfo info, String cause) {
874         done(true /* abort */, info, cause, 0L /* timestampNs */);
875     }
876 
877     /** Called when the given transition (info) is no longer active. */
done(boolean abort, @Nullable TransitionInfo info, String cause, long timestampNs)878     private void done(boolean abort, @Nullable TransitionInfo info, String cause,
879             long timestampNs) {
880         if (DEBUG_METRICS) {
881             Slog.i(TAG, "done abort=" + abort + " cause=" + cause + " timestamp=" + timestampNs
882                     + " info=" + info);
883         }
884         if (info == null) {
885             launchObserverNotifyIntentFailed();
886             return;
887         }
888 
889         stopLaunchTrace(info);
890         final Boolean isHibernating =
891                 mLastHibernationStates.remove(info.mLastLaunchedActivity.packageName);
892         if (abort) {
893             mLastTransitionInfo.remove(info.mLastLaunchedActivity);
894             mSupervisor.stopWaitingForActivityVisible(info.mLastLaunchedActivity);
895             launchObserverNotifyActivityLaunchCancelled(info);
896         } else {
897             if (info.isInterestingToLoggerAndObserver()) {
898                 launchObserverNotifyActivityLaunchFinished(info, timestampNs);
899             }
900             logAppTransitionFinished(info, isHibernating != null ? isHibernating : false);
901         }
902         info.mPendingDrawActivities.clear();
903         mTransitionInfoList.remove(info);
904     }
905 
logAppTransitionCancel(TransitionInfo info)906     private void logAppTransitionCancel(TransitionInfo info) {
907         final int type = info.mTransitionType;
908         final ActivityRecord activity = info.mLastLaunchedActivity;
909         final LogMaker builder = new LogMaker(APP_TRANSITION_CANCELLED);
910         builder.setPackageName(activity.packageName);
911         builder.setType(type);
912         builder.addTaggedData(FIELD_CLASS_NAME, activity.info.name);
913         mMetricsLogger.write(builder);
914         FrameworkStatsLog.write(
915                 FrameworkStatsLog.APP_START_CANCELED,
916                 activity.info.applicationInfo.uid,
917                 activity.packageName,
918                 getAppStartTransitionType(type, info.mRelaunched),
919                 activity.info.name);
920         if (DEBUG_METRICS) {
921             Slog.i(TAG, String.format("APP_START_CANCELED(%s, %s, %s, %s)",
922                     activity.info.applicationInfo.uid,
923                     activity.packageName,
924                     getAppStartTransitionType(type, info.mRelaunched),
925                     activity.info.name));
926         }
927     }
928 
logAppTransitionFinished(@onNull TransitionInfo info, boolean isHibernating)929     private void logAppTransitionFinished(@NonNull TransitionInfo info, boolean isHibernating) {
930         if (DEBUG_METRICS) Slog.i(TAG, "logging finished transition " + info);
931 
932         // Take a snapshot of the transition info before sending it to the handler for logging.
933         // This will avoid any races with other operations that modify the ActivityRecord.
934         final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
935         if (info.isInterestingToLoggerAndObserver()) {
936             final long timestamp = info.mTransitionStartTimeNs;
937             final long uptime = info.mTransitionDeviceUptimeMs;
938             final int transitionDelay = info.mCurrentTransitionDelayMs;
939             mLoggerHandler.post(() -> logAppTransition(
940                     timestamp, uptime, transitionDelay, infoSnapshot, isHibernating));
941         }
942         mLoggerHandler.post(() -> logAppDisplayed(infoSnapshot));
943         if (info.mPendingFullyDrawn != null) {
944             info.mPendingFullyDrawn.run();
945         }
946 
947         info.mLastLaunchedActivity.info.launchToken = null;
948     }
949 
950     // This gets called on another thread without holding the activity manager lock.
logAppTransition(long transitionStartTimeNs, long transitionDeviceUptimeMs, int currentTransitionDelayMs, TransitionInfoSnapshot info, boolean isHibernating)951     private void logAppTransition(long transitionStartTimeNs, long transitionDeviceUptimeMs,
952             int currentTransitionDelayMs, TransitionInfoSnapshot info, boolean isHibernating) {
953         final LogMaker builder = new LogMaker(APP_TRANSITION);
954         builder.setPackageName(info.packageName);
955         builder.setType(info.type);
956         builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivityName);
957         final boolean isInstantApp = info.applicationInfo.isInstantApp();
958         if (info.launchedActivityLaunchedFromPackage != null) {
959             builder.addTaggedData(APP_TRANSITION_CALLING_PACKAGE_NAME,
960                     info.launchedActivityLaunchedFromPackage);
961         }
962         String launchToken = info.launchedActivityLaunchToken;
963         if (launchToken != null) {
964             builder.addTaggedData(FIELD_INSTANT_APP_LAUNCH_TOKEN, launchToken);
965         }
966         builder.addTaggedData(APP_TRANSITION_IS_EPHEMERAL, isInstantApp ? 1 : 0);
967         builder.addTaggedData(APP_TRANSITION_DEVICE_UPTIME_SECONDS,
968                 TimeUnit.MILLISECONDS.toSeconds(transitionDeviceUptimeMs));
969         builder.addTaggedData(APP_TRANSITION_DELAY_MS, currentTransitionDelayMs);
970         builder.setSubtype(info.reason);
971         if (info.startingWindowDelayMs != INVALID_DELAY) {
972             builder.addTaggedData(APP_TRANSITION_STARTING_WINDOW_DELAY_MS,
973                     info.startingWindowDelayMs);
974         }
975         if (info.bindApplicationDelayMs != INVALID_DELAY) {
976             builder.addTaggedData(APP_TRANSITION_BIND_APPLICATION_DELAY_MS,
977                     info.bindApplicationDelayMs);
978         }
979         builder.addTaggedData(APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS, info.windowsDrawnDelayMs);
980         final PackageOptimizationInfo packageOptimizationInfo =
981                 info.getPackageOptimizationInfo(getArtManagerInternal());
982         builder.addTaggedData(PACKAGE_OPTIMIZATION_COMPILATION_REASON,
983                 packageOptimizationInfo.getCompilationReason());
984         builder.addTaggedData(PACKAGE_OPTIMIZATION_COMPILATION_FILTER,
985                 packageOptimizationInfo.getCompilationFilter());
986         mMetricsLogger.write(builder);
987 
988         // Incremental info
989         boolean isIncremental = false, isLoading = false;
990         final String codePath = info.applicationInfo.getCodePath();
991         if (codePath != null && IncrementalManager.isIncrementalPath(codePath)) {
992             isIncremental = true;
993             isLoading = isIncrementalLoading(info.packageName, info.userId);
994         }
995         FrameworkStatsLog.write(
996                 FrameworkStatsLog.APP_START_OCCURRED,
997                 info.applicationInfo.uid,
998                 info.packageName,
999                 getAppStartTransitionType(info.type, info.relaunched),
1000                 info.launchedActivityName,
1001                 info.launchedActivityLaunchedFromPackage,
1002                 isInstantApp,
1003                 0 /* deprecated transitionDeviceUptimeMs */,
1004                 info.reason,
1005                 currentTransitionDelayMs,
1006                 info.startingWindowDelayMs,
1007                 info.bindApplicationDelayMs,
1008                 info.windowsDrawnDelayMs,
1009                 launchToken,
1010                 packageOptimizationInfo.getCompilationReason(),
1011                 packageOptimizationInfo.getCompilationFilter(),
1012                 info.sourceType,
1013                 info.sourceEventDelayMs,
1014                 isHibernating,
1015                 isIncremental,
1016                 isLoading,
1017                 info.launchedActivityName.hashCode(),
1018                 TimeUnit.NANOSECONDS.toMillis(transitionStartTimeNs));
1019 
1020         if (DEBUG_METRICS) {
1021             Slog.i(TAG, String.format("APP_START_OCCURRED(%s, %s, %s, %s, %s)",
1022                     info.applicationInfo.uid,
1023                     info.packageName,
1024                     getAppStartTransitionType(info.type, info.relaunched),
1025                     info.launchedActivityName,
1026                     info.launchedActivityLaunchedFromPackage));
1027         }
1028 
1029 
1030         logAppStartMemoryStateCapture(info);
1031     }
1032 
isIncrementalLoading(String packageName, int userId)1033     private boolean isIncrementalLoading(String packageName, int userId) {
1034         final IncrementalStatesInfo info = mSupervisor.mService.getPackageManagerInternalLocked()
1035                 .getIncrementalStatesInfo(packageName, 0 /* filterCallingUid */, userId);
1036         return info != null && info.isLoading();
1037     }
1038 
logAppDisplayed(TransitionInfoSnapshot info)1039     private void logAppDisplayed(TransitionInfoSnapshot info) {
1040         if (info.type != TYPE_TRANSITION_WARM_LAUNCH && info.type != TYPE_TRANSITION_COLD_LAUNCH) {
1041             return;
1042         }
1043 
1044         EventLog.writeEvent(WM_ACTIVITY_LAUNCH_TIME,
1045                 info.userId, info.activityRecordIdHashCode, info.launchedActivityShortComponentName,
1046                 info.windowsDrawnDelayMs);
1047 
1048         StringBuilder sb = mStringBuilder;
1049         sb.setLength(0);
1050         sb.append("Displayed ");
1051         sb.append(info.launchedActivityShortComponentName);
1052         sb.append(": ");
1053         TimeUtils.formatDuration(info.windowsDrawnDelayMs, sb);
1054         Log.i(TAG, sb.toString());
1055     }
1056 
getAppStartTransitionType(int tronType, boolean relaunched)1057     private static int getAppStartTransitionType(int tronType, boolean relaunched) {
1058         if (tronType == TYPE_TRANSITION_COLD_LAUNCH) {
1059             return FrameworkStatsLog.APP_START_OCCURRED__TYPE__COLD;
1060         }
1061         if (tronType == TYPE_TRANSITION_WARM_LAUNCH) {
1062             return FrameworkStatsLog.APP_START_OCCURRED__TYPE__WARM;
1063         }
1064         if (tronType == TYPE_TRANSITION_HOT_LAUNCH) {
1065             return relaunched
1066                     ? FrameworkStatsLog.APP_START_OCCURRED__TYPE__RELAUNCH
1067                     : FrameworkStatsLog.APP_START_OCCURRED__TYPE__HOT;
1068         }
1069         return FrameworkStatsLog.APP_START_OCCURRED__TYPE__UNKNOWN;
1070     }
1071 
1072     /** @see android.app.Activity#reportFullyDrawn */
logAppTransitionReportedDrawn(ActivityRecord r, boolean restoredFromBundle)1073     TransitionInfoSnapshot logAppTransitionReportedDrawn(ActivityRecord r,
1074             boolean restoredFromBundle) {
1075         final TransitionInfo info = mLastTransitionInfo.get(r);
1076         if (info == null) {
1077             return null;
1078         }
1079         if (!info.allDrawn() && info.mPendingFullyDrawn == null) {
1080             // There are still undrawn activities, postpone reporting fully drawn until all of its
1081             // windows are drawn. So that is closer to an usable state.
1082             info.mPendingFullyDrawn = () -> {
1083                 logAppTransitionReportedDrawn(r, restoredFromBundle);
1084                 info.mPendingFullyDrawn = null;
1085             };
1086             return null;
1087         }
1088 
1089         final long currentTimestampNs = SystemClock.elapsedRealtimeNanos();
1090         final long startupTimeMs = info.mPendingFullyDrawn != null
1091                 ? info.mWindowsDrawnDelayMs
1092                 : TimeUnit.NANOSECONDS.toMillis(currentTimestampNs - info.mTransitionStartTimeNs);
1093         final TransitionInfoSnapshot infoSnapshot =
1094                 new TransitionInfoSnapshot(info, r, (int) startupTimeMs);
1095         mLoggerHandler.post(() -> logAppFullyDrawn(infoSnapshot));
1096         mLastTransitionInfo.remove(r);
1097 
1098         if (!info.isInterestingToLoggerAndObserver()) {
1099             return infoSnapshot;
1100         }
1101 
1102         // Record the handling of the reportFullyDrawn callback in the trace system. This is not
1103         // actually used to trace this function, but instead the logical task that this function
1104         // fullfils (handling reportFullyDrawn() callbacks).
1105         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1106                 "ActivityManager:ReportingFullyDrawn " + info.mLastLaunchedActivity.packageName);
1107 
1108         final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN);
1109         builder.setPackageName(r.packageName);
1110         builder.addTaggedData(FIELD_CLASS_NAME, r.info.name);
1111         builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS, startupTimeMs);
1112         builder.setType(restoredFromBundle
1113                 ? TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE
1114                 : TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE);
1115         builder.addTaggedData(APP_TRANSITION_PROCESS_RUNNING,
1116                 info.mProcessRunning ? 1 : 0);
1117         mMetricsLogger.write(builder);
1118         final PackageOptimizationInfo packageOptimizationInfo =
1119                 infoSnapshot.getPackageOptimizationInfo(getArtManagerInternal());
1120         // Incremental info
1121         boolean isIncremental = false, isLoading = false;
1122         final String codePath = info.mLastLaunchedActivity.info.applicationInfo.getCodePath();
1123         if (codePath != null && IncrementalManager.isIncrementalPath(codePath)) {
1124             isIncremental = true;
1125             isLoading = isIncrementalLoading(info.mLastLaunchedActivity.packageName,
1126                             info.mLastLaunchedActivity.mUserId);
1127         }
1128         FrameworkStatsLog.write(
1129                 FrameworkStatsLog.APP_START_FULLY_DRAWN,
1130                 info.mLastLaunchedActivity.info.applicationInfo.uid,
1131                 info.mLastLaunchedActivity.packageName,
1132                 restoredFromBundle
1133                         ? FrameworkStatsLog.APP_START_FULLY_DRAWN__TYPE__WITH_BUNDLE
1134                         : FrameworkStatsLog.APP_START_FULLY_DRAWN__TYPE__WITHOUT_BUNDLE,
1135                 info.mLastLaunchedActivity.info.name,
1136                 info.mProcessRunning,
1137                 startupTimeMs,
1138                 packageOptimizationInfo.getCompilationReason(),
1139                 packageOptimizationInfo.getCompilationFilter(),
1140                 info.mSourceType,
1141                 info.mSourceEventDelayMs,
1142                 isIncremental,
1143                 isLoading,
1144                 info.mLastLaunchedActivity.info.name.hashCode());
1145 
1146         // Ends the trace started at the beginning of this function. This is located here to allow
1147         // the trace slice to have a noticable duration.
1148         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1149 
1150         // Notify reportFullyDrawn event.
1151         launchObserverNotifyReportFullyDrawn(r, currentTimestampNs);
1152 
1153         return infoSnapshot;
1154     }
1155 
logAppFullyDrawn(TransitionInfoSnapshot info)1156     private void logAppFullyDrawn(TransitionInfoSnapshot info) {
1157         if (info.type != TYPE_TRANSITION_WARM_LAUNCH && info.type != TYPE_TRANSITION_COLD_LAUNCH) {
1158             return;
1159         }
1160 
1161         StringBuilder sb = mStringBuilder;
1162         sb.setLength(0);
1163         sb.append("Fully drawn ");
1164         sb.append(info.launchedActivityShortComponentName);
1165         sb.append(": ");
1166         TimeUtils.formatDuration(info.windowsFullyDrawnDelayMs, sb);
1167         Log.i(TAG, sb.toString());
1168     }
1169 
logAbortedBgActivityStart(Intent intent, WindowProcessController callerApp, int callingUid, String callingPackage, int callingUidProcState, boolean callingUidHasAnyVisibleWindow, int realCallingUid, int realCallingUidProcState, boolean realCallingUidHasAnyVisibleWindow, boolean comingFromPendingIntent)1170     void logAbortedBgActivityStart(Intent intent, WindowProcessController callerApp,
1171             int callingUid, String callingPackage, int callingUidProcState,
1172             boolean callingUidHasAnyVisibleWindow,
1173             int realCallingUid, int realCallingUidProcState,
1174             boolean realCallingUidHasAnyVisibleWindow,
1175             boolean comingFromPendingIntent) {
1176 
1177         final long nowElapsed = SystemClock.elapsedRealtime();
1178         final long nowUptime = SystemClock.uptimeMillis();
1179         final LogMaker builder = new LogMaker(ACTION_ACTIVITY_START);
1180         builder.setTimestamp(System.currentTimeMillis());
1181         builder.addTaggedData(FIELD_CALLING_UID, callingUid);
1182         builder.addTaggedData(FIELD_CALLING_PACKAGE_NAME, callingPackage);
1183         builder.addTaggedData(FIELD_CALLING_UID_PROC_STATE,
1184                 processStateAmToProto(callingUidProcState));
1185         builder.addTaggedData(FIELD_CALLING_UID_HAS_ANY_VISIBLE_WINDOW,
1186                 callingUidHasAnyVisibleWindow ? 1 : 0);
1187         builder.addTaggedData(FIELD_REAL_CALLING_UID, realCallingUid);
1188         builder.addTaggedData(FIELD_REAL_CALLING_UID_PROC_STATE,
1189                 processStateAmToProto(realCallingUidProcState));
1190         builder.addTaggedData(FIELD_REAL_CALLING_UID_HAS_ANY_VISIBLE_WINDOW,
1191                 realCallingUidHasAnyVisibleWindow ? 1 : 0);
1192         builder.addTaggedData(FIELD_COMING_FROM_PENDING_INTENT, comingFromPendingIntent ? 1 : 0);
1193         if (intent != null) {
1194             builder.addTaggedData(FIELD_INTENT_ACTION, intent.getAction());
1195             ComponentName component = intent.getComponent();
1196             if (component != null) {
1197                 builder.addTaggedData(FIELD_TARGET_SHORT_COMPONENT_NAME,
1198                         component.flattenToShortString());
1199             }
1200         }
1201         if (callerApp != null) {
1202             builder.addTaggedData(FIELD_PROCESS_RECORD_PROCESS_NAME, callerApp.mName);
1203             builder.addTaggedData(FIELD_PROCESS_RECORD_CUR_PROC_STATE,
1204                     processStateAmToProto(callerApp.getCurrentProcState()));
1205             builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_CLIENT_ACTIVITIES,
1206                     callerApp.hasClientActivities() ? 1 : 0);
1207             builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_FOREGROUND_SERVICES,
1208                     callerApp.hasForegroundServices() ? 1 : 0);
1209             builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_FOREGROUND_ACTIVITIES,
1210                     callerApp.hasForegroundActivities() ? 1 : 0);
1211             builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_TOP_UI, callerApp.hasTopUi() ? 1 : 0);
1212             builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_OVERLAY_UI,
1213                     callerApp.hasOverlayUi() ? 1 : 0);
1214             builder.addTaggedData(FIELD_PROCESS_RECORD_PENDING_UI_CLEAN,
1215                     callerApp.hasPendingUiClean() ? 1 : 0);
1216             if (callerApp.getInteractionEventTime() != 0) {
1217                 builder.addTaggedData(FIELD_PROCESS_RECORD_MILLIS_SINCE_LAST_INTERACTION_EVENT,
1218                         (nowElapsed - callerApp.getInteractionEventTime()));
1219             }
1220             if (callerApp.getFgInteractionTime() != 0) {
1221                 builder.addTaggedData(FIELD_PROCESS_RECORD_MILLIS_SINCE_FG_INTERACTION,
1222                         (nowElapsed - callerApp.getFgInteractionTime()));
1223             }
1224             if (callerApp.getWhenUnimportant() != 0) {
1225                 builder.addTaggedData(FIELD_PROCESS_RECORD_MILLIS_SINCE_UNIMPORTANT,
1226                         (nowUptime - callerApp.getWhenUnimportant()));
1227             }
1228         }
1229         mMetricsLogger.write(builder);
1230     }
1231 
logAppStartMemoryStateCapture(TransitionInfoSnapshot info)1232     private void logAppStartMemoryStateCapture(TransitionInfoSnapshot info) {
1233         if (info.processRecord == null) {
1234             if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture processRecord null");
1235             return;
1236         }
1237 
1238         final int pid = info.processRecord.getPid();
1239         final int uid = info.applicationInfo.uid;
1240         final MemoryStat memoryStat = readMemoryStatFromFilesystem(uid, pid);
1241         if (memoryStat == null) {
1242             if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture memoryStat null");
1243             return;
1244         }
1245 
1246         FrameworkStatsLog.write(
1247                 FrameworkStatsLog.APP_START_MEMORY_STATE_CAPTURED,
1248                 uid,
1249                 info.processName,
1250                 info.launchedActivityName,
1251                 memoryStat.pgfault,
1252                 memoryStat.pgmajfault,
1253                 memoryStat.rssInBytes,
1254                 memoryStat.cacheInBytes,
1255                 memoryStat.swapInBytes);
1256     }
1257 
getArtManagerInternal()1258     private ArtManagerInternal getArtManagerInternal() {
1259         if (mArtManagerInternal == null) {
1260             // Note that this may be null.
1261             // ArtManagerInternal is registered during PackageManagerService
1262             // initialization which happens after ActivityManagerService.
1263             mArtManagerInternal = LocalServices.getService(ArtManagerInternal.class);
1264         }
1265         return mArtManagerInternal;
1266     }
1267 
1268     /** Starts trace for an activity is actually launching. */
startLaunchTrace(@onNull TransitionInfo info)1269     private void startLaunchTrace(@NonNull TransitionInfo info) {
1270         if (DEBUG_METRICS) Slog.i(TAG, "startLaunchTrace " + info);
1271         if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
1272             return;
1273         }
1274         info.mLaunchTraceName = "launching: " + info.mLastLaunchedActivity.packageName;
1275         Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName,
1276                 (int) info.mTransitionStartTimeNs /* cookie */);
1277     }
1278 
1279     /** Stops trace for the launch is completed or cancelled. */
stopLaunchTrace(@onNull TransitionInfo info)1280     private void stopLaunchTrace(@NonNull TransitionInfo info) {
1281         if (DEBUG_METRICS) Slog.i(TAG, "stopLaunchTrace " + info);
1282         if (info.mLaunchTraceName == null) {
1283             return;
1284         }
1285         Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName,
1286                 (int) info.mTransitionStartTimeNs /* cookie */);
1287         info.mLaunchTraceName = null;
1288     }
1289 
getLaunchObserverRegistry()1290     public ActivityMetricsLaunchObserverRegistry getLaunchObserverRegistry() {
1291         return mLaunchObserver;
1292     }
1293 
1294     /** Notify the {@link ActivityMetricsLaunchObserver} that a new launch sequence has begun. */
launchObserverNotifyIntentStarted(Intent intent, long timestampNs)1295     private void launchObserverNotifyIntentStarted(Intent intent, long timestampNs) {
1296         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1297                 "MetricsLogger:launchObserverNotifyIntentStarted");
1298 
1299         // Beginning a launch is timing sensitive and so should be observed as soon as possible.
1300         mLaunchObserver.onIntentStarted(intent, timestampNs);
1301 
1302         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1303     }
1304 
1305     /**
1306      * Notify the {@link ActivityMetricsLaunchObserver} that the previous launch sequence has
1307      * aborted due to intent failure (e.g. intent resolve failed or security error, etc) or
1308      * intent being delivered to the top running activity.
1309      */
launchObserverNotifyIntentFailed()1310     private void launchObserverNotifyIntentFailed() {
1311        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1312                 "MetricsLogger:launchObserverNotifyIntentFailed");
1313 
1314         mLaunchObserver.onIntentFailed();
1315 
1316         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1317     }
1318 
1319     /**
1320      * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence's activity
1321      * has started.
1322      */
launchObserverNotifyActivityLaunched(TransitionInfo info)1323     private void launchObserverNotifyActivityLaunched(TransitionInfo info) {
1324         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1325                 "MetricsLogger:launchObserverNotifyActivityLaunched");
1326 
1327         @ActivityMetricsLaunchObserver.Temperature int temperature =
1328                 convertTransitionTypeToLaunchObserverTemperature(info.mTransitionType);
1329 
1330         // Beginning a launch is timing sensitive and so should be observed as soon as possible.
1331         mLaunchObserver.onActivityLaunched(convertActivityRecordToProto(info.mLastLaunchedActivity),
1332                 temperature);
1333 
1334         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1335     }
1336 
1337     /**
1338      * Notifies the {@link ActivityMetricsLaunchObserver} the reportFullDrawn event.
1339      */
launchObserverNotifyReportFullyDrawn(ActivityRecord r, long timestampNs)1340     private void launchObserverNotifyReportFullyDrawn(ActivityRecord r, long timestampNs) {
1341         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1342             "MetricsLogger:launchObserverNotifyReportFullyDrawn");
1343         mLaunchObserver.onReportFullyDrawn(convertActivityRecordToProto(r), timestampNs);
1344         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1345     }
1346 
1347     /**
1348      * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence is
1349      * cancelled.
1350      */
launchObserverNotifyActivityLaunchCancelled(TransitionInfo info)1351     private void launchObserverNotifyActivityLaunchCancelled(TransitionInfo info) {
1352         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1353                 "MetricsLogger:launchObserverNotifyActivityLaunchCancelled");
1354 
1355         final @ActivityMetricsLaunchObserver.ActivityRecordProto byte[] activityRecordProto =
1356                 info != null ? convertActivityRecordToProto(info.mLastLaunchedActivity) : null;
1357 
1358         mLaunchObserver.onActivityLaunchCancelled(activityRecordProto);
1359 
1360         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1361     }
1362 
1363     /**
1364      * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence's activity
1365      * has fully finished (successfully).
1366      */
launchObserverNotifyActivityLaunchFinished(TransitionInfo info, long timestampNs)1367     private void launchObserverNotifyActivityLaunchFinished(TransitionInfo info, long timestampNs) {
1368         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1369                 "MetricsLogger:launchObserverNotifyActivityLaunchFinished");
1370 
1371         mLaunchObserver.onActivityLaunchFinished(
1372                 convertActivityRecordToProto(info.mLastLaunchedActivity), timestampNs);
1373 
1374         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1375     }
1376 
1377     @VisibleForTesting
1378     static @ActivityMetricsLaunchObserver.ActivityRecordProto byte[]
convertActivityRecordToProto(ActivityRecord record)1379             convertActivityRecordToProto(ActivityRecord record) {
1380         // May take non-negligible amount of time to convert ActivityRecord into a proto,
1381         // so track the time.
1382         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1383                 "MetricsLogger:convertActivityRecordToProto");
1384 
1385         // There does not appear to be a way to 'reset' a ProtoOutputBuffer stream,
1386         // so create a new one every time.
1387         final ProtoOutputStream protoOutputStream =
1388                 new ProtoOutputStream(LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
1389         // Write this data out as the top-most ActivityRecordProto (i.e. it is not a sub-object).
1390         record.dumpDebug(protoOutputStream, WindowTraceLogLevel.ALL);
1391         final byte[] bytes = protoOutputStream.getBytes();
1392 
1393         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1394 
1395         return bytes;
1396     }
1397 
1398     private static @ActivityMetricsLaunchObserver.Temperature int
convertTransitionTypeToLaunchObserverTemperature(int transitionType)1399             convertTransitionTypeToLaunchObserverTemperature(int transitionType) {
1400         switch (transitionType) {
1401             case TYPE_TRANSITION_WARM_LAUNCH:
1402                 return ActivityMetricsLaunchObserver.TEMPERATURE_WARM;
1403             case TYPE_TRANSITION_HOT_LAUNCH:
1404                 return ActivityMetricsLaunchObserver.TEMPERATURE_HOT;
1405             case TYPE_TRANSITION_COLD_LAUNCH:
1406                 return ActivityMetricsLaunchObserver.TEMPERATURE_COLD;
1407             default:
1408                 return -1;
1409         }
1410     }
1411 }
1412