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