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

Commit 26df817b authored by Vova Sharaienko's avatar Vova Sharaienko
Browse files

ActivityManagerService: reroute lmkd atoms logging

- Added support to subscribe for a lmkd LMK_ASYNC_EVENT_STAT event
- Added processing LMK_KILL_OCCURRED and LMK_STATE_CHANGED packets
  with logging to statsd
- Added statsd auto-generated code wrapping the statsd logging

Bug: 184698933
Test: lmkd_unit_test - test check_for_oom tests lmkd message send to AMS
Test: statsd_testdrive 51 54 to inspect statsd logged atoms data
Change-Id: I69ef1a9daa5532244a15665bff06d0ad6b370869
parent 0408e507
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -43,8 +43,12 @@ import java.nio.ByteBuffer;
public class LmkdConnection {
    private static final String TAG = TAG_WITH_CLASS_NAME ? "LmkdConnection" : TAG_AM;

    // lmkd reply max size in bytes
    private static final int LMKD_REPLY_MAX_SIZE = 12;
    /**
     * Max LMKD reply packet length in bytes
     * Used to hold the data for the statsd atoms logging
     * Must be in sync with statslog.h
     */
    private static final int LMKD_REPLY_MAX_SIZE = 214;

    // connection listener interface
    interface LmkdConnectionListener {
+114 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 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 com.android.server.am;

import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;

import android.util.Slog;

import com.android.internal.util.FrameworkStatsLog;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * Activity manager communication with lmkd data handling and statsd atom logging
 */
public final class LmkdStatsReporter {

    static final String TAG = TAG_WITH_CLASS_NAME ? "LmkdStatsReporter" : TAG_AM;

    public static final int KILL_OCCURRED_MSG_SIZE = 80;
    public static final int STATE_CHANGED_MSG_SIZE = 8;

    private static final int PRESSURE_AFTER_KILL = 0;
    private static final int NOT_RESPONDING = 1;
    private static final int LOW_SWAP_AND_THRASHING = 2;
    private static final int LOW_MEM_AND_SWAP = 3;
    private static final int LOW_MEM_AND_THRASHING = 4;
    private static final int DIRECT_RECL_AND_THRASHING = 5;
    private static final int LOW_MEM_AND_SWAP_UTIL = 6;

    /**
     * Processes the LMK_KILL_OCCURRED packet data
     * Logs the event when LMKD kills a process to reduce memory pressure.
     * Code: LMK_KILL_OCCURRED = 51
     */
    public static void logKillOccurred(ByteBuffer dataReceived) {
        DataInputStream inputData = new DataInputStream(
                new ByteArrayInputStream(dataReceived.array()));

        try {
            //read first int which denotes the message type
            final int msgType = inputData.readInt();
            final long pgFault = inputData.readLong();
            final long pgMajFault = inputData.readLong();
            final long rssInBytes = inputData.readLong();
            final long cacheInBytes = inputData.readLong();
            final long swapInBytes = inputData.readLong();
            final long processStartTimeNS = inputData.readLong();
            final int uid = inputData.readInt();
            final int oomScore = inputData.readInt();
            final int minOomScore = inputData.readInt();
            final int freeMemKb = inputData.readInt();
            final int freeSwapKb = inputData.readInt();
            final int killReason = inputData.readInt();
            final String procName = inputData.readUTF();

            FrameworkStatsLog.write(FrameworkStatsLog.LMK_KILL_OCCURRED, uid, procName, oomScore,
                    pgFault, pgMajFault, rssInBytes, cacheInBytes, swapInBytes, processStartTimeNS,
                    minOomScore, freeMemKb, freeSwapKb, mapKillReason(killReason));
        } catch (IOException e) {
            Slog.e(TAG, "Invalid buffer data. Failed to log LMK_KILL_OCCURRED");
            return;
        }
    }

    /**
     * Processes the LMK_STATE_CHANGED packet
     * Logs the change in LMKD state which is used as start/stop boundaries for logging
     * LMK_KILL_OCCURRED event.
     * Code: LMK_STATE_CHANGED = 54
     */
    public static void logStateChanged(int state) {
        FrameworkStatsLog.write(FrameworkStatsLog.LMK_STATE_CHANGED, state);
    }

