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