| /* |
| * 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.CurrentTimeMillisLong; |
| import android.annotation.IntDef; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.app.ActivityManager.RunningAppProcessInfo.Importance; |
| import android.icu.text.SimpleDateFormat; |
| import android.os.Parcel; |
| import android.os.ParcelFileDescriptor; |
| import android.os.Parcelable; |
| import android.os.RemoteException; |
| import android.os.UserHandle; |
| import android.text.TextUtils; |
| import android.util.DebugUtils; |
| import android.util.proto.ProtoInputStream; |
| import android.util.proto.ProtoOutputStream; |
| import android.util.proto.WireTypeMismatchException; |
| |
| import com.android.internal.util.ArrayUtils; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.PrintWriter; |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.util.Date; |
| import java.util.Objects; |
| import java.util.zip.GZIPInputStream; |
| |
| /** |
| * Describes the information of an application process's death. |
| * |
| * <p> |
| * Application process could die for many reasons, for example {@link #REASON_LOW_MEMORY} |
| * when it was killed by the system because it was running low on memory. Reason |
| * of the death can be retrieved via {@link #getReason}. Besides the reason, there are a few other |
| * auxiliary APIs like {@link #getStatus} and {@link #getImportance} to help the caller with |
| * additional diagnostic information. |
| * </p> |
| * |
| */ |
| public final class ApplicationExitInfo implements Parcelable { |
| |
| /** |
| * Application process died due to unknown reason. |
| */ |
| public static final int REASON_UNKNOWN = 0; |
| |
| /** |
| * Application process exit normally by itself, for example, |
| * via {@link java.lang.System#exit}; {@link #getStatus} will specify the exit code. |
| * |
| * <p>Applications should normally not do this, as the system has a better knowledge |
| * in terms of process management.</p> |
| */ |
| public static final int REASON_EXIT_SELF = 1; |
| |
| /** |
| * Application process died due to the result of an OS signal; for example, |
| * {@link android.system.OsConstants#SIGKILL}; {@link #getStatus} will specify the signal |
| * number. |
| */ |
| public static final int REASON_SIGNALED = 2; |
| |
| /** |
| * Application process was killed by the system low memory killer, meaning the system was |
| * under memory pressure at the time of kill. |
| * |
| * <p class="note"> |
| * Not all devices support reporting {@link #REASON_LOW_MEMORY}; on a device with no such |
| * support, when a process is killed due to memory pressure, the {@link #getReason} will return |
| * {@link #REASON_SIGNALED} and {@link #getStatus} will return |
| * the value {@link android.system.OsConstants#SIGKILL}. |
| * |
| * Application should use {@link android.app.ActivityManager#isLowMemoryKillReportSupported() |
| * ActivityManager.isLowMemoryKillReportSupported()} to check |
| * if the device supports reporting {@link #REASON_LOW_MEMORY} or not. |
| * </p> |
| */ |
| public static final int REASON_LOW_MEMORY = 3; |
| |
| /** |
| * Application process died because of an unhandled exception in Java code. |
| */ |
| public static final int REASON_CRASH = 4; |
| |
| /** |
| * Application process died because of a native code crash. |
| */ |
| public static final int REASON_CRASH_NATIVE = 5; |
| |
| /** |
| * Application process was killed due to being unresponsive (ANR). |
| */ |
| public static final int REASON_ANR = 6; |
| |
| /** |
| * Application process was killed because of initialization failure, |
| * for example, it took too long to attach to the system during the start, |
| * or there was an error during initialization. |
| */ |
| public static final int REASON_INITIALIZATION_FAILURE = 7; |
| |
| /** |
| * Application process was killed due to a runtime permission change. |
| */ |
| public static final int REASON_PERMISSION_CHANGE = 8; |
| |
| /** |
| * Application process was killed by the system due to excessive resource usage. |
| */ |
| public static final int REASON_EXCESSIVE_RESOURCE_USAGE = 9; |
| |
| /** |
| * Application process was killed because of the user request, for example, |
| * user clicked the "Force stop" button of the application in the Settings, |
| * or removed the application away from Recents. |
| * <p> |
| * Prior to {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, one of the uses of this |
| * reason was to indicate that an app was killed due to it being updated or any of its component |
| * states have changed without {@link android.content.pm.PackageManager#DONT_KILL_APP} |
| */ |
| public static final int REASON_USER_REQUESTED = 10; |
| |
| /** |
| * Application process was killed, because the user it is running as on devices |
| * with mutlple users, was stopped. |
| */ |
| public static final int REASON_USER_STOPPED = 11; |
| |
| /** |
| * Application process was killed because its dependency was going away, for example, |
| * a stable content provider connection's client will be killed if the provider is killed. |
| */ |
| public static final int REASON_DEPENDENCY_DIED = 12; |
| |
| /** |
| * Application process was killed by the system for various other reasons which are |
| * not by problems in apps and not actionable by apps, for example, the system just |
| * finished updates; {@link #getDescription} will specify the cause given by the system. |
| */ |
| public static final int REASON_OTHER = 13; |
| |
| /** |
| * Application process was killed by App Freezer, for example, because it receives |
| * sync binder transactions while being frozen. |
| */ |
| public static final int REASON_FREEZER = 14; |
| |
| /** |
| * Application process was killed because the app was disabled, or any of its |
| * component states have changed without {@link android.content.pm.PackageManager#DONT_KILL_APP} |
| * <p> |
| * Prior to {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, |
| * {@link #REASON_USER_REQUESTED} was used to indicate that an app was updated. |
| */ |
| public static final int REASON_PACKAGE_STATE_CHANGE = 15; |
| |
| /** |
| * Application process was killed because it was updated. |
| * <p> |
| * Prior to {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, |
| * {@link #REASON_USER_REQUESTED} was used to indicate that an app was updated. |
| */ |
| public static final int REASON_PACKAGE_UPDATED = 16; |
| |
| /** |
| * Application process kills subreason is unknown. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_UNKNOWN = 0; |
| |
| /** |
| * Application process was killed because user quit it on the "wait for debugger" dialog; |
| * this would be set when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_WAIT_FOR_DEBUGGER = 1; |
| |
| /** |
| * Application process was killed by the activity manager because there were too many cached |
| * processes; this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_TOO_MANY_CACHED = 2; |
| |
| /** |
| * Application process was killed by the activity manager because there were too many empty |
| * processes; this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_TOO_MANY_EMPTY = 3; |
| |
| /** |
| * Application process was killed by the activity manager because there were too many cached |
| * processes and this process had been in empty state for a long time; |
| * this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_TRIM_EMPTY = 4; |
| |
| /** |
| * Application process was killed by the activity manager because system was on memory pressure |
| * and this process took large amount of cached memory; |
| * this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_LARGE_CACHED = 5; |
| |
| /** |
| * Application process was killed by the activity manager because the system was on low memory |
| * pressure for a significant amount of time since last idle; |
| * this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_MEMORY_PRESSURE = 6; |
| |
| /** |
| * Application process was killed by the activity manager due to excessive CPU usage; |
| * this would be set only when the reason is {@link #REASON_EXCESSIVE_RESOURCE_USAGE}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_EXCESSIVE_CPU = 7; |
| |
| /** |
| * System update has done (so the system update process should be killed); |
| * this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_SYSTEM_UPDATE_DONE = 8; |
| |
| /** |
| * Kill all foreground services, for now it only occurs when enabling the quiet |
| * mode for the managed profile; |
| * this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_KILL_ALL_FG = 9; |
| |
| /** |
| * All background processes except certain ones were killed, for now it only occurs |
| * when the density of the default display is changed; |
| * this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_KILL_ALL_BG_EXCEPT = 10; |
| |
| /** |
| * The process associated with the UID was explicitly killed, for example, |
| * it could be because of platform compatibility overrides; |
| * this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_KILL_UID = 11; |
| |
| /** |
| * The process was explicitly killed with its PID, typically because of |
| * the low memory for surfaces; |
| * this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_KILL_PID = 12; |
| |
| /** |
| * The start of the process was invalid; |
| * this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_INVALID_START = 13; |
| |
| /** |
| * The process was killed because it's in an invalid state, typically |
| * it's triggered from SHELL; |
| * this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_INVALID_STATE = 14; |
| |
| /** |
| * The process was killed when it's imperceptible to user, because it was |
| * in a bad state; |
| * this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_IMPERCEPTIBLE = 15; |
| |
| /** |
| * The process was killed because it's being moved out from LRU list; |
| * this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_REMOVE_LRU = 16; |
| |
| /** |
| * The process was killed because it's isolated and was in a cached state; |
| * this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_ISOLATED_NOT_NEEDED = 17; |
| |
| /** |
| * The process was killed because it's in forced-app-standby state, and it's cached and |
| * its uid state is idle; this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_CACHED_IDLE_FORCED_APP_STANDBY = 18; |
| |
| /** |
| * The process was killed because it fails to freeze/unfreeze binder |
| * or query binder frozen info while being frozen. |
| * this would be set only when the reason is {@link #REASON_FREEZER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_FREEZER_BINDER_IOCTL = 19; |
| |
| /** |
| * The process was killed because it receives sync binder transactions |
| * while being frozen. |
| * this would be set only when the reason is {@link #REASON_FREEZER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_FREEZER_BINDER_TRANSACTION = 20; |
| |
| /** |
| * The process was killed because of force-stop, it could be due to that |
| * the user clicked the "Force stop" button of the application in the Settings; |
| * this would be set only when the reason is {@link #REASON_USER_REQUESTED}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_FORCE_STOP = 21; |
| |
| /** |
| * The process was killed because the user removed the application away from Recents; |
| * this would be set only when the reason is {@link #REASON_USER_REQUESTED}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_REMOVE_TASK = 22; |
| |
| /** |
| * The process was killed because the user stopped the application from the task manager; |
| * this would be set only when the reason is {@link #REASON_USER_REQUESTED}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_STOP_APP = 23; |
| |
| /** |
| * The process was killed because the user stopped the application from developer options, |
| * or via the adb shell commmand interface; this would be set only when the reason is |
| * {@link #REASON_USER_REQUESTED}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_KILL_BACKGROUND = 24; |
| |
| /** |
| * The process was killed because of package update; this would be set only when the reason is |
| * {@link #REASON_USER_REQUESTED}. |
| * |
| * For internal use only. |
| * |
| * @deprecated starting {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, |
| * an app being killed due to a package update will have the reason |
| * {@link #REASON_PACKAGE_UPDATED} |
| * |
| * @hide |
| */ |
| public static final int SUBREASON_PACKAGE_UPDATE = 25; |
| |
| /** |
| * The process was killed because of undelivered broadcasts; this would be set only when the |
| * reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_UNDELIVERED_BROADCAST = 26; |
| |
| /** |
| * The process was killed because its associated SDK sandbox process (where it had loaded SDKs) |
| * had died; this would be set only when the reason is {@link #REASON_DEPENDENCY_DIED}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_SDK_SANDBOX_DIED = 27; |
| |
| /** |
| * The process was killed because it was an SDK sandbox process that was either not usable or |
| * was no longer being used; this would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_SDK_SANDBOX_NOT_NEEDED = 28; |
| |
| /** |
| * The process was killed because the binder proxy limit for system server was exceeded. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_EXCESSIVE_BINDER_OBJECTS = 29; |
| |
| /** |
| * The process was killed by the [kernel] Out-of-memory (OOM) killer; this |
| * would be set only when the reason is {@link #REASON_LOW_MEMORY}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_OOM_KILL = 30; |
| |
| /** |
| * The process was killed because its async kernel binder buffer is running out |
| * while being frozen. |
| * this would be set only when the reason is {@link #REASON_FREEZER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_FREEZER_BINDER_ASYNC_FULL = 31; |
| |
| /** |
| * The process was killed because it was sending too many broadcasts while it is in the |
| * Cached state. This would be set only when the reason is {@link #REASON_OTHER}. |
| * |
| * For internal use only. |
| * @hide |
| */ |
| public static final int SUBREASON_EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED = 32; |
| |
| // If there is any OEM code which involves additional app kill reasons, it should |
| // be categorized in {@link #REASON_OTHER}, with subreason code starting from 1000. |
| |
| /** |
| * @see #getPid |
| */ |
| private int mPid; |
| |
| /** |
| * @see #getRealUid |
| */ |
| private int mRealUid; |
| |
| /** |
| * @see #getPackageUid |
| */ |
| private int mPackageUid; |
| |
| /** |
| * @see #getDefiningUid |
| */ |
| private int mDefiningUid; |
| |
| /** |
| * @see #getProcessName |
| */ |
| private String mProcessName; |
| |
| /** |
| * @see #getReason |
| */ |
| private @Reason int mReason; |
| |
| /** |
| * @see #getStatus |
| */ |
| private int mStatus; |
| |
| /** |
| * @see #getImportance |
| */ |
| private @Importance int mImportance; |
| |
| /** |
| * @see #getPss |
| */ |
| private long mPss; |
| |
| /** |
| * @see #getRss |
| */ |
| private long mRss; |
| |
| /** |
| * @see #getTimestamp |
| */ |
| private @CurrentTimeMillisLong long mTimestamp; |
| |
| /** |
| * @see #getDescription |
| */ |
| private @Nullable String mDescription; |
| |
| /** |
| * @see #getSubReason |
| */ |
| private @SubReason int mSubReason; |
| |
| /** |
| * @see #getConnectionGroup |
| */ |
| private int mConnectionGroup; |
| |
| /** |
| * @see #getPackageName |
| */ |
| private String mPackageName; |
| |
| /** |
| * @see #getPackageList |
| */ |
| private String[] mPackageList; |
| |
| /** |
| * @see #getProcessStateSummary |
| */ |
| private byte[] mState; |
| |
| /** |
| * The file to the trace file in the storage; |
| * |
| * for system internal use only, will not retain across processes. |
| * |
| * @see #getTraceInputStream |
| */ |
| private File mTraceFile; |
| |
| /** |
| * The Binder interface to retrieve the file descriptor to |
| * the trace file from the system. |
| */ |
| private IAppTraceRetriever mAppTraceRetriever; |
| |
| /** |
| * ParcelFileDescriptor pointing to a native tombstone. |
| * |
| * @see #getTraceInputStream |
| */ |
| private IParcelFileDescriptorRetriever mNativeTombstoneRetriever; |
| |
| /** |
| * Whether or not we've logged this into the statsd. |
| * |
| * for system internal use only, will not retain across processes. |
| */ |
| private boolean mLoggedInStatsd; |
| |
| /** |
| * Whether or not this process hosts one or more foreground services. |
| * |
| * for system internal use only, will not retain across processes. |
| */ |
| private boolean mHasForegroundServices; |
| |
| /** @hide */ |
| @IntDef(prefix = { "REASON_" }, value = { |
| REASON_UNKNOWN, |
| REASON_EXIT_SELF, |
| REASON_SIGNALED, |
| REASON_LOW_MEMORY, |
| REASON_CRASH, |
| REASON_CRASH_NATIVE, |
| REASON_ANR, |
| REASON_INITIALIZATION_FAILURE, |
| REASON_PERMISSION_CHANGE, |
| REASON_EXCESSIVE_RESOURCE_USAGE, |
| REASON_USER_REQUESTED, |
| REASON_USER_STOPPED, |
| REASON_DEPENDENCY_DIED, |
| REASON_OTHER, |
| REASON_FREEZER, |
| REASON_PACKAGE_STATE_CHANGE, |
| REASON_PACKAGE_UPDATED, |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface Reason {} |
| |
| /** @hide */ |
| @IntDef(prefix = { "SUBREASON_" }, value = { |
| SUBREASON_UNKNOWN, |
| SUBREASON_WAIT_FOR_DEBUGGER, |
| SUBREASON_TOO_MANY_CACHED, |
| SUBREASON_TOO_MANY_EMPTY, |
| SUBREASON_TRIM_EMPTY, |
| SUBREASON_LARGE_CACHED, |
| SUBREASON_MEMORY_PRESSURE, |
| SUBREASON_EXCESSIVE_CPU, |
| SUBREASON_SYSTEM_UPDATE_DONE, |
| SUBREASON_KILL_ALL_FG, |
| SUBREASON_KILL_ALL_BG_EXCEPT, |
| SUBREASON_KILL_UID, |
| SUBREASON_KILL_PID, |
| SUBREASON_INVALID_START, |
| SUBREASON_INVALID_STATE, |
| SUBREASON_IMPERCEPTIBLE, |
| SUBREASON_REMOVE_LRU, |
| SUBREASON_ISOLATED_NOT_NEEDED, |
| SUBREASON_FREEZER_BINDER_IOCTL, |
| SUBREASON_FREEZER_BINDER_TRANSACTION, |
| SUBREASON_FORCE_STOP, |
| SUBREASON_REMOVE_TASK, |
| SUBREASON_STOP_APP, |
| SUBREASON_KILL_BACKGROUND, |
| SUBREASON_PACKAGE_UPDATE, |
| SUBREASON_UNDELIVERED_BROADCAST, |
| SUBREASON_EXCESSIVE_BINDER_OBJECTS, |
| SUBREASON_OOM_KILL, |
| SUBREASON_FREEZER_BINDER_ASYNC_FULL, |
| SUBREASON_EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED, |
| }) |
| @Retention(RetentionPolicy.SOURCE) |
| public @interface SubReason {} |
| |
| /** |
| * The process id of the process that died. |
| */ |
| 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. |
| */ |
| public int getRealUid() { |
| return mRealUid; |
| } |
| |
| /** |
| * Similar to {@link #getRealUid}, it's the kernel user identifier that is assigned at the |
| * package installation time. |
| */ |
| 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. |
| */ |
| public int getDefiningUid() { |
| return mDefiningUid; |
| } |
| |
| /** |
| * The actual process name it was running with. |
| */ |
| public @NonNull String getProcessName() { |
| return mProcessName; |
| } |
| |
| /** |
| * The reason code of the process's death. |
| */ |
| public @Reason int getReason() { |
| return mReason; |
| } |
| |
| /** |
| * The exit status argument of exit() if the application calls it, or the signal |
| * number if the application is signaled. |
| */ |
| public int getStatus() { |
| return mStatus; |
| } |
| |
| /** |
| * The importance of the process that it used to have before the death. |
| */ |
| public @Importance int getImportance() { |
| return mImportance; |
| } |
| |
| /** |
| * Last proportional set size of the memory that the process had used in kB. |
| * |
| * <p class="note">Note: This is the value from last sampling on the process, |
| * it's NOT the exact memory information prior to its death; and it'll be zero |
| * if the process died before system had a chance to take the sample. </p> |
| */ |
| public long getPss() { |
| return mPss; |
| } |
| |
| /** |
| * Last resident set size of the memory that the process had used in kB. |
| * |
| * <p class="note">Note: This is the value from last sampling on the process, |
| * it's NOT the exact memory information prior to its death; and it'll be zero |
| * if the process died before system had a chance to take the sample. </p> |
| */ |
| public long getRss() { |
| return mRss; |
| } |
| |
| /** |
| * The timestamp of the process's death, in milliseconds since the epoch, |
| * as returned by {@link java.lang.System#currentTimeMillis() System.currentTimeMillis()}. |
| */ |
| public @CurrentTimeMillisLong long getTimestamp() { |
| return mTimestamp; |
| } |
| |
| /** |
| * The human readable description of the process's death, given by the system; could be null. |
| * |
| * <p class="note">Note: only intended to be human-readable and the system provides no |
| * guarantees that the format is stable across devices or Android releases.</p> |
| */ |
| public @Nullable String getDescription() { |
| final StringBuilder sb = new StringBuilder(); |
| |
| if (mSubReason != SUBREASON_UNKNOWN) { |
| sb.append("["); |
| sb.append(subreasonToString(mSubReason)); |
| sb.append("]"); |
| } |
| |
| if (!TextUtils.isEmpty(mDescription)) { |
| if (sb.length() > 0) { |
| sb.append(" "); |
| } |
| sb.append(mDescription); |
| } |
| |
| return sb.toString(); |
| } |
| |
| /** |
| * Return the user id of the record on a multi-user system. |
| */ |
| public @NonNull UserHandle getUserHandle() { |
| return UserHandle.of(UserHandle.getUserId(mRealUid)); |
| } |
| |
| /** |
| * Return the state data set by calling |
| * {@link android.app.ActivityManager#setProcessStateSummary(byte[]) |
| * ActivityManager.setProcessStateSummary(byte[])} from the process before its death. |
| * |
| * @return The process-customized data |
| * @see ActivityManager#setProcessStateSummary(byte[]) |
| */ |
| public @Nullable byte[] getProcessStateSummary() { |
| return mState; |
| } |
| |
| /** |
| * Return the InputStream to the traces that was taken by the system |
| * prior to the death of the process; typically it'll be available when |
| * the reason is {@link #REASON_ANR}, though if the process gets an ANR |
| * but recovers, and dies for another reason later, this trace will be included |
| * in the record of {@link ApplicationExitInfo} still. Beginning with API 31, |
| * tombstone traces will be returned for |
| * {@link #REASON_CRASH_NATIVE}, with an InputStream containing a protobuf with |
| * <a href="https://android.googlesource.com/platform/system/core/+/refs/heads/master/debuggerd/proto/tombstone.proto">this schema</a>. |
| * Note that because these traces are kept in a separate global circular buffer, crashes may be |
| * overwritten by newer crashes (including from other applications), so this may still return |
| * null. |
| * |
| * @return The input stream to the traces that was taken by the system |
| * prior to the death of the process. |
| */ |
| public @Nullable InputStream getTraceInputStream() throws IOException { |
| if (mAppTraceRetriever == null && mNativeTombstoneRetriever == null) { |
| return null; |
| } |
| |
| try { |
| if (mNativeTombstoneRetriever != null) { |
| final ParcelFileDescriptor pfd = mNativeTombstoneRetriever.getPfd(); |
| if (pfd == null) { |
| return null; |
| } |
| |
| return new ParcelFileDescriptor.AutoCloseInputStream(pfd); |
| } else { |
| final ParcelFileDescriptor fd = mAppTraceRetriever.getTraceFileDescriptor( |
| mPackageName, mPackageUid, mPid); |
| if (fd == null) { |
| return null; |
| } |
| return new GZIPInputStream(new ParcelFileDescriptor.AutoCloseInputStream(fd)); |
| } |
| } catch (RemoteException e) { |
| return null; |
| } |
| } |
| |
| /** |
| * Similar to {@link #getTraceInputStream} but return the File object. |
| * |
| * For internal use only. |
| * |
| * @hide |
| */ |
| public @Nullable File getTraceFile() { |
| return mTraceFile; |
| } |
| |
| /** |
| * A subtype reason in conjunction with {@link #mReason}. |
| * |
| * For internal use only. |
| * |
| * @hide |
| */ |
| public @SubReason int getSubReason() { |
| return mSubReason; |
| } |
| |
| /** |
| * The connection group this process belongs to, if there is any. |
| * @see android.content.Context#updateServiceGroup |
| * |
| * For internal use only. |
| * |
| * @hide |
| */ |
| public int getConnectionGroup() { |
| return mConnectionGroup; |
| } |
| |
| /** |
| * Name of first package running in this process; |
| * |
| * @hide |
| */ |
| public String getPackageName() { |
| return mPackageName; |
| } |
| |
| /** |
| * List of packages running in this process; |
| * |
| * For system internal use only, will not retain across processes. |
| * |
| * @hide |
| */ |
| public String[] getPackageList() { |
| return mPackageList; |
| } |
| |
| /** |
| * @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 #getProcessName |
| * |
| * @hide |
| */ |
| public void setProcessName(final String processName) { |
| mProcessName = intern(processName); |
| } |
| |
| /** |
| * @see #getReason |
| * |
| * @hide |
| */ |
| public void setReason(final @Reason int reason) { |
| mReason = reason; |
| } |
| |
| /** |
| * @see #getStatus |
| * |
| * @hide |
| */ |
| public void setStatus(final int status) { |
| mStatus = status; |
| } |
| |
| /** |
| * @see #getImportance |
| * |
| * @hide |
| */ |
| public void setImportance(final @Importance int importance) { |
| mImportance = importance; |
| } |
| |
| /** |
| * @see #getPss |
| * |
| * @hide |
| */ |
| public void setPss(final long pss) { |
| mPss = pss; |
| } |
| |
| /** |
| * @see #getRss |
| * |
| * @hide |
| */ |
| public void setRss(final long rss) { |
| mRss = rss; |
| } |
| |
| /** |
| * @see #getTimestamp |
| * |
| * @hide |
| */ |
| public void setTimestamp(final @CurrentTimeMillisLong long timestamp) { |
| mTimestamp = timestamp; |
| } |
| |
| /** |
| * @see #getDescription |
| * |
| * @hide |
| */ |
| public void setDescription(final String description) { |
| mDescription = intern(description); |
| } |
| |
| /** |
| * @see #getSubReason |
| * |
| * @hide |
| */ |
| public void setSubReason(final @SubReason int subReason) { |
| mSubReason = subReason; |
| } |
| |
| /** |
| * @see #getConnectionGroup |
| * |
| * @hide |
| */ |
| public void setConnectionGroup(final int connectionGroup) { |
| mConnectionGroup = connectionGroup; |
| } |
| |
| /** |
| * @see #getPackageName |
| * |
| * @hide |
| */ |
| public void setPackageName(final String packageName) { |
| mPackageName = intern(packageName); |
| } |
| |
| /** |
| * @see #getPackageList |
| * |
| * @hide |
| */ |
| public void setPackageList(final String[] packageList) { |
| mPackageList = packageList; |
| } |
| |
| /** |
| * @see #getProcessStateSummary |
| * |
| * @hide |
| */ |
| public void setProcessStateSummary(final byte[] state) { |
| mState = state; |
| } |
| |
| /** |
| * @see #getTraceFile |
| * |
| * @hide |
| */ |
| public void setTraceFile(final File traceFile) { |
| mTraceFile = traceFile; |
| } |
| |
| /** |
| * @see #mAppTraceRetriever |
| * |
| * @hide |
| */ |
| public void setAppTraceRetriever(final IAppTraceRetriever retriever) { |
| mAppTraceRetriever = retriever; |
| } |
| |
| /** |
| * @see mNativeTombstoneRetriever |
| * |
| * @hide |
| */ |
| public void setNativeTombstoneRetriever(final IParcelFileDescriptorRetriever retriever) { |
| mNativeTombstoneRetriever = retriever; |
| } |
| |
| /** |
| * @see #mLoggedInStatsd |
| * |
| * @hide |
| */ |
| public boolean isLoggedInStatsd() { |
| return mLoggedInStatsd; |
| } |
| |
| /** |
| * @see #mLoggedInStatsd |
| * |
| * @hide |
| */ |
| public void setLoggedInStatsd(boolean loggedInStatsd) { |
| mLoggedInStatsd = loggedInStatsd; |
| } |
| |
| /** |
| * @see #mHasForegroundServices |
| * |
| * @hide |
| */ |
| public boolean hasForegroundServices() { |
| return mHasForegroundServices; |
| } |
| |
| /** |
| * @see #mHasForegroundServices |
| * |
| * @hide |
| */ |
| public void setHasForegroundServices(boolean hasForegroundServices) { |
| mHasForegroundServices = hasForegroundServices; |
| } |
| |
| @Override |
| public int describeContents() { |
| return 0; |
| } |
| |
| @Override |
| public void writeToParcel(@NonNull Parcel dest, int flags) { |
| dest.writeInt(mPid); |
| dest.writeInt(mRealUid); |
| dest.writeInt(mPackageUid); |
| dest.writeInt(mDefiningUid); |
| dest.writeString(mProcessName); |
| dest.writeString(mPackageName); |
| dest.writeInt(mConnectionGroup); |
| dest.writeInt(mReason); |
| dest.writeInt(mSubReason); |
| dest.writeInt(mStatus); |
| dest.writeInt(mImportance); |
| dest.writeLong(mPss); |
| dest.writeLong(mRss); |
| dest.writeLong(mTimestamp); |
| dest.writeString(mDescription); |
| dest.writeByteArray(mState); |
| if (mAppTraceRetriever != null) { |
| dest.writeInt(1); |
| dest.writeStrongBinder(mAppTraceRetriever.asBinder()); |
| } else { |
| dest.writeInt(0); |
| } |
| if (mNativeTombstoneRetriever != null) { |
| dest.writeInt(1); |
| dest.writeStrongBinder(mNativeTombstoneRetriever.asBinder()); |
| } else { |
| dest.writeInt(0); |
| } |
| } |
| |
| /** @hide */ |
| public ApplicationExitInfo() { |
| } |
| |
| /** @hide */ |
| public ApplicationExitInfo(ApplicationExitInfo other) { |
| mPid = other.mPid; |
| mRealUid = other.mRealUid; |
| mPackageUid = other.mPackageUid; |
| mDefiningUid = other.mDefiningUid; |
| mProcessName = other.mProcessName; |
| mPackageName = other.mPackageName; |
| mConnectionGroup = other.mConnectionGroup; |
| mReason = other.mReason; |
| mStatus = other.mStatus; |
| mSubReason = other.mSubReason; |
| mImportance = other.mImportance; |
| mPss = other.mPss; |
| mRss = other.mRss; |
| mTimestamp = other.mTimestamp; |
| mDescription = other.mDescription; |
| mPackageName = other.mPackageName; |
| mPackageList = other.mPackageList; |
| mState = other.mState; |
| mTraceFile = other.mTraceFile; |
| mAppTraceRetriever = other.mAppTraceRetriever; |
| mNativeTombstoneRetriever = other.mNativeTombstoneRetriever; |
| mLoggedInStatsd = other.mLoggedInStatsd; |
| mHasForegroundServices = other.mHasForegroundServices; |
| } |
| |
| private ApplicationExitInfo(@NonNull Parcel in) { |
| mPid = in.readInt(); |
| mRealUid = in.readInt(); |
| mPackageUid = in.readInt(); |
| mDefiningUid = in.readInt(); |
| mProcessName = intern(in.readString()); |
| mPackageName = intern(in.readString()); |
| mConnectionGroup = in.readInt(); |
| mReason = in.readInt(); |
| mSubReason = in.readInt(); |
| mStatus = in.readInt(); |
| mImportance = in.readInt(); |
| mPss = in.readLong(); |
| mRss = in.readLong(); |
| mTimestamp = in.readLong(); |
| mDescription = intern(in.readString()); |
| mState = in.createByteArray(); |
| if (in.readInt() == 1) { |
| mAppTraceRetriever = IAppTraceRetriever.Stub.asInterface(in.readStrongBinder()); |
| } |
| if (in.readInt() == 1) { |
| mNativeTombstoneRetriever = IParcelFileDescriptorRetriever.Stub.asInterface( |
| in.readStrongBinder()); |
| } |
| } |
| |
| private static String intern(@Nullable String source) { |
| return source != null ? source.intern() : null; |
| } |
| |
| public @NonNull static final Creator<ApplicationExitInfo> CREATOR = |
| new Creator<ApplicationExitInfo>() { |
| @Override |
| public ApplicationExitInfo createFromParcel(Parcel in) { |
| return new ApplicationExitInfo(in); |
| } |
| |
| @Override |
| public ApplicationExitInfo[] newArray(int size) { |
| return new ApplicationExitInfo[size]; |
| } |
| }; |
| |
| /** @hide */ |
| public void dump(@NonNull PrintWriter pw, @Nullable String prefix, @Nullable String seqSuffix, |
| @NonNull SimpleDateFormat sdf) { |
| StringBuilder sb = new StringBuilder(); |
| sb.append(prefix) |
| .append("ApplicationExitInfo ").append(seqSuffix).append(':') |
| .append('\n'); |
| sb.append(prefix).append(' ') |
| .append(" timestamp=").append(sdf.format(new Date(mTimestamp))) |
| .append(" pid=").append(mPid) |
| .append(" realUid=").append(mRealUid) |
| .append(" packageUid=").append(mPackageUid) |
| .append(" definingUid=").append(mDefiningUid) |
| .append(" user=").append(UserHandle.getUserId(mPackageUid)) |
| .append('\n'); |
| sb.append(prefix).append(' ') |
| .append(" process=").append(mProcessName) |
| .append(" reason=").append(mReason) |
| .append(" (").append(reasonCodeToString(mReason)).append(")") |
| .append(" subreason=").append(mSubReason) |
| .append(" (").append(subreasonToString(mSubReason)).append(")") |
| .append(" status=").append(mStatus) |
| .append('\n'); |
| sb.append(prefix).append(' ') |
| .append(" importance=").append(mImportance) |
| .append(" pss="); |
| DebugUtils.sizeValueToString(mPss << 10, sb); |
| sb.append(" rss="); |
| DebugUtils.sizeValueToString(mRss << 10, sb); |
| sb.append(" description=").append(mDescription) |
| .append(" state=").append((ArrayUtils.isEmpty(mState) |
| ? "empty" : Integer.toString(mState.length) + " bytes")) |
| .append(" trace=").append(mTraceFile) |
| .append('\n'); |
| pw.print(sb.toString()); |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append("ApplicationExitInfo(timestamp="); |
| sb.append(new SimpleDateFormat().format(new Date(mTimestamp))); |
| sb.append(" pid=").append(mPid); |
| sb.append(" realUid=").append(mRealUid); |
| sb.append(" packageUid=").append(mPackageUid); |
| sb.append(" definingUid=").append(mDefiningUid); |
| sb.append(" user=").append(UserHandle.getUserId(mPackageUid)); |
| sb.append(" process=").append(mProcessName); |
| sb.append(" reason=").append(mReason).append(" (") |
| .append(reasonCodeToString(mReason)).append(")"); |
| sb.append(" subreason=").append(mSubReason).append(" (") |
| .append(subreasonToString(mSubReason)).append(")"); |
| sb.append(" status=").append(mStatus); |
| sb.append(" importance=").append(mImportance); |
| sb.append(" pss="); DebugUtils.sizeValueToString(mPss << 10, sb); |
| sb.append(" rss="); DebugUtils.sizeValueToString(mRss << 10, sb); |
| sb.append(" description=").append(mDescription); |
| sb.append(" state=").append(ArrayUtils.isEmpty(mState) |
| ? "empty" : Integer.toString(mState.length) + " bytes"); |
| sb.append(" trace=").append(mTraceFile); |
| |
| return sb.toString(); |
| } |
| |
| /** @hide */ |
| public static String reasonCodeToString(@Reason int reason) { |
| switch (reason) { |
| case REASON_EXIT_SELF: |
| return "EXIT_SELF"; |
| case REASON_SIGNALED: |
| return "SIGNALED"; |
| case REASON_LOW_MEMORY: |
| return "LOW_MEMORY"; |
| case REASON_CRASH: |
| return "APP CRASH(EXCEPTION)"; |
| case REASON_CRASH_NATIVE: |
| return "APP CRASH(NATIVE)"; |
| case REASON_ANR: |
| return "ANR"; |
| case REASON_INITIALIZATION_FAILURE: |
| return "INITIALIZATION FAILURE"; |
| case REASON_PERMISSION_CHANGE: |
| return "PERMISSION CHANGE"; |
| case REASON_EXCESSIVE_RESOURCE_USAGE: |
| return "EXCESSIVE RESOURCE USAGE"; |
| case REASON_USER_REQUESTED: |
| return "USER REQUESTED"; |
| case REASON_USER_STOPPED: |
| return "USER STOPPED"; |
| case REASON_DEPENDENCY_DIED: |
| return "DEPENDENCY DIED"; |
| case REASON_OTHER: |
| return "OTHER KILLS BY SYSTEM"; |
| case REASON_FREEZER: |
| return "FREEZER"; |
| case REASON_PACKAGE_STATE_CHANGE: |
| return "STATE CHANGE"; |
| case REASON_PACKAGE_UPDATED: |
| return "PACKAGE UPDATED"; |
| default: |
| return "UNKNOWN"; |
| } |
| } |
| |
| /** @hide */ |
| public static String subreasonToString(@SubReason int subreason) { |
| switch (subreason) { |
| case SUBREASON_WAIT_FOR_DEBUGGER: |
| return "WAIT FOR DEBUGGER"; |
| case SUBREASON_TOO_MANY_CACHED: |
| return "TOO MANY CACHED PROCS"; |
| case SUBREASON_TOO_MANY_EMPTY: |
| return "TOO MANY EMPTY PROCS"; |
| case SUBREASON_TRIM_EMPTY: |
| return "TRIM EMPTY"; |
| case SUBREASON_LARGE_CACHED: |
| return "LARGE CACHED"; |
| case SUBREASON_MEMORY_PRESSURE: |
| return "MEMORY PRESSURE"; |
| case SUBREASON_EXCESSIVE_CPU: |
| return "EXCESSIVE CPU USAGE"; |
| case SUBREASON_SYSTEM_UPDATE_DONE: |
| return "SYSTEM UPDATE_DONE"; |
| case SUBREASON_KILL_ALL_FG: |
| return "KILL ALL FG"; |
| case SUBREASON_KILL_ALL_BG_EXCEPT: |
| return "KILL ALL BG EXCEPT"; |
| case SUBREASON_KILL_UID: |
| return "KILL UID"; |
| case SUBREASON_KILL_PID: |
| return "KILL PID"; |
| case SUBREASON_INVALID_START: |
| return "INVALID START"; |
| case SUBREASON_INVALID_STATE: |
| return "INVALID STATE"; |
| case SUBREASON_IMPERCEPTIBLE: |
| return "IMPERCEPTIBLE"; |
| case SUBREASON_REMOVE_LRU: |
| return "REMOVE LRU"; |
| case SUBREASON_ISOLATED_NOT_NEEDED: |
| return "ISOLATED NOT NEEDED"; |
| case SUBREASON_FREEZER_BINDER_IOCTL: |
| return "FREEZER BINDER IOCTL"; |
| case SUBREASON_FREEZER_BINDER_TRANSACTION: |
| return "FREEZER BINDER TRANSACTION"; |
| case SUBREASON_FORCE_STOP: |
| return "FORCE STOP"; |
| case SUBREASON_REMOVE_TASK: |
| return "REMOVE TASK"; |
| case SUBREASON_STOP_APP: |
| return "STOP APP"; |
| case SUBREASON_KILL_BACKGROUND: |
| return "KILL BACKGROUND"; |
| case SUBREASON_PACKAGE_UPDATE: |
| return "PACKAGE UPDATE"; |
| case SUBREASON_UNDELIVERED_BROADCAST: |
| return "UNDELIVERED BROADCAST"; |
| case SUBREASON_EXCESSIVE_BINDER_OBJECTS: |
| return "EXCESSIVE BINDER OBJECTS"; |
| case SUBREASON_OOM_KILL: |
| return "OOM KILL"; |
| case SUBREASON_FREEZER_BINDER_ASYNC_FULL: |
| return "FREEZER BINDER ASYNC FULL"; |
| case SUBREASON_EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED: |
| return "EXCESSIVE_OUTGOING_BROADCASTS_WHILE_CACHED"; |
| default: |
| return "UNKNOWN"; |
| } |
| } |
| |
| /** |
| * Write to a protocol buffer output stream. |
| * Protocol buffer message definition at {@link android.app.ApplicationExitInfoProto} |
| * |
| * @param proto Stream to write the ApplicationExitInfo object to. |
| * @param fieldId Field Id of the ApplicationExitInfo as defined in the parent message |
| * @hide |
| */ |
| public void writeToProto(ProtoOutputStream proto, long fieldId) { |
| final long token = proto.start(fieldId); |
| proto.write(ApplicationExitInfoProto.PID, mPid); |
| proto.write(ApplicationExitInfoProto.REAL_UID, mRealUid); |
| proto.write(ApplicationExitInfoProto.PACKAGE_UID, mPackageUid); |
| proto.write(ApplicationExitInfoProto.DEFINING_UID, mDefiningUid); |
| proto.write(ApplicationExitInfoProto.PROCESS_NAME, mProcessName); |
| proto.write(ApplicationExitInfoProto.CONNECTION_GROUP, mConnectionGroup); |
| proto.write(ApplicationExitInfoProto.REASON, mReason); |
| proto.write(ApplicationExitInfoProto.SUB_REASON, mSubReason); |
| proto.write(ApplicationExitInfoProto.STATUS, mStatus); |
| proto.write(ApplicationExitInfoProto.IMPORTANCE, mImportance); |
| proto.write(ApplicationExitInfoProto.PSS, mPss); |
| proto.write(ApplicationExitInfoProto.RSS, mRss); |
| proto.write(ApplicationExitInfoProto.TIMESTAMP, mTimestamp); |
| proto.write(ApplicationExitInfoProto.DESCRIPTION, mDescription); |
| proto.write(ApplicationExitInfoProto.STATE, mState); |
| proto.write(ApplicationExitInfoProto.TRACE_FILE, |
| mTraceFile == null ? null : mTraceFile.getAbsolutePath()); |
| proto.end(token); |
| } |
| |
| /** |
| * Read from a protocol buffer input stream. |
| * Protocol buffer message definition at {@link android.app.ApplicationExitInfoProto} |
| * |
| * @param proto Stream to read the ApplicationExitInfo object from. |
| * @param fieldId Field Id of the ApplicationExitInfo as defined in the parent message |
| * @hide |
| */ |
| public void readFromProto(ProtoInputStream proto, long fieldId) |
| throws IOException, WireTypeMismatchException { |
| final long token = proto.start(fieldId); |
| while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) { |
| switch (proto.getFieldNumber()) { |
| case (int) ApplicationExitInfoProto.PID: |
| mPid = proto.readInt(ApplicationExitInfoProto.PID); |
| break; |
| case (int) ApplicationExitInfoProto.REAL_UID: |
| mRealUid = proto.readInt(ApplicationExitInfoProto.REAL_UID); |
| break; |
| case (int) ApplicationExitInfoProto.PACKAGE_UID: |
| mPackageUid = proto.readInt(ApplicationExitInfoProto.PACKAGE_UID); |
| break; |
| case (int) ApplicationExitInfoProto.DEFINING_UID: |
| mDefiningUid = proto.readInt(ApplicationExitInfoProto.DEFINING_UID); |
| break; |
| case (int) ApplicationExitInfoProto.PROCESS_NAME: |
| mProcessName = intern(proto.readString(ApplicationExitInfoProto.PROCESS_NAME)); |
| break; |
| case (int) ApplicationExitInfoProto.CONNECTION_GROUP: |
| mConnectionGroup = proto.readInt(ApplicationExitInfoProto.CONNECTION_GROUP); |
| break; |
| case (int) ApplicationExitInfoProto.REASON: |
| mReason = proto.readInt(ApplicationExitInfoProto.REASON); |
| break; |
| case (int) ApplicationExitInfoProto.SUB_REASON: |
| mSubReason = proto.readInt(ApplicationExitInfoProto.SUB_REASON); |
| break; |
| case (int) ApplicationExitInfoProto.STATUS: |
| mStatus = proto.readInt(ApplicationExitInfoProto.STATUS); |
| break; |
| case (int) ApplicationExitInfoProto.IMPORTANCE: |
| mImportance = proto.readInt(ApplicationExitInfoProto.IMPORTANCE); |
| break; |
| case (int) ApplicationExitInfoProto.PSS: |
| mPss = proto.readLong(ApplicationExitInfoProto.PSS); |
| break; |
| case (int) ApplicationExitInfoProto.RSS: |
| mRss = proto.readLong(ApplicationExitInfoProto.RSS); |
| break; |
| case (int) ApplicationExitInfoProto.TIMESTAMP: |
| mTimestamp = proto.readLong(ApplicationExitInfoProto.TIMESTAMP); |
| break; |
| case (int) ApplicationExitInfoProto.DESCRIPTION: |
| mDescription = intern(proto.readString(ApplicationExitInfoProto.DESCRIPTION)); |
| break; |
| case (int) ApplicationExitInfoProto.STATE: |
| mState = proto.readBytes(ApplicationExitInfoProto.STATE); |
| break; |
| case (int) ApplicationExitInfoProto.TRACE_FILE: |
| final String path = proto.readString(ApplicationExitInfoProto.TRACE_FILE); |
| if (!TextUtils.isEmpty(path)) { |
| mTraceFile = new File(path); |
| } |
| break; |
| } |
| } |
| proto.end(token); |
| } |
| |
| @Override |
| public boolean equals(@Nullable Object other) { |
| if (other == null || !(other instanceof ApplicationExitInfo)) { |
| return false; |
| } |
| ApplicationExitInfo o = (ApplicationExitInfo) other; |
| return mPid == o.mPid && mRealUid == o.mRealUid && mPackageUid == o.mPackageUid |
| && mDefiningUid == o.mDefiningUid |
| && mConnectionGroup == o.mConnectionGroup && mReason == o.mReason |
| && mSubReason == o.mSubReason && mImportance == o.mImportance |
| && mStatus == o.mStatus && mTimestamp == o.mTimestamp |
| && mPss == o.mPss && mRss == o.mRss |
| && TextUtils.equals(mProcessName, o.mProcessName) |
| && TextUtils.equals(mDescription, o.mDescription); |
| } |
| |
| @Override |
| public int hashCode() { |
| int result = mPid; |
| result = 31 * result + mRealUid; |
| result = 31 * result + mPackageUid; |
| result = 31 * result + mDefiningUid; |
| result = 31 * result + mConnectionGroup; |
| result = 31 * result + mReason; |
| result = 31 * result + mSubReason; |
| result = 31 * result + mImportance; |
| result = 31 * result + mStatus; |
| result = 31 * result + (int) mPss; |
| result = 31 * result + (int) mRss; |
| result = 31 * result + Long.hashCode(mTimestamp); |
| result = 31 * result + Objects.hashCode(mProcessName); |
| result = 31 * result + Objects.hashCode(mDescription); |
| return result; |
| } |
| } |