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
Merged-In: I69ef1a9daa5532244a15665bff06d0ad6b370869
This commit is contained in:
Vova Sharaienko
2021-04-24 00:26:56 +00:00
parent 3996048bad
commit 48f93dabe0
3 changed files with 149 additions and 3 deletions

View File

@@ -43,8 +43,12 @@ import java.nio.ByteBuffer;
public class LmkdConnection { public class LmkdConnection {
private static final String TAG = TAG_WITH_CLASS_NAME ? "LmkdConnection" : TAG_AM; 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 // connection listener interface
interface LmkdConnectionListener { interface LmkdConnectionListener {

View File

@@ -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;
}
}
}

View File

@@ -316,18 +316,25 @@ public final class ProcessList {
// LMK_GETKILLCNT // LMK_GETKILLCNT
// LMK_SUBSCRIBE // LMK_SUBSCRIBE
// LMK_PROCKILL // LMK_PROCKILL
// LMK_UPDATE_PROPS
// LMK_KILL_OCCURRED
// LMK_STATE_CHANGED
static final byte LMK_TARGET = 0; static final byte LMK_TARGET = 0;
static final byte LMK_PROCPRIO = 1; static final byte LMK_PROCPRIO = 1;
static final byte LMK_PROCREMOVE = 2; static final byte LMK_PROCREMOVE = 2;
static final byte LMK_PROCPURGE = 3; static final byte LMK_PROCPURGE = 3;
static final byte LMK_GETKILLCNT = 4; static final byte LMK_GETKILLCNT = 4;
static final byte LMK_SUBSCRIBE = 5; 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. // Low Memory Killer Daemon command codes.
// These must be kept in sync with async_event_type definitions in lmkd.h // 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_KILL = 0;
static final int LMK_ASYNC_EVENT_STAT = 1;
// lmkd reconnect delay in msecs // lmkd reconnect delay in msecs
private static final long LMKD_RECONNECT_DELAY_MS = 1000; private static final long LMKD_RECONNECT_DELAY_MS = 1000;
@@ -781,6 +788,7 @@ public final class ProcessList {
if (receivedLen < 4) { if (receivedLen < 4) {
return false; return false;
} }
switch (dataReceived.getInt(0)) { switch (dataReceived.getInt(0)) {
case LMK_PROCKILL: case LMK_PROCKILL:
if (receivedLen != 12) { if (receivedLen != 12) {
@@ -789,6 +797,20 @@ public final class ProcessList {
mAppExitInfoTracker.scheduleNoteLmkdProcKilled( mAppExitInfoTracker.scheduleNoteLmkdProcKilled(
dataReceived.getInt(4), dataReceived.getInt(8)); dataReceived.getInt(4), dataReceived.getInt(8));
return true; 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: default:
return false; return false;
} }
@@ -1433,6 +1455,12 @@ public final class ProcessList {
buf.putInt(LMK_SUBSCRIBE); buf.putInt(LMK_SUBSCRIBE);
buf.putInt(LMK_ASYNC_EVENT_KILL); buf.putInt(LMK_ASYNC_EVENT_KILL);
ostream.write(buf.array(), 0, buf.position()); 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) { } catch (IOException ex) {
return false; return false;
} }