    private static int mapKillReason(int reason) {
        switch (reason) {
            case PRESSURE_AFTER_KILL:
                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__PRESSURE_AFTER_KILL;
            case NOT_RESPONDING:
                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__NOT_RESPONDING;
            case LOW_SWAP_AND_THRASHING:
                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_SWAP_AND_THRASHING;
            case LOW_MEM_AND_SWAP:
                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM_AND_SWAP;
            case LOW_MEM_AND_THRASHING:
                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM_AND_THRASHING;
            case DIRECT_RECL_AND_THRASHING:
                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__DIRECT_RECL_AND_THRASHING;
            case LOW_MEM_AND_SWAP_UTIL:
                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__LOW_MEM_AND_SWAP_UTIL;
            default:
                return FrameworkStatsLog.LMK_KILL_OCCURRED__REASON__UNKNOWN;
        }
    }
}
+29 −1
Original line number Diff line number Diff line
@@ -334,18 +334,25 @@ public final class ProcessList {
    // LMK_GETKILLCNT
    // LMK_SUBSCRIBE
    // LMK_PROCKILL
    // LMK_UPDATE_PROPS
    // LMK_KILL_OCCURRED
    // LMK_STATE_CHANGED
    static final byte LMK_TARGET = 0;
    static final byte LMK_PROCPRIO = 1;
    static final byte LMK_PROCREMOVE = 2;
    static final byte LMK_PROCPURGE = 3;
    static final byte LMK_GETKILLCNT = 4;
    static final byte LMK_SUBSCRIBE = 5;
    static final byte LMK_PROCKILL = 6; // Note: this is an unsolicated command
    static final byte LMK_PROCKILL = 6; // Note: this is an unsolicited command
    static final byte LMK_UPDATE_PROPS = 7;
    static final byte LMK_KILL_OCCURRED = 8; // Msg to subscribed clients on kill occurred event
    static final byte LMK_STATE_CHANGED = 9; // Msg to subscribed clients on state changed

    // Low Memory Killer Daemon command codes.
    // These must be kept in sync with async_event_type definitions in lmkd.h
    //
    static final int LMK_ASYNC_EVENT_KILL = 0;
    static final int LMK_ASYNC_EVENT_STAT = 1;

    // lmkd reconnect delay in msecs
    private static final long LMKD_RECONNECT_DELAY_MS = 1000;
@@ -833,6 +840,7 @@ public final class ProcessList {
                            if (receivedLen < 4) {
                                return false;
                            }

                            switch (dataReceived.getInt(0)) {
                                case LMK_PROCKILL:
                                    if (receivedLen != 12) {
@@ -841,6 +849,20 @@ public final class ProcessList {
                                    mAppExitInfoTracker.scheduleNoteLmkdProcKilled(
                                            dataReceived.getInt(4), dataReceived.getInt(8));
                                    return true;
                                case LMK_KILL_OCCURRED:
                                    if (receivedLen < LmkdStatsReporter.KILL_OCCURRED_MSG_SIZE) {
                                        return false;
                                    }
                                    dataReceived.position(4);
                                    LmkdStatsReporter.logKillOccurred(dataReceived);
                                    return true;
                                case LMK_STATE_CHANGED:
                                    if (receivedLen != LmkdStatsReporter.STATE_CHANGED_MSG_SIZE) {
                                        return false;
                                    }
                                    LmkdStatsReporter.logStateChanged(
                                            dataReceived.getInt(4));
                                    return true;
                                default:
                                    return false;
                            }
@@ -1475,6 +1497,12 @@ public final class ProcessList {
            buf.putInt(LMK_SUBSCRIBE);
            buf.putInt(LMK_ASYNC_EVENT_KILL);
            ostream.write(buf.array(), 0, buf.position());

            // Subscribe for stats event notifications
            buf = ByteBuffer.allocate(4 * 2);
            buf.putInt(LMK_SUBSCRIBE);
            buf.putInt(LMK_ASYNC_EVENT_STAT);
            ostream.write(buf.array(), 0, buf.position());
        } catch (IOException ex) {
            return false;
        }