diff options
| -rw-r--r-- | services/core/jni/com_android_server_SystemServer.cpp | 49 | ||||
| -rw-r--r-- | services/java/com/android/server/SystemServer.java | 67 |
2 files changed, 75 insertions, 41 deletions
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp index 43f50bfc33d5..729fa71af169 100644 --- a/services/core/jni/com_android_server_SystemServer.cpp +++ b/services/core/jni/com_android_server_SystemServer.cpp @@ -99,47 +99,17 @@ static void android_server_SystemServer_initZygoteChildHeapProfiling(JNIEnv* /* android_mallopt(M_INIT_ZYGOTE_CHILD_PROFILING, nullptr, 0); } -static int get_current_max_fd() { - // Not actually guaranteed to be the max, but close enough for our purposes. - int fd = open("/dev/null", O_RDONLY | O_CLOEXEC); - LOG_ALWAYS_FATAL_IF(fd == -1, "failed to open /dev/null: %s", strerror(errno)); - close(fd); - return fd; -} +static void android_server_SystemServer_fdtrackAbort(JNIEnv*, jobject) { + raise(BIONIC_SIGNAL_FDTRACK); -static const char kFdLeakEnableThresholdProperty[] = "persist.sys.debug.fdtrack_enable_threshold"; -static const char kFdLeakAbortThresholdProperty[] = "persist.sys.debug.fdtrack_abort_threshold"; -static const char kFdLeakCheckIntervalProperty[] = "persist.sys.debug.fdtrack_interval"; + // Wait for a bit to allow fdtrack to dump backtraces to logcat. + std::this_thread::sleep_for(5s); -static void android_server_SystemServer_spawnFdLeakCheckThread(JNIEnv*, jobject) { + // Abort on a different thread to avoid ART dumping runtime stacks. std::thread([]() { - pthread_setname_np(pthread_self(), "FdLeakCheckThread"); - bool loaded = false; - while (true) { - const int enable_threshold = GetIntProperty(kFdLeakEnableThresholdProperty, 1024); - const int abort_threshold = GetIntProperty(kFdLeakAbortThresholdProperty, 2048); - const int check_interval = GetIntProperty(kFdLeakCheckIntervalProperty, 120); - int max_fd = get_current_max_fd(); - if (max_fd > enable_threshold && !loaded) { - loaded = true; - ALOGE("fd count above threshold of %d, starting fd backtraces", enable_threshold); - if (dlopen("libfdtrack.so", RTLD_GLOBAL) == nullptr) { - ALOGE("failed to load libfdtrack.so: %s", dlerror()); - } - } else if (max_fd > abort_threshold) { - raise(BIONIC_SIGNAL_FDTRACK); - - // Wait for a bit to allow fdtrack to dump backtraces to logcat. - std::this_thread::sleep_for(5s); - - LOG_ALWAYS_FATAL( - "b/140703823: aborting due to fd leak: check logs for fd " - "backtraces"); - } - - std::this_thread::sleep_for(std::chrono::seconds(check_interval)); - } - }).detach(); + LOG_ALWAYS_FATAL("b/140703823: aborting due to fd leak: check logs for fd " + "backtraces"); + }).join(); } static jlong android_server_SystemServer_startIncrementalService(JNIEnv* env, jclass klass, @@ -161,8 +131,7 @@ static const JNINativeMethod gMethods[] = { {"startHidlServices", "()V", (void*)android_server_SystemServer_startHidlServices}, {"initZygoteChildHeapProfiling", "()V", (void*)android_server_SystemServer_initZygoteChildHeapProfiling}, - {"spawnFdLeakCheckThread", "()V", - (void*)android_server_SystemServer_spawnFdLeakCheckThread}, + {"fdtrackAbort", "()V", (void*)android_server_SystemServer_fdtrackAbort}, {"startIncrementalService", "()J", (void*)android_server_SystemServer_startIncrementalService}, {"setIncrementalServiceSystemReady", "(J)V", diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 4cd1348a0f7a..516c64217177 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -23,6 +23,8 @@ import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL; import static android.os.IServiceManager.DUMP_FLAG_PROTO; import static android.os.Process.SYSTEM_UID; import static android.os.Process.myPid; +import static android.system.OsConstants.O_CLOEXEC; +import static android.system.OsConstants.O_RDONLY; import static android.view.Display.DEFAULT_DISPLAY; import static com.android.server.utils.TimingsTraceAndSlog.SYSTEM_SERVER_TIMING_TAG; @@ -75,6 +77,8 @@ import android.provider.DeviceConfig; import android.provider.Settings; import android.server.ServerProtoEnums; import android.sysprop.VoldProperties; +import android.system.ErrnoException; +import android.system.Os; import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.EventLog; @@ -188,6 +192,7 @@ import dalvik.system.VMRuntime; import com.google.android.startop.iorap.IorapForwardingService; import java.io.File; +import java.io.FileDescriptor; import java.io.IOException; import java.util.LinkedList; import java.util.Locale; @@ -394,11 +399,71 @@ public final class SystemServer { */ private static native void initZygoteChildHeapProfiling(); + private static final String SYSPROP_FDTRACK_ENABLE_THRESHOLD = + "persist.sys.debug.fdtrack_enable_threshold"; + private static final String SYSPROP_FDTRACK_ABORT_THRESHOLD = + "persist.sys.debug.fdtrack_abort_threshold"; + private static final String SYSPROP_FDTRACK_INTERVAL = + "persist.sys.debug.fdtrack_interval"; + + private static int getMaxFd() { + FileDescriptor fd = null; + try { + fd = Os.open("/dev/null", O_RDONLY | O_CLOEXEC, 0); + return fd.getInt$(); + } catch (ErrnoException ex) { + Slog.e("System", "Failed to get maximum fd: " + ex); + } finally { + if (fd != null) { + try { + Os.close(fd); + } catch (ErrnoException ex) { + // If Os.close threw, something went horribly wrong. + throw new RuntimeException(ex); + } + } + } + + return Integer.MAX_VALUE; + } + + private static native void fdtrackAbort(); /** * Spawn a thread that monitors for fd leaks. */ - private static native void spawnFdLeakCheckThread(); + private static void spawnFdLeakCheckThread() { + final int enableThreshold = SystemProperties.getInt(SYSPROP_FDTRACK_ENABLE_THRESHOLD, 1024); + final int abortThreshold = SystemProperties.getInt(SYSPROP_FDTRACK_ABORT_THRESHOLD, 2048); + final int checkInterval = SystemProperties.getInt(SYSPROP_FDTRACK_INTERVAL, 120); + + new Thread(() -> { + boolean enabled = false; + while (true) { + int maxFd = getMaxFd(); + if (maxFd > enableThreshold) { + // Do a manual GC to clean up fds that are hanging around as garbage. + System.gc(); + maxFd = getMaxFd(); + } + + if (maxFd > enableThreshold && !enabled) { + Slog.i("System", "fdtrack enable threshold reached, enabling"); + System.loadLibrary("fdtrack"); + enabled = true; + } else if (maxFd > abortThreshold) { + Slog.i("System", "fdtrack abort threshold reached, dumping and aborting"); + fdtrackAbort(); + } + + try { + Thread.sleep(checkInterval); + } catch (InterruptedException ex) { + continue; + } + } + }).start(); + } /** * Start native Incremental Service and get its handle. |