1 package com.android.server.wm;
2 
3 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
4 import static android.app.ActivityManager.START_SUCCESS;
5 import static android.app.ActivityManager.START_TASK_TO_FRONT;
6 import static android.app.ActivityManager.processStateAmToProto;
7 import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_DISMISSED;
8 import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_HIDDEN;
9 import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED;
10 import static android.app.CameraCompatTaskInfo.CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED;
11 import static android.app.WaitResult.INVALID_DELAY;
12 import static android.app.WaitResult.LAUNCH_STATE_COLD;
13 import static android.app.WaitResult.LAUNCH_STATE_HOT;
14 import static android.app.WaitResult.LAUNCH_STATE_RELAUNCH;
15 import static android.app.WaitResult.LAUNCH_STATE_WARM;
16 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
17 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
18 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
19 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
20 
21 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_ACTIVITY_START;
22 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION;
23 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_BIND_APPLICATION_DELAY_MS;
24 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CALLING_PACKAGE_NAME;
25 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CANCELLED;
26 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS;
27 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS;
28 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_IS_EPHEMERAL;
29 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_PROCESS_RUNNING;
30 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN;
31 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN_MS;
32 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_STARTING_WINDOW_DELAY_MS;
33 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS;
34 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_PACKAGE_NAME;
35 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_UID;
36 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_UID_HAS_ANY_VISIBLE_WINDOW;
37 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CALLING_UID_PROC_STATE;
38 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CLASS_NAME;
39 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_COMING_FROM_PENDING_INTENT;
40 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INSTANT_APP_LAUNCH_TOKEN;
41 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_INTENT_ACTION;
42 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_CUR_PROC_STATE;
43 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_CLIENT_ACTIVITIES;
44 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_FOREGROUND_ACTIVITIES;
45 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_FOREGROUND_SERVICES;
46 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_OVERLAY_UI;
47 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_HAS_TOP_UI;
48 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_MILLIS_SINCE_FG_INTERACTION;
49 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_MILLIS_SINCE_LAST_INTERACTION_EVENT;
50 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_MILLIS_SINCE_UNIMPORTANT;
51 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_PENDING_UI_CLEAN;
52 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_PROCESS_RECORD_PROCESS_NAME;
53 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID;
54 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID_HAS_ANY_VISIBLE_WINDOW;
55 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_REAL_CALLING_UID_PROC_STATE;
56 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TARGET_SHORT_COMPONENT_NAME;
57 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PACKAGE_OPTIMIZATION_COMPILATION_FILTER;
58 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.PACKAGE_OPTIMIZATION_COMPILATION_REASON;
59 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_COLD_LAUNCH;
60 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_HOT_LAUNCH;
61 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE;
62 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE;
63 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
64 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__NOT_LETTERBOXED_POSITION;
65 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO;
66 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION;
67 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
68 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
69 import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
70 import static com.android.internal.util.FrameworkStatsLog.APP_START_OCCURRED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL;
71 import static com.android.internal.util.FrameworkStatsLog.APP_START_OCCURRED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_STOPPED;
72 import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__APPEARED_APPLY_TREATMENT;
73 import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__APPEARED_REVERT_TREATMENT;
74 import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_APPLY_TREATMENT;
75 import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_DISMISS;
76 import static com.android.internal.util.FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_REVERT_TREATMENT;
77 import static com.android.server.am.MemoryStatUtil.MemoryStat;
78 import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
79 import static com.android.server.am.ProcessList.INVALID_ADJ;
80 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_METRICS;
81 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
82 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
83 import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
84 import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT;
85 import static com.android.server.wm.EventLogTags.WM_ACTIVITY_LAUNCH_TIME;
86 
87 import android.annotation.NonNull;
88 import android.annotation.Nullable;
89 import android.app.ActivityOptions;
90 import android.app.ActivityOptions.SourceInfo;
91 import android.app.ApplicationStartInfo;
92 import android.app.CameraCompatTaskInfo.CameraCompatControlState;
93 import android.app.WaitResult;
94 import android.app.WindowConfiguration.WindowingMode;
95 import android.content.ComponentName;
96 import android.content.Intent;
97 import android.content.pm.ApplicationInfo;
98 import android.content.pm.IncrementalStatesInfo;
99 import android.content.pm.dex.ArtManagerInternal;
100 import android.content.pm.dex.PackageOptimizationInfo;
101 import android.metrics.LogMaker;
102 import android.os.Handler;
103 import android.os.Looper;
104 import android.os.SystemClock;
105 import android.os.Trace;
106 import android.os.incremental.IncrementalManager;
107 import android.util.ArrayMap;
108 import android.util.EventLog;
109 import android.util.Log;
110 import android.util.Slog;
111 import android.util.SparseArray;
112 import android.util.TimeUtils;
113 
114 import com.android.internal.annotations.VisibleForTesting;
115 import com.android.internal.logging.MetricsLogger;
116 import com.android.internal.util.FrameworkStatsLog;
117 import com.android.internal.util.LatencyTracker;
118 import com.android.internal.util.function.pooled.PooledLambda;
119 import com.android.server.FgThread;
120 import com.android.server.LocalServices;
121 import com.android.server.apphibernation.AppHibernationManagerInternal;
122 import com.android.server.apphibernation.AppHibernationService;
123 
124 import java.util.ArrayList;
125 import java.util.concurrent.TimeUnit;
126 
127 /**
128  * Listens to activity launches, transitions, visibility changes and window drawn callbacks to
129  * determine app launch times and draw delays. Source of truth for activity metrics and provides
130  * data for Tron, logcat, event logs and {@link android.app.WaitResult}.
131  * <p>
132  * A typical sequence of a launch event could be:
133  * {@link #notifyActivityLaunching}, {@link #notifyActivityLaunched},
134  * {@link #notifyStartingWindowDrawn} (optional), {@link #notifyTransitionStarting}
135  * {@link #notifyWindowsDrawn}.
136  * <p>
137  * Tests:
138  * atest CtsWindowManagerDeviceTestCases:ActivityMetricsLoggerTests
139  */
140 class ActivityMetricsLogger {
141 
142     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityMetricsLogger" : TAG_ATM;
143 
144     // Window modes we are interested in logging. If we ever introduce a new type, we need to add
145     // a value here and increase the {@link #TRON_WINDOW_STATE_VARZ_STRINGS} array.
146     private static final int WINDOW_STATE_STANDARD = 0;
147     private static final int WINDOW_STATE_SIDE_BY_SIDE = 1;
148     private static final int WINDOW_STATE_FREEFORM = 2;
149     private static final int WINDOW_STATE_ASSISTANT = 3;
150     private static final int WINDOW_STATE_MULTI_WINDOW = 4;
151     private static final int WINDOW_STATE_INVALID = -1;
152 
153     // These should match AppStartOccurred.MultiWindowLaunchType in the atoms.proto
154     private static final int MULTI_WINDOW_LAUNCH_TYPE_UNSPECIFIED = 0;
155     private static final int MULTI_WINDOW_LAUNCH_TYPE_APP_PAIR = 1;
156 
157     /**
158      * If a launching activity isn't visible within this duration when the device is sleeping, e.g.
159      * keyguard is locked, its transition info will be dropped.
160      */
161     private static final long UNKNOWN_VISIBILITY_CHECK_DELAY_MS = 3000;
162 
163     /**
164      * If the recents animation is finished before the delay since the window drawn, do not log the
165      * action because the duration is too small that may be just an accidentally touch.
166      */
167     private static final long LATENCY_TRACKER_RECENTS_DELAY_MS = 300;
168 
169     /**
170      * The flag for {@link #notifyActivityLaunching} to skip associating a new launch with an active
171      * transition, in the case the launch is standalone (e.g. from recents).
172      */
173     private static final int IGNORE_CALLER = -1;
174 
175     // Preallocated strings we are sending to tron, so we don't have to allocate a new one every
176     // time we log.
177     private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = {
178             "window_time_0", "window_time_1", "window_time_2", "window_time_3", "window_time_4"};
179 
180     private int mWindowState = WINDOW_STATE_STANDARD;
181     private long mLastLogTimeSecs;
182     private final ActivityTaskSupervisor mSupervisor;
183     private final MetricsLogger mMetricsLogger = new MetricsLogger();
184     private final Handler mLoggerHandler = FgThread.getHandler();
185 
186     /** All active transitions. */
187     private final ArrayList<TransitionInfo> mTransitionInfoList = new ArrayList<>();
188     /** Map : Last launched activity => {@link TransitionInfo} */
189     private final ArrayMap<ActivityRecord, TransitionInfo> mLastTransitionInfo = new ArrayMap<>();
190     /** SparseArray : Package UID => {@link PackageCompatStateInfo} */
191     private final SparseArray<PackageCompatStateInfo> mPackageUidToCompatStateInfo =
192             new SparseArray<>(0);
193 
194     private ArtManagerInternal mArtManagerInternal;
195     private final StringBuilder mStringBuilder = new StringBuilder();
196 
197     /**
198      * Due to the global single concurrent launch sequence, all calls to this observer must be made
199      * in-order on the same thread to fulfill the "happens-before" guarantee in LaunchObserver.
200      */
201     private final LaunchObserverRegistryImpl mLaunchObserver;
202     private final ArrayMap<String, Boolean> mLastHibernationStates = new ArrayMap<>();
203     private AppHibernationManagerInternal mAppHibernationManagerInternal;
204 
205     /**
206      * The information created when an intent is incoming but we do not yet know whether it will be
207      * launched successfully.
208      */
209     static final class LaunchingState {
210         /**
211          * The device uptime of {@link #notifyActivityLaunching}. It can be used as a key for
212          * observer to identify which callbacks belong to a launch event.
213          */
214         final long mStartUptimeNs = SystemClock.uptimeNanos();
215         /**
216          * The timestamp of {@link #notifyActivityLaunching}. It is used to provide the time
217          * relative to the wall-time.
218          */
219         final long mStartRealtimeNs = SystemClock.elapsedRealtimeNanos();
220         /** Non-null when a {@link TransitionInfo} is created for this state. */
221         private TransitionInfo mAssociatedTransitionInfo;
222         /** The sequence id for trace. It is used to map the traces before resolving intent. */
223         private static int sTraceSeqId;
224         /** The trace format is "launchingActivity#$seqId:$state(:$packageName)". */
225         String mTraceName;
226 
LaunchingState()227         LaunchingState() {
228             if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
229                 return;
230             }
231             // Use an id because the launching app is not yet known before resolving intent.
232             sTraceSeqId++;
233             mTraceName = "launchingActivity#" + sTraceSeqId;
234             Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName, 0);
235         }
236 
stopTrace(boolean abort, TransitionInfo endInfo)237         void stopTrace(boolean abort, TransitionInfo endInfo) {
238             if (mTraceName == null) return;
239             if (!abort && endInfo != mAssociatedTransitionInfo) {
240                 // Multiple TransitionInfo can be associated with the same LaunchingState (e.g. a
241                 // launching activity launches another activity in a different windowing mode or
242                 // display). Only the original associated info can emit a "completed" trace.
243                 return;
244             }
245             Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName, 0);
246             final String launchResult;
247             if (mAssociatedTransitionInfo == null) {
248                 launchResult = ":failed";
249             } else {
250                 final String status;
251                 if (abort) {
252                     status = ":canceled:";
253                 } else if (!mAssociatedTransitionInfo.mProcessSwitch) {
254                     status = ":completed-same-process:";
255                 } else {
256                     if (endInfo.mTransitionType == TYPE_TRANSITION_HOT_LAUNCH) {
257                         status = ":completed-hot:";
258                     } else if (endInfo.mTransitionType == TYPE_TRANSITION_WARM_LAUNCH) {
259                         status = ":completed-warm:";
260                     } else {
261                         status = ":completed-cold:";
262                     }
263                 }
264                 launchResult = status + mAssociatedTransitionInfo.mLastLaunchedActivity.packageName;
265             }
266             // Put a supplement trace as the description of the async trace with the same id.
267             Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, mTraceName + launchResult);
268             mTraceName = null;
269         }
270 
271         @VisibleForTesting
allDrawn()272         boolean allDrawn() {
273             return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.mIsDrawn;
274         }
275 
hasActiveTransitionInfo()276         boolean hasActiveTransitionInfo() {
277             return mAssociatedTransitionInfo != null;
278         }
279 
contains(ActivityRecord r)280         boolean contains(ActivityRecord r) {
281             return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.contains(r);
282         }
283     }
284 
285     /** The information created when an activity is confirmed to be launched. */
286     private static final class TransitionInfo {
287         /**
288          * The field to lookup and update an existing transition efficiently between
289          * {@link #notifyActivityLaunching} and {@link #notifyActivityLaunched}.
290          *
291          * @see LaunchingState#mAssociatedTransitionInfo
292          */
293         final LaunchingState mLaunchingState;
294 
295         /** The type can be cold (new process), warm (new activity), or hot (bring to front). */
296         int mTransitionType;
297         /** Whether the process was already running when the transition started. */
298         boolean mProcessRunning;
299         /** whether the process of the launching activity didn't have any active activity. */
300         final boolean mProcessSwitch;
301         /** The process state of the launching activity prior to the launch */
302         final int mProcessState;
303         /** The oom adj score of the launching activity prior to the launch */
304         final int mProcessOomAdj;
305         /** Whether the activity is launched above a visible activity in the same task. */
306         final boolean mIsInTaskActivityStart;
307         /** Whether the last launched activity has reported drawn. */
308         boolean mIsDrawn;
309         /** The latest activity to have been launched. */
310         @NonNull ActivityRecord mLastLaunchedActivity;
311 
312         /** The type of the source that triggers the launch event. */
313         @SourceInfo.SourceType int mSourceType;
314         /** The time from the source event (e.g. touch) to {@link #notifyActivityLaunching}. */
315         int mSourceEventDelayMs = INVALID_DELAY;
316         /** The time from {@link #notifyActivityLaunching} to {@link #notifyTransitionStarting}. */
317         int mCurrentTransitionDelayMs;
318         /** The time from {@link #notifyActivityLaunching} to {@link #notifyStartingWindowDrawn}. */
319         int mStartingWindowDelayMs = INVALID_DELAY;
320         /** The time from {@link #notifyActivityLaunching} to {@link #notifyBindApplication}. */
321         int mBindApplicationDelayMs = INVALID_DELAY;
322         /** Elapsed time from when we launch an activity to when its windows are drawn. */
323         int mWindowsDrawnDelayMs;
324         /** The reason why the transition started (see ActivityManagerInternal.APP_TRANSITION_*). */
325         int mReason = APP_TRANSITION_TIMEOUT;
326         /** The flag ensures that {@link #mStartingWindowDelayMs} is only set once. */
327         boolean mLoggedStartingWindowDrawn;
328         /** If the any app transitions have been logged as starting. */
329         boolean mLoggedTransitionStarting;
330         /** Whether any activity belonging to this transition has relaunched. */
331         boolean mRelaunched;
332 
333         /** Non-null if the application has reported drawn but its window hasn't. */
334         @Nullable Runnable mPendingFullyDrawn;
335         /** Non-null if the trace is active. */
336         @Nullable String mLaunchTraceName;
337         /** Whether this transition info is for an activity that is a part of multi-window. */
338         int mMultiWindowLaunchType = MULTI_WINDOW_LAUNCH_TYPE_UNSPECIFIED;
339 
340         /** @return Non-null if there will be a window drawn event for the launch. */
341         @Nullable
create(@onNull ActivityRecord r, @NonNull LaunchingState launchingState, @Nullable ActivityOptions options, boolean processRunning, boolean processSwitch, int processState, int processOomAdj, boolean newActivityCreated, boolean isInTaskActivityStart, int startResult)342         static TransitionInfo create(@NonNull ActivityRecord r,
343                 @NonNull LaunchingState launchingState, @Nullable ActivityOptions options,
344                 boolean processRunning, boolean processSwitch, int processState, int processOomAdj,
345                 boolean newActivityCreated, boolean isInTaskActivityStart, int startResult) {
346             if (startResult != START_SUCCESS && startResult != START_TASK_TO_FRONT) {
347                 return null;
348             }
349             final int transitionType;
350             if (processRunning) {
351                 transitionType = !newActivityCreated && r.attachedToProcess()
352                         ? TYPE_TRANSITION_HOT_LAUNCH
353                         : TYPE_TRANSITION_WARM_LAUNCH;
354             } else {
355                 // Task may still exist when cold launching an activity and the start result will be
356                 // set to START_TASK_TO_FRONT. Treat this as a COLD launch.
357                 transitionType = TYPE_TRANSITION_COLD_LAUNCH;
358             }
359             return new TransitionInfo(r, launchingState, options, transitionType, processRunning,
360                     processSwitch, processState, processOomAdj, isInTaskActivityStart);
361         }
362 
363         /** 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, int processState, int processOomAdj, boolean isInTaskActivityStart)364         private TransitionInfo(ActivityRecord r, LaunchingState launchingState,
365                 ActivityOptions options, int transitionType, boolean processRunning,
366                 boolean processSwitch, int processState, int processOomAdj,
367                 boolean isInTaskActivityStart) {
368             mLaunchingState = launchingState;
369             mTransitionType = transitionType;
370             mProcessRunning = processRunning;
371             mProcessSwitch = processSwitch;
372             mProcessState = processState;
373             mProcessOomAdj = processOomAdj;
374             mIsInTaskActivityStart = isInTaskActivityStart;
375             setLatestLaunchedActivity(r);
376             // The launching state can be reused by consecutive launch. Its original association
377             // shouldn't be changed by a separated transition.
378             if (launchingState.mAssociatedTransitionInfo == null) {
379                 launchingState.mAssociatedTransitionInfo = this;
380             }
381             if (options != null) {
382                 final SourceInfo sourceInfo = options.getSourceInfo();
383                 if (sourceInfo != null) {
384                     mSourceType = sourceInfo.type;
385                     mSourceEventDelayMs = (int) (TimeUnit.NANOSECONDS.toMillis(
386                             launchingState.mStartUptimeNs) - sourceInfo.eventTimeMs);
387                 }
388             }
389         }
390 
391         /**
392          * Remembers the latest launched activity to represent the final transition. This also
393          * tracks the activities that should be drawn, so a consecutive launching sequence can be
394          * coalesced as one event.
395          */
setLatestLaunchedActivity(ActivityRecord r)396         void setLatestLaunchedActivity(ActivityRecord r) {
397             if (mLastLaunchedActivity == r) {
398                 return;
399             }
400             if (mLastLaunchedActivity != null) {
401                 // Transfer the launch cookie and launch root task because it is a consecutive
402                 // launch event.
403                 r.mLaunchCookie = mLastLaunchedActivity.mLaunchCookie;
404                 mLastLaunchedActivity.mLaunchCookie = null;
405                 r.mLaunchRootTask = mLastLaunchedActivity.mLaunchRootTask;
406                 mLastLaunchedActivity.mLaunchRootTask = null;
407             }
408             mLastLaunchedActivity = r;
409             mIsDrawn = r.isReportedDrawn();
410         }
411 
412         /** Returns {@code true} if the incoming activity can belong to this transition. */
canCoalesce(ActivityRecord r)413         boolean canCoalesce(ActivityRecord r) {
414             if (mLastLaunchedActivity.mDisplayContent != r.mDisplayContent
415                     || mLastLaunchedActivity.getWindowingMode() != r.getWindowingMode()) {
416                 return false;
417             }
418             // The current task should be non-null because it is just launched. While the
419             // last task can be cleared when starting activity with FLAG_ACTIVITY_CLEAR_TASK.
420             final Task lastTask = mLastLaunchedActivity.getTask();
421             final Task currentTask = r.getTask();
422             if (lastTask != null && currentTask != null) {
423                 if (lastTask == currentTask) {
424                     return true;
425                 }
426                 return lastTask.getBounds().equals(currentTask.getBounds());
427             }
428             return mLastLaunchedActivity.isUid(r.launchedFromUid);
429         }
430 
431         /** @return {@code true} if the activity matches a launched activity in this transition. */
contains(ActivityRecord r)432         boolean contains(ActivityRecord r) {
433             return r == mLastLaunchedActivity;
434         }
435 
436         /**
437          * @return {@code true} if the transition info should be sent to MetricsLogger, StatsLog, or
438          *         LaunchObserver.
439          */
isInterestingToLoggerAndObserver()440         boolean isInterestingToLoggerAndObserver() {
441             return mProcessSwitch;
442         }
443 
calculateCurrentDelay()444         int calculateCurrentDelay() {
445             return calculateDelay(SystemClock.uptimeNanos());
446         }
447 
calculateDelay(long timestampNs)448         int calculateDelay(long timestampNs) {
449             // Shouldn't take more than 25 days to launch an app, so int is fine here.
450             return (int) TimeUnit.NANOSECONDS.toMillis(
451                     timestampNs - mLaunchingState.mStartUptimeNs);
452         }
453 
454         @Override
toString()455         public String toString() {
456             return "TransitionInfo{" + Integer.toHexString(System.identityHashCode(this))
457                     + " a=" + mLastLaunchedActivity + " d=" + mIsDrawn + "}";
458         }
459     }
460 
461     static final class TransitionInfoSnapshot {
462         final private ApplicationInfo applicationInfo;
463         final private WindowProcessController processRecord;
464         final String packageName;
465         final String launchedActivityName;
466         final private String launchedActivityLaunchedFromPackage;
467         final private String launchedActivityLaunchToken;
468         final private String launchedActivityAppRecordRequiredAbi;
469         final String launchedActivityShortComponentName;
470         final private String processName;
471         @VisibleForTesting final @SourceInfo.SourceType int sourceType;
472         @VisibleForTesting final int sourceEventDelayMs;
473         final private int reason;
474         final private int startingWindowDelayMs;
475         final private int bindApplicationDelayMs;
476         final int windowsDrawnDelayMs;
477         final int type;
478         final int userId;
479         /**
480          * Elapsed time from when we launch an activity to when the app reported it was
481          * fully drawn. If this is not reported then the value is set to INVALID_DELAY.
482          */
483         final int windowsFullyDrawnDelayMs;
484         final int activityRecordIdHashCode;
485         final boolean relaunched;
486         final long timestampNs;
487         final int multiWindowLaunchType;
488 
TransitionInfoSnapshot(TransitionInfo info)489         private TransitionInfoSnapshot(TransitionInfo info) {
490             this(info, info.mLastLaunchedActivity, INVALID_DELAY);
491         }
492 
TransitionInfoSnapshot(TransitionInfo info, ActivityRecord launchedActivity, int windowsFullyDrawnDelayMs)493         private TransitionInfoSnapshot(TransitionInfo info, ActivityRecord launchedActivity,
494                 int windowsFullyDrawnDelayMs) {
495             applicationInfo = launchedActivity.info.applicationInfo;
496             packageName = launchedActivity.packageName;
497             launchedActivityName = launchedActivity.info.name;
498             launchedActivityLaunchedFromPackage = launchedActivity.launchedFromPackage;
499             launchedActivityLaunchToken = launchedActivity.info.launchToken;
500             launchedActivityAppRecordRequiredAbi = launchedActivity.app == null
501                     ? null
502                     : launchedActivity.app.getRequiredAbi();
503             reason = info.mReason;
504             sourceEventDelayMs = info.mSourceEventDelayMs;
505             startingWindowDelayMs = info.mStartingWindowDelayMs;
506             bindApplicationDelayMs = info.mBindApplicationDelayMs;
507             windowsDrawnDelayMs = info.mWindowsDrawnDelayMs;
508             type = info.mTransitionType;
509             processRecord = launchedActivity.app;
510             processName = launchedActivity.processName;
511             sourceType = info.mSourceType;
512             userId = launchedActivity.mUserId;
513             launchedActivityShortComponentName = launchedActivity.shortComponentName;
514             activityRecordIdHashCode = System.identityHashCode(launchedActivity);
515             this.windowsFullyDrawnDelayMs = windowsFullyDrawnDelayMs;
516             relaunched = info.mRelaunched;
517             timestampNs = info.mLaunchingState.mStartRealtimeNs;
518             multiWindowLaunchType = info.mMultiWindowLaunchType;
519         }
520 
getLaunchState()521         @WaitResult.LaunchState int getLaunchState() {
522             switch (type) {
523                 case TYPE_TRANSITION_WARM_LAUNCH:
524                     return LAUNCH_STATE_WARM;
525                 case TYPE_TRANSITION_HOT_LAUNCH:
526                     return relaunched ? LAUNCH_STATE_RELAUNCH : LAUNCH_STATE_HOT;
527                 case TYPE_TRANSITION_COLD_LAUNCH:
528                     return LAUNCH_STATE_COLD;
529                 default:
530                     return -1;
531             }
532         }
533 
isInterestedToEventLog()534         boolean isInterestedToEventLog() {
535             return type == TYPE_TRANSITION_WARM_LAUNCH || type == TYPE_TRANSITION_COLD_LAUNCH;
536         }
537 
getPackageOptimizationInfo(ArtManagerInternal artManagerInternal)538         PackageOptimizationInfo getPackageOptimizationInfo(ArtManagerInternal artManagerInternal) {
539             return artManagerInternal == null || launchedActivityAppRecordRequiredAbi == null
540                     ? PackageOptimizationInfo.createWithNoInfo()
541                     : artManagerInternal.getPackageOptimizationInfo(applicationInfo,
542                             launchedActivityAppRecordRequiredAbi, launchedActivityName);
543         }
544     }
545 
546     /** Information about the App Compat state logging associated with a package UID . */
547     private static final class PackageCompatStateInfo {
548         /** All activities that have a visible state. */
549         final ArrayList<ActivityRecord> mVisibleActivities = new ArrayList<>();
550         /** The last logged state. */
551         int mLastLoggedState = APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
552         @Nullable ActivityRecord mLastLoggedActivity;
553     }
554 
ActivityMetricsLogger(ActivityTaskSupervisor supervisor, Looper looper)555     ActivityMetricsLogger(ActivityTaskSupervisor supervisor, Looper looper) {
556         mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
557         mSupervisor = supervisor;
558         mLaunchObserver = new LaunchObserverRegistryImpl(looper);
559     }
560 
logWindowState(String state, int durationSecs)561     private void logWindowState(String state, int durationSecs) {
562         mMetricsLogger.count(state, durationSecs);
563     }
564 
logWindowState()565     void logWindowState() {
566         final long now = SystemClock.elapsedRealtime() / 1000;
567         if (mWindowState != WINDOW_STATE_INVALID) {
568             // We log even if the window state hasn't changed, because the user might remain in
569             // home/fullscreen move forever and we would like to track this kind of behavior
570             // too.
571             mLoggerHandler.sendMessage(PooledLambda.obtainMessage(
572                     ActivityMetricsLogger::logWindowState, this,
573                     TRON_WINDOW_STATE_VARZ_STRINGS[mWindowState], (int) (now - mLastLogTimeSecs)));
574         }
575         mLastLogTimeSecs = now;
576 
577         mWindowState = WINDOW_STATE_INVALID;
578         final Task focusedTask = mSupervisor.mRootWindowContainer.getTopDisplayFocusedRootTask();
579         if (focusedTask == null)  return;
580         if (focusedTask.isActivityTypeAssistant()) {
581             mWindowState = WINDOW_STATE_ASSISTANT;
582             return;
583         }
584 
585         @WindowingMode final int windowingMode = focusedTask.getWindowingMode();
586         switch (windowingMode) {
587             case WINDOWING_MODE_FULLSCREEN:
588                 mWindowState = WINDOW_STATE_STANDARD;
589                 break;
590             case WINDOWING_MODE_FREEFORM:
591                 mWindowState = WINDOW_STATE_FREEFORM;
592                 break;
593             case WINDOWING_MODE_MULTI_WINDOW:
594                 mWindowState = WINDOW_STATE_MULTI_WINDOW;
595                 break;
596             default:
597                 if (windowingMode != WINDOWING_MODE_UNDEFINED) {
598                     Slog.wtf(TAG, "Unknown windowing mode for task=" + focusedTask
599                             + " windowingMode=" + windowingMode);
600                 }
601         }
602     }
603 
604     /** @return Non-null {@link TransitionInfo} if the activity is found in an active transition. */
605     @Nullable
getActiveTransitionInfo(ActivityRecord r)606     private TransitionInfo getActiveTransitionInfo(ActivityRecord r) {
607         for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
608             final TransitionInfo info = mTransitionInfoList.get(i);
609             if (info.contains(r)) {
610                 return info;
611             }
612         }
613         return null;
614     }
615 
616     /**
617      * This method should be only used by starting recents and starting from recents, or internal
618      * tests. Because it doesn't lookup caller and always creates a new launching state.
619      *
620      * @see #notifyActivityLaunching(Intent, ActivityRecord, int)
621      */
notifyActivityLaunching(Intent intent)622     LaunchingState notifyActivityLaunching(Intent intent) {
623         return notifyActivityLaunching(intent, null /* caller */, IGNORE_CALLER);
624     }
625 
626     /**
627      * Notifies the tracker at the earliest possible point when we are starting to launch an
628      * activity. The caller must ensure that {@link #notifyActivityLaunched} will be called later
629      * with the returned {@link LaunchingState}. If the caller is found in an active transition,
630      * it will be considered as consecutive launch and coalesced into the active transition.
631      */
notifyActivityLaunching(Intent intent, @Nullable ActivityRecord caller, int callingUid)632     LaunchingState notifyActivityLaunching(Intent intent, @Nullable ActivityRecord caller,
633             int callingUid) {
634         TransitionInfo existingInfo = null;
635         if (callingUid != IGNORE_CALLER) {
636             // Associate the launching event to an active transition if the caller is found in its
637             // launched activities.
638             for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
639                 final TransitionInfo info = mTransitionInfoList.get(i);
640                 if (caller != null && info.contains(caller)) {
641                     existingInfo = info;
642                     break;
643                 }
644                 if (existingInfo == null && callingUid == info.mLastLaunchedActivity.getUid()) {
645                     // Fallback to check the most recent matched uid for the case that the caller is
646                     // not an activity.
647                     existingInfo = info;
648                 }
649             }
650         }
651         if (DEBUG_METRICS) {
652             Slog.i(TAG, "notifyActivityLaunching intent=" + intent
653                     + " existingInfo=" + existingInfo);
654         }
655 
656         if (existingInfo == null) {
657             final LaunchingState launchingState = new LaunchingState();
658             // Only notify the observer for a new launching event.
659             launchObserverNotifyIntentStarted(intent, launchingState.mStartUptimeNs);
660             return launchingState;
661         }
662         return existingInfo.mLaunchingState;
663     }
664 
665     /**
666      * Notifies the tracker that the activity is actually launching.
667      *
668      * @param launchingState The launching state to track the new or active transition.
669      * @param resultCode One of the {@link android.app.ActivityManager}.START_* flags, indicating
670      *                   the result of the launch.
671      * @param launchedActivity The activity that is being launched
672      * @param newActivityCreated Whether a new activity instance is created.
673      * @param options The given options of the launching activity.
674      */
notifyActivityLaunched(@onNull LaunchingState launchingState, int resultCode, boolean newActivityCreated, @Nullable ActivityRecord launchedActivity, @Nullable ActivityOptions options)675     void notifyActivityLaunched(@NonNull LaunchingState launchingState, int resultCode,
676             boolean newActivityCreated, @Nullable ActivityRecord launchedActivity,
677             @Nullable ActivityOptions options) {
678         if (launchedActivity == null || launchedActivity.getTask() == null) {
679             // The launch is aborted, e.g. intent not resolved, class not found.
680             abort(launchingState, "nothing launched");
681             return;
682         }
683 
684         final WindowProcessController processRecord = launchedActivity.app != null
685                 ? launchedActivity.app
686                 : mSupervisor.mService.getProcessController(
687                         launchedActivity.processName, launchedActivity.info.applicationInfo.uid);
688         // Whether the process that will contains the activity is already running.
689         final boolean processRunning = processRecord != null;
690         // We consider this a "process switch" if the process of the activity that gets launched
691         // didn't have an activity that was in started state. In this case, we assume that lot
692         // of caches might be purged so the time until it produces the first frame is very
693         // interesting.
694         final boolean processSwitch = !processRunning
695                 || !processRecord.hasStartedActivity(launchedActivity);
696         final int processState;
697         final int processOomAdj;
698         if (processRunning) {
699             processState = processRecord.getCurrentProcState();
700             processOomAdj = processRecord.getCurrentAdj();
701         } else {
702             processState = PROCESS_STATE_NONEXISTENT;
703             processOomAdj = INVALID_ADJ;
704         }
705 
706         final TransitionInfo info = launchingState.mAssociatedTransitionInfo;
707         if (DEBUG_METRICS) {
708             Slog.i(TAG, "notifyActivityLaunched" + " resultCode=" + resultCode
709                     + " launchedActivity=" + launchedActivity + " processRunning=" + processRunning
710                     + " processSwitch=" + processSwitch
711                     + " processState=" + processState
712                     + " processOomAdj=" + processOomAdj
713                     + " newActivityCreated=" + newActivityCreated + " info=" + info);
714         }
715 
716         if (launchedActivity.isReportedDrawn() && launchedActivity.isVisible()) {
717             // Launched activity is already visible. We cannot measure windows drawn delay.
718             abort(launchingState, "launched activity already visible");
719             return;
720         }
721 
722         // If the launched activity is started from an existing active transition, it will be put
723         // into the transition info.
724         if (info != null && info.canCoalesce(launchedActivity)) {
725             if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched consecutive launch");
726 
727             final boolean crossPackage =
728                     !info.mLastLaunchedActivity.packageName.equals(launchedActivity.packageName);
729             // The trace name uses package name so different packages should be separated.
730             if (crossPackage) {
731                 stopLaunchTrace(info);
732             }
733 
734             mLastTransitionInfo.remove(info.mLastLaunchedActivity);
735             // Coalesce multiple (trampoline) activities from a single sequence together.
736             info.setLatestLaunchedActivity(launchedActivity);
737             // Update the latest one so it can be found when reporting fully-drawn.
738             mLastTransitionInfo.put(launchedActivity, info);
739 
740             if (crossPackage) {
741                 startLaunchTrace(info);
742             }
743             scheduleCheckActivityToBeDrawnIfSleeping(launchedActivity);
744             return;
745         }
746 
747         final boolean isInTaskActivityStart = launchedActivity.getTask().isVisible();
748         final TransitionInfo newInfo = TransitionInfo.create(launchedActivity, launchingState,
749                 options, processRunning, processSwitch, processState, processOomAdj,
750                 newActivityCreated, isInTaskActivityStart, resultCode);
751         if (newInfo == null) {
752             abort(launchingState, "unrecognized launch");
753             return;
754         }
755 
756         // Look at all other transition infos and mark them as a split pair if they belong to
757         // adjacent tasks
758         updateSplitPairLaunches(newInfo);
759 
760         if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched successful");
761         // A new launch sequence has begun. Start tracking it.
762         mTransitionInfoList.add(newInfo);
763         mLastTransitionInfo.put(launchedActivity, newInfo);
764         startLaunchTrace(newInfo);
765         if (newInfo.isInterestingToLoggerAndObserver()) {
766             launchObserverNotifyActivityLaunched(newInfo);
767         } else {
768             // As abort for no process switch.
769             launchObserverNotifyIntentFailed(newInfo.mLaunchingState.mStartUptimeNs);
770         }
771         scheduleCheckActivityToBeDrawnIfSleeping(launchedActivity);
772 
773         // If the previous transitions are no longer visible, abort them to avoid counting the
774         // launch time when resuming from back stack. E.g. launch 2 independent tasks in a short
775         // time, the transition info of the first task should not keep active until it becomes
776         // visible such as after the top task is finished.
777         for (int i = mTransitionInfoList.size() - 2; i >= 0; i--) {
778             final TransitionInfo prevInfo = mTransitionInfoList.get(i);
779             if (prevInfo.mIsDrawn || !prevInfo.mLastLaunchedActivity.isVisibleRequested()) {
780                 scheduleCheckActivityToBeDrawn(prevInfo.mLastLaunchedActivity, 0 /* delay */);
781             }
782         }
783     }
784 
785     /**
786      * Updates all transition infos including the given {@param info} if they are a part of a
787      * split pair launch.
788      */
updateSplitPairLaunches(@onNull TransitionInfo info)789     private void updateSplitPairLaunches(@NonNull TransitionInfo info) {
790         final Task launchedActivityTask = info.mLastLaunchedActivity.getTask();
791         final Task adjacentToLaunchedTask = launchedActivityTask.getAdjacentTask();
792         if (adjacentToLaunchedTask == null) {
793             // Not a part of a split pair
794             return;
795         }
796         for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
797             final TransitionInfo otherInfo = mTransitionInfoList.get(i);
798             if (otherInfo == info) {
799                 continue;
800             }
801             final Task otherTask = otherInfo.mLastLaunchedActivity.getTask();
802             // The adjacent task is the split root in which activities are started
803             if (otherTask.isDescendantOf(adjacentToLaunchedTask)) {
804                 if (DEBUG_METRICS) {
805                     Slog.i(TAG, "Found adjacent tasks t1=" + launchedActivityTask.mTaskId
806                             + " t2=" + otherTask.mTaskId);
807                 }
808                 // These tasks are adjacent, so mark them as such
809                 info.mMultiWindowLaunchType = MULTI_WINDOW_LAUNCH_TYPE_APP_PAIR;
810                 otherInfo.mMultiWindowLaunchType = MULTI_WINDOW_LAUNCH_TYPE_APP_PAIR;
811             }
812         }
813     }
814 
scheduleCheckActivityToBeDrawnIfSleeping(@onNull ActivityRecord r)815     private void scheduleCheckActivityToBeDrawnIfSleeping(@NonNull ActivityRecord r) {
816         if (r.mDisplayContent.isSleeping()) {
817             // It is unknown whether the activity can be drawn or not, e.g. it depends on the
818             // keyguard states and the attributes or flags set by the activity. If the activity
819             // keeps invisible in the grace period, the tracker will be cancelled so it won't get
820             // a very long launch time that takes unlocking as the end of launch.
821             scheduleCheckActivityToBeDrawn(r, UNKNOWN_VISIBILITY_CHECK_DELAY_MS);
822         }
823     }
824 
825     /**
826      * Notifies the tracker that all windows of the app have been drawn.
827      *
828      * @return Non-null info if the activity was pending to draw, otherwise it might have been set
829      *         to invisible (removed from active transition) or it was already drawn.
830      */
831     @Nullable
notifyWindowsDrawn(@onNull ActivityRecord r)832     TransitionInfoSnapshot notifyWindowsDrawn(@NonNull ActivityRecord r) {
833         if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn " + r);
834 
835         final long timestampNs = SystemClock.uptimeNanos();
836         final TransitionInfo info = getActiveTransitionInfo(r);
837         if (info == null || info.mIsDrawn) {
838             if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn not pending drawn " + info);
839             return null;
840         }
841         // Always calculate the delay because the caller may need to know the individual drawn time.
842         info.mWindowsDrawnDelayMs = info.calculateDelay(timestampNs);
843         info.mIsDrawn = true;
844         final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
845         if (info.mLoggedTransitionStarting || (!r.mDisplayContent.mOpeningApps.contains(r)
846                 && !r.mTransitionController.isCollecting(r))) {
847             done(false /* abort */, info, "notifyWindowsDrawn", timestampNs);
848         }
849 
850         if (android.app.Flags.appStartInfoTimestamps()) {
851             // Log here to match StatsD for time to first frame.
852             mLoggerHandler.post(
853                     () -> mSupervisor.mService.mWindowManager.mAmInternal.addStartInfoTimestamp(
854                             ApplicationStartInfo.START_TIMESTAMP_FIRST_FRAME,
855                             timestampNs, r.getUid(), r.getPid(),
856                             info.mLastLaunchedActivity.mUserId));
857         }
858 
859         return infoSnapshot;
860     }
861 
862     /**
863      * Notifies the tracker that the starting window was drawn.
864      */
notifyStartingWindowDrawn(@onNull ActivityRecord r)865     void notifyStartingWindowDrawn(@NonNull ActivityRecord r) {
866         final TransitionInfo info = getActiveTransitionInfo(r);
867         if (info == null || info.mLoggedStartingWindowDrawn) {
868             return;
869         }
870         if (DEBUG_METRICS) Slog.i(TAG, "notifyStartingWindowDrawn " + r);
871         info.mLoggedStartingWindowDrawn = true;
872         info.mStartingWindowDelayMs = info.calculateCurrentDelay();
873     }
874 
875     /**
876      * Notifies the tracker that the app transition is starting.
877      *
878      * @param activityToReason A map from activity to a reason integer, which must be on of
879      *                         ActivityTaskManagerInternal.APP_TRANSITION_* reasons.
880      */
notifyTransitionStarting(ArrayMap<WindowContainer, Integer> activityToReason)881     void notifyTransitionStarting(ArrayMap<WindowContainer, Integer> activityToReason) {
882         if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting " + activityToReason);
883 
884         final long timestampNs = SystemClock.uptimeNanos();
885         for (int index = activityToReason.size() - 1; index >= 0; index--) {
886             final WindowContainer<?> wc = activityToReason.keyAt(index);
887             final ActivityRecord activity = wc.asActivityRecord();
888             final ActivityRecord r = activity != null ? activity
889                     : wc.getTopActivity(false /* includeFinishing */, true /* includeOverlays */);
890             final TransitionInfo info = getActiveTransitionInfo(r);
891             if (info == null || info.mLoggedTransitionStarting) {
892                 // Ignore any subsequent notifyTransitionStarting.
893                 continue;
894             }
895             if (DEBUG_METRICS) {
896                 Slog.i(TAG, "notifyTransitionStarting activity=" + wc + " info=" + info);
897             }
898 
899             info.mCurrentTransitionDelayMs = info.calculateDelay(timestampNs);
900             info.mReason = activityToReason.valueAt(index);
901             info.mLoggedTransitionStarting = true;
902             if (info.mIsDrawn) {
903                 done(false /* abort */, info, "notifyTransitionStarting drawn", timestampNs);
904             }
905         }
906     }
907 
notifyActivityRelaunched(ActivityRecord r)908     void notifyActivityRelaunched(ActivityRecord r) {
909         final TransitionInfo info = getActiveTransitionInfo(r);
910         if (info != null) {
911             info.mRelaunched = true;
912         }
913     }
914 
915     /** Makes sure that the reference to the removed activity is cleared. */
notifyActivityRemoved(@onNull ActivityRecord r)916     void notifyActivityRemoved(@NonNull ActivityRecord r) {
917         mLastTransitionInfo.remove(r);
918         final TransitionInfo info = getActiveTransitionInfo(r);
919         if (info != null) {
920             abort(info, "removed");
921         }
922 
923         final int packageUid = r.info.applicationInfo.uid;
924         final PackageCompatStateInfo compatStateInfo = mPackageUidToCompatStateInfo.get(packageUid);
925         if (compatStateInfo == null) {
926             return;
927         }
928 
929         compatStateInfo.mVisibleActivities.remove(r);
930         if (compatStateInfo.mLastLoggedActivity == r) {
931             compatStateInfo.mLastLoggedActivity = null;
932         }
933     }
934 
935     /**
936      * Notifies the tracker that the visibility of an app is changing.
937      *
938      * @param r the app that is changing its visibility
939      */
notifyVisibilityChanged(@onNull ActivityRecord r)940     void notifyVisibilityChanged(@NonNull ActivityRecord r) {
941         final TransitionInfo info = getActiveTransitionInfo(r);
942         if (info == null) {
943             return;
944         }
945         if (DEBUG_METRICS) {
946             Slog.i(TAG, "notifyVisibilityChanged " + r + " visible=" + r.isVisibleRequested()
947                     + " state=" + r.getState() + " finishing=" + r.finishing);
948         }
949         if (r.isState(ActivityRecord.State.RESUMED) && r.mDisplayContent.isSleeping()) {
950             // The activity may be launching while keyguard is locked. The keyguard may be dismissed
951             // after the activity finished relayout, so skip the visibility check to avoid aborting
952             // the tracking of launch event.
953             return;
954         }
955         if (!r.isVisibleRequested() || r.finishing) {
956             // Check if the tracker can be cancelled because the last launched activity may be
957             // no longer visible.
958             scheduleCheckActivityToBeDrawn(r, 0 /* delay */);
959         }
960     }
961 
scheduleCheckActivityToBeDrawn(@onNull ActivityRecord r, long delay)962     private void scheduleCheckActivityToBeDrawn(@NonNull ActivityRecord r, long delay) {
963         // The activity and its task are passed separately because it is possible that the activity
964         // is removed from the task later.
965         r.mAtmService.mH.sendMessageDelayed(PooledLambda.obtainMessage(
966                 ActivityMetricsLogger::checkActivityToBeDrawn, this, r.getTask(), r), delay);
967     }
968 
969     /** Cancels the tracking of launch if there won't be an activity to be drawn. */
checkActivityToBeDrawn(Task t, ActivityRecord r)970     private void checkActivityToBeDrawn(Task t, ActivityRecord r) {
971         synchronized (mSupervisor.mService.mGlobalLock) {
972             final TransitionInfo info = getActiveTransitionInfo(r);
973 
974             // If we have an active transition that's waiting on a certain activity that will be
975             // invisible now, we'll never get onWindowsDrawn, so abort the transition if necessary.
976 
977             // We have no active transitions. Or the notified activity whose visibility changed is
978             // no longer the launched activity, then we can still wait to get onWindowsDrawn.
979             if (info == null) {
980                 return;
981             }
982 
983             // If the task of the launched activity contains any activity to be drawn, then the
984             // window drawn event should report later to complete the transition. Otherwise all
985             // activities in this task may be finished, invisible or drawn, so the transition event
986             // should be cancelled.
987             if (t != null && t.forAllActivities(
988                     a -> a.isVisibleRequested() && !a.isReportedDrawn() && !a.finishing)) {
989                 return;
990             }
991 
992             if (DEBUG_METRICS) Slog.i(TAG, "checkActivityToBeDrawn cancels activity=" + r);
993             logAppTransitionCancel(info);
994             abort(info, "checkActivityToBeDrawn (invisible or drawn already)");
995         }
996     }
997 
998     @Nullable
getAppHibernationManagerInternal()999     private AppHibernationManagerInternal getAppHibernationManagerInternal() {
1000         if (!AppHibernationService.isAppHibernationEnabled()) return null;
1001         if (mAppHibernationManagerInternal == null) {
1002             mAppHibernationManagerInternal =
1003                     LocalServices.getService(AppHibernationManagerInternal.class);
1004         }
1005         return mAppHibernationManagerInternal;
1006     }
1007 
1008     /**
1009      * Notifies the tracker before the package is unstopped because of launching activity.
1010      * @param packageName The package to be unstopped.
1011      */
notifyBeforePackageUnstopped(@onNull String packageName)1012     void notifyBeforePackageUnstopped(@NonNull String packageName) {
1013         final AppHibernationManagerInternal ahmInternal = getAppHibernationManagerInternal();
1014         if (ahmInternal != null) {
1015             mLastHibernationStates.put(packageName, ahmInternal.isHibernatingGlobally(packageName));
1016         }
1017     }
1018 
1019     /**
1020      * Notifies the tracker that we called immediately before we call bindApplication on the client.
1021      *
1022      * @param appInfo The client into which we'll call bindApplication.
1023      */
notifyBindApplication(ApplicationInfo appInfo)1024     void notifyBindApplication(ApplicationInfo appInfo) {
1025         for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
1026             final TransitionInfo info = mTransitionInfoList.get(i);
1027 
1028             // App isn't attached to record yet, so match with info.
1029             if (info.mLastLaunchedActivity.info.applicationInfo == appInfo) {
1030                 info.mBindApplicationDelayMs = info.calculateCurrentDelay();
1031                 if (info.mProcessRunning) {
1032                     // It was HOT/WARM launch, but the process was died somehow right after the
1033                     // launch request.
1034                     info.mProcessRunning = false;
1035                     info.mTransitionType = TYPE_TRANSITION_COLD_LAUNCH;
1036                     final String msg = "Process " + info.mLastLaunchedActivity.info.processName
1037                             + " restarted";
1038                     Slog.i(TAG, msg);
1039                     if (info.mLaunchingState.mTraceName != null) {
1040                         Trace.instant(Trace.TRACE_TAG_ACTIVITY_MANAGER, msg + "#"
1041                                 + LaunchingState.sTraceSeqId);
1042                     }
1043                 }
1044             }
1045         }
1046     }
1047 
abort(@onNull LaunchingState state, String cause)1048     private void abort(@NonNull LaunchingState state, String cause) {
1049         if (state.mAssociatedTransitionInfo != null) {
1050             abort(state.mAssociatedTransitionInfo, cause);
1051             return;
1052         }
1053         if (DEBUG_METRICS) Slog.i(TAG, "abort launch cause=" + cause);
1054         state.stopTrace(true /* abort */, null /* endInfo */);
1055         launchObserverNotifyIntentFailed(state.mStartUptimeNs);
1056     }
1057 
1058     /** Aborts tracking of current launch metrics. */
abort(@onNull TransitionInfo info, String cause)1059     private void abort(@NonNull TransitionInfo info, String cause) {
1060         done(true /* abort */, info, cause, 0L /* timestampNs */);
1061     }
1062 
1063     /** Called when the given transition (info) is no longer active. */
done(boolean abort, @NonNull TransitionInfo info, String cause, long timestampNs)1064     private void done(boolean abort, @NonNull TransitionInfo info, String cause,
1065             long timestampNs) {
1066         if (DEBUG_METRICS) {
1067             Slog.i(TAG, "done abort=" + abort + " cause=" + cause + " timestamp=" + timestampNs
1068                     + " info=" + info);
1069         }
1070         info.mLaunchingState.stopTrace(abort, info);
1071         stopLaunchTrace(info);
1072         final Boolean isHibernating =
1073                 mLastHibernationStates.remove(info.mLastLaunchedActivity.packageName);
1074         if (abort) {
1075             mLastTransitionInfo.remove(info.mLastLaunchedActivity);
1076             mSupervisor.stopWaitingForActivityVisible(info.mLastLaunchedActivity);
1077             launchObserverNotifyActivityLaunchCancelled(info);
1078         } else {
1079             if (info.isInterestingToLoggerAndObserver()) {
1080                 launchObserverNotifyActivityLaunchFinished(info, timestampNs);
1081             }
1082             logAppTransitionFinished(info, isHibernating != null ? isHibernating : false);
1083             if (info.mReason == APP_TRANSITION_RECENTS_ANIM) {
1084                 logRecentsAnimationLatency(info);
1085             }
1086         }
1087         mTransitionInfoList.remove(info);
1088     }
1089 
logAppTransitionCancel(TransitionInfo info)1090     private void logAppTransitionCancel(TransitionInfo info) {
1091         final int type = info.mTransitionType;
1092         final ActivityRecord activity = info.mLastLaunchedActivity;
1093         final LogMaker builder = new LogMaker(APP_TRANSITION_CANCELLED);
1094         builder.setPackageName(activity.packageName);
1095         builder.setType(type);
1096         builder.addTaggedData(FIELD_CLASS_NAME, activity.info.name);
1097         mMetricsLogger.write(builder);
1098         FrameworkStatsLog.write(
1099                 FrameworkStatsLog.APP_START_CANCELED,
1100                 activity.info.applicationInfo.uid,
1101                 activity.packageName,
1102                 getAppStartTransitionType(type, info.mRelaunched),
1103                 activity.info.name);
1104         if (DEBUG_METRICS) {
1105             Slog.i(TAG, String.format("APP_START_CANCELED(%s, %s, %s, %s)",
1106                     activity.info.applicationInfo.uid,
1107                     activity.packageName,
1108                     getAppStartTransitionType(type, info.mRelaunched),
1109                     activity.info.name));
1110         }
1111     }
1112 
logAppTransitionFinished(@onNull TransitionInfo info, boolean isHibernating)1113     private void logAppTransitionFinished(@NonNull TransitionInfo info, boolean isHibernating) {
1114         if (DEBUG_METRICS) Slog.i(TAG, "logging finished transition " + info);
1115 
1116         // Take a snapshot of the transition info before sending it to the handler for logging.
1117         // This will avoid any races with other operations that modify the ActivityRecord.
1118         final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
1119         final boolean isOpaque = info.mLastLaunchedActivity.mStyleFillsParent;
1120         final long uptimeNs = info.mLaunchingState.mStartUptimeNs;
1121         final int transitionDelay = info.mCurrentTransitionDelayMs;
1122         final int processState = info.mProcessState;
1123         final int processOomAdj = info.mProcessOomAdj;
1124         mLoggerHandler.post(() -> {
1125             if (info.isInterestingToLoggerAndObserver()) {
1126                 logAppTransition(uptimeNs, transitionDelay, infoSnapshot, isHibernating,
1127                         processState, processOomAdj);
1128             }
1129             if (info.mIsInTaskActivityStart) {
1130                 logInTaskActivityStart(infoSnapshot, isOpaque, transitionDelay);
1131             }
1132             if (infoSnapshot.isInterestedToEventLog()) {
1133                 logAppDisplayed(infoSnapshot);
1134             }
1135         });
1136         if (info.mPendingFullyDrawn != null) {
1137             info.mPendingFullyDrawn.run();
1138         }
1139 
1140         info.mLastLaunchedActivity.info.launchToken = null;
1141     }
1142 
1143     // This gets called on another thread without holding the activity manager lock.
logAppTransition(long transitionDeviceUptimeNs, int currentTransitionDelayMs, TransitionInfoSnapshot info, boolean isHibernating, int processState, int processOomAdj)1144     private void logAppTransition(long transitionDeviceUptimeNs,
1145             int currentTransitionDelayMs, TransitionInfoSnapshot info, boolean isHibernating,
1146             int processState, int processOomAdj) {
1147         final LogMaker builder = new LogMaker(APP_TRANSITION);
1148         builder.setPackageName(info.packageName);
1149         builder.setType(info.type);
1150         builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivityName);
1151         final boolean isInstantApp = info.applicationInfo.isInstantApp();
1152         if (info.launchedActivityLaunchedFromPackage != null) {
1153             builder.addTaggedData(APP_TRANSITION_CALLING_PACKAGE_NAME,
1154                     info.launchedActivityLaunchedFromPackage);
1155         }
1156         String launchToken = info.launchedActivityLaunchToken;
1157         if (launchToken != null) {
1158             builder.addTaggedData(FIELD_INSTANT_APP_LAUNCH_TOKEN, launchToken);
1159         }
1160         builder.addTaggedData(APP_TRANSITION_IS_EPHEMERAL, isInstantApp ? 1 : 0);
1161         builder.addTaggedData(APP_TRANSITION_DEVICE_UPTIME_SECONDS,
1162                 TimeUnit.NANOSECONDS.toSeconds(transitionDeviceUptimeNs));
1163         builder.addTaggedData(APP_TRANSITION_DELAY_MS, currentTransitionDelayMs);
1164         builder.setSubtype(info.reason);
1165         if (info.startingWindowDelayMs != INVALID_DELAY) {
1166             builder.addTaggedData(APP_TRANSITION_STARTING_WINDOW_DELAY_MS,
1167                     info.startingWindowDelayMs);
1168         }
1169         if (info.bindApplicationDelayMs != INVALID_DELAY) {
1170             builder.addTaggedData(APP_TRANSITION_BIND_APPLICATION_DELAY_MS,
1171                     info.bindApplicationDelayMs);
1172         }
1173         builder.addTaggedData(APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS, info.windowsDrawnDelayMs);
1174         final PackageOptimizationInfo packageOptimizationInfo =
1175                 info.getPackageOptimizationInfo(getArtManagerInternal());
1176         builder.addTaggedData(PACKAGE_OPTIMIZATION_COMPILATION_REASON,
1177                 packageOptimizationInfo.getCompilationReason());
1178         builder.addTaggedData(PACKAGE_OPTIMIZATION_COMPILATION_FILTER,
1179                 packageOptimizationInfo.getCompilationFilter());
1180         mMetricsLogger.write(builder);
1181 
1182         // Incremental info
1183         boolean isIncremental = false, isLoading = false;
1184         final String codePath = info.applicationInfo.getCodePath();
1185         if (codePath != null && IncrementalManager.isIncrementalPath(codePath)) {
1186             isIncremental = true;
1187             isLoading = isIncrementalLoading(info.packageName, info.userId);
1188         }
1189         final boolean stopped = wasStoppedNeedsLogging(info);
1190         final int packageState = stopped
1191                 ? APP_START_OCCURRED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_STOPPED
1192                 : APP_START_OCCURRED__PACKAGE_STOPPED_STATE__PACKAGE_STATE_NORMAL;
1193 
1194         final boolean firstLaunch = wasFirstLaunch(info);
1195         FrameworkStatsLog.write(
1196                 FrameworkStatsLog.APP_START_OCCURRED,
1197                 info.applicationInfo.uid,
1198                 info.packageName,
1199                 getAppStartTransitionType(info.type, info.relaunched),
1200                 info.launchedActivityName,
1201                 info.launchedActivityLaunchedFromPackage,
1202                 isInstantApp,
1203                 0 /* deprecated transitionDeviceUptimeMs */,
1204                 info.reason,
1205                 currentTransitionDelayMs,
1206                 info.startingWindowDelayMs,
1207                 info.bindApplicationDelayMs,
1208                 info.windowsDrawnDelayMs,
1209                 launchToken,
1210                 packageOptimizationInfo.getCompilationReason(),
1211                 packageOptimizationInfo.getCompilationFilter(),
1212                 info.sourceType,
1213                 info.sourceEventDelayMs,
1214                 isHibernating,
1215                 isIncremental,
1216                 isLoading,
1217                 info.launchedActivityName.hashCode(),
1218                 TimeUnit.NANOSECONDS.toMillis(info.timestampNs),
1219                 processState,
1220                 processOomAdj,
1221                 packageState,
1222                 false, // is_xr_activity
1223                 firstLaunch,
1224                 0L /* TODO: stoppedDuration */,
1225                 info.multiWindowLaunchType);
1226         // Reset the stopped state to avoid reporting stopped again
1227         if (info.processRecord != null) {
1228             info.processRecord.setWasStoppedLogged(true);
1229         }
1230 
1231         if (DEBUG_METRICS) {
1232             Slog.i(TAG, String.format(
1233                     "APP_START_OCCURRED(%s, %s, %s, %s, %s, wasStopped=%b, firstLaunch=%b)",
1234                     info.applicationInfo.uid,
1235                     info.packageName,
1236                     getAppStartTransitionType(info.type, info.relaunched),
1237                     info.launchedActivityName,
1238                     info.launchedActivityLaunchedFromPackage,
1239                     stopped, firstLaunch));
1240         }
1241 
1242         logAppStartMemoryStateCapture(info);
1243     }
1244 
isIncrementalLoading(String packageName, int userId)1245     private boolean isIncrementalLoading(String packageName, int userId) {
1246         final IncrementalStatesInfo info = mSupervisor.mService.getPackageManagerInternalLocked()
1247                 .getIncrementalStatesInfo(packageName, 0 /* filterCallingUid */, userId);
1248         return info != null && info.isLoading();
1249     }
1250 
1251     @VisibleForTesting
logInTaskActivityStart(TransitionInfoSnapshot info, boolean isOpaque, int transitionDelayMs)1252     void logInTaskActivityStart(TransitionInfoSnapshot info, boolean isOpaque,
1253             int transitionDelayMs) {
1254         if (DEBUG_METRICS) {
1255             Slog.i(TAG, "IN_TASK_ACTIVITY_STARTED " + info.launchedActivityName
1256                     + " transitionDelayMs=" + transitionDelayMs + "ms");
1257         }
1258         FrameworkStatsLog.write(FrameworkStatsLog.IN_TASK_ACTIVITY_STARTED,
1259                 info.applicationInfo.uid,
1260                 getAppStartTransitionType(info.type, info.relaunched),
1261                 isOpaque,
1262                 transitionDelayMs,
1263                 info.windowsDrawnDelayMs,
1264                 TimeUnit.NANOSECONDS.toMillis(info.timestampNs));
1265     }
1266 
logAppDisplayed(TransitionInfoSnapshot info)1267     private void logAppDisplayed(TransitionInfoSnapshot info) {
1268         EventLog.writeEvent(WM_ACTIVITY_LAUNCH_TIME,
1269                 info.userId, info.activityRecordIdHashCode, info.launchedActivityShortComponentName,
1270                 info.windowsDrawnDelayMs);
1271 
1272         StringBuilder sb = mStringBuilder;
1273         sb.setLength(0);
1274         sb.append("Displayed ");
1275         sb.append(info.launchedActivityShortComponentName);
1276         sb.append(" for user ");
1277         sb.append(info.userId);
1278         sb.append(": ");
1279         TimeUtils.formatDuration(info.windowsDrawnDelayMs, sb);
1280         Log.i(TAG, sb.toString());
1281     }
1282 
logRecentsAnimationLatency(TransitionInfo info)1283     private void logRecentsAnimationLatency(TransitionInfo info) {
1284         final int duration = info.mSourceEventDelayMs + info.mWindowsDrawnDelayMs;
1285         final ActivityRecord r = info.mLastLaunchedActivity;
1286         final long lastTopLossTime = r.topResumedStateLossTime;
1287         final WindowManagerService wm = mSupervisor.mService.mWindowManager;
1288         final Object controller = wm.getRecentsAnimationController();
1289         mLoggerHandler.postDelayed(() -> {
1290             if (lastTopLossTime != r.topResumedStateLossTime
1291                     || controller != wm.getRecentsAnimationController()) {
1292                 // Skip if the animation was finished in a short time.
1293                 return;
1294             }
1295             wm.mLatencyTracker.logAction(LatencyTracker.ACTION_START_RECENTS_ANIMATION, duration);
1296         }, LATENCY_TRACKER_RECENTS_DELAY_MS);
1297     }
1298 
getAppStartTransitionType(int tronType, boolean relaunched)1299     private static int getAppStartTransitionType(int tronType, boolean relaunched) {
1300         if (tronType == TYPE_TRANSITION_COLD_LAUNCH) {
1301             return FrameworkStatsLog.APP_START_OCCURRED__TYPE__COLD;
1302         }
1303         if (tronType == TYPE_TRANSITION_WARM_LAUNCH) {
1304             return FrameworkStatsLog.APP_START_OCCURRED__TYPE__WARM;
1305         }
1306         if (tronType == TYPE_TRANSITION_HOT_LAUNCH) {
1307             return relaunched
1308                     ? FrameworkStatsLog.APP_START_OCCURRED__TYPE__RELAUNCH
1309                     : FrameworkStatsLog.APP_START_OCCURRED__TYPE__HOT;
1310         }
1311         return FrameworkStatsLog.APP_START_OCCURRED__TYPE__UNKNOWN;
1312     }
1313 
1314     /** @see android.app.Activity#reportFullyDrawn */
notifyFullyDrawn(ActivityRecord r, boolean restoredFromBundle)1315     TransitionInfoSnapshot notifyFullyDrawn(ActivityRecord r, boolean restoredFromBundle) {
1316         final TransitionInfo info = mLastTransitionInfo.get(r);
1317         if (info == null) {
1318             return null;
1319         }
1320         if (!info.mIsDrawn && info.mPendingFullyDrawn == null) {
1321             // There are still undrawn activities, postpone reporting fully drawn until all of its
1322             // windows are drawn. So that is closer to an usable state.
1323             info.mPendingFullyDrawn = () -> {
1324                 notifyFullyDrawn(r, restoredFromBundle);
1325                 info.mPendingFullyDrawn = null;
1326             };
1327             return null;
1328         }
1329 
1330         final long currentTimestampNs = SystemClock.uptimeNanos();
1331         final long startupTimeMs = info.mPendingFullyDrawn != null
1332                 ? info.mWindowsDrawnDelayMs
1333                 : TimeUnit.NANOSECONDS.toMillis(
1334                         currentTimestampNs - info.mLaunchingState.mStartUptimeNs);
1335         final TransitionInfoSnapshot infoSnapshot =
1336                 new TransitionInfoSnapshot(info, r, (int) startupTimeMs);
1337         if (infoSnapshot.isInterestedToEventLog()) {
1338             mLoggerHandler.post(() -> logAppFullyDrawn(infoSnapshot));
1339         }
1340         mLastTransitionInfo.remove(r);
1341 
1342         if (!info.isInterestingToLoggerAndObserver()) {
1343             return infoSnapshot;
1344         }
1345 
1346         // Record the handling of the reportFullyDrawn callback in the trace system. This is not
1347         // actually used to trace this function, but instead the logical task that this function
1348         // fullfils (handling reportFullyDrawn() callbacks).
1349         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1350                 "ActivityManager:ReportingFullyDrawn " + info.mLastLaunchedActivity.packageName);
1351         mLoggerHandler.post(() -> logAppFullyDrawnMetrics(infoSnapshot, restoredFromBundle,
1352                 info.mProcessRunning));
1353         // Ends the trace started at the beginning of this function. This is located here to allow
1354         // the trace slice to have a noticable duration.
1355         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1356 
1357         // Notify reportFullyDrawn event.
1358         launchObserverNotifyReportFullyDrawn(info, currentTimestampNs);
1359 
1360         return infoSnapshot;
1361     }
1362 
logAppFullyDrawnMetrics(TransitionInfoSnapshot info, boolean restoredFromBundle, boolean processRunning)1363     private void logAppFullyDrawnMetrics(TransitionInfoSnapshot info, boolean restoredFromBundle,
1364             boolean processRunning) {
1365         final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN);
1366         builder.setPackageName(info.packageName);
1367         builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivityName);
1368         builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS,
1369                 (long) info.windowsFullyDrawnDelayMs);
1370         builder.setType(restoredFromBundle
1371                 ? TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE
1372                 : TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE);
1373         builder.addTaggedData(APP_TRANSITION_PROCESS_RUNNING, processRunning ? 1 : 0);
1374         mMetricsLogger.write(builder);
1375         final PackageOptimizationInfo packageOptimizationInfo =
1376                 info.getPackageOptimizationInfo(getArtManagerInternal());
1377         // Incremental info
1378         boolean isIncremental = false, isLoading = false;
1379         final String codePath = info.applicationInfo.getCodePath();
1380         if (codePath != null && IncrementalManager.isIncrementalPath(codePath)) {
1381             isIncremental = true;
1382             isLoading = isIncrementalLoading(info.packageName, info.userId);
1383         }
1384         FrameworkStatsLog.write(
1385                 FrameworkStatsLog.APP_START_FULLY_DRAWN,
1386                 info.applicationInfo.uid,
1387                 info.packageName,
1388                 restoredFromBundle
1389                         ? FrameworkStatsLog.APP_START_FULLY_DRAWN__TYPE__WITH_BUNDLE
1390                         : FrameworkStatsLog.APP_START_FULLY_DRAWN__TYPE__WITHOUT_BUNDLE,
1391                 info.launchedActivityName,
1392                 processRunning,
1393                 info.windowsFullyDrawnDelayMs,
1394                 packageOptimizationInfo.getCompilationReason(),
1395                 packageOptimizationInfo.getCompilationFilter(),
1396                 info.sourceType,
1397                 info.sourceEventDelayMs,
1398                 isIncremental,
1399                 isLoading,
1400                 info.launchedActivityName.hashCode(),
1401                 TimeUnit.NANOSECONDS.toMillis(info.timestampNs));
1402     }
1403 
logAppFullyDrawn(TransitionInfoSnapshot info)1404     private void logAppFullyDrawn(TransitionInfoSnapshot info) {
1405         StringBuilder sb = mStringBuilder;
1406         sb.setLength(0);
1407         sb.append("Fully drawn ");
1408         sb.append(info.launchedActivityShortComponentName);
1409         sb.append(": ");
1410         TimeUtils.formatDuration(info.windowsFullyDrawnDelayMs, sb);
1411         Log.i(TAG, sb.toString());
1412     }
1413 
logAbortedBgActivityStart(Intent intent, WindowProcessController callerApp, int callingUid, String callingPackage, int callingUidProcState, boolean callingUidHasAnyVisibleWindow, int realCallingUid, int realCallingUidProcState, boolean realCallingUidHasAnyVisibleWindow, boolean comingFromPendingIntent)1414     void logAbortedBgActivityStart(Intent intent, WindowProcessController callerApp,
1415             int callingUid, String callingPackage, int callingUidProcState,
1416             boolean callingUidHasAnyVisibleWindow,
1417             int realCallingUid, int realCallingUidProcState,
1418             boolean realCallingUidHasAnyVisibleWindow,
1419             boolean comingFromPendingIntent) {
1420 
1421         final long nowElapsed = SystemClock.elapsedRealtime();
1422         final long nowUptime = SystemClock.uptimeMillis();
1423         final LogMaker builder = new LogMaker(ACTION_ACTIVITY_START);
1424         builder.setTimestamp(System.currentTimeMillis());
1425         builder.addTaggedData(FIELD_CALLING_UID, callingUid);
1426         builder.addTaggedData(FIELD_CALLING_PACKAGE_NAME, callingPackage);
1427         builder.addTaggedData(FIELD_CALLING_UID_PROC_STATE,
1428                 processStateAmToProto(callingUidProcState));
1429         builder.addTaggedData(FIELD_CALLING_UID_HAS_ANY_VISIBLE_WINDOW,
1430                 callingUidHasAnyVisibleWindow ? 1 : 0);
1431         builder.addTaggedData(FIELD_REAL_CALLING_UID, realCallingUid);
1432         builder.addTaggedData(FIELD_REAL_CALLING_UID_PROC_STATE,
1433                 processStateAmToProto(realCallingUidProcState));
1434         builder.addTaggedData(FIELD_REAL_CALLING_UID_HAS_ANY_VISIBLE_WINDOW,
1435                 realCallingUidHasAnyVisibleWindow ? 1 : 0);
1436         builder.addTaggedData(FIELD_COMING_FROM_PENDING_INTENT, comingFromPendingIntent ? 1 : 0);
1437         if (intent != null) {
1438             builder.addTaggedData(FIELD_INTENT_ACTION, intent.getAction());
1439             ComponentName component = intent.getComponent();
1440             if (component != null) {
1441                 builder.addTaggedData(FIELD_TARGET_SHORT_COMPONENT_NAME,
1442                         component.flattenToShortString());
1443             }
1444         }
1445         if (callerApp != null) {
1446             builder.addTaggedData(FIELD_PROCESS_RECORD_PROCESS_NAME, callerApp.mName);
1447             builder.addTaggedData(FIELD_PROCESS_RECORD_CUR_PROC_STATE,
1448                     processStateAmToProto(callerApp.getCurrentProcState()));
1449             builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_CLIENT_ACTIVITIES,
1450                     callerApp.hasClientActivities() ? 1 : 0);
1451             builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_FOREGROUND_SERVICES,
1452                     callerApp.hasForegroundServices() ? 1 : 0);
1453             builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_FOREGROUND_ACTIVITIES,
1454                     callerApp.hasForegroundActivities() ? 1 : 0);
1455             builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_TOP_UI, callerApp.hasTopUi() ? 1 : 0);
1456             builder.addTaggedData(FIELD_PROCESS_RECORD_HAS_OVERLAY_UI,
1457                     callerApp.hasOverlayUi() ? 1 : 0);
1458             builder.addTaggedData(FIELD_PROCESS_RECORD_PENDING_UI_CLEAN,
1459                     callerApp.hasPendingUiClean() ? 1 : 0);
1460             if (callerApp.getInteractionEventTime() != 0) {
1461                 builder.addTaggedData(FIELD_PROCESS_RECORD_MILLIS_SINCE_LAST_INTERACTION_EVENT,
1462                         (nowElapsed - callerApp.getInteractionEventTime()));
1463             }
1464             if (callerApp.getFgInteractionTime() != 0) {
1465                 builder.addTaggedData(FIELD_PROCESS_RECORD_MILLIS_SINCE_FG_INTERACTION,
1466                         (nowElapsed - callerApp.getFgInteractionTime()));
1467             }
1468             if (callerApp.getWhenUnimportant() != 0) {
1469                 builder.addTaggedData(FIELD_PROCESS_RECORD_MILLIS_SINCE_UNIMPORTANT,
1470                         (nowUptime - callerApp.getWhenUnimportant()));
1471             }
1472         }
1473         mMetricsLogger.write(builder);
1474     }
1475 
logAppStartMemoryStateCapture(TransitionInfoSnapshot info)1476     private void logAppStartMemoryStateCapture(TransitionInfoSnapshot info) {
1477         if (info.processRecord == null) {
1478             if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture processRecord null");
1479             return;
1480         }
1481 
1482         final int pid = info.processRecord.getPid();
1483         final int uid = info.applicationInfo.uid;
1484         final MemoryStat memoryStat = readMemoryStatFromFilesystem(uid, pid);
1485         if (memoryStat == null) {
1486             if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture memoryStat null");
1487             return;
1488         }
1489 
1490         FrameworkStatsLog.write(
1491                 FrameworkStatsLog.APP_START_MEMORY_STATE_CAPTURED,
1492                 uid,
1493                 info.processName,
1494                 info.launchedActivityName,
1495                 memoryStat.pgfault,
1496                 memoryStat.pgmajfault,
1497                 memoryStat.rssInBytes,
1498                 memoryStat.cacheInBytes,
1499                 memoryStat.swapInBytes);
1500     }
1501 
1502     /**
1503      * Logs the current App Compat state of the given {@link ActivityRecord} with its package
1504      * UID, if all of the following hold:
1505      * <ul>
1506      *   <li>The current state is different than the last logged state for the package UID of the
1507      *   activity.
1508      *   <li>If the current state is NOT_VISIBLE, there is a previously logged state for the
1509      *   package UID and there are no other visible activities with the same package UID.
1510      *   <li>The last logged activity with the same package UID is either {@code activity} (or an
1511      *   activity that has been removed) or the last logged state is NOT_VISIBLE or NOT_LETTERBOXED.
1512      * </ul>
1513      *
1514      * <p>If the current state is NOT_VISIBLE and the previous state which was logged by {@code
1515      * activity} (or an activity that has been removed) wasn't, looks for the first visible activity
1516      * with the same package UID that has a letterboxed state, or a non-letterboxed state if
1517      * there isn't one, and logs that state.
1518      *
1519      * <p>This method assumes that the caller is wrapping the call with a synchronized block so
1520      * that there won't be a race condition between two activities with the same package.
1521      */
logAppCompatState(@onNull ActivityRecord activity)1522     void logAppCompatState(@NonNull ActivityRecord activity) {
1523         final int packageUid = activity.info.applicationInfo.uid;
1524         final int state = activity.getAppCompatState();
1525 
1526         if (!mPackageUidToCompatStateInfo.contains(packageUid)) {
1527             mPackageUidToCompatStateInfo.put(packageUid, new PackageCompatStateInfo());
1528         }
1529         final PackageCompatStateInfo compatStateInfo = mPackageUidToCompatStateInfo.get(packageUid);
1530         final int lastLoggedState = compatStateInfo.mLastLoggedState;
1531         final ActivityRecord lastLoggedActivity = compatStateInfo.mLastLoggedActivity;
1532 
1533         final boolean isVisible = state != APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
1534         final ArrayList<ActivityRecord> visibleActivities = compatStateInfo.mVisibleActivities;
1535         if (isVisible && !visibleActivities.contains(activity)) {
1536             visibleActivities.add(activity);
1537         } else if (!isVisible) {
1538             visibleActivities.remove(activity);
1539             if (visibleActivities.isEmpty()) {
1540                 // No need to keep the entry if there are no visible activities.
1541                 mPackageUidToCompatStateInfo.remove(packageUid);
1542             }
1543         }
1544 
1545         if (state == lastLoggedState) {
1546             // We don’t want to log the same state twice or log DEFAULT_NOT_VISIBLE before any
1547             // visible state was logged.
1548             return;
1549         }
1550 
1551         if (!isVisible && !visibleActivities.isEmpty()) {
1552             // There is another visible activity for this package UID.
1553             if (lastLoggedActivity == null || activity == lastLoggedActivity) {
1554                 // Make sure a new visible state is logged if needed.
1555                 findAppCompatStateToLog(compatStateInfo, packageUid);
1556             }
1557             return;
1558         }
1559 
1560         if (lastLoggedActivity != null && activity != lastLoggedActivity
1561                 && lastLoggedState != APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE
1562                 && lastLoggedState != APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED) {
1563             // Another visible activity for this package UID has logged a letterboxed state.
1564             return;
1565         }
1566 
1567         logAppCompatStateInternal(activity, state, compatStateInfo);
1568     }
1569 
1570     /**
1571      * Looks for the first visible activity in {@code compatStateInfo} that has a letterboxed
1572      * state, or a non-letterboxed state if there isn't one, and logs that state for the given
1573      * {@code packageUid}.
1574      *
1575      * <p>If there is a visible activity in {@code compatStateInfo} with the same state as the
1576      * last logged state for the given {@code packageUid}, changes the last logged activity to
1577      * reference the first such activity without actually logging the same state twice.
1578      */
findAppCompatStateToLog(PackageCompatStateInfo compatStateInfo, int packageUid)1579     private void findAppCompatStateToLog(PackageCompatStateInfo compatStateInfo, int packageUid) {
1580         final ArrayList<ActivityRecord> visibleActivities = compatStateInfo.mVisibleActivities;
1581         final int lastLoggedState = compatStateInfo.mLastLoggedState;
1582 
1583         ActivityRecord activityToLog = null;
1584         int stateToLog = APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
1585         for (int i = 0; i < visibleActivities.size(); i++) {
1586             ActivityRecord activity = visibleActivities.get(i);
1587             int state = activity.getAppCompatState();
1588             if (state == lastLoggedState) {
1589                 // Change last logged activity without logging the same state twice.
1590                 compatStateInfo.mLastLoggedActivity = activity;
1591                 return;
1592             }
1593             if (state == APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE) {
1594                 // This shouldn't happen.
1595                 Slog.w(TAG, "Visible activity with NOT_VISIBLE App Compat state for package UID: "
1596                         + packageUid);
1597                 continue;
1598             }
1599             if (stateToLog == APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE || (
1600                     stateToLog == APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED
1601                             && state != APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED)) {
1602                 activityToLog = activity;
1603                 stateToLog = state;
1604             }
1605         }
1606         if (activityToLog != null && stateToLog != APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE) {
1607             logAppCompatStateInternal(activityToLog, stateToLog, compatStateInfo);
1608         }
1609     }
1610 
isAppCompateStateChangedToLetterboxed(int state)1611     private static boolean isAppCompateStateChangedToLetterboxed(int state) {
1612         return state == APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO
1613                 || state == APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION
1614                 || state == APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
1615     }
1616 
logAppCompatStateInternal(@onNull ActivityRecord activity, int state, PackageCompatStateInfo compatStateInfo)1617     private void logAppCompatStateInternal(@NonNull ActivityRecord activity, int state,
1618              PackageCompatStateInfo compatStateInfo) {
1619         compatStateInfo.mLastLoggedState = state;
1620         compatStateInfo.mLastLoggedActivity = activity;
1621         int packageUid = activity.info.applicationInfo.uid;
1622 
1623         int positionToLog = APP_COMPAT_STATE_CHANGED__LETTERBOX_POSITION__NOT_LETTERBOXED_POSITION;
1624         if (isAppCompateStateChangedToLetterboxed(state)) {
1625             positionToLog = activity.mLetterboxUiController.getLetterboxPositionForLogging();
1626         }
1627         FrameworkStatsLog.write(FrameworkStatsLog.APP_COMPAT_STATE_CHANGED,
1628                 packageUid, state, positionToLog);
1629 
1630         if (DEBUG_METRICS) {
1631             Slog.i(TAG, String.format("APP_COMPAT_STATE_CHANGED(%s, %s, %s)",
1632                     packageUid, state, positionToLog));
1633         }
1634     }
1635 
1636     /**
1637      * Logs the changing of the letterbox position along with its package UID
1638      */
logLetterboxPositionChange(@onNull ActivityRecord activity, int position)1639     void logLetterboxPositionChange(@NonNull ActivityRecord activity, int position) {
1640         int packageUid = activity.info.applicationInfo.uid;
1641         FrameworkStatsLog.write(FrameworkStatsLog.LETTERBOX_POSITION_CHANGED, packageUid, position);
1642 
1643         if (!mPackageUidToCompatStateInfo.contains(packageUid)) {
1644             // There is no last logged activity for this packageUid so we should not log the
1645             // position change as we can only log the position change for the current activity
1646             return;
1647         }
1648         final PackageCompatStateInfo compatStateInfo = mPackageUidToCompatStateInfo.get(packageUid);
1649         final ActivityRecord lastLoggedActivity = compatStateInfo.mLastLoggedActivity;
1650         if (activity != lastLoggedActivity) {
1651             // Only log the position change for the current activity to be consistent with
1652             // findAppCompatStateToLog and ensure that metrics for the state changes are computed
1653             // correctly
1654             return;
1655         }
1656         int state = activity.getAppCompatState();
1657         logAppCompatStateInternal(activity, state, compatStateInfo);
1658 
1659         if (DEBUG_METRICS) {
1660             Slog.i(TAG, String.format("LETTERBOX_POSITION_CHANGED(%s, %s)",
1661                     packageUid, position));
1662         }
1663     }
1664 
1665     /**
1666      * Logs the Camera Compat Control appeared event that corresponds to the given {@code state}
1667      * with the given {@code packageUid}.
1668      */
logCameraCompatControlAppearedEventReported(@ameraCompatControlState int state, int packageUid)1669     void logCameraCompatControlAppearedEventReported(@CameraCompatControlState int state,
1670             int packageUid) {
1671         switch (state) {
1672             case CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED:
1673                 logCameraCompatControlEventReported(
1674                         CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__APPEARED_APPLY_TREATMENT,
1675                         packageUid);
1676                 break;
1677             case CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED:
1678                 logCameraCompatControlEventReported(
1679                         CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__APPEARED_REVERT_TREATMENT,
1680                         packageUid);
1681                 break;
1682             case CAMERA_COMPAT_CONTROL_HIDDEN:
1683                 // Nothing to log.
1684                 break;
1685             default:
1686                 Slog.w(TAG, "Unexpected state in logCameraCompatControlAppearedEventReported: "
1687                         + state);
1688                 break;
1689         }
1690     }
1691 
1692     /**
1693      * Logs the Camera Compat Control clicked event that corresponds to the given {@code state}
1694      * with the given {@code packageUid}.
1695      */
logCameraCompatControlClickedEventReported(@ameraCompatControlState int state, int packageUid)1696     void logCameraCompatControlClickedEventReported(@CameraCompatControlState int state,
1697             int packageUid) {
1698         switch (state) {
1699             case CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED:
1700                 logCameraCompatControlEventReported(
1701                         CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_APPLY_TREATMENT,
1702                         packageUid);
1703                 break;
1704             case CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED:
1705                 logCameraCompatControlEventReported(
1706                         CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_REVERT_TREATMENT,
1707                         packageUid);
1708                 break;
1709             case CAMERA_COMPAT_CONTROL_DISMISSED:
1710                 logCameraCompatControlEventReported(
1711                         CAMERA_COMPAT_CONTROL_EVENT_REPORTED__EVENT__CLICKED_DISMISS,
1712                         packageUid);
1713                 break;
1714             default:
1715                 Slog.w(TAG, "Unexpected state in logCameraCompatControlAppearedEventReported: "
1716                         + state);
1717                 break;
1718         }
1719     }
1720 
logCameraCompatControlEventReported(int event, int packageUid)1721     private void logCameraCompatControlEventReported(int event, int packageUid) {
1722         FrameworkStatsLog.write(FrameworkStatsLog.CAMERA_COMPAT_CONTROL_EVENT_REPORTED, packageUid,
1723                 event);
1724         if (DEBUG_METRICS) {
1725             Slog.i(TAG, String.format("CAMERA_COMPAT_CONTROL_EVENT_REPORTED(%s, %s)", packageUid,
1726                     event));
1727         }
1728     }
1729 
getArtManagerInternal()1730     private ArtManagerInternal getArtManagerInternal() {
1731         if (mArtManagerInternal == null) {
1732             // Note that this may be null.
1733             // ArtManagerInternal is registered during PackageManagerService
1734             // initialization which happens after ActivityManagerService.
1735             mArtManagerInternal = LocalServices.getService(ArtManagerInternal.class);
1736         }
1737         return mArtManagerInternal;
1738     }
1739 
1740     /** Starts trace for an activity is actually launching. */
startLaunchTrace(@onNull TransitionInfo info)1741     private void startLaunchTrace(@NonNull TransitionInfo info) {
1742         if (DEBUG_METRICS) Slog.i(TAG, "startLaunchTrace " + info);
1743         if (info.mLaunchingState.mTraceName == null) {
1744             return;
1745         }
1746         info.mLaunchTraceName = "launching: " + info.mLastLaunchedActivity.packageName;
1747         Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName,
1748                 (int) info.mLaunchingState.mStartRealtimeNs /* cookie */);
1749     }
1750 
1751     /** Stops trace for the launch is completed or cancelled. */
stopLaunchTrace(@onNull TransitionInfo info)1752     private void stopLaunchTrace(@NonNull TransitionInfo info) {
1753         if (DEBUG_METRICS) Slog.i(TAG, "stopLaunchTrace " + info);
1754         if (info.mLaunchTraceName == null) {
1755             return;
1756         }
1757         Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName,
1758                 (int) info.mLaunchingState.mStartRealtimeNs /* cookie */);
1759         info.mLaunchTraceName = null;
1760     }
1761 
getLaunchObserverRegistry()1762     public ActivityMetricsLaunchObserverRegistry getLaunchObserverRegistry() {
1763         return mLaunchObserver;
1764     }
1765 
1766     /** Notify the {@link ActivityMetricsLaunchObserver} that a new launch sequence has begun. */
launchObserverNotifyIntentStarted(Intent intent, long timestampNs)1767     private void launchObserverNotifyIntentStarted(Intent intent, long timestampNs) {
1768         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1769                 "MetricsLogger:launchObserverNotifyIntentStarted");
1770 
1771         // Beginning a launch is timing sensitive and so should be observed as soon as possible.
1772         mLaunchObserver.onIntentStarted(intent, timestampNs);
1773 
1774         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1775     }
1776 
1777     /**
1778      * Notify the {@link ActivityMetricsLaunchObserver} that the previous launch sequence has
1779      * aborted due to intent failure (e.g. intent resolve failed or security error, etc) or
1780      * intent being delivered to the top running activity.
1781      */
launchObserverNotifyIntentFailed(long id)1782     private void launchObserverNotifyIntentFailed(long id) {
1783        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1784                 "MetricsLogger:launchObserverNotifyIntentFailed");
1785 
1786         mLaunchObserver.onIntentFailed(id);
1787 
1788         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1789     }
1790 
1791     /**
1792      * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence's activity
1793      * has started.
1794      */
launchObserverNotifyActivityLaunched(TransitionInfo info)1795     private void launchObserverNotifyActivityLaunched(TransitionInfo info) {
1796         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1797                 "MetricsLogger:launchObserverNotifyActivityLaunched");
1798 
1799         @ActivityMetricsLaunchObserver.Temperature int temperature =
1800                 convertTransitionTypeToLaunchObserverTemperature(info.mTransitionType);
1801 
1802         // Beginning a launch is timing sensitive and so should be observed as soon as possible.
1803         mLaunchObserver.onActivityLaunched(info.mLaunchingState.mStartUptimeNs,
1804                 info.mLastLaunchedActivity.mActivityComponent, temperature,
1805                 info.mLastLaunchedActivity.mUserId);
1806 
1807         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1808     }
1809 
1810     /**
1811      * Notifies the {@link ActivityMetricsLaunchObserver} the reportFullDrawn event.
1812      */
launchObserverNotifyReportFullyDrawn(TransitionInfo info, long timestampNs)1813     private void launchObserverNotifyReportFullyDrawn(TransitionInfo info, long timestampNs) {
1814         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1815             "MetricsLogger:launchObserverNotifyReportFullyDrawn");
1816         mLaunchObserver.onReportFullyDrawn(info.mLaunchingState.mStartUptimeNs, timestampNs);
1817         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1818     }
1819 
1820     /**
1821      * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence is
1822      * cancelled.
1823      */
launchObserverNotifyActivityLaunchCancelled(TransitionInfo info)1824     private void launchObserverNotifyActivityLaunchCancelled(TransitionInfo info) {
1825         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1826                 "MetricsLogger:launchObserverNotifyActivityLaunchCancelled");
1827 
1828         mLaunchObserver.onActivityLaunchCancelled(info.mLaunchingState.mStartUptimeNs);
1829 
1830         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1831     }
1832 
1833     /**
1834      * Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence's activity
1835      * has fully finished (successfully).
1836      */
launchObserverNotifyActivityLaunchFinished(TransitionInfo info, long timestampNs)1837     private void launchObserverNotifyActivityLaunchFinished(TransitionInfo info, long timestampNs) {
1838         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1839                 "MetricsLogger:launchObserverNotifyActivityLaunchFinished");
1840 
1841         mLaunchObserver.onActivityLaunchFinished(info.mLaunchingState.mStartUptimeNs,
1842                 info.mLastLaunchedActivity.mActivityComponent, timestampNs,
1843                 info.mLastLaunchedActivity.launchMode);
1844 
1845         Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1846     }
1847 
1848     private static @ActivityMetricsLaunchObserver.Temperature int
convertTransitionTypeToLaunchObserverTemperature(int transitionType)1849             convertTransitionTypeToLaunchObserverTemperature(int transitionType) {
1850         switch (transitionType) {
1851             case TYPE_TRANSITION_WARM_LAUNCH:
1852                 return ActivityMetricsLaunchObserver.TEMPERATURE_WARM;
1853             case TYPE_TRANSITION_HOT_LAUNCH:
1854                 return ActivityMetricsLaunchObserver.TEMPERATURE_HOT;
1855             case TYPE_TRANSITION_COLD_LAUNCH:
1856                 return ActivityMetricsLaunchObserver.TEMPERATURE_COLD;
1857             default:
1858                 return -1;
1859         }
1860     }
1861 
wasStoppedNeedsLogging(TransitionInfoSnapshot info)1862     private boolean wasStoppedNeedsLogging(TransitionInfoSnapshot info) {
1863         if (info.processRecord != null) {
1864             return (info.processRecord.wasForceStopped()
1865                         || info.processRecord.wasFirstLaunch())
1866                     && !info.processRecord.getWasStoppedLogged();
1867         } else {
1868             return (info.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0;
1869         }
1870     }
1871 
wasFirstLaunch(TransitionInfoSnapshot info)1872     private boolean wasFirstLaunch(TransitionInfoSnapshot info) {
1873         if (info.processRecord != null) {
1874             return info.processRecord.wasFirstLaunch()
1875                     && !info.processRecord.getWasStoppedLogged();
1876         }
1877         try {
1878             return !mSupervisor.mService.getPackageManagerInternalLocked()
1879                     .wasPackageEverLaunched(info.packageName, info.userId);
1880         } catch (Exception e) {
1881             // Couldn't find the state record, so must be a newly installed app
1882             return true;
1883         }
1884     }
1885 }
1886