Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0ec24536 authored by Jing Ji's avatar Jing Ji Committed by Android (Google) Code Review
Browse files

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

parents f3bb0f28 40eba653
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -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;
+0 −245
Original line number Diff line number Diff line
/*
 * 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;
}
+1 −1
Original line number Diff line number Diff line
@@ -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.
+60 −1
Original line number Diff line number Diff line
@@ -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);
            }