• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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 android.app;
18 
19 import android.annotation.FlaggedApi;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.SuppressLint;
24 import android.content.Intent;
25 import android.content.pm.ApplicationInfo;
26 import android.icu.text.SimpleDateFormat;
27 import android.os.Parcel;
28 import android.os.Parcelable;
29 import android.os.UserHandle;
30 import android.text.TextUtils;
31 import android.util.ArrayMap;
32 import android.util.Xml;
33 import android.util.proto.ProtoInputStream;
34 import android.util.proto.ProtoOutputStream;
35 import android.util.proto.WireTypeMismatchException;
36 
37 import com.android.internal.util.XmlUtils;
38 import com.android.modules.utils.TypedXmlPullParser;
39 import com.android.modules.utils.TypedXmlSerializer;
40 
41 import org.xmlpull.v1.XmlPullParserException;
42 
43 import java.io.ByteArrayInputStream;
44 import java.io.ByteArrayOutputStream;
45 import java.io.IOException;
46 import java.io.ObjectInputStream;
47 import java.io.ObjectOutputStream;
48 import java.io.PrintWriter;
49 import java.lang.annotation.Retention;
50 import java.lang.annotation.RetentionPolicy;
51 import java.util.Map;
52 import java.util.Objects;
53 
54 /**
55  * Describes information related to an application process's startup.
56  *
57  * <p>
58  * Many aspects concerning why and how an applications process was started are valuable for apps
59  * both for logging and for potential behavior changes. Reason for process start, start type,
60  * start times, throttling, and other useful diagnostic data can be obtained from
61  * {@link ApplicationStartInfo} records.
62  * </p>
63  *
64  * <p>
65 *  ApplicationStartInfo objects can be retrieved via:
66 *  - {@link ActivityManager#getHistoricalProcessStartReasons}, which can be called during or after
67  *      a application's startup. Using this method, an app can retrieve information about an
68  *      in-progress app start.
69 *  - {@link ActivityManager#addApplicationStartInfoCompletionListener}, which returns an
70  *      ApplicationStartInfo object via a callback when the startup is complete, or immediately
71  *      if requested after the startup is complete.
72  * </p>
73  */
74 @FlaggedApi(Flags.FLAG_APP_START_INFO)
75 public final class ApplicationStartInfo implements Parcelable {
76 
77     /**
78      * State indicating process startup has started. Some information is available in
79      * {@link ApplicationStartInfo} and more will be added.
80      */
81     public static final int STARTUP_STATE_STARTED = 0;
82 
83     /**
84      * State indicating process startup has failed. Startup information in
85      * {@link ApplicationStartInfo} is incomplete, but no more will be added.
86      */
87     public static final int STARTUP_STATE_ERROR = 1;
88 
89     /**
90      * State indicating process startup has made it to first frame draw. Startup
91      * information in {@link ApplicationStartInfo} is complete with potential exception
92      * of fully drawn timestamp which is not guaranteed to be set.
93      */
94     public static final int STARTUP_STATE_FIRST_FRAME_DRAWN = 2;
95 
96     /** Process started due to alarm. */
97     public static final int START_REASON_ALARM = 0;
98 
99     /** Process started to run backup. */
100     public static final int START_REASON_BACKUP = 1;
101 
102     /** Process started due to boot complete. */
103     public static final int START_REASON_BOOT_COMPLETE = 2;
104 
105     /**  Process started due to broadcast received. */
106     public static final int START_REASON_BROADCAST = 3;
107 
108     /** Process started due to access of ContentProvider */
109     public static final int START_REASON_CONTENT_PROVIDER = 4;
110 
111     /** * Process started to run scheduled job. */
112     public static final int START_REASON_JOB = 5;
113 
114     /** Process started due to click app icon or widget from launcher. */
115     public static final int START_REASON_LAUNCHER = 6;
116 
117     /** Process started from launcher recents. */
118     public static final int START_REASON_LAUNCHER_RECENTS = 7;
119 
120     /** Process started not for any of the listed reasons. */
121     public static final int START_REASON_OTHER = 8;
122 
123     /** Process started due to push message. */
124     public static final int START_REASON_PUSH = 9;
125 
126     /** Process service started. */
127     public static final int START_REASON_SERVICE = 10;
128 
129     /** Process started due to Activity started for any reason not explicitly listed. */
130     public static final int START_REASON_START_ACTIVITY = 11;
131 
132     /** Start type not yet set. */
133     public static final int START_TYPE_UNSET = 0;
134 
135     /** Process started from scratch. */
136     public static final int START_TYPE_COLD = 1;
137 
138     /** Process retained minimally SavedInstanceState. */
139     public static final int START_TYPE_WARM = 2;
140 
141     /** Process brought back to foreground. */
142     public static final int START_TYPE_HOT = 3;
143 
144     /**
145      * Default. The system always creates a new instance of the activity in the target task and
146      * routes the intent to it.
147      */
148     public static final int LAUNCH_MODE_STANDARD = 0;
149 
150     /**
151      * If an instance of the activity already exists at the top of the target task, the system
152      * routes the intent to that instance through a call to its onNewIntent() method, rather than
153      * creating a new instance of the activity.
154      */
155     public static final int LAUNCH_MODE_SINGLE_TOP = 1;
156 
157     /**
158      * The system creates the activity at the root of a new task or locates the activity on an
159      * existing task with the same affinity. If an instance of the activity already exists and is at
160      * the root of the task, the system routes the intent to existing instance through a call to its
161      * onNewIntent() method, rather than creating a new one.
162      */
163     public static final int LAUNCH_MODE_SINGLE_INSTANCE = 2;
164 
165     /**
166      * Same as "singleTask", except that the system doesn't launch any other activities into the
167      * task holding the instance. The activity is always the single and only member of its task.
168      */
169     public static final int LAUNCH_MODE_SINGLE_TASK = 3;
170 
171     /**
172      * The activity can only be running as the root activity of the task, the first activity that
173      * created the task, and therefore there will only be one instance of this activity in a task;
174      * but activity can be instantiated multiple times in different tasks.
175      */
176     public static final int LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK = 4;
177 
178     /** The end of the range, beginning with 0, reserved for system timestamps.*/
179     public static final int START_TIMESTAMP_RESERVED_RANGE_SYSTEM = 20;
180 
181     /** The beginning of the range reserved for developer supplied timestamps.*/
182     public static final int START_TIMESTAMP_RESERVED_RANGE_DEVELOPER_START =
183             START_TIMESTAMP_RESERVED_RANGE_SYSTEM + 1;
184 
185     /** The end of the range reserved for developer supplied timestamps.*/
186     public static final int START_TIMESTAMP_RESERVED_RANGE_DEVELOPER = 30;
187 
188     /** Clock monotonic timestamp of launch started. */
189     public static final int START_TIMESTAMP_LAUNCH = 0;
190 
191     /** Clock monotonic timestamp of process fork. */
192     public static final int START_TIMESTAMP_FORK = 1;
193 
194     /** Clock monotonic timestamp of Application onCreate called. */
195     public static final int START_TIMESTAMP_APPLICATION_ONCREATE = 2;
196 
197     /** Clock monotonic timestamp of bindApplication called. */
198     public static final int START_TIMESTAMP_BIND_APPLICATION = 3;
199 
200     /** Clock monotonic timestamp of first frame drawn. */
201     public static final int START_TIMESTAMP_FIRST_FRAME = 4;
202 
203     /** Clock monotonic timestamp of reportFullyDrawn called by application. */
204     public static final int START_TIMESTAMP_FULLY_DRAWN = 5;
205 
206     /** Clock monotonic timestamp of initial renderthread frame. */
207     public static final int START_TIMESTAMP_INITIAL_RENDERTHREAD_FRAME = 6;
208 
209     /** Clock monotonic timestamp of surfaceflinger composition complete. */
210     public static final int START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE = 7;
211 
212     /**
213      * @see #getStartupState
214      */
215     private @StartupState int mStartupState;
216 
217     /**
218      * @see #getPid
219      */
220     private int mPid;
221 
222     /**
223      * @see #getRealUid
224      */
225     private int mRealUid;
226 
227     /**
228      * @see #getPackageUid
229      */
230     private int mPackageUid;
231 
232     /**
233      * @see #getDefiningUid
234      */
235     private int mDefiningUid;
236 
237     /**
238      * @see #getPackageName
239      */
240     private String mPackageName;
241 
242     /**
243      * @see #getProcessName
244      */
245     private String mProcessName;
246 
247     /**
248      * @see #getReason
249      */
250     private @StartReason int mReason;
251 
252     /**
253      * @see #getStartupTimestamps
254      */
255     private ArrayMap<Integer, Long> mStartupTimestampsNs;
256 
257     /**
258      * @see #getStartType
259      */
260     private @StartType int mStartType;
261 
262     /**
263      * @see #getIntent
264      */
265     private Intent mStartIntent;
266 
267     /**
268      * @see #getLaunchMode
269      */
270     private @LaunchMode int mLaunchMode;
271 
272     /**
273      * @see #wasForceStopped()
274      */
275     private boolean mWasForceStopped;
276 
277     /**
278      * @hide *
279      */
280     @IntDef(
281             prefix = {"STARTUP_STATE_"},
282             value = {
283                 STARTUP_STATE_STARTED,
284                 STARTUP_STATE_ERROR,
285                 STARTUP_STATE_FIRST_FRAME_DRAWN,
286             })
287     @Retention(RetentionPolicy.SOURCE)
288     public @interface StartupState {}
289 
290     /**
291      * @hide *
292      */
293     @IntDef(
294             prefix = {"START_REASON_"},
295             value = {
296                 START_REASON_ALARM,
297                 START_REASON_BACKUP,
298                 START_REASON_BOOT_COMPLETE,
299                 START_REASON_BROADCAST,
300                 START_REASON_CONTENT_PROVIDER,
301                 START_REASON_JOB,
302                 START_REASON_LAUNCHER,
303                 START_REASON_LAUNCHER_RECENTS,
304                 START_REASON_OTHER,
305                 START_REASON_PUSH,
306                 START_REASON_SERVICE,
307                 START_REASON_START_ACTIVITY,
308             })
309     @Retention(RetentionPolicy.SOURCE)
310     public @interface StartReason {}
311 
312     /**
313      * @hide *
314      */
315     @IntDef(
316             prefix = {"START_TYPE_"},
317             value = {
318                 START_TYPE_UNSET,
319                 START_TYPE_COLD,
320                 START_TYPE_WARM,
321                 START_TYPE_HOT,
322             })
323     @Retention(RetentionPolicy.SOURCE)
324     public @interface StartType {}
325 
326     /**
327      * @hide *
328      */
329     @IntDef(
330             prefix = {"LAUNCH_MODE_"},
331             value = {
332                 LAUNCH_MODE_STANDARD,
333                 LAUNCH_MODE_SINGLE_TOP,
334                 LAUNCH_MODE_SINGLE_INSTANCE,
335                 LAUNCH_MODE_SINGLE_TASK,
336                 LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK,
337             })
338     @Retention(RetentionPolicy.SOURCE)
339     public @interface LaunchMode {}
340 
341     /**
342      * @see #getStartupState
343      * @hide
344      */
setStartupState(final @StartupState int startupState)345     public void setStartupState(final @StartupState int startupState) {
346         mStartupState = startupState;
347     }
348 
349     /**
350      * @see #getPid
351      * @hide
352      */
setPid(final int pid)353     public void setPid(final int pid) {
354         mPid = pid;
355     }
356 
357     /**
358      * @see #getRealUid
359      * @hide
360      */
setRealUid(final int uid)361     public void setRealUid(final int uid) {
362         mRealUid = uid;
363     }
364 
365     /**
366      * @see #getPackageUid
367      * @hide
368      */
setPackageUid(final int uid)369     public void setPackageUid(final int uid) {
370         mPackageUid = uid;
371     }
372 
373     /**
374      * @see #getDefiningUid
375      * @hide
376      */
setDefiningUid(final int uid)377     public void setDefiningUid(final int uid) {
378         mDefiningUid = uid;
379     }
380 
381     /**
382      * @see #getPackageName
383      * @hide
384      */
setPackageName(final String packageName)385     public void setPackageName(final String packageName) {
386         mPackageName = intern(packageName);
387     }
388 
389     /**
390      * @see #getProcessName
391      * @hide
392      */
setProcessName(final String processName)393     public void setProcessName(final String processName) {
394         mProcessName = intern(processName);
395     }
396 
397     /**
398      * @see #getReason
399      * @hide
400      */
setReason(@tartReason int reason)401     public void setReason(@StartReason int reason) {
402         mReason = reason;
403     }
404 
405     /**
406      * @see #getStartupTimestamps
407      * @hide
408      */
addStartupTimestamp(int key, long timestampNs)409     public void addStartupTimestamp(int key, long timestampNs) {
410         if (key < 0 || key > START_TIMESTAMP_RESERVED_RANGE_DEVELOPER) {
411             return;
412         }
413         if (mStartupTimestampsNs == null) {
414             mStartupTimestampsNs = new ArrayMap<Integer, Long>();
415         }
416         mStartupTimestampsNs.put(key, timestampNs);
417     }
418 
419     /**
420      * @see #getStartType
421      * @hide
422      */
setStartType(@tartType int startType)423     public void setStartType(@StartType int startType) {
424         mStartType = startType;
425     }
426 
427     /**
428      * @see #getStartIntent
429      *
430      * <p class="note"> Note: This method will clone the provided intent and ensure that the cloned
431      * intent doesn't contain any large objects like bitmaps in its extras by stripping it in the
432      * least aggressive acceptable way for the individual intent.</p>
433      *
434      * @hide
435      */
setIntent(Intent startIntent)436     public void setIntent(Intent startIntent) {
437         if (startIntent != null) {
438             if (startIntent.canStripForHistory()) {
439                 // If maybeStripForHistory will return a lightened version, do that.
440                 mStartIntent = startIntent.maybeStripForHistory();
441             } else if (startIntent.getExtras() != null) {
442                 // If maybeStripForHistory would not return a lightened version and extras is
443                 // non-null then extras contains un-parcelled data. Use cloneFilter to strip data
444                 // more aggressively.
445                 mStartIntent = startIntent.cloneFilter();
446             } else {
447                 // Finally, if maybeStripForHistory would not return a lightened version and extras
448                 // is null then do a regular clone so we don't leak the intent.
449                 mStartIntent = new Intent(startIntent);
450             }
451 
452             // If the newly cloned intent has an original intent, clear that as we don't need it and
453             // can't guarantee it doesn't need to be stripped as well.
454             if (mStartIntent.getOriginalIntent() != null) {
455                 mStartIntent.setOriginalIntent(null);
456             }
457         }
458     }
459 
460     /**
461      * @see #getLaunchMode
462      * @hide
463      */
setLaunchMode(@aunchMode int launchMode)464     public void setLaunchMode(@LaunchMode int launchMode) {
465         mLaunchMode = launchMode;
466     }
467 
468     /**
469      * @see #wasForceStopped()
470      * @param wasForceStopped whether the app had been force-stopped in the past
471      * @hide
472      */
setForceStopped(boolean wasForceStopped)473     public void setForceStopped(boolean wasForceStopped) {
474         mWasForceStopped = wasForceStopped;
475     }
476 
477     /**
478      * Current state of startup.
479      *
480      * Can be used to determine whether the object will have additional fields added as it may be
481      * queried before all data is collected.
482      *
483      * <p class="note"> Note: field will always be set and available.</p>
484      */
getStartupState()485     public @StartupState int getStartupState() {
486         return mStartupState;
487     }
488 
489     /**
490      * The process id.
491      *
492      * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
493      */
getPid()494     public int getPid() {
495         return mPid;
496     }
497 
498     /**
499      * The kernel user identifier of the process, most of the time the system uses this to do access
500      * control checks. It's typically the uid of the package where the component is running from,
501      * except the case of isolated process, where this field identifies the kernel user identifier
502      * that this process is actually running with, while the {@link #getPackageUid} identifies the
503      * kernel user identifier that is assigned at the package installation time.
504      *
505      * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
506      */
getRealUid()507     public int getRealUid() {
508         return mRealUid;
509     }
510 
511     /**
512      * Similar to {@link #getRealUid}, it's the kernel user identifier that is assigned at the
513      * package installation time.
514      *
515      * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
516      */
getPackageUid()517     public int getPackageUid() {
518         return mPackageUid;
519     }
520 
521     /**
522      * Return the defining kernel user identifier, maybe different from {@link #getRealUid} and
523      * {@link #getPackageUid}, if an external service has the {@link
524      * android.R.styleable#AndroidManifestService_useAppZygote android:useAppZygote} set to <code>
525      * true</code> and was bound with the flag {@link android.content.Context#BIND_EXTERNAL_SERVICE}
526      * - in this case, this field here will be the kernel user identifier of the external service
527      * provider.
528      *
529      * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
530      */
getDefiningUid()531     public int getDefiningUid() {
532         return mDefiningUid;
533     }
534 
535     /**
536      * Name of first package running in this process;
537      *
538      * @hide
539      */
getPackageName()540     public String getPackageName() {
541         return mPackageName;
542     }
543 
544     /**
545      * The actual process name it was running with.
546      *
547      * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
548      */
getProcessName()549     public @NonNull String getProcessName() {
550         return mProcessName;
551     }
552 
553     /**
554      * The reason code of what triggered the process's start.
555      *
556      * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
557      */
getReason()558     public @StartReason int getReason() {
559         return mReason;
560     }
561 
562     /**
563      * Various clock monotonic timestamps in nanoseconds throughout the startup process.
564      *
565      * <p class="note"> Note: different timestamps will be available for different values of
566      * {@link #getStartupState}:
567      *
568      * (Subsequent rows contain all timestamps of proceding states.)
569      *
570      * For {@link #STARTUP_STATE_STARTED}, timestamp {@link #START_TIMESTAMP_LAUNCH} will be
571      * available.
572      * For {@link #STARTUP_STATE_ERROR}, no additional timestamps are guaranteed available.
573      * For {@link #STARTUP_STATE_FIRST_FRAME_DRAWN}, timestamps
574      * {@link #START_TIMESTAMP_APPLICATION_ONCREATE}, {@link #START_TIMESTAMP_BIND_APPLICATION},
575      * and {@link #START_TIMESTAMP_FIRST_FRAME} will additionally be available.
576      *
577      * Timestamp {@link #START_TIMESTAMP_FULLY_DRAWN} is never guaranteed to be available as it is
578      * dependant on devloper calling {@link Activity#reportFullyDrawn}.
579      * </p>
580      */
getStartupTimestamps()581     public @NonNull Map<Integer, Long> getStartupTimestamps() {
582         if (mStartupTimestampsNs == null) {
583             mStartupTimestampsNs = new ArrayMap<Integer, Long>();
584         }
585         return mStartupTimestampsNs;
586     }
587 
588     /**
589      * The state of the app at startup.
590      *
591      * <p class="note"> Note: field will be set for {@link #getStartupState} value
592      * {@link #STARTUP_STATE_FIRST_FRAME_DRAWN}. Not guaranteed for other states.</p>
593      */
getStartType()594     public @StartType int getStartType() {
595         return mStartType;
596     }
597 
598     /**
599      * The intent used to launch the application.
600      *
601      * <p class="note"> Note: Intent is stripped and does not include extras.</p>
602      *
603      * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
604      */
605     @SuppressLint("IntentBuilderName")
606     @Nullable
getIntent()607     public Intent getIntent() {
608         return mStartIntent;
609     }
610 
611     /**
612      * An instruction on how the activity should be launched. There are five modes that work in
613      * conjunction with activity flags in Intent objects to determine what should happen when the
614      * activity is called upon to handle an intent.
615      *
616      * Modes:
617      * {@link #LAUNCH_MODE_STANDARD}
618      * {@link #LAUNCH_MODE_SINGLE_TOP}
619      * {@link #LAUNCH_MODE_SINGLE_INSTANCE}
620      * {@link #LAUNCH_MODE_SINGLE_TASK}
621      * {@link #LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK}
622      *
623      * <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
624      */
getLaunchMode()625     public @LaunchMode int getLaunchMode() {
626         return mLaunchMode;
627     }
628 
629     /**
630      * Informs whether this is the first process launch for an app since it was
631      * {@link ApplicationInfo#FLAG_STOPPED force-stopped} for some reason.
632      * This allows the app to know if it should re-register for any alarms, jobs and other callbacks
633      * that were cleared when the app was force-stopped.
634      *
635      * @return {@code true} if this is the first process launch of the app after having been
636      *      stopped, {@code false} otherwise.
637      */
638     @FlaggedApi(android.content.pm.Flags.FLAG_STAY_STOPPED)
wasForceStopped()639     public boolean wasForceStopped() {
640         return mWasForceStopped;
641     }
642 
643     @Override
describeContents()644     public int describeContents() {
645         return 0;
646     }
647 
648     @Override
writeToParcel(@onNull Parcel dest, int flags)649     public void writeToParcel(@NonNull Parcel dest, int flags) {
650         dest.writeInt(mStartupState);
651         dest.writeInt(mPid);
652         dest.writeInt(mRealUid);
653         dest.writeInt(mPackageUid);
654         dest.writeInt(mDefiningUid);
655         dest.writeString(mPackageName);
656         dest.writeString(mProcessName);
657         dest.writeInt(mReason);
658         dest.writeInt(mStartupTimestampsNs == null ? 0 : mStartupTimestampsNs.size());
659         if (mStartupTimestampsNs != null) {
660             for (int i = 0; i < mStartupTimestampsNs.size(); i++) {
661                 dest.writeInt(mStartupTimestampsNs.keyAt(i));
662                 dest.writeLong(mStartupTimestampsNs.valueAt(i));
663             }
664         }
665         dest.writeInt(mStartType);
666         dest.writeParcelable(mStartIntent, flags);
667         dest.writeInt(mLaunchMode);
668         dest.writeBoolean(mWasForceStopped);
669     }
670 
671     /** @hide */
ApplicationStartInfo()672     public ApplicationStartInfo() {}
673 
674     /** @hide */
ApplicationStartInfo(ApplicationStartInfo other)675     public ApplicationStartInfo(ApplicationStartInfo other) {
676         mStartupState = other.mStartupState;
677         mPid = other.mPid;
678         mRealUid = other.mRealUid;
679         mPackageUid = other.mPackageUid;
680         mDefiningUid = other.mDefiningUid;
681         mPackageName = other.mPackageName;
682         mProcessName = other.mProcessName;
683         mReason = other.mReason;
684         mStartupTimestampsNs = other.mStartupTimestampsNs;
685         mStartType = other.mStartType;
686         mStartIntent = other.mStartIntent;
687         mLaunchMode = other.mLaunchMode;
688         mWasForceStopped = other.mWasForceStopped;
689     }
690 
ApplicationStartInfo(@onNull Parcel in)691     private ApplicationStartInfo(@NonNull Parcel in) {
692         mStartupState = in.readInt();
693         mPid = in.readInt();
694         mRealUid = in.readInt();
695         mPackageUid = in.readInt();
696         mDefiningUid = in.readInt();
697         mPackageName = intern(in.readString());
698         mProcessName = intern(in.readString());
699         mReason = in.readInt();
700         int starupTimestampCount = in.readInt();
701         for (int i = 0; i < starupTimestampCount; i++) {
702             int key = in.readInt();
703             long val = in.readLong();
704             addStartupTimestamp(key, val);
705         }
706         mStartType = in.readInt();
707         mStartIntent =
708                 in.readParcelable(Intent.class.getClassLoader(), android.content.Intent.class);
709         mLaunchMode = in.readInt();
710         mWasForceStopped = in.readBoolean();
711     }
712 
intern(@ullable String source)713     private static String intern(@Nullable String source) {
714         return source != null ? source.intern() : null;
715     }
716 
717     public @NonNull static final Creator<ApplicationStartInfo> CREATOR =
718             new Creator<ApplicationStartInfo>() {
719                 @Override
720                 public ApplicationStartInfo createFromParcel(Parcel in) {
721                     return new ApplicationStartInfo(in);
722                 }
723 
724                 @Override
725                 public ApplicationStartInfo[] newArray(int size) {
726                     return new ApplicationStartInfo[size];
727                 }
728             };
729 
730     private static final String PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS = "timestamps";
731     private static final String PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP = "timestamp";
732     private static final String PROTO_SERIALIZER_ATTRIBUTE_KEY = "key";
733     private static final String PROTO_SERIALIZER_ATTRIBUTE_TS = "ts";
734     private static final String PROTO_SERIALIZER_ATTRIBUTE_INTENT = "intent";
735 
736     /**
737      * Write to a protocol buffer output stream. Protocol buffer message definition at {@link
738      * android.app.ApplicationStartInfoProto}
739      *
740      * @param proto Stream to write the ApplicationStartInfo object to.
741      * @param fieldId Field Id of the ApplicationStartInfo as defined in the parent message
742      * @hide
743      */
writeToProto(ProtoOutputStream proto, long fieldId)744     public void writeToProto(ProtoOutputStream proto, long fieldId) throws IOException {
745         final long token = proto.start(fieldId);
746         proto.write(ApplicationStartInfoProto.PID, mPid);
747         proto.write(ApplicationStartInfoProto.REAL_UID, mRealUid);
748         proto.write(ApplicationStartInfoProto.PACKAGE_UID, mPackageUid);
749         proto.write(ApplicationStartInfoProto.DEFINING_UID, mDefiningUid);
750         proto.write(ApplicationStartInfoProto.PROCESS_NAME, mProcessName);
751         proto.write(ApplicationStartInfoProto.STARTUP_STATE, mStartupState);
752         proto.write(ApplicationStartInfoProto.REASON, mReason);
753         if (mStartupTimestampsNs != null && mStartupTimestampsNs.size() > 0) {
754             ByteArrayOutputStream timestampsBytes = new ByteArrayOutputStream();
755             ObjectOutputStream timestampsOut = new ObjectOutputStream(timestampsBytes);
756             TypedXmlSerializer serializer = Xml.resolveSerializer(timestampsOut);
757             serializer.startDocument(null, true);
758             serializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS);
759             for (int i = 0; i < mStartupTimestampsNs.size(); i++) {
760                 serializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP);
761                 serializer.attributeInt(null, PROTO_SERIALIZER_ATTRIBUTE_KEY,
762                         mStartupTimestampsNs.keyAt(i));
763                 serializer.attributeLong(null, PROTO_SERIALIZER_ATTRIBUTE_TS,
764                         mStartupTimestampsNs.valueAt(i));
765                 serializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP);
766             }
767             serializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS);
768             serializer.endDocument();
769             proto.write(ApplicationStartInfoProto.STARTUP_TIMESTAMPS,
770                     timestampsBytes.toByteArray());
771             timestampsOut.close();
772         }
773         proto.write(ApplicationStartInfoProto.START_TYPE, mStartType);
774         if (mStartIntent != null) {
775             ByteArrayOutputStream intentBytes = new ByteArrayOutputStream();
776             ObjectOutputStream intentOut = new ObjectOutputStream(intentBytes);
777             TypedXmlSerializer serializer = Xml.resolveSerializer(intentOut);
778             serializer.startDocument(null, true);
779             serializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_INTENT);
780             mStartIntent.saveToXml(serializer);
781             serializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_INTENT);
782             serializer.endDocument();
783             proto.write(ApplicationStartInfoProto.START_INTENT,
784                     intentBytes.toByteArray());
785             intentOut.close();
786         }
787         proto.write(ApplicationStartInfoProto.LAUNCH_MODE, mLaunchMode);
788         proto.write(ApplicationStartInfoProto.WAS_FORCE_STOPPED, mWasForceStopped);
789         proto.end(token);
790     }
791 
792     /**
793      * Read from a protocol buffer input stream. Protocol buffer message definition at {@link
794      * android.app.ApplicationStartInfoProto}
795      *
796      * @param proto Stream to read the ApplicationStartInfo object from.
797      * @param fieldId Field Id of the ApplicationStartInfo as defined in the parent message
798      * @hide
799      */
readFromProto(ProtoInputStream proto, long fieldId)800     public void readFromProto(ProtoInputStream proto, long fieldId)
801             throws IOException, WireTypeMismatchException, ClassNotFoundException {
802         final long token = proto.start(fieldId);
803         while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
804             switch (proto.getFieldNumber()) {
805                 case (int) ApplicationStartInfoProto.PID:
806                     mPid = proto.readInt(ApplicationStartInfoProto.PID);
807                     break;
808                 case (int) ApplicationStartInfoProto.REAL_UID:
809                     mRealUid = proto.readInt(ApplicationStartInfoProto.REAL_UID);
810                     break;
811                 case (int) ApplicationStartInfoProto.PACKAGE_UID:
812                     mPackageUid = proto.readInt(ApplicationStartInfoProto.PACKAGE_UID);
813                     break;
814                 case (int) ApplicationStartInfoProto.DEFINING_UID:
815                     mDefiningUid = proto.readInt(ApplicationStartInfoProto.DEFINING_UID);
816                     break;
817                 case (int) ApplicationStartInfoProto.PROCESS_NAME:
818                     mProcessName = intern(proto.readString(ApplicationStartInfoProto.PROCESS_NAME));
819                     break;
820                 case (int) ApplicationStartInfoProto.STARTUP_STATE:
821                     mStartupState = proto.readInt(ApplicationStartInfoProto.STARTUP_STATE);
822                     break;
823                 case (int) ApplicationStartInfoProto.REASON:
824                     mReason = proto.readInt(ApplicationStartInfoProto.REASON);
825                     break;
826                 case (int) ApplicationStartInfoProto.STARTUP_TIMESTAMPS:
827                     ByteArrayInputStream timestampsBytes = new ByteArrayInputStream(proto.readBytes(
828                             ApplicationStartInfoProto.STARTUP_TIMESTAMPS));
829                     ObjectInputStream timestampsIn = new ObjectInputStream(timestampsBytes);
830                     mStartupTimestampsNs = new ArrayMap<Integer, Long>();
831                     try {
832                         TypedXmlPullParser parser = Xml.resolvePullParser(timestampsIn);
833                         XmlUtils.beginDocument(parser, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS);
834                         int depth = parser.getDepth();
835                         while (XmlUtils.nextElementWithin(parser, depth)) {
836                             if (PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP.equals(parser.getName())) {
837                                 int key = parser.getAttributeInt(null,
838                                         PROTO_SERIALIZER_ATTRIBUTE_KEY);
839                                 long ts = parser.getAttributeLong(null,
840                                         PROTO_SERIALIZER_ATTRIBUTE_TS);
841                                 mStartupTimestampsNs.put(key, ts);
842                             }
843                         }
844                     } catch (XmlPullParserException e) {
845                         // Timestamps lost
846                     }
847                     timestampsIn.close();
848                     break;
849                 case (int) ApplicationStartInfoProto.START_TYPE:
850                     mStartType = proto.readInt(ApplicationStartInfoProto.START_TYPE);
851                     break;
852                 case (int) ApplicationStartInfoProto.START_INTENT:
853                     ByteArrayInputStream intentBytes = new ByteArrayInputStream(proto.readBytes(
854                             ApplicationStartInfoProto.START_INTENT));
855                     ObjectInputStream intentIn = new ObjectInputStream(intentBytes);
856                     try {
857                         TypedXmlPullParser parser = Xml.resolvePullParser(intentIn);
858                         XmlUtils.beginDocument(parser, PROTO_SERIALIZER_ATTRIBUTE_INTENT);
859                         mStartIntent = Intent.restoreFromXml(parser);
860                     } catch (XmlPullParserException e) {
861                         // Intent lost
862                     }
863                     intentIn.close();
864                     break;
865                 case (int) ApplicationStartInfoProto.LAUNCH_MODE:
866                     mLaunchMode = proto.readInt(ApplicationStartInfoProto.LAUNCH_MODE);
867                     break;
868                 case (int) ApplicationStartInfoProto.WAS_FORCE_STOPPED:
869                     mWasForceStopped = proto.readBoolean(
870                             ApplicationStartInfoProto.WAS_FORCE_STOPPED);
871                     break;
872             }
873         }
874         proto.end(token);
875     }
876 
877     /** @hide */
dump(@onNull PrintWriter pw, @Nullable String prefix, @Nullable String seqSuffix, @NonNull SimpleDateFormat sdf)878     public void dump(@NonNull PrintWriter pw, @Nullable String prefix, @Nullable String seqSuffix,
879             @NonNull SimpleDateFormat sdf) {
880         StringBuilder sb = new StringBuilder();
881         sb.append(prefix)
882                 .append("ApplicationStartInfo ").append(seqSuffix).append(':')
883                 .append('\n')
884                 .append(" pid=").append(mPid)
885                 .append(" realUid=").append(mRealUid)
886                 .append(" packageUid=").append(mPackageUid)
887                 .append(" definingUid=").append(mDefiningUid)
888                 .append(" user=").append(UserHandle.getUserId(mPackageUid))
889                 .append('\n')
890                 .append(" package=").append(mPackageName)
891                 .append(" process=").append(mProcessName)
892                 .append(" startupState=").append(mStartupState)
893                 .append(" reason=").append(reasonToString(mReason))
894                 .append(" startType=").append(startTypeToString(mStartType))
895                 .append(" launchMode=").append(mLaunchMode)
896                 .append(" wasForceStopped=").append(mWasForceStopped)
897                 .append('\n');
898         if (mStartIntent != null) {
899             sb.append(" intent=").append(mStartIntent.toString())
900                 .append('\n');
901         }
902         if (mStartupTimestampsNs != null && mStartupTimestampsNs.size() > 0) {
903             sb.append(" timestamps: ");
904             for (int i = 0; i < mStartupTimestampsNs.size(); i++) {
905                 sb.append(mStartupTimestampsNs.keyAt(i)).append("=").append(mStartupTimestampsNs
906                         .valueAt(i)).append(" ");
907             }
908             sb.append('\n');
909         }
910         pw.print(sb.toString());
911     }
912 
reasonToString(@tartReason int reason)913     private static String reasonToString(@StartReason int reason) {
914         return switch (reason) {
915             case START_REASON_ALARM -> "ALARM";
916             case START_REASON_BACKUP -> "BACKUP";
917             case START_REASON_BOOT_COMPLETE -> "BOOT COMPLETE";
918             case START_REASON_BROADCAST -> "BROADCAST";
919             case START_REASON_CONTENT_PROVIDER -> "CONTENT PROVIDER";
920             case START_REASON_JOB -> "JOB";
921             case START_REASON_LAUNCHER -> "LAUNCHER";
922             case START_REASON_LAUNCHER_RECENTS -> "LAUNCHER RECENTS";
923             case START_REASON_OTHER -> "OTHER";
924             case START_REASON_PUSH -> "PUSH";
925             case START_REASON_SERVICE -> "SERVICE";
926             case START_REASON_START_ACTIVITY -> "START ACTIVITY";
927             default -> "";
928         };
929     }
930 
startTypeToString(@tartType int startType)931     private static String startTypeToString(@StartType int startType) {
932         return switch (startType) {
933             case START_TYPE_UNSET -> "UNSET";
934             case START_TYPE_COLD -> "COLD";
935             case START_TYPE_WARM -> "WARM";
936             case START_TYPE_HOT -> "HOT";
937             default -> "";
938         };
939     }
940 
941     /** @hide */
942     @Override
943     public boolean equals(@Nullable Object other) {
944         if (other == null || !(other instanceof ApplicationStartInfo)) {
945             return false;
946         }
947         final ApplicationStartInfo o = (ApplicationStartInfo) other;
948         return mPid == o.mPid && mRealUid == o.mRealUid && mPackageUid == o.mPackageUid
949             && mDefiningUid == o.mDefiningUid && mReason == o.mReason
950             && mStartupState == o.mStartupState && mStartType == o.mStartType
951             && mLaunchMode == o.mLaunchMode && TextUtils.equals(mProcessName, o.mProcessName)
952             && timestampsEquals(o) && mWasForceStopped == o.mWasForceStopped;
953     }
954 
955     @Override
956     public int hashCode() {
957         return Objects.hash(mPid, mRealUid, mPackageUid, mDefiningUid, mReason, mStartupState,
958                 mStartType, mLaunchMode, mProcessName,
959                 mStartupTimestampsNs);
960     }
961 
962     private boolean timestampsEquals(@NonNull ApplicationStartInfo other) {
963         if (mStartupTimestampsNs == null && other.mStartupTimestampsNs == null) {
964             return true;
965         }
966         if (mStartupTimestampsNs == null || other.mStartupTimestampsNs == null) {
967             return false;
968         }
969         return mStartupTimestampsNs.equals(other.mStartupTimestampsNs);
970     }
971 }
972