package org.succlz123.utils; import org.succlz123.s1go.app.utils.common.IOUtils; import android.os.Build; import android.os.Process; import android.os.SystemClock; import android.support.annotation.VisibleForTesting; import android.system.Os; import android.system.OsConstants; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Created by succlz123 on 2016/12/16. */ public class ProcessUtils { /** * {@code /proc/self/cmdline}. * See <a href="http://man7.org/linux/man-pages/man5/proc.5.html">proc(5)</a>. */ public static String myProcName() { return procName(Process.myPid()); } @VisibleForTesting static String procNameOld(int pid) { StringBuffer cmdline = new StringBuffer(); FileInputStream is = null; try { is = new FileInputStream("/proc/" + pid + "/cmdline"); for (; ; ) { int c = is.read(); if (c < 0) break; cmdline.append((char) c); } } catch (Exception ignored) { } finally { IOUtils.closeQuietly(is); } // trim the last '\0' return StringUtils.trim(cmdline.toString()); } /** * Gets the specified process name with pid. * See <a href="http://man7.org/linux/man-pages/man5/proc.5.html">proc(5)</a>. * {@code /proc/[pid]/cmdline} */ public static String procName(int pid) { return StringUtils.trimToEmpty(FileUtils.string("/proc/" + pid + "/cmdline")); } /** * {@code /proc/[pid]/stat}. * See <a href="http://man7.org/linux/man-pages/man5/proc.5.html">proc(5)</a>. */ public static String[] procStat(int pid) { return StringUtils.split(FileUtils.string("/proc/" + pid + "/stat")); } /** * {@code /proc/self/stat}. * See <a href="http://man7.org/linux/man-pages/man5/proc.5.html">proc(5)</a>. */ public static String[] myProcStat() { return procStat(Process.myPid()); } /** * {@code ps} */ public static String dumpProcStatus() { String[] stat = myProcStat(); if (stat.length < 27) { return "unknown stat string:" + Arrays.toString(stat); } StringBuilder builder = new StringBuilder(128); builder.append("uptime=").append(SystemClock.elapsedRealtime()).append('\t'); if (Build.VERSION.SDK_INT >= 21) { builder.append("CLK_TCK=").append(Os.sysconf(OsConstants._SC_CLK_TCK)).append("HZ\t"); } builder.append("pid=").append(stat[0]).append(',') .append("utime=").append(stat[13]).append(',') .append("stime=").append(stat[14]).append(',') .append("num_threads=").append(stat[19]).append(',') .append("starttime=").append(stat[21]); return builder.toString(); } /** * @param procName Process name. null == 'main process' * @see #isMainProcess() */ public static boolean isInProcess(String procName) { if (procName == null) { return isMainProcess(); } return StringUtils.equals(procName, myProcName()); } /** * dump opening file descriptors * See <a href="http://man7.org/linux/man-pages/man5/proc.5.html">proc(5)</a>. */ public static String dumpOpeningFds() { File[] files = listOpeningFiles(); if (files.length == 0) { return StringUtils.EMPTY; } final String fd = "/proc/" + Process.myPid() + "/fd/"; List<String> list = new ArrayList<>(files.length); for (File file : files) { try { String canonicalPath = file.getCanonicalPath(); int pos = canonicalPath.indexOf(fd); // remove 'fd' if (pos == 0) { canonicalPath = canonicalPath.substring(fd.length()); } list.add(file.getName() + " -> " + canonicalPath); } catch (IOException e) { // fall through list.add(file.getName() + " -> " + file.getAbsolutePath()); } } int size = list.size(); if (size == 0) return StringUtils.EMPTY; return "list " + fd + " : " + files.length + "\n " + StringUtils.join(list, "\n "); } /** * lsof */ public static File[] listOpeningFiles() { final String fd = "/proc/" + Process.myPid() + "/fd/"; File proc = new File(fd); if (!proc.isDirectory()) { return ArrayUtils.emptyArray(File.class); } File[] files = proc.listFiles(); if (files == null) { return ArrayUtils.emptyArray(File.class); } return files; } /** * ps -p {@code self} -t * See http://man7.org/linux/man-pages/man1/ps.1.html */ public static Thread[] getAllThreads() { ThreadGroup group = Thread.currentThread().getThreadGroup(); ThreadGroup system = null; do { system = group; group = group.getParent(); } while (group != null); int count = system.activeCount(); final Thread[] threads = new Thread[count << 1]; count = system.enumerate(threads); return count == threads.length ? threads : ArrayUtils.subarray(threads, 0, count); } /** * cat /proc/sys/fs/file-nr * * @return Array that contains 3 numbers, -1 means read error */ public static long[] getFileHandlesUsage() { String str = StringUtils.trimToEmpty(FileUtils.string("/proc/sys/fs/file-nr")); String[] arr = StringUtils.splitByWholeSeparator(str, null); if (arr.length < 3) return new long[]{-1, -1, -1}; long[] handles = new long[3]; for (int i = 0; i < arr.length; i++) { String s = arr[i]; try { handles[i] = Long.parseLong(s); } catch (NumberFormatException e) { handles[i] = -1; } } return handles; } /** * cat /proc/sys/fs/file-max * * @return -1 means read error */ public static long getMaxFileHandles() { String str = StringUtils.trimToEmpty(FileUtils.string("/proc/sys/fs/file-max")); try { return Long.parseLong(str); } catch (NumberFormatException e) { return -1; } } /** * Check current process is 'main process' */ public static boolean isMainProcess() { return StringUtils.indexOf(myProcName(), ':') == -1; } /** * kill -9 {@code self} */ public static void suicide() { Process.killProcess(Process.myPid()); } }