Merge "Add support to log app kill stats into statsd" into sc-dev

This commit is contained in:
Jing Ji
2021-05-10 16:34:21 +00:00
committed by Android (Google) Code Review
4 changed files with 86 additions and 247 deletions

View File

@@ -444,6 +444,13 @@ public final class ApplicationExitInfo implements Parcelable {
*/
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;
/** @hide */
@IntDef(prefix = { "REASON_" }, value = {
REASON_UNKNOWN,
@@ -890,6 +897,24 @@ public final class ApplicationExitInfo implements Parcelable {
mNativeTombstoneRetriever = retriever;
}
/**
* @see #mLoggedInStatsd
*
* @hide
*/
public boolean isLoggedInStatsd() {
return mLoggedInStatsd;
}
/**
* @see #mLoggedInStatsd
*
* @hide
*/
public void setLoggedInStatsd(boolean loggedInStatsd) {
mLoggedInStatsd = loggedInStatsd;
}
@Override
public int describeContents() {
return 0;

View File

@@ -1,245 +0,0 @@
/*
* Copyright (C) 2020 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.
*/
syntax = "proto2";
option java_multiple_files = true;
package android.app;
/**
* The reason code that why app process is killed.
*/
enum AppExitReasonCode {
/**
* Application process died due to unknown reason.
*/
REASON_UNKNOWN = 0;
/**
* Application process exit normally by itself, for example,
* via {@link android.os.Process#exit}; {@link #status} 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>
*/
REASON_EXIT_SELF = 1;
/**
* Application process died due to the result of an OS signal; for example,
* {@link android.os.Process#SIGNAL_KILL}; {@link #status} will specify the signum.
*/
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.
*/
REASON_LOW_MEMORY = 3;
/**
* Application process died because of an unhandled exception in Java code.
*/
REASON_CRASH = 4;
/**
* Application process died because it's crashed due to a native code crash.
*/
REASON_CRASH_NATIVE = 5;
/**
* Application process was killed due to being unresponsive (ANR).
*/
REASON_ANR = 6;
/**
* Application process was killed because it took too long to attach to the system
* during the start.
*/
REASON_INITIALIZATION_FAILURE = 7;
/**
* 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.
*/
REASON_PERMISSION_CHANGE = 8;
/**
* Application process was killed by the activity manager due to excessive resource usage.
*/
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 swiped away the application from Recents.
*/
REASON_USER_REQUESTED = 10;
/**
* Application process was killed, because the user they are running as on devices
* with mutlple users, was stopped.
*/
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.
*/
REASON_DEPENDENCY_DIED = 12;
/**
* Application process was killed by the system for various other reasons,
* for example, the application package got disabled by the user;
* {@link #description} will specify the cause given by the system.
*/
REASON_OTHER = 13;
}
/**
* The supplemental reason code that why app process is killed
*/
enum AppExitSubReasonCode {
/**
* Application process kills subReason is unknown.
*/
SUBREASON_UNKNOWN = 0;
/**
* Application process was killed because user quit it on the "wait for debugger" dialog.
*/
SUBREASON_WAIT_FOR_DEBUGGER = 1;
/**
* Application process was killed by the activity manager because there were too many cached
* processes.
*/
SUBREASON_TOO_MANY_CACHED = 2;
/**
* Application process was killed by the activity manager because there were too many empty
* processes.
*/
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.
*/
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.
*/
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.
*/
SUBREASON_MEMORY_PRESSURE = 6;
/**
* Application process was killed by the activity manager due to excessive CPU usage.
*/
SUBREASON_EXCESSIVE_CPU = 7;
/**
* System update has done (so the system update process should be killed).
*/
SUBREASON_SYSTEM_UPDATE_DONE = 8;
/**
* Kill all foreground services, for now it only occurs when enabling the quiet
* mode for the managed profile.
*/
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.
*/
SUBREASON_KILL_ALL_BG_EXCEPT = 10;
/**
* The process associated with the UID was explicitly killed, for example,
* it could be because of permission changes.
*/
SUBREASON_KILL_UID = 11;
/**
* The process was explicitly killed with its PID, typically because of
* the low memory for surfaces.
*/
SUBREASON_KILL_PID = 12;
/**
* The start of the process was invalid.
*/
SUBREASON_INVALID_START = 13;
/**
* The process was killed because it's in an invalid state, typically
* it's triggered from SHELL.
*/
SUBREASON_INVALID_STATE = 14;
/**
* The process was killed when it's imperceptible to user, because it was
* in a bad state.
*/
SUBREASON_IMPERCEPTIBLE = 15;
/**
* The process was killed because it's being moved out from LRU list.
*/
SUBREASON_REMOVE_LRU = 16;
/**
* The process was killed because it's isolated and was in a cached state.
*/
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}.
*/
SUBREASON_CACHED_IDLE_FORCED_APP_STANDBY = 18;
}
/** * The relative importance level that the system places on a process.
* Keep sync with the definitions in
* {@link android.app.ActivityManager.RunningAppProcessInfo}
*/
enum Importance {
option allow_alias = true;
IMPORTANCE_FOREGROUND = 100;
IMPORTANCE_FOREGROUND_SERVICE = 125;
IMPORTANCE_TOP_SLEEPING_PRE_28 = 150;
IMPORTANCE_VISIBLE = 200;
IMPORTANCE_PERCEPTIBLE_PRE_26 = 130;
IMPORTANCE_PERCEPTIBLE = 230;
IMPORTANCE_CANT_SAVE_STATE_PRE_26 = 170;
IMPORTANCE_SERVICE = 300;
IMPORTANCE_TOP_SLEEPING = 325;
IMPORTANCE_CANT_SAVE_STATE = 350;
IMPORTANCE_CACHED = 400;
IMPORTANCE_BACKGROUND = 400;
IMPORTANCE_EMPTY = 500;
IMPORTANCE_GONE = 1000;
}

View File

@@ -20,7 +20,7 @@ option java_multiple_files = true;
package android.app;
import "frameworks/base/core/proto/android/privacy.proto";
import "frameworks/base/core/proto/android/app/appexit_enums.proto";
import "frameworks/proto_logging/stats/enums/app/enums.proto";
/**
* An android.app.ApplicationExitInfo object.

View File

@@ -61,6 +61,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ProcessMap;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.IoThread;
import com.android.server.LocalServices;
@@ -108,6 +109,13 @@ public final class AppExitInfoTracker {
private static final int APP_EXIT_RAW_INFO_POOL_SIZE = 8;
/**
* How long we're going to hold before logging an app exit info into statsd;
* we do this is because there could be multiple sources signaling an app exit, we'd like to
* gather the most accurate information before logging into statsd.
*/
private static final long APP_EXIT_INFO_STATSD_LOG_DEBOUNCE = TimeUnit.SECONDS.toMillis(15);
@VisibleForTesting
static final String APP_EXIT_STORE_DIR = "procexitstore";
@@ -384,6 +392,8 @@ public final class AppExitInfoTracker {
ApplicationExitInfo.REASON_LOW_MEMORY);
} else if (zygote != null) {
updateExistingExitInfoRecordLocked(info, (Integer) zygote.second, null);
} else {
scheduleLogToStatsdLocked(info, false);
}
}
}
@@ -398,7 +408,7 @@ public final class AppExitInfoTracker {
raw.getPackageName(), raw.getPackageUid(), raw.getPid());
if (info == null) {
addExitInfoLocked(raw);
info = addExitInfoLocked(raw);
} else {
// always override the existing info since we are now more informational.
info.setReason(raw.getReason());
@@ -407,6 +417,7 @@ public final class AppExitInfoTracker {
info.setTimestamp(System.currentTimeMillis());
info.setDescription(raw.getDescription());
}
scheduleLogToStatsdLocked(info, true);
}
@GuardedBy("mLock")
@@ -438,22 +449,29 @@ public final class AppExitInfoTracker {
// if the record is way outdated, don't update it then (because of potential pid reuse)
return;
}
boolean immediateLog = false;
if (status != null) {
if (OsConstants.WIFEXITED(status)) {
info.setReason(ApplicationExitInfo.REASON_EXIT_SELF);
info.setStatus(OsConstants.WEXITSTATUS(status));
immediateLog = true;
} else if (OsConstants.WIFSIGNALED(status)) {
if (info.getReason() == ApplicationExitInfo.REASON_UNKNOWN) {
info.setReason(ApplicationExitInfo.REASON_SIGNALED);
info.setStatus(OsConstants.WTERMSIG(status));
} else if (info.getReason() == ApplicationExitInfo.REASON_CRASH_NATIVE) {
info.setStatus(OsConstants.WTERMSIG(status));
immediateLog = true;
}
}
}
if (reason != null) {
info.setReason(reason);
if (reason == ApplicationExitInfo.REASON_LOW_MEMORY) {
immediateLog = true;
}
}
scheduleLogToStatsdLocked(info, immediateLog);
}
/**
@@ -836,6 +854,40 @@ public final class AppExitInfoTracker {
container.addExitInfoLocked(info);
}
@GuardedBy("mLock")
private void scheduleLogToStatsdLocked(ApplicationExitInfo info, boolean immediate) {
if (info.isLoggedInStatsd()) {
return;
}
if (immediate) {
mKillHandler.removeMessages(KillHandler.MSG_STATSD_LOG, info);
performLogToStatsdLocked(info);
} else if (!mKillHandler.hasMessages(KillHandler.MSG_STATSD_LOG, info)) {
mKillHandler.sendMessageDelayed(mKillHandler.obtainMessage(
KillHandler.MSG_STATSD_LOG, info), APP_EXIT_INFO_STATSD_LOG_DEBOUNCE);
}
}
@GuardedBy("mLock")
private void performLogToStatsdLocked(ApplicationExitInfo info) {
if (info.isLoggedInStatsd()) {
return;
}
info.setLoggedInStatsd(true);
final String pkgName = info.getPackageName();
String processName = info.getProcessName();
if (TextUtils.equals(pkgName, processName)) {
// Omit the process name here to save space
processName = null;
} else if (processName != null && processName.startsWith(pkgName)) {
// Strip the prefix to save space
processName = processName.substring(pkgName.length());
}
FrameworkStatsLog.write(FrameworkStatsLog.APP_PROCESS_DIED,
info.getPackageUid(), processName, info.getReason(), info.getSubReason(),
info.getImportance(), (int) info.getPss(), (int) info.getRss());
}
@GuardedBy("mLock")
private void forEachPackageLocked(
BiFunction<String, SparseArray<AppExitInfoContainer>, Integer> callback) {
@@ -1532,6 +1584,7 @@ public final class AppExitInfoTracker {
static final int MSG_CHILD_PROC_DIED = 4102;
static final int MSG_PROC_DIED = 4103;
static final int MSG_APP_KILL = 4104;
static final int MSG_STATSD_LOG = 4105;
KillHandler(Looper looper) {
super(looper, null, true);
@@ -1564,6 +1617,12 @@ public final class AppExitInfoTracker {
recycleRawRecord(raw);
}
break;
case MSG_STATSD_LOG: {
synchronized (mLock) {
performLogToStatsdLocked((ApplicationExitInfo) msg.obj);
}
}
break;
default:
super.handleMessage(msg);
}