script-astra/Android/Sdk/sources/android-35/android/app/ApplicationStartInfo.java

939 lines
34 KiB
Java
Raw Permalink Normal View History

2025-01-20 15:15:20 +00:00
/*
* Copyright (C) 2019 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 android.app;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.icu.text.SimpleDateFormat;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Xml;
import android.util.proto.ProtoInputStream;
import android.util.proto.ProtoOutputStream;
import android.util.proto.WireTypeMismatchException;
import com.android.internal.util.XmlUtils;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Map;
import java.util.Objects;
/**
* Describes information related to an application process's startup.
*
* <p>
* Many aspects concerning why and how an applications process was started are valuable for apps
* both for logging and for potential behavior changes. Reason for process start, start type,
* start times, throttling, and other useful diagnostic data can be obtained from
* {@link ApplicationStartInfo} records.
* </p>
*/
@FlaggedApi(Flags.FLAG_APP_START_INFO)
public final class ApplicationStartInfo implements Parcelable {
/**
* State indicating process startup has started. Some information is available in
* {@link ApplicationStartInfo} and more will be added.
*/
public static final int STARTUP_STATE_STARTED = 0;
/**
* State indicating process startup has failed. Startup information in
* {@link ApplicationStartInfo} is incomplete, but no more will be added.
*/
public static final int STARTUP_STATE_ERROR = 1;
/**
* State indicating process startup has made it to first frame draw. Startup
* information in {@link ApplicationStartInfo} is complete with potential exception
* of fully drawn timestamp which is not guaranteed to be set.
*/
public static final int STARTUP_STATE_FIRST_FRAME_DRAWN = 2;
/** Process started due to alarm. */
public static final int START_REASON_ALARM = 0;
/** Process started to run backup. */
public static final int START_REASON_BACKUP = 1;
/** Process started due to boot complete. */
public static final int START_REASON_BOOT_COMPLETE = 2;
/** Process started due to broadcast received. */
public static final int START_REASON_BROADCAST = 3;
/** Process started due to access of ContentProvider */
public static final int START_REASON_CONTENT_PROVIDER = 4;
/** * Process started to run scheduled job. */
public static final int START_REASON_JOB = 5;
/** Process started due to click app icon or widget from launcher. */
public static final int START_REASON_LAUNCHER = 6;
/** Process started from launcher recents. */
public static final int START_REASON_LAUNCHER_RECENTS = 7;
/** Process started not for any of the listed reasons. */
public static final int START_REASON_OTHER = 8;
/** Process started due to push message. */
public static final int START_REASON_PUSH = 9;
/** Process service started. */
public static final int START_REASON_SERVICE = 10;
/** Process started due to Activity started for any reason not explicitly listed. */
public static final int START_REASON_START_ACTIVITY = 11;
/** Start type not yet set. */
public static final int START_TYPE_UNSET = 0;
/** Process started from scratch. */
public static final int START_TYPE_COLD = 1;
/** Process retained minimally SavedInstanceState. */
public static final int START_TYPE_WARM = 2;
/** Process brought back to foreground. */
public static final int START_TYPE_HOT = 3;
/**
* Default. The system always creates a new instance of the activity in the target task and
* routes the intent to it.
*/
public static final int LAUNCH_MODE_STANDARD = 0;
/**
* If an instance of the activity already exists at the top of the target task, the system
* routes the intent to that instance through a call to its onNewIntent() method, rather than
* creating a new instance of the activity.
*/
public static final int LAUNCH_MODE_SINGLE_TOP = 1;
/**
* The system creates the activity at the root of a new task or locates the activity on an
* existing task with the same affinity. If an instance of the activity already exists and is at
* the root of the task, the system routes the intent to existing instance through a call to its
* onNewIntent() method, rather than creating a new one.
*/
public static final int LAUNCH_MODE_SINGLE_INSTANCE = 2;
/**
* Same as "singleTask", except that the system doesn't launch any other activities into the
* task holding the instance. The activity is always the single and only member of its task.
*/
public static final int LAUNCH_MODE_SINGLE_TASK = 3;
/**
* The activity can only be running as the root activity of the task, the first activity that
* created the task, and therefore there will only be one instance of this activity in a task;
* but activity can be instantiated multiple times in different tasks.
*/
public static final int LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK = 4;
/** The end of the range, beginning with 0, reserved for system timestamps.*/
public static final int START_TIMESTAMP_RESERVED_RANGE_SYSTEM = 20;
/** The beginning of the range reserved for developer supplied timestamps.*/
public static final int START_TIMESTAMP_RESERVED_RANGE_DEVELOPER_START =
START_TIMESTAMP_RESERVED_RANGE_SYSTEM + 1;
/** The end of the range reserved for developer supplied timestamps.*/
public static final int START_TIMESTAMP_RESERVED_RANGE_DEVELOPER = 30;
/** Clock monotonic timestamp of launch started. */
public static final int START_TIMESTAMP_LAUNCH = 0;
/** Clock monotonic timestamp of process fork. */
public static final int START_TIMESTAMP_FORK = 1;
/** Clock monotonic timestamp of Application onCreate called. */
public static final int START_TIMESTAMP_APPLICATION_ONCREATE = 2;
/** Clock monotonic timestamp of bindApplication called. */
public static final int START_TIMESTAMP_BIND_APPLICATION = 3;
/** Clock monotonic timestamp of first frame drawn. */
public static final int START_TIMESTAMP_FIRST_FRAME = 4;
/** Clock monotonic timestamp of reportFullyDrawn called by application. */
public static final int START_TIMESTAMP_FULLY_DRAWN = 5;
/** Clock monotonic timestamp of initial renderthread frame. */
public static final int START_TIMESTAMP_INITIAL_RENDERTHREAD_FRAME = 6;
/** Clock monotonic timestamp of surfaceflinger composition complete. */
public static final int START_TIMESTAMP_SURFACEFLINGER_COMPOSITION_COMPLETE = 7;
/**
* @see #getStartupState
*/
private @StartupState int mStartupState;
/**
* @see #getPid
*/
private int mPid;
/**
* @see #getRealUid
*/
private int mRealUid;
/**
* @see #getPackageUid
*/
private int mPackageUid;
/**
* @see #getDefiningUid
*/
private int mDefiningUid;
/**
* @see #getPackageName
*/
private String mPackageName;
/**
* @see #getProcessName
*/
private String mProcessName;
/**
* @see #getReason
*/
private @StartReason int mReason;
/**
* @see #getStartupTimestamps
*/
private ArrayMap<Integer, Long> mStartupTimestampsNs;
/**
* @see #getStartType
*/
private @StartType int mStartType;
/**
* @see #getIntent
*/
private Intent mStartIntent;
/**
* @see #getLaunchMode
*/
private @LaunchMode int mLaunchMode;
/**
* @see #wasForceStopped()
*/
private boolean mWasForceStopped;
/**
* @hide *
*/
@IntDef(
prefix = {"STARTUP_STATE_"},
value = {
STARTUP_STATE_STARTED,
STARTUP_STATE_ERROR,
STARTUP_STATE_FIRST_FRAME_DRAWN,
})
@Retention(RetentionPolicy.SOURCE)
public @interface StartupState {}
/**
* @hide *
*/
@IntDef(
prefix = {"START_REASON_"},
value = {
START_REASON_ALARM,
START_REASON_BACKUP,
START_REASON_BOOT_COMPLETE,
START_REASON_BROADCAST,
START_REASON_CONTENT_PROVIDER,
START_REASON_JOB,
START_REASON_LAUNCHER,
START_REASON_LAUNCHER_RECENTS,
START_REASON_OTHER,
START_REASON_PUSH,
START_REASON_SERVICE,
START_REASON_START_ACTIVITY,
})
@Retention(RetentionPolicy.SOURCE)
public @interface StartReason {}
/**
* @hide *
*/
@IntDef(
prefix = {"START_TYPE_"},
value = {
START_TYPE_UNSET,
START_TYPE_COLD,
START_TYPE_WARM,
START_TYPE_HOT,
})
@Retention(RetentionPolicy.SOURCE)
public @interface StartType {}
/**
* @hide *
*/
@IntDef(
prefix = {"LAUNCH_MODE_"},
value = {
LAUNCH_MODE_STANDARD,
LAUNCH_MODE_SINGLE_TOP,
LAUNCH_MODE_SINGLE_INSTANCE,
LAUNCH_MODE_SINGLE_TASK,
LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK,
})
@Retention(RetentionPolicy.SOURCE)
public @interface LaunchMode {}
/**
* @see #getStartupState
* @hide
*/
public void setStartupState(final @StartupState int startupState) {
mStartupState = startupState;
}
/**
* @see #getPid
* @hide
*/
public void setPid(final int pid) {
mPid = pid;
}
/**
* @see #getRealUid
* @hide
*/
public void setRealUid(final int uid) {
mRealUid = uid;
}
/**
* @see #getPackageUid
* @hide
*/
public void setPackageUid(final int uid) {
mPackageUid = uid;
}
/**
* @see #getDefiningUid
* @hide
*/
public void setDefiningUid(final int uid) {
mDefiningUid = uid;
}
/**
* @see #getPackageName
* @hide
*/
public void setPackageName(final String packageName) {
mPackageName = intern(packageName);
}
/**
* @see #getProcessName
* @hide
*/
public void setProcessName(final String processName) {
mProcessName = intern(processName);
}
/**
* @see #getReason
* @hide
*/
public void setReason(@StartReason int reason) {
mReason = reason;
}
/**
* @see #getStartupTimestamps
* @hide
*/
public void addStartupTimestamp(int key, long timestampNs) {
if (key < 0 || key > START_TIMESTAMP_RESERVED_RANGE_DEVELOPER) {
return;
}
if (mStartupTimestampsNs == null) {
mStartupTimestampsNs = new ArrayMap<Integer, Long>();
}
mStartupTimestampsNs.put(key, timestampNs);
}
/**
* @see #getStartType
* @hide
*/
public void setStartType(@StartType int startType) {
mStartType = startType;
}
/**
* @see #getStartIntent
* @hide
*/
public void setIntent(Intent startIntent) {
if (startIntent != null) {
mStartIntent = startIntent.maybeStripForHistory();
}
}
/**
* @see #getLaunchMode
* @hide
*/
public void setLaunchMode(@LaunchMode int launchMode) {
mLaunchMode = launchMode;
}
/**
* @see #wasForceStopped()
* @param wasForceStopped whether the app had been force-stopped in the past
* @hide
*/
public void setForceStopped(boolean wasForceStopped) {
mWasForceStopped = wasForceStopped;
}
/**
* Current state of startup.
*
* Can be used to determine whether the object will have additional fields added as it may be
* queried before all data is collected.
*
* <p class="note"> Note: field will always be set and available.</p>
*/
public @StartupState int getStartupState() {
return mStartupState;
}
/**
* The process id.
*
* <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
*/
public int getPid() {
return mPid;
}
/**
* The kernel user identifier of the process, most of the time the system uses this to do access
* control checks. It's typically the uid of the package where the component is running from,
* except the case of isolated process, where this field identifies the kernel user identifier
* that this process is actually running with, while the {@link #getPackageUid} identifies the
* kernel user identifier that is assigned at the package installation time.
*
* <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
*/
public int getRealUid() {
return mRealUid;
}
/**
* Similar to {@link #getRealUid}, it's the kernel user identifier that is assigned at the
* package installation time.
*
* <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
*/
public int getPackageUid() {
return mPackageUid;
}
/**
* Return the defining kernel user identifier, maybe different from {@link #getRealUid} and
* {@link #getPackageUid}, if an external service has the {@link
* android.R.styleable#AndroidManifestService_useAppZygote android:useAppZygote} set to <code>
* true</code> and was bound with the flag {@link android.content.Context#BIND_EXTERNAL_SERVICE}
* - in this case, this field here will be the kernel user identifier of the external service
* provider.
*
* <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
*/
public int getDefiningUid() {
return mDefiningUid;
}
/**
* Name of first package running in this process;
*
* @hide
*/
public String getPackageName() {
return mPackageName;
}
/**
* The actual process name it was running with.
*
* <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
*/
public @NonNull String getProcessName() {
return mProcessName;
}
/**
* The reason code of what triggered the process's start.
*
* <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
*/
public @StartReason int getReason() {
return mReason;
}
/**
* Various clock monotonic timestamps in nanoseconds throughout the startup process.
*
* <p class="note"> Note: different timestamps will be available for different values of
* {@link #getStartupState}:
*
* (Subsequent rows contain all timestamps of proceding states.)
*
* For {@link #STARTUP_STATE_STARTED}, timestamp {@link #START_TIMESTAMP_LAUNCH} will be
* available.
* For {@link #STARTUP_STATE_ERROR}, no additional timestamps are guaranteed available.
* For {@link #STARTUP_STATE_FIRST_FRAME_DRAWN}, timestamps
* {@link #START_TIMESTAMP_APPLICATION_ONCREATE}, {@link #START_TIMESTAMP_BIND_APPLICATION},
* and {@link #START_TIMESTAMP_FIRST_FRAME} will additionally be available.
*
* Timestamp {@link #START_TIMESTAMP_FULLY_DRAWN} is never guaranteed to be available as it is
* dependant on devloper calling {@link Activity#reportFullyDrawn}.
* </p>
*/
public @NonNull Map<Integer, Long> getStartupTimestamps() {
if (mStartupTimestampsNs == null) {
mStartupTimestampsNs = new ArrayMap<Integer, Long>();
}
return mStartupTimestampsNs;
}
/**
* The state of the app at startup.
*
* <p class="note"> Note: field will be set for {@link #getStartupState} value
* {@link #STARTUP_STATE_FIRST_FRAME_DRAWN}. Not guaranteed for other states.</p>
*/
public @StartType int getStartType() {
return mStartType;
}
/**
* The intent used to launch the application.
*
* <p class="note"> Note: Intent is stripped and does not include extras.</p>
*
* <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
*/
@SuppressLint("IntentBuilderName")
@Nullable
public Intent getIntent() {
return mStartIntent;
}
/**
* An instruction on how the activity should be launched. There are five modes that work in
* conjunction with activity flags in Intent objects to determine what should happen when the
* activity is called upon to handle an intent.
*
* Modes:
* {@link #LAUNCH_MODE_STANDARD}
* {@link #LAUNCH_MODE_SINGLE_TOP}
* {@link #LAUNCH_MODE_SINGLE_INSTANCE}
* {@link #LAUNCH_MODE_SINGLE_TASK}
* {@link #LAUNCH_MODE_SINGLE_INSTANCE_PER_TASK}
*
* <p class="note"> Note: field will be set for any {@link #getStartupState} value.</p>
*/
public @LaunchMode int getLaunchMode() {
return mLaunchMode;
}
/**
* Informs whether this is the first process launch for an app since it was
* {@link ApplicationInfo#FLAG_STOPPED force-stopped} for some reason.
* This allows the app to know if it should re-register for any alarms, jobs and other callbacks
* that were cleared when the app was force-stopped.
*
* @return {@code true} if this is the first process launch of the app after having been
* stopped, {@code false} otherwise.
*/
@FlaggedApi(android.content.pm.Flags.FLAG_STAY_STOPPED)
public boolean wasForceStopped() {
return mWasForceStopped;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mStartupState);
dest.writeInt(mPid);
dest.writeInt(mRealUid);
dest.writeInt(mPackageUid);
dest.writeInt(mDefiningUid);
dest.writeString(mPackageName);
dest.writeString(mProcessName);
dest.writeInt(mReason);
dest.writeInt(mStartupTimestampsNs == null ? 0 : mStartupTimestampsNs.size());
if (mStartupTimestampsNs != null) {
for (int i = 0; i < mStartupTimestampsNs.size(); i++) {
dest.writeInt(mStartupTimestampsNs.keyAt(i));
dest.writeLong(mStartupTimestampsNs.valueAt(i));
}
}
dest.writeInt(mStartType);
dest.writeParcelable(mStartIntent, flags);
dest.writeInt(mLaunchMode);
dest.writeBoolean(mWasForceStopped);
}
/** @hide */
public ApplicationStartInfo() {}
/** @hide */
public ApplicationStartInfo(ApplicationStartInfo other) {
mStartupState = other.mStartupState;
mPid = other.mPid;
mRealUid = other.mRealUid;
mPackageUid = other.mPackageUid;
mDefiningUid = other.mDefiningUid;
mPackageName = other.mPackageName;
mProcessName = other.mProcessName;
mReason = other.mReason;
mStartupTimestampsNs = other.mStartupTimestampsNs;
mStartType = other.mStartType;
mStartIntent = other.mStartIntent;
mLaunchMode = other.mLaunchMode;
mWasForceStopped = other.mWasForceStopped;
}
private ApplicationStartInfo(@NonNull Parcel in) {
mStartupState = in.readInt();
mPid = in.readInt();
mRealUid = in.readInt();
mPackageUid = in.readInt();
mDefiningUid = in.readInt();
mPackageName = intern(in.readString());
mProcessName = intern(in.readString());
mReason = in.readInt();
int starupTimestampCount = in.readInt();
for (int i = 0; i < starupTimestampCount; i++) {
int key = in.readInt();
long val = in.readLong();
addStartupTimestamp(key, val);
}
mStartType = in.readInt();
mStartIntent =
in.readParcelable(Intent.class.getClassLoader(), android.content.Intent.class);
mLaunchMode = in.readInt();
mWasForceStopped = in.readBoolean();
}
private static String intern(@Nullable String source) {
return source != null ? source.intern() : null;
}
public @NonNull static final Creator<ApplicationStartInfo> CREATOR =
new Creator<ApplicationStartInfo>() {
@Override
public ApplicationStartInfo createFromParcel(Parcel in) {
return new ApplicationStartInfo(in);
}
@Override
public ApplicationStartInfo[] newArray(int size) {
return new ApplicationStartInfo[size];
}
};
private static final String PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS = "timestamps";
private static final String PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP = "timestamp";
private static final String PROTO_SERIALIZER_ATTRIBUTE_KEY = "key";
private static final String PROTO_SERIALIZER_ATTRIBUTE_TS = "ts";
private static final String PROTO_SERIALIZER_ATTRIBUTE_INTENT = "intent";
/**
* Write to a protocol buffer output stream. Protocol buffer message definition at {@link
* android.app.ApplicationStartInfoProto}
*
* @param proto Stream to write the ApplicationStartInfo object to.
* @param fieldId Field Id of the ApplicationStartInfo as defined in the parent message
* @hide
*/
public void writeToProto(ProtoOutputStream proto, long fieldId) throws IOException {
final long token = proto.start(fieldId);
proto.write(ApplicationStartInfoProto.PID, mPid);
proto.write(ApplicationStartInfoProto.REAL_UID, mRealUid);
proto.write(ApplicationStartInfoProto.PACKAGE_UID, mPackageUid);
proto.write(ApplicationStartInfoProto.DEFINING_UID, mDefiningUid);
proto.write(ApplicationStartInfoProto.PROCESS_NAME, mProcessName);
proto.write(ApplicationStartInfoProto.STARTUP_STATE, mStartupState);
proto.write(ApplicationStartInfoProto.REASON, mReason);
if (mStartupTimestampsNs != null && mStartupTimestampsNs.size() > 0) {
ByteArrayOutputStream timestampsBytes = new ByteArrayOutputStream();
ObjectOutputStream timestampsOut = new ObjectOutputStream(timestampsBytes);
TypedXmlSerializer serializer = Xml.resolveSerializer(timestampsOut);
serializer.startDocument(null, true);
serializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS);
for (int i = 0; i < mStartupTimestampsNs.size(); i++) {
serializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP);
serializer.attributeInt(null, PROTO_SERIALIZER_ATTRIBUTE_KEY,
mStartupTimestampsNs.keyAt(i));
serializer.attributeLong(null, PROTO_SERIALIZER_ATTRIBUTE_TS,
mStartupTimestampsNs.valueAt(i));
serializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP);
}
serializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS);
serializer.endDocument();
proto.write(ApplicationStartInfoProto.STARTUP_TIMESTAMPS,
timestampsBytes.toByteArray());
timestampsOut.close();
}
proto.write(ApplicationStartInfoProto.START_TYPE, mStartType);
if (mStartIntent != null) {
ByteArrayOutputStream intentBytes = new ByteArrayOutputStream();
ObjectOutputStream intentOut = new ObjectOutputStream(intentBytes);
TypedXmlSerializer serializer = Xml.resolveSerializer(intentOut);
serializer.startDocument(null, true);
serializer.startTag(null, PROTO_SERIALIZER_ATTRIBUTE_INTENT);
mStartIntent.saveToXml(serializer);
serializer.endTag(null, PROTO_SERIALIZER_ATTRIBUTE_INTENT);
serializer.endDocument();
proto.write(ApplicationStartInfoProto.START_INTENT,
intentBytes.toByteArray());
intentOut.close();
}
proto.write(ApplicationStartInfoProto.LAUNCH_MODE, mLaunchMode);
proto.write(ApplicationStartInfoProto.WAS_FORCE_STOPPED, mWasForceStopped);
proto.end(token);
}
/**
* Read from a protocol buffer input stream. Protocol buffer message definition at {@link
* android.app.ApplicationStartInfoProto}
*
* @param proto Stream to read the ApplicationStartInfo object from.
* @param fieldId Field Id of the ApplicationStartInfo as defined in the parent message
* @hide
*/
public void readFromProto(ProtoInputStream proto, long fieldId)
throws IOException, WireTypeMismatchException, ClassNotFoundException {
final long token = proto.start(fieldId);
while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (proto.getFieldNumber()) {
case (int) ApplicationStartInfoProto.PID:
mPid = proto.readInt(ApplicationStartInfoProto.PID);
break;
case (int) ApplicationStartInfoProto.REAL_UID:
mRealUid = proto.readInt(ApplicationStartInfoProto.REAL_UID);
break;
case (int) ApplicationStartInfoProto.PACKAGE_UID:
mPackageUid = proto.readInt(ApplicationStartInfoProto.PACKAGE_UID);
break;
case (int) ApplicationStartInfoProto.DEFINING_UID:
mDefiningUid = proto.readInt(ApplicationStartInfoProto.DEFINING_UID);
break;
case (int) ApplicationStartInfoProto.PROCESS_NAME:
mProcessName = intern(proto.readString(ApplicationStartInfoProto.PROCESS_NAME));
break;
case (int) ApplicationStartInfoProto.STARTUP_STATE:
mStartupState = proto.readInt(ApplicationStartInfoProto.STARTUP_STATE);
break;
case (int) ApplicationStartInfoProto.REASON:
mReason = proto.readInt(ApplicationStartInfoProto.REASON);
break;
case (int) ApplicationStartInfoProto.STARTUP_TIMESTAMPS:
ByteArrayInputStream timestampsBytes = new ByteArrayInputStream(proto.readBytes(
ApplicationStartInfoProto.STARTUP_TIMESTAMPS));
ObjectInputStream timestampsIn = new ObjectInputStream(timestampsBytes);
mStartupTimestampsNs = new ArrayMap<Integer, Long>();
try {
TypedXmlPullParser parser = Xml.resolvePullParser(timestampsIn);
XmlUtils.beginDocument(parser, PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMPS);
int depth = parser.getDepth();
while (XmlUtils.nextElementWithin(parser, depth)) {
if (PROTO_SERIALIZER_ATTRIBUTE_TIMESTAMP.equals(parser.getName())) {
int key = parser.getAttributeInt(null,
PROTO_SERIALIZER_ATTRIBUTE_KEY);
long ts = parser.getAttributeLong(null,
PROTO_SERIALIZER_ATTRIBUTE_TS);
mStartupTimestampsNs.put(key, ts);
}
}
} catch (XmlPullParserException e) {
// Timestamps lost
}
timestampsIn.close();
break;
case (int) ApplicationStartInfoProto.START_TYPE:
mStartType = proto.readInt(ApplicationStartInfoProto.START_TYPE);
break;
case (int) ApplicationStartInfoProto.START_INTENT:
ByteArrayInputStream intentBytes = new ByteArrayInputStream(proto.readBytes(
ApplicationStartInfoProto.START_INTENT));
ObjectInputStream intentIn = new ObjectInputStream(intentBytes);
try {
TypedXmlPullParser parser = Xml.resolvePullParser(intentIn);
XmlUtils.beginDocument(parser, PROTO_SERIALIZER_ATTRIBUTE_INTENT);
mStartIntent = Intent.restoreFromXml(parser);
} catch (XmlPullParserException e) {
// Intent lost
}
intentIn.close();
break;
case (int) ApplicationStartInfoProto.LAUNCH_MODE:
mLaunchMode = proto.readInt(ApplicationStartInfoProto.LAUNCH_MODE);
break;
case (int) ApplicationStartInfoProto.WAS_FORCE_STOPPED:
mWasForceStopped = proto.readBoolean(
ApplicationStartInfoProto.WAS_FORCE_STOPPED);
break;
}
}
proto.end(token);
}
/** @hide */
public void dump(@NonNull PrintWriter pw, @Nullable String prefix, @Nullable String seqSuffix,
@NonNull SimpleDateFormat sdf) {
StringBuilder sb = new StringBuilder();
sb.append(prefix)
.append("ApplicationStartInfo ").append(seqSuffix).append(':')
.append('\n')
.append(" pid=").append(mPid)
.append(" realUid=").append(mRealUid)
.append(" packageUid=").append(mPackageUid)
.append(" definingUid=").append(mDefiningUid)
.append(" user=").append(UserHandle.getUserId(mPackageUid))
.append('\n')
.append(" package=").append(mPackageName)
.append(" process=").append(mProcessName)
.append(" startupState=").append(mStartupState)
.append(" reason=").append(reasonToString(mReason))
.append(" startType=").append(startTypeToString(mStartType))
.append(" launchMode=").append(mLaunchMode)
.append(" wasForceStopped=").append(mWasForceStopped)
.append('\n');
if (mStartIntent != null) {
sb.append(" intent=").append(mStartIntent.toString())
.append('\n');
}
if (mStartupTimestampsNs != null && mStartupTimestampsNs.size() > 0) {
sb.append(" timestamps: ");
for (int i = 0; i < mStartupTimestampsNs.size(); i++) {
sb.append(mStartupTimestampsNs.keyAt(i)).append("=").append(mStartupTimestampsNs
.valueAt(i)).append(" ");
}
sb.append('\n');
}
pw.print(sb.toString());
}
private static String reasonToString(@StartReason int reason) {
return switch (reason) {
case START_REASON_ALARM -> "ALARM";
case START_REASON_BACKUP -> "BACKUP";
case START_REASON_BOOT_COMPLETE -> "BOOT COMPLETE";
case START_REASON_BROADCAST -> "BROADCAST";
case START_REASON_CONTENT_PROVIDER -> "CONTENT PROVIDER";
case START_REASON_JOB -> "JOB";
case START_REASON_LAUNCHER -> "LAUNCHER";
case START_REASON_LAUNCHER_RECENTS -> "LAUNCHER RECENTS";
case START_REASON_OTHER -> "OTHER";
case START_REASON_PUSH -> "PUSH";
case START_REASON_SERVICE -> "SERVICE";
case START_REASON_START_ACTIVITY -> "START ACTIVITY";
default -> "";
};
}
private static String startTypeToString(@StartType int startType) {
return switch (startType) {
case START_TYPE_UNSET -> "UNSET";
case START_TYPE_COLD -> "COLD";
case START_TYPE_WARM -> "WARM";
case START_TYPE_HOT -> "HOT";
default -> "";
};
}
/** @hide */
@Override
public boolean equals(@Nullable Object other) {
if (other == null || !(other instanceof ApplicationStartInfo)) {
return false;
}
final ApplicationStartInfo o = (ApplicationStartInfo) other;
return mPid == o.mPid && mRealUid == o.mRealUid && mPackageUid == o.mPackageUid
&& mDefiningUid == o.mDefiningUid && mReason == o.mReason
&& mStartupState == o.mStartupState && mStartType == o.mStartType
&& mLaunchMode == o.mLaunchMode && TextUtils.equals(mProcessName, o.mProcessName)
&& timestampsEquals(o) && mWasForceStopped == o.mWasForceStopped;
}
@Override
public int hashCode() {
return Objects.hash(mPid, mRealUid, mPackageUid, mDefiningUid, mReason, mStartupState,
mStartType, mLaunchMode, mProcessName,
mStartupTimestampsNs);
}
private boolean timestampsEquals(@NonNull ApplicationStartInfo other) {
if (mStartupTimestampsNs == null && other.mStartupTimestampsNs == null) {
return true;
}
if (mStartupTimestampsNs == null || other.mStartupTimestampsNs == null) {
return false;
}
return mStartupTimestampsNs.equals(other.mStartupTimestampsNs);
}
}