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