Loading services/core/java/com/android/server/Watchdog.java +22 −135 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.hidl.manager.V1_0.IServiceManager; import android.os.Binder; import android.os.Build; import android.os.Debug; import android.os.Handler; import android.os.IPowerManager; Loading @@ -32,10 +31,6 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; 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.Log; import android.util.Slog; Loading @@ -48,13 +43,8 @@ import com.android.server.wm.SurfaceAnimationThread; import java.io.File; import java.io.FileWriter; 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.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; Loading Loading @@ -132,7 +122,6 @@ public class Watchdog extends Thread { int mPhonePid; IActivityController mController; boolean mAllowRestart = true; final OpenFdMonitor mOpenFdMonitor; /** * Used for checking status of handle threads and scheduling monitor callbacks. Loading Loading @@ -337,8 +326,6 @@ public class Watchdog extends Thread { // Initialize monitor for Binder threads. addMonitor(new BinderThreadMonitor()); mOpenFdMonitor = OpenFdMonitor.create(); // See the notes on DEFAULT_TIMEOUT. assert DB || DEFAULT_TIMEOUT > ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS; Loading Loading @@ -560,12 +547,6 @@ public class Watchdog extends Thread { timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start); } boolean fdLimitTriggered = false; if (mOpenFdMonitor != null) { fdLimitTriggered = mOpenFdMonitor.monitor(); } if (!fdLimitTriggered) { final int waitState = evaluateCheckerCompletionLocked(); if (waitState == COMPLETED) { // The monitors have returned; reset Loading @@ -591,10 +572,6 @@ public class Watchdog extends Thread { // something is overdue! blockedCheckers = getBlockedCheckersLocked(); subject = describeCheckersLocked(blockedCheckers); } else { blockedCheckers = Collections.emptyList(); subject = "Open FD high water mark reached"; } allowRestart = mAllowRestart; } Loading Loading @@ -688,94 +665,4 @@ public class Watchdog extends Thread { 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; } } } Loading
services/core/java/com/android/server/Watchdog.java +22 −135 Original line number Diff line number Diff line Loading @@ -23,7 +23,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.hidl.manager.V1_0.IServiceManager; import android.os.Binder; import android.os.Build; import android.os.Debug; import android.os.Handler; import android.os.IPowerManager; Loading @@ -32,10 +31,6 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; 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.Log; import android.util.Slog; Loading @@ -48,13 +43,8 @@ import com.android.server.wm.SurfaceAnimationThread; import java.io.File; import java.io.FileWriter; 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.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; Loading Loading @@ -132,7 +122,6 @@ public class Watchdog extends Thread { int mPhonePid; IActivityController mController; boolean mAllowRestart = true; final OpenFdMonitor mOpenFdMonitor; /** * Used for checking status of handle threads and scheduling monitor callbacks. Loading Loading @@ -337,8 +326,6 @@ public class Watchdog extends Thread { // Initialize monitor for Binder threads. addMonitor(new BinderThreadMonitor()); mOpenFdMonitor = OpenFdMonitor.create(); // See the notes on DEFAULT_TIMEOUT. assert DB || DEFAULT_TIMEOUT > ZygoteConnectionConstants.WRAPPED_PID_TIMEOUT_MILLIS; Loading Loading @@ -560,12 +547,6 @@ public class Watchdog extends Thread { timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start); } boolean fdLimitTriggered = false; if (mOpenFdMonitor != null) { fdLimitTriggered = mOpenFdMonitor.monitor(); } if (!fdLimitTriggered) { final int waitState = evaluateCheckerCompletionLocked(); if (waitState == COMPLETED) { // The monitors have returned; reset Loading @@ -591,10 +572,6 @@ public class Watchdog extends Thread { // something is overdue! blockedCheckers = getBlockedCheckersLocked(); subject = describeCheckersLocked(blockedCheckers); } else { blockedCheckers = Collections.emptyList(); subject = "Open FD high water mark reached"; } allowRestart = mAllowRestart; } Loading Loading @@ -688,94 +665,4 @@ public class Watchdog extends Thread { 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; } } }