ActivityManagerService: reroute lmkd atoms logging am: 48f93dabe0
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1702073
Change-Id: Ic4bfb73a97f0155e5db6e56037d276d7d1a4c1ac
diff --git a/services/core/java/com/android/server/am/LmkdConnection.java b/services/core/java/com/android/server/am/LmkdConnection.java
index f41c364..4cffd6f 100644
--- a/services/core/java/com/android/server/am/LmkdConnection.java
+++ b/services/core/java/com/android/server/am/LmkdConnection.java
@@ -43,8 +43,12 @@
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 {
diff --git a/services/core/java/com/android/server/am/LmkdStatsReporter.java b/services/core/java/com/android/server/am/LmkdStatsReporter.java
new file mode 100644
index 0000000..8ffec91
--- /dev/null
+++ b/services/core/java/com/android/server/am/LmkdStatsReporter.java
@@ -0,0 +1,114 @@
+/*
+ * 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;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 444418c..c2259139 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -316,18 +316,25 @@
// 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;
@@ -781,6 +788,7 @@
if (receivedLen < 4) {
return false;
}
+
switch (dataReceived.getInt(0)) {
case LMK_PROCKILL:
if (receivedLen != 12) {
@@ -789,6 +797,20 @@
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;
}
@@ -1433,6 +1455,12 @@
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;
}