Merge changes from topic "reroute-lmkd-ams" into sc-dev
* changes: AMS: added caching DataInputStream object ActivityManagerService: reroute lmkd atoms logging
This commit is contained in:
committed by
Android (Google) Code Review
commit
85e554b8d8
@@ -31,6 +31,8 @@ import com.android.internal.annotations.GuardedBy;
|
|||||||
|
|
||||||
import libcore.io.IoUtils;
|
import libcore.io.IoUtils;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -43,8 +45,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 {
|
||||||
@@ -70,7 +76,7 @@ public class LmkdConnection {
|
|||||||
* @param receivedLen Size of the data received
|
* @param receivedLen Size of the data received
|
||||||
* @return True if the message has been handled correctly, false otherwise.
|
* @return True if the message has been handled correctly, false otherwise.
|
||||||
*/
|
*/
|
||||||
boolean handleUnsolicitedMessage(ByteBuffer dataReceived, int receivedLen);
|
boolean handleUnsolicitedMessage(DataInputStream inputData, int receivedLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final MessageQueue mMsgQueue;
|
private final MessageQueue mMsgQueue;
|
||||||
@@ -95,6 +101,10 @@ public class LmkdConnection {
|
|||||||
private final ByteBuffer mInputBuf =
|
private final ByteBuffer mInputBuf =
|
||||||
ByteBuffer.allocate(LMKD_REPLY_MAX_SIZE);
|
ByteBuffer.allocate(LMKD_REPLY_MAX_SIZE);
|
||||||
|
|
||||||
|
// Input stream to parse the incoming data
|
||||||
|
private final DataInputStream mInputData = new DataInputStream(
|
||||||
|
new ByteArrayInputStream(mInputBuf.array()));
|
||||||
|
|
||||||
// object to protect mReplyBuf and to wait/notify when reply is received
|
// object to protect mReplyBuf and to wait/notify when reply is received
|
||||||
private final Object mReplyBufLock = new Object();
|
private final Object mReplyBufLock = new Object();
|
||||||
|
|
||||||
@@ -186,26 +196,32 @@ public class LmkdConnection {
|
|||||||
private void processIncomingData() {
|
private void processIncomingData() {
|
||||||
int len = read(mInputBuf);
|
int len = read(mInputBuf);
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
synchronized (mReplyBufLock) {
|
try {
|
||||||
if (mReplyBuf != null) {
|
// reset InputStream to point into mInputBuf.array() begin
|
||||||
if (mListener.isReplyExpected(mReplyBuf, mInputBuf, len)) {
|
mInputData.reset();
|
||||||
// copy into reply buffer
|
synchronized (mReplyBufLock) {
|
||||||
mReplyBuf.put(mInputBuf.array(), 0, len);
|
if (mReplyBuf != null) {
|
||||||
mReplyBuf.rewind();
|
if (mListener.isReplyExpected(mReplyBuf, mInputBuf, len)) {
|
||||||
// wakeup the waiting thread
|
// copy into reply buffer
|
||||||
mReplyBufLock.notifyAll();
|
mReplyBuf.put(mInputBuf.array(), 0, len);
|
||||||
} else if (!mListener.handleUnsolicitedMessage(mInputBuf, len)) {
|
mReplyBuf.rewind();
|
||||||
// received unexpected packet
|
// wakeup the waiting thread
|
||||||
// treat this as an error
|
mReplyBufLock.notifyAll();
|
||||||
mReplyBuf = null;
|
} else if (!mListener.handleUnsolicitedMessage(mInputData, len)) {
|
||||||
mReplyBufLock.notifyAll();
|
// received unexpected packet
|
||||||
Slog.e(TAG, "Received an unexpected packet from lmkd");
|
// treat this as an error
|
||||||
|
mReplyBuf = null;
|
||||||
|
mReplyBufLock.notifyAll();
|
||||||
|
Slog.e(TAG, "Received an unexpected packet from lmkd");
|
||||||
|
}
|
||||||
|
} else if (!mListener.handleUnsolicitedMessage(mInputData, len)) {
|
||||||
|
// received asynchronous communication from lmkd
|
||||||
|
// but we don't recognize it.
|
||||||
|
Slog.w(TAG, "Received an unexpected packet from lmkd");
|
||||||
}
|
}
|
||||||
} else if (!mListener.handleUnsolicitedMessage(mInputBuf, len)) {
|
|
||||||
// received asynchronous communication from lmkd
|
|
||||||
// but we don't recognize it.
|
|
||||||
Slog.w(TAG, "Received an unexpected packet from lmkd");
|
|
||||||
}
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Slog.e(TAG, "Failed to parse lmkd data buffer. Size = " + len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
107
services/core/java/com/android/server/am/LmkdStatsReporter.java
Normal file
107
services/core/java/com/android/server/am/LmkdStatsReporter.java
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/*
|
||||||
|
* 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.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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(DataInputStream inputData) {
|
||||||
|
try {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -140,6 +140,7 @@ import com.android.server.wm.WindowProcessController;
|
|||||||
|
|
||||||
import dalvik.system.VMRuntime;
|
import dalvik.system.VMRuntime;
|
||||||
|
|
||||||
|
import java.io.DataInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -335,18 +336,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;
|
||||||
@@ -829,22 +837,44 @@ public final class ProcessList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean handleUnsolicitedMessage(ByteBuffer dataReceived,
|
public boolean handleUnsolicitedMessage(DataInputStream inputData,
|
||||||
int receivedLen) {
|
int receivedLen) {
|
||||||
if (receivedLen < 4) {
|
if (receivedLen < 4) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch (dataReceived.getInt(0)) {
|
|
||||||
case LMK_PROCKILL:
|
try {
|
||||||
if (receivedLen != 12) {
|
switch (inputData.readInt()) {
|
||||||
|
case LMK_PROCKILL:
|
||||||
|
if (receivedLen != 12) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final int pid = inputData.readInt();
|
||||||
|
final int uid = inputData.readInt();
|
||||||
|
mAppExitInfoTracker.scheduleNoteLmkdProcKilled(pid, uid);
|
||||||
|
return true;
|
||||||
|
case LMK_KILL_OCCURRED:
|
||||||
|
if (receivedLen
|
||||||
|
< LmkdStatsReporter.KILL_OCCURRED_MSG_SIZE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LmkdStatsReporter.logKillOccurred(inputData);
|
||||||
|
return true;
|
||||||
|
case LMK_STATE_CHANGED:
|
||||||
|
if (receivedLen
|
||||||
|
!= LmkdStatsReporter.STATE_CHANGED_MSG_SIZE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final int state = inputData.readInt();
|
||||||
|
LmkdStatsReporter.logStateChanged(state);
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
mAppExitInfoTracker.scheduleNoteLmkdProcKilled(
|
} catch (IOException e) {
|
||||||
dataReceived.getInt(4), dataReceived.getInt(8));
|
Slog.e(TAG, "Invalid buffer data. Failed to log LMK_KILL_OCCURRED");
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -1476,6 +1506,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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user