1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.content.Intent; 23 24 import java.lang.annotation.Retention; 25 import java.lang.annotation.RetentionPolicy; 26 27 /** 28 * Observe activity manager launch sequences. 29 * 30 * The activity manager can have at most 1 concurrent launch sequences. Calls to this interface 31 * are ordered by a happens-before relation for each defined state transition (see below). 32 * 33 * When a new launch sequence is made, that sequence is in the {@code INTENT_STARTED} state which 34 * is communicated by the {@link #onIntentStarted} callback. This is a transient state. 35 * 36 * The intent can fail to launch the activity, in which case the sequence's state transitions to 37 * {@code INTENT_FAILED} via {@link #onIntentFailed}. This is a terminal state. 38 * 39 * If an activity is successfully started, the launch sequence's state will transition into 40 * {@code STARTED} via {@link #onActivityLaunched}. This is a transient state. 41 * 42 * It must then transition to either {@code CANCELLED} with {@link #onActivityLaunchCancelled}, 43 * which is a terminal state or into {@code FINISHED} with {@link #onActivityLaunchFinished}. 44 * 45 * The {@code FINISHED} with {@link #onActivityLaunchFinished} then may transition to 46 * {@code FULLY_DRAWN} with {@link #onReportFullyDrawn}, which is a terminal state. 47 * Note this transition may not happen if the reportFullyDrawn event is not receivied, 48 * in which case {@code FINISHED} is terminal. 49 * 50 * Note that the {@code ActivityRecordProto} provided as a parameter to some state transitions isn't 51 * necessarily the same within a single launch sequence: it is only the top-most activity at the 52 * time (if any). Trampoline activities coalesce several activity starts into a single launch 53 * sequence. 54 * 55 * Upon reaching a terminal state, it is considered that there are no active launch sequences 56 * until a subsequent transition into {@code INTENT_STARTED} initiates a new launch sequence. 57 * 58 * <pre> 59 * ┌⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┐ ┌⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┐ ┌--------------------------┐ 60 * ╴╴▶ INTENT_STARTED ──▶ ACTIVITY_LAUNCHED ──▶ ACTIVITY_LAUNCH_FINISHED 61 * └⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┘ └⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯⋯┘ └--------------------------┘ 62 * : : : 63 * : : : 64 * ▼ ▼ ▼ 65 * ╔════════════════╗ ╔═══════════════════════════╗ ╔═══════════════════════════╗ 66 * ║ INTENT_FAILED ║ ║ ACTIVITY_LAUNCH_CANCELLED ║ ║ REPORT_FULLY_DRAWN ║ 67 * ╚════════════════╝ ╚═══════════════════════════╝ ╚═══════════════════════════╝ 68 * </pre> 69 */ 70 public interface ActivityMetricsLaunchObserver { 71 /** 72 * The 'temperature' at which a launch sequence had started. 73 * 74 * The lower the temperature the more work has to be done during start-up. 75 * A 'cold' temperature means that a new process has been started and likely 76 * nothing is cached. 77 * 78 * A hot temperature means the existing activity is brought to the foreground. 79 * It may need to regenerate some objects as a result of {@code onTrimMemory}. 80 * 81 * A warm temperature is in the middle; an existing process is used, but the activity 82 * has to be created from scratch with {@code #onCreate}. 83 * 84 * @see https://developer.android.com/topic/performance/vitals/launch-time 85 */ 86 @Retention(RetentionPolicy.SOURCE) 87 @IntDef({ 88 TEMPERATURE_COLD, 89 TEMPERATURE_WARM, 90 TEMPERATURE_HOT 91 }) 92 @interface Temperature {} 93 94 /** Cold launch sequence: a new process has started. */ 95 public static final int TEMPERATURE_COLD = 1; 96 /** Warm launch sequence: process reused, but activity has to be created. */ 97 public static final int TEMPERATURE_WARM = 2; 98 /** Hot launch sequence: process reused, activity brought-to-top. */ 99 public static final int TEMPERATURE_HOT = 3; 100 101 /** 102 * Typedef marker that a {@code byte[]} actually contains an 103 * <a href="proto/android/server/activitymanagerservice.proto">ActivityRecordProto</a> 104 * in the protobuf format. 105 */ 106 @Retention(RetentionPolicy.SOURCE) 107 @interface ActivityRecordProto {} 108 109 /** 110 * Notifies the observer that a new launch sequence has begun as a result of a new intent. 111 * 112 * Once a launch sequence begins, the resolved activity will either subsequently start with 113 * {@link #onActivityLaunched} or abort early (for example due to a resolution error or due to 114 * a security error) with {@link #onIntentFailed}. 115 * 116 * Multiple calls to this method cannot occur without first terminating the current 117 * launch sequence. 118 */ onIntentStarted(@onNull Intent intent, long timestampNanos)119 public void onIntentStarted(@NonNull Intent intent, long timestampNanos); 120 121 /** 122 * Notifies the observer that the current launch sequence has failed to launch an activity. 123 * 124 * This function call terminates the current launch sequence. The next method call, if any, 125 * must be {@link #onIntentStarted}. 126 * 127 * Examples of this happening: 128 * - Failure to resolve to an activity 129 * - Calling package did not have the security permissions to call the requested activity 130 * - Resolved activity was already running and only needed to be brought to the top 131 * 132 * Multiple calls to this method cannot occur without first terminating the current 133 * launch sequence. 134 */ onIntentFailed()135 public void onIntentFailed(); 136 137 /** 138 * Notifies the observer that the current launch sequence had begun starting an activity. 139 * 140 * This is an intermediate state: once an activity begins starting, the entire launch sequence 141 * will later terminate by either finishing or cancelling. 142 * 143 * The initial activity is the first activity to be started as part of a launch sequence: 144 * it is represented by {@param activity} However, it isn't 145 * necessarily the activity which will be considered as displayed when the activity 146 * finishes launching (e.g. {@code activity} in {@link #onActivityLaunchFinished}). 147 * 148 * Multiple calls to this method cannot occur without first terminating the current 149 * launch sequence. 150 */ onActivityLaunched(@onNull @ctivityRecordProto byte[] activity, @Temperature int temperature)151 public void onActivityLaunched(@NonNull @ActivityRecordProto byte[] activity, 152 @Temperature int temperature); 153 154 /** 155 * Notifies the observer that the current launch sequence has been aborted. 156 * 157 * This function call terminates the current launch sequence. The next method call, if any, 158 * must be {@link #onIntentStarted}. 159 * 160 * This can happen for many reasons, for example the user switches away to another app 161 * prior to the launch sequence completing, or the application being killed. 162 * 163 * Multiple calls to this method cannot occur without first terminating the current 164 * launch sequence. 165 * 166 * @param abortingActivity the last activity that had the top-most window during abort 167 * (this can be {@code null} in rare situations its unknown). 168 * 169 * @apiNote The aborting activity isn't necessarily the same as the starting activity; 170 * in the case of a trampoline, multiple activities could've been started 171 * and only the latest activity is reported here. 172 */ onActivityLaunchCancelled(@ullable @ctivityRecordProto byte[] abortingActivity)173 public void onActivityLaunchCancelled(@Nullable @ActivityRecordProto byte[] abortingActivity); 174 175 /** 176 * Notifies the observer that the current launch sequence has been successfully finished. 177 * 178 * This function call terminates the current launch sequence. The next method call, if any, 179 * must be {@link #onIntentStarted}. 180 * 181 * A launch sequence is considered to be successfully finished when a frame is fully 182 * drawn for the first time: the top-most activity at the time is what's reported here. 183 * 184 * @param finalActivity the top-most activity whose windows were first to fully draw 185 * @param timestampNanos the timestamp of ActivityLaunchFinished event in nanoseconds. 186 * To compute the TotalTime duration, deduct the timestamp {@link #onIntentStarted} 187 * from {@code timestampNanos}. 188 * 189 * Multiple calls to this method cannot occur without first terminating the current 190 * launch sequence. 191 * 192 * @apiNote The finishing activity isn't necessarily the same as the starting activity; 193 * in the case of a trampoline, multiple activities could've been started 194 * and only the latest activity that was top-most during first-frame drawn 195 * is reported here. 196 */ onActivityLaunchFinished(@onNull @ctivityRecordProto byte[] finalActivity, long timestampNanos)197 public void onActivityLaunchFinished(@NonNull @ActivityRecordProto byte[] finalActivity, 198 long timestampNanos); 199 200 /** 201 * Notifies the observer that the application self-reported itself as being fully drawn. 202 * 203 * @param activity the activity that triggers the ReportFullyDrawn event. 204 * @param timestampNanos the timestamp of ReportFullyDrawn event in nanoseconds. 205 * To compute the duration, deduct the deduct the timestamp {@link #onIntentStarted} 206 * from {@code timestampNanos}. 207 * 208 * @apiNote The behavior of ReportFullyDrawn mostly depends on the app. 209 * It is used as an accurate estimate of meanfully app startup time. 210 * This event may be missing for many apps. 211 */ onReportFullyDrawn(@onNull @ctivityRecordProto byte[] activity, long timestampNanos)212 public void onReportFullyDrawn(@NonNull @ActivityRecordProto byte[] activity, 213 long timestampNanos); 214 215 } 216