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