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