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