Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6647ef54 authored by Nandana Dutt's avatar Nandana Dutt
Browse files

Fix system server leaked fd dump

'lsof' was execed to dump the open file descriptors, but it does
not have the same permissions as system_server, presumably due to
SELinux restrcitions.

Now we get a list of open file descriptors from /proc/<pid>/fd and
resolve them via readlink, all inside system_server.

Test: Manually tested on a device and compared with the output of adb
lsof.

Change-Id: I4db8369a3a2bb0009c776277a8a6f92f72857ef8
parent 89b325a9
Loading
Loading
Loading
Loading
+34 −14
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.os.Binder;
import android.os.Build;
import android.os.RemoteException;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
import android.system.StructRlimit;
import com.android.internal.os.ZygoteConnectionConstants;
@@ -47,6 +48,10 @@ import android.util.Slog;
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;
@@ -621,23 +626,38 @@ public class Watchdog extends Thread {
            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);
                java.lang.Process proc = new ProcessBuilder()
                    .command("/system/bin/lsof", "-p", String.valueOf(Process.myPid()))
                    .redirectErrorStream(true)
                    .redirectOutput(dumpFile)
                    .start();

                int returnCode = proc.waitFor();
                if (returnCode != 0) {
                    Slog.w(TAG, "Unable to dump open descriptors, lsof return code: "
                        + returnCode);
                    dumpFile.delete();
                }
            } catch (IOException | InterruptedException ex) {
                Slog.w(TAG, "Unable to dump open descriptors: " + ex);
                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);
            }
        }