Merge "Remove the watchdog's fd tracker." am: 4a724fc1ee
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1360733 Change-Id: I920005c586557faa6b5d7b614506593673ddcfad
This commit is contained in:
@@ -23,7 +23,6 @@ import android.content.Intent;
|
|||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.hidl.manager.V1_0.IServiceManager;
|
import android.hidl.manager.V1_0.IServiceManager;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Debug;
|
import android.os.Debug;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.IPowerManager;
|
import android.os.IPowerManager;
|
||||||
@@ -32,10 +31,6 @@ import android.os.Process;
|
|||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.ServiceManager;
|
import android.os.ServiceManager;
|
||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.system.ErrnoException;
|
|
||||||
import android.system.Os;
|
|
||||||
import android.system.OsConstants;
|
|
||||||
import android.system.StructRlimit;
|
|
||||||
import android.util.EventLog;
|
import android.util.EventLog;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
@@ -48,13 +43,8 @@ import com.android.server.wm.SurfaceAnimationThread;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -132,7 +122,6 @@ public class Watchdog extends Thread {
|
|||||||
int mPhonePid;
|
int mPhonePid;
|
||||||
IActivityController mController;
|
IActivityController mController;
|
||||||
boolean mAllowRestart = true;
|
boolean mAllowRestart = true;
|
||||||
final OpenFdMonitor mOpenFdMonitor;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for checking status of handle threads and scheduling monitor callbacks.
|
* Used for checking status of handle threads and scheduling monitor callbacks.
|
||||||
@@ -337,8 +326,6 @@ public class Watchdog extends Thread {
|
|||||||
// Initialize monitor for Binder threads.
|
// Initialize monitor for Binder threads.
|
||||||
addMonitor(new BinderThreadMonitor());
|
addMonitor(new BinderThreadMonitor());
|
||||||
|
|
||||||
mOpenFdMonitor = OpenFdMonitor.create();
|
|
||||||
|
|
||||||
// See the notes on DEFAULT_TIMEOUT.
|
// See the notes on DEFAULT_TIMEOUT.
|
||||||
assert DB ||
|
assert DB ||
|
||||||
DEFAULT_TIMEOUT > ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
|
DEFAULT_TIMEOUT > ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS;
|
||||||
@@ -560,41 +547,31 @@ public class Watchdog extends Thread {
|
|||||||
timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);
|
timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean fdLimitTriggered = false;
|
final int waitState = evaluateCheckerCompletionLocked();
|
||||||
if (mOpenFdMonitor != null) {
|
if (waitState == COMPLETED) {
|
||||||
fdLimitTriggered = mOpenFdMonitor.monitor();
|
// The monitors have returned; reset
|
||||||
}
|
waitedHalf = false;
|
||||||
|
continue;
|
||||||
if (!fdLimitTriggered) {
|
} else if (waitState == WAITING) {
|
||||||
final int waitState = evaluateCheckerCompletionLocked();
|
// still waiting but within their configured intervals; back off and recheck
|
||||||
if (waitState == COMPLETED) {
|
continue;
|
||||||
// The monitors have returned; reset
|
} else if (waitState == WAITED_HALF) {
|
||||||
waitedHalf = false;
|
if (!waitedHalf) {
|
||||||
continue;
|
Slog.i(TAG, "WAITED_HALF");
|
||||||
} else if (waitState == WAITING) {
|
// We've waited half the deadlock-detection interval. Pull a stack
|
||||||
// still waiting but within their configured intervals; back off and recheck
|
// trace and wait another half.
|
||||||
continue;
|
ArrayList<Integer> pids = new ArrayList<Integer>();
|
||||||
} else if (waitState == WAITED_HALF) {
|
pids.add(Process.myPid());
|
||||||
if (!waitedHalf) {
|
ActivityManagerService.dumpStackTraces(pids, null, null,
|
||||||
Slog.i(TAG, "WAITED_HALF");
|
|
||||||
// We've waited half the deadlock-detection interval. Pull a stack
|
|
||||||
// trace and wait another half.
|
|
||||||
ArrayList<Integer> pids = new ArrayList<Integer>();
|
|
||||||
pids.add(Process.myPid());
|
|
||||||
ActivityManagerService.dumpStackTraces(pids, null, null,
|
|
||||||
getInterestingNativePids());
|
getInterestingNativePids());
|
||||||
waitedHalf = true;
|
waitedHalf = true;
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
// something is overdue!
|
|
||||||
blockedCheckers = getBlockedCheckersLocked();
|
|
||||||
subject = describeCheckersLocked(blockedCheckers);
|
|
||||||
} else {
|
|
||||||
blockedCheckers = Collections.emptyList();
|
|
||||||
subject = "Open FD high water mark reached";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// something is overdue!
|
||||||
|
blockedCheckers = getBlockedCheckersLocked();
|
||||||
|
subject = describeCheckersLocked(blockedCheckers);
|
||||||
allowRestart = mAllowRestart;
|
allowRestart = mAllowRestart;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -688,94 +665,4 @@ public class Watchdog extends Thread {
|
|||||||
Slog.w(TAG, "Failed to write to /proc/sysrq-trigger", e);
|
Slog.w(TAG, "Failed to write to /proc/sysrq-trigger", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class OpenFdMonitor {
|
|
||||||
/**
|
|
||||||
* Number of FDs below the soft limit that we trigger a runtime restart at. This was
|
|
||||||
* chosen arbitrarily, but will need to be at least 6 in order to have a sufficient number
|
|
||||||
* of FDs in reserve to complete a dump.
|
|
||||||
*/
|
|
||||||
private static final int FD_HIGH_WATER_MARK = 12;
|
|
||||||
|
|
||||||
private final File mDumpDir;
|
|
||||||
private final File mFdHighWaterMark;
|
|
||||||
|
|
||||||
public static OpenFdMonitor create() {
|
|
||||||
// Only run the FD monitor on debuggable builds (such as userdebug and eng builds).
|
|
||||||
if (!Build.IS_DEBUGGABLE) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final StructRlimit rlimit;
|
|
||||||
try {
|
|
||||||
rlimit = android.system.Os.getrlimit(OsConstants.RLIMIT_NOFILE);
|
|
||||||
} catch (ErrnoException errno) {
|
|
||||||
Slog.w(TAG, "Error thrown from getrlimit(RLIMIT_NOFILE)", errno);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The assumption we're making here is that FD numbers are allocated (more or less)
|
|
||||||
// sequentially, which is currently (and historically) true since open is currently
|
|
||||||
// specified to always return the lowest-numbered non-open file descriptor for the
|
|
||||||
// current process.
|
|
||||||
//
|
|
||||||
// We do this to avoid having to enumerate the contents of /proc/self/fd in order to
|
|
||||||
// count the number of descriptors open in the process.
|
|
||||||
final File fdThreshold = new File("/proc/self/fd/" + (rlimit.rlim_cur - FD_HIGH_WATER_MARK));
|
|
||||||
return new OpenFdMonitor(new File("/data/anr"), fdThreshold);
|
|
||||||
}
|
|
||||||
|
|
||||||
OpenFdMonitor(File dumpDir, File fdThreshold) {
|
|
||||||
mDumpDir = dumpDir;
|
|
||||||
mFdHighWaterMark = fdThreshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dumps open file descriptors and their full paths to a temporary file in {@code mDumpDir}.
|
|
||||||
*/
|
|
||||||
private void dumpOpenDescriptors() {
|
|
||||||
// We cannot exec lsof to get more info about open file descriptors because a newly
|
|
||||||
// forked process will not have the permissions to readlink. Instead list all open
|
|
||||||
// descriptors from /proc/pid/fd and resolve them.
|
|
||||||
List<String> dumpInfo = new ArrayList<>();
|
|
||||||
String fdDirPath = String.format("/proc/%d/fd/", Process.myPid());
|
|
||||||
File[] fds = new File(fdDirPath).listFiles();
|
|
||||||
if (fds == null) {
|
|
||||||
dumpInfo.add("Unable to list " + fdDirPath);
|
|
||||||
} else {
|
|
||||||
for (File f : fds) {
|
|
||||||
String fdSymLink = f.getAbsolutePath();
|
|
||||||
String resolvedPath = "";
|
|
||||||
try {
|
|
||||||
resolvedPath = Os.readlink(fdSymLink);
|
|
||||||
} catch (ErrnoException ex) {
|
|
||||||
resolvedPath = ex.getMessage();
|
|
||||||
}
|
|
||||||
dumpInfo.add(fdSymLink + "\t" + resolvedPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dump the fds & paths to a temp file.
|
|
||||||
try {
|
|
||||||
File dumpFile = File.createTempFile("anr_fd_", "", mDumpDir);
|
|
||||||
Path out = Paths.get(dumpFile.getAbsolutePath());
|
|
||||||
Files.write(out, dumpInfo, StandardCharsets.UTF_8);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
Slog.w(TAG, "Unable to write open descriptors to file: " + ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {@code true} if the high water mark was breached and a dump was written,
|
|
||||||
* {@code false} otherwise.
|
|
||||||
*/
|
|
||||||
public boolean monitor() {
|
|
||||||
if (mFdHighWaterMark.exists()) {
|
|
||||||
dumpOpenDescriptors();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user